1 //===- ObjectFileTransformer.cpp --------------------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "llvm/Object/ELFObjectFile.h"
10 #include "llvm/Object/MachOUniversal.h"
11 #include "llvm/Object/ObjectFile.h"
12 #include "llvm/Support/DataExtractor.h"
13 #include "llvm/Support/raw_ostream.h"
15 #include "llvm/DebugInfo/GSYM/GsymCreator.h"
16 #include "llvm/DebugInfo/GSYM/ObjectFileTransformer.h"
17 #include "llvm/DebugInfo/GSYM/OutputAggregator.h"
22 constexpr uint32_t NT_GNU_BUILD_ID_TAG
= 0x03;
24 static std::vector
<uint8_t> getUUID(const object::ObjectFile
&Obj
) {
25 // Extract the UUID from the object file
26 std::vector
<uint8_t> UUID
;
27 if (auto *MachO
= dyn_cast
<object::MachOObjectFile
>(&Obj
)) {
28 const ArrayRef
<uint8_t> MachUUID
= MachO
->getUuid();
29 if (!MachUUID
.empty())
30 UUID
.assign(MachUUID
.data(), MachUUID
.data() + MachUUID
.size());
31 } else if (isa
<object::ELFObjectFileBase
>(&Obj
)) {
32 const StringRef
GNUBuildID(".note.gnu.build-id");
33 for (const object::SectionRef
&Sect
: Obj
.sections()) {
34 Expected
<StringRef
> SectNameOrErr
= Sect
.getName();
36 consumeError(SectNameOrErr
.takeError());
39 StringRef
SectName(*SectNameOrErr
);
40 if (SectName
!= GNUBuildID
)
42 StringRef BuildIDData
;
43 Expected
<StringRef
> E
= Sect
.getContents();
47 consumeError(E
.takeError());
50 DataExtractor
Decoder(BuildIDData
, Obj
.makeTriple().isLittleEndian(), 8);
52 const uint32_t NameSize
= Decoder
.getU32(&Offset
);
53 const uint32_t PayloadSize
= Decoder
.getU32(&Offset
);
54 const uint32_t PayloadType
= Decoder
.getU32(&Offset
);
55 StringRef
Name(Decoder
.getFixedLengthString(&Offset
, NameSize
));
56 if (Name
== "GNU" && PayloadType
== NT_GNU_BUILD_ID_TAG
) {
57 Offset
= alignTo(Offset
, 4);
58 StringRef
UUIDBytes(Decoder
.getBytes(&Offset
, PayloadSize
));
59 if (!UUIDBytes
.empty()) {
60 auto Ptr
= reinterpret_cast<const uint8_t *>(UUIDBytes
.data());
61 UUID
.assign(Ptr
, Ptr
+ UUIDBytes
.size());
69 llvm::Error
ObjectFileTransformer::convert(const object::ObjectFile
&Obj
,
70 OutputAggregator
&Out
,
72 using namespace llvm::object
;
74 const bool IsMachO
= isa
<MachOObjectFile
>(&Obj
);
75 const bool IsELF
= isa
<ELFObjectFileBase
>(&Obj
);
78 Gsym
.setUUID(getUUID(Obj
));
80 // Parse the symbol table.
81 size_t NumBefore
= Gsym
.getNumFunctionInfos();
82 for (const object::SymbolRef
&Sym
: Obj
.symbols()) {
83 Expected
<SymbolRef::Type
> SymType
= Sym
.getType();
85 consumeError(SymType
.takeError());
88 Expected
<uint64_t> AddrOrErr
= Sym
.getValue();
90 // TODO: Test this error.
91 return AddrOrErr
.takeError();
93 if (SymType
.get() != SymbolRef::Type::ST_Function
||
94 !Gsym
.IsValidTextAddress(*AddrOrErr
))
96 // Function size for MachO files will be 0
97 constexpr bool NoCopy
= false;
98 const uint64_t size
= IsELF
? ELFSymbolRef(Sym
).getSize() : 0;
99 Expected
<StringRef
> Name
= Sym
.getName();
102 logAllUnhandledErrors(Name
.takeError(), *Out
.GetOS(),
103 "ObjectFileTransformer: ");
105 consumeError(Name
.takeError());
108 // Remove the leading '_' character in any symbol names if there is one
111 Name
->consume_front("_");
112 Gsym
.addFunctionInfo(
113 FunctionInfo(*AddrOrErr
, size
, Gsym
.insertString(*Name
, NoCopy
)));
115 size_t FunctionsAddedCount
= Gsym
.getNumFunctionInfos() - NumBefore
;
117 *Out
.GetOS() << "Loaded " << FunctionsAddedCount
118 << " functions from symbol table.\n";
119 return Error::success();