1 //===-- llvm-objdump.cpp - Object file dumping utility for llvm -----------===// 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 // This program is a utility that works like binutils "objdump", that is, it 10 // dumps out a plethora of information about an object file depending on the 11 // flags. 12 // 13 // The flags and output of this program should be near identical to those of 14 // binutils objdump. 15 // 16 //===----------------------------------------------------------------------===// 17 18 #include "llvm-objdump.h" 19 #include "COFFDump.h" 20 #include "ELFDump.h" 21 #include "MachODump.h" 22 #include "ObjdumpOptID.h" 23 #include "OffloadDump.h" 24 #include "SourcePrinter.h" 25 #include "WasmDump.h" 26 #include "XCOFFDump.h" 27 #include "llvm/ADT/STLExtras.h" 28 #include "llvm/ADT/SetOperations.h" 29 #include "llvm/ADT/StringExtras.h" 30 #include "llvm/ADT/Twine.h" 31 #include "llvm/BinaryFormat/Wasm.h" 32 #include "llvm/DebugInfo/BTF/BTFParser.h" 33 #include "llvm/DebugInfo/DWARF/DWARFContext.h" 34 #include "llvm/DebugInfo/Symbolize/Symbolize.h" 35 #include "llvm/Debuginfod/BuildIDFetcher.h" 36 #include "llvm/Debuginfod/Debuginfod.h" 37 #include "llvm/Debuginfod/HTTPClient.h" 38 #include "llvm/Demangle/Demangle.h" 39 #include "llvm/MC/MCAsmInfo.h" 40 #include "llvm/MC/MCContext.h" 41 #include "llvm/MC/MCDisassembler/MCRelocationInfo.h" 42 #include "llvm/MC/MCInst.h" 43 #include "llvm/MC/MCInstPrinter.h" 44 #include "llvm/MC/MCInstrAnalysis.h" 45 #include "llvm/MC/MCInstrInfo.h" 46 #include "llvm/MC/MCObjectFileInfo.h" 47 #include "llvm/MC/MCRegisterInfo.h" 48 #include "llvm/MC/MCTargetOptions.h" 49 #include "llvm/MC/TargetRegistry.h" 50 #include "llvm/Object/BuildID.h" 51 #include "llvm/Object/COFF.h" 52 #include "llvm/Object/COFFImportFile.h" 53 #include "llvm/Object/ELFObjectFile.h" 54 #include "llvm/Object/ELFTypes.h" 55 #include "llvm/Object/FaultMapParser.h" 56 #include "llvm/Object/MachO.h" 57 #include "llvm/Object/MachOUniversal.h" 58 #include "llvm/Object/OffloadBinary.h" 59 #include "llvm/Object/Wasm.h" 60 #include "llvm/Option/Arg.h" 61 #include "llvm/Option/ArgList.h" 62 #include "llvm/Option/Option.h" 63 #include "llvm/Support/Casting.h" 64 #include "llvm/Support/Debug.h" 65 #include "llvm/Support/Errc.h" 66 #include "llvm/Support/FileSystem.h" 67 #include "llvm/Support/Format.h" 68 #include "llvm/Support/LLVMDriver.h" 69 #include "llvm/Support/MemoryBuffer.h" 70 #include "llvm/Support/SourceMgr.h" 71 #include "llvm/Support/StringSaver.h" 72 #include "llvm/Support/TargetSelect.h" 73 #include "llvm/Support/WithColor.h" 74 #include "llvm/Support/raw_ostream.h" 75 #include "llvm/TargetParser/Host.h" 76 #include "llvm/TargetParser/Triple.h" 77 #include <algorithm> 78 #include <cctype> 79 #include <cstring> 80 #include <optional> 81 #include <set> 82 #include <system_error> 83 #include <unordered_map> 84 #include <utility> 85 86 using namespace llvm; 87 using namespace llvm::object; 88 using namespace llvm::objdump; 89 using namespace llvm::opt; 90 91 namespace { 92 93 class CommonOptTable : public opt::GenericOptTable { 94 public: 95 CommonOptTable(const StringTable &StrTable, 96 ArrayRef<StringTable::Offset> PrefixesTable, 97 ArrayRef<Info> OptionInfos, const char *Usage, 98 const char *Description) 99 : opt::GenericOptTable(StrTable, PrefixesTable, OptionInfos), 100 Usage(Usage), Description(Description) { 101 setGroupedShortOptions(true); 102 } 103 104 void printHelp(StringRef Argv0, bool ShowHidden = false) const { 105 Argv0 = sys::path::filename(Argv0); 106 opt::GenericOptTable::printHelp(outs(), (Argv0 + Usage).str().c_str(), 107 Description, ShowHidden, ShowHidden); 108 // TODO Replace this with OptTable API once it adds extrahelp support. 109 outs() << "\nPass @FILE as argument to read options from FILE.\n"; 110 } 111 112 private: 113 const char *Usage; 114 const char *Description; 115 }; 116 117 // ObjdumpOptID is in ObjdumpOptID.h 118 namespace objdump_opt { 119 #define OPTTABLE_STR_TABLE_CODE 120 #include "ObjdumpOpts.inc" 121 #undef OPTTABLE_STR_TABLE_CODE 122 123 #define OPTTABLE_PREFIXES_TABLE_CODE 124 #include "ObjdumpOpts.inc" 125 #undef OPTTABLE_PREFIXES_TABLE_CODE 126 127 static constexpr opt::OptTable::Info ObjdumpInfoTable[] = { 128 #define OPTION(...) \ 129 LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(OBJDUMP_, __VA_ARGS__), 130 #include "ObjdumpOpts.inc" 131 #undef OPTION 132 }; 133 } // namespace objdump_opt 134 135 class ObjdumpOptTable : public CommonOptTable { 136 public: 137 ObjdumpOptTable() 138 : CommonOptTable( 139 objdump_opt::OptionStrTable, objdump_opt::OptionPrefixesTable, 140 objdump_opt::ObjdumpInfoTable, " [options] <input object files>", 141 "llvm object file dumper") {} 142 }; 143 144 enum OtoolOptID { 145 OTOOL_INVALID = 0, // This is not an option ID. 146 #define OPTION(...) LLVM_MAKE_OPT_ID_WITH_ID_PREFIX(OTOOL_, __VA_ARGS__), 147 #include "OtoolOpts.inc" 148 #undef OPTION 149 }; 150 151 namespace otool { 152 #define OPTTABLE_STR_TABLE_CODE 153 #include "OtoolOpts.inc" 154 #undef OPTTABLE_STR_TABLE_CODE 155 156 #define OPTTABLE_PREFIXES_TABLE_CODE 157 #include "OtoolOpts.inc" 158 #undef OPTTABLE_PREFIXES_TABLE_CODE 159 160 static constexpr opt::OptTable::Info OtoolInfoTable[] = { 161 #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(OTOOL_, __VA_ARGS__), 162 #include "OtoolOpts.inc" 163 #undef OPTION 164 }; 165 } // namespace otool 166 167 class OtoolOptTable : public CommonOptTable { 168 public: 169 OtoolOptTable() 170 : CommonOptTable(otool::OptionStrTable, otool::OptionPrefixesTable, 171 otool::OtoolInfoTable, " [option...] [file...]", 172 "Mach-O object file displaying tool") {} 173 }; 174 175 struct BBAddrMapLabel { 176 std::string BlockLabel; 177 std::string PGOAnalysis; 178 }; 179 180 // This class represents the BBAddrMap and PGOMap associated with a single 181 // function. 182 class BBAddrMapFunctionEntry { 183 public: 184 BBAddrMapFunctionEntry(BBAddrMap AddrMap, PGOAnalysisMap PGOMap) 185 : AddrMap(std::move(AddrMap)), PGOMap(std::move(PGOMap)) {} 186 187 const BBAddrMap &getAddrMap() const { return AddrMap; } 188 189 // Returns the PGO string associated with the entry of index `PGOBBEntryIndex` 190 // in `PGOMap`. If PrettyPGOAnalysis is true, prints BFI as relative frequency 191 // and BPI as percentage. Otherwise raw values are displayed. 192 std::string constructPGOLabelString(size_t PGOBBEntryIndex, 193 bool PrettyPGOAnalysis) const { 194 if (!PGOMap.FeatEnable.hasPGOAnalysis()) 195 return ""; 196 std::string PGOString; 197 raw_string_ostream PGOSS(PGOString); 198 199 PGOSS << " ("; 200 if (PGOMap.FeatEnable.FuncEntryCount && PGOBBEntryIndex == 0) { 201 PGOSS << "Entry count: " << Twine(PGOMap.FuncEntryCount); 202 if (PGOMap.FeatEnable.hasPGOAnalysisBBData()) { 203 PGOSS << ", "; 204 } 205 } 206 207 if (PGOMap.FeatEnable.hasPGOAnalysisBBData()) { 208 209 assert(PGOBBEntryIndex < PGOMap.BBEntries.size() && 210 "Expected PGOAnalysisMap and BBAddrMap to have the same entries"); 211 const PGOAnalysisMap::PGOBBEntry &PGOBBEntry = 212 PGOMap.BBEntries[PGOBBEntryIndex]; 213 214 if (PGOMap.FeatEnable.BBFreq) { 215 PGOSS << "Frequency: "; 216 if (PrettyPGOAnalysis) 217 printRelativeBlockFreq(PGOSS, PGOMap.BBEntries.front().BlockFreq, 218 PGOBBEntry.BlockFreq); 219 else 220 PGOSS << Twine(PGOBBEntry.BlockFreq.getFrequency()); 221 if (PGOMap.FeatEnable.BrProb && PGOBBEntry.Successors.size() > 0) { 222 PGOSS << ", "; 223 } 224 } 225 if (PGOMap.FeatEnable.BrProb && PGOBBEntry.Successors.size() > 0) { 226 PGOSS << "Successors: "; 227 interleaveComma( 228 PGOBBEntry.Successors, PGOSS, 229 [&](const PGOAnalysisMap::PGOBBEntry::SuccessorEntry &SE) { 230 PGOSS << "BB" << SE.ID << ":"; 231 if (PrettyPGOAnalysis) 232 PGOSS << "[" << SE.Prob << "]"; 233 else 234 PGOSS.write_hex(SE.Prob.getNumerator()); 235 }); 236 } 237 } 238 PGOSS << ")"; 239 240 return PGOString; 241 } 242 243 private: 244 const BBAddrMap AddrMap; 245 const PGOAnalysisMap PGOMap; 246 }; 247 248 // This class represents the BBAddrMap and PGOMap of potentially multiple 249 // functions in a section. 250 class BBAddrMapInfo { 251 public: 252 void clear() { 253 FunctionAddrToMap.clear(); 254 RangeBaseAddrToFunctionAddr.clear(); 255 } 256 257 bool empty() const { return FunctionAddrToMap.empty(); } 258 259 void AddFunctionEntry(BBAddrMap AddrMap, PGOAnalysisMap PGOMap) { 260 uint64_t FunctionAddr = AddrMap.getFunctionAddress(); 261 for (size_t I = 1; I < AddrMap.BBRanges.size(); ++I) 262 RangeBaseAddrToFunctionAddr.emplace(AddrMap.BBRanges[I].BaseAddress, 263 FunctionAddr); 264 [[maybe_unused]] auto R = FunctionAddrToMap.try_emplace( 265 FunctionAddr, std::move(AddrMap), std::move(PGOMap)); 266 assert(R.second && "duplicate function address"); 267 } 268 269 // Returns the BBAddrMap entry for the function associated with `BaseAddress`. 270 // `BaseAddress` could be the function address or the address of a range 271 // associated with that function. Returns `nullptr` if `BaseAddress` is not 272 // mapped to any entry. 273 const BBAddrMapFunctionEntry *getEntryForAddress(uint64_t BaseAddress) const { 274 uint64_t FunctionAddr = BaseAddress; 275 auto S = RangeBaseAddrToFunctionAddr.find(BaseAddress); 276 if (S != RangeBaseAddrToFunctionAddr.end()) 277 FunctionAddr = S->second; 278 auto R = FunctionAddrToMap.find(FunctionAddr); 279 if (R == FunctionAddrToMap.end()) 280 return nullptr; 281 return &R->second; 282 } 283 284 private: 285 std::unordered_map<uint64_t, BBAddrMapFunctionEntry> FunctionAddrToMap; 286 std::unordered_map<uint64_t, uint64_t> RangeBaseAddrToFunctionAddr; 287 }; 288 289 } // namespace 290 291 #define DEBUG_TYPE "objdump" 292 293 enum class ColorOutput { 294 Auto, 295 Enable, 296 Disable, 297 Invalid, 298 }; 299 300 static uint64_t AdjustVMA; 301 static bool AllHeaders; 302 static std::string ArchName; 303 bool objdump::ArchiveHeaders; 304 bool objdump::Demangle; 305 bool objdump::Disassemble; 306 bool objdump::DisassembleAll; 307 std::vector<std::string> objdump::DisassemblerOptions; 308 bool objdump::SymbolDescription; 309 bool objdump::TracebackTable; 310 static std::vector<std::string> DisassembleSymbols; 311 static bool DisassembleZeroes; 312 static ColorOutput DisassemblyColor; 313 DIDumpType objdump::DwarfDumpType; 314 static bool DynamicRelocations; 315 static bool FaultMapSection; 316 static bool FileHeaders; 317 bool objdump::SectionContents; 318 static std::vector<std::string> InputFilenames; 319 bool objdump::PrintLines; 320 static bool MachOOpt; 321 std::string objdump::MCPU; 322 std::vector<std::string> objdump::MAttrs; 323 bool objdump::ShowRawInsn; 324 bool objdump::LeadingAddr; 325 static bool Offloading; 326 static bool RawClangAST; 327 bool objdump::Relocations; 328 bool objdump::PrintImmHex; 329 bool objdump::PrivateHeaders; 330 std::vector<std::string> objdump::FilterSections; 331 bool objdump::SectionHeaders; 332 static bool ShowAllSymbols; 333 static bool ShowLMA; 334 bool objdump::PrintSource; 335 336 static uint64_t StartAddress; 337 static bool HasStartAddressFlag; 338 static uint64_t StopAddress = UINT64_MAX; 339 static bool HasStopAddressFlag; 340 341 bool objdump::SymbolTable; 342 static bool SymbolizeOperands; 343 static bool PrettyPGOAnalysisMap; 344 static bool DynamicSymbolTable; 345 std::string objdump::TripleName; 346 bool objdump::UnwindInfo; 347 static bool Wide; 348 std::string objdump::Prefix; 349 uint32_t objdump::PrefixStrip; 350 351 DebugVarsFormat objdump::DbgVariables = DVDisabled; 352 353 int objdump::DbgIndent = 52; 354 355 static StringSet<> DisasmSymbolSet; 356 StringSet<> objdump::FoundSectionSet; 357 static StringRef ToolName; 358 359 std::unique_ptr<BuildIDFetcher> BIDFetcher; 360 361 Dumper::Dumper(const object::ObjectFile &O) : O(O), OS(outs()) { 362 WarningHandler = [this](const Twine &Msg) { 363 if (Warnings.insert(Msg.str()).second) 364 reportWarning(Msg, this->O.getFileName()); 365 return Error::success(); 366 }; 367 } 368 369 void Dumper::reportUniqueWarning(Error Err) { 370 reportUniqueWarning(toString(std::move(Err))); 371 } 372 373 void Dumper::reportUniqueWarning(const Twine &Msg) { 374 cantFail(WarningHandler(Msg)); 375 } 376 377 static Expected<std::unique_ptr<Dumper>> createDumper(const ObjectFile &Obj) { 378 if (const auto *O = dyn_cast<COFFObjectFile>(&Obj)) 379 return createCOFFDumper(*O); 380 if (const auto *O = dyn_cast<ELFObjectFileBase>(&Obj)) 381 return createELFDumper(*O); 382 if (const auto *O = dyn_cast<MachOObjectFile>(&Obj)) 383 return createMachODumper(*O); 384 if (const auto *O = dyn_cast<WasmObjectFile>(&Obj)) 385 return createWasmDumper(*O); 386 if (const auto *O = dyn_cast<XCOFFObjectFile>(&Obj)) 387 return createXCOFFDumper(*O); 388 389 return createStringError(errc::invalid_argument, 390 "unsupported object file format"); 391 } 392 393 namespace { 394 struct FilterResult { 395 // True if the section should not be skipped. 396 bool Keep; 397 398 // True if the index counter should be incremented, even if the section should 399 // be skipped. For example, sections may be skipped if they are not included 400 // in the --section flag, but we still want those to count toward the section 401 // count. 402 bool IncrementIndex; 403 }; 404 } // namespace 405 406 static FilterResult checkSectionFilter(object::SectionRef S) { 407 if (FilterSections.empty()) 408 return {/*Keep=*/true, /*IncrementIndex=*/true}; 409 410 Expected<StringRef> SecNameOrErr = S.getName(); 411 if (!SecNameOrErr) { 412 consumeError(SecNameOrErr.takeError()); 413 return {/*Keep=*/false, /*IncrementIndex=*/false}; 414 } 415 StringRef SecName = *SecNameOrErr; 416 417 // StringSet does not allow empty key so avoid adding sections with 418 // no name (such as the section with index 0) here. 419 if (!SecName.empty()) 420 FoundSectionSet.insert(SecName); 421 422 // Only show the section if it's in the FilterSections list, but always 423 // increment so the indexing is stable. 424 return {/*Keep=*/is_contained(FilterSections, SecName), 425 /*IncrementIndex=*/true}; 426 } 427 428 SectionFilter objdump::ToolSectionFilter(object::ObjectFile const &O, 429 uint64_t *Idx) { 430 // Start at UINT64_MAX so that the first index returned after an increment is 431 // zero (after the unsigned wrap). 432 if (Idx) 433 *Idx = UINT64_MAX; 434 return SectionFilter( 435 [Idx](object::SectionRef S) { 436 FilterResult Result = checkSectionFilter(S); 437 if (Idx != nullptr && Result.IncrementIndex) 438 *Idx += 1; 439 return Result.Keep; 440 }, 441 O); 442 } 443 444 std::string objdump::getFileNameForError(const object::Archive::Child &C, 445 unsigned Index) { 446 Expected<StringRef> NameOrErr = C.getName(); 447 if (NameOrErr) 448 return std::string(NameOrErr.get()); 449 // If we have an error getting the name then we print the index of the archive 450 // member. Since we are already in an error state, we just ignore this error. 451 consumeError(NameOrErr.takeError()); 452 return "<file index: " + std::to_string(Index) + ">"; 453 } 454 455 void objdump::reportWarning(const Twine &Message, StringRef File) { 456 // Output order between errs() and outs() matters especially for archive 457 // files where the output is per member object. 458 outs().flush(); 459 WithColor::warning(errs(), ToolName) 460 << "'" << File << "': " << Message << "\n"; 461 } 462 463 [[noreturn]] void objdump::reportError(StringRef File, const Twine &Message) { 464 outs().flush(); 465 WithColor::error(errs(), ToolName) << "'" << File << "': " << Message << "\n"; 466 exit(1); 467 } 468 469 [[noreturn]] void objdump::reportError(Error E, StringRef FileName, 470 StringRef ArchiveName, 471 StringRef ArchitectureName) { 472 assert(E); 473 outs().flush(); 474 WithColor::error(errs(), ToolName); 475 if (ArchiveName != "") 476 errs() << ArchiveName << "(" << FileName << ")"; 477 else 478 errs() << "'" << FileName << "'"; 479 if (!ArchitectureName.empty()) 480 errs() << " (for architecture " << ArchitectureName << ")"; 481 errs() << ": "; 482 logAllUnhandledErrors(std::move(E), errs()); 483 exit(1); 484 } 485 486 static void reportCmdLineWarning(const Twine &Message) { 487 WithColor::warning(errs(), ToolName) << Message << "\n"; 488 } 489 490 [[noreturn]] static void reportCmdLineError(const Twine &Message) { 491 WithColor::error(errs(), ToolName) << Message << "\n"; 492 exit(1); 493 } 494 495 static void warnOnNoMatchForSections() { 496 SetVector<StringRef> MissingSections; 497 for (StringRef S : FilterSections) { 498 if (FoundSectionSet.count(S)) 499 return; 500 // User may specify a unnamed section. Don't warn for it. 501 if (!S.empty()) 502 MissingSections.insert(S); 503 } 504 505 // Warn only if no section in FilterSections is matched. 506 for (StringRef S : MissingSections) 507 reportCmdLineWarning("section '" + S + 508 "' mentioned in a -j/--section option, but not " 509 "found in any input file"); 510 } 511 512 static const Target *getTarget(const ObjectFile *Obj) { 513 // Figure out the target triple. 514 Triple TheTriple("unknown-unknown-unknown"); 515 if (TripleName.empty()) { 516 TheTriple = Obj->makeTriple(); 517 } else { 518 TheTriple.setTriple(Triple::normalize(TripleName)); 519 auto Arch = Obj->getArch(); 520 if (Arch == Triple::arm || Arch == Triple::armeb) 521 Obj->setARMSubArch(TheTriple); 522 } 523 524 // Get the target specific parser. 525 std::string Error; 526 const Target *TheTarget = TargetRegistry::lookupTarget(ArchName, TheTriple, 527 Error); 528 if (!TheTarget) 529 reportError(Obj->getFileName(), "can't find target: " + Error); 530 531 // Update the triple name and return the found target. 532 TripleName = TheTriple.getTriple(); 533 return TheTarget; 534 } 535 536 bool objdump::isRelocAddressLess(RelocationRef A, RelocationRef B) { 537 return A.getOffset() < B.getOffset(); 538 } 539 540 static Error getRelocationValueString(const RelocationRef &Rel, 541 bool SymbolDescription, 542 SmallVectorImpl<char> &Result) { 543 const ObjectFile *Obj = Rel.getObject(); 544 if (auto *ELF = dyn_cast<ELFObjectFileBase>(Obj)) 545 return getELFRelocationValueString(ELF, Rel, Result); 546 if (auto *COFF = dyn_cast<COFFObjectFile>(Obj)) 547 return getCOFFRelocationValueString(COFF, Rel, Result); 548 if (auto *Wasm = dyn_cast<WasmObjectFile>(Obj)) 549 return getWasmRelocationValueString(Wasm, Rel, Result); 550 if (auto *MachO = dyn_cast<MachOObjectFile>(Obj)) 551 return getMachORelocationValueString(MachO, Rel, Result); 552 if (auto *XCOFF = dyn_cast<XCOFFObjectFile>(Obj)) 553 return getXCOFFRelocationValueString(*XCOFF, Rel, SymbolDescription, 554 Result); 555 llvm_unreachable("unknown object file format"); 556 } 557 558 /// Indicates whether this relocation should hidden when listing 559 /// relocations, usually because it is the trailing part of a multipart 560 /// relocation that will be printed as part of the leading relocation. 561 static bool getHidden(RelocationRef RelRef) { 562 auto *MachO = dyn_cast<MachOObjectFile>(RelRef.getObject()); 563 if (!MachO) 564 return false; 565 566 unsigned Arch = MachO->getArch(); 567 DataRefImpl Rel = RelRef.getRawDataRefImpl(); 568 uint64_t Type = MachO->getRelocationType(Rel); 569 570 // On arches that use the generic relocations, GENERIC_RELOC_PAIR 571 // is always hidden. 572 if (Arch == Triple::x86 || Arch == Triple::arm || Arch == Triple::ppc) 573 return Type == MachO::GENERIC_RELOC_PAIR; 574 575 if (Arch == Triple::x86_64) { 576 // On x86_64, X86_64_RELOC_UNSIGNED is hidden only when it follows 577 // an X86_64_RELOC_SUBTRACTOR. 578 if (Type == MachO::X86_64_RELOC_UNSIGNED && Rel.d.a > 0) { 579 DataRefImpl RelPrev = Rel; 580 RelPrev.d.a--; 581 uint64_t PrevType = MachO->getRelocationType(RelPrev); 582 if (PrevType == MachO::X86_64_RELOC_SUBTRACTOR) 583 return true; 584 } 585 } 586 587 return false; 588 } 589 590 /// Get the column at which we want to start printing the instruction 591 /// disassembly, taking into account anything which appears to the left of it. 592 unsigned objdump::getInstStartColumn(const MCSubtargetInfo &STI) { 593 return !ShowRawInsn ? 16 : STI.getTargetTriple().isX86() ? 40 : 24; 594 } 595 596 static void AlignToInstStartColumn(size_t Start, const MCSubtargetInfo &STI, 597 raw_ostream &OS) { 598 // The output of printInst starts with a tab. Print some spaces so that 599 // the tab has 1 column and advances to the target tab stop. 600 unsigned TabStop = getInstStartColumn(STI); 601 unsigned Column = OS.tell() - Start; 602 OS.indent(Column < TabStop - 1 ? TabStop - 1 - Column : 7 - Column % 8); 603 } 604 605 void objdump::printRawData(ArrayRef<uint8_t> Bytes, uint64_t Address, 606 formatted_raw_ostream &OS, 607 MCSubtargetInfo const &STI) { 608 size_t Start = OS.tell(); 609 if (LeadingAddr) 610 OS << format("%8" PRIx64 ":", Address); 611 if (ShowRawInsn) { 612 OS << ' '; 613 dumpBytes(Bytes, OS); 614 } 615 AlignToInstStartColumn(Start, STI, OS); 616 } 617 618 namespace { 619 620 static bool isAArch64Elf(const ObjectFile &Obj) { 621 const auto *Elf = dyn_cast<ELFObjectFileBase>(&Obj); 622 return Elf && Elf->getEMachine() == ELF::EM_AARCH64; 623 } 624 625 static bool isArmElf(const ObjectFile &Obj) { 626 const auto *Elf = dyn_cast<ELFObjectFileBase>(&Obj); 627 return Elf && Elf->getEMachine() == ELF::EM_ARM; 628 } 629 630 static bool isCSKYElf(const ObjectFile &Obj) { 631 const auto *Elf = dyn_cast<ELFObjectFileBase>(&Obj); 632 return Elf && Elf->getEMachine() == ELF::EM_CSKY; 633 } 634 635 static bool hasMappingSymbols(const ObjectFile &Obj) { 636 return isArmElf(Obj) || isAArch64Elf(Obj) || isCSKYElf(Obj) ; 637 } 638 639 static void printRelocation(formatted_raw_ostream &OS, StringRef FileName, 640 const RelocationRef &Rel, uint64_t Address, 641 bool Is64Bits) { 642 StringRef Fmt = Is64Bits ? "%016" PRIx64 ": " : "%08" PRIx64 ": "; 643 SmallString<16> Name; 644 SmallString<32> Val; 645 Rel.getTypeName(Name); 646 if (Error E = getRelocationValueString(Rel, SymbolDescription, Val)) 647 reportError(std::move(E), FileName); 648 OS << (Is64Bits || !LeadingAddr ? "\t\t" : "\t\t\t"); 649 if (LeadingAddr) 650 OS << format(Fmt.data(), Address); 651 OS << Name << "\t" << Val; 652 } 653 654 static void printBTFRelocation(formatted_raw_ostream &FOS, llvm::BTFParser &BTF, 655 object::SectionedAddress Address, 656 LiveVariablePrinter &LVP) { 657 const llvm::BTF::BPFFieldReloc *Reloc = BTF.findFieldReloc(Address); 658 if (!Reloc) 659 return; 660 661 SmallString<64> Val; 662 BTF.symbolize(Reloc, Val); 663 FOS << "\t\t"; 664 if (LeadingAddr) 665 FOS << format("%016" PRIx64 ": ", Address.Address + AdjustVMA); 666 FOS << "CO-RE " << Val; 667 LVP.printAfterOtherLine(FOS, true); 668 } 669 670 class PrettyPrinter { 671 public: 672 virtual ~PrettyPrinter() = default; 673 virtual void 674 printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes, 675 object::SectionedAddress Address, formatted_raw_ostream &OS, 676 StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP, 677 StringRef ObjectFilename, std::vector<RelocationRef> *Rels, 678 LiveVariablePrinter &LVP) { 679 if (SP && (PrintSource || PrintLines)) 680 SP->printSourceLine(OS, Address, ObjectFilename, LVP); 681 LVP.printBetweenInsts(OS, false); 682 683 printRawData(Bytes, Address.Address, OS, STI); 684 685 if (MI) { 686 // See MCInstPrinter::printInst. On targets where a PC relative immediate 687 // is relative to the next instruction and the length of a MCInst is 688 // difficult to measure (x86), this is the address of the next 689 // instruction. 690 uint64_t Addr = 691 Address.Address + (STI.getTargetTriple().isX86() ? Bytes.size() : 0); 692 IP.printInst(MI, Addr, "", STI, OS); 693 } else 694 OS << "\t<unknown>"; 695 } 696 }; 697 PrettyPrinter PrettyPrinterInst; 698 699 class HexagonPrettyPrinter : public PrettyPrinter { 700 public: 701 void printLead(ArrayRef<uint8_t> Bytes, uint64_t Address, 702 formatted_raw_ostream &OS) { 703 if (LeadingAddr) 704 OS << format("%8" PRIx64 ":", Address); 705 if (ShowRawInsn) { 706 OS << "\t"; 707 if (Bytes.size() >= 4) { 708 dumpBytes(Bytes.slice(0, 4), OS); 709 uint32_t opcode = 710 (Bytes[3] << 24) | (Bytes[2] << 16) | (Bytes[1] << 8) | Bytes[0]; 711 OS << format("\t%08" PRIx32, opcode); 712 } else { 713 dumpBytes(Bytes, OS); 714 } 715 } 716 } 717 void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes, 718 object::SectionedAddress Address, formatted_raw_ostream &OS, 719 StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP, 720 StringRef ObjectFilename, std::vector<RelocationRef> *Rels, 721 LiveVariablePrinter &LVP) override { 722 if (SP && (PrintSource || PrintLines)) 723 SP->printSourceLine(OS, Address, ObjectFilename, LVP, ""); 724 if (!MI) { 725 printLead(Bytes, Address.Address, OS); 726 OS << " <unknown>"; 727 return; 728 } 729 std::string Buffer; 730 { 731 raw_string_ostream TempStream(Buffer); 732 IP.printInst(MI, Address.Address, "", STI, TempStream); 733 } 734 StringRef Contents(Buffer); 735 // Split off bundle attributes 736 auto PacketBundle = Contents.rsplit('\n'); 737 // Split off first instruction from the rest 738 auto HeadTail = PacketBundle.first.split('\n'); 739 auto Preamble = " { "; 740 auto Separator = ""; 741 742 // Hexagon's packets require relocations to be inline rather than 743 // clustered at the end of the packet. 744 std::vector<RelocationRef>::const_iterator RelCur = Rels->begin(); 745 std::vector<RelocationRef>::const_iterator RelEnd = Rels->end(); 746 auto PrintReloc = [&]() -> void { 747 while ((RelCur != RelEnd) && (RelCur->getOffset() <= Address.Address)) { 748 if (RelCur->getOffset() == Address.Address) { 749 printRelocation(OS, ObjectFilename, *RelCur, Address.Address, false); 750 return; 751 } 752 ++RelCur; 753 } 754 }; 755 756 while (!HeadTail.first.empty()) { 757 OS << Separator; 758 Separator = "\n"; 759 if (SP && (PrintSource || PrintLines)) 760 SP->printSourceLine(OS, Address, ObjectFilename, LVP, ""); 761 printLead(Bytes, Address.Address, OS); 762 OS << Preamble; 763 Preamble = " "; 764 StringRef Inst; 765 auto Duplex = HeadTail.first.split('\v'); 766 if (!Duplex.second.empty()) { 767 OS << Duplex.first; 768 OS << "; "; 769 Inst = Duplex.second; 770 } 771 else 772 Inst = HeadTail.first; 773 OS << Inst; 774 HeadTail = HeadTail.second.split('\n'); 775 if (HeadTail.first.empty()) 776 OS << " } " << PacketBundle.second; 777 PrintReloc(); 778 Bytes = Bytes.slice(4); 779 Address.Address += 4; 780 } 781 } 782 }; 783 HexagonPrettyPrinter HexagonPrettyPrinterInst; 784 785 class AMDGCNPrettyPrinter : public PrettyPrinter { 786 public: 787 void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes, 788 object::SectionedAddress Address, formatted_raw_ostream &OS, 789 StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP, 790 StringRef ObjectFilename, std::vector<RelocationRef> *Rels, 791 LiveVariablePrinter &LVP) override { 792 if (SP && (PrintSource || PrintLines)) 793 SP->printSourceLine(OS, Address, ObjectFilename, LVP); 794 795 if (MI) { 796 SmallString<40> InstStr; 797 raw_svector_ostream IS(InstStr); 798 799 IP.printInst(MI, Address.Address, "", STI, IS); 800 801 OS << left_justify(IS.str(), 60); 802 } else { 803 // an unrecognized encoding - this is probably data so represent it 804 // using the .long directive, or .byte directive if fewer than 4 bytes 805 // remaining 806 if (Bytes.size() >= 4) { 807 OS << format( 808 "\t.long 0x%08" PRIx32 " ", 809 support::endian::read32<llvm::endianness::little>(Bytes.data())); 810 OS.indent(42); 811 } else { 812 OS << format("\t.byte 0x%02" PRIx8, Bytes[0]); 813 for (unsigned int i = 1; i < Bytes.size(); i++) 814 OS << format(", 0x%02" PRIx8, Bytes[i]); 815 OS.indent(55 - (6 * Bytes.size())); 816 } 817 } 818 819 OS << format("// %012" PRIX64 ":", Address.Address); 820 if (Bytes.size() >= 4) { 821 // D should be casted to uint32_t here as it is passed by format to 822 // snprintf as vararg. 823 for (uint32_t D : 824 ArrayRef(reinterpret_cast<const support::little32_t *>(Bytes.data()), 825 Bytes.size() / 4)) 826 OS << format(" %08" PRIX32, D); 827 } else { 828 for (unsigned char B : Bytes) 829 OS << format(" %02" PRIX8, B); 830 } 831 832 if (!Annot.empty()) 833 OS << " // " << Annot; 834 } 835 }; 836 AMDGCNPrettyPrinter AMDGCNPrettyPrinterInst; 837 838 class BPFPrettyPrinter : public PrettyPrinter { 839 public: 840 void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes, 841 object::SectionedAddress Address, formatted_raw_ostream &OS, 842 StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP, 843 StringRef ObjectFilename, std::vector<RelocationRef> *Rels, 844 LiveVariablePrinter &LVP) override { 845 if (SP && (PrintSource || PrintLines)) 846 SP->printSourceLine(OS, Address, ObjectFilename, LVP); 847 if (LeadingAddr) 848 OS << format("%8" PRId64 ":", Address.Address / 8); 849 if (ShowRawInsn) { 850 OS << "\t"; 851 dumpBytes(Bytes, OS); 852 } 853 if (MI) 854 IP.printInst(MI, Address.Address, "", STI, OS); 855 else 856 OS << "\t<unknown>"; 857 } 858 }; 859 BPFPrettyPrinter BPFPrettyPrinterInst; 860 861 class ARMPrettyPrinter : public PrettyPrinter { 862 public: 863 void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes, 864 object::SectionedAddress Address, formatted_raw_ostream &OS, 865 StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP, 866 StringRef ObjectFilename, std::vector<RelocationRef> *Rels, 867 LiveVariablePrinter &LVP) override { 868 if (SP && (PrintSource || PrintLines)) 869 SP->printSourceLine(OS, Address, ObjectFilename, LVP); 870 LVP.printBetweenInsts(OS, false); 871 872 size_t Start = OS.tell(); 873 if (LeadingAddr) 874 OS << format("%8" PRIx64 ":", Address.Address); 875 if (ShowRawInsn) { 876 size_t Pos = 0, End = Bytes.size(); 877 if (STI.checkFeatures("+thumb-mode")) { 878 for (; Pos + 2 <= End; Pos += 2) 879 OS << ' ' 880 << format_hex_no_prefix( 881 llvm::support::endian::read<uint16_t>( 882 Bytes.data() + Pos, InstructionEndianness), 883 4); 884 } else { 885 for (; Pos + 4 <= End; Pos += 4) 886 OS << ' ' 887 << format_hex_no_prefix( 888 llvm::support::endian::read<uint32_t>( 889 Bytes.data() + Pos, InstructionEndianness), 890 8); 891 } 892 if (Pos < End) { 893 OS << ' '; 894 dumpBytes(Bytes.slice(Pos), OS); 895 } 896 } 897 898 AlignToInstStartColumn(Start, STI, OS); 899 900 if (MI) { 901 IP.printInst(MI, Address.Address, "", STI, OS); 902 } else 903 OS << "\t<unknown>"; 904 } 905 906 void setInstructionEndianness(llvm::endianness Endianness) { 907 InstructionEndianness = Endianness; 908 } 909 910 private: 911 llvm::endianness InstructionEndianness = llvm::endianness::little; 912 }; 913 ARMPrettyPrinter ARMPrettyPrinterInst; 914 915 class AArch64PrettyPrinter : public PrettyPrinter { 916 public: 917 void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes, 918 object::SectionedAddress Address, formatted_raw_ostream &OS, 919 StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP, 920 StringRef ObjectFilename, std::vector<RelocationRef> *Rels, 921 LiveVariablePrinter &LVP) override { 922 if (SP && (PrintSource || PrintLines)) 923 SP->printSourceLine(OS, Address, ObjectFilename, LVP); 924 LVP.printBetweenInsts(OS, false); 925 926 size_t Start = OS.tell(); 927 if (LeadingAddr) 928 OS << format("%8" PRIx64 ":", Address.Address); 929 if (ShowRawInsn) { 930 size_t Pos = 0, End = Bytes.size(); 931 for (; Pos + 4 <= End; Pos += 4) 932 OS << ' ' 933 << format_hex_no_prefix( 934 llvm::support::endian::read<uint32_t>( 935 Bytes.data() + Pos, llvm::endianness::little), 936 8); 937 if (Pos < End) { 938 OS << ' '; 939 dumpBytes(Bytes.slice(Pos), OS); 940 } 941 } 942 943 AlignToInstStartColumn(Start, STI, OS); 944 945 if (MI) { 946 IP.printInst(MI, Address.Address, "", STI, OS); 947 } else 948 OS << "\t<unknown>"; 949 } 950 }; 951 AArch64PrettyPrinter AArch64PrettyPrinterInst; 952 953 class RISCVPrettyPrinter : public PrettyPrinter { 954 public: 955 void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes, 956 object::SectionedAddress Address, formatted_raw_ostream &OS, 957 StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP, 958 StringRef ObjectFilename, std::vector<RelocationRef> *Rels, 959 LiveVariablePrinter &LVP) override { 960 if (SP && (PrintSource || PrintLines)) 961 SP->printSourceLine(OS, Address, ObjectFilename, LVP); 962 LVP.printBetweenInsts(OS, false); 963 964 size_t Start = OS.tell(); 965 if (LeadingAddr) 966 OS << format("%8" PRIx64 ":", Address.Address); 967 if (ShowRawInsn) { 968 size_t Pos = 0, End = Bytes.size(); 969 if (End % 4 == 0) { 970 // 32-bit and 64-bit instructions. 971 for (; Pos + 4 <= End; Pos += 4) 972 OS << ' ' 973 << format_hex_no_prefix( 974 llvm::support::endian::read<uint32_t>( 975 Bytes.data() + Pos, llvm::endianness::little), 976 8); 977 } else if (End % 2 == 0) { 978 // 16-bit and 48-bits instructions. 979 for (; Pos + 2 <= End; Pos += 2) 980 OS << ' ' 981 << format_hex_no_prefix( 982 llvm::support::endian::read<uint16_t>( 983 Bytes.data() + Pos, llvm::endianness::little), 984 4); 985 } 986 if (Pos < End) { 987 OS << ' '; 988 dumpBytes(Bytes.slice(Pos), OS); 989 } 990 } 991 992 AlignToInstStartColumn(Start, STI, OS); 993 994 if (MI) { 995 IP.printInst(MI, Address.Address, "", STI, OS); 996 } else 997 OS << "\t<unknown>"; 998 } 999 }; 1000 RISCVPrettyPrinter RISCVPrettyPrinterInst; 1001 1002 PrettyPrinter &selectPrettyPrinter(Triple const &Triple) { 1003 switch(Triple.getArch()) { 1004 default: 1005 return PrettyPrinterInst; 1006 case Triple::hexagon: 1007 return HexagonPrettyPrinterInst; 1008 case Triple::amdgcn: 1009 return AMDGCNPrettyPrinterInst; 1010 case Triple::bpfel: 1011 case Triple::bpfeb: 1012 return BPFPrettyPrinterInst; 1013 case Triple::arm: 1014 case Triple::armeb: 1015 case Triple::thumb: 1016 case Triple::thumbeb: 1017 return ARMPrettyPrinterInst; 1018 case Triple::aarch64: 1019 case Triple::aarch64_be: 1020 case Triple::aarch64_32: 1021 return AArch64PrettyPrinterInst; 1022 case Triple::riscv32: 1023 case Triple::riscv64: 1024 return RISCVPrettyPrinterInst; 1025 } 1026 } 1027 1028 class DisassemblerTarget { 1029 public: 1030 const Target *TheTarget; 1031 std::unique_ptr<const MCSubtargetInfo> SubtargetInfo; 1032 std::shared_ptr<MCContext> Context; 1033 std::unique_ptr<MCDisassembler> DisAsm; 1034 std::shared_ptr<MCInstrAnalysis> InstrAnalysis; 1035 std::shared_ptr<MCInstPrinter> InstPrinter; 1036 PrettyPrinter *Printer; 1037 1038 DisassemblerTarget(const Target *TheTarget, ObjectFile &Obj, 1039 StringRef TripleName, StringRef MCPU, 1040 SubtargetFeatures &Features); 1041 DisassemblerTarget(DisassemblerTarget &Other, SubtargetFeatures &Features); 1042 1043 private: 1044 MCTargetOptions Options; 1045 std::shared_ptr<const MCRegisterInfo> RegisterInfo; 1046 std::shared_ptr<const MCAsmInfo> AsmInfo; 1047 std::shared_ptr<const MCInstrInfo> InstrInfo; 1048 std::shared_ptr<MCObjectFileInfo> ObjectFileInfo; 1049 }; 1050 1051 DisassemblerTarget::DisassemblerTarget(const Target *TheTarget, ObjectFile &Obj, 1052 StringRef TripleName, StringRef MCPU, 1053 SubtargetFeatures &Features) 1054 : TheTarget(TheTarget), 1055 Printer(&selectPrettyPrinter(Triple(TripleName))), 1056 RegisterInfo(TheTarget->createMCRegInfo(TripleName)) { 1057 if (!RegisterInfo) 1058 reportError(Obj.getFileName(), "no register info for target " + TripleName); 1059 1060 // Set up disassembler. 1061 AsmInfo.reset(TheTarget->createMCAsmInfo(*RegisterInfo, TripleName, Options)); 1062 if (!AsmInfo) 1063 reportError(Obj.getFileName(), "no assembly info for target " + TripleName); 1064 1065 SubtargetInfo.reset( 1066 TheTarget->createMCSubtargetInfo(TripleName, MCPU, Features.getString())); 1067 if (!SubtargetInfo) 1068 reportError(Obj.getFileName(), 1069 "no subtarget info for target " + TripleName); 1070 InstrInfo.reset(TheTarget->createMCInstrInfo()); 1071 if (!InstrInfo) 1072 reportError(Obj.getFileName(), 1073 "no instruction info for target " + TripleName); 1074 Context = 1075 std::make_shared<MCContext>(Triple(TripleName), AsmInfo.get(), 1076 RegisterInfo.get(), SubtargetInfo.get()); 1077 1078 // FIXME: for now initialize MCObjectFileInfo with default values 1079 ObjectFileInfo.reset( 1080 TheTarget->createMCObjectFileInfo(*Context, /*PIC=*/false)); 1081 Context->setObjectFileInfo(ObjectFileInfo.get()); 1082 1083 DisAsm.reset(TheTarget->createMCDisassembler(*SubtargetInfo, *Context)); 1084 if (!DisAsm) 1085 reportError(Obj.getFileName(), "no disassembler for target " + TripleName); 1086 1087 if (auto *ELFObj = dyn_cast<ELFObjectFileBase>(&Obj)) 1088 DisAsm->setABIVersion(ELFObj->getEIdentABIVersion()); 1089 1090 InstrAnalysis.reset(TheTarget->createMCInstrAnalysis(InstrInfo.get())); 1091 1092 int AsmPrinterVariant = AsmInfo->getAssemblerDialect(); 1093 InstPrinter.reset(TheTarget->createMCInstPrinter(Triple(TripleName), 1094 AsmPrinterVariant, *AsmInfo, 1095 *InstrInfo, *RegisterInfo)); 1096 if (!InstPrinter) 1097 reportError(Obj.getFileName(), 1098 "no instruction printer for target " + TripleName); 1099 InstPrinter->setPrintImmHex(PrintImmHex); 1100 InstPrinter->setPrintBranchImmAsAddress(true); 1101 InstPrinter->setSymbolizeOperands(SymbolizeOperands); 1102 InstPrinter->setMCInstrAnalysis(InstrAnalysis.get()); 1103 1104 switch (DisassemblyColor) { 1105 case ColorOutput::Enable: 1106 InstPrinter->setUseColor(true); 1107 break; 1108 case ColorOutput::Auto: 1109 InstPrinter->setUseColor(outs().has_colors()); 1110 break; 1111 case ColorOutput::Disable: 1112 case ColorOutput::Invalid: 1113 InstPrinter->setUseColor(false); 1114 break; 1115 }; 1116 } 1117 1118 DisassemblerTarget::DisassemblerTarget(DisassemblerTarget &Other, 1119 SubtargetFeatures &Features) 1120 : TheTarget(Other.TheTarget), 1121 SubtargetInfo(TheTarget->createMCSubtargetInfo(TripleName, MCPU, 1122 Features.getString())), 1123 Context(Other.Context), 1124 DisAsm(TheTarget->createMCDisassembler(*SubtargetInfo, *Context)), 1125 InstrAnalysis(Other.InstrAnalysis), InstPrinter(Other.InstPrinter), 1126 Printer(Other.Printer), RegisterInfo(Other.RegisterInfo), 1127 AsmInfo(Other.AsmInfo), InstrInfo(Other.InstrInfo), 1128 ObjectFileInfo(Other.ObjectFileInfo) {} 1129 } // namespace 1130 1131 static uint8_t getElfSymbolType(const ObjectFile &Obj, const SymbolRef &Sym) { 1132 assert(Obj.isELF()); 1133 if (auto *Elf32LEObj = dyn_cast<ELF32LEObjectFile>(&Obj)) 1134 return unwrapOrError(Elf32LEObj->getSymbol(Sym.getRawDataRefImpl()), 1135 Obj.getFileName()) 1136 ->getType(); 1137 if (auto *Elf64LEObj = dyn_cast<ELF64LEObjectFile>(&Obj)) 1138 return unwrapOrError(Elf64LEObj->getSymbol(Sym.getRawDataRefImpl()), 1139 Obj.getFileName()) 1140 ->getType(); 1141 if (auto *Elf32BEObj = dyn_cast<ELF32BEObjectFile>(&Obj)) 1142 return unwrapOrError(Elf32BEObj->getSymbol(Sym.getRawDataRefImpl()), 1143 Obj.getFileName()) 1144 ->getType(); 1145 if (auto *Elf64BEObj = cast<ELF64BEObjectFile>(&Obj)) 1146 return unwrapOrError(Elf64BEObj->getSymbol(Sym.getRawDataRefImpl()), 1147 Obj.getFileName()) 1148 ->getType(); 1149 llvm_unreachable("Unsupported binary format"); 1150 } 1151 1152 template <class ELFT> 1153 static void 1154 addDynamicElfSymbols(const ELFObjectFile<ELFT> &Obj, 1155 std::map<SectionRef, SectionSymbolsTy> &AllSymbols) { 1156 for (auto Symbol : Obj.getDynamicSymbolIterators()) { 1157 uint8_t SymbolType = Symbol.getELFType(); 1158 if (SymbolType == ELF::STT_SECTION) 1159 continue; 1160 1161 uint64_t Address = unwrapOrError(Symbol.getAddress(), Obj.getFileName()); 1162 // ELFSymbolRef::getAddress() returns size instead of value for common 1163 // symbols which is not desirable for disassembly output. Overriding. 1164 if (SymbolType == ELF::STT_COMMON) 1165 Address = unwrapOrError(Obj.getSymbol(Symbol.getRawDataRefImpl()), 1166 Obj.getFileName()) 1167 ->st_value; 1168 1169 StringRef Name = unwrapOrError(Symbol.getName(), Obj.getFileName()); 1170 if (Name.empty()) 1171 continue; 1172 1173 section_iterator SecI = 1174 unwrapOrError(Symbol.getSection(), Obj.getFileName()); 1175 if (SecI == Obj.section_end()) 1176 continue; 1177 1178 AllSymbols[*SecI].emplace_back(Address, Name, SymbolType); 1179 } 1180 } 1181 1182 static void 1183 addDynamicElfSymbols(const ELFObjectFileBase &Obj, 1184 std::map<SectionRef, SectionSymbolsTy> &AllSymbols) { 1185 if (auto *Elf32LEObj = dyn_cast<ELF32LEObjectFile>(&Obj)) 1186 addDynamicElfSymbols(*Elf32LEObj, AllSymbols); 1187 else if (auto *Elf64LEObj = dyn_cast<ELF64LEObjectFile>(&Obj)) 1188 addDynamicElfSymbols(*Elf64LEObj, AllSymbols); 1189 else if (auto *Elf32BEObj = dyn_cast<ELF32BEObjectFile>(&Obj)) 1190 addDynamicElfSymbols(*Elf32BEObj, AllSymbols); 1191 else if (auto *Elf64BEObj = cast<ELF64BEObjectFile>(&Obj)) 1192 addDynamicElfSymbols(*Elf64BEObj, AllSymbols); 1193 else 1194 llvm_unreachable("Unsupported binary format"); 1195 } 1196 1197 static std::optional<SectionRef> getWasmCodeSection(const WasmObjectFile &Obj) { 1198 for (auto SecI : Obj.sections()) { 1199 const WasmSection &Section = Obj.getWasmSection(SecI); 1200 if (Section.Type == wasm::WASM_SEC_CODE) 1201 return SecI; 1202 } 1203 return std::nullopt; 1204 } 1205 1206 static void 1207 addMissingWasmCodeSymbols(const WasmObjectFile &Obj, 1208 std::map<SectionRef, SectionSymbolsTy> &AllSymbols) { 1209 std::optional<SectionRef> Section = getWasmCodeSection(Obj); 1210 if (!Section) 1211 return; 1212 SectionSymbolsTy &Symbols = AllSymbols[*Section]; 1213 1214 std::set<uint64_t> SymbolAddresses; 1215 for (const auto &Sym : Symbols) 1216 SymbolAddresses.insert(Sym.Addr); 1217 1218 for (const wasm::WasmFunction &Function : Obj.functions()) { 1219 // This adjustment mirrors the one in WasmObjectFile::getSymbolAddress. 1220 uint32_t Adjustment = Obj.isRelocatableObject() || Obj.isSharedObject() 1221 ? 0 1222 : Section->getAddress(); 1223 uint64_t Address = Function.CodeSectionOffset + Adjustment; 1224 // Only add fallback symbols for functions not already present in the symbol 1225 // table. 1226 if (SymbolAddresses.count(Address)) 1227 continue; 1228 // This function has no symbol, so it should have no SymbolName. 1229 assert(Function.SymbolName.empty()); 1230 // We use DebugName for the name, though it may be empty if there is no 1231 // "name" custom section, or that section is missing a name for this 1232 // function. 1233 StringRef Name = Function.DebugName; 1234 Symbols.emplace_back(Address, Name, ELF::STT_NOTYPE); 1235 } 1236 } 1237 1238 static DenseMap<StringRef, SectionRef> getSectionNames(const ObjectFile &Obj) { 1239 DenseMap<StringRef, SectionRef> Sections; 1240 for (SectionRef Section : Obj.sections()) { 1241 Expected<StringRef> SecNameOrErr = Section.getName(); 1242 if (!SecNameOrErr) { 1243 consumeError(SecNameOrErr.takeError()); 1244 continue; 1245 } 1246 Sections[*SecNameOrErr] = Section; 1247 } 1248 return Sections; 1249 } 1250 1251 static void addPltEntries(const MCSubtargetInfo &STI, const ObjectFile &Obj, 1252 DenseMap<StringRef, SectionRef> &SectionNames, 1253 std::map<SectionRef, SectionSymbolsTy> &AllSymbols, 1254 StringSaver &Saver) { 1255 auto *ElfObj = dyn_cast<ELFObjectFileBase>(&Obj); 1256 if (!ElfObj) 1257 return; 1258 for (auto Plt : ElfObj->getPltEntries(STI)) { 1259 if (Plt.Symbol) { 1260 SymbolRef Symbol(*Plt.Symbol, ElfObj); 1261 uint8_t SymbolType = getElfSymbolType(Obj, Symbol); 1262 if (Expected<StringRef> NameOrErr = Symbol.getName()) { 1263 if (!NameOrErr->empty()) 1264 AllSymbols[SectionNames[Plt.Section]].emplace_back( 1265 Plt.Address, Saver.save((*NameOrErr + "@plt").str()), SymbolType); 1266 continue; 1267 } else { 1268 // The warning has been reported in disassembleObject(). 1269 consumeError(NameOrErr.takeError()); 1270 } 1271 } 1272 reportWarning("PLT entry at 0x" + Twine::utohexstr(Plt.Address) + 1273 " references an invalid symbol", 1274 Obj.getFileName()); 1275 } 1276 } 1277 1278 // Normally the disassembly output will skip blocks of zeroes. This function 1279 // returns the number of zero bytes that can be skipped when dumping the 1280 // disassembly of the instructions in Buf. 1281 static size_t countSkippableZeroBytes(ArrayRef<uint8_t> Buf) { 1282 // Find the number of leading zeroes. 1283 size_t N = 0; 1284 while (N < Buf.size() && !Buf[N]) 1285 ++N; 1286 1287 // We may want to skip blocks of zero bytes, but unless we see 1288 // at least 8 of them in a row. 1289 if (N < 8) 1290 return 0; 1291 1292 // We skip zeroes in multiples of 4 because do not want to truncate an 1293 // instruction if it starts with a zero byte. 1294 return N & ~0x3; 1295 } 1296 1297 // Returns a map from sections to their relocations. 1298 static std::map<SectionRef, std::vector<RelocationRef>> 1299 getRelocsMap(object::ObjectFile const &Obj) { 1300 std::map<SectionRef, std::vector<RelocationRef>> Ret; 1301 uint64_t I = (uint64_t)-1; 1302 for (SectionRef Sec : Obj.sections()) { 1303 ++I; 1304 Expected<section_iterator> RelocatedOrErr = Sec.getRelocatedSection(); 1305 if (!RelocatedOrErr) 1306 reportError(Obj.getFileName(), 1307 "section (" + Twine(I) + 1308 "): failed to get a relocated section: " + 1309 toString(RelocatedOrErr.takeError())); 1310 1311 section_iterator Relocated = *RelocatedOrErr; 1312 if (Relocated == Obj.section_end() || !checkSectionFilter(*Relocated).Keep) 1313 continue; 1314 std::vector<RelocationRef> &V = Ret[*Relocated]; 1315 append_range(V, Sec.relocations()); 1316 // Sort relocations by address. 1317 llvm::stable_sort(V, isRelocAddressLess); 1318 } 1319 return Ret; 1320 } 1321 1322 // Used for --adjust-vma to check if address should be adjusted by the 1323 // specified value for a given section. 1324 // For ELF we do not adjust non-allocatable sections like debug ones, 1325 // because they are not loadable. 1326 // TODO: implement for other file formats. 1327 static bool shouldAdjustVA(const SectionRef &Section) { 1328 const ObjectFile *Obj = Section.getObject(); 1329 if (Obj->isELF()) 1330 return ELFSectionRef(Section).getFlags() & ELF::SHF_ALLOC; 1331 return false; 1332 } 1333 1334 1335 typedef std::pair<uint64_t, char> MappingSymbolPair; 1336 static char getMappingSymbolKind(ArrayRef<MappingSymbolPair> MappingSymbols, 1337 uint64_t Address) { 1338 auto It = 1339 partition_point(MappingSymbols, [Address](const MappingSymbolPair &Val) { 1340 return Val.first <= Address; 1341 }); 1342 // Return zero for any address before the first mapping symbol; this means 1343 // we should use the default disassembly mode, depending on the target. 1344 if (It == MappingSymbols.begin()) 1345 return '\x00'; 1346 return (It - 1)->second; 1347 } 1348 1349 static uint64_t dumpARMELFData(uint64_t SectionAddr, uint64_t Index, 1350 uint64_t End, const ObjectFile &Obj, 1351 ArrayRef<uint8_t> Bytes, 1352 ArrayRef<MappingSymbolPair> MappingSymbols, 1353 const MCSubtargetInfo &STI, raw_ostream &OS) { 1354 llvm::endianness Endian = 1355 Obj.isLittleEndian() ? llvm::endianness::little : llvm::endianness::big; 1356 size_t Start = OS.tell(); 1357 OS << format("%8" PRIx64 ": ", SectionAddr + Index); 1358 if (Index + 4 <= End) { 1359 dumpBytes(Bytes.slice(Index, 4), OS); 1360 AlignToInstStartColumn(Start, STI, OS); 1361 OS << "\t.word\t" 1362 << format_hex(support::endian::read32(Bytes.data() + Index, Endian), 1363 10); 1364 return 4; 1365 } 1366 if (Index + 2 <= End) { 1367 dumpBytes(Bytes.slice(Index, 2), OS); 1368 AlignToInstStartColumn(Start, STI, OS); 1369 OS << "\t.short\t" 1370 << format_hex(support::endian::read16(Bytes.data() + Index, Endian), 6); 1371 return 2; 1372 } 1373 dumpBytes(Bytes.slice(Index, 1), OS); 1374 AlignToInstStartColumn(Start, STI, OS); 1375 OS << "\t.byte\t" << format_hex(Bytes[Index], 4); 1376 return 1; 1377 } 1378 1379 static void dumpELFData(uint64_t SectionAddr, uint64_t Index, uint64_t End, 1380 ArrayRef<uint8_t> Bytes, raw_ostream &OS) { 1381 // print out data up to 8 bytes at a time in hex and ascii 1382 uint8_t AsciiData[9] = {'\0'}; 1383 uint8_t Byte; 1384 int NumBytes = 0; 1385 1386 for (; Index < End; ++Index) { 1387 if (NumBytes == 0) 1388 OS << format("%8" PRIx64 ":", SectionAddr + Index); 1389 Byte = Bytes.slice(Index)[0]; 1390 OS << format(" %02x", Byte); 1391 AsciiData[NumBytes] = isPrint(Byte) ? Byte : '.'; 1392 1393 uint8_t IndentOffset = 0; 1394 NumBytes++; 1395 if (Index == End - 1 || NumBytes > 8) { 1396 // Indent the space for less than 8 bytes data. 1397 // 2 spaces for byte and one for space between bytes 1398 IndentOffset = 3 * (8 - NumBytes); 1399 for (int Excess = NumBytes; Excess < 8; Excess++) 1400 AsciiData[Excess] = '\0'; 1401 NumBytes = 8; 1402 } 1403 if (NumBytes == 8) { 1404 AsciiData[8] = '\0'; 1405 OS << std::string(IndentOffset, ' ') << " "; 1406 OS << reinterpret_cast<char *>(AsciiData); 1407 OS << '\n'; 1408 NumBytes = 0; 1409 } 1410 } 1411 } 1412 1413 SymbolInfoTy objdump::createSymbolInfo(const ObjectFile &Obj, 1414 const SymbolRef &Symbol, 1415 bool IsMappingSymbol) { 1416 const StringRef FileName = Obj.getFileName(); 1417 const uint64_t Addr = unwrapOrError(Symbol.getAddress(), FileName); 1418 const StringRef Name = unwrapOrError(Symbol.getName(), FileName); 1419 1420 if (Obj.isXCOFF() && (SymbolDescription || TracebackTable)) { 1421 const auto &XCOFFObj = cast<XCOFFObjectFile>(Obj); 1422 DataRefImpl SymbolDRI = Symbol.getRawDataRefImpl(); 1423 1424 const uint32_t SymbolIndex = XCOFFObj.getSymbolIndex(SymbolDRI.p); 1425 std::optional<XCOFF::StorageMappingClass> Smc = 1426 getXCOFFSymbolCsectSMC(XCOFFObj, Symbol); 1427 return SymbolInfoTy(Smc, Addr, Name, SymbolIndex, 1428 isLabel(XCOFFObj, Symbol)); 1429 } else if (Obj.isXCOFF()) { 1430 const SymbolRef::Type SymType = unwrapOrError(Symbol.getType(), FileName); 1431 return SymbolInfoTy(Addr, Name, SymType, /*IsMappingSymbol=*/false, 1432 /*IsXCOFF=*/true); 1433 } else if (Obj.isWasm()) { 1434 uint8_t SymType = 1435 cast<WasmObjectFile>(&Obj)->getWasmSymbol(Symbol).Info.Kind; 1436 return SymbolInfoTy(Addr, Name, SymType, false); 1437 } else { 1438 uint8_t Type = 1439 Obj.isELF() ? getElfSymbolType(Obj, Symbol) : (uint8_t)ELF::STT_NOTYPE; 1440 return SymbolInfoTy(Addr, Name, Type, IsMappingSymbol); 1441 } 1442 } 1443 1444 static SymbolInfoTy createDummySymbolInfo(const ObjectFile &Obj, 1445 const uint64_t Addr, StringRef &Name, 1446 uint8_t Type) { 1447 if (Obj.isXCOFF() && (SymbolDescription || TracebackTable)) 1448 return SymbolInfoTy(std::nullopt, Addr, Name, std::nullopt, false); 1449 if (Obj.isWasm()) 1450 return SymbolInfoTy(Addr, Name, wasm::WASM_SYMBOL_TYPE_SECTION); 1451 return SymbolInfoTy(Addr, Name, Type); 1452 } 1453 1454 static void collectBBAddrMapLabels( 1455 const BBAddrMapInfo &FullAddrMap, uint64_t SectionAddr, uint64_t Start, 1456 uint64_t End, 1457 std::unordered_map<uint64_t, std::vector<BBAddrMapLabel>> &Labels) { 1458 if (FullAddrMap.empty()) 1459 return; 1460 Labels.clear(); 1461 uint64_t StartAddress = SectionAddr + Start; 1462 uint64_t EndAddress = SectionAddr + End; 1463 const BBAddrMapFunctionEntry *FunctionMap = 1464 FullAddrMap.getEntryForAddress(StartAddress); 1465 if (!FunctionMap) 1466 return; 1467 std::optional<size_t> BBRangeIndex = 1468 FunctionMap->getAddrMap().getBBRangeIndexForBaseAddress(StartAddress); 1469 if (!BBRangeIndex) 1470 return; 1471 size_t NumBBEntriesBeforeRange = 0; 1472 for (size_t I = 0; I < *BBRangeIndex; ++I) 1473 NumBBEntriesBeforeRange += 1474 FunctionMap->getAddrMap().BBRanges[I].BBEntries.size(); 1475 const auto &BBRange = FunctionMap->getAddrMap().BBRanges[*BBRangeIndex]; 1476 for (size_t I = 0; I < BBRange.BBEntries.size(); ++I) { 1477 const BBAddrMap::BBEntry &BBEntry = BBRange.BBEntries[I]; 1478 uint64_t BBAddress = BBEntry.Offset + BBRange.BaseAddress; 1479 if (BBAddress >= EndAddress) 1480 continue; 1481 1482 std::string LabelString = ("BB" + Twine(BBEntry.ID)).str(); 1483 Labels[BBAddress].push_back( 1484 {LabelString, FunctionMap->constructPGOLabelString( 1485 NumBBEntriesBeforeRange + I, PrettyPGOAnalysisMap)}); 1486 } 1487 } 1488 1489 static void 1490 collectLocalBranchTargets(ArrayRef<uint8_t> Bytes, MCInstrAnalysis *MIA, 1491 MCDisassembler *DisAsm, MCInstPrinter *IP, 1492 const MCSubtargetInfo *STI, uint64_t SectionAddr, 1493 uint64_t Start, uint64_t End, 1494 std::unordered_map<uint64_t, std::string> &Labels) { 1495 // Supported by certain targets. 1496 const bool isPPC = STI->getTargetTriple().isPPC(); 1497 const bool isX86 = STI->getTargetTriple().isX86(); 1498 const bool isAArch64 = STI->getTargetTriple().isAArch64(); 1499 const bool isBPF = STI->getTargetTriple().isBPF(); 1500 if (!isPPC && !isX86 && !isAArch64 && !isBPF) 1501 return; 1502 1503 if (MIA) 1504 MIA->resetState(); 1505 1506 std::set<uint64_t> Targets; 1507 Start += SectionAddr; 1508 End += SectionAddr; 1509 const bool isXCOFF = STI->getTargetTriple().isOSBinFormatXCOFF(); 1510 for (uint64_t Index = Start; Index < End;) { 1511 // Disassemble a real instruction and record function-local branch labels. 1512 MCInst Inst; 1513 uint64_t Size; 1514 ArrayRef<uint8_t> ThisBytes = Bytes.slice(Index - SectionAddr); 1515 bool Disassembled = 1516 DisAsm->getInstruction(Inst, Size, ThisBytes, Index, nulls()); 1517 if (Size == 0) 1518 Size = std::min<uint64_t>(ThisBytes.size(), 1519 DisAsm->suggestBytesToSkip(ThisBytes, Index)); 1520 1521 if (MIA) { 1522 if (Disassembled) { 1523 uint64_t Target; 1524 bool TargetKnown = MIA->evaluateBranch(Inst, Index, Size, Target); 1525 if (TargetKnown && (Target >= Start && Target < End) && 1526 !Targets.count(Target)) { 1527 // On PowerPC and AIX, a function call is encoded as a branch to 0. 1528 // On other PowerPC platforms (ELF), a function call is encoded as 1529 // a branch to self. Do not add a label for these cases. 1530 if (!(isPPC && 1531 ((Target == 0 && isXCOFF) || (Target == Index && !isXCOFF)))) 1532 Targets.insert(Target); 1533 } 1534 MIA->updateState(Inst, Index); 1535 } else 1536 MIA->resetState(); 1537 } 1538 Index += Size; 1539 } 1540 1541 Labels.clear(); 1542 for (auto [Idx, Target] : enumerate(Targets)) 1543 Labels[Target] = ("L" + Twine(Idx)).str(); 1544 } 1545 1546 // Create an MCSymbolizer for the target and add it to the MCDisassembler. 1547 // This is currently only used on AMDGPU, and assumes the format of the 1548 // void * argument passed to AMDGPU's createMCSymbolizer. 1549 static void addSymbolizer( 1550 MCContext &Ctx, const Target *Target, StringRef TripleName, 1551 MCDisassembler *DisAsm, uint64_t SectionAddr, ArrayRef<uint8_t> Bytes, 1552 SectionSymbolsTy &Symbols, 1553 std::vector<std::unique_ptr<std::string>> &SynthesizedLabelNames) { 1554 1555 std::unique_ptr<MCRelocationInfo> RelInfo( 1556 Target->createMCRelocationInfo(TripleName, Ctx)); 1557 if (!RelInfo) 1558 return; 1559 std::unique_ptr<MCSymbolizer> Symbolizer(Target->createMCSymbolizer( 1560 TripleName, nullptr, nullptr, &Symbols, &Ctx, std::move(RelInfo))); 1561 MCSymbolizer *SymbolizerPtr = &*Symbolizer; 1562 DisAsm->setSymbolizer(std::move(Symbolizer)); 1563 1564 if (!SymbolizeOperands) 1565 return; 1566 1567 // Synthesize labels referenced by branch instructions by 1568 // disassembling, discarding the output, and collecting the referenced 1569 // addresses from the symbolizer. 1570 for (size_t Index = 0; Index != Bytes.size();) { 1571 MCInst Inst; 1572 uint64_t Size; 1573 ArrayRef<uint8_t> ThisBytes = Bytes.slice(Index); 1574 const uint64_t ThisAddr = SectionAddr + Index; 1575 DisAsm->getInstruction(Inst, Size, ThisBytes, ThisAddr, nulls()); 1576 if (Size == 0) 1577 Size = std::min<uint64_t>(ThisBytes.size(), 1578 DisAsm->suggestBytesToSkip(ThisBytes, Index)); 1579 Index += Size; 1580 } 1581 ArrayRef<uint64_t> LabelAddrsRef = SymbolizerPtr->getReferencedAddresses(); 1582 // Copy and sort to remove duplicates. 1583 std::vector<uint64_t> LabelAddrs; 1584 llvm::append_range(LabelAddrs, LabelAddrsRef); 1585 llvm::sort(LabelAddrs); 1586 LabelAddrs.resize(llvm::unique(LabelAddrs) - LabelAddrs.begin()); 1587 // Add the labels. 1588 for (unsigned LabelNum = 0; LabelNum != LabelAddrs.size(); ++LabelNum) { 1589 auto Name = std::make_unique<std::string>(); 1590 *Name = (Twine("L") + Twine(LabelNum)).str(); 1591 SynthesizedLabelNames.push_back(std::move(Name)); 1592 Symbols.push_back(SymbolInfoTy( 1593 LabelAddrs[LabelNum], *SynthesizedLabelNames.back(), ELF::STT_NOTYPE)); 1594 } 1595 llvm::stable_sort(Symbols); 1596 // Recreate the symbolizer with the new symbols list. 1597 RelInfo.reset(Target->createMCRelocationInfo(TripleName, Ctx)); 1598 Symbolizer.reset(Target->createMCSymbolizer( 1599 TripleName, nullptr, nullptr, &Symbols, &Ctx, std::move(RelInfo))); 1600 DisAsm->setSymbolizer(std::move(Symbolizer)); 1601 } 1602 1603 static StringRef getSegmentName(const MachOObjectFile *MachO, 1604 const SectionRef &Section) { 1605 if (MachO) { 1606 DataRefImpl DR = Section.getRawDataRefImpl(); 1607 StringRef SegmentName = MachO->getSectionFinalSegmentName(DR); 1608 return SegmentName; 1609 } 1610 return ""; 1611 } 1612 1613 static void emitPostInstructionInfo(formatted_raw_ostream &FOS, 1614 const MCAsmInfo &MAI, 1615 const MCSubtargetInfo &STI, 1616 StringRef Comments, 1617 LiveVariablePrinter &LVP) { 1618 do { 1619 if (!Comments.empty()) { 1620 // Emit a line of comments. 1621 StringRef Comment; 1622 std::tie(Comment, Comments) = Comments.split('\n'); 1623 // MAI.getCommentColumn() assumes that instructions are printed at the 1624 // position of 8, while getInstStartColumn() returns the actual position. 1625 unsigned CommentColumn = 1626 MAI.getCommentColumn() - 8 + getInstStartColumn(STI); 1627 FOS.PadToColumn(CommentColumn); 1628 FOS << MAI.getCommentString() << ' ' << Comment; 1629 } 1630 LVP.printAfterInst(FOS); 1631 FOS << '\n'; 1632 } while (!Comments.empty()); 1633 FOS.flush(); 1634 } 1635 1636 static void createFakeELFSections(ObjectFile &Obj) { 1637 assert(Obj.isELF()); 1638 if (auto *Elf32LEObj = dyn_cast<ELF32LEObjectFile>(&Obj)) 1639 Elf32LEObj->createFakeSections(); 1640 else if (auto *Elf64LEObj = dyn_cast<ELF64LEObjectFile>(&Obj)) 1641 Elf64LEObj->createFakeSections(); 1642 else if (auto *Elf32BEObj = dyn_cast<ELF32BEObjectFile>(&Obj)) 1643 Elf32BEObj->createFakeSections(); 1644 else if (auto *Elf64BEObj = cast<ELF64BEObjectFile>(&Obj)) 1645 Elf64BEObj->createFakeSections(); 1646 else 1647 llvm_unreachable("Unsupported binary format"); 1648 } 1649 1650 // Tries to fetch a more complete version of the given object file using its 1651 // Build ID. Returns std::nullopt if nothing was found. 1652 static std::optional<OwningBinary<Binary>> 1653 fetchBinaryByBuildID(const ObjectFile &Obj) { 1654 object::BuildIDRef BuildID = getBuildID(&Obj); 1655 if (BuildID.empty()) 1656 return std::nullopt; 1657 std::optional<std::string> Path = BIDFetcher->fetch(BuildID); 1658 if (!Path) 1659 return std::nullopt; 1660 Expected<OwningBinary<Binary>> DebugBinary = createBinary(*Path); 1661 if (!DebugBinary) { 1662 reportWarning(toString(DebugBinary.takeError()), *Path); 1663 return std::nullopt; 1664 } 1665 return std::move(*DebugBinary); 1666 } 1667 1668 static void 1669 disassembleObject(ObjectFile &Obj, const ObjectFile &DbgObj, 1670 DisassemblerTarget &PrimaryTarget, 1671 std::optional<DisassemblerTarget> &SecondaryTarget, 1672 SourcePrinter &SP, bool InlineRelocs, raw_ostream &OS) { 1673 DisassemblerTarget *DT = &PrimaryTarget; 1674 bool PrimaryIsThumb = false; 1675 SmallVector<std::pair<uint64_t, uint64_t>, 0> CHPECodeMap; 1676 1677 if (SecondaryTarget) { 1678 if (isArmElf(Obj)) { 1679 PrimaryIsThumb = 1680 PrimaryTarget.SubtargetInfo->checkFeatures("+thumb-mode"); 1681 } else if (const auto *COFFObj = dyn_cast<COFFObjectFile>(&Obj)) { 1682 const chpe_metadata *CHPEMetadata = COFFObj->getCHPEMetadata(); 1683 if (CHPEMetadata && CHPEMetadata->CodeMapCount) { 1684 uintptr_t CodeMapInt; 1685 cantFail(COFFObj->getRvaPtr(CHPEMetadata->CodeMap, CodeMapInt)); 1686 auto CodeMap = reinterpret_cast<const chpe_range_entry *>(CodeMapInt); 1687 1688 for (uint32_t i = 0; i < CHPEMetadata->CodeMapCount; ++i) { 1689 if (CodeMap[i].getType() == chpe_range_type::Amd64 && 1690 CodeMap[i].Length) { 1691 // Store x86_64 CHPE code ranges. 1692 uint64_t Start = CodeMap[i].getStart() + COFFObj->getImageBase(); 1693 CHPECodeMap.emplace_back(Start, Start + CodeMap[i].Length); 1694 } 1695 } 1696 llvm::sort(CHPECodeMap); 1697 } 1698 } 1699 } 1700 1701 std::map<SectionRef, std::vector<RelocationRef>> RelocMap; 1702 if (InlineRelocs || Obj.isXCOFF()) 1703 RelocMap = getRelocsMap(Obj); 1704 bool Is64Bits = Obj.getBytesInAddress() > 4; 1705 1706 // Create a mapping from virtual address to symbol name. This is used to 1707 // pretty print the symbols while disassembling. 1708 std::map<SectionRef, SectionSymbolsTy> AllSymbols; 1709 std::map<SectionRef, SmallVector<MappingSymbolPair, 0>> AllMappingSymbols; 1710 SectionSymbolsTy AbsoluteSymbols; 1711 const StringRef FileName = Obj.getFileName(); 1712 const MachOObjectFile *MachO = dyn_cast<const MachOObjectFile>(&Obj); 1713 for (const SymbolRef &Symbol : Obj.symbols()) { 1714 Expected<StringRef> NameOrErr = Symbol.getName(); 1715 if (!NameOrErr) { 1716 reportWarning(toString(NameOrErr.takeError()), FileName); 1717 continue; 1718 } 1719 if (NameOrErr->empty() && !(Obj.isXCOFF() && SymbolDescription)) 1720 continue; 1721 1722 if (Obj.isELF() && 1723 (cantFail(Symbol.getFlags()) & SymbolRef::SF_FormatSpecific)) { 1724 // Symbol is intended not to be displayed by default (STT_FILE, 1725 // STT_SECTION, or a mapping symbol). Ignore STT_SECTION symbols. We will 1726 // synthesize a section symbol if no symbol is defined at offset 0. 1727 // 1728 // For a mapping symbol, store it within both AllSymbols and 1729 // AllMappingSymbols. If --show-all-symbols is unspecified, its label will 1730 // not be printed in disassembly listing. 1731 if (getElfSymbolType(Obj, Symbol) != ELF::STT_SECTION && 1732 hasMappingSymbols(Obj)) { 1733 section_iterator SecI = unwrapOrError(Symbol.getSection(), FileName); 1734 if (SecI != Obj.section_end()) { 1735 uint64_t SectionAddr = SecI->getAddress(); 1736 uint64_t Address = cantFail(Symbol.getAddress()); 1737 StringRef Name = *NameOrErr; 1738 if (Name.consume_front("$") && Name.size() && 1739 strchr("adtx", Name[0])) { 1740 AllMappingSymbols[*SecI].emplace_back(Address - SectionAddr, 1741 Name[0]); 1742 AllSymbols[*SecI].push_back( 1743 createSymbolInfo(Obj, Symbol, /*MappingSymbol=*/true)); 1744 } 1745 } 1746 } 1747 continue; 1748 } 1749 1750 if (MachO) { 1751 // __mh_(execute|dylib|dylinker|bundle|preload|object)_header are special 1752 // symbols that support MachO header introspection. They do not bind to 1753 // code locations and are irrelevant for disassembly. 1754 if (NameOrErr->starts_with("__mh_") && NameOrErr->ends_with("_header")) 1755 continue; 1756 // Don't ask a Mach-O STAB symbol for its section unless you know that 1757 // STAB symbol's section field refers to a valid section index. Otherwise 1758 // the symbol may error trying to load a section that does not exist. 1759 DataRefImpl SymDRI = Symbol.getRawDataRefImpl(); 1760 uint8_t NType = (MachO->is64Bit() ? 1761 MachO->getSymbol64TableEntry(SymDRI).n_type: 1762 MachO->getSymbolTableEntry(SymDRI).n_type); 1763 if (NType & MachO::N_STAB) 1764 continue; 1765 } 1766 1767 section_iterator SecI = unwrapOrError(Symbol.getSection(), FileName); 1768 if (SecI != Obj.section_end()) 1769 AllSymbols[*SecI].push_back(createSymbolInfo(Obj, Symbol)); 1770 else 1771 AbsoluteSymbols.push_back(createSymbolInfo(Obj, Symbol)); 1772 } 1773 1774 if (AllSymbols.empty() && Obj.isELF()) 1775 addDynamicElfSymbols(cast<ELFObjectFileBase>(Obj), AllSymbols); 1776 1777 if (Obj.isWasm()) 1778 addMissingWasmCodeSymbols(cast<WasmObjectFile>(Obj), AllSymbols); 1779 1780 if (Obj.isELF() && Obj.sections().empty()) 1781 createFakeELFSections(Obj); 1782 1783 DisassemblerTarget *PltTarget = DT; 1784 auto SectionNames = getSectionNames(Obj); 1785 if (SecondaryTarget && isArmElf(Obj)) { 1786 auto PltSectionRef = SectionNames.find(".plt"); 1787 if (PltSectionRef != SectionNames.end()) { 1788 bool PltIsThumb = false; 1789 for (auto [Addr, SymbolName] : AllMappingSymbols[PltSectionRef->second]) { 1790 if (Addr != 0) 1791 continue; 1792 1793 if (SymbolName == 't') { 1794 PltIsThumb = true; 1795 break; 1796 } 1797 if (SymbolName == 'a') 1798 break; 1799 } 1800 1801 if (PrimaryTarget.SubtargetInfo->checkFeatures("+thumb-mode")) 1802 PltTarget = PltIsThumb ? &PrimaryTarget : &*SecondaryTarget; 1803 else 1804 PltTarget = PltIsThumb ? &*SecondaryTarget : &PrimaryTarget; 1805 } 1806 } 1807 BumpPtrAllocator A; 1808 StringSaver Saver(A); 1809 addPltEntries(*PltTarget->SubtargetInfo, Obj, SectionNames, AllSymbols, 1810 Saver); 1811 1812 // Create a mapping from virtual address to section. An empty section can 1813 // cause more than one section at the same address. Sort such sections to be 1814 // before same-addressed non-empty sections so that symbol lookups prefer the 1815 // non-empty section. 1816 std::vector<std::pair<uint64_t, SectionRef>> SectionAddresses; 1817 for (SectionRef Sec : Obj.sections()) 1818 SectionAddresses.emplace_back(Sec.getAddress(), Sec); 1819 llvm::stable_sort(SectionAddresses, [](const auto &LHS, const auto &RHS) { 1820 if (LHS.first != RHS.first) 1821 return LHS.first < RHS.first; 1822 return LHS.second.getSize() < RHS.second.getSize(); 1823 }); 1824 1825 // Linked executables (.exe and .dll files) typically don't include a real 1826 // symbol table but they might contain an export table. 1827 if (const auto *COFFObj = dyn_cast<COFFObjectFile>(&Obj)) { 1828 for (const auto &ExportEntry : COFFObj->export_directories()) { 1829 StringRef Name; 1830 if (Error E = ExportEntry.getSymbolName(Name)) 1831 reportError(std::move(E), Obj.getFileName()); 1832 if (Name.empty()) 1833 continue; 1834 1835 uint32_t RVA; 1836 if (Error E = ExportEntry.getExportRVA(RVA)) 1837 reportError(std::move(E), Obj.getFileName()); 1838 1839 uint64_t VA = COFFObj->getImageBase() + RVA; 1840 auto Sec = partition_point( 1841 SectionAddresses, [VA](const std::pair<uint64_t, SectionRef> &O) { 1842 return O.first <= VA; 1843 }); 1844 if (Sec != SectionAddresses.begin()) { 1845 --Sec; 1846 AllSymbols[Sec->second].emplace_back(VA, Name, ELF::STT_NOTYPE); 1847 } else 1848 AbsoluteSymbols.emplace_back(VA, Name, ELF::STT_NOTYPE); 1849 } 1850 } 1851 1852 // Sort all the symbols, this allows us to use a simple binary search to find 1853 // Multiple symbols can have the same address. Use a stable sort to stabilize 1854 // the output. 1855 StringSet<> FoundDisasmSymbolSet; 1856 for (std::pair<const SectionRef, SectionSymbolsTy> &SecSyms : AllSymbols) 1857 llvm::stable_sort(SecSyms.second); 1858 llvm::stable_sort(AbsoluteSymbols); 1859 1860 std::unique_ptr<DWARFContext> DICtx; 1861 LiveVariablePrinter LVP(*DT->Context->getRegisterInfo(), *DT->SubtargetInfo); 1862 1863 if (DbgVariables != DVDisabled) { 1864 DICtx = DWARFContext::create(DbgObj); 1865 for (const std::unique_ptr<DWARFUnit> &CU : DICtx->compile_units()) 1866 LVP.addCompileUnit(CU->getUnitDIE(false)); 1867 } 1868 1869 LLVM_DEBUG(LVP.dump()); 1870 1871 BBAddrMapInfo FullAddrMap; 1872 auto ReadBBAddrMap = [&](std::optional<unsigned> SectionIndex = 1873 std::nullopt) { 1874 FullAddrMap.clear(); 1875 if (const auto *Elf = dyn_cast<ELFObjectFileBase>(&Obj)) { 1876 std::vector<PGOAnalysisMap> PGOAnalyses; 1877 auto BBAddrMapsOrErr = Elf->readBBAddrMap(SectionIndex, &PGOAnalyses); 1878 if (!BBAddrMapsOrErr) { 1879 reportWarning(toString(BBAddrMapsOrErr.takeError()), Obj.getFileName()); 1880 return; 1881 } 1882 for (auto &&[FunctionBBAddrMap, FunctionPGOAnalysis] : 1883 zip_equal(*std::move(BBAddrMapsOrErr), std::move(PGOAnalyses))) { 1884 FullAddrMap.AddFunctionEntry(std::move(FunctionBBAddrMap), 1885 std::move(FunctionPGOAnalysis)); 1886 } 1887 } 1888 }; 1889 1890 // For non-relocatable objects, Read all LLVM_BB_ADDR_MAP sections into a 1891 // single mapping, since they don't have any conflicts. 1892 if (SymbolizeOperands && !Obj.isRelocatableObject()) 1893 ReadBBAddrMap(); 1894 1895 std::optional<llvm::BTFParser> BTF; 1896 if (InlineRelocs && BTFParser::hasBTFSections(Obj)) { 1897 BTF.emplace(); 1898 BTFParser::ParseOptions Opts = {}; 1899 Opts.LoadTypes = true; 1900 Opts.LoadRelocs = true; 1901 if (Error E = BTF->parse(Obj, Opts)) 1902 WithColor::defaultErrorHandler(std::move(E)); 1903 } 1904 1905 for (const SectionRef &Section : ToolSectionFilter(Obj)) { 1906 if (FilterSections.empty() && !DisassembleAll && 1907 (!Section.isText() || Section.isVirtual())) 1908 continue; 1909 1910 uint64_t SectionAddr = Section.getAddress(); 1911 uint64_t SectSize = Section.getSize(); 1912 if (!SectSize) 1913 continue; 1914 1915 // For relocatable object files, read the LLVM_BB_ADDR_MAP section 1916 // corresponding to this section, if present. 1917 if (SymbolizeOperands && Obj.isRelocatableObject()) 1918 ReadBBAddrMap(Section.getIndex()); 1919 1920 // Get the list of all the symbols in this section. 1921 SectionSymbolsTy &Symbols = AllSymbols[Section]; 1922 auto &MappingSymbols = AllMappingSymbols[Section]; 1923 llvm::sort(MappingSymbols); 1924 1925 ArrayRef<uint8_t> Bytes = arrayRefFromStringRef( 1926 unwrapOrError(Section.getContents(), Obj.getFileName())); 1927 1928 std::vector<std::unique_ptr<std::string>> SynthesizedLabelNames; 1929 if (Obj.isELF() && Obj.getArch() == Triple::amdgcn) { 1930 // AMDGPU disassembler uses symbolizer for printing labels 1931 addSymbolizer(*DT->Context, DT->TheTarget, TripleName, DT->DisAsm.get(), 1932 SectionAddr, Bytes, Symbols, SynthesizedLabelNames); 1933 } 1934 1935 StringRef SegmentName = getSegmentName(MachO, Section); 1936 StringRef SectionName = unwrapOrError(Section.getName(), Obj.getFileName()); 1937 // If the section has no symbol at the start, just insert a dummy one. 1938 // Without --show-all-symbols, also insert one if all symbols at the start 1939 // are mapping symbols. 1940 bool CreateDummy = Symbols.empty(); 1941 if (!CreateDummy) { 1942 CreateDummy = true; 1943 for (auto &Sym : Symbols) { 1944 if (Sym.Addr != SectionAddr) 1945 break; 1946 if (!Sym.IsMappingSymbol || ShowAllSymbols) 1947 CreateDummy = false; 1948 } 1949 } 1950 if (CreateDummy) { 1951 SymbolInfoTy Sym = createDummySymbolInfo( 1952 Obj, SectionAddr, SectionName, 1953 Section.isText() ? ELF::STT_FUNC : ELF::STT_OBJECT); 1954 if (Obj.isXCOFF()) 1955 Symbols.insert(Symbols.begin(), Sym); 1956 else 1957 Symbols.insert(llvm::lower_bound(Symbols, Sym), Sym); 1958 } 1959 1960 SmallString<40> Comments; 1961 raw_svector_ostream CommentStream(Comments); 1962 1963 uint64_t VMAAdjustment = 0; 1964 if (shouldAdjustVA(Section)) 1965 VMAAdjustment = AdjustVMA; 1966 1967 // In executable and shared objects, r_offset holds a virtual address. 1968 // Subtract SectionAddr from the r_offset field of a relocation to get 1969 // the section offset. 1970 uint64_t RelAdjustment = Obj.isRelocatableObject() ? 0 : SectionAddr; 1971 uint64_t Size; 1972 uint64_t Index; 1973 bool PrintedSection = false; 1974 std::vector<RelocationRef> Rels = RelocMap[Section]; 1975 std::vector<RelocationRef>::const_iterator RelCur = Rels.begin(); 1976 std::vector<RelocationRef>::const_iterator RelEnd = Rels.end(); 1977 1978 // Loop over each chunk of code between two points where at least 1979 // one symbol is defined. 1980 for (size_t SI = 0, SE = Symbols.size(); SI != SE;) { 1981 // Advance SI past all the symbols starting at the same address, 1982 // and make an ArrayRef of them. 1983 unsigned FirstSI = SI; 1984 uint64_t Start = Symbols[SI].Addr; 1985 ArrayRef<SymbolInfoTy> SymbolsHere; 1986 while (SI != SE && Symbols[SI].Addr == Start) 1987 ++SI; 1988 SymbolsHere = ArrayRef<SymbolInfoTy>(&Symbols[FirstSI], SI - FirstSI); 1989 1990 // Get the demangled names of all those symbols. We end up with a vector 1991 // of StringRef that holds the names we're going to use, and a vector of 1992 // std::string that stores the new strings returned by demangle(), if 1993 // any. If we don't call demangle() then that vector can stay empty. 1994 std::vector<StringRef> SymNamesHere; 1995 std::vector<std::string> DemangledSymNamesHere; 1996 if (Demangle) { 1997 // Fetch the demangled names and store them locally. 1998 for (const SymbolInfoTy &Symbol : SymbolsHere) 1999 DemangledSymNamesHere.push_back(demangle(Symbol.Name)); 2000 // Now we've finished modifying that vector, it's safe to make 2001 // a vector of StringRefs pointing into it. 2002 SymNamesHere.insert(SymNamesHere.begin(), DemangledSymNamesHere.begin(), 2003 DemangledSymNamesHere.end()); 2004 } else { 2005 for (const SymbolInfoTy &Symbol : SymbolsHere) 2006 SymNamesHere.push_back(Symbol.Name); 2007 } 2008 2009 // Distinguish ELF data from code symbols, which will be used later on to 2010 // decide whether to 'disassemble' this chunk as a data declaration via 2011 // dumpELFData(), or whether to treat it as code. 2012 // 2013 // If data _and_ code symbols are defined at the same address, the code 2014 // takes priority, on the grounds that disassembling code is our main 2015 // purpose here, and it would be a worse failure to _not_ interpret 2016 // something that _was_ meaningful as code than vice versa. 2017 // 2018 // Any ELF symbol type that is not clearly data will be regarded as code. 2019 // In particular, one of the uses of STT_NOTYPE is for branch targets 2020 // inside functions, for which STT_FUNC would be inaccurate. 2021 // 2022 // So here, we spot whether there's any non-data symbol present at all, 2023 // and only set the DisassembleAsELFData flag if there isn't. Also, we use 2024 // this distinction to inform the decision of which symbol to print at 2025 // the head of the section, so that if we're printing code, we print a 2026 // code-related symbol name to go with it. 2027 bool DisassembleAsELFData = false; 2028 size_t DisplaySymIndex = SymbolsHere.size() - 1; 2029 if (Obj.isELF() && !DisassembleAll && Section.isText()) { 2030 DisassembleAsELFData = true; // unless we find a code symbol below 2031 2032 for (size_t i = 0; i < SymbolsHere.size(); ++i) { 2033 uint8_t SymTy = SymbolsHere[i].Type; 2034 if (SymTy != ELF::STT_OBJECT && SymTy != ELF::STT_COMMON) { 2035 DisassembleAsELFData = false; 2036 DisplaySymIndex = i; 2037 } 2038 } 2039 } 2040 2041 // Decide which symbol(s) from this collection we're going to print. 2042 std::vector<bool> SymsToPrint(SymbolsHere.size(), false); 2043 // If the user has given the --disassemble-symbols option, then we must 2044 // display every symbol in that set, and no others. 2045 if (!DisasmSymbolSet.empty()) { 2046 bool FoundAny = false; 2047 for (size_t i = 0; i < SymbolsHere.size(); ++i) { 2048 if (DisasmSymbolSet.count(SymNamesHere[i])) { 2049 SymsToPrint[i] = true; 2050 FoundAny = true; 2051 } 2052 } 2053 2054 // And if none of the symbols here is one that the user asked for, skip 2055 // disassembling this entire chunk of code. 2056 if (!FoundAny) 2057 continue; 2058 } else if (!SymbolsHere[DisplaySymIndex].IsMappingSymbol) { 2059 // Otherwise, print whichever symbol at this location is last in the 2060 // Symbols array, because that array is pre-sorted in a way intended to 2061 // correlate with priority of which symbol to display. 2062 SymsToPrint[DisplaySymIndex] = true; 2063 } 2064 2065 // Now that we know we're disassembling this section, override the choice 2066 // of which symbols to display by printing _all_ of them at this address 2067 // if the user asked for all symbols. 2068 // 2069 // That way, '--show-all-symbols --disassemble-symbol=foo' will print 2070 // only the chunk of code headed by 'foo', but also show any other 2071 // symbols defined at that address, such as aliases for 'foo', or the ARM 2072 // mapping symbol preceding its code. 2073 if (ShowAllSymbols) { 2074 for (size_t i = 0; i < SymbolsHere.size(); ++i) 2075 SymsToPrint[i] = true; 2076 } 2077 2078 if (Start < SectionAddr || StopAddress <= Start) 2079 continue; 2080 2081 FoundDisasmSymbolSet.insert_range(SymNamesHere); 2082 2083 // The end is the section end, the beginning of the next symbol, or 2084 // --stop-address. 2085 uint64_t End = std::min<uint64_t>(SectionAddr + SectSize, StopAddress); 2086 if (SI < SE) 2087 End = std::min(End, Symbols[SI].Addr); 2088 if (Start >= End || End <= StartAddress) 2089 continue; 2090 Start -= SectionAddr; 2091 End -= SectionAddr; 2092 2093 if (!PrintedSection) { 2094 PrintedSection = true; 2095 OS << "\nDisassembly of section "; 2096 if (!SegmentName.empty()) 2097 OS << SegmentName << ","; 2098 OS << SectionName << ":\n"; 2099 } 2100 2101 bool PrintedLabel = false; 2102 for (size_t i = 0; i < SymbolsHere.size(); ++i) { 2103 if (!SymsToPrint[i]) 2104 continue; 2105 2106 const SymbolInfoTy &Symbol = SymbolsHere[i]; 2107 const StringRef SymbolName = SymNamesHere[i]; 2108 2109 if (!PrintedLabel) { 2110 OS << '\n'; 2111 PrintedLabel = true; 2112 } 2113 if (LeadingAddr) 2114 OS << format(Is64Bits ? "%016" PRIx64 " " : "%08" PRIx64 " ", 2115 SectionAddr + Start + VMAAdjustment); 2116 if (Obj.isXCOFF() && SymbolDescription) { 2117 OS << getXCOFFSymbolDescription(Symbol, SymbolName) << ":\n"; 2118 } else 2119 OS << '<' << SymbolName << ">:\n"; 2120 } 2121 2122 // Don't print raw contents of a virtual section. A virtual section 2123 // doesn't have any contents in the file. 2124 if (Section.isVirtual()) { 2125 OS << "...\n"; 2126 continue; 2127 } 2128 2129 // See if any of the symbols defined at this location triggers target- 2130 // specific disassembly behavior, e.g. of special descriptors or function 2131 // prelude information. 2132 // 2133 // We stop this loop at the first symbol that triggers some kind of 2134 // interesting behavior (if any), on the assumption that if two symbols 2135 // defined at the same address trigger two conflicting symbol handlers, 2136 // the object file is probably confused anyway, and it would make even 2137 // less sense to present the output of _both_ handlers, because that 2138 // would describe the same data twice. 2139 for (size_t SHI = 0; SHI < SymbolsHere.size(); ++SHI) { 2140 SymbolInfoTy Symbol = SymbolsHere[SHI]; 2141 2142 Expected<bool> RespondedOrErr = DT->DisAsm->onSymbolStart( 2143 Symbol, Size, Bytes.slice(Start, End - Start), SectionAddr + Start); 2144 2145 if (RespondedOrErr && !*RespondedOrErr) { 2146 // This symbol didn't trigger any interesting handling. Try the other 2147 // symbols defined at this address. 2148 continue; 2149 } 2150 2151 // If onSymbolStart returned an Error, that means it identified some 2152 // kind of special data at this address, but wasn't able to disassemble 2153 // it meaningfully. So we fall back to printing the error out and 2154 // disassembling the failed region as bytes, assuming that the target 2155 // detected the failure before printing anything. 2156 if (!RespondedOrErr) { 2157 std::string ErrMsgStr = toString(RespondedOrErr.takeError()); 2158 StringRef ErrMsg = ErrMsgStr; 2159 do { 2160 StringRef Line; 2161 std::tie(Line, ErrMsg) = ErrMsg.split('\n'); 2162 OS << DT->Context->getAsmInfo()->getCommentString() 2163 << " error decoding " << SymNamesHere[SHI] << ": " << Line 2164 << '\n'; 2165 } while (!ErrMsg.empty()); 2166 2167 if (Size) { 2168 OS << DT->Context->getAsmInfo()->getCommentString() 2169 << " decoding failed region as bytes\n"; 2170 for (uint64_t I = 0; I < Size; ++I) 2171 OS << "\t.byte\t " << format_hex(Bytes[I], 1, /*Upper=*/true) 2172 << '\n'; 2173 } 2174 } 2175 2176 // Regardless of whether onSymbolStart returned an Error or true, 'Size' 2177 // will have been set to the amount of data covered by whatever prologue 2178 // the target identified. So we advance our own position to beyond that. 2179 // Sometimes that will be the entire distance to the next symbol, and 2180 // sometimes it will be just a prologue and we should start 2181 // disassembling instructions from where it left off. 2182 Start += Size; 2183 break; 2184 } 2185 formatted_raw_ostream FOS(OS); 2186 Index = Start; 2187 if (SectionAddr < StartAddress) 2188 Index = std::max<uint64_t>(Index, StartAddress - SectionAddr); 2189 2190 if (DisassembleAsELFData) { 2191 dumpELFData(SectionAddr, Index, End, Bytes, FOS); 2192 Index = End; 2193 continue; 2194 } 2195 2196 // Skip relocations from symbols that are not dumped. 2197 for (; RelCur != RelEnd; ++RelCur) { 2198 uint64_t Offset = RelCur->getOffset() - RelAdjustment; 2199 if (Index <= Offset) 2200 break; 2201 } 2202 2203 bool DumpARMELFData = false; 2204 bool DumpTracebackTableForXCOFFFunction = 2205 Obj.isXCOFF() && Section.isText() && TracebackTable && 2206 Symbols[SI - 1].XCOFFSymInfo.StorageMappingClass && 2207 (*Symbols[SI - 1].XCOFFSymInfo.StorageMappingClass == XCOFF::XMC_PR); 2208 2209 std::unordered_map<uint64_t, std::string> AllLabels; 2210 std::unordered_map<uint64_t, std::vector<BBAddrMapLabel>> BBAddrMapLabels; 2211 if (SymbolizeOperands) { 2212 collectLocalBranchTargets(Bytes, DT->InstrAnalysis.get(), 2213 DT->DisAsm.get(), DT->InstPrinter.get(), 2214 PrimaryTarget.SubtargetInfo.get(), 2215 SectionAddr, Index, End, AllLabels); 2216 collectBBAddrMapLabels(FullAddrMap, SectionAddr, Index, End, 2217 BBAddrMapLabels); 2218 } 2219 2220 if (DT->InstrAnalysis) 2221 DT->InstrAnalysis->resetState(); 2222 2223 while (Index < End) { 2224 uint64_t RelOffset; 2225 2226 // ARM and AArch64 ELF binaries can interleave data and text in the 2227 // same section. We rely on the markers introduced to understand what 2228 // we need to dump. If the data marker is within a function, it is 2229 // denoted as a word/short etc. 2230 if (!MappingSymbols.empty()) { 2231 char Kind = getMappingSymbolKind(MappingSymbols, Index); 2232 DumpARMELFData = Kind == 'd'; 2233 if (SecondaryTarget) { 2234 if (Kind == 'a') { 2235 DT = PrimaryIsThumb ? &*SecondaryTarget : &PrimaryTarget; 2236 } else if (Kind == 't') { 2237 DT = PrimaryIsThumb ? &PrimaryTarget : &*SecondaryTarget; 2238 } 2239 } 2240 } else if (!CHPECodeMap.empty()) { 2241 uint64_t Address = SectionAddr + Index; 2242 auto It = partition_point( 2243 CHPECodeMap, 2244 [Address](const std::pair<uint64_t, uint64_t> &Entry) { 2245 return Entry.first <= Address; 2246 }); 2247 if (It != CHPECodeMap.begin() && Address < (It - 1)->second) { 2248 DT = &*SecondaryTarget; 2249 } else { 2250 DT = &PrimaryTarget; 2251 // X64 disassembler range may have left Index unaligned, so 2252 // make sure that it's aligned when we switch back to ARM64 2253 // code. 2254 Index = llvm::alignTo(Index, 4); 2255 if (Index >= End) 2256 break; 2257 } 2258 } 2259 2260 auto findRel = [&]() { 2261 while (RelCur != RelEnd) { 2262 RelOffset = RelCur->getOffset() - RelAdjustment; 2263 // If this relocation is hidden, skip it. 2264 if (getHidden(*RelCur) || SectionAddr + RelOffset < StartAddress) { 2265 ++RelCur; 2266 continue; 2267 } 2268 2269 // Stop when RelCur's offset is past the disassembled 2270 // instruction/data. 2271 if (RelOffset >= Index + Size) 2272 return false; 2273 if (RelOffset >= Index) 2274 return true; 2275 ++RelCur; 2276 } 2277 return false; 2278 }; 2279 2280 // When -z or --disassemble-zeroes are given we always dissasemble 2281 // them. Otherwise we might want to skip zero bytes we see. 2282 if (!DisassembleZeroes) { 2283 uint64_t MaxOffset = End - Index; 2284 // For --reloc: print zero blocks patched by relocations, so that 2285 // relocations can be shown in the dump. 2286 if (InlineRelocs && RelCur != RelEnd) 2287 MaxOffset = std::min(RelCur->getOffset() - RelAdjustment - Index, 2288 MaxOffset); 2289 2290 if (size_t N = 2291 countSkippableZeroBytes(Bytes.slice(Index, MaxOffset))) { 2292 FOS << "\t\t..." << '\n'; 2293 Index += N; 2294 continue; 2295 } 2296 } 2297 2298 if (DumpARMELFData) { 2299 Size = dumpARMELFData(SectionAddr, Index, End, Obj, Bytes, 2300 MappingSymbols, *DT->SubtargetInfo, FOS); 2301 } else { 2302 2303 if (DumpTracebackTableForXCOFFFunction && 2304 doesXCOFFTracebackTableBegin(Bytes.slice(Index, 4))) { 2305 dumpTracebackTable(Bytes.slice(Index), 2306 SectionAddr + Index + VMAAdjustment, FOS, 2307 SectionAddr + End + VMAAdjustment, 2308 *DT->SubtargetInfo, cast<XCOFFObjectFile>(&Obj)); 2309 Index = End; 2310 continue; 2311 } 2312 2313 // Print local label if there's any. 2314 auto Iter1 = BBAddrMapLabels.find(SectionAddr + Index); 2315 if (Iter1 != BBAddrMapLabels.end()) { 2316 for (const auto &BBLabel : Iter1->second) 2317 FOS << "<" << BBLabel.BlockLabel << ">" << BBLabel.PGOAnalysis 2318 << ":\n"; 2319 } else { 2320 auto Iter2 = AllLabels.find(SectionAddr + Index); 2321 if (Iter2 != AllLabels.end()) 2322 FOS << "<" << Iter2->second << ">:\n"; 2323 } 2324 2325 // Disassemble a real instruction or a data when disassemble all is 2326 // provided 2327 MCInst Inst; 2328 ArrayRef<uint8_t> ThisBytes = Bytes.slice(Index); 2329 uint64_t ThisAddr = SectionAddr + Index + VMAAdjustment; 2330 bool Disassembled = DT->DisAsm->getInstruction( 2331 Inst, Size, ThisBytes, ThisAddr, CommentStream); 2332 if (Size == 0) 2333 Size = std::min<uint64_t>( 2334 ThisBytes.size(), 2335 DT->DisAsm->suggestBytesToSkip(ThisBytes, ThisAddr)); 2336 2337 LVP.update({Index, Section.getIndex()}, 2338 {Index + Size, Section.getIndex()}, Index + Size != End); 2339 2340 DT->InstPrinter->setCommentStream(CommentStream); 2341 2342 DT->Printer->printInst( 2343 *DT->InstPrinter, Disassembled ? &Inst : nullptr, 2344 Bytes.slice(Index, Size), 2345 {SectionAddr + Index + VMAAdjustment, Section.getIndex()}, FOS, 2346 "", *DT->SubtargetInfo, &SP, Obj.getFileName(), &Rels, LVP); 2347 2348 DT->InstPrinter->setCommentStream(llvm::nulls()); 2349 2350 // If disassembly succeeds, we try to resolve the target address 2351 // (jump target or memory operand address) and print it to the 2352 // right of the instruction. 2353 // 2354 // Otherwise, we don't print anything else so that we avoid 2355 // analyzing invalid or incomplete instruction information. 2356 if (Disassembled && DT->InstrAnalysis) { 2357 llvm::raw_ostream *TargetOS = &FOS; 2358 uint64_t Target; 2359 bool PrintTarget = DT->InstrAnalysis->evaluateBranch( 2360 Inst, SectionAddr + Index, Size, Target); 2361 2362 if (!PrintTarget) { 2363 if (std::optional<uint64_t> MaybeTarget = 2364 DT->InstrAnalysis->evaluateMemoryOperandAddress( 2365 Inst, DT->SubtargetInfo.get(), SectionAddr + Index, 2366 Size)) { 2367 Target = *MaybeTarget; 2368 PrintTarget = true; 2369 // Do not print real address when symbolizing. 2370 if (!SymbolizeOperands) { 2371 // Memory operand addresses are printed as comments. 2372 TargetOS = &CommentStream; 2373 *TargetOS << "0x" << Twine::utohexstr(Target); 2374 } 2375 } 2376 } 2377 2378 if (PrintTarget) { 2379 // In a relocatable object, the target's section must reside in 2380 // the same section as the call instruction or it is accessed 2381 // through a relocation. 2382 // 2383 // In a non-relocatable object, the target may be in any section. 2384 // In that case, locate the section(s) containing the target 2385 // address and find the symbol in one of those, if possible. 2386 // 2387 // N.B. Except for XCOFF, we don't walk the relocations in the 2388 // relocatable case yet. 2389 std::vector<const SectionSymbolsTy *> TargetSectionSymbols; 2390 if (!Obj.isRelocatableObject()) { 2391 auto It = llvm::partition_point( 2392 SectionAddresses, 2393 [=](const std::pair<uint64_t, SectionRef> &O) { 2394 return O.first <= Target; 2395 }); 2396 uint64_t TargetSecAddr = 0; 2397 while (It != SectionAddresses.begin()) { 2398 --It; 2399 if (TargetSecAddr == 0) 2400 TargetSecAddr = It->first; 2401 if (It->first != TargetSecAddr) 2402 break; 2403 TargetSectionSymbols.push_back(&AllSymbols[It->second]); 2404 } 2405 } else { 2406 TargetSectionSymbols.push_back(&Symbols); 2407 } 2408 TargetSectionSymbols.push_back(&AbsoluteSymbols); 2409 2410 // Find the last symbol in the first candidate section whose 2411 // offset is less than or equal to the target. If there are no 2412 // such symbols, try in the next section and so on, before finally 2413 // using the nearest preceding absolute symbol (if any), if there 2414 // are no other valid symbols. 2415 const SymbolInfoTy *TargetSym = nullptr; 2416 for (const SectionSymbolsTy *TargetSymbols : 2417 TargetSectionSymbols) { 2418 auto It = llvm::partition_point( 2419 *TargetSymbols, 2420 [=](const SymbolInfoTy &O) { return O.Addr <= Target; }); 2421 while (It != TargetSymbols->begin()) { 2422 --It; 2423 // Skip mapping symbols to avoid possible ambiguity as they 2424 // do not allow uniquely identifying the target address. 2425 if (!It->IsMappingSymbol) { 2426 TargetSym = &*It; 2427 break; 2428 } 2429 } 2430 if (TargetSym) 2431 break; 2432 } 2433 2434 // Branch targets are printed just after the instructions. 2435 // Print the labels corresponding to the target if there's any. 2436 bool BBAddrMapLabelAvailable = BBAddrMapLabels.count(Target); 2437 bool LabelAvailable = AllLabels.count(Target); 2438 2439 if (TargetSym != nullptr) { 2440 uint64_t TargetAddress = TargetSym->Addr; 2441 uint64_t Disp = Target - TargetAddress; 2442 std::string TargetName = Demangle ? demangle(TargetSym->Name) 2443 : TargetSym->Name.str(); 2444 bool RelFixedUp = false; 2445 SmallString<32> Val; 2446 2447 *TargetOS << " <"; 2448 // On XCOFF, we use relocations, even without -r, so we 2449 // can print the correct name for an extern function call. 2450 if (Obj.isXCOFF() && findRel()) { 2451 // Check for possible branch relocations and 2452 // branches to fixup code. 2453 bool BranchRelocationType = true; 2454 XCOFF::RelocationType RelocType; 2455 if (Obj.is64Bit()) { 2456 const XCOFFRelocation64 *Reloc = 2457 reinterpret_cast<XCOFFRelocation64 *>( 2458 RelCur->getRawDataRefImpl().p); 2459 RelFixedUp = Reloc->isFixupIndicated(); 2460 RelocType = Reloc->Type; 2461 } else { 2462 const XCOFFRelocation32 *Reloc = 2463 reinterpret_cast<XCOFFRelocation32 *>( 2464 RelCur->getRawDataRefImpl().p); 2465 RelFixedUp = Reloc->isFixupIndicated(); 2466 RelocType = Reloc->Type; 2467 } 2468 BranchRelocationType = 2469 RelocType == XCOFF::R_BA || RelocType == XCOFF::R_BR || 2470 RelocType == XCOFF::R_RBA || RelocType == XCOFF::R_RBR; 2471 2472 // If we have a valid relocation, try to print its 2473 // corresponding symbol name. Multiple relocations on the 2474 // same instruction are not handled. 2475 // Branches to fixup code will have the RelFixedUp flag set in 2476 // the RLD. For these instructions, we print the correct 2477 // branch target, but print the referenced symbol as a 2478 // comment. 2479 if (Error E = getRelocationValueString(*RelCur, false, Val)) { 2480 // If -r was used, this error will be printed later. 2481 // Otherwise, we ignore the error and print what 2482 // would have been printed without using relocations. 2483 consumeError(std::move(E)); 2484 *TargetOS << TargetName; 2485 RelFixedUp = false; // Suppress comment for RLD sym name 2486 } else if (BranchRelocationType && !RelFixedUp) 2487 *TargetOS << Val; 2488 else 2489 *TargetOS << TargetName; 2490 if (Disp) 2491 *TargetOS << "+0x" << Twine::utohexstr(Disp); 2492 } else if (!Disp) { 2493 *TargetOS << TargetName; 2494 } else if (BBAddrMapLabelAvailable) { 2495 *TargetOS << BBAddrMapLabels[Target].front().BlockLabel; 2496 } else if (LabelAvailable) { 2497 *TargetOS << AllLabels[Target]; 2498 } else { 2499 // Always Print the binary symbol plus an offset if there's no 2500 // local label corresponding to the target address. 2501 *TargetOS << TargetName << "+0x" << Twine::utohexstr(Disp); 2502 } 2503 *TargetOS << ">"; 2504 if (RelFixedUp && !InlineRelocs) { 2505 // We have fixup code for a relocation. We print the 2506 // referenced symbol as a comment. 2507 *TargetOS << "\t# " << Val; 2508 } 2509 2510 } else if (BBAddrMapLabelAvailable) { 2511 *TargetOS << " <" << BBAddrMapLabels[Target].front().BlockLabel 2512 << ">"; 2513 } else if (LabelAvailable) { 2514 *TargetOS << " <" << AllLabels[Target] << ">"; 2515 } 2516 // By convention, each record in the comment stream should be 2517 // terminated. 2518 if (TargetOS == &CommentStream) 2519 *TargetOS << "\n"; 2520 } 2521 2522 DT->InstrAnalysis->updateState(Inst, SectionAddr + Index); 2523 } else if (!Disassembled && DT->InstrAnalysis) { 2524 DT->InstrAnalysis->resetState(); 2525 } 2526 } 2527 2528 assert(DT->Context->getAsmInfo()); 2529 emitPostInstructionInfo(FOS, *DT->Context->getAsmInfo(), 2530 *DT->SubtargetInfo, CommentStream.str(), LVP); 2531 Comments.clear(); 2532 2533 if (BTF) 2534 printBTFRelocation(FOS, *BTF, {Index, Section.getIndex()}, LVP); 2535 2536 // Hexagon handles relocs in pretty printer 2537 if (InlineRelocs && Obj.getArch() != Triple::hexagon) { 2538 while (findRel()) { 2539 // When --adjust-vma is used, update the address printed. 2540 printRelocation(FOS, Obj.getFileName(), *RelCur, 2541 SectionAddr + RelOffset + VMAAdjustment, Is64Bits); 2542 LVP.printAfterOtherLine(FOS, true); 2543 ++RelCur; 2544 } 2545 } 2546 2547 Index += Size; 2548 } 2549 } 2550 } 2551 StringSet<> MissingDisasmSymbolSet = 2552 set_difference(DisasmSymbolSet, FoundDisasmSymbolSet); 2553 for (StringRef Sym : MissingDisasmSymbolSet.keys()) 2554 reportWarning("failed to disassemble missing symbol " + Sym, FileName); 2555 } 2556 2557 static void disassembleObject(ObjectFile *Obj, bool InlineRelocs, 2558 raw_ostream &OS) { 2559 // If information useful for showing the disassembly is missing, try to find a 2560 // more complete binary and disassemble that instead. 2561 OwningBinary<Binary> FetchedBinary; 2562 if (Obj->symbols().empty()) { 2563 if (std::optional<OwningBinary<Binary>> FetchedBinaryOpt = 2564 fetchBinaryByBuildID(*Obj)) { 2565 if (auto *O = dyn_cast<ObjectFile>(FetchedBinaryOpt->getBinary())) { 2566 if (!O->symbols().empty() || 2567 (!O->sections().empty() && Obj->sections().empty())) { 2568 FetchedBinary = std::move(*FetchedBinaryOpt); 2569 Obj = O; 2570 } 2571 } 2572 } 2573 } 2574 2575 const Target *TheTarget = getTarget(Obj); 2576 2577 // Package up features to be passed to target/subtarget 2578 Expected<SubtargetFeatures> FeaturesValue = Obj->getFeatures(); 2579 if (!FeaturesValue) 2580 reportError(FeaturesValue.takeError(), Obj->getFileName()); 2581 SubtargetFeatures Features = *FeaturesValue; 2582 if (!MAttrs.empty()) { 2583 for (unsigned I = 0; I != MAttrs.size(); ++I) 2584 Features.AddFeature(MAttrs[I]); 2585 } else if (MCPU.empty() && Obj->makeTriple().isAArch64()) { 2586 Features.AddFeature("+all"); 2587 } 2588 2589 if (MCPU.empty()) 2590 MCPU = Obj->tryGetCPUName().value_or("").str(); 2591 2592 if (isArmElf(*Obj)) { 2593 // When disassembling big-endian Arm ELF, the instruction endianness is 2594 // determined in a complex way. In relocatable objects, AAELF32 mandates 2595 // that instruction endianness matches the ELF file endianness; in 2596 // executable images, that's true unless the file header has the EF_ARM_BE8 2597 // flag, in which case instructions are little-endian regardless of data 2598 // endianness. 2599 // 2600 // We must set the big-endian-instructions SubtargetFeature to make the 2601 // disassembler read the instructions the right way round, and also tell 2602 // our own prettyprinter to retrieve the encodings the same way to print in 2603 // hex. 2604 const auto *Elf32BE = dyn_cast<ELF32BEObjectFile>(Obj); 2605 2606 if (Elf32BE && (Elf32BE->isRelocatableObject() || 2607 !(Elf32BE->getPlatformFlags() & ELF::EF_ARM_BE8))) { 2608 Features.AddFeature("+big-endian-instructions"); 2609 ARMPrettyPrinterInst.setInstructionEndianness(llvm::endianness::big); 2610 } else { 2611 ARMPrettyPrinterInst.setInstructionEndianness(llvm::endianness::little); 2612 } 2613 } 2614 2615 DisassemblerTarget PrimaryTarget(TheTarget, *Obj, TripleName, MCPU, Features); 2616 2617 // If we have an ARM object file, we need a second disassembler, because 2618 // ARM CPUs have two different instruction sets: ARM mode, and Thumb mode. 2619 // We use mapping symbols to switch between the two assemblers, where 2620 // appropriate. 2621 std::optional<DisassemblerTarget> SecondaryTarget; 2622 2623 if (isArmElf(*Obj)) { 2624 if (!PrimaryTarget.SubtargetInfo->checkFeatures("+mclass")) { 2625 if (PrimaryTarget.SubtargetInfo->checkFeatures("+thumb-mode")) 2626 Features.AddFeature("-thumb-mode"); 2627 else 2628 Features.AddFeature("+thumb-mode"); 2629 SecondaryTarget.emplace(PrimaryTarget, Features); 2630 } 2631 } else if (const auto *COFFObj = dyn_cast<COFFObjectFile>(Obj)) { 2632 const chpe_metadata *CHPEMetadata = COFFObj->getCHPEMetadata(); 2633 if (CHPEMetadata && CHPEMetadata->CodeMapCount) { 2634 // Set up x86_64 disassembler for ARM64EC binaries. 2635 Triple X64Triple(TripleName); 2636 X64Triple.setArch(Triple::ArchType::x86_64); 2637 2638 std::string Error; 2639 const Target *X64Target = 2640 TargetRegistry::lookupTarget("", X64Triple, Error); 2641 if (X64Target) { 2642 SubtargetFeatures X64Features; 2643 SecondaryTarget.emplace(X64Target, *Obj, X64Triple.getTriple(), "", 2644 X64Features); 2645 } else { 2646 reportWarning(Error, Obj->getFileName()); 2647 } 2648 } 2649 } 2650 2651 const ObjectFile *DbgObj = Obj; 2652 if (!FetchedBinary.getBinary() && !Obj->hasDebugInfo()) { 2653 if (std::optional<OwningBinary<Binary>> DebugBinaryOpt = 2654 fetchBinaryByBuildID(*Obj)) { 2655 if (auto *FetchedObj = 2656 dyn_cast<const ObjectFile>(DebugBinaryOpt->getBinary())) { 2657 if (FetchedObj->hasDebugInfo()) { 2658 FetchedBinary = std::move(*DebugBinaryOpt); 2659 DbgObj = FetchedObj; 2660 } 2661 } 2662 } 2663 } 2664 2665 std::unique_ptr<object::Binary> DSYMBinary; 2666 std::unique_ptr<MemoryBuffer> DSYMBuf; 2667 if (!DbgObj->hasDebugInfo()) { 2668 if (const MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&*Obj)) { 2669 DbgObj = objdump::getMachODSymObject(MachOOF, Obj->getFileName(), 2670 DSYMBinary, DSYMBuf); 2671 if (!DbgObj) 2672 return; 2673 } 2674 } 2675 2676 SourcePrinter SP(DbgObj, TheTarget->getName()); 2677 2678 for (StringRef Opt : DisassemblerOptions) 2679 if (!PrimaryTarget.InstPrinter->applyTargetSpecificCLOption(Opt)) 2680 reportError(Obj->getFileName(), 2681 "Unrecognized disassembler option: " + Opt); 2682 2683 disassembleObject(*Obj, *DbgObj, PrimaryTarget, SecondaryTarget, SP, 2684 InlineRelocs, OS); 2685 } 2686 2687 void Dumper::printRelocations() { 2688 StringRef Fmt = O.getBytesInAddress() > 4 ? "%016" PRIx64 : "%08" PRIx64; 2689 2690 // Build a mapping from relocation target to a vector of relocation 2691 // sections. Usually, there is an only one relocation section for 2692 // each relocated section. 2693 MapVector<SectionRef, std::vector<SectionRef>> SecToRelSec; 2694 uint64_t Ndx; 2695 for (const SectionRef &Section : ToolSectionFilter(O, &Ndx)) { 2696 if (O.isELF() && (ELFSectionRef(Section).getFlags() & ELF::SHF_ALLOC)) 2697 continue; 2698 if (Section.relocation_begin() == Section.relocation_end()) 2699 continue; 2700 Expected<section_iterator> SecOrErr = Section.getRelocatedSection(); 2701 if (!SecOrErr) 2702 reportError(O.getFileName(), 2703 "section (" + Twine(Ndx) + 2704 "): unable to get a relocation target: " + 2705 toString(SecOrErr.takeError())); 2706 SecToRelSec[**SecOrErr].push_back(Section); 2707 } 2708 2709 for (std::pair<SectionRef, std::vector<SectionRef>> &P : SecToRelSec) { 2710 StringRef SecName = unwrapOrError(P.first.getName(), O.getFileName()); 2711 outs() << "\nRELOCATION RECORDS FOR [" << SecName << "]:\n"; 2712 uint32_t OffsetPadding = (O.getBytesInAddress() > 4 ? 16 : 8); 2713 uint32_t TypePadding = 24; 2714 outs() << left_justify("OFFSET", OffsetPadding) << " " 2715 << left_justify("TYPE", TypePadding) << " " 2716 << "VALUE\n"; 2717 2718 for (SectionRef Section : P.second) { 2719 // CREL sections require decoding, each section may have its own specific 2720 // decode problems. 2721 if (O.isELF() && ELFSectionRef(Section).getType() == ELF::SHT_CREL) { 2722 StringRef Err = 2723 cast<const ELFObjectFileBase>(O).getCrelDecodeProblem(Section); 2724 if (!Err.empty()) { 2725 reportUniqueWarning(Err); 2726 continue; 2727 } 2728 } 2729 for (const RelocationRef &Reloc : Section.relocations()) { 2730 uint64_t Address = Reloc.getOffset(); 2731 SmallString<32> RelocName; 2732 SmallString<32> ValueStr; 2733 if (Address < StartAddress || Address > StopAddress || getHidden(Reloc)) 2734 continue; 2735 Reloc.getTypeName(RelocName); 2736 if (Error E = 2737 getRelocationValueString(Reloc, SymbolDescription, ValueStr)) 2738 reportUniqueWarning(std::move(E)); 2739 2740 outs() << format(Fmt.data(), Address) << " " 2741 << left_justify(RelocName, TypePadding) << " " << ValueStr 2742 << "\n"; 2743 } 2744 } 2745 } 2746 } 2747 2748 // Returns true if we need to show LMA column when dumping section headers. We 2749 // show it only when the platform is ELF and either we have at least one section 2750 // whose VMA and LMA are different and/or when --show-lma flag is used. 2751 static bool shouldDisplayLMA(const ObjectFile &Obj) { 2752 if (!Obj.isELF()) 2753 return false; 2754 for (const SectionRef &S : ToolSectionFilter(Obj)) 2755 if (S.getAddress() != getELFSectionLMA(S)) 2756 return true; 2757 return ShowLMA; 2758 } 2759 2760 static size_t getMaxSectionNameWidth(const ObjectFile &Obj) { 2761 // Default column width for names is 13 even if no names are that long. 2762 size_t MaxWidth = 13; 2763 for (const SectionRef &Section : ToolSectionFilter(Obj)) { 2764 StringRef Name = unwrapOrError(Section.getName(), Obj.getFileName()); 2765 MaxWidth = std::max(MaxWidth, Name.size()); 2766 } 2767 return MaxWidth; 2768 } 2769 2770 void objdump::printSectionHeaders(ObjectFile &Obj) { 2771 if (Obj.isELF() && Obj.sections().empty()) 2772 createFakeELFSections(Obj); 2773 2774 size_t NameWidth = getMaxSectionNameWidth(Obj); 2775 size_t AddressWidth = 2 * Obj.getBytesInAddress(); 2776 bool HasLMAColumn = shouldDisplayLMA(Obj); 2777 outs() << "\nSections:\n"; 2778 if (HasLMAColumn) 2779 outs() << "Idx " << left_justify("Name", NameWidth) << " Size " 2780 << left_justify("VMA", AddressWidth) << " " 2781 << left_justify("LMA", AddressWidth) << " Type\n"; 2782 else 2783 outs() << "Idx " << left_justify("Name", NameWidth) << " Size " 2784 << left_justify("VMA", AddressWidth) << " Type\n"; 2785 2786 uint64_t Idx; 2787 for (const SectionRef &Section : ToolSectionFilter(Obj, &Idx)) { 2788 StringRef Name = unwrapOrError(Section.getName(), Obj.getFileName()); 2789 uint64_t VMA = Section.getAddress(); 2790 if (shouldAdjustVA(Section)) 2791 VMA += AdjustVMA; 2792 2793 uint64_t Size = Section.getSize(); 2794 2795 std::string Type = Section.isText() ? "TEXT" : ""; 2796 if (Section.isData()) 2797 Type += Type.empty() ? "DATA" : ", DATA"; 2798 if (Section.isBSS()) 2799 Type += Type.empty() ? "BSS" : ", BSS"; 2800 if (Section.isDebugSection()) 2801 Type += Type.empty() ? "DEBUG" : ", DEBUG"; 2802 2803 if (HasLMAColumn) 2804 outs() << format("%3" PRIu64 " %-*s %08" PRIx64 " ", Idx, NameWidth, 2805 Name.str().c_str(), Size) 2806 << format_hex_no_prefix(VMA, AddressWidth) << " " 2807 << format_hex_no_prefix(getELFSectionLMA(Section), AddressWidth) 2808 << " " << Type << "\n"; 2809 else 2810 outs() << format("%3" PRIu64 " %-*s %08" PRIx64 " ", Idx, NameWidth, 2811 Name.str().c_str(), Size) 2812 << format_hex_no_prefix(VMA, AddressWidth) << " " << Type << "\n"; 2813 } 2814 } 2815 2816 void objdump::printSectionContents(const ObjectFile *Obj) { 2817 const MachOObjectFile *MachO = dyn_cast<const MachOObjectFile>(Obj); 2818 2819 for (const SectionRef &Section : ToolSectionFilter(*Obj)) { 2820 StringRef Name = unwrapOrError(Section.getName(), Obj->getFileName()); 2821 uint64_t BaseAddr = Section.getAddress(); 2822 uint64_t Size = Section.getSize(); 2823 if (!Size) 2824 continue; 2825 2826 outs() << "Contents of section "; 2827 StringRef SegmentName = getSegmentName(MachO, Section); 2828 if (!SegmentName.empty()) 2829 outs() << SegmentName << ","; 2830 outs() << Name << ":\n"; 2831 if (Section.isBSS()) { 2832 outs() << format("<skipping contents of bss section at [%04" PRIx64 2833 ", %04" PRIx64 ")>\n", 2834 BaseAddr, BaseAddr + Size); 2835 continue; 2836 } 2837 2838 StringRef Contents = unwrapOrError(Section.getContents(), Obj->getFileName()); 2839 2840 // Dump out the content as hex and printable ascii characters. 2841 for (std::size_t Addr = 0, End = Contents.size(); Addr < End; Addr += 16) { 2842 outs() << format(" %04" PRIx64 " ", BaseAddr + Addr); 2843 // Dump line of hex. 2844 for (std::size_t I = 0; I < 16; ++I) { 2845 if (I != 0 && I % 4 == 0) 2846 outs() << ' '; 2847 if (Addr + I < End) 2848 outs() << hexdigit((Contents[Addr + I] >> 4) & 0xF, true) 2849 << hexdigit(Contents[Addr + I] & 0xF, true); 2850 else 2851 outs() << " "; 2852 } 2853 // Print ascii. 2854 outs() << " "; 2855 for (std::size_t I = 0; I < 16 && Addr + I < End; ++I) { 2856 if (isPrint(static_cast<unsigned char>(Contents[Addr + I]) & 0xFF)) 2857 outs() << Contents[Addr + I]; 2858 else 2859 outs() << "."; 2860 } 2861 outs() << "\n"; 2862 } 2863 } 2864 } 2865 2866 void Dumper::printSymbolTable(StringRef ArchiveName, StringRef ArchitectureName, 2867 bool DumpDynamic) { 2868 if (O.isCOFF() && !DumpDynamic) { 2869 outs() << "\nSYMBOL TABLE:\n"; 2870 printCOFFSymbolTable(cast<const COFFObjectFile>(O)); 2871 return; 2872 } 2873 2874 const StringRef FileName = O.getFileName(); 2875 2876 if (!DumpDynamic) { 2877 outs() << "\nSYMBOL TABLE:\n"; 2878 for (auto I = O.symbol_begin(); I != O.symbol_end(); ++I) 2879 printSymbol(*I, {}, FileName, ArchiveName, ArchitectureName, DumpDynamic); 2880 return; 2881 } 2882 2883 outs() << "\nDYNAMIC SYMBOL TABLE:\n"; 2884 if (!O.isELF()) { 2885 reportWarning( 2886 "this operation is not currently supported for this file format", 2887 FileName); 2888 return; 2889 } 2890 2891 const ELFObjectFileBase *ELF = cast<const ELFObjectFileBase>(&O); 2892 auto Symbols = ELF->getDynamicSymbolIterators(); 2893 Expected<std::vector<VersionEntry>> SymbolVersionsOrErr = 2894 ELF->readDynsymVersions(); 2895 if (!SymbolVersionsOrErr) { 2896 reportWarning(toString(SymbolVersionsOrErr.takeError()), FileName); 2897 SymbolVersionsOrErr = std::vector<VersionEntry>(); 2898 (void)!SymbolVersionsOrErr; 2899 } 2900 for (auto &Sym : Symbols) 2901 printSymbol(Sym, *SymbolVersionsOrErr, FileName, ArchiveName, 2902 ArchitectureName, DumpDynamic); 2903 } 2904 2905 void Dumper::printSymbol(const SymbolRef &Symbol, 2906 ArrayRef<VersionEntry> SymbolVersions, 2907 StringRef FileName, StringRef ArchiveName, 2908 StringRef ArchitectureName, bool DumpDynamic) { 2909 const MachOObjectFile *MachO = dyn_cast<const MachOObjectFile>(&O); 2910 Expected<uint64_t> AddrOrErr = Symbol.getAddress(); 2911 if (!AddrOrErr) { 2912 reportUniqueWarning(AddrOrErr.takeError()); 2913 return; 2914 } 2915 2916 // Don't ask a Mach-O STAB symbol for its section unless you know that 2917 // STAB symbol's section field refers to a valid section index. Otherwise 2918 // the symbol may error trying to load a section that does not exist. 2919 bool IsSTAB = false; 2920 if (MachO) { 2921 DataRefImpl SymDRI = Symbol.getRawDataRefImpl(); 2922 uint8_t NType = 2923 (MachO->is64Bit() ? MachO->getSymbol64TableEntry(SymDRI).n_type 2924 : MachO->getSymbolTableEntry(SymDRI).n_type); 2925 if (NType & MachO::N_STAB) 2926 IsSTAB = true; 2927 } 2928 section_iterator Section = IsSTAB 2929 ? O.section_end() 2930 : unwrapOrError(Symbol.getSection(), FileName, 2931 ArchiveName, ArchitectureName); 2932 2933 uint64_t Address = *AddrOrErr; 2934 if (Section != O.section_end() && shouldAdjustVA(*Section)) 2935 Address += AdjustVMA; 2936 if ((Address < StartAddress) || (Address > StopAddress)) 2937 return; 2938 SymbolRef::Type Type = 2939 unwrapOrError(Symbol.getType(), FileName, ArchiveName, ArchitectureName); 2940 uint32_t Flags = 2941 unwrapOrError(Symbol.getFlags(), FileName, ArchiveName, ArchitectureName); 2942 2943 StringRef Name; 2944 if (Type == SymbolRef::ST_Debug && Section != O.section_end()) { 2945 if (Expected<StringRef> NameOrErr = Section->getName()) 2946 Name = *NameOrErr; 2947 else 2948 consumeError(NameOrErr.takeError()); 2949 2950 } else { 2951 Name = unwrapOrError(Symbol.getName(), FileName, ArchiveName, 2952 ArchitectureName); 2953 } 2954 2955 bool Global = Flags & SymbolRef::SF_Global; 2956 bool Weak = Flags & SymbolRef::SF_Weak; 2957 bool Absolute = Flags & SymbolRef::SF_Absolute; 2958 bool Common = Flags & SymbolRef::SF_Common; 2959 bool Hidden = Flags & SymbolRef::SF_Hidden; 2960 2961 char GlobLoc = ' '; 2962 if ((Section != O.section_end() || Absolute) && !Weak) 2963 GlobLoc = Global ? 'g' : 'l'; 2964 char IFunc = ' '; 2965 if (O.isELF()) { 2966 if (ELFSymbolRef(Symbol).getELFType() == ELF::STT_GNU_IFUNC) 2967 IFunc = 'i'; 2968 if (ELFSymbolRef(Symbol).getBinding() == ELF::STB_GNU_UNIQUE) 2969 GlobLoc = 'u'; 2970 } 2971 2972 char Debug = ' '; 2973 if (DumpDynamic) 2974 Debug = 'D'; 2975 else if (Type == SymbolRef::ST_Debug || Type == SymbolRef::ST_File) 2976 Debug = 'd'; 2977 2978 char FileFunc = ' '; 2979 if (Type == SymbolRef::ST_File) 2980 FileFunc = 'f'; 2981 else if (Type == SymbolRef::ST_Function) 2982 FileFunc = 'F'; 2983 else if (Type == SymbolRef::ST_Data) 2984 FileFunc = 'O'; 2985 2986 const char *Fmt = O.getBytesInAddress() > 4 ? "%016" PRIx64 : "%08" PRIx64; 2987 2988 outs() << format(Fmt, Address) << " " 2989 << GlobLoc // Local -> 'l', Global -> 'g', Neither -> ' ' 2990 << (Weak ? 'w' : ' ') // Weak? 2991 << ' ' // Constructor. Not supported yet. 2992 << ' ' // Warning. Not supported yet. 2993 << IFunc // Indirect reference to another symbol. 2994 << Debug // Debugging (d) or dynamic (D) symbol. 2995 << FileFunc // Name of function (F), file (f) or object (O). 2996 << ' '; 2997 if (Absolute) { 2998 outs() << "*ABS*"; 2999 } else if (Common) { 3000 outs() << "*COM*"; 3001 } else if (Section == O.section_end()) { 3002 if (O.isXCOFF()) { 3003 XCOFFSymbolRef XCOFFSym = cast<const XCOFFObjectFile>(O).toSymbolRef( 3004 Symbol.getRawDataRefImpl()); 3005 if (XCOFF::N_DEBUG == XCOFFSym.getSectionNumber()) 3006 outs() << "*DEBUG*"; 3007 else 3008 outs() << "*UND*"; 3009 } else 3010 outs() << "*UND*"; 3011 } else { 3012 StringRef SegmentName = getSegmentName(MachO, *Section); 3013 if (!SegmentName.empty()) 3014 outs() << SegmentName << ","; 3015 StringRef SectionName = unwrapOrError(Section->getName(), FileName); 3016 outs() << SectionName; 3017 if (O.isXCOFF()) { 3018 std::optional<SymbolRef> SymRef = 3019 getXCOFFSymbolContainingSymbolRef(cast<XCOFFObjectFile>(O), Symbol); 3020 if (SymRef) { 3021 3022 Expected<StringRef> NameOrErr = SymRef->getName(); 3023 3024 if (NameOrErr) { 3025 outs() << " (csect:"; 3026 std::string SymName = 3027 Demangle ? demangle(*NameOrErr) : NameOrErr->str(); 3028 3029 if (SymbolDescription) 3030 SymName = getXCOFFSymbolDescription(createSymbolInfo(O, *SymRef), 3031 SymName); 3032 3033 outs() << ' ' << SymName; 3034 outs() << ") "; 3035 } else 3036 reportWarning(toString(NameOrErr.takeError()), FileName); 3037 } 3038 } 3039 } 3040 3041 if (Common) 3042 outs() << '\t' << format(Fmt, static_cast<uint64_t>(Symbol.getAlignment())); 3043 else if (O.isXCOFF()) 3044 outs() << '\t' 3045 << format(Fmt, cast<XCOFFObjectFile>(O).getSymbolSize( 3046 Symbol.getRawDataRefImpl())); 3047 else if (O.isELF()) 3048 outs() << '\t' << format(Fmt, ELFSymbolRef(Symbol).getSize()); 3049 else if (O.isWasm()) 3050 outs() << '\t' 3051 << format(Fmt, static_cast<uint64_t>( 3052 cast<WasmObjectFile>(O).getSymbolSize(Symbol))); 3053 3054 if (O.isELF()) { 3055 if (!SymbolVersions.empty()) { 3056 const VersionEntry &Ver = 3057 SymbolVersions[Symbol.getRawDataRefImpl().d.b - 1]; 3058 std::string Str; 3059 if (!Ver.Name.empty()) 3060 Str = Ver.IsVerDef ? ' ' + Ver.Name : '(' + Ver.Name + ')'; 3061 outs() << ' ' << left_justify(Str, 12); 3062 } 3063 3064 uint8_t Other = ELFSymbolRef(Symbol).getOther(); 3065 switch (Other) { 3066 case ELF::STV_DEFAULT: 3067 break; 3068 case ELF::STV_INTERNAL: 3069 outs() << " .internal"; 3070 break; 3071 case ELF::STV_HIDDEN: 3072 outs() << " .hidden"; 3073 break; 3074 case ELF::STV_PROTECTED: 3075 outs() << " .protected"; 3076 break; 3077 default: 3078 outs() << format(" 0x%02x", Other); 3079 break; 3080 } 3081 } else if (Hidden) { 3082 outs() << " .hidden"; 3083 } 3084 3085 std::string SymName = Demangle ? demangle(Name) : Name.str(); 3086 if (O.isXCOFF() && SymbolDescription) 3087 SymName = getXCOFFSymbolDescription(createSymbolInfo(O, Symbol), SymName); 3088 3089 outs() << ' ' << SymName << '\n'; 3090 } 3091 3092 static void printUnwindInfo(const ObjectFile *O) { 3093 outs() << "Unwind info:\n\n"; 3094 3095 if (const COFFObjectFile *Coff = dyn_cast<COFFObjectFile>(O)) 3096 printCOFFUnwindInfo(Coff); 3097 else if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(O)) 3098 printMachOUnwindInfo(MachO); 3099 else 3100 // TODO: Extract DWARF dump tool to objdump. 3101 WithColor::error(errs(), ToolName) 3102 << "This operation is only currently supported " 3103 "for COFF and MachO object files.\n"; 3104 } 3105 3106 /// Dump the raw contents of the __clangast section so the output can be piped 3107 /// into llvm-bcanalyzer. 3108 static void printRawClangAST(const ObjectFile *Obj) { 3109 if (outs().is_displayed()) { 3110 WithColor::error(errs(), ToolName) 3111 << "The -raw-clang-ast option will dump the raw binary contents of " 3112 "the clang ast section.\n" 3113 "Please redirect the output to a file or another program such as " 3114 "llvm-bcanalyzer.\n"; 3115 return; 3116 } 3117 3118 StringRef ClangASTSectionName("__clangast"); 3119 if (Obj->isCOFF()) { 3120 ClangASTSectionName = "clangast"; 3121 } 3122 3123 std::optional<object::SectionRef> ClangASTSection; 3124 for (auto Sec : ToolSectionFilter(*Obj)) { 3125 StringRef Name; 3126 if (Expected<StringRef> NameOrErr = Sec.getName()) 3127 Name = *NameOrErr; 3128 else 3129 consumeError(NameOrErr.takeError()); 3130 3131 if (Name == ClangASTSectionName) { 3132 ClangASTSection = Sec; 3133 break; 3134 } 3135 } 3136 if (!ClangASTSection) 3137 return; 3138 3139 StringRef ClangASTContents = 3140 unwrapOrError(ClangASTSection->getContents(), Obj->getFileName()); 3141 outs().write(ClangASTContents.data(), ClangASTContents.size()); 3142 } 3143 3144 static void printFaultMaps(const ObjectFile *Obj) { 3145 StringRef FaultMapSectionName; 3146 3147 if (Obj->isELF()) { 3148 FaultMapSectionName = ".llvm_faultmaps"; 3149 } else if (Obj->isMachO()) { 3150 FaultMapSectionName = "__llvm_faultmaps"; 3151 } else { 3152 WithColor::error(errs(), ToolName) 3153 << "This operation is only currently supported " 3154 "for ELF and Mach-O executable files.\n"; 3155 return; 3156 } 3157 3158 std::optional<object::SectionRef> FaultMapSection; 3159 3160 for (auto Sec : ToolSectionFilter(*Obj)) { 3161 StringRef Name; 3162 if (Expected<StringRef> NameOrErr = Sec.getName()) 3163 Name = *NameOrErr; 3164 else 3165 consumeError(NameOrErr.takeError()); 3166 3167 if (Name == FaultMapSectionName) { 3168 FaultMapSection = Sec; 3169 break; 3170 } 3171 } 3172 3173 outs() << "FaultMap table:\n"; 3174 3175 if (!FaultMapSection) { 3176 outs() << "<not found>\n"; 3177 return; 3178 } 3179 3180 StringRef FaultMapContents = 3181 unwrapOrError(FaultMapSection->getContents(), Obj->getFileName()); 3182 FaultMapParser FMP(FaultMapContents.bytes_begin(), 3183 FaultMapContents.bytes_end()); 3184 3185 outs() << FMP; 3186 } 3187 3188 void Dumper::printPrivateHeaders() { 3189 reportError(O.getFileName(), "Invalid/Unsupported object file format"); 3190 } 3191 3192 static void printFileHeaders(const ObjectFile *O) { 3193 if (!O->isELF() && !O->isCOFF() && !O->isXCOFF()) 3194 reportError(O->getFileName(), "Invalid/Unsupported object file format"); 3195 3196 Triple::ArchType AT = O->getArch(); 3197 outs() << "architecture: " << Triple::getArchTypeName(AT) << "\n"; 3198 uint64_t Address = unwrapOrError(O->getStartAddress(), O->getFileName()); 3199 3200 StringRef Fmt = O->getBytesInAddress() > 4 ? "%016" PRIx64 : "%08" PRIx64; 3201 outs() << "start address: " 3202 << "0x" << format(Fmt.data(), Address) << "\n"; 3203 } 3204 3205 static void printArchiveChild(StringRef Filename, const Archive::Child &C) { 3206 Expected<sys::fs::perms> ModeOrErr = C.getAccessMode(); 3207 if (!ModeOrErr) { 3208 WithColor::error(errs(), ToolName) << "ill-formed archive entry.\n"; 3209 consumeError(ModeOrErr.takeError()); 3210 return; 3211 } 3212 sys::fs::perms Mode = ModeOrErr.get(); 3213 outs() << ((Mode & sys::fs::owner_read) ? "r" : "-"); 3214 outs() << ((Mode & sys::fs::owner_write) ? "w" : "-"); 3215 outs() << ((Mode & sys::fs::owner_exe) ? "x" : "-"); 3216 outs() << ((Mode & sys::fs::group_read) ? "r" : "-"); 3217 outs() << ((Mode & sys::fs::group_write) ? "w" : "-"); 3218 outs() << ((Mode & sys::fs::group_exe) ? "x" : "-"); 3219 outs() << ((Mode & sys::fs::others_read) ? "r" : "-"); 3220 outs() << ((Mode & sys::fs::others_write) ? "w" : "-"); 3221 outs() << ((Mode & sys::fs::others_exe) ? "x" : "-"); 3222 3223 outs() << " "; 3224 3225 outs() << format("%d/%d %6" PRId64 " ", unwrapOrError(C.getUID(), Filename), 3226 unwrapOrError(C.getGID(), Filename), 3227 unwrapOrError(C.getRawSize(), Filename)); 3228 3229 StringRef RawLastModified = C.getRawLastModified(); 3230 unsigned Seconds; 3231 if (RawLastModified.getAsInteger(10, Seconds)) 3232 outs() << "(date: \"" << RawLastModified 3233 << "\" contains non-decimal chars) "; 3234 else { 3235 // Since ctime(3) returns a 26 character string of the form: 3236 // "Sun Sep 16 01:03:52 1973\n\0" 3237 // just print 24 characters. 3238 time_t t = Seconds; 3239 outs() << format("%.24s ", ctime(&t)); 3240 } 3241 3242 StringRef Name = ""; 3243 Expected<StringRef> NameOrErr = C.getName(); 3244 if (!NameOrErr) { 3245 consumeError(NameOrErr.takeError()); 3246 Name = unwrapOrError(C.getRawName(), Filename); 3247 } else { 3248 Name = NameOrErr.get(); 3249 } 3250 outs() << Name << "\n"; 3251 } 3252 3253 // For ELF only now. 3254 static bool shouldWarnForInvalidStartStopAddress(ObjectFile *Obj) { 3255 if (const auto *Elf = dyn_cast<ELFObjectFileBase>(Obj)) { 3256 if (Elf->getEType() != ELF::ET_REL) 3257 return true; 3258 } 3259 return false; 3260 } 3261 3262 static void checkForInvalidStartStopAddress(ObjectFile *Obj, 3263 uint64_t Start, uint64_t Stop) { 3264 if (!shouldWarnForInvalidStartStopAddress(Obj)) 3265 return; 3266 3267 for (const SectionRef &Section : Obj->sections()) 3268 if (ELFSectionRef(Section).getFlags() & ELF::SHF_ALLOC) { 3269 uint64_t BaseAddr = Section.getAddress(); 3270 uint64_t Size = Section.getSize(); 3271 if ((Start < BaseAddr + Size) && Stop > BaseAddr) 3272 return; 3273 } 3274 3275 if (!HasStartAddressFlag) 3276 reportWarning("no section has address less than 0x" + 3277 Twine::utohexstr(Stop) + " specified by --stop-address", 3278 Obj->getFileName()); 3279 else if (!HasStopAddressFlag) 3280 reportWarning("no section has address greater than or equal to 0x" + 3281 Twine::utohexstr(Start) + " specified by --start-address", 3282 Obj->getFileName()); 3283 else 3284 reportWarning("no section overlaps the range [0x" + 3285 Twine::utohexstr(Start) + ",0x" + Twine::utohexstr(Stop) + 3286 ") specified by --start-address/--stop-address", 3287 Obj->getFileName()); 3288 } 3289 3290 static void dumpObject(ObjectFile *O, const Archive *A = nullptr, 3291 const Archive::Child *C = nullptr) { 3292 Expected<std::unique_ptr<Dumper>> DumperOrErr = createDumper(*O); 3293 if (!DumperOrErr) { 3294 reportError(DumperOrErr.takeError(), O->getFileName(), 3295 A ? A->getFileName() : ""); 3296 return; 3297 } 3298 Dumper &D = **DumperOrErr; 3299 3300 // Avoid other output when using a raw option. 3301 if (!RawClangAST) { 3302 outs() << '\n'; 3303 if (A) 3304 outs() << A->getFileName() << "(" << O->getFileName() << ")"; 3305 else 3306 outs() << O->getFileName(); 3307 outs() << ":\tfile format " << O->getFileFormatName().lower() << "\n"; 3308 } 3309 3310 if (HasStartAddressFlag || HasStopAddressFlag) 3311 checkForInvalidStartStopAddress(O, StartAddress, StopAddress); 3312 3313 // TODO: Change print* free functions to Dumper member functions to utilitize 3314 // stateful functions like reportUniqueWarning. 3315 3316 // Note: the order here matches GNU objdump for compatability. 3317 StringRef ArchiveName = A ? A->getFileName() : ""; 3318 if (ArchiveHeaders && !MachOOpt && C) 3319 printArchiveChild(ArchiveName, *C); 3320 if (FileHeaders) 3321 printFileHeaders(O); 3322 if (PrivateHeaders || FirstPrivateHeader) 3323 D.printPrivateHeaders(); 3324 if (SectionHeaders) 3325 printSectionHeaders(*O); 3326 if (SymbolTable) 3327 D.printSymbolTable(ArchiveName); 3328 if (DynamicSymbolTable) 3329 D.printSymbolTable(ArchiveName, /*ArchitectureName=*/"", 3330 /*DumpDynamic=*/true); 3331 if (DwarfDumpType != DIDT_Null) { 3332 std::unique_ptr<DIContext> DICtx = DWARFContext::create(*O); 3333 // Dump the complete DWARF structure. 3334 DIDumpOptions DumpOpts; 3335 DumpOpts.DumpType = DwarfDumpType; 3336 DICtx->dump(outs(), DumpOpts); 3337 } 3338 if (Relocations && !Disassemble) 3339 D.printRelocations(); 3340 if (DynamicRelocations) 3341 D.printDynamicRelocations(); 3342 if (SectionContents) 3343 printSectionContents(O); 3344 if (Disassemble) 3345 disassembleObject(O, Relocations, outs()); 3346 if (UnwindInfo) 3347 printUnwindInfo(O); 3348 3349 // Mach-O specific options: 3350 if (ExportsTrie) 3351 printExportsTrie(O); 3352 if (Rebase) 3353 printRebaseTable(O); 3354 if (Bind) 3355 printBindTable(O); 3356 if (LazyBind) 3357 printLazyBindTable(O); 3358 if (WeakBind) 3359 printWeakBindTable(O); 3360 3361 // Other special sections: 3362 if (RawClangAST) 3363 printRawClangAST(O); 3364 if (FaultMapSection) 3365 printFaultMaps(O); 3366 if (Offloading) 3367 dumpOffloadBinary(*O, StringRef(ArchName)); 3368 } 3369 3370 static void dumpObject(const COFFImportFile *I, const Archive *A, 3371 const Archive::Child *C = nullptr) { 3372 StringRef ArchiveName = A ? A->getFileName() : ""; 3373 3374 // Avoid other output when using a raw option. 3375 if (!RawClangAST) 3376 outs() << '\n' 3377 << ArchiveName << "(" << I->getFileName() << ")" 3378 << ":\tfile format COFF-import-file" 3379 << "\n\n"; 3380 3381 if (ArchiveHeaders && !MachOOpt && C) 3382 printArchiveChild(ArchiveName, *C); 3383 if (SymbolTable) 3384 printCOFFSymbolTable(*I); 3385 } 3386 3387 /// Dump each object file in \a a; 3388 static void dumpArchive(const Archive *A) { 3389 Error Err = Error::success(); 3390 unsigned I = -1; 3391 for (auto &C : A->children(Err)) { 3392 ++I; 3393 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); 3394 if (!ChildOrErr) { 3395 if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) 3396 reportError(std::move(E), getFileNameForError(C, I), A->getFileName()); 3397 continue; 3398 } 3399 if (ObjectFile *O = dyn_cast<ObjectFile>(&*ChildOrErr.get())) 3400 dumpObject(O, A, &C); 3401 else if (COFFImportFile *I = dyn_cast<COFFImportFile>(&*ChildOrErr.get())) 3402 dumpObject(I, A, &C); 3403 else 3404 reportError(errorCodeToError(object_error::invalid_file_type), 3405 A->getFileName()); 3406 } 3407 if (Err) 3408 reportError(std::move(Err), A->getFileName()); 3409 } 3410 3411 /// Open file and figure out how to dump it. 3412 static void dumpInput(StringRef file) { 3413 // If we are using the Mach-O specific object file parser, then let it parse 3414 // the file and process the command line options. So the -arch flags can 3415 // be used to select specific slices, etc. 3416 if (MachOOpt) { 3417 parseInputMachO(file); 3418 return; 3419 } 3420 3421 // Attempt to open the binary. 3422 OwningBinary<Binary> OBinary = unwrapOrError(createBinary(file), file); 3423 Binary &Binary = *OBinary.getBinary(); 3424 3425 if (Archive *A = dyn_cast<Archive>(&Binary)) 3426 dumpArchive(A); 3427 else if (ObjectFile *O = dyn_cast<ObjectFile>(&Binary)) 3428 dumpObject(O); 3429 else if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(&Binary)) 3430 parseInputMachO(UB); 3431 else if (OffloadBinary *OB = dyn_cast<OffloadBinary>(&Binary)) 3432 dumpOffloadSections(*OB); 3433 else 3434 reportError(errorCodeToError(object_error::invalid_file_type), file); 3435 } 3436 3437 template <typename T> 3438 static void parseIntArg(const llvm::opt::InputArgList &InputArgs, int ID, 3439 T &Value) { 3440 if (const opt::Arg *A = InputArgs.getLastArg(ID)) { 3441 StringRef V(A->getValue()); 3442 if (!llvm::to_integer(V, Value, 0)) { 3443 reportCmdLineError(A->getSpelling() + 3444 ": expected a non-negative integer, but got '" + V + 3445 "'"); 3446 } 3447 } 3448 } 3449 3450 static object::BuildID parseBuildIDArg(const opt::Arg *A) { 3451 StringRef V(A->getValue()); 3452 object::BuildID BID = parseBuildID(V); 3453 if (BID.empty()) 3454 reportCmdLineError(A->getSpelling() + ": expected a build ID, but got '" + 3455 V + "'"); 3456 return BID; 3457 } 3458 3459 void objdump::invalidArgValue(const opt::Arg *A) { 3460 reportCmdLineError("'" + StringRef(A->getValue()) + 3461 "' is not a valid value for '" + A->getSpelling() + "'"); 3462 } 3463 3464 static std::vector<std::string> 3465 commaSeparatedValues(const llvm::opt::InputArgList &InputArgs, int ID) { 3466 std::vector<std::string> Values; 3467 for (StringRef Value : InputArgs.getAllArgValues(ID)) { 3468 llvm::SmallVector<StringRef, 2> SplitValues; 3469 llvm::SplitString(Value, SplitValues, ","); 3470 for (StringRef SplitValue : SplitValues) 3471 Values.push_back(SplitValue.str()); 3472 } 3473 return Values; 3474 } 3475 3476 static void parseOtoolOptions(const llvm::opt::InputArgList &InputArgs) { 3477 MachOOpt = true; 3478 FullLeadingAddr = true; 3479 PrintImmHex = true; 3480 3481 ArchName = InputArgs.getLastArgValue(OTOOL_arch).str(); 3482 LinkOptHints = InputArgs.hasArg(OTOOL_C); 3483 if (InputArgs.hasArg(OTOOL_d)) 3484 FilterSections.push_back("__DATA,__data"); 3485 DylibId = InputArgs.hasArg(OTOOL_D); 3486 UniversalHeaders = InputArgs.hasArg(OTOOL_f); 3487 DataInCode = InputArgs.hasArg(OTOOL_G); 3488 FirstPrivateHeader = InputArgs.hasArg(OTOOL_h); 3489 IndirectSymbols = InputArgs.hasArg(OTOOL_I); 3490 ShowRawInsn = InputArgs.hasArg(OTOOL_j); 3491 PrivateHeaders = InputArgs.hasArg(OTOOL_l); 3492 DylibsUsed = InputArgs.hasArg(OTOOL_L); 3493 MCPU = InputArgs.getLastArgValue(OTOOL_mcpu_EQ).str(); 3494 ObjcMetaData = InputArgs.hasArg(OTOOL_o); 3495 DisSymName = InputArgs.getLastArgValue(OTOOL_p).str(); 3496 InfoPlist = InputArgs.hasArg(OTOOL_P); 3497 Relocations = InputArgs.hasArg(OTOOL_r); 3498 if (const Arg *A = InputArgs.getLastArg(OTOOL_s)) { 3499 auto Filter = (A->getValue(0) + StringRef(",") + A->getValue(1)).str(); 3500 FilterSections.push_back(Filter); 3501 } 3502 if (InputArgs.hasArg(OTOOL_t)) 3503 FilterSections.push_back("__TEXT,__text"); 3504 Verbose = InputArgs.hasArg(OTOOL_v) || InputArgs.hasArg(OTOOL_V) || 3505 InputArgs.hasArg(OTOOL_o); 3506 SymbolicOperands = InputArgs.hasArg(OTOOL_V); 3507 if (InputArgs.hasArg(OTOOL_x)) 3508 FilterSections.push_back(",__text"); 3509 LeadingAddr = LeadingHeaders = !InputArgs.hasArg(OTOOL_X); 3510 3511 ChainedFixups = InputArgs.hasArg(OTOOL_chained_fixups); 3512 DyldInfo = InputArgs.hasArg(OTOOL_dyld_info); 3513 3514 InputFilenames = InputArgs.getAllArgValues(OTOOL_INPUT); 3515 if (InputFilenames.empty()) 3516 reportCmdLineError("no input file"); 3517 3518 for (const Arg *A : InputArgs) { 3519 const Option &O = A->getOption(); 3520 if (O.getGroup().isValid() && O.getGroup().getID() == OTOOL_grp_obsolete) { 3521 reportCmdLineWarning(O.getPrefixedName() + 3522 " is obsolete and not implemented"); 3523 } 3524 } 3525 } 3526 3527 static void parseObjdumpOptions(const llvm::opt::InputArgList &InputArgs) { 3528 parseIntArg(InputArgs, OBJDUMP_adjust_vma_EQ, AdjustVMA); 3529 AllHeaders = InputArgs.hasArg(OBJDUMP_all_headers); 3530 ArchName = InputArgs.getLastArgValue(OBJDUMP_arch_name_EQ).str(); 3531 ArchiveHeaders = InputArgs.hasArg(OBJDUMP_archive_headers); 3532 Demangle = InputArgs.hasArg(OBJDUMP_demangle); 3533 Disassemble = InputArgs.hasArg(OBJDUMP_disassemble); 3534 DisassembleAll = InputArgs.hasArg(OBJDUMP_disassemble_all); 3535 SymbolDescription = InputArgs.hasArg(OBJDUMP_symbol_description); 3536 TracebackTable = InputArgs.hasArg(OBJDUMP_traceback_table); 3537 DisassembleSymbols = 3538 commaSeparatedValues(InputArgs, OBJDUMP_disassemble_symbols_EQ); 3539 DisassembleZeroes = InputArgs.hasArg(OBJDUMP_disassemble_zeroes); 3540 if (const opt::Arg *A = InputArgs.getLastArg(OBJDUMP_dwarf_EQ)) { 3541 DwarfDumpType = StringSwitch<DIDumpType>(A->getValue()) 3542 .Case("frames", DIDT_DebugFrame) 3543 .Default(DIDT_Null); 3544 if (DwarfDumpType == DIDT_Null) 3545 invalidArgValue(A); 3546 } 3547 DynamicRelocations = InputArgs.hasArg(OBJDUMP_dynamic_reloc); 3548 FaultMapSection = InputArgs.hasArg(OBJDUMP_fault_map_section); 3549 Offloading = InputArgs.hasArg(OBJDUMP_offloading); 3550 FileHeaders = InputArgs.hasArg(OBJDUMP_file_headers); 3551 SectionContents = InputArgs.hasArg(OBJDUMP_full_contents); 3552 PrintLines = InputArgs.hasArg(OBJDUMP_line_numbers); 3553 InputFilenames = InputArgs.getAllArgValues(OBJDUMP_INPUT); 3554 MachOOpt = InputArgs.hasArg(OBJDUMP_macho); 3555 MCPU = InputArgs.getLastArgValue(OBJDUMP_mcpu_EQ).str(); 3556 MAttrs = commaSeparatedValues(InputArgs, OBJDUMP_mattr_EQ); 3557 ShowRawInsn = !InputArgs.hasArg(OBJDUMP_no_show_raw_insn); 3558 LeadingAddr = !InputArgs.hasArg(OBJDUMP_no_leading_addr); 3559 RawClangAST = InputArgs.hasArg(OBJDUMP_raw_clang_ast); 3560 Relocations = InputArgs.hasArg(OBJDUMP_reloc); 3561 PrintImmHex = 3562 InputArgs.hasFlag(OBJDUMP_print_imm_hex, OBJDUMP_no_print_imm_hex, true); 3563 PrivateHeaders = InputArgs.hasArg(OBJDUMP_private_headers); 3564 FilterSections = InputArgs.getAllArgValues(OBJDUMP_section_EQ); 3565 SectionHeaders = InputArgs.hasArg(OBJDUMP_section_headers); 3566 ShowAllSymbols = InputArgs.hasArg(OBJDUMP_show_all_symbols); 3567 ShowLMA = InputArgs.hasArg(OBJDUMP_show_lma); 3568 PrintSource = InputArgs.hasArg(OBJDUMP_source); 3569 parseIntArg(InputArgs, OBJDUMP_start_address_EQ, StartAddress); 3570 HasStartAddressFlag = InputArgs.hasArg(OBJDUMP_start_address_EQ); 3571 parseIntArg(InputArgs, OBJDUMP_stop_address_EQ, StopAddress); 3572 HasStopAddressFlag = InputArgs.hasArg(OBJDUMP_stop_address_EQ); 3573 SymbolTable = InputArgs.hasArg(OBJDUMP_syms); 3574 SymbolizeOperands = InputArgs.hasArg(OBJDUMP_symbolize_operands); 3575 PrettyPGOAnalysisMap = InputArgs.hasArg(OBJDUMP_pretty_pgo_analysis_map); 3576 if (PrettyPGOAnalysisMap && !SymbolizeOperands) 3577 reportCmdLineWarning("--symbolize-operands must be enabled for " 3578 "--pretty-pgo-analysis-map to have an effect"); 3579 DynamicSymbolTable = InputArgs.hasArg(OBJDUMP_dynamic_syms); 3580 TripleName = InputArgs.getLastArgValue(OBJDUMP_triple_EQ).str(); 3581 UnwindInfo = InputArgs.hasArg(OBJDUMP_unwind_info); 3582 Wide = InputArgs.hasArg(OBJDUMP_wide); 3583 Prefix = InputArgs.getLastArgValue(OBJDUMP_prefix).str(); 3584 parseIntArg(InputArgs, OBJDUMP_prefix_strip, PrefixStrip); 3585 if (const opt::Arg *A = InputArgs.getLastArg(OBJDUMP_debug_vars_EQ)) { 3586 DbgVariables = StringSwitch<DebugVarsFormat>(A->getValue()) 3587 .Case("ascii", DVASCII) 3588 .Case("unicode", DVUnicode) 3589 .Default(DVInvalid); 3590 if (DbgVariables == DVInvalid) 3591 invalidArgValue(A); 3592 } 3593 if (const opt::Arg *A = InputArgs.getLastArg(OBJDUMP_disassembler_color_EQ)) { 3594 DisassemblyColor = StringSwitch<ColorOutput>(A->getValue()) 3595 .Case("on", ColorOutput::Enable) 3596 .Case("off", ColorOutput::Disable) 3597 .Case("terminal", ColorOutput::Auto) 3598 .Default(ColorOutput::Invalid); 3599 if (DisassemblyColor == ColorOutput::Invalid) 3600 invalidArgValue(A); 3601 } 3602 3603 parseIntArg(InputArgs, OBJDUMP_debug_vars_indent_EQ, DbgIndent); 3604 3605 parseMachOOptions(InputArgs); 3606 3607 // Parse -M (--disassembler-options) and deprecated 3608 // --x86-asm-syntax={att,intel}. 3609 // 3610 // Note, for x86, the asm dialect (AssemblerDialect) is initialized when the 3611 // MCAsmInfo is constructed. MCInstPrinter::applyTargetSpecificCLOption is 3612 // called too late. For now we have to use the internal cl::opt option. 3613 const char *AsmSyntax = nullptr; 3614 for (const auto *A : InputArgs.filtered(OBJDUMP_disassembler_options_EQ, 3615 OBJDUMP_x86_asm_syntax_att, 3616 OBJDUMP_x86_asm_syntax_intel)) { 3617 switch (A->getOption().getID()) { 3618 case OBJDUMP_x86_asm_syntax_att: 3619 AsmSyntax = "--x86-asm-syntax=att"; 3620 continue; 3621 case OBJDUMP_x86_asm_syntax_intel: 3622 AsmSyntax = "--x86-asm-syntax=intel"; 3623 continue; 3624 } 3625 3626 SmallVector<StringRef, 2> Values; 3627 llvm::SplitString(A->getValue(), Values, ","); 3628 for (StringRef V : Values) { 3629 if (V == "att") 3630 AsmSyntax = "--x86-asm-syntax=att"; 3631 else if (V == "intel") 3632 AsmSyntax = "--x86-asm-syntax=intel"; 3633 else 3634 DisassemblerOptions.push_back(V.str()); 3635 } 3636 } 3637 SmallVector<const char *> Args = {"llvm-objdump"}; 3638 for (const opt::Arg *A : InputArgs.filtered(OBJDUMP_mllvm)) 3639 Args.push_back(A->getValue()); 3640 if (AsmSyntax) 3641 Args.push_back(AsmSyntax); 3642 if (Args.size() > 1) 3643 llvm::cl::ParseCommandLineOptions(Args.size(), Args.data()); 3644 3645 // Look up any provided build IDs, then append them to the input filenames. 3646 for (const opt::Arg *A : InputArgs.filtered(OBJDUMP_build_id)) { 3647 object::BuildID BuildID = parseBuildIDArg(A); 3648 std::optional<std::string> Path = BIDFetcher->fetch(BuildID); 3649 if (!Path) { 3650 reportCmdLineError(A->getSpelling() + ": could not find build ID '" + 3651 A->getValue() + "'"); 3652 } 3653 InputFilenames.push_back(std::move(*Path)); 3654 } 3655 3656 // objdump defaults to a.out if no filenames specified. 3657 if (InputFilenames.empty()) 3658 InputFilenames.push_back("a.out"); 3659 } 3660 3661 int llvm_objdump_main(int argc, char **argv, const llvm::ToolContext &) { 3662 using namespace llvm; 3663 3664 ToolName = argv[0]; 3665 std::unique_ptr<CommonOptTable> T; 3666 OptSpecifier Unknown, HelpFlag, HelpHiddenFlag, VersionFlag; 3667 3668 StringRef Stem = sys::path::stem(ToolName); 3669 auto Is = [=](StringRef Tool) { 3670 // We need to recognize the following filenames: 3671 // 3672 // llvm-objdump -> objdump 3673 // llvm-otool-10.exe -> otool 3674 // powerpc64-unknown-freebsd13-objdump -> objdump 3675 auto I = Stem.rfind_insensitive(Tool); 3676 return I != StringRef::npos && 3677 (I + Tool.size() == Stem.size() || !isAlnum(Stem[I + Tool.size()])); 3678 }; 3679 if (Is("otool")) { 3680 T = std::make_unique<OtoolOptTable>(); 3681 Unknown = OTOOL_UNKNOWN; 3682 HelpFlag = OTOOL_help; 3683 HelpHiddenFlag = OTOOL_help_hidden; 3684 VersionFlag = OTOOL_version; 3685 } else { 3686 T = std::make_unique<ObjdumpOptTable>(); 3687 Unknown = OBJDUMP_UNKNOWN; 3688 HelpFlag = OBJDUMP_help; 3689 HelpHiddenFlag = OBJDUMP_help_hidden; 3690 VersionFlag = OBJDUMP_version; 3691 } 3692 3693 BumpPtrAllocator A; 3694 StringSaver Saver(A); 3695 opt::InputArgList InputArgs = 3696 T->parseArgs(argc, argv, Unknown, Saver, 3697 [&](StringRef Msg) { reportCmdLineError(Msg); }); 3698 3699 if (InputArgs.size() == 0 || InputArgs.hasArg(HelpFlag)) { 3700 T->printHelp(ToolName); 3701 return 0; 3702 } 3703 if (InputArgs.hasArg(HelpHiddenFlag)) { 3704 T->printHelp(ToolName, /*ShowHidden=*/true); 3705 return 0; 3706 } 3707 3708 // Initialize targets and assembly printers/parsers. 3709 InitializeAllTargetInfos(); 3710 InitializeAllTargetMCs(); 3711 InitializeAllDisassemblers(); 3712 3713 if (InputArgs.hasArg(VersionFlag)) { 3714 cl::PrintVersionMessage(); 3715 if (!Is("otool")) { 3716 outs() << '\n'; 3717 TargetRegistry::printRegisteredTargetsForVersion(outs()); 3718 } 3719 return 0; 3720 } 3721 3722 // Initialize debuginfod. 3723 const bool ShouldUseDebuginfodByDefault = 3724 InputArgs.hasArg(OBJDUMP_build_id) || canUseDebuginfod(); 3725 std::vector<std::string> DebugFileDirectories = 3726 InputArgs.getAllArgValues(OBJDUMP_debug_file_directory); 3727 if (InputArgs.hasFlag(OBJDUMP_debuginfod, OBJDUMP_no_debuginfod, 3728 ShouldUseDebuginfodByDefault)) { 3729 HTTPClient::initialize(); 3730 BIDFetcher = 3731 std::make_unique<DebuginfodFetcher>(std::move(DebugFileDirectories)); 3732 } else { 3733 BIDFetcher = 3734 std::make_unique<BuildIDFetcher>(std::move(DebugFileDirectories)); 3735 } 3736 3737 if (Is("otool")) 3738 parseOtoolOptions(InputArgs); 3739 else 3740 parseObjdumpOptions(InputArgs); 3741 3742 if (StartAddress >= StopAddress) 3743 reportCmdLineError("start address should be less than stop address"); 3744 3745 // Removes trailing separators from prefix. 3746 while (!Prefix.empty() && sys::path::is_separator(Prefix.back())) 3747 Prefix.pop_back(); 3748 3749 if (AllHeaders) 3750 ArchiveHeaders = FileHeaders = PrivateHeaders = Relocations = 3751 SectionHeaders = SymbolTable = true; 3752 3753 if (DisassembleAll || PrintSource || PrintLines || TracebackTable || 3754 !DisassembleSymbols.empty()) 3755 Disassemble = true; 3756 3757 if (!ArchiveHeaders && !Disassemble && DwarfDumpType == DIDT_Null && 3758 !DynamicRelocations && !FileHeaders && !PrivateHeaders && !RawClangAST && 3759 !Relocations && !SectionHeaders && !SectionContents && !SymbolTable && 3760 !DynamicSymbolTable && !UnwindInfo && !FaultMapSection && !Offloading && 3761 !(MachOOpt && 3762 (Bind || DataInCode || ChainedFixups || DyldInfo || DylibId || 3763 DylibsUsed || ExportsTrie || FirstPrivateHeader || 3764 FunctionStartsType != FunctionStartsMode::None || IndirectSymbols || 3765 InfoPlist || LazyBind || LinkOptHints || ObjcMetaData || Rebase || 3766 Rpaths || UniversalHeaders || WeakBind || !FilterSections.empty()))) { 3767 T->printHelp(ToolName); 3768 return 2; 3769 } 3770 3771 DisasmSymbolSet.insert_range(DisassembleSymbols); 3772 3773 llvm::for_each(InputFilenames, dumpInput); 3774 3775 warnOnNoMatchForSections(); 3776 3777 return EXIT_SUCCESS; 3778 } 3779