1 //===- tools/dsymutil/DebugMap.cpp - Generic debug map representation -----===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "DebugMap.h" 11 #include "BinaryHolder.h" 12 #include "llvm/ADT/Optional.h" 13 #include "llvm/ADT/SmallString.h" 14 #include "llvm/ADT/StringMap.h" 15 #include "llvm/ADT/StringRef.h" 16 #include "llvm/ADT/Triple.h" 17 #include "llvm/ADT/iterator_range.h" 18 #include "llvm/BinaryFormat/MachO.h" 19 #include "llvm/Object/ObjectFile.h" 20 #include "llvm/Support/Chrono.h" 21 #include "llvm/Support/Error.h" 22 #include "llvm/Support/Format.h" 23 #include "llvm/Support/MemoryBuffer.h" 24 #include "llvm/Support/Path.h" 25 #include "llvm/Support/WithColor.h" 26 #include "llvm/Support/YAMLTraits.h" 27 #include "llvm/Support/raw_ostream.h" 28 #include <algorithm> 29 #include <cinttypes> 30 #include <cstdint> 31 #include <memory> 32 #include <string> 33 #include <utility> 34 #include <vector> 35 36 namespace llvm { 37 38 namespace dsymutil { 39 40 using namespace llvm::object; 41 42 DebugMapObject::DebugMapObject(StringRef ObjectFilename, 43 sys::TimePoint<std::chrono::seconds> Timestamp, 44 uint8_t Type) 45 : Filename(ObjectFilename), Timestamp(Timestamp), Type(Type) {} 46 47 bool DebugMapObject::addSymbol(StringRef Name, Optional<uint64_t> ObjectAddress, 48 uint64_t LinkedAddress, uint32_t Size) { 49 auto InsertResult = Symbols.insert( 50 std::make_pair(Name, SymbolMapping(ObjectAddress, LinkedAddress, Size))); 51 52 if (ObjectAddress && InsertResult.second) 53 AddressToMapping[*ObjectAddress] = &*InsertResult.first; 54 return InsertResult.second; 55 } 56 57 void DebugMapObject::print(raw_ostream &OS) const { 58 OS << getObjectFilename() << ":\n"; 59 // Sort the symbols in alphabetical order, like llvm-nm (and to get 60 // deterministic output for testing). 61 using Entry = std::pair<StringRef, SymbolMapping>; 62 std::vector<Entry> Entries; 63 Entries.reserve(Symbols.getNumItems()); 64 for (const auto &Sym : make_range(Symbols.begin(), Symbols.end())) 65 Entries.push_back(std::make_pair(Sym.getKey(), Sym.getValue())); 66 llvm::sort( 67 Entries.begin(), Entries.end(), 68 [](const Entry &LHS, const Entry &RHS) { return LHS.first < RHS.first; }); 69 for (const auto &Sym : Entries) { 70 if (Sym.second.ObjectAddress) 71 OS << format("\t%016" PRIx64, uint64_t(*Sym.second.ObjectAddress)); 72 else 73 OS << "\t????????????????"; 74 OS << format(" => %016" PRIx64 "+0x%x\t%s\n", 75 uint64_t(Sym.second.BinaryAddress), uint32_t(Sym.second.Size), 76 Sym.first.data()); 77 } 78 OS << '\n'; 79 } 80 81 #ifndef NDEBUG 82 void DebugMapObject::dump() const { print(errs()); } 83 #endif 84 85 DebugMapObject & 86 DebugMap::addDebugMapObject(StringRef ObjectFilePath, 87 sys::TimePoint<std::chrono::seconds> Timestamp, 88 uint8_t Type) { 89 Objects.emplace_back(new DebugMapObject(ObjectFilePath, Timestamp, Type)); 90 return *Objects.back(); 91 } 92 93 const DebugMapObject::DebugMapEntry * 94 DebugMapObject::lookupSymbol(StringRef SymbolName) const { 95 StringMap<SymbolMapping>::const_iterator Sym = Symbols.find(SymbolName); 96 if (Sym == Symbols.end()) 97 return nullptr; 98 return &*Sym; 99 } 100 101 const DebugMapObject::DebugMapEntry * 102 DebugMapObject::lookupObjectAddress(uint64_t Address) const { 103 auto Mapping = AddressToMapping.find(Address); 104 if (Mapping == AddressToMapping.end()) 105 return nullptr; 106 return Mapping->getSecond(); 107 } 108 109 void DebugMap::print(raw_ostream &OS) const { 110 yaml::Output yout(OS, /* Ctxt = */ nullptr, /* WrapColumn = */ 0); 111 yout << const_cast<DebugMap &>(*this); 112 } 113 114 #ifndef NDEBUG 115 void DebugMap::dump() const { print(errs()); } 116 #endif 117 118 namespace { 119 120 struct YAMLContext { 121 StringRef PrependPath; 122 Triple BinaryTriple; 123 }; 124 125 } // end anonymous namespace 126 127 ErrorOr<std::vector<std::unique_ptr<DebugMap>>> 128 DebugMap::parseYAMLDebugMap(StringRef InputFile, StringRef PrependPath, 129 bool Verbose) { 130 auto ErrOrFile = MemoryBuffer::getFileOrSTDIN(InputFile); 131 if (auto Err = ErrOrFile.getError()) 132 return Err; 133 134 YAMLContext Ctxt; 135 136 Ctxt.PrependPath = PrependPath; 137 138 std::unique_ptr<DebugMap> Res; 139 yaml::Input yin((*ErrOrFile)->getBuffer(), &Ctxt); 140 yin >> Res; 141 142 if (auto EC = yin.error()) 143 return EC; 144 std::vector<std::unique_ptr<DebugMap>> Result; 145 Result.push_back(std::move(Res)); 146 return std::move(Result); 147 } 148 149 } // end namespace dsymutil 150 151 namespace yaml { 152 153 // Normalize/Denormalize between YAML and a DebugMapObject. 154 struct MappingTraits<dsymutil::DebugMapObject>::YamlDMO { 155 YamlDMO(IO &io) { Timestamp = 0; } 156 YamlDMO(IO &io, dsymutil::DebugMapObject &Obj); 157 dsymutil::DebugMapObject denormalize(IO &IO); 158 159 std::string Filename; 160 int64_t Timestamp; 161 std::vector<dsymutil::DebugMapObject::YAMLSymbolMapping> Entries; 162 }; 163 164 void MappingTraits<std::pair<std::string, DebugMapObject::SymbolMapping>>:: 165 mapping(IO &io, std::pair<std::string, DebugMapObject::SymbolMapping> &s) { 166 io.mapRequired("sym", s.first); 167 io.mapOptional("objAddr", s.second.ObjectAddress); 168 io.mapRequired("binAddr", s.second.BinaryAddress); 169 io.mapOptional("size", s.second.Size); 170 } 171 172 void MappingTraits<dsymutil::DebugMapObject>::mapping( 173 IO &io, dsymutil::DebugMapObject &DMO) { 174 MappingNormalization<YamlDMO, dsymutil::DebugMapObject> Norm(io, DMO); 175 io.mapRequired("filename", Norm->Filename); 176 io.mapOptional("timestamp", Norm->Timestamp); 177 io.mapRequired("symbols", Norm->Entries); 178 } 179 180 void ScalarTraits<Triple>::output(const Triple &val, void *, raw_ostream &out) { 181 out << val.str(); 182 } 183 184 StringRef ScalarTraits<Triple>::input(StringRef scalar, void *, Triple &value) { 185 value = Triple(scalar); 186 return StringRef(); 187 } 188 189 size_t 190 SequenceTraits<std::vector<std::unique_ptr<dsymutil::DebugMapObject>>>::size( 191 IO &io, std::vector<std::unique_ptr<dsymutil::DebugMapObject>> &seq) { 192 return seq.size(); 193 } 194 195 dsymutil::DebugMapObject & 196 SequenceTraits<std::vector<std::unique_ptr<dsymutil::DebugMapObject>>>::element( 197 IO &, std::vector<std::unique_ptr<dsymutil::DebugMapObject>> &seq, 198 size_t index) { 199 if (index >= seq.size()) { 200 seq.resize(index + 1); 201 seq[index].reset(new dsymutil::DebugMapObject); 202 } 203 return *seq[index]; 204 } 205 206 void MappingTraits<dsymutil::DebugMap>::mapping(IO &io, 207 dsymutil::DebugMap &DM) { 208 io.mapRequired("triple", DM.BinaryTriple); 209 io.mapOptional("binary-path", DM.BinaryPath); 210 if (void *Ctxt = io.getContext()) 211 reinterpret_cast<YAMLContext *>(Ctxt)->BinaryTriple = DM.BinaryTriple; 212 io.mapOptional("objects", DM.Objects); 213 } 214 215 void MappingTraits<std::unique_ptr<dsymutil::DebugMap>>::mapping( 216 IO &io, std::unique_ptr<dsymutil::DebugMap> &DM) { 217 if (!DM) 218 DM.reset(new DebugMap()); 219 io.mapRequired("triple", DM->BinaryTriple); 220 io.mapOptional("binary-path", DM->BinaryPath); 221 if (void *Ctxt = io.getContext()) 222 reinterpret_cast<YAMLContext *>(Ctxt)->BinaryTriple = DM->BinaryTriple; 223 io.mapOptional("objects", DM->Objects); 224 } 225 226 MappingTraits<dsymutil::DebugMapObject>::YamlDMO::YamlDMO( 227 IO &io, dsymutil::DebugMapObject &Obj) { 228 Filename = Obj.Filename; 229 Timestamp = sys::toTimeT(Obj.getTimestamp()); 230 Entries.reserve(Obj.Symbols.size()); 231 for (auto &Entry : Obj.Symbols) 232 Entries.push_back(std::make_pair(Entry.getKey(), Entry.getValue())); 233 } 234 235 dsymutil::DebugMapObject 236 MappingTraits<dsymutil::DebugMapObject>::YamlDMO::denormalize(IO &IO) { 237 BinaryHolder BinHolder(/* Verbose =*/false); 238 const auto &Ctxt = *reinterpret_cast<YAMLContext *>(IO.getContext()); 239 SmallString<80> Path(Ctxt.PrependPath); 240 StringMap<uint64_t> SymbolAddresses; 241 242 sys::path::append(Path, Filename); 243 244 auto ObjectEntry = BinHolder.getObjectEntry(Path); 245 if (!ObjectEntry) { 246 auto Err = ObjectEntry.takeError(); 247 WithColor::warning() << "Unable to open " << Path << " " 248 << toString(std::move(Err)) << '\n'; 249 } else { 250 auto Object = ObjectEntry->getObject(Ctxt.BinaryTriple); 251 if (!Object) { 252 auto Err = Object.takeError(); 253 WithColor::warning() << "Unable to open " << Path << " " 254 << toString(std::move(Err)) << '\n'; 255 } else { 256 for (const auto &Sym : Object->symbols()) { 257 uint64_t Address = Sym.getValue(); 258 Expected<StringRef> Name = Sym.getName(); 259 if (!Name || (Sym.getFlags() & 260 (SymbolRef::SF_Absolute | SymbolRef::SF_Common))) { 261 // TODO: Actually report errors helpfully. 262 if (!Name) 263 consumeError(Name.takeError()); 264 continue; 265 } 266 SymbolAddresses[*Name] = Address; 267 } 268 } 269 } 270 271 dsymutil::DebugMapObject Res(Path, sys::toTimePoint(Timestamp), MachO::N_OSO); 272 for (auto &Entry : Entries) { 273 auto &Mapping = Entry.second; 274 Optional<uint64_t> ObjAddress; 275 if (Mapping.ObjectAddress) 276 ObjAddress = *Mapping.ObjectAddress; 277 auto AddressIt = SymbolAddresses.find(Entry.first); 278 if (AddressIt != SymbolAddresses.end()) 279 ObjAddress = AddressIt->getValue(); 280 Res.addSymbol(Entry.first, ObjAddress, Mapping.BinaryAddress, Mapping.Size); 281 } 282 return Res; 283 } 284 285 } // end namespace yaml 286 } // end namespace llvm 287