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::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 118 return std::move(Res); 119 } 120 } 121 122 namespace yaml { 123 124 // Normalize/Denormalize between YAML and a DebugMapObject. 125 struct MappingTraits<dsymutil::DebugMapObject>::YamlDMO { 126 YamlDMO(IO &io) { Timestamp = 0; } 127 YamlDMO(IO &io, dsymutil::DebugMapObject &Obj); 128 dsymutil::DebugMapObject denormalize(IO &IO); 129 130 std::string Filename; 131 sys::TimeValue::SecondsType Timestamp; 132 std::vector<dsymutil::DebugMapObject::YAMLSymbolMapping> Entries; 133 }; 134 135 void MappingTraits<std::pair<std::string, DebugMapObject::SymbolMapping>>:: 136 mapping(IO &io, std::pair<std::string, DebugMapObject::SymbolMapping> &s) { 137 io.mapRequired("sym", s.first); 138 io.mapRequired("objAddr", s.second.ObjectAddress); 139 io.mapRequired("binAddr", s.second.BinaryAddress); 140 io.mapOptional("size", s.second.Size); 141 } 142 143 void MappingTraits<dsymutil::DebugMapObject>::mapping( 144 IO &io, dsymutil::DebugMapObject &DMO) { 145 MappingNormalization<YamlDMO, dsymutil::DebugMapObject> Norm(io, DMO); 146 io.mapRequired("filename", Norm->Filename); 147 io.mapOptional("timestamp", Norm->Timestamp); 148 io.mapRequired("symbols", Norm->Entries); 149 } 150 151 void ScalarTraits<Triple>::output(const Triple &val, void *, 152 llvm::raw_ostream &out) { 153 out << val.str(); 154 } 155 156 StringRef ScalarTraits<Triple>::input(StringRef scalar, void *, Triple &value) { 157 value = Triple(scalar); 158 return StringRef(); 159 } 160 161 size_t 162 SequenceTraits<std::vector<std::unique_ptr<dsymutil::DebugMapObject>>>::size( 163 IO &io, std::vector<std::unique_ptr<dsymutil::DebugMapObject>> &seq) { 164 return seq.size(); 165 } 166 167 dsymutil::DebugMapObject & 168 SequenceTraits<std::vector<std::unique_ptr<dsymutil::DebugMapObject>>>::element( 169 IO &, std::vector<std::unique_ptr<dsymutil::DebugMapObject>> &seq, 170 size_t index) { 171 if (index >= seq.size()) { 172 seq.resize(index + 1); 173 seq[index].reset(new dsymutil::DebugMapObject); 174 } 175 return *seq[index]; 176 } 177 178 void MappingTraits<dsymutil::DebugMap>::mapping(IO &io, 179 dsymutil::DebugMap &DM) { 180 io.mapRequired("triple", DM.BinaryTriple); 181 if (void *Ctxt = io.getContext()) 182 reinterpret_cast<YAMLContext *>(Ctxt)->BinaryTriple = DM.BinaryTriple; 183 io.mapOptional("objects", DM.Objects); 184 } 185 186 void MappingTraits<std::unique_ptr<dsymutil::DebugMap>>::mapping( 187 IO &io, std::unique_ptr<dsymutil::DebugMap> &DM) { 188 if (!DM) 189 DM.reset(new DebugMap()); 190 io.mapRequired("triple", DM->BinaryTriple); 191 if (void *Ctxt = io.getContext()) 192 reinterpret_cast<YAMLContext *>(Ctxt)->BinaryTriple = DM->BinaryTriple; 193 io.mapOptional("objects", DM->Objects); 194 } 195 196 MappingTraits<dsymutil::DebugMapObject>::YamlDMO::YamlDMO( 197 IO &io, dsymutil::DebugMapObject &Obj) { 198 Filename = Obj.Filename; 199 Timestamp = Obj.getTimestamp().toEpochTime(); 200 Entries.reserve(Obj.Symbols.size()); 201 for (auto &Entry : Obj.Symbols) 202 Entries.push_back(std::make_pair(Entry.getKey(), Entry.getValue())); 203 } 204 205 dsymutil::DebugMapObject 206 MappingTraits<dsymutil::DebugMapObject>::YamlDMO::denormalize(IO &IO) { 207 BinaryHolder BinHolder(/* Verbose =*/false); 208 const auto &Ctxt = *reinterpret_cast<YAMLContext *>(IO.getContext()); 209 SmallString<80> Path(Ctxt.PrependPath); 210 StringMap<uint64_t> SymbolAddresses; 211 212 sys::path::append(Path, Filename); 213 auto ErrOrObjectFiles = BinHolder.GetObjectFiles(Path); 214 if (auto EC = ErrOrObjectFiles.getError()) { 215 llvm::errs() << "warning: Unable to open " << Path << " " << EC.message() 216 << '\n'; 217 } else if (auto ErrOrObjectFile = BinHolder.Get(Ctxt.BinaryTriple)) { 218 // Rewrite the object file symbol addresses in the debug map. The 219 // YAML input is mainly used to test llvm-dsymutil without 220 // requiring binaries checked-in. If we generate the object files 221 // during the test, we can't hardcode the symbols addresses, so 222 // look them up here and rewrite them. 223 for (const auto &Sym : ErrOrObjectFile->symbols()) { 224 uint64_t Address = Sym.getValue(); 225 ErrorOr<StringRef> Name = Sym.getName(); 226 if (!Name) 227 continue; 228 SymbolAddresses[*Name] = Address; 229 } 230 } 231 232 sys::TimeValue TV; 233 TV.fromEpochTime(Timestamp); 234 dsymutil::DebugMapObject Res(Path, TV); 235 for (auto &Entry : Entries) { 236 auto &Mapping = Entry.second; 237 uint64_t ObjAddress = Mapping.ObjectAddress; 238 auto AddressIt = SymbolAddresses.find(Entry.first); 239 if (AddressIt != SymbolAddresses.end()) 240 ObjAddress = AddressIt->getValue(); 241 Res.addSymbol(Entry.first, ObjAddress, Mapping.BinaryAddress, Mapping.Size); 242 } 243 return Res; 244 } 245 } 246 } 247