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