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