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