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