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