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