Path: blob/main/contrib/llvm-project/llvm/tools/llvm-objdump/llvm-objdump.cpp
35231 views
//===-- llvm-objdump.cpp - Object file dumping utility for llvm -----------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This program is a utility that works like binutils "objdump", that is, it9// dumps out a plethora of information about an object file depending on the10// flags.11//12// The flags and output of this program should be near identical to those of13// binutils objdump.14//15//===----------------------------------------------------------------------===//1617#include "llvm-objdump.h"18#include "COFFDump.h"19#include "ELFDump.h"20#include "MachODump.h"21#include "ObjdumpOptID.h"22#include "OffloadDump.h"23#include "SourcePrinter.h"24#include "WasmDump.h"25#include "XCOFFDump.h"26#include "llvm/ADT/STLExtras.h"27#include "llvm/ADT/SetOperations.h"28#include "llvm/ADT/StringExtras.h"29#include "llvm/ADT/StringSet.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/SymbolizableModule.h"35#include "llvm/DebugInfo/Symbolize/Symbolize.h"36#include "llvm/Debuginfod/BuildIDFetcher.h"37#include "llvm/Debuginfod/Debuginfod.h"38#include "llvm/Debuginfod/HTTPClient.h"39#include "llvm/Demangle/Demangle.h"40#include "llvm/MC/MCAsmInfo.h"41#include "llvm/MC/MCContext.h"42#include "llvm/MC/MCDisassembler/MCDisassembler.h"43#include "llvm/MC/MCDisassembler/MCRelocationInfo.h"44#include "llvm/MC/MCInst.h"45#include "llvm/MC/MCInstPrinter.h"46#include "llvm/MC/MCInstrAnalysis.h"47#include "llvm/MC/MCInstrInfo.h"48#include "llvm/MC/MCObjectFileInfo.h"49#include "llvm/MC/MCRegisterInfo.h"50#include "llvm/MC/MCTargetOptions.h"51#include "llvm/MC/TargetRegistry.h"52#include "llvm/Object/Archive.h"53#include "llvm/Object/BuildID.h"54#include "llvm/Object/COFF.h"55#include "llvm/Object/COFFImportFile.h"56#include "llvm/Object/ELFObjectFile.h"57#include "llvm/Object/ELFTypes.h"58#include "llvm/Object/FaultMapParser.h"59#include "llvm/Object/MachO.h"60#include "llvm/Object/MachOUniversal.h"61#include "llvm/Object/ObjectFile.h"62#include "llvm/Object/OffloadBinary.h"63#include "llvm/Object/Wasm.h"64#include "llvm/Option/Arg.h"65#include "llvm/Option/ArgList.h"66#include "llvm/Option/Option.h"67#include "llvm/Support/Casting.h"68#include "llvm/Support/Debug.h"69#include "llvm/Support/Errc.h"70#include "llvm/Support/FileSystem.h"71#include "llvm/Support/Format.h"72#include "llvm/Support/FormatVariadic.h"73#include "llvm/Support/GraphWriter.h"74#include "llvm/Support/LLVMDriver.h"75#include "llvm/Support/MemoryBuffer.h"76#include "llvm/Support/SourceMgr.h"77#include "llvm/Support/StringSaver.h"78#include "llvm/Support/TargetSelect.h"79#include "llvm/Support/WithColor.h"80#include "llvm/Support/raw_ostream.h"81#include "llvm/TargetParser/Host.h"82#include "llvm/TargetParser/Triple.h"83#include <algorithm>84#include <cctype>85#include <cstring>86#include <optional>87#include <set>88#include <system_error>89#include <unordered_map>90#include <utility>9192using namespace llvm;93using namespace llvm::object;94using namespace llvm::objdump;95using namespace llvm::opt;9697namespace {9899class CommonOptTable : public opt::GenericOptTable {100public:101CommonOptTable(ArrayRef<Info> OptionInfos, const char *Usage,102const char *Description)103: opt::GenericOptTable(OptionInfos), Usage(Usage),104Description(Description) {105setGroupedShortOptions(true);106}107108void printHelp(StringRef Argv0, bool ShowHidden = false) const {109Argv0 = sys::path::filename(Argv0);110opt::GenericOptTable::printHelp(outs(), (Argv0 + Usage).str().c_str(),111Description, ShowHidden, ShowHidden);112// TODO Replace this with OptTable API once it adds extrahelp support.113outs() << "\nPass @FILE as argument to read options from FILE.\n";114}115116private:117const char *Usage;118const char *Description;119};120121// ObjdumpOptID is in ObjdumpOptID.h122namespace objdump_opt {123#define PREFIX(NAME, VALUE) \124static constexpr StringLiteral NAME##_init[] = VALUE; \125static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \126std::size(NAME##_init) - 1);127#include "ObjdumpOpts.inc"128#undef PREFIX129130static constexpr opt::OptTable::Info ObjdumpInfoTable[] = {131#define OPTION(...) \132LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(OBJDUMP_, __VA_ARGS__),133#include "ObjdumpOpts.inc"134#undef OPTION135};136} // namespace objdump_opt137138class ObjdumpOptTable : public CommonOptTable {139public:140ObjdumpOptTable()141: CommonOptTable(objdump_opt::ObjdumpInfoTable,142" [options] <input object files>",143"llvm object file dumper") {}144};145146enum OtoolOptID {147OTOOL_INVALID = 0, // This is not an option ID.148#define OPTION(...) LLVM_MAKE_OPT_ID_WITH_ID_PREFIX(OTOOL_, __VA_ARGS__),149#include "OtoolOpts.inc"150#undef OPTION151};152153namespace otool {154#define PREFIX(NAME, VALUE) \155static constexpr StringLiteral NAME##_init[] = VALUE; \156static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \157std::size(NAME##_init) - 1);158#include "OtoolOpts.inc"159#undef PREFIX160161static 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 otool167168class OtoolOptTable : public CommonOptTable {169public:170OtoolOptTable()171: CommonOptTable(otool::OtoolInfoTable, " [option...] [file...]",172"Mach-O object file displaying tool") {}173};174175struct BBAddrMapLabel {176std::string BlockLabel;177std::string PGOAnalysis;178};179180// This class represents the BBAddrMap and PGOMap associated with a single181// function.182class BBAddrMapFunctionEntry {183public:184BBAddrMapFunctionEntry(BBAddrMap AddrMap, PGOAnalysisMap PGOMap)185: AddrMap(std::move(AddrMap)), PGOMap(std::move(PGOMap)) {}186187const BBAddrMap &getAddrMap() const { return AddrMap; }188189// Returns the PGO string associated with the entry of index `PGOBBEntryIndex`190// in `PGOMap`. If PrettyPGOAnalysis is true, prints BFI as relative frequency191// and BPI as percentage. Otherwise raw values are displayed.192std::string constructPGOLabelString(size_t PGOBBEntryIndex,193bool PrettyPGOAnalysis) const {194if (!PGOMap.FeatEnable.hasPGOAnalysis())195return "";196std::string PGOString;197raw_string_ostream PGOSS(PGOString);198199PGOSS << " (";200if (PGOMap.FeatEnable.FuncEntryCount && PGOBBEntryIndex == 0) {201PGOSS << "Entry count: " << Twine(PGOMap.FuncEntryCount);202if (PGOMap.FeatEnable.hasPGOAnalysisBBData()) {203PGOSS << ", ";204}205}206207if (PGOMap.FeatEnable.hasPGOAnalysisBBData()) {208209assert(PGOBBEntryIndex < PGOMap.BBEntries.size() &&210"Expected PGOAnalysisMap and BBAddrMap to have the same entries");211const PGOAnalysisMap::PGOBBEntry &PGOBBEntry =212PGOMap.BBEntries[PGOBBEntryIndex];213214if (PGOMap.FeatEnable.BBFreq) {215PGOSS << "Frequency: ";216if (PrettyPGOAnalysis)217printRelativeBlockFreq(PGOSS, PGOMap.BBEntries.front().BlockFreq,218PGOBBEntry.BlockFreq);219else220PGOSS << Twine(PGOBBEntry.BlockFreq.getFrequency());221if (PGOMap.FeatEnable.BrProb && PGOBBEntry.Successors.size() > 0) {222PGOSS << ", ";223}224}225if (PGOMap.FeatEnable.BrProb && PGOBBEntry.Successors.size() > 0) {226PGOSS << "Successors: ";227interleaveComma(228PGOBBEntry.Successors, PGOSS,229[&](const PGOAnalysisMap::PGOBBEntry::SuccessorEntry &SE) {230PGOSS << "BB" << SE.ID << ":";231if (PrettyPGOAnalysis)232PGOSS << "[" << SE.Prob << "]";233else234PGOSS.write_hex(SE.Prob.getNumerator());235});236}237}238PGOSS << ")";239240return PGOString;241}242243private:244const BBAddrMap AddrMap;245const PGOAnalysisMap PGOMap;246};247248// This class represents the BBAddrMap and PGOMap of potentially multiple249// functions in a section.250class BBAddrMapInfo {251public:252void clear() {253FunctionAddrToMap.clear();254RangeBaseAddrToFunctionAddr.clear();255}256257bool empty() const { return FunctionAddrToMap.empty(); }258259void AddFunctionEntry(BBAddrMap AddrMap, PGOAnalysisMap PGOMap) {260uint64_t FunctionAddr = AddrMap.getFunctionAddress();261for (size_t I = 1; I < AddrMap.BBRanges.size(); ++I)262RangeBaseAddrToFunctionAddr.emplace(AddrMap.BBRanges[I].BaseAddress,263FunctionAddr);264[[maybe_unused]] auto R = FunctionAddrToMap.try_emplace(265FunctionAddr, std::move(AddrMap), std::move(PGOMap));266assert(R.second && "duplicate function address");267}268269// Returns the BBAddrMap entry for the function associated with `BaseAddress`.270// `BaseAddress` could be the function address or the address of a range271// associated with that function. Returns `nullptr` if `BaseAddress` is not272// mapped to any entry.273const BBAddrMapFunctionEntry *getEntryForAddress(uint64_t BaseAddress) const {274uint64_t FunctionAddr = BaseAddress;275auto S = RangeBaseAddrToFunctionAddr.find(BaseAddress);276if (S != RangeBaseAddrToFunctionAddr.end())277FunctionAddr = S->second;278auto R = FunctionAddrToMap.find(FunctionAddr);279if (R == FunctionAddrToMap.end())280return nullptr;281return &R->second;282}283284private:285std::unordered_map<uint64_t, BBAddrMapFunctionEntry> FunctionAddrToMap;286std::unordered_map<uint64_t, uint64_t> RangeBaseAddrToFunctionAddr;287};288289} // namespace290291#define DEBUG_TYPE "objdump"292293enum class ColorOutput {294Auto,295Enable,296Disable,297Invalid,298};299300static uint64_t AdjustVMA;301static bool AllHeaders;302static std::string ArchName;303bool objdump::ArchiveHeaders;304bool objdump::Demangle;305bool objdump::Disassemble;306bool objdump::DisassembleAll;307bool objdump::SymbolDescription;308bool objdump::TracebackTable;309static std::vector<std::string> DisassembleSymbols;310static bool DisassembleZeroes;311static std::vector<std::string> DisassemblerOptions;312static ColorOutput DisassemblyColor;313DIDumpType objdump::DwarfDumpType;314static bool DynamicRelocations;315static bool FaultMapSection;316static bool FileHeaders;317bool objdump::SectionContents;318static std::vector<std::string> InputFilenames;319bool objdump::PrintLines;320static bool MachOOpt;321std::string objdump::MCPU;322std::vector<std::string> objdump::MAttrs;323bool objdump::ShowRawInsn;324bool objdump::LeadingAddr;325static bool Offloading;326static bool RawClangAST;327bool objdump::Relocations;328bool objdump::PrintImmHex;329bool objdump::PrivateHeaders;330std::vector<std::string> objdump::FilterSections;331bool objdump::SectionHeaders;332static bool ShowAllSymbols;333static bool ShowLMA;334bool objdump::PrintSource;335336static uint64_t StartAddress;337static bool HasStartAddressFlag;338static uint64_t StopAddress = UINT64_MAX;339static bool HasStopAddressFlag;340341bool objdump::SymbolTable;342static bool SymbolizeOperands;343static bool PrettyPGOAnalysisMap;344static bool DynamicSymbolTable;345std::string objdump::TripleName;346bool objdump::UnwindInfo;347static bool Wide;348std::string objdump::Prefix;349uint32_t objdump::PrefixStrip;350351DebugVarsFormat objdump::DbgVariables = DVDisabled;352353int objdump::DbgIndent = 52;354355static StringSet<> DisasmSymbolSet;356StringSet<> objdump::FoundSectionSet;357static StringRef ToolName;358359std::unique_ptr<BuildIDFetcher> BIDFetcher;360361Dumper::Dumper(const object::ObjectFile &O) : O(O) {362WarningHandler = [this](const Twine &Msg) {363if (Warnings.insert(Msg.str()).second)364reportWarning(Msg, this->O.getFileName());365return Error::success();366};367}368369void Dumper::reportUniqueWarning(Error Err) {370reportUniqueWarning(toString(std::move(Err)));371}372373void Dumper::reportUniqueWarning(const Twine &Msg) {374cantFail(WarningHandler(Msg));375}376377static Expected<std::unique_ptr<Dumper>> createDumper(const ObjectFile &Obj) {378if (const auto *O = dyn_cast<COFFObjectFile>(&Obj))379return createCOFFDumper(*O);380if (const auto *O = dyn_cast<ELFObjectFileBase>(&Obj))381return createELFDumper(*O);382if (const auto *O = dyn_cast<MachOObjectFile>(&Obj))383return createMachODumper(*O);384if (const auto *O = dyn_cast<WasmObjectFile>(&Obj))385return createWasmDumper(*O);386if (const auto *O = dyn_cast<XCOFFObjectFile>(&Obj))387return createXCOFFDumper(*O);388389return createStringError(errc::invalid_argument,390"unsupported object file format");391}392393namespace {394struct FilterResult {395// True if the section should not be skipped.396bool Keep;397398// True if the index counter should be incremented, even if the section should399// be skipped. For example, sections may be skipped if they are not included400// in the --section flag, but we still want those to count toward the section401// count.402bool IncrementIndex;403};404} // namespace405406static FilterResult checkSectionFilter(object::SectionRef S) {407if (FilterSections.empty())408return {/*Keep=*/true, /*IncrementIndex=*/true};409410Expected<StringRef> SecNameOrErr = S.getName();411if (!SecNameOrErr) {412consumeError(SecNameOrErr.takeError());413return {/*Keep=*/false, /*IncrementIndex=*/false};414}415StringRef SecName = *SecNameOrErr;416417// StringSet does not allow empty key so avoid adding sections with418// no name (such as the section with index 0) here.419if (!SecName.empty())420FoundSectionSet.insert(SecName);421422// Only show the section if it's in the FilterSections list, but always423// increment so the indexing is stable.424return {/*Keep=*/is_contained(FilterSections, SecName),425/*IncrementIndex=*/true};426}427428SectionFilter objdump::ToolSectionFilter(object::ObjectFile const &O,429uint64_t *Idx) {430// Start at UINT64_MAX so that the first index returned after an increment is431// zero (after the unsigned wrap).432if (Idx)433*Idx = UINT64_MAX;434return SectionFilter(435[Idx](object::SectionRef S) {436FilterResult Result = checkSectionFilter(S);437if (Idx != nullptr && Result.IncrementIndex)438*Idx += 1;439return Result.Keep;440},441O);442}443444std::string objdump::getFileNameForError(const object::Archive::Child &C,445unsigned Index) {446Expected<StringRef> NameOrErr = C.getName();447if (NameOrErr)448return std::string(NameOrErr.get());449// If we have an error getting the name then we print the index of the archive450// member. Since we are already in an error state, we just ignore this error.451consumeError(NameOrErr.takeError());452return "<file index: " + std::to_string(Index) + ">";453}454455void objdump::reportWarning(const Twine &Message, StringRef File) {456// Output order between errs() and outs() matters especially for archive457// files where the output is per member object.458outs().flush();459WithColor::warning(errs(), ToolName)460<< "'" << File << "': " << Message << "\n";461}462463[[noreturn]] void objdump::reportError(StringRef File, const Twine &Message) {464outs().flush();465WithColor::error(errs(), ToolName) << "'" << File << "': " << Message << "\n";466exit(1);467}468469[[noreturn]] void objdump::reportError(Error E, StringRef FileName,470StringRef ArchiveName,471StringRef ArchitectureName) {472assert(E);473outs().flush();474WithColor::error(errs(), ToolName);475if (ArchiveName != "")476errs() << ArchiveName << "(" << FileName << ")";477else478errs() << "'" << FileName << "'";479if (!ArchitectureName.empty())480errs() << " (for architecture " << ArchitectureName << ")";481errs() << ": ";482logAllUnhandledErrors(std::move(E), errs());483exit(1);484}485486static void reportCmdLineWarning(const Twine &Message) {487WithColor::warning(errs(), ToolName) << Message << "\n";488}489490[[noreturn]] static void reportCmdLineError(const Twine &Message) {491WithColor::error(errs(), ToolName) << Message << "\n";492exit(1);493}494495static void warnOnNoMatchForSections() {496SetVector<StringRef> MissingSections;497for (StringRef S : FilterSections) {498if (FoundSectionSet.count(S))499return;500// User may specify a unnamed section. Don't warn for it.501if (!S.empty())502MissingSections.insert(S);503}504505// Warn only if no section in FilterSections is matched.506for (StringRef S : MissingSections)507reportCmdLineWarning("section '" + S +508"' mentioned in a -j/--section option, but not "509"found in any input file");510}511512static const Target *getTarget(const ObjectFile *Obj) {513// Figure out the target triple.514Triple TheTriple("unknown-unknown-unknown");515if (TripleName.empty()) {516TheTriple = Obj->makeTriple();517} else {518TheTriple.setTriple(Triple::normalize(TripleName));519auto Arch = Obj->getArch();520if (Arch == Triple::arm || Arch == Triple::armeb)521Obj->setARMSubArch(TheTriple);522}523524// Get the target specific parser.525std::string Error;526const Target *TheTarget = TargetRegistry::lookupTarget(ArchName, TheTriple,527Error);528if (!TheTarget)529reportError(Obj->getFileName(), "can't find target: " + Error);530531// Update the triple name and return the found target.532TripleName = TheTriple.getTriple();533return TheTarget;534}535536bool objdump::isRelocAddressLess(RelocationRef A, RelocationRef B) {537return A.getOffset() < B.getOffset();538}539540static Error getRelocationValueString(const RelocationRef &Rel,541bool SymbolDescription,542SmallVectorImpl<char> &Result) {543const ObjectFile *Obj = Rel.getObject();544if (auto *ELF = dyn_cast<ELFObjectFileBase>(Obj))545return getELFRelocationValueString(ELF, Rel, Result);546if (auto *COFF = dyn_cast<COFFObjectFile>(Obj))547return getCOFFRelocationValueString(COFF, Rel, Result);548if (auto *Wasm = dyn_cast<WasmObjectFile>(Obj))549return getWasmRelocationValueString(Wasm, Rel, Result);550if (auto *MachO = dyn_cast<MachOObjectFile>(Obj))551return getMachORelocationValueString(MachO, Rel, Result);552if (auto *XCOFF = dyn_cast<XCOFFObjectFile>(Obj))553return getXCOFFRelocationValueString(*XCOFF, Rel, SymbolDescription,554Result);555llvm_unreachable("unknown object file format");556}557558/// Indicates whether this relocation should hidden when listing559/// relocations, usually because it is the trailing part of a multipart560/// relocation that will be printed as part of the leading relocation.561static bool getHidden(RelocationRef RelRef) {562auto *MachO = dyn_cast<MachOObjectFile>(RelRef.getObject());563if (!MachO)564return false;565566unsigned Arch = MachO->getArch();567DataRefImpl Rel = RelRef.getRawDataRefImpl();568uint64_t Type = MachO->getRelocationType(Rel);569570// On arches that use the generic relocations, GENERIC_RELOC_PAIR571// is always hidden.572if (Arch == Triple::x86 || Arch == Triple::arm || Arch == Triple::ppc)573return Type == MachO::GENERIC_RELOC_PAIR;574575if (Arch == Triple::x86_64) {576// On x86_64, X86_64_RELOC_UNSIGNED is hidden only when it follows577// an X86_64_RELOC_SUBTRACTOR.578if (Type == MachO::X86_64_RELOC_UNSIGNED && Rel.d.a > 0) {579DataRefImpl RelPrev = Rel;580RelPrev.d.a--;581uint64_t PrevType = MachO->getRelocationType(RelPrev);582if (PrevType == MachO::X86_64_RELOC_SUBTRACTOR)583return true;584}585}586587return false;588}589590/// Get the column at which we want to start printing the instruction591/// disassembly, taking into account anything which appears to the left of it.592unsigned objdump::getInstStartColumn(const MCSubtargetInfo &STI) {593return !ShowRawInsn ? 16 : STI.getTargetTriple().isX86() ? 40 : 24;594}595596static void AlignToInstStartColumn(size_t Start, const MCSubtargetInfo &STI,597raw_ostream &OS) {598// The output of printInst starts with a tab. Print some spaces so that599// the tab has 1 column and advances to the target tab stop.600unsigned TabStop = getInstStartColumn(STI);601unsigned Column = OS.tell() - Start;602OS.indent(Column < TabStop - 1 ? TabStop - 1 - Column : 7 - Column % 8);603}604605void objdump::printRawData(ArrayRef<uint8_t> Bytes, uint64_t Address,606formatted_raw_ostream &OS,607MCSubtargetInfo const &STI) {608size_t Start = OS.tell();609if (LeadingAddr)610OS << format("%8" PRIx64 ":", Address);611if (ShowRawInsn) {612OS << ' ';613dumpBytes(Bytes, OS);614}615AlignToInstStartColumn(Start, STI, OS);616}617618namespace {619620static bool isAArch64Elf(const ObjectFile &Obj) {621const auto *Elf = dyn_cast<ELFObjectFileBase>(&Obj);622return Elf && Elf->getEMachine() == ELF::EM_AARCH64;623}624625static bool isArmElf(const ObjectFile &Obj) {626const auto *Elf = dyn_cast<ELFObjectFileBase>(&Obj);627return Elf && Elf->getEMachine() == ELF::EM_ARM;628}629630static bool isCSKYElf(const ObjectFile &Obj) {631const auto *Elf = dyn_cast<ELFObjectFileBase>(&Obj);632return Elf && Elf->getEMachine() == ELF::EM_CSKY;633}634635static bool hasMappingSymbols(const ObjectFile &Obj) {636return isArmElf(Obj) || isAArch64Elf(Obj) || isCSKYElf(Obj) ;637}638639static void printRelocation(formatted_raw_ostream &OS, StringRef FileName,640const RelocationRef &Rel, uint64_t Address,641bool Is64Bits) {642StringRef Fmt = Is64Bits ? "%016" PRIx64 ": " : "%08" PRIx64 ": ";643SmallString<16> Name;644SmallString<32> Val;645Rel.getTypeName(Name);646if (Error E = getRelocationValueString(Rel, SymbolDescription, Val))647reportError(std::move(E), FileName);648OS << (Is64Bits || !LeadingAddr ? "\t\t" : "\t\t\t");649if (LeadingAddr)650OS << format(Fmt.data(), Address);651OS << Name << "\t" << Val;652}653654static void printBTFRelocation(formatted_raw_ostream &FOS, llvm::BTFParser &BTF,655object::SectionedAddress Address,656LiveVariablePrinter &LVP) {657const llvm::BTF::BPFFieldReloc *Reloc = BTF.findFieldReloc(Address);658if (!Reloc)659return;660661SmallString<64> Val;662BTF.symbolize(Reloc, Val);663FOS << "\t\t";664if (LeadingAddr)665FOS << format("%016" PRIx64 ": ", Address.Address + AdjustVMA);666FOS << "CO-RE " << Val;667LVP.printAfterOtherLine(FOS, true);668}669670class PrettyPrinter {671public:672virtual ~PrettyPrinter() = default;673virtual void674printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes,675object::SectionedAddress Address, formatted_raw_ostream &OS,676StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP,677StringRef ObjectFilename, std::vector<RelocationRef> *Rels,678LiveVariablePrinter &LVP) {679if (SP && (PrintSource || PrintLines))680SP->printSourceLine(OS, Address, ObjectFilename, LVP);681LVP.printBetweenInsts(OS, false);682683printRawData(Bytes, Address.Address, OS, STI);684685if (MI) {686// See MCInstPrinter::printInst. On targets where a PC relative immediate687// is relative to the next instruction and the length of a MCInst is688// difficult to measure (x86), this is the address of the next689// instruction.690uint64_t Addr =691Address.Address + (STI.getTargetTriple().isX86() ? Bytes.size() : 0);692IP.printInst(MI, Addr, "", STI, OS);693} else694OS << "\t<unknown>";695}696};697PrettyPrinter PrettyPrinterInst;698699class HexagonPrettyPrinter : public PrettyPrinter {700public:701void printLead(ArrayRef<uint8_t> Bytes, uint64_t Address,702formatted_raw_ostream &OS) {703uint32_t opcode =704(Bytes[3] << 24) | (Bytes[2] << 16) | (Bytes[1] << 8) | Bytes[0];705if (LeadingAddr)706OS << format("%8" PRIx64 ":", Address);707if (ShowRawInsn) {708OS << "\t";709dumpBytes(Bytes.slice(0, 4), OS);710OS << format("\t%08" PRIx32, opcode);711}712}713void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes,714object::SectionedAddress Address, formatted_raw_ostream &OS,715StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP,716StringRef ObjectFilename, std::vector<RelocationRef> *Rels,717LiveVariablePrinter &LVP) override {718if (SP && (PrintSource || PrintLines))719SP->printSourceLine(OS, Address, ObjectFilename, LVP, "");720if (!MI) {721printLead(Bytes, Address.Address, OS);722OS << " <unknown>";723return;724}725std::string Buffer;726{727raw_string_ostream TempStream(Buffer);728IP.printInst(MI, Address.Address, "", STI, TempStream);729}730StringRef Contents(Buffer);731// Split off bundle attributes732auto PacketBundle = Contents.rsplit('\n');733// Split off first instruction from the rest734auto HeadTail = PacketBundle.first.split('\n');735auto Preamble = " { ";736auto Separator = "";737738// Hexagon's packets require relocations to be inline rather than739// clustered at the end of the packet.740std::vector<RelocationRef>::const_iterator RelCur = Rels->begin();741std::vector<RelocationRef>::const_iterator RelEnd = Rels->end();742auto PrintReloc = [&]() -> void {743while ((RelCur != RelEnd) && (RelCur->getOffset() <= Address.Address)) {744if (RelCur->getOffset() == Address.Address) {745printRelocation(OS, ObjectFilename, *RelCur, Address.Address, false);746return;747}748++RelCur;749}750};751752while (!HeadTail.first.empty()) {753OS << Separator;754Separator = "\n";755if (SP && (PrintSource || PrintLines))756SP->printSourceLine(OS, Address, ObjectFilename, LVP, "");757printLead(Bytes, Address.Address, OS);758OS << Preamble;759Preamble = " ";760StringRef Inst;761auto Duplex = HeadTail.first.split('\v');762if (!Duplex.second.empty()) {763OS << Duplex.first;764OS << "; ";765Inst = Duplex.second;766}767else768Inst = HeadTail.first;769OS << Inst;770HeadTail = HeadTail.second.split('\n');771if (HeadTail.first.empty())772OS << " } " << PacketBundle.second;773PrintReloc();774Bytes = Bytes.slice(4);775Address.Address += 4;776}777}778};779HexagonPrettyPrinter HexagonPrettyPrinterInst;780781class AMDGCNPrettyPrinter : public PrettyPrinter {782public:783void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes,784object::SectionedAddress Address, formatted_raw_ostream &OS,785StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP,786StringRef ObjectFilename, std::vector<RelocationRef> *Rels,787LiveVariablePrinter &LVP) override {788if (SP && (PrintSource || PrintLines))789SP->printSourceLine(OS, Address, ObjectFilename, LVP);790791if (MI) {792SmallString<40> InstStr;793raw_svector_ostream IS(InstStr);794795IP.printInst(MI, Address.Address, "", STI, IS);796797OS << left_justify(IS.str(), 60);798} else {799// an unrecognized encoding - this is probably data so represent it800// using the .long directive, or .byte directive if fewer than 4 bytes801// remaining802if (Bytes.size() >= 4) {803OS << format(804"\t.long 0x%08" PRIx32 " ",805support::endian::read32<llvm::endianness::little>(Bytes.data()));806OS.indent(42);807} else {808OS << format("\t.byte 0x%02" PRIx8, Bytes[0]);809for (unsigned int i = 1; i < Bytes.size(); i++)810OS << format(", 0x%02" PRIx8, Bytes[i]);811OS.indent(55 - (6 * Bytes.size()));812}813}814815OS << format("// %012" PRIX64 ":", Address.Address);816if (Bytes.size() >= 4) {817// D should be casted to uint32_t here as it is passed by format to818// snprintf as vararg.819for (uint32_t D :820ArrayRef(reinterpret_cast<const support::little32_t *>(Bytes.data()),821Bytes.size() / 4))822OS << format(" %08" PRIX32, D);823} else {824for (unsigned char B : Bytes)825OS << format(" %02" PRIX8, B);826}827828if (!Annot.empty())829OS << " // " << Annot;830}831};832AMDGCNPrettyPrinter AMDGCNPrettyPrinterInst;833834class BPFPrettyPrinter : public PrettyPrinter {835public:836void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes,837object::SectionedAddress Address, formatted_raw_ostream &OS,838StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP,839StringRef ObjectFilename, std::vector<RelocationRef> *Rels,840LiveVariablePrinter &LVP) override {841if (SP && (PrintSource || PrintLines))842SP->printSourceLine(OS, Address, ObjectFilename, LVP);843if (LeadingAddr)844OS << format("%8" PRId64 ":", Address.Address / 8);845if (ShowRawInsn) {846OS << "\t";847dumpBytes(Bytes, OS);848}849if (MI)850IP.printInst(MI, Address.Address, "", STI, OS);851else852OS << "\t<unknown>";853}854};855BPFPrettyPrinter BPFPrettyPrinterInst;856857class ARMPrettyPrinter : public PrettyPrinter {858public:859void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes,860object::SectionedAddress Address, formatted_raw_ostream &OS,861StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP,862StringRef ObjectFilename, std::vector<RelocationRef> *Rels,863LiveVariablePrinter &LVP) override {864if (SP && (PrintSource || PrintLines))865SP->printSourceLine(OS, Address, ObjectFilename, LVP);866LVP.printBetweenInsts(OS, false);867868size_t Start = OS.tell();869if (LeadingAddr)870OS << format("%8" PRIx64 ":", Address.Address);871if (ShowRawInsn) {872size_t Pos = 0, End = Bytes.size();873if (STI.checkFeatures("+thumb-mode")) {874for (; Pos + 2 <= End; Pos += 2)875OS << ' '876<< format_hex_no_prefix(877llvm::support::endian::read<uint16_t>(878Bytes.data() + Pos, InstructionEndianness),8794);880} else {881for (; Pos + 4 <= End; Pos += 4)882OS << ' '883<< format_hex_no_prefix(884llvm::support::endian::read<uint32_t>(885Bytes.data() + Pos, InstructionEndianness),8868);887}888if (Pos < End) {889OS << ' ';890dumpBytes(Bytes.slice(Pos), OS);891}892}893894AlignToInstStartColumn(Start, STI, OS);895896if (MI) {897IP.printInst(MI, Address.Address, "", STI, OS);898} else899OS << "\t<unknown>";900}901902void setInstructionEndianness(llvm::endianness Endianness) {903InstructionEndianness = Endianness;904}905906private:907llvm::endianness InstructionEndianness = llvm::endianness::little;908};909ARMPrettyPrinter ARMPrettyPrinterInst;910911class AArch64PrettyPrinter : public PrettyPrinter {912public:913void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes,914object::SectionedAddress Address, formatted_raw_ostream &OS,915StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP,916StringRef ObjectFilename, std::vector<RelocationRef> *Rels,917LiveVariablePrinter &LVP) override {918if (SP && (PrintSource || PrintLines))919SP->printSourceLine(OS, Address, ObjectFilename, LVP);920LVP.printBetweenInsts(OS, false);921922size_t Start = OS.tell();923if (LeadingAddr)924OS << format("%8" PRIx64 ":", Address.Address);925if (ShowRawInsn) {926size_t Pos = 0, End = Bytes.size();927for (; Pos + 4 <= End; Pos += 4)928OS << ' '929<< format_hex_no_prefix(930llvm::support::endian::read<uint32_t>(931Bytes.data() + Pos, llvm::endianness::little),9328);933if (Pos < End) {934OS << ' ';935dumpBytes(Bytes.slice(Pos), OS);936}937}938939AlignToInstStartColumn(Start, STI, OS);940941if (MI) {942IP.printInst(MI, Address.Address, "", STI, OS);943} else944OS << "\t<unknown>";945}946};947AArch64PrettyPrinter AArch64PrettyPrinterInst;948949class RISCVPrettyPrinter : public PrettyPrinter {950public:951void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes,952object::SectionedAddress Address, formatted_raw_ostream &OS,953StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP,954StringRef ObjectFilename, std::vector<RelocationRef> *Rels,955LiveVariablePrinter &LVP) override {956if (SP && (PrintSource || PrintLines))957SP->printSourceLine(OS, Address, ObjectFilename, LVP);958LVP.printBetweenInsts(OS, false);959960size_t Start = OS.tell();961if (LeadingAddr)962OS << format("%8" PRIx64 ":", Address.Address);963if (ShowRawInsn) {964size_t Pos = 0, End = Bytes.size();965if (End % 4 == 0) {966// 32-bit and 64-bit instructions.967for (; Pos + 4 <= End; Pos += 4)968OS << ' '969<< format_hex_no_prefix(970llvm::support::endian::read<uint32_t>(971Bytes.data() + Pos, llvm::endianness::little),9728);973} else if (End % 2 == 0) {974// 16-bit and 48-bits instructions.975for (; Pos + 2 <= End; Pos += 2)976OS << ' '977<< format_hex_no_prefix(978llvm::support::endian::read<uint16_t>(979Bytes.data() + Pos, llvm::endianness::little),9804);981}982if (Pos < End) {983OS << ' ';984dumpBytes(Bytes.slice(Pos), OS);985}986}987988AlignToInstStartColumn(Start, STI, OS);989990if (MI) {991IP.printInst(MI, Address.Address, "", STI, OS);992} else993OS << "\t<unknown>";994}995};996RISCVPrettyPrinter RISCVPrettyPrinterInst;997998PrettyPrinter &selectPrettyPrinter(Triple const &Triple) {999switch(Triple.getArch()) {1000default:1001return PrettyPrinterInst;1002case Triple::hexagon:1003return HexagonPrettyPrinterInst;1004case Triple::amdgcn:1005return AMDGCNPrettyPrinterInst;1006case Triple::bpfel:1007case Triple::bpfeb:1008return BPFPrettyPrinterInst;1009case Triple::arm:1010case Triple::armeb:1011case Triple::thumb:1012case Triple::thumbeb:1013return ARMPrettyPrinterInst;1014case Triple::aarch64:1015case Triple::aarch64_be:1016case Triple::aarch64_32:1017return AArch64PrettyPrinterInst;1018case Triple::riscv32:1019case Triple::riscv64:1020return RISCVPrettyPrinterInst;1021}1022}10231024class DisassemblerTarget {1025public:1026const Target *TheTarget;1027std::unique_ptr<const MCSubtargetInfo> SubtargetInfo;1028std::shared_ptr<MCContext> Context;1029std::unique_ptr<MCDisassembler> DisAsm;1030std::shared_ptr<MCInstrAnalysis> InstrAnalysis;1031std::shared_ptr<MCInstPrinter> InstPrinter;1032PrettyPrinter *Printer;10331034DisassemblerTarget(const Target *TheTarget, ObjectFile &Obj,1035StringRef TripleName, StringRef MCPU,1036SubtargetFeatures &Features);1037DisassemblerTarget(DisassemblerTarget &Other, SubtargetFeatures &Features);10381039private:1040MCTargetOptions Options;1041std::shared_ptr<const MCRegisterInfo> RegisterInfo;1042std::shared_ptr<const MCAsmInfo> AsmInfo;1043std::shared_ptr<const MCInstrInfo> InstrInfo;1044std::shared_ptr<MCObjectFileInfo> ObjectFileInfo;1045};10461047DisassemblerTarget::DisassemblerTarget(const Target *TheTarget, ObjectFile &Obj,1048StringRef TripleName, StringRef MCPU,1049SubtargetFeatures &Features)1050: TheTarget(TheTarget),1051Printer(&selectPrettyPrinter(Triple(TripleName))),1052RegisterInfo(TheTarget->createMCRegInfo(TripleName)) {1053if (!RegisterInfo)1054reportError(Obj.getFileName(), "no register info for target " + TripleName);10551056// Set up disassembler.1057AsmInfo.reset(TheTarget->createMCAsmInfo(*RegisterInfo, TripleName, Options));1058if (!AsmInfo)1059reportError(Obj.getFileName(), "no assembly info for target " + TripleName);10601061SubtargetInfo.reset(1062TheTarget->createMCSubtargetInfo(TripleName, MCPU, Features.getString()));1063if (!SubtargetInfo)1064reportError(Obj.getFileName(),1065"no subtarget info for target " + TripleName);1066InstrInfo.reset(TheTarget->createMCInstrInfo());1067if (!InstrInfo)1068reportError(Obj.getFileName(),1069"no instruction info for target " + TripleName);1070Context =1071std::make_shared<MCContext>(Triple(TripleName), AsmInfo.get(),1072RegisterInfo.get(), SubtargetInfo.get());10731074// FIXME: for now initialize MCObjectFileInfo with default values1075ObjectFileInfo.reset(1076TheTarget->createMCObjectFileInfo(*Context, /*PIC=*/false));1077Context->setObjectFileInfo(ObjectFileInfo.get());10781079DisAsm.reset(TheTarget->createMCDisassembler(*SubtargetInfo, *Context));1080if (!DisAsm)1081reportError(Obj.getFileName(), "no disassembler for target " + TripleName);10821083if (auto *ELFObj = dyn_cast<ELFObjectFileBase>(&Obj))1084DisAsm->setABIVersion(ELFObj->getEIdentABIVersion());10851086InstrAnalysis.reset(TheTarget->createMCInstrAnalysis(InstrInfo.get()));10871088int AsmPrinterVariant = AsmInfo->getAssemblerDialect();1089InstPrinter.reset(TheTarget->createMCInstPrinter(Triple(TripleName),1090AsmPrinterVariant, *AsmInfo,1091*InstrInfo, *RegisterInfo));1092if (!InstPrinter)1093reportError(Obj.getFileName(),1094"no instruction printer for target " + TripleName);1095InstPrinter->setPrintImmHex(PrintImmHex);1096InstPrinter->setPrintBranchImmAsAddress(true);1097InstPrinter->setSymbolizeOperands(SymbolizeOperands);1098InstPrinter->setMCInstrAnalysis(InstrAnalysis.get());10991100switch (DisassemblyColor) {1101case ColorOutput::Enable:1102InstPrinter->setUseColor(true);1103break;1104case ColorOutput::Auto:1105InstPrinter->setUseColor(outs().has_colors());1106break;1107case ColorOutput::Disable:1108case ColorOutput::Invalid:1109InstPrinter->setUseColor(false);1110break;1111};1112}11131114DisassemblerTarget::DisassemblerTarget(DisassemblerTarget &Other,1115SubtargetFeatures &Features)1116: TheTarget(Other.TheTarget),1117SubtargetInfo(TheTarget->createMCSubtargetInfo(TripleName, MCPU,1118Features.getString())),1119Context(Other.Context),1120DisAsm(TheTarget->createMCDisassembler(*SubtargetInfo, *Context)),1121InstrAnalysis(Other.InstrAnalysis), InstPrinter(Other.InstPrinter),1122Printer(Other.Printer), RegisterInfo(Other.RegisterInfo),1123AsmInfo(Other.AsmInfo), InstrInfo(Other.InstrInfo),1124ObjectFileInfo(Other.ObjectFileInfo) {}1125} // namespace11261127static uint8_t getElfSymbolType(const ObjectFile &Obj, const SymbolRef &Sym) {1128assert(Obj.isELF());1129if (auto *Elf32LEObj = dyn_cast<ELF32LEObjectFile>(&Obj))1130return unwrapOrError(Elf32LEObj->getSymbol(Sym.getRawDataRefImpl()),1131Obj.getFileName())1132->getType();1133if (auto *Elf64LEObj = dyn_cast<ELF64LEObjectFile>(&Obj))1134return unwrapOrError(Elf64LEObj->getSymbol(Sym.getRawDataRefImpl()),1135Obj.getFileName())1136->getType();1137if (auto *Elf32BEObj = dyn_cast<ELF32BEObjectFile>(&Obj))1138return unwrapOrError(Elf32BEObj->getSymbol(Sym.getRawDataRefImpl()),1139Obj.getFileName())1140->getType();1141if (auto *Elf64BEObj = cast<ELF64BEObjectFile>(&Obj))1142return unwrapOrError(Elf64BEObj->getSymbol(Sym.getRawDataRefImpl()),1143Obj.getFileName())1144->getType();1145llvm_unreachable("Unsupported binary format");1146}11471148template <class ELFT>1149static void1150addDynamicElfSymbols(const ELFObjectFile<ELFT> &Obj,1151std::map<SectionRef, SectionSymbolsTy> &AllSymbols) {1152for (auto Symbol : Obj.getDynamicSymbolIterators()) {1153uint8_t SymbolType = Symbol.getELFType();1154if (SymbolType == ELF::STT_SECTION)1155continue;11561157uint64_t Address = unwrapOrError(Symbol.getAddress(), Obj.getFileName());1158// ELFSymbolRef::getAddress() returns size instead of value for common1159// symbols which is not desirable for disassembly output. Overriding.1160if (SymbolType == ELF::STT_COMMON)1161Address = unwrapOrError(Obj.getSymbol(Symbol.getRawDataRefImpl()),1162Obj.getFileName())1163->st_value;11641165StringRef Name = unwrapOrError(Symbol.getName(), Obj.getFileName());1166if (Name.empty())1167continue;11681169section_iterator SecI =1170unwrapOrError(Symbol.getSection(), Obj.getFileName());1171if (SecI == Obj.section_end())1172continue;11731174AllSymbols[*SecI].emplace_back(Address, Name, SymbolType);1175}1176}11771178static void1179addDynamicElfSymbols(const ELFObjectFileBase &Obj,1180std::map<SectionRef, SectionSymbolsTy> &AllSymbols) {1181if (auto *Elf32LEObj = dyn_cast<ELF32LEObjectFile>(&Obj))1182addDynamicElfSymbols(*Elf32LEObj, AllSymbols);1183else if (auto *Elf64LEObj = dyn_cast<ELF64LEObjectFile>(&Obj))1184addDynamicElfSymbols(*Elf64LEObj, AllSymbols);1185else if (auto *Elf32BEObj = dyn_cast<ELF32BEObjectFile>(&Obj))1186addDynamicElfSymbols(*Elf32BEObj, AllSymbols);1187else if (auto *Elf64BEObj = cast<ELF64BEObjectFile>(&Obj))1188addDynamicElfSymbols(*Elf64BEObj, AllSymbols);1189else1190llvm_unreachable("Unsupported binary format");1191}11921193static std::optional<SectionRef> getWasmCodeSection(const WasmObjectFile &Obj) {1194for (auto SecI : Obj.sections()) {1195const WasmSection &Section = Obj.getWasmSection(SecI);1196if (Section.Type == wasm::WASM_SEC_CODE)1197return SecI;1198}1199return std::nullopt;1200}12011202static void1203addMissingWasmCodeSymbols(const WasmObjectFile &Obj,1204std::map<SectionRef, SectionSymbolsTy> &AllSymbols) {1205std::optional<SectionRef> Section = getWasmCodeSection(Obj);1206if (!Section)1207return;1208SectionSymbolsTy &Symbols = AllSymbols[*Section];12091210std::set<uint64_t> SymbolAddresses;1211for (const auto &Sym : Symbols)1212SymbolAddresses.insert(Sym.Addr);12131214for (const wasm::WasmFunction &Function : Obj.functions()) {1215// This adjustment mirrors the one in WasmObjectFile::getSymbolAddress.1216uint32_t Adjustment = Obj.isRelocatableObject() || Obj.isSharedObject()1217? 01218: Section->getAddress();1219uint64_t Address = Function.CodeSectionOffset + Adjustment;1220// Only add fallback symbols for functions not already present in the symbol1221// table.1222if (SymbolAddresses.count(Address))1223continue;1224// This function has no symbol, so it should have no SymbolName.1225assert(Function.SymbolName.empty());1226// We use DebugName for the name, though it may be empty if there is no1227// "name" custom section, or that section is missing a name for this1228// function.1229StringRef Name = Function.DebugName;1230Symbols.emplace_back(Address, Name, ELF::STT_NOTYPE);1231}1232}12331234static void addPltEntries(const ObjectFile &Obj,1235std::map<SectionRef, SectionSymbolsTy> &AllSymbols,1236StringSaver &Saver) {1237auto *ElfObj = dyn_cast<ELFObjectFileBase>(&Obj);1238if (!ElfObj)1239return;1240DenseMap<StringRef, SectionRef> Sections;1241for (SectionRef Section : Obj.sections()) {1242Expected<StringRef> SecNameOrErr = Section.getName();1243if (!SecNameOrErr) {1244consumeError(SecNameOrErr.takeError());1245continue;1246}1247Sections[*SecNameOrErr] = Section;1248}1249for (auto Plt : ElfObj->getPltEntries()) {1250if (Plt.Symbol) {1251SymbolRef Symbol(*Plt.Symbol, ElfObj);1252uint8_t SymbolType = getElfSymbolType(Obj, Symbol);1253if (Expected<StringRef> NameOrErr = Symbol.getName()) {1254if (!NameOrErr->empty())1255AllSymbols[Sections[Plt.Section]].emplace_back(1256Plt.Address, Saver.save((*NameOrErr + "@plt").str()), SymbolType);1257continue;1258} else {1259// The warning has been reported in disassembleObject().1260consumeError(NameOrErr.takeError());1261}1262}1263reportWarning("PLT entry at 0x" + Twine::utohexstr(Plt.Address) +1264" references an invalid symbol",1265Obj.getFileName());1266}1267}12681269// Normally the disassembly output will skip blocks of zeroes. This function1270// returns the number of zero bytes that can be skipped when dumping the1271// disassembly of the instructions in Buf.1272static size_t countSkippableZeroBytes(ArrayRef<uint8_t> Buf) {1273// Find the number of leading zeroes.1274size_t N = 0;1275while (N < Buf.size() && !Buf[N])1276++N;12771278// We may want to skip blocks of zero bytes, but unless we see1279// at least 8 of them in a row.1280if (N < 8)1281return 0;12821283// We skip zeroes in multiples of 4 because do not want to truncate an1284// instruction if it starts with a zero byte.1285return N & ~0x3;1286}12871288// Returns a map from sections to their relocations.1289static std::map<SectionRef, std::vector<RelocationRef>>1290getRelocsMap(object::ObjectFile const &Obj) {1291std::map<SectionRef, std::vector<RelocationRef>> Ret;1292uint64_t I = (uint64_t)-1;1293for (SectionRef Sec : Obj.sections()) {1294++I;1295Expected<section_iterator> RelocatedOrErr = Sec.getRelocatedSection();1296if (!RelocatedOrErr)1297reportError(Obj.getFileName(),1298"section (" + Twine(I) +1299"): failed to get a relocated section: " +1300toString(RelocatedOrErr.takeError()));13011302section_iterator Relocated = *RelocatedOrErr;1303if (Relocated == Obj.section_end() || !checkSectionFilter(*Relocated).Keep)1304continue;1305std::vector<RelocationRef> &V = Ret[*Relocated];1306append_range(V, Sec.relocations());1307// Sort relocations by address.1308llvm::stable_sort(V, isRelocAddressLess);1309}1310return Ret;1311}13121313// Used for --adjust-vma to check if address should be adjusted by the1314// specified value for a given section.1315// For ELF we do not adjust non-allocatable sections like debug ones,1316// because they are not loadable.1317// TODO: implement for other file formats.1318static bool shouldAdjustVA(const SectionRef &Section) {1319const ObjectFile *Obj = Section.getObject();1320if (Obj->isELF())1321return ELFSectionRef(Section).getFlags() & ELF::SHF_ALLOC;1322return false;1323}132413251326typedef std::pair<uint64_t, char> MappingSymbolPair;1327static char getMappingSymbolKind(ArrayRef<MappingSymbolPair> MappingSymbols,1328uint64_t Address) {1329auto It =1330partition_point(MappingSymbols, [Address](const MappingSymbolPair &Val) {1331return Val.first <= Address;1332});1333// Return zero for any address before the first mapping symbol; this means1334// we should use the default disassembly mode, depending on the target.1335if (It == MappingSymbols.begin())1336return '\x00';1337return (It - 1)->second;1338}13391340static uint64_t dumpARMELFData(uint64_t SectionAddr, uint64_t Index,1341uint64_t End, const ObjectFile &Obj,1342ArrayRef<uint8_t> Bytes,1343ArrayRef<MappingSymbolPair> MappingSymbols,1344const MCSubtargetInfo &STI, raw_ostream &OS) {1345llvm::endianness Endian =1346Obj.isLittleEndian() ? llvm::endianness::little : llvm::endianness::big;1347size_t Start = OS.tell();1348OS << format("%8" PRIx64 ": ", SectionAddr + Index);1349if (Index + 4 <= End) {1350dumpBytes(Bytes.slice(Index, 4), OS);1351AlignToInstStartColumn(Start, STI, OS);1352OS << "\t.word\t"1353<< format_hex(support::endian::read32(Bytes.data() + Index, Endian),135410);1355return 4;1356}1357if (Index + 2 <= End) {1358dumpBytes(Bytes.slice(Index, 2), OS);1359AlignToInstStartColumn(Start, STI, OS);1360OS << "\t.short\t"1361<< format_hex(support::endian::read16(Bytes.data() + Index, Endian), 6);1362return 2;1363}1364dumpBytes(Bytes.slice(Index, 1), OS);1365AlignToInstStartColumn(Start, STI, OS);1366OS << "\t.byte\t" << format_hex(Bytes[Index], 4);1367return 1;1368}13691370static void dumpELFData(uint64_t SectionAddr, uint64_t Index, uint64_t End,1371ArrayRef<uint8_t> Bytes) {1372// print out data up to 8 bytes at a time in hex and ascii1373uint8_t AsciiData[9] = {'\0'};1374uint8_t Byte;1375int NumBytes = 0;13761377for (; Index < End; ++Index) {1378if (NumBytes == 0)1379outs() << format("%8" PRIx64 ":", SectionAddr + Index);1380Byte = Bytes.slice(Index)[0];1381outs() << format(" %02x", Byte);1382AsciiData[NumBytes] = isPrint(Byte) ? Byte : '.';13831384uint8_t IndentOffset = 0;1385NumBytes++;1386if (Index == End - 1 || NumBytes > 8) {1387// Indent the space for less than 8 bytes data.1388// 2 spaces for byte and one for space between bytes1389IndentOffset = 3 * (8 - NumBytes);1390for (int Excess = NumBytes; Excess < 8; Excess++)1391AsciiData[Excess] = '\0';1392NumBytes = 8;1393}1394if (NumBytes == 8) {1395AsciiData[8] = '\0';1396outs() << std::string(IndentOffset, ' ') << " ";1397outs() << reinterpret_cast<char *>(AsciiData);1398outs() << '\n';1399NumBytes = 0;1400}1401}1402}14031404SymbolInfoTy objdump::createSymbolInfo(const ObjectFile &Obj,1405const SymbolRef &Symbol,1406bool IsMappingSymbol) {1407const StringRef FileName = Obj.getFileName();1408const uint64_t Addr = unwrapOrError(Symbol.getAddress(), FileName);1409const StringRef Name = unwrapOrError(Symbol.getName(), FileName);14101411if (Obj.isXCOFF() && (SymbolDescription || TracebackTable)) {1412const auto &XCOFFObj = cast<XCOFFObjectFile>(Obj);1413DataRefImpl SymbolDRI = Symbol.getRawDataRefImpl();14141415const uint32_t SymbolIndex = XCOFFObj.getSymbolIndex(SymbolDRI.p);1416std::optional<XCOFF::StorageMappingClass> Smc =1417getXCOFFSymbolCsectSMC(XCOFFObj, Symbol);1418return SymbolInfoTy(Smc, Addr, Name, SymbolIndex,1419isLabel(XCOFFObj, Symbol));1420} else if (Obj.isXCOFF()) {1421const SymbolRef::Type SymType = unwrapOrError(Symbol.getType(), FileName);1422return SymbolInfoTy(Addr, Name, SymType, /*IsMappingSymbol=*/false,1423/*IsXCOFF=*/true);1424} else if (Obj.isWasm()) {1425uint8_t SymType =1426cast<WasmObjectFile>(&Obj)->getWasmSymbol(Symbol).Info.Kind;1427return SymbolInfoTy(Addr, Name, SymType, false);1428} else {1429uint8_t Type =1430Obj.isELF() ? getElfSymbolType(Obj, Symbol) : (uint8_t)ELF::STT_NOTYPE;1431return SymbolInfoTy(Addr, Name, Type, IsMappingSymbol);1432}1433}14341435static SymbolInfoTy createDummySymbolInfo(const ObjectFile &Obj,1436const uint64_t Addr, StringRef &Name,1437uint8_t Type) {1438if (Obj.isXCOFF() && (SymbolDescription || TracebackTable))1439return SymbolInfoTy(std::nullopt, Addr, Name, std::nullopt, false);1440if (Obj.isWasm())1441return SymbolInfoTy(Addr, Name, wasm::WASM_SYMBOL_TYPE_SECTION);1442return SymbolInfoTy(Addr, Name, Type);1443}14441445static void collectBBAddrMapLabels(1446const BBAddrMapInfo &FullAddrMap, uint64_t SectionAddr, uint64_t Start,1447uint64_t End,1448std::unordered_map<uint64_t, std::vector<BBAddrMapLabel>> &Labels) {1449if (FullAddrMap.empty())1450return;1451Labels.clear();1452uint64_t StartAddress = SectionAddr + Start;1453uint64_t EndAddress = SectionAddr + End;1454const BBAddrMapFunctionEntry *FunctionMap =1455FullAddrMap.getEntryForAddress(StartAddress);1456if (!FunctionMap)1457return;1458std::optional<size_t> BBRangeIndex =1459FunctionMap->getAddrMap().getBBRangeIndexForBaseAddress(StartAddress);1460if (!BBRangeIndex)1461return;1462size_t NumBBEntriesBeforeRange = 0;1463for (size_t I = 0; I < *BBRangeIndex; ++I)1464NumBBEntriesBeforeRange +=1465FunctionMap->getAddrMap().BBRanges[I].BBEntries.size();1466const auto &BBRange = FunctionMap->getAddrMap().BBRanges[*BBRangeIndex];1467for (size_t I = 0; I < BBRange.BBEntries.size(); ++I) {1468const BBAddrMap::BBEntry &BBEntry = BBRange.BBEntries[I];1469uint64_t BBAddress = BBEntry.Offset + BBRange.BaseAddress;1470if (BBAddress >= EndAddress)1471continue;14721473std::string LabelString = ("BB" + Twine(BBEntry.ID)).str();1474Labels[BBAddress].push_back(1475{LabelString, FunctionMap->constructPGOLabelString(1476NumBBEntriesBeforeRange + I, PrettyPGOAnalysisMap)});1477}1478}14791480static void1481collectLocalBranchTargets(ArrayRef<uint8_t> Bytes, MCInstrAnalysis *MIA,1482MCDisassembler *DisAsm, MCInstPrinter *IP,1483const MCSubtargetInfo *STI, uint64_t SectionAddr,1484uint64_t Start, uint64_t End,1485std::unordered_map<uint64_t, std::string> &Labels) {1486// So far only supports PowerPC and X86.1487const bool isPPC = STI->getTargetTriple().isPPC();1488if (!isPPC && !STI->getTargetTriple().isX86())1489return;14901491if (MIA)1492MIA->resetState();14931494Labels.clear();1495unsigned LabelCount = 0;1496Start += SectionAddr;1497End += SectionAddr;1498const bool isXCOFF = STI->getTargetTriple().isOSBinFormatXCOFF();1499for (uint64_t Index = Start; Index < End;) {1500// Disassemble a real instruction and record function-local branch labels.1501MCInst Inst;1502uint64_t Size;1503ArrayRef<uint8_t> ThisBytes = Bytes.slice(Index - SectionAddr);1504bool Disassembled =1505DisAsm->getInstruction(Inst, Size, ThisBytes, Index, nulls());1506if (Size == 0)1507Size = std::min<uint64_t>(ThisBytes.size(),1508DisAsm->suggestBytesToSkip(ThisBytes, Index));15091510if (MIA) {1511if (Disassembled) {1512uint64_t Target;1513bool TargetKnown = MIA->evaluateBranch(Inst, Index, Size, Target);1514if (TargetKnown && (Target >= Start && Target < End) &&1515!Labels.count(Target)) {1516// On PowerPC and AIX, a function call is encoded as a branch to 0.1517// On other PowerPC platforms (ELF), a function call is encoded as1518// a branch to self. Do not add a label for these cases.1519if (!(isPPC &&1520((Target == 0 && isXCOFF) || (Target == Index && !isXCOFF))))1521Labels[Target] = ("L" + Twine(LabelCount++)).str();1522}1523MIA->updateState(Inst, Index);1524} else1525MIA->resetState();1526}1527Index += Size;1528}1529}15301531// Create an MCSymbolizer for the target and add it to the MCDisassembler.1532// This is currently only used on AMDGPU, and assumes the format of the1533// void * argument passed to AMDGPU's createMCSymbolizer.1534static void addSymbolizer(1535MCContext &Ctx, const Target *Target, StringRef TripleName,1536MCDisassembler *DisAsm, uint64_t SectionAddr, ArrayRef<uint8_t> Bytes,1537SectionSymbolsTy &Symbols,1538std::vector<std::unique_ptr<std::string>> &SynthesizedLabelNames) {15391540std::unique_ptr<MCRelocationInfo> RelInfo(1541Target->createMCRelocationInfo(TripleName, Ctx));1542if (!RelInfo)1543return;1544std::unique_ptr<MCSymbolizer> Symbolizer(Target->createMCSymbolizer(1545TripleName, nullptr, nullptr, &Symbols, &Ctx, std::move(RelInfo)));1546MCSymbolizer *SymbolizerPtr = &*Symbolizer;1547DisAsm->setSymbolizer(std::move(Symbolizer));15481549if (!SymbolizeOperands)1550return;15511552// Synthesize labels referenced by branch instructions by1553// disassembling, discarding the output, and collecting the referenced1554// addresses from the symbolizer.1555for (size_t Index = 0; Index != Bytes.size();) {1556MCInst Inst;1557uint64_t Size;1558ArrayRef<uint8_t> ThisBytes = Bytes.slice(Index);1559const uint64_t ThisAddr = SectionAddr + Index;1560DisAsm->getInstruction(Inst, Size, ThisBytes, ThisAddr, nulls());1561if (Size == 0)1562Size = std::min<uint64_t>(ThisBytes.size(),1563DisAsm->suggestBytesToSkip(ThisBytes, Index));1564Index += Size;1565}1566ArrayRef<uint64_t> LabelAddrsRef = SymbolizerPtr->getReferencedAddresses();1567// Copy and sort to remove duplicates.1568std::vector<uint64_t> LabelAddrs;1569LabelAddrs.insert(LabelAddrs.end(), LabelAddrsRef.begin(),1570LabelAddrsRef.end());1571llvm::sort(LabelAddrs);1572LabelAddrs.resize(llvm::unique(LabelAddrs) - LabelAddrs.begin());1573// Add the labels.1574for (unsigned LabelNum = 0; LabelNum != LabelAddrs.size(); ++LabelNum) {1575auto Name = std::make_unique<std::string>();1576*Name = (Twine("L") + Twine(LabelNum)).str();1577SynthesizedLabelNames.push_back(std::move(Name));1578Symbols.push_back(SymbolInfoTy(1579LabelAddrs[LabelNum], *SynthesizedLabelNames.back(), ELF::STT_NOTYPE));1580}1581llvm::stable_sort(Symbols);1582// Recreate the symbolizer with the new symbols list.1583RelInfo.reset(Target->createMCRelocationInfo(TripleName, Ctx));1584Symbolizer.reset(Target->createMCSymbolizer(1585TripleName, nullptr, nullptr, &Symbols, &Ctx, std::move(RelInfo)));1586DisAsm->setSymbolizer(std::move(Symbolizer));1587}15881589static StringRef getSegmentName(const MachOObjectFile *MachO,1590const SectionRef &Section) {1591if (MachO) {1592DataRefImpl DR = Section.getRawDataRefImpl();1593StringRef SegmentName = MachO->getSectionFinalSegmentName(DR);1594return SegmentName;1595}1596return "";1597}15981599static void emitPostInstructionInfo(formatted_raw_ostream &FOS,1600const MCAsmInfo &MAI,1601const MCSubtargetInfo &STI,1602StringRef Comments,1603LiveVariablePrinter &LVP) {1604do {1605if (!Comments.empty()) {1606// Emit a line of comments.1607StringRef Comment;1608std::tie(Comment, Comments) = Comments.split('\n');1609// MAI.getCommentColumn() assumes that instructions are printed at the1610// position of 8, while getInstStartColumn() returns the actual position.1611unsigned CommentColumn =1612MAI.getCommentColumn() - 8 + getInstStartColumn(STI);1613FOS.PadToColumn(CommentColumn);1614FOS << MAI.getCommentString() << ' ' << Comment;1615}1616LVP.printAfterInst(FOS);1617FOS << '\n';1618} while (!Comments.empty());1619FOS.flush();1620}16211622static void createFakeELFSections(ObjectFile &Obj) {1623assert(Obj.isELF());1624if (auto *Elf32LEObj = dyn_cast<ELF32LEObjectFile>(&Obj))1625Elf32LEObj->createFakeSections();1626else if (auto *Elf64LEObj = dyn_cast<ELF64LEObjectFile>(&Obj))1627Elf64LEObj->createFakeSections();1628else if (auto *Elf32BEObj = dyn_cast<ELF32BEObjectFile>(&Obj))1629Elf32BEObj->createFakeSections();1630else if (auto *Elf64BEObj = cast<ELF64BEObjectFile>(&Obj))1631Elf64BEObj->createFakeSections();1632else1633llvm_unreachable("Unsupported binary format");1634}16351636// Tries to fetch a more complete version of the given object file using its1637// Build ID. Returns std::nullopt if nothing was found.1638static std::optional<OwningBinary<Binary>>1639fetchBinaryByBuildID(const ObjectFile &Obj) {1640object::BuildIDRef BuildID = getBuildID(&Obj);1641if (BuildID.empty())1642return std::nullopt;1643std::optional<std::string> Path = BIDFetcher->fetch(BuildID);1644if (!Path)1645return std::nullopt;1646Expected<OwningBinary<Binary>> DebugBinary = createBinary(*Path);1647if (!DebugBinary) {1648reportWarning(toString(DebugBinary.takeError()), *Path);1649return std::nullopt;1650}1651return std::move(*DebugBinary);1652}16531654static void1655disassembleObject(ObjectFile &Obj, const ObjectFile &DbgObj,1656DisassemblerTarget &PrimaryTarget,1657std::optional<DisassemblerTarget> &SecondaryTarget,1658SourcePrinter &SP, bool InlineRelocs) {1659DisassemblerTarget *DT = &PrimaryTarget;1660bool PrimaryIsThumb = false;1661SmallVector<std::pair<uint64_t, uint64_t>, 0> CHPECodeMap;16621663if (SecondaryTarget) {1664if (isArmElf(Obj)) {1665PrimaryIsThumb =1666PrimaryTarget.SubtargetInfo->checkFeatures("+thumb-mode");1667} else if (const auto *COFFObj = dyn_cast<COFFObjectFile>(&Obj)) {1668const chpe_metadata *CHPEMetadata = COFFObj->getCHPEMetadata();1669if (CHPEMetadata && CHPEMetadata->CodeMapCount) {1670uintptr_t CodeMapInt;1671cantFail(COFFObj->getRvaPtr(CHPEMetadata->CodeMap, CodeMapInt));1672auto CodeMap = reinterpret_cast<const chpe_range_entry *>(CodeMapInt);16731674for (uint32_t i = 0; i < CHPEMetadata->CodeMapCount; ++i) {1675if (CodeMap[i].getType() == chpe_range_type::Amd64 &&1676CodeMap[i].Length) {1677// Store x86_64 CHPE code ranges.1678uint64_t Start = CodeMap[i].getStart() + COFFObj->getImageBase();1679CHPECodeMap.emplace_back(Start, Start + CodeMap[i].Length);1680}1681}1682llvm::sort(CHPECodeMap);1683}1684}1685}16861687std::map<SectionRef, std::vector<RelocationRef>> RelocMap;1688if (InlineRelocs || Obj.isXCOFF())1689RelocMap = getRelocsMap(Obj);1690bool Is64Bits = Obj.getBytesInAddress() > 4;16911692// Create a mapping from virtual address to symbol name. This is used to1693// pretty print the symbols while disassembling.1694std::map<SectionRef, SectionSymbolsTy> AllSymbols;1695std::map<SectionRef, SmallVector<MappingSymbolPair, 0>> AllMappingSymbols;1696SectionSymbolsTy AbsoluteSymbols;1697const StringRef FileName = Obj.getFileName();1698const MachOObjectFile *MachO = dyn_cast<const MachOObjectFile>(&Obj);1699for (const SymbolRef &Symbol : Obj.symbols()) {1700Expected<StringRef> NameOrErr = Symbol.getName();1701if (!NameOrErr) {1702reportWarning(toString(NameOrErr.takeError()), FileName);1703continue;1704}1705if (NameOrErr->empty() && !(Obj.isXCOFF() && SymbolDescription))1706continue;17071708if (Obj.isELF() &&1709(cantFail(Symbol.getFlags()) & SymbolRef::SF_FormatSpecific)) {1710// Symbol is intended not to be displayed by default (STT_FILE,1711// STT_SECTION, or a mapping symbol). Ignore STT_SECTION symbols. We will1712// synthesize a section symbol if no symbol is defined at offset 0.1713//1714// For a mapping symbol, store it within both AllSymbols and1715// AllMappingSymbols. If --show-all-symbols is unspecified, its label will1716// not be printed in disassembly listing.1717if (getElfSymbolType(Obj, Symbol) != ELF::STT_SECTION &&1718hasMappingSymbols(Obj)) {1719section_iterator SecI = unwrapOrError(Symbol.getSection(), FileName);1720if (SecI != Obj.section_end()) {1721uint64_t SectionAddr = SecI->getAddress();1722uint64_t Address = cantFail(Symbol.getAddress());1723StringRef Name = *NameOrErr;1724if (Name.consume_front("$") && Name.size() &&1725strchr("adtx", Name[0])) {1726AllMappingSymbols[*SecI].emplace_back(Address - SectionAddr,1727Name[0]);1728AllSymbols[*SecI].push_back(1729createSymbolInfo(Obj, Symbol, /*MappingSymbol=*/true));1730}1731}1732}1733continue;1734}17351736if (MachO) {1737// __mh_(execute|dylib|dylinker|bundle|preload|object)_header are special1738// symbols that support MachO header introspection. They do not bind to1739// code locations and are irrelevant for disassembly.1740if (NameOrErr->starts_with("__mh_") && NameOrErr->ends_with("_header"))1741continue;1742// Don't ask a Mach-O STAB symbol for its section unless you know that1743// STAB symbol's section field refers to a valid section index. Otherwise1744// the symbol may error trying to load a section that does not exist.1745DataRefImpl SymDRI = Symbol.getRawDataRefImpl();1746uint8_t NType = (MachO->is64Bit() ?1747MachO->getSymbol64TableEntry(SymDRI).n_type:1748MachO->getSymbolTableEntry(SymDRI).n_type);1749if (NType & MachO::N_STAB)1750continue;1751}17521753section_iterator SecI = unwrapOrError(Symbol.getSection(), FileName);1754if (SecI != Obj.section_end())1755AllSymbols[*SecI].push_back(createSymbolInfo(Obj, Symbol));1756else1757AbsoluteSymbols.push_back(createSymbolInfo(Obj, Symbol));1758}17591760if (AllSymbols.empty() && Obj.isELF())1761addDynamicElfSymbols(cast<ELFObjectFileBase>(Obj), AllSymbols);17621763if (Obj.isWasm())1764addMissingWasmCodeSymbols(cast<WasmObjectFile>(Obj), AllSymbols);17651766if (Obj.isELF() && Obj.sections().empty())1767createFakeELFSections(Obj);17681769BumpPtrAllocator A;1770StringSaver Saver(A);1771addPltEntries(Obj, AllSymbols, Saver);17721773// Create a mapping from virtual address to section. An empty section can1774// cause more than one section at the same address. Sort such sections to be1775// before same-addressed non-empty sections so that symbol lookups prefer the1776// non-empty section.1777std::vector<std::pair<uint64_t, SectionRef>> SectionAddresses;1778for (SectionRef Sec : Obj.sections())1779SectionAddresses.emplace_back(Sec.getAddress(), Sec);1780llvm::stable_sort(SectionAddresses, [](const auto &LHS, const auto &RHS) {1781if (LHS.first != RHS.first)1782return LHS.first < RHS.first;1783return LHS.second.getSize() < RHS.second.getSize();1784});17851786// Linked executables (.exe and .dll files) typically don't include a real1787// symbol table but they might contain an export table.1788if (const auto *COFFObj = dyn_cast<COFFObjectFile>(&Obj)) {1789for (const auto &ExportEntry : COFFObj->export_directories()) {1790StringRef Name;1791if (Error E = ExportEntry.getSymbolName(Name))1792reportError(std::move(E), Obj.getFileName());1793if (Name.empty())1794continue;17951796uint32_t RVA;1797if (Error E = ExportEntry.getExportRVA(RVA))1798reportError(std::move(E), Obj.getFileName());17991800uint64_t VA = COFFObj->getImageBase() + RVA;1801auto Sec = partition_point(1802SectionAddresses, [VA](const std::pair<uint64_t, SectionRef> &O) {1803return O.first <= VA;1804});1805if (Sec != SectionAddresses.begin()) {1806--Sec;1807AllSymbols[Sec->second].emplace_back(VA, Name, ELF::STT_NOTYPE);1808} else1809AbsoluteSymbols.emplace_back(VA, Name, ELF::STT_NOTYPE);1810}1811}18121813// Sort all the symbols, this allows us to use a simple binary search to find1814// Multiple symbols can have the same address. Use a stable sort to stabilize1815// the output.1816StringSet<> FoundDisasmSymbolSet;1817for (std::pair<const SectionRef, SectionSymbolsTy> &SecSyms : AllSymbols)1818llvm::stable_sort(SecSyms.second);1819llvm::stable_sort(AbsoluteSymbols);18201821std::unique_ptr<DWARFContext> DICtx;1822LiveVariablePrinter LVP(*DT->Context->getRegisterInfo(), *DT->SubtargetInfo);18231824if (DbgVariables != DVDisabled) {1825DICtx = DWARFContext::create(DbgObj);1826for (const std::unique_ptr<DWARFUnit> &CU : DICtx->compile_units())1827LVP.addCompileUnit(CU->getUnitDIE(false));1828}18291830LLVM_DEBUG(LVP.dump());18311832BBAddrMapInfo FullAddrMap;1833auto ReadBBAddrMap = [&](std::optional<unsigned> SectionIndex =1834std::nullopt) {1835FullAddrMap.clear();1836if (const auto *Elf = dyn_cast<ELFObjectFileBase>(&Obj)) {1837std::vector<PGOAnalysisMap> PGOAnalyses;1838auto BBAddrMapsOrErr = Elf->readBBAddrMap(SectionIndex, &PGOAnalyses);1839if (!BBAddrMapsOrErr) {1840reportWarning(toString(BBAddrMapsOrErr.takeError()), Obj.getFileName());1841return;1842}1843for (auto &&[FunctionBBAddrMap, FunctionPGOAnalysis] :1844zip_equal(*std::move(BBAddrMapsOrErr), std::move(PGOAnalyses))) {1845FullAddrMap.AddFunctionEntry(std::move(FunctionBBAddrMap),1846std::move(FunctionPGOAnalysis));1847}1848}1849};18501851// For non-relocatable objects, Read all LLVM_BB_ADDR_MAP sections into a1852// single mapping, since they don't have any conflicts.1853if (SymbolizeOperands && !Obj.isRelocatableObject())1854ReadBBAddrMap();18551856std::optional<llvm::BTFParser> BTF;1857if (InlineRelocs && BTFParser::hasBTFSections(Obj)) {1858BTF.emplace();1859BTFParser::ParseOptions Opts = {};1860Opts.LoadTypes = true;1861Opts.LoadRelocs = true;1862if (Error E = BTF->parse(Obj, Opts))1863WithColor::defaultErrorHandler(std::move(E));1864}18651866for (const SectionRef &Section : ToolSectionFilter(Obj)) {1867if (FilterSections.empty() && !DisassembleAll &&1868(!Section.isText() || Section.isVirtual()))1869continue;18701871uint64_t SectionAddr = Section.getAddress();1872uint64_t SectSize = Section.getSize();1873if (!SectSize)1874continue;18751876// For relocatable object files, read the LLVM_BB_ADDR_MAP section1877// corresponding to this section, if present.1878if (SymbolizeOperands && Obj.isRelocatableObject())1879ReadBBAddrMap(Section.getIndex());18801881// Get the list of all the symbols in this section.1882SectionSymbolsTy &Symbols = AllSymbols[Section];1883auto &MappingSymbols = AllMappingSymbols[Section];1884llvm::sort(MappingSymbols);18851886ArrayRef<uint8_t> Bytes = arrayRefFromStringRef(1887unwrapOrError(Section.getContents(), Obj.getFileName()));18881889std::vector<std::unique_ptr<std::string>> SynthesizedLabelNames;1890if (Obj.isELF() && Obj.getArch() == Triple::amdgcn) {1891// AMDGPU disassembler uses symbolizer for printing labels1892addSymbolizer(*DT->Context, DT->TheTarget, TripleName, DT->DisAsm.get(),1893SectionAddr, Bytes, Symbols, SynthesizedLabelNames);1894}18951896StringRef SegmentName = getSegmentName(MachO, Section);1897StringRef SectionName = unwrapOrError(Section.getName(), Obj.getFileName());1898// If the section has no symbol at the start, just insert a dummy one.1899// Without --show-all-symbols, also insert one if all symbols at the start1900// are mapping symbols.1901bool CreateDummy = Symbols.empty();1902if (!CreateDummy) {1903CreateDummy = true;1904for (auto &Sym : Symbols) {1905if (Sym.Addr != SectionAddr)1906break;1907if (!Sym.IsMappingSymbol || ShowAllSymbols)1908CreateDummy = false;1909}1910}1911if (CreateDummy) {1912SymbolInfoTy Sym = createDummySymbolInfo(1913Obj, SectionAddr, SectionName,1914Section.isText() ? ELF::STT_FUNC : ELF::STT_OBJECT);1915if (Obj.isXCOFF())1916Symbols.insert(Symbols.begin(), Sym);1917else1918Symbols.insert(llvm::lower_bound(Symbols, Sym), Sym);1919}19201921SmallString<40> Comments;1922raw_svector_ostream CommentStream(Comments);19231924uint64_t VMAAdjustment = 0;1925if (shouldAdjustVA(Section))1926VMAAdjustment = AdjustVMA;19271928// In executable and shared objects, r_offset holds a virtual address.1929// Subtract SectionAddr from the r_offset field of a relocation to get1930// the section offset.1931uint64_t RelAdjustment = Obj.isRelocatableObject() ? 0 : SectionAddr;1932uint64_t Size;1933uint64_t Index;1934bool PrintedSection = false;1935std::vector<RelocationRef> Rels = RelocMap[Section];1936std::vector<RelocationRef>::const_iterator RelCur = Rels.begin();1937std::vector<RelocationRef>::const_iterator RelEnd = Rels.end();19381939// Loop over each chunk of code between two points where at least1940// one symbol is defined.1941for (size_t SI = 0, SE = Symbols.size(); SI != SE;) {1942// Advance SI past all the symbols starting at the same address,1943// and make an ArrayRef of them.1944unsigned FirstSI = SI;1945uint64_t Start = Symbols[SI].Addr;1946ArrayRef<SymbolInfoTy> SymbolsHere;1947while (SI != SE && Symbols[SI].Addr == Start)1948++SI;1949SymbolsHere = ArrayRef<SymbolInfoTy>(&Symbols[FirstSI], SI - FirstSI);19501951// Get the demangled names of all those symbols. We end up with a vector1952// of StringRef that holds the names we're going to use, and a vector of1953// std::string that stores the new strings returned by demangle(), if1954// any. If we don't call demangle() then that vector can stay empty.1955std::vector<StringRef> SymNamesHere;1956std::vector<std::string> DemangledSymNamesHere;1957if (Demangle) {1958// Fetch the demangled names and store them locally.1959for (const SymbolInfoTy &Symbol : SymbolsHere)1960DemangledSymNamesHere.push_back(demangle(Symbol.Name));1961// Now we've finished modifying that vector, it's safe to make1962// a vector of StringRefs pointing into it.1963SymNamesHere.insert(SymNamesHere.begin(), DemangledSymNamesHere.begin(),1964DemangledSymNamesHere.end());1965} else {1966for (const SymbolInfoTy &Symbol : SymbolsHere)1967SymNamesHere.push_back(Symbol.Name);1968}19691970// Distinguish ELF data from code symbols, which will be used later on to1971// decide whether to 'disassemble' this chunk as a data declaration via1972// dumpELFData(), or whether to treat it as code.1973//1974// If data _and_ code symbols are defined at the same address, the code1975// takes priority, on the grounds that disassembling code is our main1976// purpose here, and it would be a worse failure to _not_ interpret1977// something that _was_ meaningful as code than vice versa.1978//1979// Any ELF symbol type that is not clearly data will be regarded as code.1980// In particular, one of the uses of STT_NOTYPE is for branch targets1981// inside functions, for which STT_FUNC would be inaccurate.1982//1983// So here, we spot whether there's any non-data symbol present at all,1984// and only set the DisassembleAsELFData flag if there isn't. Also, we use1985// this distinction to inform the decision of which symbol to print at1986// the head of the section, so that if we're printing code, we print a1987// code-related symbol name to go with it.1988bool DisassembleAsELFData = false;1989size_t DisplaySymIndex = SymbolsHere.size() - 1;1990if (Obj.isELF() && !DisassembleAll && Section.isText()) {1991DisassembleAsELFData = true; // unless we find a code symbol below19921993for (size_t i = 0; i < SymbolsHere.size(); ++i) {1994uint8_t SymTy = SymbolsHere[i].Type;1995if (SymTy != ELF::STT_OBJECT && SymTy != ELF::STT_COMMON) {1996DisassembleAsELFData = false;1997DisplaySymIndex = i;1998}1999}2000}20012002// Decide which symbol(s) from this collection we're going to print.2003std::vector<bool> SymsToPrint(SymbolsHere.size(), false);2004// If the user has given the --disassemble-symbols option, then we must2005// display every symbol in that set, and no others.2006if (!DisasmSymbolSet.empty()) {2007bool FoundAny = false;2008for (size_t i = 0; i < SymbolsHere.size(); ++i) {2009if (DisasmSymbolSet.count(SymNamesHere[i])) {2010SymsToPrint[i] = true;2011FoundAny = true;2012}2013}20142015// And if none of the symbols here is one that the user asked for, skip2016// disassembling this entire chunk of code.2017if (!FoundAny)2018continue;2019} else if (!SymbolsHere[DisplaySymIndex].IsMappingSymbol) {2020// Otherwise, print whichever symbol at this location is last in the2021// Symbols array, because that array is pre-sorted in a way intended to2022// correlate with priority of which symbol to display.2023SymsToPrint[DisplaySymIndex] = true;2024}20252026// Now that we know we're disassembling this section, override the choice2027// of which symbols to display by printing _all_ of them at this address2028// if the user asked for all symbols.2029//2030// That way, '--show-all-symbols --disassemble-symbol=foo' will print2031// only the chunk of code headed by 'foo', but also show any other2032// symbols defined at that address, such as aliases for 'foo', or the ARM2033// mapping symbol preceding its code.2034if (ShowAllSymbols) {2035for (size_t i = 0; i < SymbolsHere.size(); ++i)2036SymsToPrint[i] = true;2037}20382039if (Start < SectionAddr || StopAddress <= Start)2040continue;20412042for (size_t i = 0; i < SymbolsHere.size(); ++i)2043FoundDisasmSymbolSet.insert(SymNamesHere[i]);20442045// The end is the section end, the beginning of the next symbol, or2046// --stop-address.2047uint64_t End = std::min<uint64_t>(SectionAddr + SectSize, StopAddress);2048if (SI < SE)2049End = std::min(End, Symbols[SI].Addr);2050if (Start >= End || End <= StartAddress)2051continue;2052Start -= SectionAddr;2053End -= SectionAddr;20542055if (!PrintedSection) {2056PrintedSection = true;2057outs() << "\nDisassembly of section ";2058if (!SegmentName.empty())2059outs() << SegmentName << ",";2060outs() << SectionName << ":\n";2061}20622063bool PrintedLabel = false;2064for (size_t i = 0; i < SymbolsHere.size(); ++i) {2065if (!SymsToPrint[i])2066continue;20672068const SymbolInfoTy &Symbol = SymbolsHere[i];2069const StringRef SymbolName = SymNamesHere[i];20702071if (!PrintedLabel) {2072outs() << '\n';2073PrintedLabel = true;2074}2075if (LeadingAddr)2076outs() << format(Is64Bits ? "%016" PRIx64 " " : "%08" PRIx64 " ",2077SectionAddr + Start + VMAAdjustment);2078if (Obj.isXCOFF() && SymbolDescription) {2079outs() << getXCOFFSymbolDescription(Symbol, SymbolName) << ":\n";2080} else2081outs() << '<' << SymbolName << ">:\n";2082}20832084// Don't print raw contents of a virtual section. A virtual section2085// doesn't have any contents in the file.2086if (Section.isVirtual()) {2087outs() << "...\n";2088continue;2089}20902091// See if any of the symbols defined at this location triggers target-2092// specific disassembly behavior, e.g. of special descriptors or function2093// prelude information.2094//2095// We stop this loop at the first symbol that triggers some kind of2096// interesting behavior (if any), on the assumption that if two symbols2097// defined at the same address trigger two conflicting symbol handlers,2098// the object file is probably confused anyway, and it would make even2099// less sense to present the output of _both_ handlers, because that2100// would describe the same data twice.2101for (size_t SHI = 0; SHI < SymbolsHere.size(); ++SHI) {2102SymbolInfoTy Symbol = SymbolsHere[SHI];21032104Expected<bool> RespondedOrErr = DT->DisAsm->onSymbolStart(2105Symbol, Size, Bytes.slice(Start, End - Start), SectionAddr + Start);21062107if (RespondedOrErr && !*RespondedOrErr) {2108// This symbol didn't trigger any interesting handling. Try the other2109// symbols defined at this address.2110continue;2111}21122113// If onSymbolStart returned an Error, that means it identified some2114// kind of special data at this address, but wasn't able to disassemble2115// it meaningfully. So we fall back to printing the error out and2116// disassembling the failed region as bytes, assuming that the target2117// detected the failure before printing anything.2118if (!RespondedOrErr) {2119std::string ErrMsgStr = toString(RespondedOrErr.takeError());2120StringRef ErrMsg = ErrMsgStr;2121do {2122StringRef Line;2123std::tie(Line, ErrMsg) = ErrMsg.split('\n');2124outs() << DT->Context->getAsmInfo()->getCommentString()2125<< " error decoding " << SymNamesHere[SHI] << ": " << Line2126<< '\n';2127} while (!ErrMsg.empty());21282129if (Size) {2130outs() << DT->Context->getAsmInfo()->getCommentString()2131<< " decoding failed region as bytes\n";2132for (uint64_t I = 0; I < Size; ++I)2133outs() << "\t.byte\t " << format_hex(Bytes[I], 1, /*Upper=*/true)2134<< '\n';2135}2136}21372138// Regardless of whether onSymbolStart returned an Error or true, 'Size'2139// will have been set to the amount of data covered by whatever prologue2140// the target identified. So we advance our own position to beyond that.2141// Sometimes that will be the entire distance to the next symbol, and2142// sometimes it will be just a prologue and we should start2143// disassembling instructions from where it left off.2144Start += Size;2145break;2146}21472148Index = Start;2149if (SectionAddr < StartAddress)2150Index = std::max<uint64_t>(Index, StartAddress - SectionAddr);21512152if (DisassembleAsELFData) {2153dumpELFData(SectionAddr, Index, End, Bytes);2154Index = End;2155continue;2156}21572158// Skip relocations from symbols that are not dumped.2159for (; RelCur != RelEnd; ++RelCur) {2160uint64_t Offset = RelCur->getOffset() - RelAdjustment;2161if (Index <= Offset)2162break;2163}21642165bool DumpARMELFData = false;2166bool DumpTracebackTableForXCOFFFunction =2167Obj.isXCOFF() && Section.isText() && TracebackTable &&2168Symbols[SI - 1].XCOFFSymInfo.StorageMappingClass &&2169(*Symbols[SI - 1].XCOFFSymInfo.StorageMappingClass == XCOFF::XMC_PR);21702171formatted_raw_ostream FOS(outs());21722173std::unordered_map<uint64_t, std::string> AllLabels;2174std::unordered_map<uint64_t, std::vector<BBAddrMapLabel>> BBAddrMapLabels;2175if (SymbolizeOperands) {2176collectLocalBranchTargets(Bytes, DT->InstrAnalysis.get(),2177DT->DisAsm.get(), DT->InstPrinter.get(),2178PrimaryTarget.SubtargetInfo.get(),2179SectionAddr, Index, End, AllLabels);2180collectBBAddrMapLabels(FullAddrMap, SectionAddr, Index, End,2181BBAddrMapLabels);2182}21832184if (DT->InstrAnalysis)2185DT->InstrAnalysis->resetState();21862187while (Index < End) {2188uint64_t RelOffset;21892190// ARM and AArch64 ELF binaries can interleave data and text in the2191// same section. We rely on the markers introduced to understand what2192// we need to dump. If the data marker is within a function, it is2193// denoted as a word/short etc.2194if (!MappingSymbols.empty()) {2195char Kind = getMappingSymbolKind(MappingSymbols, Index);2196DumpARMELFData = Kind == 'd';2197if (SecondaryTarget) {2198if (Kind == 'a') {2199DT = PrimaryIsThumb ? &*SecondaryTarget : &PrimaryTarget;2200} else if (Kind == 't') {2201DT = PrimaryIsThumb ? &PrimaryTarget : &*SecondaryTarget;2202}2203}2204} else if (!CHPECodeMap.empty()) {2205uint64_t Address = SectionAddr + Index;2206auto It = partition_point(2207CHPECodeMap,2208[Address](const std::pair<uint64_t, uint64_t> &Entry) {2209return Entry.first <= Address;2210});2211if (It != CHPECodeMap.begin() && Address < (It - 1)->second) {2212DT = &*SecondaryTarget;2213} else {2214DT = &PrimaryTarget;2215// X64 disassembler range may have left Index unaligned, so2216// make sure that it's aligned when we switch back to ARM642217// code.2218Index = llvm::alignTo(Index, 4);2219if (Index >= End)2220break;2221}2222}22232224auto findRel = [&]() {2225while (RelCur != RelEnd) {2226RelOffset = RelCur->getOffset() - RelAdjustment;2227// If this relocation is hidden, skip it.2228if (getHidden(*RelCur) || SectionAddr + RelOffset < StartAddress) {2229++RelCur;2230continue;2231}22322233// Stop when RelCur's offset is past the disassembled2234// instruction/data.2235if (RelOffset >= Index + Size)2236return false;2237if (RelOffset >= Index)2238return true;2239++RelCur;2240}2241return false;2242};22432244if (DumpARMELFData) {2245Size = dumpARMELFData(SectionAddr, Index, End, Obj, Bytes,2246MappingSymbols, *DT->SubtargetInfo, FOS);2247} else {2248// When -z or --disassemble-zeroes are given we always dissasemble2249// them. Otherwise we might want to skip zero bytes we see.2250if (!DisassembleZeroes) {2251uint64_t MaxOffset = End - Index;2252// For --reloc: print zero blocks patched by relocations, so that2253// relocations can be shown in the dump.2254if (InlineRelocs && RelCur != RelEnd)2255MaxOffset = std::min(RelCur->getOffset() - RelAdjustment - Index,2256MaxOffset);22572258if (size_t N =2259countSkippableZeroBytes(Bytes.slice(Index, MaxOffset))) {2260FOS << "\t\t..." << '\n';2261Index += N;2262continue;2263}2264}22652266if (DumpTracebackTableForXCOFFFunction &&2267doesXCOFFTracebackTableBegin(Bytes.slice(Index, 4))) {2268dumpTracebackTable(Bytes.slice(Index),2269SectionAddr + Index + VMAAdjustment, FOS,2270SectionAddr + End + VMAAdjustment,2271*DT->SubtargetInfo, cast<XCOFFObjectFile>(&Obj));2272Index = End;2273continue;2274}22752276// Print local label if there's any.2277auto Iter1 = BBAddrMapLabels.find(SectionAddr + Index);2278if (Iter1 != BBAddrMapLabels.end()) {2279for (const auto &BBLabel : Iter1->second)2280FOS << "<" << BBLabel.BlockLabel << ">" << BBLabel.PGOAnalysis2281<< ":\n";2282} else {2283auto Iter2 = AllLabels.find(SectionAddr + Index);2284if (Iter2 != AllLabels.end())2285FOS << "<" << Iter2->second << ">:\n";2286}22872288// Disassemble a real instruction or a data when disassemble all is2289// provided2290MCInst Inst;2291ArrayRef<uint8_t> ThisBytes = Bytes.slice(Index);2292uint64_t ThisAddr = SectionAddr + Index;2293bool Disassembled = DT->DisAsm->getInstruction(2294Inst, Size, ThisBytes, ThisAddr, CommentStream);2295if (Size == 0)2296Size = std::min<uint64_t>(2297ThisBytes.size(),2298DT->DisAsm->suggestBytesToSkip(ThisBytes, ThisAddr));22992300LVP.update({Index, Section.getIndex()},2301{Index + Size, Section.getIndex()}, Index + Size != End);23022303DT->InstPrinter->setCommentStream(CommentStream);23042305DT->Printer->printInst(2306*DT->InstPrinter, Disassembled ? &Inst : nullptr,2307Bytes.slice(Index, Size),2308{SectionAddr + Index + VMAAdjustment, Section.getIndex()}, FOS,2309"", *DT->SubtargetInfo, &SP, Obj.getFileName(), &Rels, LVP);23102311DT->InstPrinter->setCommentStream(llvm::nulls());23122313// If disassembly succeeds, we try to resolve the target address2314// (jump target or memory operand address) and print it to the2315// right of the instruction.2316//2317// Otherwise, we don't print anything else so that we avoid2318// analyzing invalid or incomplete instruction information.2319if (Disassembled && DT->InstrAnalysis) {2320llvm::raw_ostream *TargetOS = &FOS;2321uint64_t Target;2322bool PrintTarget = DT->InstrAnalysis->evaluateBranch(2323Inst, SectionAddr + Index, Size, Target);23242325if (!PrintTarget) {2326if (std::optional<uint64_t> MaybeTarget =2327DT->InstrAnalysis->evaluateMemoryOperandAddress(2328Inst, DT->SubtargetInfo.get(), SectionAddr + Index,2329Size)) {2330Target = *MaybeTarget;2331PrintTarget = true;2332// Do not print real address when symbolizing.2333if (!SymbolizeOperands) {2334// Memory operand addresses are printed as comments.2335TargetOS = &CommentStream;2336*TargetOS << "0x" << Twine::utohexstr(Target);2337}2338}2339}23402341if (PrintTarget) {2342// In a relocatable object, the target's section must reside in2343// the same section as the call instruction or it is accessed2344// through a relocation.2345//2346// In a non-relocatable object, the target may be in any section.2347// In that case, locate the section(s) containing the target2348// address and find the symbol in one of those, if possible.2349//2350// N.B. Except for XCOFF, we don't walk the relocations in the2351// relocatable case yet.2352std::vector<const SectionSymbolsTy *> TargetSectionSymbols;2353if (!Obj.isRelocatableObject()) {2354auto It = llvm::partition_point(2355SectionAddresses,2356[=](const std::pair<uint64_t, SectionRef> &O) {2357return O.first <= Target;2358});2359uint64_t TargetSecAddr = 0;2360while (It != SectionAddresses.begin()) {2361--It;2362if (TargetSecAddr == 0)2363TargetSecAddr = It->first;2364if (It->first != TargetSecAddr)2365break;2366TargetSectionSymbols.push_back(&AllSymbols[It->second]);2367}2368} else {2369TargetSectionSymbols.push_back(&Symbols);2370}2371TargetSectionSymbols.push_back(&AbsoluteSymbols);23722373// Find the last symbol in the first candidate section whose2374// offset is less than or equal to the target. If there are no2375// such symbols, try in the next section and so on, before finally2376// using the nearest preceding absolute symbol (if any), if there2377// are no other valid symbols.2378const SymbolInfoTy *TargetSym = nullptr;2379for (const SectionSymbolsTy *TargetSymbols :2380TargetSectionSymbols) {2381auto It = llvm::partition_point(2382*TargetSymbols,2383[=](const SymbolInfoTy &O) { return O.Addr <= Target; });2384while (It != TargetSymbols->begin()) {2385--It;2386// Skip mapping symbols to avoid possible ambiguity as they2387// do not allow uniquely identifying the target address.2388if (!It->IsMappingSymbol) {2389TargetSym = &*It;2390break;2391}2392}2393if (TargetSym)2394break;2395}23962397// Branch targets are printed just after the instructions.2398// Print the labels corresponding to the target if there's any.2399bool BBAddrMapLabelAvailable = BBAddrMapLabels.count(Target);2400bool LabelAvailable = AllLabels.count(Target);24012402if (TargetSym != nullptr) {2403uint64_t TargetAddress = TargetSym->Addr;2404uint64_t Disp = Target - TargetAddress;2405std::string TargetName = Demangle ? demangle(TargetSym->Name)2406: TargetSym->Name.str();2407bool RelFixedUp = false;2408SmallString<32> Val;24092410*TargetOS << " <";2411// On XCOFF, we use relocations, even without -r, so we2412// can print the correct name for an extern function call.2413if (Obj.isXCOFF() && findRel()) {2414// Check for possible branch relocations and2415// branches to fixup code.2416bool BranchRelocationType = true;2417XCOFF::RelocationType RelocType;2418if (Obj.is64Bit()) {2419const XCOFFRelocation64 *Reloc =2420reinterpret_cast<XCOFFRelocation64 *>(2421RelCur->getRawDataRefImpl().p);2422RelFixedUp = Reloc->isFixupIndicated();2423RelocType = Reloc->Type;2424} else {2425const XCOFFRelocation32 *Reloc =2426reinterpret_cast<XCOFFRelocation32 *>(2427RelCur->getRawDataRefImpl().p);2428RelFixedUp = Reloc->isFixupIndicated();2429RelocType = Reloc->Type;2430}2431BranchRelocationType =2432RelocType == XCOFF::R_BA || RelocType == XCOFF::R_BR ||2433RelocType == XCOFF::R_RBA || RelocType == XCOFF::R_RBR;24342435// If we have a valid relocation, try to print its2436// corresponding symbol name. Multiple relocations on the2437// same instruction are not handled.2438// Branches to fixup code will have the RelFixedUp flag set in2439// the RLD. For these instructions, we print the correct2440// branch target, but print the referenced symbol as a2441// comment.2442if (Error E = getRelocationValueString(*RelCur, false, Val)) {2443// If -r was used, this error will be printed later.2444// Otherwise, we ignore the error and print what2445// would have been printed without using relocations.2446consumeError(std::move(E));2447*TargetOS << TargetName;2448RelFixedUp = false; // Suppress comment for RLD sym name2449} else if (BranchRelocationType && !RelFixedUp)2450*TargetOS << Val;2451else2452*TargetOS << TargetName;2453if (Disp)2454*TargetOS << "+0x" << Twine::utohexstr(Disp);2455} else if (!Disp) {2456*TargetOS << TargetName;2457} else if (BBAddrMapLabelAvailable) {2458*TargetOS << BBAddrMapLabels[Target].front().BlockLabel;2459} else if (LabelAvailable) {2460*TargetOS << AllLabels[Target];2461} else {2462// Always Print the binary symbol plus an offset if there's no2463// local label corresponding to the target address.2464*TargetOS << TargetName << "+0x" << Twine::utohexstr(Disp);2465}2466*TargetOS << ">";2467if (RelFixedUp && !InlineRelocs) {2468// We have fixup code for a relocation. We print the2469// referenced symbol as a comment.2470*TargetOS << "\t# " << Val;2471}24722473} else if (BBAddrMapLabelAvailable) {2474*TargetOS << " <" << BBAddrMapLabels[Target].front().BlockLabel2475<< ">";2476} else if (LabelAvailable) {2477*TargetOS << " <" << AllLabels[Target] << ">";2478}2479// By convention, each record in the comment stream should be2480// terminated.2481if (TargetOS == &CommentStream)2482*TargetOS << "\n";2483}24842485DT->InstrAnalysis->updateState(Inst, SectionAddr + Index);2486} else if (!Disassembled && DT->InstrAnalysis) {2487DT->InstrAnalysis->resetState();2488}2489}24902491assert(DT->Context->getAsmInfo());2492emitPostInstructionInfo(FOS, *DT->Context->getAsmInfo(),2493*DT->SubtargetInfo, CommentStream.str(), LVP);2494Comments.clear();24952496if (BTF)2497printBTFRelocation(FOS, *BTF, {Index, Section.getIndex()}, LVP);24982499// Hexagon handles relocs in pretty printer2500if (InlineRelocs && Obj.getArch() != Triple::hexagon) {2501while (findRel()) {2502// When --adjust-vma is used, update the address printed.2503if (RelCur->getSymbol() != Obj.symbol_end()) {2504Expected<section_iterator> SymSI =2505RelCur->getSymbol()->getSection();2506if (SymSI && *SymSI != Obj.section_end() &&2507shouldAdjustVA(**SymSI))2508RelOffset += AdjustVMA;2509}25102511printRelocation(FOS, Obj.getFileName(), *RelCur,2512SectionAddr + RelOffset, Is64Bits);2513LVP.printAfterOtherLine(FOS, true);2514++RelCur;2515}2516}25172518Index += Size;2519}2520}2521}2522StringSet<> MissingDisasmSymbolSet =2523set_difference(DisasmSymbolSet, FoundDisasmSymbolSet);2524for (StringRef Sym : MissingDisasmSymbolSet.keys())2525reportWarning("failed to disassemble missing symbol " + Sym, FileName);2526}25272528static void disassembleObject(ObjectFile *Obj, bool InlineRelocs) {2529// If information useful for showing the disassembly is missing, try to find a2530// more complete binary and disassemble that instead.2531OwningBinary<Binary> FetchedBinary;2532if (Obj->symbols().empty()) {2533if (std::optional<OwningBinary<Binary>> FetchedBinaryOpt =2534fetchBinaryByBuildID(*Obj)) {2535if (auto *O = dyn_cast<ObjectFile>(FetchedBinaryOpt->getBinary())) {2536if (!O->symbols().empty() ||2537(!O->sections().empty() && Obj->sections().empty())) {2538FetchedBinary = std::move(*FetchedBinaryOpt);2539Obj = O;2540}2541}2542}2543}25442545const Target *TheTarget = getTarget(Obj);25462547// Package up features to be passed to target/subtarget2548Expected<SubtargetFeatures> FeaturesValue = Obj->getFeatures();2549if (!FeaturesValue)2550reportError(FeaturesValue.takeError(), Obj->getFileName());2551SubtargetFeatures Features = *FeaturesValue;2552if (!MAttrs.empty()) {2553for (unsigned I = 0; I != MAttrs.size(); ++I)2554Features.AddFeature(MAttrs[I]);2555} else if (MCPU.empty() && Obj->getArch() == llvm::Triple::aarch64) {2556Features.AddFeature("+all");2557}25582559if (MCPU.empty())2560MCPU = Obj->tryGetCPUName().value_or("").str();25612562if (isArmElf(*Obj)) {2563// When disassembling big-endian Arm ELF, the instruction endianness is2564// determined in a complex way. In relocatable objects, AAELF32 mandates2565// that instruction endianness matches the ELF file endianness; in2566// executable images, that's true unless the file header has the EF_ARM_BE82567// flag, in which case instructions are little-endian regardless of data2568// endianness.2569//2570// We must set the big-endian-instructions SubtargetFeature to make the2571// disassembler read the instructions the right way round, and also tell2572// our own prettyprinter to retrieve the encodings the same way to print in2573// hex.2574const auto *Elf32BE = dyn_cast<ELF32BEObjectFile>(Obj);25752576if (Elf32BE && (Elf32BE->isRelocatableObject() ||2577!(Elf32BE->getPlatformFlags() & ELF::EF_ARM_BE8))) {2578Features.AddFeature("+big-endian-instructions");2579ARMPrettyPrinterInst.setInstructionEndianness(llvm::endianness::big);2580} else {2581ARMPrettyPrinterInst.setInstructionEndianness(llvm::endianness::little);2582}2583}25842585DisassemblerTarget PrimaryTarget(TheTarget, *Obj, TripleName, MCPU, Features);25862587// If we have an ARM object file, we need a second disassembler, because2588// ARM CPUs have two different instruction sets: ARM mode, and Thumb mode.2589// We use mapping symbols to switch between the two assemblers, where2590// appropriate.2591std::optional<DisassemblerTarget> SecondaryTarget;25922593if (isArmElf(*Obj)) {2594if (!PrimaryTarget.SubtargetInfo->checkFeatures("+mclass")) {2595if (PrimaryTarget.SubtargetInfo->checkFeatures("+thumb-mode"))2596Features.AddFeature("-thumb-mode");2597else2598Features.AddFeature("+thumb-mode");2599SecondaryTarget.emplace(PrimaryTarget, Features);2600}2601} else if (const auto *COFFObj = dyn_cast<COFFObjectFile>(Obj)) {2602const chpe_metadata *CHPEMetadata = COFFObj->getCHPEMetadata();2603if (CHPEMetadata && CHPEMetadata->CodeMapCount) {2604// Set up x86_64 disassembler for ARM64EC binaries.2605Triple X64Triple(TripleName);2606X64Triple.setArch(Triple::ArchType::x86_64);26072608std::string Error;2609const Target *X64Target =2610TargetRegistry::lookupTarget("", X64Triple, Error);2611if (X64Target) {2612SubtargetFeatures X64Features;2613SecondaryTarget.emplace(X64Target, *Obj, X64Triple.getTriple(), "",2614X64Features);2615} else {2616reportWarning(Error, Obj->getFileName());2617}2618}2619}26202621const ObjectFile *DbgObj = Obj;2622if (!FetchedBinary.getBinary() && !Obj->hasDebugInfo()) {2623if (std::optional<OwningBinary<Binary>> DebugBinaryOpt =2624fetchBinaryByBuildID(*Obj)) {2625if (auto *FetchedObj =2626dyn_cast<const ObjectFile>(DebugBinaryOpt->getBinary())) {2627if (FetchedObj->hasDebugInfo()) {2628FetchedBinary = std::move(*DebugBinaryOpt);2629DbgObj = FetchedObj;2630}2631}2632}2633}26342635std::unique_ptr<object::Binary> DSYMBinary;2636std::unique_ptr<MemoryBuffer> DSYMBuf;2637if (!DbgObj->hasDebugInfo()) {2638if (const MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&*Obj)) {2639DbgObj = objdump::getMachODSymObject(MachOOF, Obj->getFileName(),2640DSYMBinary, DSYMBuf);2641if (!DbgObj)2642return;2643}2644}26452646SourcePrinter SP(DbgObj, TheTarget->getName());26472648for (StringRef Opt : DisassemblerOptions)2649if (!PrimaryTarget.InstPrinter->applyTargetSpecificCLOption(Opt))2650reportError(Obj->getFileName(),2651"Unrecognized disassembler option: " + Opt);26522653disassembleObject(*Obj, *DbgObj, PrimaryTarget, SecondaryTarget, SP,2654InlineRelocs);2655}26562657void Dumper::printRelocations() {2658StringRef Fmt = O.getBytesInAddress() > 4 ? "%016" PRIx64 : "%08" PRIx64;26592660// Build a mapping from relocation target to a vector of relocation2661// sections. Usually, there is an only one relocation section for2662// each relocated section.2663MapVector<SectionRef, std::vector<SectionRef>> SecToRelSec;2664uint64_t Ndx;2665for (const SectionRef &Section : ToolSectionFilter(O, &Ndx)) {2666if (O.isELF() && (ELFSectionRef(Section).getFlags() & ELF::SHF_ALLOC))2667continue;2668if (Section.relocation_begin() == Section.relocation_end())2669continue;2670Expected<section_iterator> SecOrErr = Section.getRelocatedSection();2671if (!SecOrErr)2672reportError(O.getFileName(),2673"section (" + Twine(Ndx) +2674"): unable to get a relocation target: " +2675toString(SecOrErr.takeError()));2676SecToRelSec[**SecOrErr].push_back(Section);2677}26782679for (std::pair<SectionRef, std::vector<SectionRef>> &P : SecToRelSec) {2680StringRef SecName = unwrapOrError(P.first.getName(), O.getFileName());2681outs() << "\nRELOCATION RECORDS FOR [" << SecName << "]:\n";2682uint32_t OffsetPadding = (O.getBytesInAddress() > 4 ? 16 : 8);2683uint32_t TypePadding = 24;2684outs() << left_justify("OFFSET", OffsetPadding) << " "2685<< left_justify("TYPE", TypePadding) << " "2686<< "VALUE\n";26872688for (SectionRef Section : P.second) {2689// CREL sections require decoding, each section may have its own specific2690// decode problems.2691if (O.isELF() && ELFSectionRef(Section).getType() == ELF::SHT_CREL) {2692StringRef Err =2693cast<const ELFObjectFileBase>(O).getCrelDecodeProblem(Section);2694if (!Err.empty()) {2695reportUniqueWarning(Err);2696continue;2697}2698}2699for (const RelocationRef &Reloc : Section.relocations()) {2700uint64_t Address = Reloc.getOffset();2701SmallString<32> RelocName;2702SmallString<32> ValueStr;2703if (Address < StartAddress || Address > StopAddress || getHidden(Reloc))2704continue;2705Reloc.getTypeName(RelocName);2706if (Error E =2707getRelocationValueString(Reloc, SymbolDescription, ValueStr))2708reportUniqueWarning(std::move(E));27092710outs() << format(Fmt.data(), Address) << " "2711<< left_justify(RelocName, TypePadding) << " " << ValueStr2712<< "\n";2713}2714}2715}2716}27172718// Returns true if we need to show LMA column when dumping section headers. We2719// show it only when the platform is ELF and either we have at least one section2720// whose VMA and LMA are different and/or when --show-lma flag is used.2721static bool shouldDisplayLMA(const ObjectFile &Obj) {2722if (!Obj.isELF())2723return false;2724for (const SectionRef &S : ToolSectionFilter(Obj))2725if (S.getAddress() != getELFSectionLMA(S))2726return true;2727return ShowLMA;2728}27292730static size_t getMaxSectionNameWidth(const ObjectFile &Obj) {2731// Default column width for names is 13 even if no names are that long.2732size_t MaxWidth = 13;2733for (const SectionRef &Section : ToolSectionFilter(Obj)) {2734StringRef Name = unwrapOrError(Section.getName(), Obj.getFileName());2735MaxWidth = std::max(MaxWidth, Name.size());2736}2737return MaxWidth;2738}27392740void objdump::printSectionHeaders(ObjectFile &Obj) {2741if (Obj.isELF() && Obj.sections().empty())2742createFakeELFSections(Obj);27432744size_t NameWidth = getMaxSectionNameWidth(Obj);2745size_t AddressWidth = 2 * Obj.getBytesInAddress();2746bool HasLMAColumn = shouldDisplayLMA(Obj);2747outs() << "\nSections:\n";2748if (HasLMAColumn)2749outs() << "Idx " << left_justify("Name", NameWidth) << " Size "2750<< left_justify("VMA", AddressWidth) << " "2751<< left_justify("LMA", AddressWidth) << " Type\n";2752else2753outs() << "Idx " << left_justify("Name", NameWidth) << " Size "2754<< left_justify("VMA", AddressWidth) << " Type\n";27552756uint64_t Idx;2757for (const SectionRef &Section : ToolSectionFilter(Obj, &Idx)) {2758StringRef Name = unwrapOrError(Section.getName(), Obj.getFileName());2759uint64_t VMA = Section.getAddress();2760if (shouldAdjustVA(Section))2761VMA += AdjustVMA;27622763uint64_t Size = Section.getSize();27642765std::string Type = Section.isText() ? "TEXT" : "";2766if (Section.isData())2767Type += Type.empty() ? "DATA" : ", DATA";2768if (Section.isBSS())2769Type += Type.empty() ? "BSS" : ", BSS";2770if (Section.isDebugSection())2771Type += Type.empty() ? "DEBUG" : ", DEBUG";27722773if (HasLMAColumn)2774outs() << format("%3" PRIu64 " %-*s %08" PRIx64 " ", Idx, NameWidth,2775Name.str().c_str(), Size)2776<< format_hex_no_prefix(VMA, AddressWidth) << " "2777<< format_hex_no_prefix(getELFSectionLMA(Section), AddressWidth)2778<< " " << Type << "\n";2779else2780outs() << format("%3" PRIu64 " %-*s %08" PRIx64 " ", Idx, NameWidth,2781Name.str().c_str(), Size)2782<< format_hex_no_prefix(VMA, AddressWidth) << " " << Type << "\n";2783}2784}27852786void objdump::printSectionContents(const ObjectFile *Obj) {2787const MachOObjectFile *MachO = dyn_cast<const MachOObjectFile>(Obj);27882789for (const SectionRef &Section : ToolSectionFilter(*Obj)) {2790StringRef Name = unwrapOrError(Section.getName(), Obj->getFileName());2791uint64_t BaseAddr = Section.getAddress();2792uint64_t Size = Section.getSize();2793if (!Size)2794continue;27952796outs() << "Contents of section ";2797StringRef SegmentName = getSegmentName(MachO, Section);2798if (!SegmentName.empty())2799outs() << SegmentName << ",";2800outs() << Name << ":\n";2801if (Section.isBSS()) {2802outs() << format("<skipping contents of bss section at [%04" PRIx642803", %04" PRIx64 ")>\n",2804BaseAddr, BaseAddr + Size);2805continue;2806}28072808StringRef Contents = unwrapOrError(Section.getContents(), Obj->getFileName());28092810// Dump out the content as hex and printable ascii characters.2811for (std::size_t Addr = 0, End = Contents.size(); Addr < End; Addr += 16) {2812outs() << format(" %04" PRIx64 " ", BaseAddr + Addr);2813// Dump line of hex.2814for (std::size_t I = 0; I < 16; ++I) {2815if (I != 0 && I % 4 == 0)2816outs() << ' ';2817if (Addr + I < End)2818outs() << hexdigit((Contents[Addr + I] >> 4) & 0xF, true)2819<< hexdigit(Contents[Addr + I] & 0xF, true);2820else2821outs() << " ";2822}2823// Print ascii.2824outs() << " ";2825for (std::size_t I = 0; I < 16 && Addr + I < End; ++I) {2826if (isPrint(static_cast<unsigned char>(Contents[Addr + I]) & 0xFF))2827outs() << Contents[Addr + I];2828else2829outs() << ".";2830}2831outs() << "\n";2832}2833}2834}28352836void Dumper::printSymbolTable(StringRef ArchiveName, StringRef ArchitectureName,2837bool DumpDynamic) {2838if (O.isCOFF() && !DumpDynamic) {2839outs() << "\nSYMBOL TABLE:\n";2840printCOFFSymbolTable(cast<const COFFObjectFile>(O));2841return;2842}28432844const StringRef FileName = O.getFileName();28452846if (!DumpDynamic) {2847outs() << "\nSYMBOL TABLE:\n";2848for (auto I = O.symbol_begin(); I != O.symbol_end(); ++I)2849printSymbol(*I, {}, FileName, ArchiveName, ArchitectureName, DumpDynamic);2850return;2851}28522853outs() << "\nDYNAMIC SYMBOL TABLE:\n";2854if (!O.isELF()) {2855reportWarning(2856"this operation is not currently supported for this file format",2857FileName);2858return;2859}28602861const ELFObjectFileBase *ELF = cast<const ELFObjectFileBase>(&O);2862auto Symbols = ELF->getDynamicSymbolIterators();2863Expected<std::vector<VersionEntry>> SymbolVersionsOrErr =2864ELF->readDynsymVersions();2865if (!SymbolVersionsOrErr) {2866reportWarning(toString(SymbolVersionsOrErr.takeError()), FileName);2867SymbolVersionsOrErr = std::vector<VersionEntry>();2868(void)!SymbolVersionsOrErr;2869}2870for (auto &Sym : Symbols)2871printSymbol(Sym, *SymbolVersionsOrErr, FileName, ArchiveName,2872ArchitectureName, DumpDynamic);2873}28742875void Dumper::printSymbol(const SymbolRef &Symbol,2876ArrayRef<VersionEntry> SymbolVersions,2877StringRef FileName, StringRef ArchiveName,2878StringRef ArchitectureName, bool DumpDynamic) {2879const MachOObjectFile *MachO = dyn_cast<const MachOObjectFile>(&O);2880Expected<uint64_t> AddrOrErr = Symbol.getAddress();2881if (!AddrOrErr) {2882reportUniqueWarning(AddrOrErr.takeError());2883return;2884}2885uint64_t Address = *AddrOrErr;2886section_iterator SecI = unwrapOrError(Symbol.getSection(), FileName);2887if (SecI != O.section_end() && shouldAdjustVA(*SecI))2888Address += AdjustVMA;2889if ((Address < StartAddress) || (Address > StopAddress))2890return;2891SymbolRef::Type Type =2892unwrapOrError(Symbol.getType(), FileName, ArchiveName, ArchitectureName);2893uint32_t Flags =2894unwrapOrError(Symbol.getFlags(), FileName, ArchiveName, ArchitectureName);28952896// Don't ask a Mach-O STAB symbol for its section unless you know that2897// STAB symbol's section field refers to a valid section index. Otherwise2898// the symbol may error trying to load a section that does not exist.2899bool IsSTAB = false;2900if (MachO) {2901DataRefImpl SymDRI = Symbol.getRawDataRefImpl();2902uint8_t NType =2903(MachO->is64Bit() ? MachO->getSymbol64TableEntry(SymDRI).n_type2904: MachO->getSymbolTableEntry(SymDRI).n_type);2905if (NType & MachO::N_STAB)2906IsSTAB = true;2907}2908section_iterator Section = IsSTAB2909? O.section_end()2910: unwrapOrError(Symbol.getSection(), FileName,2911ArchiveName, ArchitectureName);29122913StringRef Name;2914if (Type == SymbolRef::ST_Debug && Section != O.section_end()) {2915if (Expected<StringRef> NameOrErr = Section->getName())2916Name = *NameOrErr;2917else2918consumeError(NameOrErr.takeError());29192920} else {2921Name = unwrapOrError(Symbol.getName(), FileName, ArchiveName,2922ArchitectureName);2923}29242925bool Global = Flags & SymbolRef::SF_Global;2926bool Weak = Flags & SymbolRef::SF_Weak;2927bool Absolute = Flags & SymbolRef::SF_Absolute;2928bool Common = Flags & SymbolRef::SF_Common;2929bool Hidden = Flags & SymbolRef::SF_Hidden;29302931char GlobLoc = ' ';2932if ((Section != O.section_end() || Absolute) && !Weak)2933GlobLoc = Global ? 'g' : 'l';2934char IFunc = ' ';2935if (O.isELF()) {2936if (ELFSymbolRef(Symbol).getELFType() == ELF::STT_GNU_IFUNC)2937IFunc = 'i';2938if (ELFSymbolRef(Symbol).getBinding() == ELF::STB_GNU_UNIQUE)2939GlobLoc = 'u';2940}29412942char Debug = ' ';2943if (DumpDynamic)2944Debug = 'D';2945else if (Type == SymbolRef::ST_Debug || Type == SymbolRef::ST_File)2946Debug = 'd';29472948char FileFunc = ' ';2949if (Type == SymbolRef::ST_File)2950FileFunc = 'f';2951else if (Type == SymbolRef::ST_Function)2952FileFunc = 'F';2953else if (Type == SymbolRef::ST_Data)2954FileFunc = 'O';29552956const char *Fmt = O.getBytesInAddress() > 4 ? "%016" PRIx64 : "%08" PRIx64;29572958outs() << format(Fmt, Address) << " "2959<< GlobLoc // Local -> 'l', Global -> 'g', Neither -> ' '2960<< (Weak ? 'w' : ' ') // Weak?2961<< ' ' // Constructor. Not supported yet.2962<< ' ' // Warning. Not supported yet.2963<< IFunc // Indirect reference to another symbol.2964<< Debug // Debugging (d) or dynamic (D) symbol.2965<< FileFunc // Name of function (F), file (f) or object (O).2966<< ' ';2967if (Absolute) {2968outs() << "*ABS*";2969} else if (Common) {2970outs() << "*COM*";2971} else if (Section == O.section_end()) {2972if (O.isXCOFF()) {2973XCOFFSymbolRef XCOFFSym = cast<const XCOFFObjectFile>(O).toSymbolRef(2974Symbol.getRawDataRefImpl());2975if (XCOFF::N_DEBUG == XCOFFSym.getSectionNumber())2976outs() << "*DEBUG*";2977else2978outs() << "*UND*";2979} else2980outs() << "*UND*";2981} else {2982StringRef SegmentName = getSegmentName(MachO, *Section);2983if (!SegmentName.empty())2984outs() << SegmentName << ",";2985StringRef SectionName = unwrapOrError(Section->getName(), FileName);2986outs() << SectionName;2987if (O.isXCOFF()) {2988std::optional<SymbolRef> SymRef =2989getXCOFFSymbolContainingSymbolRef(cast<XCOFFObjectFile>(O), Symbol);2990if (SymRef) {29912992Expected<StringRef> NameOrErr = SymRef->getName();29932994if (NameOrErr) {2995outs() << " (csect:";2996std::string SymName =2997Demangle ? demangle(*NameOrErr) : NameOrErr->str();29982999if (SymbolDescription)3000SymName = getXCOFFSymbolDescription(createSymbolInfo(O, *SymRef),3001SymName);30023003outs() << ' ' << SymName;3004outs() << ") ";3005} else3006reportWarning(toString(NameOrErr.takeError()), FileName);3007}3008}3009}30103011if (Common)3012outs() << '\t' << format(Fmt, static_cast<uint64_t>(Symbol.getAlignment()));3013else if (O.isXCOFF())3014outs() << '\t'3015<< format(Fmt, cast<XCOFFObjectFile>(O).getSymbolSize(3016Symbol.getRawDataRefImpl()));3017else if (O.isELF())3018outs() << '\t' << format(Fmt, ELFSymbolRef(Symbol).getSize());3019else if (O.isWasm())3020outs() << '\t'3021<< format(Fmt, static_cast<uint64_t>(3022cast<WasmObjectFile>(O).getSymbolSize(Symbol)));30233024if (O.isELF()) {3025if (!SymbolVersions.empty()) {3026const VersionEntry &Ver =3027SymbolVersions[Symbol.getRawDataRefImpl().d.b - 1];3028std::string Str;3029if (!Ver.Name.empty())3030Str = Ver.IsVerDef ? ' ' + Ver.Name : '(' + Ver.Name + ')';3031outs() << ' ' << left_justify(Str, 12);3032}30333034uint8_t Other = ELFSymbolRef(Symbol).getOther();3035switch (Other) {3036case ELF::STV_DEFAULT:3037break;3038case ELF::STV_INTERNAL:3039outs() << " .internal";3040break;3041case ELF::STV_HIDDEN:3042outs() << " .hidden";3043break;3044case ELF::STV_PROTECTED:3045outs() << " .protected";3046break;3047default:3048outs() << format(" 0x%02x", Other);3049break;3050}3051} else if (Hidden) {3052outs() << " .hidden";3053}30543055std::string SymName = Demangle ? demangle(Name) : Name.str();3056if (O.isXCOFF() && SymbolDescription)3057SymName = getXCOFFSymbolDescription(createSymbolInfo(O, Symbol), SymName);30583059outs() << ' ' << SymName << '\n';3060}30613062static void printUnwindInfo(const ObjectFile *O) {3063outs() << "Unwind info:\n\n";30643065if (const COFFObjectFile *Coff = dyn_cast<COFFObjectFile>(O))3066printCOFFUnwindInfo(Coff);3067else if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(O))3068printMachOUnwindInfo(MachO);3069else3070// TODO: Extract DWARF dump tool to objdump.3071WithColor::error(errs(), ToolName)3072<< "This operation is only currently supported "3073"for COFF and MachO object files.\n";3074}30753076/// Dump the raw contents of the __clangast section so the output can be piped3077/// into llvm-bcanalyzer.3078static void printRawClangAST(const ObjectFile *Obj) {3079if (outs().is_displayed()) {3080WithColor::error(errs(), ToolName)3081<< "The -raw-clang-ast option will dump the raw binary contents of "3082"the clang ast section.\n"3083"Please redirect the output to a file or another program such as "3084"llvm-bcanalyzer.\n";3085return;3086}30873088StringRef ClangASTSectionName("__clangast");3089if (Obj->isCOFF()) {3090ClangASTSectionName = "clangast";3091}30923093std::optional<object::SectionRef> ClangASTSection;3094for (auto Sec : ToolSectionFilter(*Obj)) {3095StringRef Name;3096if (Expected<StringRef> NameOrErr = Sec.getName())3097Name = *NameOrErr;3098else3099consumeError(NameOrErr.takeError());31003101if (Name == ClangASTSectionName) {3102ClangASTSection = Sec;3103break;3104}3105}3106if (!ClangASTSection)3107return;31083109StringRef ClangASTContents =3110unwrapOrError(ClangASTSection->getContents(), Obj->getFileName());3111outs().write(ClangASTContents.data(), ClangASTContents.size());3112}31133114static void printFaultMaps(const ObjectFile *Obj) {3115StringRef FaultMapSectionName;31163117if (Obj->isELF()) {3118FaultMapSectionName = ".llvm_faultmaps";3119} else if (Obj->isMachO()) {3120FaultMapSectionName = "__llvm_faultmaps";3121} else {3122WithColor::error(errs(), ToolName)3123<< "This operation is only currently supported "3124"for ELF and Mach-O executable files.\n";3125return;3126}31273128std::optional<object::SectionRef> FaultMapSection;31293130for (auto Sec : ToolSectionFilter(*Obj)) {3131StringRef Name;3132if (Expected<StringRef> NameOrErr = Sec.getName())3133Name = *NameOrErr;3134else3135consumeError(NameOrErr.takeError());31363137if (Name == FaultMapSectionName) {3138FaultMapSection = Sec;3139break;3140}3141}31423143outs() << "FaultMap table:\n";31443145if (!FaultMapSection) {3146outs() << "<not found>\n";3147return;3148}31493150StringRef FaultMapContents =3151unwrapOrError(FaultMapSection->getContents(), Obj->getFileName());3152FaultMapParser FMP(FaultMapContents.bytes_begin(),3153FaultMapContents.bytes_end());31543155outs() << FMP;3156}31573158void Dumper::printPrivateHeaders() {3159reportError(O.getFileName(), "Invalid/Unsupported object file format");3160}31613162static void printFileHeaders(const ObjectFile *O) {3163if (!O->isELF() && !O->isCOFF() && !O->isXCOFF())3164reportError(O->getFileName(), "Invalid/Unsupported object file format");31653166Triple::ArchType AT = O->getArch();3167outs() << "architecture: " << Triple::getArchTypeName(AT) << "\n";3168uint64_t Address = unwrapOrError(O->getStartAddress(), O->getFileName());31693170StringRef Fmt = O->getBytesInAddress() > 4 ? "%016" PRIx64 : "%08" PRIx64;3171outs() << "start address: "3172<< "0x" << format(Fmt.data(), Address) << "\n";3173}31743175static void printArchiveChild(StringRef Filename, const Archive::Child &C) {3176Expected<sys::fs::perms> ModeOrErr = C.getAccessMode();3177if (!ModeOrErr) {3178WithColor::error(errs(), ToolName) << "ill-formed archive entry.\n";3179consumeError(ModeOrErr.takeError());3180return;3181}3182sys::fs::perms Mode = ModeOrErr.get();3183outs() << ((Mode & sys::fs::owner_read) ? "r" : "-");3184outs() << ((Mode & sys::fs::owner_write) ? "w" : "-");3185outs() << ((Mode & sys::fs::owner_exe) ? "x" : "-");3186outs() << ((Mode & sys::fs::group_read) ? "r" : "-");3187outs() << ((Mode & sys::fs::group_write) ? "w" : "-");3188outs() << ((Mode & sys::fs::group_exe) ? "x" : "-");3189outs() << ((Mode & sys::fs::others_read) ? "r" : "-");3190outs() << ((Mode & sys::fs::others_write) ? "w" : "-");3191outs() << ((Mode & sys::fs::others_exe) ? "x" : "-");31923193outs() << " ";31943195outs() << format("%d/%d %6" PRId64 " ", unwrapOrError(C.getUID(), Filename),3196unwrapOrError(C.getGID(), Filename),3197unwrapOrError(C.getRawSize(), Filename));31983199StringRef RawLastModified = C.getRawLastModified();3200unsigned Seconds;3201if (RawLastModified.getAsInteger(10, Seconds))3202outs() << "(date: \"" << RawLastModified3203<< "\" contains non-decimal chars) ";3204else {3205// Since ctime(3) returns a 26 character string of the form:3206// "Sun Sep 16 01:03:52 1973\n\0"3207// just print 24 characters.3208time_t t = Seconds;3209outs() << format("%.24s ", ctime(&t));3210}32113212StringRef Name = "";3213Expected<StringRef> NameOrErr = C.getName();3214if (!NameOrErr) {3215consumeError(NameOrErr.takeError());3216Name = unwrapOrError(C.getRawName(), Filename);3217} else {3218Name = NameOrErr.get();3219}3220outs() << Name << "\n";3221}32223223// For ELF only now.3224static bool shouldWarnForInvalidStartStopAddress(ObjectFile *Obj) {3225if (const auto *Elf = dyn_cast<ELFObjectFileBase>(Obj)) {3226if (Elf->getEType() != ELF::ET_REL)3227return true;3228}3229return false;3230}32313232static void checkForInvalidStartStopAddress(ObjectFile *Obj,3233uint64_t Start, uint64_t Stop) {3234if (!shouldWarnForInvalidStartStopAddress(Obj))3235return;32363237for (const SectionRef &Section : Obj->sections())3238if (ELFSectionRef(Section).getFlags() & ELF::SHF_ALLOC) {3239uint64_t BaseAddr = Section.getAddress();3240uint64_t Size = Section.getSize();3241if ((Start < BaseAddr + Size) && Stop > BaseAddr)3242return;3243}32443245if (!HasStartAddressFlag)3246reportWarning("no section has address less than 0x" +3247Twine::utohexstr(Stop) + " specified by --stop-address",3248Obj->getFileName());3249else if (!HasStopAddressFlag)3250reportWarning("no section has address greater than or equal to 0x" +3251Twine::utohexstr(Start) + " specified by --start-address",3252Obj->getFileName());3253else3254reportWarning("no section overlaps the range [0x" +3255Twine::utohexstr(Start) + ",0x" + Twine::utohexstr(Stop) +3256") specified by --start-address/--stop-address",3257Obj->getFileName());3258}32593260static void dumpObject(ObjectFile *O, const Archive *A = nullptr,3261const Archive::Child *C = nullptr) {3262Expected<std::unique_ptr<Dumper>> DumperOrErr = createDumper(*O);3263if (!DumperOrErr) {3264reportError(DumperOrErr.takeError(), O->getFileName(),3265A ? A->getFileName() : "");3266return;3267}3268Dumper &D = **DumperOrErr;32693270// Avoid other output when using a raw option.3271if (!RawClangAST) {3272outs() << '\n';3273if (A)3274outs() << A->getFileName() << "(" << O->getFileName() << ")";3275else3276outs() << O->getFileName();3277outs() << ":\tfile format " << O->getFileFormatName().lower() << "\n";3278}32793280if (HasStartAddressFlag || HasStopAddressFlag)3281checkForInvalidStartStopAddress(O, StartAddress, StopAddress);32823283// TODO: Change print* free functions to Dumper member functions to utilitize3284// stateful functions like reportUniqueWarning.32853286// Note: the order here matches GNU objdump for compatability.3287StringRef ArchiveName = A ? A->getFileName() : "";3288if (ArchiveHeaders && !MachOOpt && C)3289printArchiveChild(ArchiveName, *C);3290if (FileHeaders)3291printFileHeaders(O);3292if (PrivateHeaders || FirstPrivateHeader)3293D.printPrivateHeaders();3294if (SectionHeaders)3295printSectionHeaders(*O);3296if (SymbolTable)3297D.printSymbolTable(ArchiveName);3298if (DynamicSymbolTable)3299D.printSymbolTable(ArchiveName, /*ArchitectureName=*/"",3300/*DumpDynamic=*/true);3301if (DwarfDumpType != DIDT_Null) {3302std::unique_ptr<DIContext> DICtx = DWARFContext::create(*O);3303// Dump the complete DWARF structure.3304DIDumpOptions DumpOpts;3305DumpOpts.DumpType = DwarfDumpType;3306DICtx->dump(outs(), DumpOpts);3307}3308if (Relocations && !Disassemble)3309D.printRelocations();3310if (DynamicRelocations)3311D.printDynamicRelocations();3312if (SectionContents)3313printSectionContents(O);3314if (Disassemble)3315disassembleObject(O, Relocations);3316if (UnwindInfo)3317printUnwindInfo(O);33183319// Mach-O specific options:3320if (ExportsTrie)3321printExportsTrie(O);3322if (Rebase)3323printRebaseTable(O);3324if (Bind)3325printBindTable(O);3326if (LazyBind)3327printLazyBindTable(O);3328if (WeakBind)3329printWeakBindTable(O);33303331// Other special sections:3332if (RawClangAST)3333printRawClangAST(O);3334if (FaultMapSection)3335printFaultMaps(O);3336if (Offloading)3337dumpOffloadBinary(*O);3338}33393340static void dumpObject(const COFFImportFile *I, const Archive *A,3341const Archive::Child *C = nullptr) {3342StringRef ArchiveName = A ? A->getFileName() : "";33433344// Avoid other output when using a raw option.3345if (!RawClangAST)3346outs() << '\n'3347<< ArchiveName << "(" << I->getFileName() << ")"3348<< ":\tfile format COFF-import-file"3349<< "\n\n";33503351if (ArchiveHeaders && !MachOOpt && C)3352printArchiveChild(ArchiveName, *C);3353if (SymbolTable)3354printCOFFSymbolTable(*I);3355}33563357/// Dump each object file in \a a;3358static void dumpArchive(const Archive *A) {3359Error Err = Error::success();3360unsigned I = -1;3361for (auto &C : A->children(Err)) {3362++I;3363Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();3364if (!ChildOrErr) {3365if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))3366reportError(std::move(E), getFileNameForError(C, I), A->getFileName());3367continue;3368}3369if (ObjectFile *O = dyn_cast<ObjectFile>(&*ChildOrErr.get()))3370dumpObject(O, A, &C);3371else if (COFFImportFile *I = dyn_cast<COFFImportFile>(&*ChildOrErr.get()))3372dumpObject(I, A, &C);3373else3374reportError(errorCodeToError(object_error::invalid_file_type),3375A->getFileName());3376}3377if (Err)3378reportError(std::move(Err), A->getFileName());3379}33803381/// Open file and figure out how to dump it.3382static void dumpInput(StringRef file) {3383// If we are using the Mach-O specific object file parser, then let it parse3384// the file and process the command line options. So the -arch flags can3385// be used to select specific slices, etc.3386if (MachOOpt) {3387parseInputMachO(file);3388return;3389}33903391// Attempt to open the binary.3392OwningBinary<Binary> OBinary = unwrapOrError(createBinary(file), file);3393Binary &Binary = *OBinary.getBinary();33943395if (Archive *A = dyn_cast<Archive>(&Binary))3396dumpArchive(A);3397else if (ObjectFile *O = dyn_cast<ObjectFile>(&Binary))3398dumpObject(O);3399else if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(&Binary))3400parseInputMachO(UB);3401else if (OffloadBinary *OB = dyn_cast<OffloadBinary>(&Binary))3402dumpOffloadSections(*OB);3403else3404reportError(errorCodeToError(object_error::invalid_file_type), file);3405}34063407template <typename T>3408static void parseIntArg(const llvm::opt::InputArgList &InputArgs, int ID,3409T &Value) {3410if (const opt::Arg *A = InputArgs.getLastArg(ID)) {3411StringRef V(A->getValue());3412if (!llvm::to_integer(V, Value, 0)) {3413reportCmdLineError(A->getSpelling() +3414": expected a non-negative integer, but got '" + V +3415"'");3416}3417}3418}34193420static object::BuildID parseBuildIDArg(const opt::Arg *A) {3421StringRef V(A->getValue());3422object::BuildID BID = parseBuildID(V);3423if (BID.empty())3424reportCmdLineError(A->getSpelling() + ": expected a build ID, but got '" +3425V + "'");3426return BID;3427}34283429void objdump::invalidArgValue(const opt::Arg *A) {3430reportCmdLineError("'" + StringRef(A->getValue()) +3431"' is not a valid value for '" + A->getSpelling() + "'");3432}34333434static std::vector<std::string>3435commaSeparatedValues(const llvm::opt::InputArgList &InputArgs, int ID) {3436std::vector<std::string> Values;3437for (StringRef Value : InputArgs.getAllArgValues(ID)) {3438llvm::SmallVector<StringRef, 2> SplitValues;3439llvm::SplitString(Value, SplitValues, ",");3440for (StringRef SplitValue : SplitValues)3441Values.push_back(SplitValue.str());3442}3443return Values;3444}34453446static void parseOtoolOptions(const llvm::opt::InputArgList &InputArgs) {3447MachOOpt = true;3448FullLeadingAddr = true;3449PrintImmHex = true;34503451ArchName = InputArgs.getLastArgValue(OTOOL_arch).str();3452LinkOptHints = InputArgs.hasArg(OTOOL_C);3453if (InputArgs.hasArg(OTOOL_d))3454FilterSections.push_back("__DATA,__data");3455DylibId = InputArgs.hasArg(OTOOL_D);3456UniversalHeaders = InputArgs.hasArg(OTOOL_f);3457DataInCode = InputArgs.hasArg(OTOOL_G);3458FirstPrivateHeader = InputArgs.hasArg(OTOOL_h);3459IndirectSymbols = InputArgs.hasArg(OTOOL_I);3460ShowRawInsn = InputArgs.hasArg(OTOOL_j);3461PrivateHeaders = InputArgs.hasArg(OTOOL_l);3462DylibsUsed = InputArgs.hasArg(OTOOL_L);3463MCPU = InputArgs.getLastArgValue(OTOOL_mcpu_EQ).str();3464ObjcMetaData = InputArgs.hasArg(OTOOL_o);3465DisSymName = InputArgs.getLastArgValue(OTOOL_p).str();3466InfoPlist = InputArgs.hasArg(OTOOL_P);3467Relocations = InputArgs.hasArg(OTOOL_r);3468if (const Arg *A = InputArgs.getLastArg(OTOOL_s)) {3469auto Filter = (A->getValue(0) + StringRef(",") + A->getValue(1)).str();3470FilterSections.push_back(Filter);3471}3472if (InputArgs.hasArg(OTOOL_t))3473FilterSections.push_back("__TEXT,__text");3474Verbose = InputArgs.hasArg(OTOOL_v) || InputArgs.hasArg(OTOOL_V) ||3475InputArgs.hasArg(OTOOL_o);3476SymbolicOperands = InputArgs.hasArg(OTOOL_V);3477if (InputArgs.hasArg(OTOOL_x))3478FilterSections.push_back(",__text");3479LeadingAddr = LeadingHeaders = !InputArgs.hasArg(OTOOL_X);34803481ChainedFixups = InputArgs.hasArg(OTOOL_chained_fixups);3482DyldInfo = InputArgs.hasArg(OTOOL_dyld_info);34833484InputFilenames = InputArgs.getAllArgValues(OTOOL_INPUT);3485if (InputFilenames.empty())3486reportCmdLineError("no input file");34873488for (const Arg *A : InputArgs) {3489const Option &O = A->getOption();3490if (O.getGroup().isValid() && O.getGroup().getID() == OTOOL_grp_obsolete) {3491reportCmdLineWarning(O.getPrefixedName() +3492" is obsolete and not implemented");3493}3494}3495}34963497static void parseObjdumpOptions(const llvm::opt::InputArgList &InputArgs) {3498parseIntArg(InputArgs, OBJDUMP_adjust_vma_EQ, AdjustVMA);3499AllHeaders = InputArgs.hasArg(OBJDUMP_all_headers);3500ArchName = InputArgs.getLastArgValue(OBJDUMP_arch_name_EQ).str();3501ArchiveHeaders = InputArgs.hasArg(OBJDUMP_archive_headers);3502Demangle = InputArgs.hasArg(OBJDUMP_demangle);3503Disassemble = InputArgs.hasArg(OBJDUMP_disassemble);3504DisassembleAll = InputArgs.hasArg(OBJDUMP_disassemble_all);3505SymbolDescription = InputArgs.hasArg(OBJDUMP_symbol_description);3506TracebackTable = InputArgs.hasArg(OBJDUMP_traceback_table);3507DisassembleSymbols =3508commaSeparatedValues(InputArgs, OBJDUMP_disassemble_symbols_EQ);3509DisassembleZeroes = InputArgs.hasArg(OBJDUMP_disassemble_zeroes);3510if (const opt::Arg *A = InputArgs.getLastArg(OBJDUMP_dwarf_EQ)) {3511DwarfDumpType = StringSwitch<DIDumpType>(A->getValue())3512.Case("frames", DIDT_DebugFrame)3513.Default(DIDT_Null);3514if (DwarfDumpType == DIDT_Null)3515invalidArgValue(A);3516}3517DynamicRelocations = InputArgs.hasArg(OBJDUMP_dynamic_reloc);3518FaultMapSection = InputArgs.hasArg(OBJDUMP_fault_map_section);3519Offloading = InputArgs.hasArg(OBJDUMP_offloading);3520FileHeaders = InputArgs.hasArg(OBJDUMP_file_headers);3521SectionContents = InputArgs.hasArg(OBJDUMP_full_contents);3522PrintLines = InputArgs.hasArg(OBJDUMP_line_numbers);3523InputFilenames = InputArgs.getAllArgValues(OBJDUMP_INPUT);3524MachOOpt = InputArgs.hasArg(OBJDUMP_macho);3525MCPU = InputArgs.getLastArgValue(OBJDUMP_mcpu_EQ).str();3526MAttrs = commaSeparatedValues(InputArgs, OBJDUMP_mattr_EQ);3527ShowRawInsn = !InputArgs.hasArg(OBJDUMP_no_show_raw_insn);3528LeadingAddr = !InputArgs.hasArg(OBJDUMP_no_leading_addr);3529RawClangAST = InputArgs.hasArg(OBJDUMP_raw_clang_ast);3530Relocations = InputArgs.hasArg(OBJDUMP_reloc);3531PrintImmHex =3532InputArgs.hasFlag(OBJDUMP_print_imm_hex, OBJDUMP_no_print_imm_hex, true);3533PrivateHeaders = InputArgs.hasArg(OBJDUMP_private_headers);3534FilterSections = InputArgs.getAllArgValues(OBJDUMP_section_EQ);3535SectionHeaders = InputArgs.hasArg(OBJDUMP_section_headers);3536ShowAllSymbols = InputArgs.hasArg(OBJDUMP_show_all_symbols);3537ShowLMA = InputArgs.hasArg(OBJDUMP_show_lma);3538PrintSource = InputArgs.hasArg(OBJDUMP_source);3539parseIntArg(InputArgs, OBJDUMP_start_address_EQ, StartAddress);3540HasStartAddressFlag = InputArgs.hasArg(OBJDUMP_start_address_EQ);3541parseIntArg(InputArgs, OBJDUMP_stop_address_EQ, StopAddress);3542HasStopAddressFlag = InputArgs.hasArg(OBJDUMP_stop_address_EQ);3543SymbolTable = InputArgs.hasArg(OBJDUMP_syms);3544SymbolizeOperands = InputArgs.hasArg(OBJDUMP_symbolize_operands);3545PrettyPGOAnalysisMap = InputArgs.hasArg(OBJDUMP_pretty_pgo_analysis_map);3546if (PrettyPGOAnalysisMap && !SymbolizeOperands)3547reportCmdLineWarning("--symbolize-operands must be enabled for "3548"--pretty-pgo-analysis-map to have an effect");3549DynamicSymbolTable = InputArgs.hasArg(OBJDUMP_dynamic_syms);3550TripleName = InputArgs.getLastArgValue(OBJDUMP_triple_EQ).str();3551UnwindInfo = InputArgs.hasArg(OBJDUMP_unwind_info);3552Wide = InputArgs.hasArg(OBJDUMP_wide);3553Prefix = InputArgs.getLastArgValue(OBJDUMP_prefix).str();3554parseIntArg(InputArgs, OBJDUMP_prefix_strip, PrefixStrip);3555if (const opt::Arg *A = InputArgs.getLastArg(OBJDUMP_debug_vars_EQ)) {3556DbgVariables = StringSwitch<DebugVarsFormat>(A->getValue())3557.Case("ascii", DVASCII)3558.Case("unicode", DVUnicode)3559.Default(DVInvalid);3560if (DbgVariables == DVInvalid)3561invalidArgValue(A);3562}3563if (const opt::Arg *A = InputArgs.getLastArg(OBJDUMP_disassembler_color_EQ)) {3564DisassemblyColor = StringSwitch<ColorOutput>(A->getValue())3565.Case("on", ColorOutput::Enable)3566.Case("off", ColorOutput::Disable)3567.Case("terminal", ColorOutput::Auto)3568.Default(ColorOutput::Invalid);3569if (DisassemblyColor == ColorOutput::Invalid)3570invalidArgValue(A);3571}35723573parseIntArg(InputArgs, OBJDUMP_debug_vars_indent_EQ, DbgIndent);35743575parseMachOOptions(InputArgs);35763577// Parse -M (--disassembler-options) and deprecated3578// --x86-asm-syntax={att,intel}.3579//3580// Note, for x86, the asm dialect (AssemblerDialect) is initialized when the3581// MCAsmInfo is constructed. MCInstPrinter::applyTargetSpecificCLOption is3582// called too late. For now we have to use the internal cl::opt option.3583const char *AsmSyntax = nullptr;3584for (const auto *A : InputArgs.filtered(OBJDUMP_disassembler_options_EQ,3585OBJDUMP_x86_asm_syntax_att,3586OBJDUMP_x86_asm_syntax_intel)) {3587switch (A->getOption().getID()) {3588case OBJDUMP_x86_asm_syntax_att:3589AsmSyntax = "--x86-asm-syntax=att";3590continue;3591case OBJDUMP_x86_asm_syntax_intel:3592AsmSyntax = "--x86-asm-syntax=intel";3593continue;3594}35953596SmallVector<StringRef, 2> Values;3597llvm::SplitString(A->getValue(), Values, ",");3598for (StringRef V : Values) {3599if (V == "att")3600AsmSyntax = "--x86-asm-syntax=att";3601else if (V == "intel")3602AsmSyntax = "--x86-asm-syntax=intel";3603else3604DisassemblerOptions.push_back(V.str());3605}3606}3607SmallVector<const char *> Args = {"llvm-objdump"};3608for (const opt::Arg *A : InputArgs.filtered(OBJDUMP_mllvm))3609Args.push_back(A->getValue());3610if (AsmSyntax)3611Args.push_back(AsmSyntax);3612if (Args.size() > 1)3613llvm::cl::ParseCommandLineOptions(Args.size(), Args.data());36143615// Look up any provided build IDs, then append them to the input filenames.3616for (const opt::Arg *A : InputArgs.filtered(OBJDUMP_build_id)) {3617object::BuildID BuildID = parseBuildIDArg(A);3618std::optional<std::string> Path = BIDFetcher->fetch(BuildID);3619if (!Path) {3620reportCmdLineError(A->getSpelling() + ": could not find build ID '" +3621A->getValue() + "'");3622}3623InputFilenames.push_back(std::move(*Path));3624}36253626// objdump defaults to a.out if no filenames specified.3627if (InputFilenames.empty())3628InputFilenames.push_back("a.out");3629}36303631int llvm_objdump_main(int argc, char **argv, const llvm::ToolContext &) {3632using namespace llvm;36333634ToolName = argv[0];3635std::unique_ptr<CommonOptTable> T;3636OptSpecifier Unknown, HelpFlag, HelpHiddenFlag, VersionFlag;36373638StringRef Stem = sys::path::stem(ToolName);3639auto Is = [=](StringRef Tool) {3640// We need to recognize the following filenames:3641//3642// llvm-objdump -> objdump3643// llvm-otool-10.exe -> otool3644// powerpc64-unknown-freebsd13-objdump -> objdump3645auto I = Stem.rfind_insensitive(Tool);3646return I != StringRef::npos &&3647(I + Tool.size() == Stem.size() || !isAlnum(Stem[I + Tool.size()]));3648};3649if (Is("otool")) {3650T = std::make_unique<OtoolOptTable>();3651Unknown = OTOOL_UNKNOWN;3652HelpFlag = OTOOL_help;3653HelpHiddenFlag = OTOOL_help_hidden;3654VersionFlag = OTOOL_version;3655} else {3656T = std::make_unique<ObjdumpOptTable>();3657Unknown = OBJDUMP_UNKNOWN;3658HelpFlag = OBJDUMP_help;3659HelpHiddenFlag = OBJDUMP_help_hidden;3660VersionFlag = OBJDUMP_version;3661}36623663BumpPtrAllocator A;3664StringSaver Saver(A);3665opt::InputArgList InputArgs =3666T->parseArgs(argc, argv, Unknown, Saver,3667[&](StringRef Msg) { reportCmdLineError(Msg); });36683669if (InputArgs.size() == 0 || InputArgs.hasArg(HelpFlag)) {3670T->printHelp(ToolName);3671return 0;3672}3673if (InputArgs.hasArg(HelpHiddenFlag)) {3674T->printHelp(ToolName, /*ShowHidden=*/true);3675return 0;3676}36773678// Initialize targets and assembly printers/parsers.3679InitializeAllTargetInfos();3680InitializeAllTargetMCs();3681InitializeAllDisassemblers();36823683if (InputArgs.hasArg(VersionFlag)) {3684cl::PrintVersionMessage();3685if (!Is("otool")) {3686outs() << '\n';3687TargetRegistry::printRegisteredTargetsForVersion(outs());3688}3689return 0;3690}36913692// Initialize debuginfod.3693const bool ShouldUseDebuginfodByDefault =3694InputArgs.hasArg(OBJDUMP_build_id) || canUseDebuginfod();3695std::vector<std::string> DebugFileDirectories =3696InputArgs.getAllArgValues(OBJDUMP_debug_file_directory);3697if (InputArgs.hasFlag(OBJDUMP_debuginfod, OBJDUMP_no_debuginfod,3698ShouldUseDebuginfodByDefault)) {3699HTTPClient::initialize();3700BIDFetcher =3701std::make_unique<DebuginfodFetcher>(std::move(DebugFileDirectories));3702} else {3703BIDFetcher =3704std::make_unique<BuildIDFetcher>(std::move(DebugFileDirectories));3705}37063707if (Is("otool"))3708parseOtoolOptions(InputArgs);3709else3710parseObjdumpOptions(InputArgs);37113712if (StartAddress >= StopAddress)3713reportCmdLineError("start address should be less than stop address");37143715// Removes trailing separators from prefix.3716while (!Prefix.empty() && sys::path::is_separator(Prefix.back()))3717Prefix.pop_back();37183719if (AllHeaders)3720ArchiveHeaders = FileHeaders = PrivateHeaders = Relocations =3721SectionHeaders = SymbolTable = true;37223723if (DisassembleAll || PrintSource || PrintLines || TracebackTable ||3724!DisassembleSymbols.empty())3725Disassemble = true;37263727if (!ArchiveHeaders && !Disassemble && DwarfDumpType == DIDT_Null &&3728!DynamicRelocations && !FileHeaders && !PrivateHeaders && !RawClangAST &&3729!Relocations && !SectionHeaders && !SectionContents && !SymbolTable &&3730!DynamicSymbolTable && !UnwindInfo && !FaultMapSection && !Offloading &&3731!(MachOOpt &&3732(Bind || DataInCode || ChainedFixups || DyldInfo || DylibId ||3733DylibsUsed || ExportsTrie || FirstPrivateHeader ||3734FunctionStartsType != FunctionStartsMode::None || IndirectSymbols ||3735InfoPlist || LazyBind || LinkOptHints || ObjcMetaData || Rebase ||3736Rpaths || UniversalHeaders || WeakBind || !FilterSections.empty()))) {3737T->printHelp(ToolName);3738return 2;3739}37403741DisasmSymbolSet.insert(DisassembleSymbols.begin(), DisassembleSymbols.end());37423743llvm::for_each(InputFilenames, dumpInput);37443745warnOnNoMatchForSections();37463747return EXIT_SUCCESS;3748}374937503751