1 //===- tools/dsymutil/DebugMap.cpp - Generic debug map representation -----===// 2 // 3 // The LLVM Linker 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 #include "DebugMap.h" 10 #include "BinaryHolder.h" 11 #include "llvm/ADT/STLExtras.h" 12 #include "llvm/ADT/iterator_range.h" 13 #include "llvm/Support/DataTypes.h" 14 #include "llvm/Support/Format.h" 15 #include "llvm/Support/raw_ostream.h" 16 #include <algorithm> 17 18 namespace llvm { 19 namespace dsymutil { 20 21 using namespace llvm::object; 22 23 DebugMapObject::DebugMapObject(StringRef ObjectFilename, 24 sys::TimeValue Timestamp) 25 : Filename(ObjectFilename), Timestamp(Timestamp) {} 26 27 bool DebugMapObject::addSymbol(StringRef Name, uint64_t ObjectAddress, 28 uint64_t LinkedAddress, uint32_t Size) { 29 auto InsertResult = Symbols.insert( 30 std::make_pair(Name, SymbolMapping(ObjectAddress, LinkedAddress, Size))); 31 32 if (InsertResult.second) 33 AddressToMapping[ObjectAddress] = &*InsertResult.first; 34 return InsertResult.second; 35 } 36 37 void DebugMapObject::print(raw_ostream &OS) const { 38 OS << getObjectFilename() << ":\n"; 39 // Sort the symbols in alphabetical order, like llvm-nm (and to get 40 // deterministic output for testing). 41 typedef std::pair<StringRef, SymbolMapping> Entry; 42 std::vector<Entry> Entries; 43 Entries.reserve(Symbols.getNumItems()); 44 for (const auto &Sym : make_range(Symbols.begin(), Symbols.end())) 45 Entries.push_back(std::make_pair(Sym.getKey(), Sym.getValue())); 46 std::sort( 47 Entries.begin(), Entries.end(), 48 [](const Entry &LHS, const Entry &RHS) { return LHS.first < RHS.first; }); 49 for (const auto &Sym : Entries) { 50 OS << format("\t%016" PRIx64 " => %016" PRIx64 "+0x%x\t%s\n", 51 uint64_t(Sym.second.ObjectAddress), 52 uint64_t(Sym.second.BinaryAddress), uint32_t(Sym.second.Size), 53 Sym.first.data()); 54 } 55 OS << '\n'; 56 } 57 58 #ifndef NDEBUG 59 void DebugMapObject::dump() const { print(errs()); } 60 #endif 61 62 DebugMapObject &DebugMap::addDebugMapObject(StringRef ObjectFilePath, 63 sys::TimeValue Timestamp) { 64 Objects.emplace_back(new DebugMapObject(ObjectFilePath, Timestamp)); 65 return *Objects.back(); 66 } 67 68 const DebugMapObject::DebugMapEntry * 69 DebugMapObject::lookupSymbol(StringRef SymbolName) const { 70 StringMap<SymbolMapping>::const_iterator Sym = Symbols.find(SymbolName); 71 if (Sym == Symbols.end()) 72 return nullptr; 73 return &*Sym; 74 } 75 76 const DebugMapObject::DebugMapEntry * 77 DebugMapObject::lookupObjectAddress(uint64_t Address) const { 78 auto Mapping = AddressToMapping.find(Address); 79 if (Mapping == AddressToMapping.end()) 80 return nullptr; 81 return Mapping->getSecond(); 82 } 83 84 void DebugMap::print(raw_ostream &OS) const { 85 yaml::Output yout(OS, /* Ctxt = */ nullptr, /* WrapColumn = */ 0); 86 yout << const_cast<DebugMap &>(*this); 87 } 88 89 #ifndef NDEBUG 90 void DebugMap::dump() const { print(errs()); } 91 #endif 92 93 namespace { 94 struct YAMLContext { 95 StringRef PrependPath; 96 Triple BinaryTriple; 97 }; 98 } 99 100 ErrorOr<std::vector<std::unique_ptr<DebugMap>>> 101 DebugMap::parseYAMLDebugMap(StringRef InputFile, StringRef PrependPath, 102 bool Verbose) { 103 auto ErrOrFile = MemoryBuffer::getFileOrSTDIN(InputFile); 104 if (auto Err = ErrOrFile.getError()) 105 return Err; 106 107 YAMLContext Ctxt; 108 109 Ctxt.PrependPath = PrependPath; 110 111 std::unique_ptr<DebugMap> Res; 112 yaml::Input yin((*ErrOrFile)->getBuffer(), &Ctxt); 113 yin >> Res; 114 115 if (auto EC = yin.error()) 116 return EC; 117 std::vector<std::unique_ptr<DebugMap>> Result; 118 Result.push_back(std::move(Res)); 119 return std::move(Result); 120 } 121 } 122 123 namespace yaml { 124 125 // Normalize/Denormalize between YAML and a DebugMapObject. 126 struct MappingTraits<dsymutil::DebugMapObject>::YamlDMO { 127 YamlDMO(IO &io) { Timestamp = 0; } 128 YamlDMO(IO &io, dsymutil::DebugMapObject &Obj); 129 dsymutil::DebugMapObject denormalize(IO &IO); 130 131 std::string Filename; 132 sys::TimeValue::SecondsType Timestamp; 133 std::vector<dsymutil::DebugMapObject::YAMLSymbolMapping> Entries; 134 }; 135 136 void MappingTraits<std::pair<std::string, DebugMapObject::SymbolMapping>>:: 137 mapping(IO &io, std::pair<std::string, DebugMapObject::SymbolMapping> &s) { 138 io.mapRequired("sym", s.first); 139 io.mapRequired("objAddr", s.second.ObjectAddress); 140 io.mapRequired("binAddr", s.second.BinaryAddress); 141 io.mapOptional("size", s.second.Size); 142 } 143 144 void MappingTraits<dsymutil::DebugMapObject>::mapping( 145 IO &io, dsymutil::DebugMapObject &DMO) { 146 MappingNormalization<YamlDMO, dsymutil::DebugMapObject> Norm(io, DMO); 147 io.mapRequired("filename", Norm->Filename); 148 io.mapOptional("timestamp", Norm->Timestamp); 149 io.mapRequired("symbols", Norm->Entries); 150 } 151 152 void ScalarTraits<Triple>::output(const Triple &val, void *, 153 llvm::raw_ostream &out) { 154 out << val.str(); 155 } 156 157 StringRef ScalarTraits<Triple>::input(StringRef scalar, void *, Triple &value) { 158 value = Triple(scalar); 159 return StringRef(); 160 } 161 162 size_t 163 SequenceTraits<std::vector<std::unique_ptr<dsymutil::DebugMapObject>>>::size( 164 IO &io, std::vector<std::unique_ptr<dsymutil::DebugMapObject>> &seq) { 165 return seq.size(); 166 } 167 168 dsymutil::DebugMapObject & 169 SequenceTraits<std::vector<std::unique_ptr<dsymutil::DebugMapObject>>>::element( 170 IO &, std::vector<std::unique_ptr<dsymutil::DebugMapObject>> &seq, 171 size_t index) { 172 if (index >= seq.size()) { 173 seq.resize(index + 1); 174 seq[index].reset(new dsymutil::DebugMapObject); 175 } 176 return *seq[index]; 177 } 178 179 void MappingTraits<dsymutil::DebugMap>::mapping(IO &io, 180 dsymutil::DebugMap &DM) { 181 io.mapRequired("triple", DM.BinaryTriple); 182 io.mapOptional("binary-path", DM.BinaryPath); 183 if (void *Ctxt = io.getContext()) 184 reinterpret_cast<YAMLContext *>(Ctxt)->BinaryTriple = DM.BinaryTriple; 185 io.mapOptional("objects", DM.Objects); 186 } 187 188 void MappingTraits<std::unique_ptr<dsymutil::DebugMap>>::mapping( 189 IO &io, std::unique_ptr<dsymutil::DebugMap> &DM) { 190 if (!DM) 191 DM.reset(new DebugMap()); 192 io.mapRequired("triple", DM->BinaryTriple); 193 io.mapOptional("binary-path", DM->BinaryPath); 194 if (void *Ctxt = io.getContext()) 195 reinterpret_cast<YAMLContext *>(Ctxt)->BinaryTriple = DM->BinaryTriple; 196 io.mapOptional("objects", DM->Objects); 197 } 198 199 MappingTraits<dsymutil::DebugMapObject>::YamlDMO::YamlDMO( 200 IO &io, dsymutil::DebugMapObject &Obj) { 201 Filename = Obj.Filename; 202 Timestamp = Obj.getTimestamp().toEpochTime(); 203 Entries.reserve(Obj.Symbols.size()); 204 for (auto &Entry : Obj.Symbols) 205 Entries.push_back(std::make_pair(Entry.getKey(), Entry.getValue())); 206 } 207 208 dsymutil::DebugMapObject 209 MappingTraits<dsymutil::DebugMapObject>::YamlDMO::denormalize(IO &IO) { 210 BinaryHolder BinHolder(/* Verbose =*/false); 211 const auto &Ctxt = *reinterpret_cast<YAMLContext *>(IO.getContext()); 212 SmallString<80> Path(Ctxt.PrependPath); 213 StringMap<uint64_t> SymbolAddresses; 214 215 sys::path::append(Path, Filename); 216 auto ErrOrObjectFiles = BinHolder.GetObjectFiles(Path); 217 if (auto EC = ErrOrObjectFiles.getError()) { 218 llvm::errs() << "warning: Unable to open " << Path << " " << EC.message() 219 << '\n'; 220 } else if (auto ErrOrObjectFile = BinHolder.Get(Ctxt.BinaryTriple)) { 221 // Rewrite the object file symbol addresses in the debug map. The 222 // YAML input is mainly used to test llvm-dsymutil without 223 // requiring binaries checked-in. If we generate the object files 224 // during the test, we can't hardcode the symbols addresses, so 225 // look them up here and rewrite them. 226 for (const auto &Sym : ErrOrObjectFile->symbols()) { 227 uint64_t Address = Sym.getValue(); 228 ErrorOr<StringRef> Name = Sym.getName(); 229 if (!Name) 230 continue; 231 SymbolAddresses[*Name] = Address; 232 } 233 } 234 235 sys::TimeValue TV; 236 TV.fromEpochTime(Timestamp); 237 dsymutil::DebugMapObject Res(Path, TV); 238 for (auto &Entry : Entries) { 239 auto &Mapping = Entry.second; 240 uint64_t ObjAddress = Mapping.ObjectAddress; 241 auto AddressIt = SymbolAddresses.find(Entry.first); 242 if (AddressIt != SymbolAddresses.end()) 243 ObjAddress = AddressIt->getValue(); 244 Res.addSymbol(Entry.first, ObjAddress, Mapping.BinaryAddress, Mapping.Size); 245 } 246 return Res; 247 } 248 } 249 } 250