1231f714eSFrederic Riss //===- tools/dsymutil/DebugMap.cpp - Generic debug map representation -----===//
2231f714eSFrederic Riss //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6231f714eSFrederic Riss //
7231f714eSFrederic Riss //===----------------------------------------------------------------------===//
80ad18f88SEugene Zelenko
9231f714eSFrederic Riss #include "DebugMap.h"
104f5874a5SFrederic Riss #include "BinaryHolder.h"
110ad18f88SEugene Zelenko #include "llvm/ADT/Optional.h"
120ad18f88SEugene Zelenko #include "llvm/ADT/SmallString.h"
130ad18f88SEugene Zelenko #include "llvm/ADT/StringMap.h"
140ad18f88SEugene Zelenko #include "llvm/ADT/StringRef.h"
150ad18f88SEugene Zelenko #include "llvm/ADT/Triple.h"
16d9903888SChandler Carruth #include "llvm/ADT/iterator_range.h"
170ad18f88SEugene Zelenko #include "llvm/BinaryFormat/MachO.h"
180ad18f88SEugene Zelenko #include "llvm/Object/ObjectFile.h"
190ad18f88SEugene Zelenko #include "llvm/Support/Chrono.h"
200ad18f88SEugene Zelenko #include "llvm/Support/Error.h"
21231f714eSFrederic Riss #include "llvm/Support/Format.h"
220ad18f88SEugene Zelenko #include "llvm/Support/MemoryBuffer.h"
230ad18f88SEugene Zelenko #include "llvm/Support/Path.h"
243072b130SJonas Devlieghere #include "llvm/Support/WithColor.h"
250ad18f88SEugene Zelenko #include "llvm/Support/YAMLTraits.h"
26231f714eSFrederic Riss #include "llvm/Support/raw_ostream.h"
27231f714eSFrederic Riss #include <algorithm>
280ad18f88SEugene Zelenko #include <cinttypes>
290ad18f88SEugene Zelenko #include <cstdint>
300ad18f88SEugene Zelenko #include <memory>
310ad18f88SEugene Zelenko #include <string>
320ad18f88SEugene Zelenko #include <utility>
330ad18f88SEugene Zelenko #include <vector>
34231f714eSFrederic Riss
35231f714eSFrederic Riss namespace llvm {
360ad18f88SEugene Zelenko
37231f714eSFrederic Riss namespace dsymutil {
38231f714eSFrederic Riss
39231f714eSFrederic Riss using namespace llvm::object;
40231f714eSFrederic Riss
DebugMapObject(StringRef ObjectFilename,sys::TimePoint<std::chrono::seconds> Timestamp,uint8_t Type)419ccfddc3SFrederic Riss DebugMapObject::DebugMapObject(StringRef ObjectFilename,
428aedfde2SFrancis Ricci sys::TimePoint<std::chrono::seconds> Timestamp,
438aedfde2SFrancis Ricci uint8_t Type)
44adcd0268SBenjamin Kramer : Filename(std::string(ObjectFilename)), Timestamp(Timestamp), Type(Type) {}
45231f714eSFrederic Riss
addSymbol(StringRef Name,Optional<uint64_t> ObjectAddress,uint64_t LinkedAddress,uint32_t Size)46d8c33dc2SFrederic Riss bool DebugMapObject::addSymbol(StringRef Name, Optional<uint64_t> ObjectAddress,
47912d0f12SFrederic Riss uint64_t LinkedAddress, uint32_t Size) {
48231f714eSFrederic Riss auto InsertResult = Symbols.insert(
49912d0f12SFrederic Riss std::make_pair(Name, SymbolMapping(ObjectAddress, LinkedAddress, Size)));
501595c5d3SFrederic Riss
51d8c33dc2SFrederic Riss if (ObjectAddress && InsertResult.second)
52d8c33dc2SFrederic Riss AddressToMapping[*ObjectAddress] = &*InsertResult.first;
53231f714eSFrederic Riss return InsertResult.second;
54231f714eSFrederic Riss }
55231f714eSFrederic Riss
print(raw_ostream & OS) const56231f714eSFrederic Riss void DebugMapObject::print(raw_ostream &OS) const {
57231f714eSFrederic Riss OS << getObjectFilename() << ":\n";
58231f714eSFrederic Riss // Sort the symbols in alphabetical order, like llvm-nm (and to get
59231f714eSFrederic Riss // deterministic output for testing).
600ad18f88SEugene Zelenko using Entry = std::pair<StringRef, SymbolMapping>;
61231f714eSFrederic Riss std::vector<Entry> Entries;
62231f714eSFrederic Riss Entries.reserve(Symbols.getNumItems());
636a6e3821SKazu Hirata for (const auto &Sym : Symbols)
64231f714eSFrederic Riss Entries.push_back(std::make_pair(Sym.getKey(), Sym.getValue()));
65*4969a692SKazu Hirata llvm::sort(Entries, llvm::less_first());
66231f714eSFrederic Riss for (const auto &Sym : Entries) {
67d8c33dc2SFrederic Riss if (Sym.second.ObjectAddress)
68d8c33dc2SFrederic Riss OS << format("\t%016" PRIx64, uint64_t(*Sym.second.ObjectAddress));
69d8c33dc2SFrederic Riss else
70d8c33dc2SFrederic Riss OS << "\t????????????????";
71d8c33dc2SFrederic Riss OS << format(" => %016" PRIx64 "+0x%x\t%s\n",
72f37964ccSFrederic Riss uint64_t(Sym.second.BinaryAddress), uint32_t(Sym.second.Size),
73f37964ccSFrederic Riss Sym.first.data());
74231f714eSFrederic Riss }
75231f714eSFrederic Riss OS << '\n';
76231f714eSFrederic Riss }
77231f714eSFrederic Riss
78231f714eSFrederic Riss #ifndef NDEBUG
dump() const79231f714eSFrederic Riss void DebugMapObject::dump() const { print(errs()); }
80231f714eSFrederic Riss #endif
81231f714eSFrederic Riss
8262d72041SPavel Labath DebugMapObject &
addDebugMapObject(StringRef ObjectFilePath,sys::TimePoint<std::chrono::seconds> Timestamp,uint8_t Type)8362d72041SPavel Labath DebugMap::addDebugMapObject(StringRef ObjectFilePath,
848aedfde2SFrancis Ricci sys::TimePoint<std::chrono::seconds> Timestamp,
858aedfde2SFrancis Ricci uint8_t Type) {
868aedfde2SFrancis Ricci Objects.emplace_back(new DebugMapObject(ObjectFilePath, Timestamp, Type));
87231f714eSFrederic Riss return *Objects.back();
88231f714eSFrederic Riss }
89231f714eSFrederic Riss
901595c5d3SFrederic Riss const DebugMapObject::DebugMapEntry *
lookupSymbol(StringRef SymbolName) const91231f714eSFrederic Riss DebugMapObject::lookupSymbol(StringRef SymbolName) const {
92231f714eSFrederic Riss StringMap<SymbolMapping>::const_iterator Sym = Symbols.find(SymbolName);
93231f714eSFrederic Riss if (Sym == Symbols.end())
94231f714eSFrederic Riss return nullptr;
951595c5d3SFrederic Riss return &*Sym;
961595c5d3SFrederic Riss }
971595c5d3SFrederic Riss
981595c5d3SFrederic Riss const DebugMapObject::DebugMapEntry *
lookupObjectAddress(uint64_t Address) const991595c5d3SFrederic Riss DebugMapObject::lookupObjectAddress(uint64_t Address) const {
1001595c5d3SFrederic Riss auto Mapping = AddressToMapping.find(Address);
1011595c5d3SFrederic Riss if (Mapping == AddressToMapping.end())
1021595c5d3SFrederic Riss return nullptr;
1031595c5d3SFrederic Riss return Mapping->getSecond();
104231f714eSFrederic Riss }
105231f714eSFrederic Riss
print(raw_ostream & OS) const106231f714eSFrederic Riss void DebugMap::print(raw_ostream &OS) const {
10708462f78SFrederic Riss yaml::Output yout(OS, /* Ctxt = */ nullptr, /* WrapColumn = */ 0);
10808462f78SFrederic Riss yout << const_cast<DebugMap &>(*this);
109231f714eSFrederic Riss }
110231f714eSFrederic Riss
111231f714eSFrederic Riss #ifndef NDEBUG
dump() const112231f714eSFrederic Riss void DebugMap::dump() const { print(errs()); }
113231f714eSFrederic Riss #endif
1144d0ba668SFrederic Riss
1154f5874a5SFrederic Riss namespace {
1160ad18f88SEugene Zelenko
1174f5874a5SFrederic Riss struct YAMLContext {
1184f5874a5SFrederic Riss StringRef PrependPath;
119a81e8814SFrederic Riss Triple BinaryTriple;
1204f5874a5SFrederic Riss };
1210ad18f88SEugene Zelenko
1220ad18f88SEugene Zelenko } // end anonymous namespace
1234f5874a5SFrederic Riss
1244dd3e0c4SFrederic Riss ErrorOr<std::vector<std::unique_ptr<DebugMap>>>
parseYAMLDebugMap(StringRef InputFile,StringRef PrependPath,bool Verbose)1254d0ba668SFrederic Riss DebugMap::parseYAMLDebugMap(StringRef InputFile, StringRef PrependPath,
1264d0ba668SFrederic Riss bool Verbose) {
1274d0ba668SFrederic Riss auto ErrOrFile = MemoryBuffer::getFileOrSTDIN(InputFile);
1284d0ba668SFrederic Riss if (auto Err = ErrOrFile.getError())
1294d0ba668SFrederic Riss return Err;
1304d0ba668SFrederic Riss
1314f5874a5SFrederic Riss YAMLContext Ctxt;
1324f5874a5SFrederic Riss
1334f5874a5SFrederic Riss Ctxt.PrependPath = PrependPath;
1344f5874a5SFrederic Riss
1354d0ba668SFrederic Riss std::unique_ptr<DebugMap> Res;
1364f5874a5SFrederic Riss yaml::Input yin((*ErrOrFile)->getBuffer(), &Ctxt);
1374d0ba668SFrederic Riss yin >> Res;
1384d0ba668SFrederic Riss
1394d0ba668SFrederic Riss if (auto EC = yin.error())
1404d0ba668SFrederic Riss return EC;
1414dd3e0c4SFrederic Riss std::vector<std::unique_ptr<DebugMap>> Result;
1424dd3e0c4SFrederic Riss Result.push_back(std::move(Res));
143c55cf4afSBill Wendling return std::move(Result);
1444d0ba668SFrederic Riss }
1450ad18f88SEugene Zelenko
1460ad18f88SEugene Zelenko } // end namespace dsymutil
1474d0ba668SFrederic Riss
1484d0ba668SFrederic Riss namespace yaml {
1494d0ba668SFrederic Riss
1504d0ba668SFrederic Riss // Normalize/Denormalize between YAML and a DebugMapObject.
1514d0ba668SFrederic Riss struct MappingTraits<dsymutil::DebugMapObject>::YamlDMO {
YamlDMOllvm::yaml::MappingTraits::YamlDMO1529ccfddc3SFrederic Riss YamlDMO(IO &io) { Timestamp = 0; }
1534d0ba668SFrederic Riss YamlDMO(IO &io, dsymutil::DebugMapObject &Obj);
1544d0ba668SFrederic Riss dsymutil::DebugMapObject denormalize(IO &IO);
1554d0ba668SFrederic Riss
1564d0ba668SFrederic Riss std::string Filename;
15762d72041SPavel Labath int64_t Timestamp;
1584d0ba668SFrederic Riss std::vector<dsymutil::DebugMapObject::YAMLSymbolMapping> Entries;
1594d0ba668SFrederic Riss };
1604d0ba668SFrederic Riss
1614d0ba668SFrederic Riss void MappingTraits<std::pair<std::string, DebugMapObject::SymbolMapping>>::
mapping(IO & io,std::pair<std::string,DebugMapObject::SymbolMapping> & s)1624d0ba668SFrederic Riss mapping(IO &io, std::pair<std::string, DebugMapObject::SymbolMapping> &s) {
1634d0ba668SFrederic Riss io.mapRequired("sym", s.first);
164d8c33dc2SFrederic Riss io.mapOptional("objAddr", s.second.ObjectAddress);
1654d0ba668SFrederic Riss io.mapRequired("binAddr", s.second.BinaryAddress);
1664d0ba668SFrederic Riss io.mapOptional("size", s.second.Size);
1674d0ba668SFrederic Riss }
1684d0ba668SFrederic Riss
mapping(IO & io,dsymutil::DebugMapObject & DMO)1694d0ba668SFrederic Riss void MappingTraits<dsymutil::DebugMapObject>::mapping(
1704d0ba668SFrederic Riss IO &io, dsymutil::DebugMapObject &DMO) {
1714d0ba668SFrederic Riss MappingNormalization<YamlDMO, dsymutil::DebugMapObject> Norm(io, DMO);
1724d0ba668SFrederic Riss io.mapRequired("filename", Norm->Filename);
1739ccfddc3SFrederic Riss io.mapOptional("timestamp", Norm->Timestamp);
1744d0ba668SFrederic Riss io.mapRequired("symbols", Norm->Entries);
1754d0ba668SFrederic Riss }
1764d0ba668SFrederic Riss
output(const Triple & val,void *,raw_ostream & out)1770ad18f88SEugene Zelenko void ScalarTraits<Triple>::output(const Triple &val, void *, raw_ostream &out) {
1784d0ba668SFrederic Riss out << val.str();
1794d0ba668SFrederic Riss }
1804d0ba668SFrederic Riss
input(StringRef scalar,void *,Triple & value)1814d0ba668SFrederic Riss StringRef ScalarTraits<Triple>::input(StringRef scalar, void *, Triple &value) {
1824d0ba668SFrederic Riss value = Triple(scalar);
1834d0ba668SFrederic Riss return StringRef();
1844d0ba668SFrederic Riss }
1854d0ba668SFrederic Riss
1864d0ba668SFrederic Riss size_t
size(IO & io,std::vector<std::unique_ptr<dsymutil::DebugMapObject>> & seq)1874d0ba668SFrederic Riss SequenceTraits<std::vector<std::unique_ptr<dsymutil::DebugMapObject>>>::size(
1884d0ba668SFrederic Riss IO &io, std::vector<std::unique_ptr<dsymutil::DebugMapObject>> &seq) {
1894d0ba668SFrederic Riss return seq.size();
1904d0ba668SFrederic Riss }
1914d0ba668SFrederic Riss
1924d0ba668SFrederic Riss dsymutil::DebugMapObject &
element(IO &,std::vector<std::unique_ptr<dsymutil::DebugMapObject>> & seq,size_t index)1934d0ba668SFrederic Riss SequenceTraits<std::vector<std::unique_ptr<dsymutil::DebugMapObject>>>::element(
1944d0ba668SFrederic Riss IO &, std::vector<std::unique_ptr<dsymutil::DebugMapObject>> &seq,
1954d0ba668SFrederic Riss size_t index) {
1964d0ba668SFrederic Riss if (index >= seq.size()) {
1974d0ba668SFrederic Riss seq.resize(index + 1);
1984d0ba668SFrederic Riss seq[index].reset(new dsymutil::DebugMapObject);
1994d0ba668SFrederic Riss }
2004d0ba668SFrederic Riss return *seq[index];
2014d0ba668SFrederic Riss }
2024d0ba668SFrederic Riss
mapping(IO & io,dsymutil::DebugMap & DM)2034d0ba668SFrederic Riss void MappingTraits<dsymutil::DebugMap>::mapping(IO &io,
2044d0ba668SFrederic Riss dsymutil::DebugMap &DM) {
2054d0ba668SFrederic Riss io.mapRequired("triple", DM.BinaryTriple);
2062c69d36dSFrederic Riss io.mapOptional("binary-path", DM.BinaryPath);
2074f5874a5SFrederic Riss if (void *Ctxt = io.getContext())
208a81e8814SFrederic Riss reinterpret_cast<YAMLContext *>(Ctxt)->BinaryTriple = DM.BinaryTriple;
209eb85c8fbSFrederic Riss io.mapOptional("objects", DM.Objects);
2104d0ba668SFrederic Riss }
2114d0ba668SFrederic Riss
mapping(IO & io,std::unique_ptr<dsymutil::DebugMap> & DM)2124d0ba668SFrederic Riss void MappingTraits<std::unique_ptr<dsymutil::DebugMap>>::mapping(
2134d0ba668SFrederic Riss IO &io, std::unique_ptr<dsymutil::DebugMap> &DM) {
2144d0ba668SFrederic Riss if (!DM)
2154d0ba668SFrederic Riss DM.reset(new DebugMap());
2164d0ba668SFrederic Riss io.mapRequired("triple", DM->BinaryTriple);
2172c69d36dSFrederic Riss io.mapOptional("binary-path", DM->BinaryPath);
2184f5874a5SFrederic Riss if (void *Ctxt = io.getContext())
219a81e8814SFrederic Riss reinterpret_cast<YAMLContext *>(Ctxt)->BinaryTriple = DM->BinaryTriple;
220eb85c8fbSFrederic Riss io.mapOptional("objects", DM->Objects);
2214d0ba668SFrederic Riss }
2224d0ba668SFrederic Riss
YamlDMO(IO & io,dsymutil::DebugMapObject & Obj)2234d0ba668SFrederic Riss MappingTraits<dsymutil::DebugMapObject>::YamlDMO::YamlDMO(
2244d0ba668SFrederic Riss IO &io, dsymutil::DebugMapObject &Obj) {
2254d0ba668SFrederic Riss Filename = Obj.Filename;
22662d72041SPavel Labath Timestamp = sys::toTimeT(Obj.getTimestamp());
2274d0ba668SFrederic Riss Entries.reserve(Obj.Symbols.size());
2284d0ba668SFrederic Riss for (auto &Entry : Obj.Symbols)
229adcd0268SBenjamin Kramer Entries.push_back(
230adcd0268SBenjamin Kramer std::make_pair(std::string(Entry.getKey()), Entry.getValue()));
2314d0ba668SFrederic Riss }
2324d0ba668SFrederic Riss
2334d0ba668SFrederic Riss dsymutil::DebugMapObject
denormalize(IO & IO)2344d0ba668SFrederic Riss MappingTraits<dsymutil::DebugMapObject>::YamlDMO::denormalize(IO &IO) {
2350be7acabSJonas Devlieghere BinaryHolder BinHolder(vfs::getRealFileSystem(), /* Verbose =*/false);
2364f5874a5SFrederic Riss const auto &Ctxt = *reinterpret_cast<YAMLContext *>(IO.getContext());
2374f5874a5SFrederic Riss SmallString<80> Path(Ctxt.PrependPath);
2384f5874a5SFrederic Riss StringMap<uint64_t> SymbolAddresses;
2394f5874a5SFrederic Riss
2404d0ba668SFrederic Riss sys::path::append(Path, Filename);
241a0857eaeSJonas Devlieghere
242a0857eaeSJonas Devlieghere auto ObjectEntry = BinHolder.getObjectEntry(Path);
243a0857eaeSJonas Devlieghere if (!ObjectEntry) {
244a0857eaeSJonas Devlieghere auto Err = ObjectEntry.takeError();
245a0857eaeSJonas Devlieghere WithColor::warning() << "Unable to open " << Path << " "
246a0857eaeSJonas Devlieghere << toString(std::move(Err)) << '\n';
247a0857eaeSJonas Devlieghere } else {
248a0857eaeSJonas Devlieghere auto Object = ObjectEntry->getObject(Ctxt.BinaryTriple);
249a0857eaeSJonas Devlieghere if (!Object) {
250a0857eaeSJonas Devlieghere auto Err = Object.takeError();
251a0857eaeSJonas Devlieghere WithColor::warning() << "Unable to open " << Path << " "
252a0857eaeSJonas Devlieghere << toString(std::move(Err)) << '\n';
253a0857eaeSJonas Devlieghere } else {
254a0857eaeSJonas Devlieghere for (const auto &Sym : Object->symbols()) {
255ff6a0b6aSXing GUO Expected<uint64_t> AddressOrErr = Sym.getValue();
256ff6a0b6aSXing GUO if (!AddressOrErr) {
257ff6a0b6aSXing GUO // TODO: Actually report errors helpfully.
258ff6a0b6aSXing GUO consumeError(AddressOrErr.takeError());
259ff6a0b6aSXing GUO continue;
260ff6a0b6aSXing GUO }
26181e8b7d9SKevin Enderby Expected<StringRef> Name = Sym.getName();
262ac00376aSvgxbj Expected<uint32_t> FlagsOrErr = Sym.getFlags();
263ac00376aSvgxbj if (!Name || !FlagsOrErr ||
264ac00376aSvgxbj (*FlagsOrErr & (SymbolRef::SF_Absolute | SymbolRef::SF_Common))) {
26581e8b7d9SKevin Enderby // TODO: Actually report errors helpfully.
266ac00376aSvgxbj if (!FlagsOrErr)
267ac00376aSvgxbj consumeError(FlagsOrErr.takeError());
26881e8b7d9SKevin Enderby if (!Name)
26981e8b7d9SKevin Enderby consumeError(Name.takeError());
2705d0c2ffaSRafael Espindola continue;
27181e8b7d9SKevin Enderby }
272ff6a0b6aSXing GUO SymbolAddresses[*Name] = *AddressOrErr;
2734f5874a5SFrederic Riss }
2744f5874a5SFrederic Riss }
275a0857eaeSJonas Devlieghere }
2764f5874a5SFrederic Riss
2778aedfde2SFrancis Ricci dsymutil::DebugMapObject Res(Path, sys::toTimePoint(Timestamp), MachO::N_OSO);
2784d0ba668SFrederic Riss for (auto &Entry : Entries) {
2794d0ba668SFrederic Riss auto &Mapping = Entry.second;
280d8c33dc2SFrederic Riss Optional<uint64_t> ObjAddress;
281d8c33dc2SFrederic Riss if (Mapping.ObjectAddress)
282d8c33dc2SFrederic Riss ObjAddress = *Mapping.ObjectAddress;
2834f5874a5SFrederic Riss auto AddressIt = SymbolAddresses.find(Entry.first);
2844f5874a5SFrederic Riss if (AddressIt != SymbolAddresses.end())
2854f5874a5SFrederic Riss ObjAddress = AddressIt->getValue();
2864f5874a5SFrederic Riss Res.addSymbol(Entry.first, ObjAddress, Mapping.BinaryAddress, Mapping.Size);
2874d0ba668SFrederic Riss }
2884d0ba668SFrederic Riss return Res;
2894d0ba668SFrederic Riss }
2900ad18f88SEugene Zelenko
2910ad18f88SEugene Zelenko } // end namespace yaml
2920ad18f88SEugene Zelenko } // end namespace llvm
293