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/Optional.h"
12 #include "llvm/ADT/SmallString.h"
13 #include "llvm/ADT/StringMap.h"
14 #include "llvm/ADT/StringRef.h"
15 #include "llvm/ADT/Triple.h"
16 #include "llvm/ADT/iterator_range.h"
17 #include "llvm/BinaryFormat/MachO.h"
18 #include "llvm/Object/ObjectFile.h"
19 #include "llvm/Support/Chrono.h"
20 #include "llvm/Support/Error.h"
21 #include "llvm/Support/Format.h"
22 #include "llvm/Support/MemoryBuffer.h"
23 #include "llvm/Support/Path.h"
24 #include "llvm/Support/WithColor.h"
25 #include "llvm/Support/YAMLTraits.h"
26 #include "llvm/Support/raw_ostream.h"
39 using namespace llvm::object
;
41 DebugMapObject::DebugMapObject(StringRef ObjectFilename
,
42 sys::TimePoint
<std::chrono::seconds
> Timestamp
,
44 : Filename(ObjectFilename
), Timestamp(Timestamp
), Type(Type
) {}
46 bool DebugMapObject::addSymbol(StringRef Name
, Optional
<uint64_t> ObjectAddress
,
47 uint64_t LinkedAddress
, uint32_t Size
) {
48 auto InsertResult
= Symbols
.insert(
49 std::make_pair(Name
, SymbolMapping(ObjectAddress
, LinkedAddress
, Size
)));
51 if (ObjectAddress
&& InsertResult
.second
)
52 AddressToMapping
[*ObjectAddress
] = &*InsertResult
.first
;
53 return InsertResult
.second
;
56 void DebugMapObject::print(raw_ostream
&OS
) const {
57 OS
<< getObjectFilename() << ":\n";
58 // Sort the symbols in alphabetical order, like llvm-nm (and to get
59 // deterministic output for testing).
60 using Entry
= std::pair
<StringRef
, SymbolMapping
>;
61 std::vector
<Entry
> Entries
;
62 Entries
.reserve(Symbols
.getNumItems());
63 for (const auto &Sym
: make_range(Symbols
.begin(), Symbols
.end()))
64 Entries
.push_back(std::make_pair(Sym
.getKey(), Sym
.getValue()));
65 llvm::sort(Entries
, [](const Entry
&LHS
, const Entry
&RHS
) {
66 return LHS
.first
< RHS
.first
;
68 for (const auto &Sym
: Entries
) {
69 if (Sym
.second
.ObjectAddress
)
70 OS
<< format("\t%016" PRIx64
, uint64_t(*Sym
.second
.ObjectAddress
));
72 OS
<< "\t????????????????";
73 OS
<< format(" => %016" PRIx64
"+0x%x\t%s\n",
74 uint64_t(Sym
.second
.BinaryAddress
), uint32_t(Sym
.second
.Size
),
81 void DebugMapObject::dump() const { print(errs()); }
85 DebugMap::addDebugMapObject(StringRef ObjectFilePath
,
86 sys::TimePoint
<std::chrono::seconds
> Timestamp
,
88 Objects
.emplace_back(new DebugMapObject(ObjectFilePath
, Timestamp
, Type
));
89 return *Objects
.back();
92 const DebugMapObject::DebugMapEntry
*
93 DebugMapObject::lookupSymbol(StringRef SymbolName
) const {
94 StringMap
<SymbolMapping
>::const_iterator Sym
= Symbols
.find(SymbolName
);
95 if (Sym
== Symbols
.end())
100 const DebugMapObject::DebugMapEntry
*
101 DebugMapObject::lookupObjectAddress(uint64_t Address
) const {
102 auto Mapping
= AddressToMapping
.find(Address
);
103 if (Mapping
== AddressToMapping
.end())
105 return Mapping
->getSecond();
108 void DebugMap::print(raw_ostream
&OS
) const {
109 yaml::Output
yout(OS
, /* Ctxt = */ nullptr, /* WrapColumn = */ 0);
110 yout
<< const_cast<DebugMap
&>(*this);
114 void DebugMap::dump() const { print(errs()); }
120 StringRef PrependPath
;
124 } // end anonymous namespace
126 ErrorOr
<std::vector
<std::unique_ptr
<DebugMap
>>>
127 DebugMap::parseYAMLDebugMap(StringRef InputFile
, StringRef PrependPath
,
129 auto ErrOrFile
= MemoryBuffer::getFileOrSTDIN(InputFile
);
130 if (auto Err
= ErrOrFile
.getError())
135 Ctxt
.PrependPath
= PrependPath
;
137 std::unique_ptr
<DebugMap
> Res
;
138 yaml::Input
yin((*ErrOrFile
)->getBuffer(), &Ctxt
);
141 if (auto EC
= yin
.error())
143 std::vector
<std::unique_ptr
<DebugMap
>> Result
;
144 Result
.push_back(std::move(Res
));
145 return std::move(Result
);
148 } // end namespace dsymutil
152 // Normalize/Denormalize between YAML and a DebugMapObject.
153 struct MappingTraits
<dsymutil::DebugMapObject
>::YamlDMO
{
154 YamlDMO(IO
&io
) { Timestamp
= 0; }
155 YamlDMO(IO
&io
, dsymutil::DebugMapObject
&Obj
);
156 dsymutil::DebugMapObject
denormalize(IO
&IO
);
158 std::string Filename
;
160 std::vector
<dsymutil::DebugMapObject::YAMLSymbolMapping
> Entries
;
163 void MappingTraits
<std::pair
<std::string
, DebugMapObject::SymbolMapping
>>::
164 mapping(IO
&io
, std::pair
<std::string
, DebugMapObject::SymbolMapping
> &s
) {
165 io
.mapRequired("sym", s
.first
);
166 io
.mapOptional("objAddr", s
.second
.ObjectAddress
);
167 io
.mapRequired("binAddr", s
.second
.BinaryAddress
);
168 io
.mapOptional("size", s
.second
.Size
);
171 void MappingTraits
<dsymutil::DebugMapObject
>::mapping(
172 IO
&io
, dsymutil::DebugMapObject
&DMO
) {
173 MappingNormalization
<YamlDMO
, dsymutil::DebugMapObject
> Norm(io
, DMO
);
174 io
.mapRequired("filename", Norm
->Filename
);
175 io
.mapOptional("timestamp", Norm
->Timestamp
);
176 io
.mapRequired("symbols", Norm
->Entries
);
179 void ScalarTraits
<Triple
>::output(const Triple
&val
, void *, raw_ostream
&out
) {
183 StringRef ScalarTraits
<Triple
>::input(StringRef scalar
, void *, Triple
&value
) {
184 value
= Triple(scalar
);
189 SequenceTraits
<std::vector
<std::unique_ptr
<dsymutil::DebugMapObject
>>>::size(
190 IO
&io
, std::vector
<std::unique_ptr
<dsymutil::DebugMapObject
>> &seq
) {
194 dsymutil::DebugMapObject
&
195 SequenceTraits
<std::vector
<std::unique_ptr
<dsymutil::DebugMapObject
>>>::element(
196 IO
&, std::vector
<std::unique_ptr
<dsymutil::DebugMapObject
>> &seq
,
198 if (index
>= seq
.size()) {
199 seq
.resize(index
+ 1);
200 seq
[index
].reset(new dsymutil::DebugMapObject
);
205 void MappingTraits
<dsymutil::DebugMap
>::mapping(IO
&io
,
206 dsymutil::DebugMap
&DM
) {
207 io
.mapRequired("triple", DM
.BinaryTriple
);
208 io
.mapOptional("binary-path", DM
.BinaryPath
);
209 if (void *Ctxt
= io
.getContext())
210 reinterpret_cast<YAMLContext
*>(Ctxt
)->BinaryTriple
= DM
.BinaryTriple
;
211 io
.mapOptional("objects", DM
.Objects
);
214 void MappingTraits
<std::unique_ptr
<dsymutil::DebugMap
>>::mapping(
215 IO
&io
, std::unique_ptr
<dsymutil::DebugMap
> &DM
) {
217 DM
.reset(new DebugMap());
218 io
.mapRequired("triple", DM
->BinaryTriple
);
219 io
.mapOptional("binary-path", DM
->BinaryPath
);
220 if (void *Ctxt
= io
.getContext())
221 reinterpret_cast<YAMLContext
*>(Ctxt
)->BinaryTriple
= DM
->BinaryTriple
;
222 io
.mapOptional("objects", DM
->Objects
);
225 MappingTraits
<dsymutil::DebugMapObject
>::YamlDMO::YamlDMO(
226 IO
&io
, dsymutil::DebugMapObject
&Obj
) {
227 Filename
= Obj
.Filename
;
228 Timestamp
= sys::toTimeT(Obj
.getTimestamp());
229 Entries
.reserve(Obj
.Symbols
.size());
230 for (auto &Entry
: Obj
.Symbols
)
231 Entries
.push_back(std::make_pair(Entry
.getKey(), Entry
.getValue()));
234 dsymutil::DebugMapObject
235 MappingTraits
<dsymutil::DebugMapObject
>::YamlDMO::denormalize(IO
&IO
) {
236 BinaryHolder
BinHolder(/* Verbose =*/false);
237 const auto &Ctxt
= *reinterpret_cast<YAMLContext
*>(IO
.getContext());
238 SmallString
<80> Path(Ctxt
.PrependPath
);
239 StringMap
<uint64_t> SymbolAddresses
;
241 sys::path::append(Path
, Filename
);
243 auto ObjectEntry
= BinHolder
.getObjectEntry(Path
);
245 auto Err
= ObjectEntry
.takeError();
246 WithColor::warning() << "Unable to open " << Path
<< " "
247 << toString(std::move(Err
)) << '\n';
249 auto Object
= ObjectEntry
->getObject(Ctxt
.BinaryTriple
);
251 auto Err
= Object
.takeError();
252 WithColor::warning() << "Unable to open " << Path
<< " "
253 << toString(std::move(Err
)) << '\n';
255 for (const auto &Sym
: Object
->symbols()) {
256 uint64_t Address
= Sym
.getValue();
257 Expected
<StringRef
> Name
= Sym
.getName();
258 if (!Name
|| (Sym
.getFlags() &
259 (SymbolRef::SF_Absolute
| SymbolRef::SF_Common
))) {
260 // TODO: Actually report errors helpfully.
262 consumeError(Name
.takeError());
265 SymbolAddresses
[*Name
] = Address
;
270 dsymutil::DebugMapObject
Res(Path
, sys::toTimePoint(Timestamp
), MachO::N_OSO
);
271 for (auto &Entry
: Entries
) {
272 auto &Mapping
= Entry
.second
;
273 Optional
<uint64_t> ObjAddress
;
274 if (Mapping
.ObjectAddress
)
275 ObjAddress
= *Mapping
.ObjectAddress
;
276 auto AddressIt
= SymbolAddresses
.find(Entry
.first
);
277 if (AddressIt
!= SymbolAddresses
.end())
278 ObjAddress
= AddressIt
->getValue();
279 Res
.addSymbol(Entry
.first
, ObjAddress
, Mapping
.BinaryAddress
, Mapping
.Size
);
284 } // end namespace yaml
285 } // end namespace llvm