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/ADT/iterator_range.h"
15 #include "llvm/BinaryFormat/MachO.h"
16 #include "llvm/Object/ObjectFile.h"
17 #include "llvm/Support/Chrono.h"
18 #include "llvm/Support/Error.h"
19 #include "llvm/Support/Format.h"
20 #include "llvm/Support/MemoryBuffer.h"
21 #include "llvm/Support/Path.h"
22 #include "llvm/Support/WithColor.h"
23 #include "llvm/Support/YAMLTraits.h"
24 #include "llvm/Support/raw_ostream.h"
25 #include "llvm/TargetParser/Triple.h"
39 using namespace llvm::object
;
41 DebugMapObject::DebugMapObject(StringRef ObjectFilename
,
42 sys::TimePoint
<std::chrono::seconds
> Timestamp
,
44 : Filename(std::string(ObjectFilename
)), Timestamp(Timestamp
), Type(Type
) {}
46 bool DebugMapObject::addSymbol(StringRef Name
,
47 std::optional
<uint64_t> ObjectAddress
,
48 uint64_t LinkedAddress
, uint32_t Size
) {
49 auto InsertResult
= Symbols
.insert(
50 std::make_pair(Name
, SymbolMapping(ObjectAddress
, LinkedAddress
, Size
)));
52 if (ObjectAddress
&& InsertResult
.second
)
53 AddressToMapping
[*ObjectAddress
] = &*InsertResult
.first
;
54 return InsertResult
.second
;
57 void DebugMapObject::print(raw_ostream
&OS
) const {
58 OS
<< getObjectFilename() << ":\n";
59 // Sort the symbols in alphabetical order, like llvm-nm (and to get
60 // deterministic output for testing).
61 using Entry
= std::pair
<StringRef
, SymbolMapping
>;
62 std::vector
<Entry
> Entries
;
63 Entries
.reserve(Symbols
.getNumItems());
64 for (const auto &Sym
: Symbols
)
65 Entries
.push_back(std::make_pair(Sym
.getKey(), Sym
.getValue()));
66 llvm::sort(Entries
, llvm::less_first());
67 for (const auto &Sym
: Entries
) {
68 if (Sym
.second
.ObjectAddress
)
69 OS
<< format("\t%016" PRIx64
, uint64_t(*Sym
.second
.ObjectAddress
));
71 OS
<< "\t????????????????";
72 OS
<< format(" => %016" PRIx64
"+0x%x\t%s\n",
73 uint64_t(Sym
.second
.BinaryAddress
), uint32_t(Sym
.second
.Size
),
80 void DebugMapObject::dump() const { print(errs()); }
84 DebugMap::addDebugMapObject(StringRef ObjectFilePath
,
85 sys::TimePoint
<std::chrono::seconds
> Timestamp
,
87 Objects
.emplace_back(new DebugMapObject(ObjectFilePath
, Timestamp
, Type
));
88 return *Objects
.back();
91 const DebugMapObject::DebugMapEntry
*
92 DebugMapObject::lookupSymbol(StringRef SymbolName
) const {
93 StringMap
<SymbolMapping
>::const_iterator Sym
= Symbols
.find(SymbolName
);
94 if (Sym
== Symbols
.end())
99 const DebugMapObject::DebugMapEntry
*
100 DebugMapObject::lookupObjectAddress(uint64_t Address
) const {
101 auto Mapping
= AddressToMapping
.find(Address
);
102 if (Mapping
== AddressToMapping
.end())
104 return Mapping
->getSecond();
107 void DebugMap::print(raw_ostream
&OS
) const {
108 yaml::Output
yout(OS
, /* Ctxt = */ nullptr, /* WrapColumn = */ 0);
109 yout
<< const_cast<DebugMap
&>(*this);
113 void DebugMap::dump() const { print(errs()); }
119 StringRef PrependPath
;
123 } // end anonymous namespace
125 ErrorOr
<std::vector
<std::unique_ptr
<DebugMap
>>>
126 DebugMap::parseYAMLDebugMap(StringRef InputFile
, StringRef PrependPath
,
128 auto ErrOrFile
= MemoryBuffer::getFileOrSTDIN(InputFile
);
129 if (auto Err
= ErrOrFile
.getError())
134 Ctxt
.PrependPath
= PrependPath
;
136 std::unique_ptr
<DebugMap
> Res
;
137 yaml::Input
yin((*ErrOrFile
)->getBuffer(), &Ctxt
);
140 if (auto EC
= yin
.error())
142 std::vector
<std::unique_ptr
<DebugMap
>> Result
;
143 Result
.push_back(std::move(Res
));
144 return std::move(Result
);
147 } // end namespace dsymutil
151 // Normalize/Denormalize between YAML and a DebugMapObject.
152 struct MappingTraits
<dsymutil::DebugMapObject
>::YamlDMO
{
153 YamlDMO(IO
&io
) { Timestamp
= 0; }
154 YamlDMO(IO
&io
, dsymutil::DebugMapObject
&Obj
);
155 dsymutil::DebugMapObject
denormalize(IO
&IO
);
157 std::string Filename
;
159 std::vector
<dsymutil::DebugMapObject::YAMLSymbolMapping
> Entries
;
162 void MappingTraits
<std::pair
<std::string
, DebugMapObject::SymbolMapping
>>::
163 mapping(IO
&io
, std::pair
<std::string
, DebugMapObject::SymbolMapping
> &s
) {
164 io
.mapRequired("sym", s
.first
);
165 io
.mapOptional("objAddr", s
.second
.ObjectAddress
);
166 io
.mapRequired("binAddr", s
.second
.BinaryAddress
);
167 io
.mapOptional("size", s
.second
.Size
);
170 void MappingTraits
<dsymutil::DebugMapObject
>::mapping(
171 IO
&io
, dsymutil::DebugMapObject
&DMO
) {
172 MappingNormalization
<YamlDMO
, dsymutil::DebugMapObject
> Norm(io
, DMO
);
173 io
.mapRequired("filename", Norm
->Filename
);
174 io
.mapOptional("timestamp", Norm
->Timestamp
);
175 io
.mapRequired("symbols", Norm
->Entries
);
178 void ScalarTraits
<Triple
>::output(const Triple
&val
, void *, raw_ostream
&out
) {
182 StringRef ScalarTraits
<Triple
>::input(StringRef scalar
, void *, Triple
&value
) {
183 value
= Triple(scalar
);
188 SequenceTraits
<std::vector
<std::unique_ptr
<dsymutil::DebugMapObject
>>>::size(
189 IO
&io
, std::vector
<std::unique_ptr
<dsymutil::DebugMapObject
>> &seq
) {
193 dsymutil::DebugMapObject
&
194 SequenceTraits
<std::vector
<std::unique_ptr
<dsymutil::DebugMapObject
>>>::element(
195 IO
&, std::vector
<std::unique_ptr
<dsymutil::DebugMapObject
>> &seq
,
197 if (index
>= seq
.size()) {
198 seq
.resize(index
+ 1);
199 seq
[index
].reset(new dsymutil::DebugMapObject
);
204 void MappingTraits
<dsymutil::DebugMap
>::mapping(IO
&io
,
205 dsymutil::DebugMap
&DM
) {
206 io
.mapRequired("triple", DM
.BinaryTriple
);
207 io
.mapOptional("binary-path", DM
.BinaryPath
);
208 if (void *Ctxt
= io
.getContext())
209 reinterpret_cast<YAMLContext
*>(Ctxt
)->BinaryTriple
= DM
.BinaryTriple
;
210 io
.mapOptional("objects", DM
.Objects
);
213 void MappingTraits
<std::unique_ptr
<dsymutil::DebugMap
>>::mapping(
214 IO
&io
, std::unique_ptr
<dsymutil::DebugMap
> &DM
) {
216 DM
.reset(new DebugMap());
217 io
.mapRequired("triple", DM
->BinaryTriple
);
218 io
.mapOptional("binary-path", DM
->BinaryPath
);
219 if (void *Ctxt
= io
.getContext())
220 reinterpret_cast<YAMLContext
*>(Ctxt
)->BinaryTriple
= DM
->BinaryTriple
;
221 io
.mapOptional("objects", DM
->Objects
);
224 MappingTraits
<dsymutil::DebugMapObject
>::YamlDMO::YamlDMO(
225 IO
&io
, dsymutil::DebugMapObject
&Obj
) {
226 Filename
= Obj
.Filename
;
227 Timestamp
= sys::toTimeT(Obj
.getTimestamp());
228 Entries
.reserve(Obj
.Symbols
.size());
229 for (auto &Entry
: Obj
.Symbols
)
231 std::make_pair(std::string(Entry
.getKey()), Entry
.getValue()));
232 llvm::sort(Entries
, llvm::less_first());
235 dsymutil::DebugMapObject
236 MappingTraits
<dsymutil::DebugMapObject
>::YamlDMO::denormalize(IO
&IO
) {
237 BinaryHolder
BinHolder(vfs::getRealFileSystem(), /* Verbose =*/false);
238 const auto &Ctxt
= *reinterpret_cast<YAMLContext
*>(IO
.getContext());
239 SmallString
<80> Path(Ctxt
.PrependPath
);
240 StringMap
<uint64_t> SymbolAddresses
;
242 sys::path::append(Path
, Filename
);
244 auto ObjectEntry
= BinHolder
.getObjectEntry(Path
);
246 auto Err
= ObjectEntry
.takeError();
247 WithColor::warning() << "Unable to open " << Path
<< " "
248 << toString(std::move(Err
)) << '\n';
250 auto Object
= ObjectEntry
->getObject(Ctxt
.BinaryTriple
);
252 auto Err
= Object
.takeError();
253 WithColor::warning() << "Unable to open " << Path
<< " "
254 << toString(std::move(Err
)) << '\n';
256 for (const auto &Sym
: Object
->symbols()) {
257 Expected
<uint64_t> AddressOrErr
= Sym
.getValue();
259 // TODO: Actually report errors helpfully.
260 consumeError(AddressOrErr
.takeError());
263 Expected
<StringRef
> Name
= Sym
.getName();
264 Expected
<uint32_t> FlagsOrErr
= Sym
.getFlags();
265 if (!Name
|| !FlagsOrErr
||
266 (*FlagsOrErr
& (SymbolRef::SF_Absolute
| SymbolRef::SF_Common
))) {
267 // TODO: Actually report errors helpfully.
269 consumeError(FlagsOrErr
.takeError());
271 consumeError(Name
.takeError());
274 SymbolAddresses
[*Name
] = *AddressOrErr
;
279 dsymutil::DebugMapObject
Res(Path
, sys::toTimePoint(Timestamp
), MachO::N_OSO
);
280 for (auto &Entry
: Entries
) {
281 auto &Mapping
= Entry
.second
;
282 std::optional
<uint64_t> ObjAddress
;
283 if (Mapping
.ObjectAddress
)
284 ObjAddress
= *Mapping
.ObjectAddress
;
285 auto AddressIt
= SymbolAddresses
.find(Entry
.first
);
286 if (AddressIt
!= SymbolAddresses
.end())
287 ObjAddress
= AddressIt
->getValue();
288 Res
.addSymbol(Entry
.first
, ObjAddress
, Mapping
.BinaryAddress
, Mapping
.Size
);
293 } // end namespace yaml
294 } // end namespace llvm