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