1 //===- tools/dsymutil/MachODebugMapParser.cpp - Parse STABS debug maps ----===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "BinaryHolder.h" 10 #include "DebugMap.h" 11 #include "MachOUtils.h" 12 #include "llvm/ADT/Optional.h" 13 #include "llvm/ADT/SmallSet.h" 14 #include "llvm/Object/MachO.h" 15 #include "llvm/Support/Path.h" 16 #include "llvm/Support/WithColor.h" 17 #include "llvm/Support/raw_ostream.h" 18 #include <vector> 19 20 namespace { 21 using namespace llvm; 22 using namespace llvm::dsymutil; 23 using namespace llvm::object; 24 25 class MachODebugMapParser { 26 public: 27 MachODebugMapParser(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, 28 StringRef BinaryPath, ArrayRef<std::string> Archs, 29 StringRef PathPrefix = "", 30 bool PaperTrailWarnings = false, bool Verbose = false) 31 : BinaryPath(std::string(BinaryPath)), Archs(Archs.begin(), Archs.end()), 32 PathPrefix(std::string(PathPrefix)), 33 PaperTrailWarnings(PaperTrailWarnings), BinHolder(VFS, Verbose), 34 CurrentDebugMapObject(nullptr) {} 35 36 /// Parses and returns the DebugMaps of the input binary. The binary contains 37 /// multiple maps in case it is a universal binary. 38 /// \returns an error in case the provided BinaryPath doesn't exist 39 /// or isn't of a supported type. 40 ErrorOr<std::vector<std::unique_ptr<DebugMap>>> parse(); 41 42 /// Walk the symbol table and dump it. 43 bool dumpStab(); 44 45 private: 46 std::string BinaryPath; 47 SmallVector<StringRef, 1> Archs; 48 std::string PathPrefix; 49 bool PaperTrailWarnings; 50 51 /// Owns the MemoryBuffer for the main binary. 52 BinaryHolder BinHolder; 53 /// Map of the binary symbol addresses. 54 StringMap<uint64_t> MainBinarySymbolAddresses; 55 StringRef MainBinaryStrings; 56 /// The constructed DebugMap. 57 std::unique_ptr<DebugMap> Result; 58 /// List of common symbols that need to be added to the debug map. 59 std::vector<std::string> CommonSymbols; 60 61 /// Map of the currently processed object file symbol addresses. 62 StringMap<Optional<uint64_t>> CurrentObjectAddresses; 63 64 /// Lazily computed map of symbols aliased to the processed object file. 65 StringMap<Optional<uint64_t>> CurrentObjectAliasMap; 66 67 /// If CurrentObjectAliasMap has been computed for a given address. 68 SmallSet<uint64_t, 4> SeenAliasValues; 69 70 /// Element of the debug map corresponding to the current object file. 71 DebugMapObject *CurrentDebugMapObject; 72 73 /// Holds function info while function scope processing. 74 const char *CurrentFunctionName; 75 uint64_t CurrentFunctionAddress; 76 77 std::unique_ptr<DebugMap> parseOneBinary(const MachOObjectFile &MainBinary, 78 StringRef BinaryPath); 79 80 void 81 switchToNewDebugMapObject(StringRef Filename, 82 sys::TimePoint<std::chrono::seconds> Timestamp); 83 void resetParserState(); 84 uint64_t getMainBinarySymbolAddress(StringRef Name); 85 std::vector<StringRef> getMainBinarySymbolNames(uint64_t Value); 86 void loadMainBinarySymbols(const MachOObjectFile &MainBinary); 87 void loadCurrentObjectFileSymbols(const object::MachOObjectFile &Obj); 88 void handleStabSymbolTableEntry(uint32_t StringIndex, uint8_t Type, 89 uint8_t SectionIndex, uint16_t Flags, 90 uint64_t Value); 91 92 template <typename STEType> void handleStabDebugMapEntry(const STEType &STE) { 93 handleStabSymbolTableEntry(STE.n_strx, STE.n_type, STE.n_sect, STE.n_desc, 94 STE.n_value); 95 } 96 97 void addCommonSymbols(); 98 99 /// Dump the symbol table output header. 100 void dumpSymTabHeader(raw_ostream &OS, StringRef Arch); 101 102 /// Dump the contents of nlist entries. 103 void dumpSymTabEntry(raw_ostream &OS, uint64_t Index, uint32_t StringIndex, 104 uint8_t Type, uint8_t SectionIndex, uint16_t Flags, 105 uint64_t Value); 106 107 template <typename STEType> 108 void dumpSymTabEntry(raw_ostream &OS, uint64_t Index, const STEType &STE) { 109 dumpSymTabEntry(OS, Index, STE.n_strx, STE.n_type, STE.n_sect, STE.n_desc, 110 STE.n_value); 111 } 112 void dumpOneBinaryStab(const MachOObjectFile &MainBinary, 113 StringRef BinaryPath); 114 115 void Warning(const Twine &Msg, StringRef File = StringRef()) { 116 WithColor::warning() << "(" 117 << MachOUtils::getArchName( 118 Result->getTriple().getArchName()) 119 << ") " << File << " " << Msg << "\n"; 120 121 if (PaperTrailWarnings) { 122 if (!File.empty()) 123 Result->addDebugMapObject(File, sys::TimePoint<std::chrono::seconds>()); 124 if (Result->end() != Result->begin()) 125 (*--Result->end())->addWarning(Msg.str()); 126 } 127 } 128 }; 129 130 } // anonymous namespace 131 132 /// Reset the parser state corresponding to the current object 133 /// file. This is to be called after an object file is finished 134 /// processing. 135 void MachODebugMapParser::resetParserState() { 136 CommonSymbols.clear(); 137 CurrentObjectAddresses.clear(); 138 CurrentObjectAliasMap.clear(); 139 SeenAliasValues.clear(); 140 CurrentDebugMapObject = nullptr; 141 } 142 143 /// Commons symbols won't show up in the symbol map but might need to be 144 /// relocated. We can add them to the symbol table ourselves by combining the 145 /// information in the object file (the symbol name) and the main binary (the 146 /// address). 147 void MachODebugMapParser::addCommonSymbols() { 148 for (auto &CommonSymbol : CommonSymbols) { 149 uint64_t CommonAddr = getMainBinarySymbolAddress(CommonSymbol); 150 if (CommonAddr == 0) { 151 // The main binary doesn't have an address for the given symbol. 152 continue; 153 } 154 if (!CurrentDebugMapObject->addSymbol(CommonSymbol, None /*ObjectAddress*/, 155 CommonAddr, 0 /*size*/)) { 156 // The symbol is already present. 157 continue; 158 } 159 } 160 } 161 162 /// Create a new DebugMapObject. This function resets the state of the 163 /// parser that was referring to the last object file and sets 164 /// everything up to add symbols to the new one. 165 void MachODebugMapParser::switchToNewDebugMapObject( 166 StringRef Filename, sys::TimePoint<std::chrono::seconds> Timestamp) { 167 addCommonSymbols(); 168 resetParserState(); 169 170 SmallString<80> Path(PathPrefix); 171 sys::path::append(Path, Filename); 172 173 auto ObjectEntry = BinHolder.getObjectEntry(Path, Timestamp); 174 if (!ObjectEntry) { 175 auto Err = ObjectEntry.takeError(); 176 Warning("unable to open object file: " + toString(std::move(Err)), 177 Path.str()); 178 return; 179 } 180 181 auto Object = ObjectEntry->getObjectAs<MachOObjectFile>(Result->getTriple()); 182 if (!Object) { 183 auto Err = Object.takeError(); 184 Warning("unable to open object file: " + toString(std::move(Err)), 185 Path.str()); 186 return; 187 } 188 189 CurrentDebugMapObject = 190 &Result->addDebugMapObject(Path, Timestamp, MachO::N_OSO); 191 loadCurrentObjectFileSymbols(*Object); 192 } 193 194 static std::string getArchName(const object::MachOObjectFile &Obj) { 195 Triple T = Obj.getArchTriple(); 196 return std::string(T.getArchName()); 197 } 198 199 std::unique_ptr<DebugMap> 200 MachODebugMapParser::parseOneBinary(const MachOObjectFile &MainBinary, 201 StringRef BinaryPath) { 202 loadMainBinarySymbols(MainBinary); 203 ArrayRef<uint8_t> UUID = MainBinary.getUuid(); 204 Result = 205 std::make_unique<DebugMap>(MainBinary.getArchTriple(), BinaryPath, UUID); 206 MainBinaryStrings = MainBinary.getStringTableData(); 207 for (const SymbolRef &Symbol : MainBinary.symbols()) { 208 const DataRefImpl &DRI = Symbol.getRawDataRefImpl(); 209 if (MainBinary.is64Bit()) 210 handleStabDebugMapEntry(MainBinary.getSymbol64TableEntry(DRI)); 211 else 212 handleStabDebugMapEntry(MainBinary.getSymbolTableEntry(DRI)); 213 } 214 215 resetParserState(); 216 return std::move(Result); 217 } 218 219 // Table that maps Darwin's Mach-O stab constants to strings to allow printing. 220 // llvm-nm has very similar code, the strings used here are however slightly 221 // different and part of the interface of dsymutil (some project's build-systems 222 // parse the ouptut of dsymutil -s), thus they shouldn't be changed. 223 struct DarwinStabName { 224 uint8_t NType; 225 const char *Name; 226 }; 227 228 const struct DarwinStabName DarwinStabNames[] = { 229 {MachO::N_GSYM, "N_GSYM"}, {MachO::N_FNAME, "N_FNAME"}, 230 {MachO::N_FUN, "N_FUN"}, {MachO::N_STSYM, "N_STSYM"}, 231 {MachO::N_LCSYM, "N_LCSYM"}, {MachO::N_BNSYM, "N_BNSYM"}, 232 {MachO::N_PC, "N_PC"}, {MachO::N_AST, "N_AST"}, 233 {MachO::N_OPT, "N_OPT"}, {MachO::N_RSYM, "N_RSYM"}, 234 {MachO::N_SLINE, "N_SLINE"}, {MachO::N_ENSYM, "N_ENSYM"}, 235 {MachO::N_SSYM, "N_SSYM"}, {MachO::N_SO, "N_SO"}, 236 {MachO::N_OSO, "N_OSO"}, {MachO::N_LSYM, "N_LSYM"}, 237 {MachO::N_BINCL, "N_BINCL"}, {MachO::N_SOL, "N_SOL"}, 238 {MachO::N_PARAMS, "N_PARAM"}, {MachO::N_VERSION, "N_VERS"}, 239 {MachO::N_OLEVEL, "N_OLEV"}, {MachO::N_PSYM, "N_PSYM"}, 240 {MachO::N_EINCL, "N_EINCL"}, {MachO::N_ENTRY, "N_ENTRY"}, 241 {MachO::N_LBRAC, "N_LBRAC"}, {MachO::N_EXCL, "N_EXCL"}, 242 {MachO::N_RBRAC, "N_RBRAC"}, {MachO::N_BCOMM, "N_BCOMM"}, 243 {MachO::N_ECOMM, "N_ECOMM"}, {MachO::N_ECOML, "N_ECOML"}, 244 {MachO::N_LENG, "N_LENG"}, {0, nullptr}}; 245 246 static const char *getDarwinStabString(uint8_t NType) { 247 for (unsigned i = 0; DarwinStabNames[i].Name; i++) { 248 if (DarwinStabNames[i].NType == NType) 249 return DarwinStabNames[i].Name; 250 } 251 return nullptr; 252 } 253 254 void MachODebugMapParser::dumpSymTabHeader(raw_ostream &OS, StringRef Arch) { 255 OS << "-----------------------------------" 256 "-----------------------------------\n"; 257 OS << "Symbol table for: '" << BinaryPath << "' (" << Arch.data() << ")\n"; 258 OS << "-----------------------------------" 259 "-----------------------------------\n"; 260 OS << "Index n_strx n_type n_sect n_desc n_value\n"; 261 OS << "======== -------- ------------------ ------ ------ ----------------\n"; 262 } 263 264 void MachODebugMapParser::dumpSymTabEntry(raw_ostream &OS, uint64_t Index, 265 uint32_t StringIndex, uint8_t Type, 266 uint8_t SectionIndex, uint16_t Flags, 267 uint64_t Value) { 268 // Index 269 OS << '[' << format_decimal(Index, 6) 270 << "] " 271 // n_strx 272 << format_hex_no_prefix(StringIndex, 8) 273 << ' ' 274 // n_type... 275 << format_hex_no_prefix(Type, 2) << " ("; 276 277 if (Type & MachO::N_STAB) 278 OS << left_justify(getDarwinStabString(Type), 13); 279 else { 280 if (Type & MachO::N_PEXT) 281 OS << "PEXT "; 282 else 283 OS << " "; 284 switch (Type & MachO::N_TYPE) { 285 case MachO::N_UNDF: // 0x0 undefined, n_sect == NO_SECT 286 OS << "UNDF"; 287 break; 288 case MachO::N_ABS: // 0x2 absolute, n_sect == NO_SECT 289 OS << "ABS "; 290 break; 291 case MachO::N_SECT: // 0xe defined in section number n_sect 292 OS << "SECT"; 293 break; 294 case MachO::N_PBUD: // 0xc prebound undefined (defined in a dylib) 295 OS << "PBUD"; 296 break; 297 case MachO::N_INDR: // 0xa indirect 298 OS << "INDR"; 299 break; 300 default: 301 OS << format_hex_no_prefix(Type, 2) << " "; 302 break; 303 } 304 if (Type & MachO::N_EXT) 305 OS << " EXT"; 306 else 307 OS << " "; 308 } 309 310 OS << ") " 311 // n_sect 312 << format_hex_no_prefix(SectionIndex, 2) 313 << " " 314 // n_desc 315 << format_hex_no_prefix(Flags, 4) 316 << " " 317 // n_value 318 << format_hex_no_prefix(Value, 16); 319 320 const char *Name = &MainBinaryStrings.data()[StringIndex]; 321 if (Name && Name[0]) 322 OS << " '" << Name << "'"; 323 324 OS << "\n"; 325 } 326 327 void MachODebugMapParser::dumpOneBinaryStab(const MachOObjectFile &MainBinary, 328 StringRef BinaryPath) { 329 loadMainBinarySymbols(MainBinary); 330 MainBinaryStrings = MainBinary.getStringTableData(); 331 raw_ostream &OS(llvm::outs()); 332 333 dumpSymTabHeader(OS, getArchName(MainBinary)); 334 uint64_t Idx = 0; 335 for (const SymbolRef &Symbol : MainBinary.symbols()) { 336 const DataRefImpl &DRI = Symbol.getRawDataRefImpl(); 337 if (MainBinary.is64Bit()) 338 dumpSymTabEntry(OS, Idx, MainBinary.getSymbol64TableEntry(DRI)); 339 else 340 dumpSymTabEntry(OS, Idx, MainBinary.getSymbolTableEntry(DRI)); 341 Idx++; 342 } 343 344 OS << "\n\n"; 345 resetParserState(); 346 } 347 348 static bool shouldLinkArch(SmallVectorImpl<StringRef> &Archs, StringRef Arch) { 349 if (Archs.empty() || is_contained(Archs, "all") || is_contained(Archs, "*")) 350 return true; 351 352 if (Arch.startswith("arm") && Arch != "arm64" && is_contained(Archs, "arm")) 353 return true; 354 355 SmallString<16> ArchName = Arch; 356 if (Arch.startswith("thumb")) 357 ArchName = ("arm" + Arch.substr(5)).str(); 358 359 return is_contained(Archs, ArchName); 360 } 361 362 bool MachODebugMapParser::dumpStab() { 363 auto ObjectEntry = BinHolder.getObjectEntry(BinaryPath); 364 if (!ObjectEntry) { 365 auto Err = ObjectEntry.takeError(); 366 WithColor::error() << "cannot load '" << BinaryPath 367 << "': " << toString(std::move(Err)) << '\n'; 368 return false; 369 } 370 371 auto Objects = ObjectEntry->getObjectsAs<MachOObjectFile>(); 372 if (!Objects) { 373 auto Err = Objects.takeError(); 374 WithColor::error() << "cannot get '" << BinaryPath 375 << "' as MachO file: " << toString(std::move(Err)) 376 << "\n"; 377 return false; 378 } 379 380 for (const auto *Object : *Objects) 381 if (shouldLinkArch(Archs, Object->getArchTriple().getArchName())) 382 dumpOneBinaryStab(*Object, BinaryPath); 383 384 return true; 385 } 386 387 /// This main parsing routine tries to open the main binary and if 388 /// successful iterates over the STAB entries. The real parsing is 389 /// done in handleStabSymbolTableEntry. 390 ErrorOr<std::vector<std::unique_ptr<DebugMap>>> MachODebugMapParser::parse() { 391 auto ObjectEntry = BinHolder.getObjectEntry(BinaryPath); 392 if (!ObjectEntry) { 393 return errorToErrorCode(ObjectEntry.takeError()); 394 } 395 396 auto Objects = ObjectEntry->getObjectsAs<MachOObjectFile>(); 397 if (!Objects) { 398 return errorToErrorCode(Objects.takeError()); 399 } 400 401 std::vector<std::unique_ptr<DebugMap>> Results; 402 for (const auto *Object : *Objects) 403 if (shouldLinkArch(Archs, Object->getArchTriple().getArchName())) 404 Results.push_back(parseOneBinary(*Object, BinaryPath)); 405 406 return std::move(Results); 407 } 408 409 /// Interpret the STAB entries to fill the DebugMap. 410 void MachODebugMapParser::handleStabSymbolTableEntry(uint32_t StringIndex, 411 uint8_t Type, 412 uint8_t SectionIndex, 413 uint16_t Flags, 414 uint64_t Value) { 415 if (!(Type & MachO::N_STAB)) 416 return; 417 418 const char *Name = &MainBinaryStrings.data()[StringIndex]; 419 420 // An N_OSO entry represents the start of a new object file description. 421 if (Type == MachO::N_OSO) 422 return switchToNewDebugMapObject(Name, sys::toTimePoint(Value)); 423 424 if (Type == MachO::N_AST) { 425 SmallString<80> Path(PathPrefix); 426 sys::path::append(Path, Name); 427 Result->addDebugMapObject(Path, sys::toTimePoint(Value), Type); 428 return; 429 } 430 431 // If the last N_OSO object file wasn't found, CurrentDebugMapObject will be 432 // null. Do not update anything until we find the next valid N_OSO entry. 433 if (!CurrentDebugMapObject) 434 return; 435 436 uint32_t Size = 0; 437 switch (Type) { 438 case MachO::N_GSYM: 439 // This is a global variable. We need to query the main binary 440 // symbol table to find its address as it might not be in the 441 // debug map (for common symbols). 442 Value = getMainBinarySymbolAddress(Name); 443 break; 444 case MachO::N_FUN: 445 // Functions are scopes in STABS. They have an end marker that 446 // contains the function size. 447 if (Name[0] == '\0') { 448 Size = Value; 449 Value = CurrentFunctionAddress; 450 Name = CurrentFunctionName; 451 break; 452 } else { 453 CurrentFunctionName = Name; 454 CurrentFunctionAddress = Value; 455 return; 456 } 457 case MachO::N_STSYM: 458 break; 459 default: 460 return; 461 } 462 463 auto ObjectSymIt = CurrentObjectAddresses.find(Name); 464 465 // If the name of a (non-static) symbol is not in the current object, we 466 // check all its aliases from the main binary. 467 if (ObjectSymIt == CurrentObjectAddresses.end() && Type != MachO::N_STSYM) { 468 if (SeenAliasValues.count(Value) == 0) { 469 auto Aliases = getMainBinarySymbolNames(Value); 470 for (const auto &Alias : Aliases) { 471 auto It = CurrentObjectAddresses.find(Alias); 472 if (It != CurrentObjectAddresses.end()) { 473 auto AliasValue = It->getValue(); 474 for (const auto &Alias : Aliases) 475 CurrentObjectAliasMap[Alias] = AliasValue; 476 break; 477 } 478 } 479 SeenAliasValues.insert(Value); 480 } 481 482 auto AliasIt = CurrentObjectAliasMap.find(Name); 483 if (AliasIt != CurrentObjectAliasMap.end()) 484 ObjectSymIt = AliasIt; 485 } 486 487 // ThinLTO adds a unique suffix to exported private symbols. 488 if (ObjectSymIt == CurrentObjectAddresses.end()) { 489 for (auto Iter = CurrentObjectAddresses.begin(); 490 Iter != CurrentObjectAddresses.end(); ++Iter) { 491 llvm::StringRef SymbolName = Iter->getKey(); 492 auto Pos = SymbolName.rfind(".llvm."); 493 if (Pos != llvm::StringRef::npos && SymbolName.substr(0, Pos) == Name) { 494 ObjectSymIt = Iter; 495 break; 496 } 497 } 498 } 499 500 if (ObjectSymIt == CurrentObjectAddresses.end()) { 501 Warning("could not find object file symbol for symbol " + Twine(Name)); 502 return; 503 } 504 505 if (!CurrentDebugMapObject->addSymbol(Name, ObjectSymIt->getValue(), Value, 506 Size)) { 507 Warning(Twine("failed to insert symbol '") + Name + "' in the debug map."); 508 return; 509 } 510 } 511 512 /// Load the current object file symbols into CurrentObjectAddresses. 513 void MachODebugMapParser::loadCurrentObjectFileSymbols( 514 const object::MachOObjectFile &Obj) { 515 CurrentObjectAddresses.clear(); 516 517 for (auto Sym : Obj.symbols()) { 518 uint64_t Addr = cantFail(Sym.getValue()); 519 Expected<StringRef> Name = Sym.getName(); 520 if (!Name) { 521 auto Err = Name.takeError(); 522 Warning("failed to get symbol name: " + toString(std::move(Err)), 523 Obj.getFileName()); 524 continue; 525 } 526 // The value of some categories of symbols isn't meaningful. For 527 // example common symbols store their size in the value field, not 528 // their address. Absolute symbols have a fixed address that can 529 // conflict with standard symbols. These symbols (especially the 530 // common ones), might still be referenced by relocations. These 531 // relocations will use the symbol itself, and won't need an 532 // object file address. The object file address field is optional 533 // in the DebugMap, leave it unassigned for these symbols. 534 uint32_t Flags = cantFail(Sym.getFlags()); 535 if (Flags & SymbolRef::SF_Absolute) { 536 CurrentObjectAddresses[*Name] = None; 537 } else if (Flags & SymbolRef::SF_Common) { 538 CurrentObjectAddresses[*Name] = None; 539 CommonSymbols.push_back(std::string(*Name)); 540 } else { 541 CurrentObjectAddresses[*Name] = Addr; 542 } 543 } 544 } 545 546 /// Lookup a symbol address in the main binary symbol table. The 547 /// parser only needs to query common symbols, thus not every symbol's 548 /// address is available through this function. 549 uint64_t MachODebugMapParser::getMainBinarySymbolAddress(StringRef Name) { 550 auto Sym = MainBinarySymbolAddresses.find(Name); 551 if (Sym == MainBinarySymbolAddresses.end()) 552 return 0; 553 return Sym->second; 554 } 555 556 /// Get all symbol names in the main binary for the given value. 557 std::vector<StringRef> 558 MachODebugMapParser::getMainBinarySymbolNames(uint64_t Value) { 559 std::vector<StringRef> Names; 560 for (const auto &Entry : MainBinarySymbolAddresses) { 561 if (Entry.second == Value) 562 Names.push_back(Entry.first()); 563 } 564 return Names; 565 } 566 567 /// Load the interesting main binary symbols' addresses into 568 /// MainBinarySymbolAddresses. 569 void MachODebugMapParser::loadMainBinarySymbols( 570 const MachOObjectFile &MainBinary) { 571 section_iterator Section = MainBinary.section_end(); 572 MainBinarySymbolAddresses.clear(); 573 for (const auto &Sym : MainBinary.symbols()) { 574 Expected<SymbolRef::Type> TypeOrErr = Sym.getType(); 575 if (!TypeOrErr) { 576 auto Err = TypeOrErr.takeError(); 577 Warning("failed to get symbol type: " + toString(std::move(Err)), 578 MainBinary.getFileName()); 579 continue; 580 } 581 SymbolRef::Type Type = *TypeOrErr; 582 // Skip undefined and STAB entries. 583 if ((Type == SymbolRef::ST_Debug) || (Type == SymbolRef::ST_Unknown)) 584 continue; 585 // In theory, the only symbols of interest are the global variables. These 586 // are the only ones that need to be queried because the address of common 587 // data won't be described in the debug map. All other addresses should be 588 // fetched for the debug map. In reality, by playing with 'ld -r' and 589 // export lists, you can get symbols described as N_GSYM in the debug map, 590 // but associated with a local symbol. Gather all the symbols, but prefer 591 // the global ones. 592 uint8_t SymType = 593 MainBinary.getSymbolTableEntry(Sym.getRawDataRefImpl()).n_type; 594 bool Extern = SymType & (MachO::N_EXT | MachO::N_PEXT); 595 Expected<section_iterator> SectionOrErr = Sym.getSection(); 596 if (!SectionOrErr) { 597 auto Err = TypeOrErr.takeError(); 598 Warning("failed to get symbol section: " + toString(std::move(Err)), 599 MainBinary.getFileName()); 600 continue; 601 } 602 Section = *SectionOrErr; 603 if ((Section == MainBinary.section_end() || Section->isText()) && !Extern) 604 continue; 605 uint64_t Addr = cantFail(Sym.getValue()); 606 Expected<StringRef> NameOrErr = Sym.getName(); 607 if (!NameOrErr) { 608 auto Err = NameOrErr.takeError(); 609 Warning("failed to get symbol name: " + toString(std::move(Err)), 610 MainBinary.getFileName()); 611 continue; 612 } 613 StringRef Name = *NameOrErr; 614 if (Name.size() == 0 || Name[0] == '\0') 615 continue; 616 // Override only if the new key is global. 617 if (Extern) 618 MainBinarySymbolAddresses[Name] = Addr; 619 else 620 MainBinarySymbolAddresses.try_emplace(Name, Addr); 621 } 622 } 623 624 namespace llvm { 625 namespace dsymutil { 626 llvm::ErrorOr<std::vector<std::unique_ptr<DebugMap>>> 627 parseDebugMap(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, 628 StringRef InputFile, ArrayRef<std::string> Archs, 629 StringRef PrependPath, bool PaperTrailWarnings, bool Verbose, 630 bool InputIsYAML) { 631 if (InputIsYAML) 632 return DebugMap::parseYAMLDebugMap(InputFile, PrependPath, Verbose); 633 634 MachODebugMapParser Parser(VFS, InputFile, Archs, PrependPath, 635 PaperTrailWarnings, Verbose); 636 return Parser.parse(); 637 } 638 639 bool dumpStab(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, 640 StringRef InputFile, ArrayRef<std::string> Archs, 641 StringRef PrependPath) { 642 MachODebugMapParser Parser(VFS, InputFile, Archs, PrependPath, false); 643 return Parser.dumpStab(); 644 } 645 } // namespace dsymutil 646 } // namespace llvm 647