1 //===- tools/dsymutil/DebugMap.cpp - Generic debug map representation -----===//
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 //===----------------------------------------------------------------------===//
10 #include "BinaryHolder.h"
11 #include "llvm/ADT/SmallString.h"
12 #include "llvm/ADT/StringMap.h"
13 #include "llvm/ADT/StringRef.h"
14 #include "llvm/BinaryFormat/MachO.h"
15 #include "llvm/Object/ObjectFile.h"
16 #include "llvm/Support/Chrono.h"
17 #include "llvm/Support/Error.h"
18 #include "llvm/Support/Format.h"
19 #include "llvm/Support/MemoryBuffer.h"
20 #include "llvm/Support/Path.h"
21 #include "llvm/Support/WithColor.h"
22 #include "llvm/Support/YAMLTraits.h"
23 #include "llvm/Support/raw_ostream.h"
24 #include "llvm/TargetParser/Triple.h"
38 using namespace llvm::object
;
40 DebugMapObject::DebugMapObject(StringRef ObjectFilename
,
41 sys::TimePoint
<std::chrono::seconds
> Timestamp
,
43 : Filename(std::string(ObjectFilename
)), Timestamp(Timestamp
), Type(Type
) {}
45 bool DebugMapObject::addSymbol(StringRef Name
,
46 std::optional
<uint64_t> ObjectAddress
,
47 uint64_t LinkedAddress
, uint32_t Size
) {
48 if (Symbols
.count(Name
)) {
49 // Symbol was previously added.
53 auto InsertResult
= Symbols
.insert(
54 std::make_pair(Name
, SymbolMapping(ObjectAddress
, LinkedAddress
, Size
)));
56 if (ObjectAddress
&& InsertResult
.second
)
57 AddressToMapping
[*ObjectAddress
] = &*InsertResult
.first
;
58 return InsertResult
.second
;
61 void DebugMapObject::setRelocationMap(dsymutil::RelocationMap
&RM
) {
65 void DebugMapObject::setInstallName(StringRef IN
) { InstallName
.emplace(IN
); }
67 void DebugMapObject::print(raw_ostream
&OS
) const {
68 OS
<< getObjectFilename() << ":\n";
69 // Sort the symbols in alphabetical order, like llvm-nm (and to get
70 // deterministic output for testing).
71 using Entry
= std::pair
<StringRef
, SymbolMapping
>;
72 std::vector
<Entry
> Entries
;
73 Entries
.reserve(Symbols
.getNumItems());
74 for (const auto &Sym
: Symbols
)
75 Entries
.push_back(std::make_pair(Sym
.getKey(), Sym
.getValue()));
76 llvm::sort(Entries
, llvm::less_first());
77 for (const auto &Sym
: Entries
) {
78 if (Sym
.second
.ObjectAddress
)
79 OS
<< format("\t%016" PRIx64
, uint64_t(*Sym
.second
.ObjectAddress
));
81 OS
<< "\t????????????????";
82 OS
<< format(" => %016" PRIx64
"+0x%x\t%s\n",
83 uint64_t(Sym
.second
.BinaryAddress
), uint32_t(Sym
.second
.Size
),
90 void DebugMapObject::dump() const { print(errs()); }
94 DebugMap::addDebugMapObject(StringRef ObjectFilePath
,
95 sys::TimePoint
<std::chrono::seconds
> Timestamp
,
97 Objects
.emplace_back(new DebugMapObject(ObjectFilePath
, Timestamp
, Type
));
98 return *Objects
.back();
101 const DebugMapObject::DebugMapEntry
*
102 DebugMapObject::lookupSymbol(StringRef SymbolName
) const {
103 StringMap
<SymbolMapping
>::const_iterator Sym
= Symbols
.find(SymbolName
);
104 if (Sym
== Symbols
.end())
109 const DebugMapObject::DebugMapEntry
*
110 DebugMapObject::lookupObjectAddress(uint64_t Address
) const {
111 auto Mapping
= AddressToMapping
.find(Address
);
112 if (Mapping
== AddressToMapping
.end())
114 return Mapping
->getSecond();
117 void DebugMap::print(raw_ostream
&OS
) const {
118 yaml::Output
yout(OS
, /* Ctxt = */ nullptr, /* WrapColumn = */ 0);
119 yout
<< const_cast<DebugMap
&>(*this);
123 void DebugMap::dump() const { print(errs()); }
129 StringRef PrependPath
;
133 } // end anonymous namespace
135 ErrorOr
<std::vector
<std::unique_ptr
<DebugMap
>>>
136 DebugMap::parseYAMLDebugMap(StringRef InputFile
, StringRef PrependPath
,
138 auto ErrOrFile
= MemoryBuffer::getFileOrSTDIN(InputFile
);
139 if (auto Err
= ErrOrFile
.getError())
144 Ctxt
.PrependPath
= PrependPath
;
146 std::unique_ptr
<DebugMap
> Res
;
147 yaml::Input
yin((*ErrOrFile
)->getBuffer(), &Ctxt
);
150 if (auto EC
= yin
.error())
152 std::vector
<std::unique_ptr
<DebugMap
>> Result
;
153 Result
.push_back(std::move(Res
));
154 return std::move(Result
);
157 } // end namespace dsymutil
161 // Normalize/Denormalize between YAML and a DebugMapObject.
162 struct MappingTraits
<dsymutil::DebugMapObject
>::YamlDMO
{
163 YamlDMO(IO
&io
) { Timestamp
= 0; }
164 YamlDMO(IO
&io
, dsymutil::DebugMapObject
&Obj
);
165 dsymutil::DebugMapObject
denormalize(IO
&IO
);
167 std::string Filename
;
169 std::vector
<dsymutil::DebugMapObject::YAMLSymbolMapping
> Entries
;
172 void MappingTraits
<std::pair
<std::string
, SymbolMapping
>>::mapping(
173 IO
&io
, std::pair
<std::string
, SymbolMapping
> &s
) {
174 io
.mapRequired("sym", s
.first
);
175 io
.mapOptional("objAddr", s
.second
.ObjectAddress
);
176 io
.mapRequired("binAddr", s
.second
.BinaryAddress
);
177 io
.mapOptional("size", s
.second
.Size
);
180 void MappingTraits
<dsymutil::DebugMapObject
>::mapping(
181 IO
&io
, dsymutil::DebugMapObject
&DMO
) {
182 MappingNormalization
<YamlDMO
, dsymutil::DebugMapObject
> Norm(io
, DMO
);
183 io
.mapRequired("filename", Norm
->Filename
);
184 io
.mapOptional("timestamp", Norm
->Timestamp
);
185 io
.mapRequired("symbols", Norm
->Entries
);
188 void ScalarTraits
<Triple
>::output(const Triple
&val
, void *, raw_ostream
&out
) {
192 StringRef ScalarTraits
<Triple
>::input(StringRef scalar
, void *, Triple
&value
) {
193 value
= Triple(scalar
);
198 SequenceTraits
<std::vector
<std::unique_ptr
<dsymutil::DebugMapObject
>>>::size(
199 IO
&io
, std::vector
<std::unique_ptr
<dsymutil::DebugMapObject
>> &seq
) {
203 dsymutil::DebugMapObject
&
204 SequenceTraits
<std::vector
<std::unique_ptr
<dsymutil::DebugMapObject
>>>::element(
205 IO
&, std::vector
<std::unique_ptr
<dsymutil::DebugMapObject
>> &seq
,
207 if (index
>= seq
.size()) {
208 seq
.resize(index
+ 1);
209 seq
[index
].reset(new dsymutil::DebugMapObject
);
214 void MappingTraits
<dsymutil::DebugMap
>::mapping(IO
&io
,
215 dsymutil::DebugMap
&DM
) {
216 io
.mapRequired("triple", DM
.BinaryTriple
);
217 io
.mapOptional("binary-path", DM
.BinaryPath
);
218 if (void *Ctxt
= io
.getContext())
219 reinterpret_cast<YAMLContext
*>(Ctxt
)->BinaryTriple
= DM
.BinaryTriple
;
220 io
.mapOptional("objects", DM
.Objects
);
223 void MappingTraits
<std::unique_ptr
<dsymutil::DebugMap
>>::mapping(
224 IO
&io
, std::unique_ptr
<dsymutil::DebugMap
> &DM
) {
226 DM
.reset(new DebugMap());
227 io
.mapRequired("triple", DM
->BinaryTriple
);
228 io
.mapOptional("binary-path", DM
->BinaryPath
);
229 if (void *Ctxt
= io
.getContext())
230 reinterpret_cast<YAMLContext
*>(Ctxt
)->BinaryTriple
= DM
->BinaryTriple
;
231 io
.mapOptional("objects", DM
->Objects
);
234 MappingTraits
<dsymutil::DebugMapObject
>::YamlDMO::YamlDMO(
235 IO
&io
, dsymutil::DebugMapObject
&Obj
) {
236 Filename
= Obj
.Filename
;
237 Timestamp
= sys::toTimeT(Obj
.getTimestamp());
238 Entries
.reserve(Obj
.Symbols
.size());
239 for (auto &Entry
: Obj
.Symbols
)
241 std::make_pair(std::string(Entry
.getKey()), Entry
.getValue()));
242 llvm::sort(Entries
, llvm::less_first());
245 dsymutil::DebugMapObject
246 MappingTraits
<dsymutil::DebugMapObject
>::YamlDMO::denormalize(IO
&IO
) {
247 BinaryHolder
BinHolder(vfs::getRealFileSystem(), /* Verbose =*/false);
248 const auto &Ctxt
= *reinterpret_cast<YAMLContext
*>(IO
.getContext());
249 SmallString
<80> Path(Ctxt
.PrependPath
);
250 StringMap
<uint64_t> SymbolAddresses
;
252 sys::path::append(Path
, Filename
);
254 auto ObjectEntry
= BinHolder
.getObjectEntry(Path
);
256 auto Err
= ObjectEntry
.takeError();
257 WithColor::warning() << "Unable to open " << Path
<< " "
258 << toString(std::move(Err
)) << '\n';
260 auto Object
= ObjectEntry
->getObject(Ctxt
.BinaryTriple
);
262 auto Err
= Object
.takeError();
263 WithColor::warning() << "Unable to open " << Path
<< " "
264 << toString(std::move(Err
)) << '\n';
266 for (const auto &Sym
: Object
->symbols()) {
267 Expected
<uint64_t> AddressOrErr
= Sym
.getValue();
269 // TODO: Actually report errors helpfully.
270 consumeError(AddressOrErr
.takeError());
273 Expected
<StringRef
> Name
= Sym
.getName();
274 Expected
<uint32_t> FlagsOrErr
= Sym
.getFlags();
275 if (!Name
|| !FlagsOrErr
||
276 (*FlagsOrErr
& (SymbolRef::SF_Absolute
| SymbolRef::SF_Common
))) {
277 // TODO: Actually report errors helpfully.
279 consumeError(FlagsOrErr
.takeError());
281 consumeError(Name
.takeError());
284 SymbolAddresses
[*Name
] = *AddressOrErr
;
289 uint8_t Type
= MachO::N_OSO
;
290 if (Path
.ends_with(".dylib")) {
291 // FIXME: find a more resilient way
294 dsymutil::DebugMapObject
Res(Path
, sys::toTimePoint(Timestamp
), Type
);
296 for (auto &Entry
: Entries
) {
297 auto &Mapping
= Entry
.second
;
298 std::optional
<uint64_t> ObjAddress
;
299 if (Mapping
.ObjectAddress
)
300 ObjAddress
= *Mapping
.ObjectAddress
;
301 auto AddressIt
= SymbolAddresses
.find(Entry
.first
);
302 if (AddressIt
!= SymbolAddresses
.end())
303 ObjAddress
= AddressIt
->getValue();
304 Res
.addSymbol(Entry
.first
, ObjAddress
, Mapping
.BinaryAddress
, Mapping
.Size
);
309 } // end namespace yaml
310 } // end namespace llvm