aboutsummaryrefslogtreecommitdiff
path: root/llvm/tools/llvm-objdump
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2023-02-11 12:38:04 +0000
committerDimitry Andric <dim@FreeBSD.org>2023-02-11 12:38:11 +0000
commite3b557809604d036af6e00c60f012c2025b59a5e (patch)
tree8a11ba2269a3b669601e2fd41145b174008f4da8 /llvm/tools/llvm-objdump
parent08e8dd7b9db7bb4a9de26d44c1cbfd24e869c014 (diff)
Diffstat (limited to 'llvm/tools/llvm-objdump')
-rw-r--r--llvm/tools/llvm-objdump/COFFDump.cpp16
-rw-r--r--llvm/tools/llvm-objdump/ELFDump.cpp48
-rw-r--r--llvm/tools/llvm-objdump/MachODump.cpp488
-rw-r--r--llvm/tools/llvm-objdump/MachODump.h12
-rw-r--r--llvm/tools/llvm-objdump/ObjdumpOpts.td47
-rw-r--r--llvm/tools/llvm-objdump/OffloadDump.cpp72
-rw-r--r--llvm/tools/llvm-objdump/OtoolOpts.td7
-rw-r--r--llvm/tools/llvm-objdump/SourcePrinter.cpp14
-rw-r--r--llvm/tools/llvm-objdump/SourcePrinter.h1
-rw-r--r--llvm/tools/llvm-objdump/XCOFFDump.cpp18
-rw-r--r--llvm/tools/llvm-objdump/XCOFFDump.h4
-rw-r--r--llvm/tools/llvm-objdump/llvm-objdump.cpp530
-rw-r--r--llvm/tools/llvm-objdump/llvm-objdump.h6
13 files changed, 925 insertions, 338 deletions
diff --git a/llvm/tools/llvm-objdump/COFFDump.cpp b/llvm/tools/llvm-objdump/COFFDump.cpp
index e65762e02022..3bc7d3ce33b0 100644
--- a/llvm/tools/llvm-objdump/COFFDump.cpp
+++ b/llvm/tools/llvm-objdump/COFFDump.cpp
@@ -10,7 +10,7 @@
/// This file implements the COFF-specific dumper for llvm-objdump.
/// It outputs the Win64 EH data structures as plain text.
/// The encoding of the unwind codes is described in MSDN:
-/// http://msdn.microsoft.com/en-us/library/ck9asaa9.aspx
+/// https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64
///
//===----------------------------------------------------------------------===//
@@ -102,7 +102,7 @@ void COFFDumper::printPEHeader(const PEHeader &Hdr) const {
};
printU16("Magic", Hdr.Magic, "%04x");
- printOptionalEnumName(Hdr.Magic, makeArrayRef(PEHeaderMagic));
+ printOptionalEnumName(Hdr.Magic, ArrayRef(PEHeaderMagic));
outs() << '\n';
print("MajorLinkerVersion", Hdr.MajorLinkerVersion);
print("MinorLinkerVersion", Hdr.MinorLinkerVersion);
@@ -127,7 +127,7 @@ void COFFDumper::printPEHeader(const PEHeader &Hdr) const {
printU32("SizeOfHeaders", Hdr.SizeOfHeaders, "%08x\n");
printU32("CheckSum", Hdr.CheckSum, "%08x\n");
printU16("Subsystem", Hdr.Subsystem, "%08x");
- printOptionalEnumName(Hdr.Subsystem, makeArrayRef(PEWindowsSubsystem));
+ printOptionalEnumName(Hdr.Subsystem, ArrayRef(PEWindowsSubsystem));
outs() << '\n';
printU16("DllCharacteristics", Hdr.DLLCharacteristics, "%08x\n");
@@ -173,7 +173,7 @@ void COFFDumper::printPEHeader(const PEHeader &Hdr) const {
"Reserved",
};
outs() << "\nThe Data Directory\n";
- for (uint32_t I = 0; I != array_lengthof(DirName); ++I) {
+ for (uint32_t I = 0; I != std::size(DirName); ++I) {
uint32_t Addr = 0, Size = 0;
if (const data_directory *Data = Obj.getDataDirectory(I)) {
Addr = Data->RelativeVirtualAddress;
@@ -194,6 +194,8 @@ static StringRef getUnwindCodeTypeName(uint8_t Code) {
case UOP_SetFPReg: return "UOP_SetFPReg";
case UOP_SaveNonVol: return "UOP_SaveNonVol";
case UOP_SaveNonVolBig: return "UOP_SaveNonVolBig";
+ case UOP_Epilog: return "UOP_Epilog";
+ case UOP_SpareCode: return "UOP_SpareCode";
case UOP_SaveXMM128: return "UOP_SaveXMM128";
case UOP_SaveXMM128Big: return "UOP_SaveXMM128Big";
case UOP_PushMachFrame: return "UOP_PushMachFrame";
@@ -234,9 +236,11 @@ static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) {
return 1;
case UOP_SaveNonVol:
case UOP_SaveXMM128:
+ case UOP_Epilog:
return 2;
case UOP_SaveNonVolBig:
case UOP_SaveXMM128Big:
+ case UOP_SpareCode:
return 3;
case UOP_AllocLarge:
return (UnwindCode.getOpInfo() == 0) ? 2 : 3;
@@ -305,7 +309,7 @@ static void printAllUnwindCodes(ArrayRef<UnwindCode> UCs) {
<< " remaining in buffer";
return ;
}
- printUnwindCode(makeArrayRef(I, E));
+ printUnwindCode(ArrayRef(I, E));
I += UsedSlots;
}
}
@@ -651,7 +655,7 @@ static void printWin64EHUnwindInfo(const Win64EH::UnwindInfo *UI) {
if (UI->NumCodes)
outs() << " Unwind Codes:\n";
- printAllUnwindCodes(makeArrayRef(&UI->UnwindCodes[0], UI->NumCodes));
+ printAllUnwindCodes(ArrayRef(&UI->UnwindCodes[0], UI->NumCodes));
outs() << "\n";
outs().flush();
diff --git a/llvm/tools/llvm-objdump/ELFDump.cpp b/llvm/tools/llvm-objdump/ELFDump.cpp
index ca73dafe2b8e..b98b45e3015a 100644
--- a/llvm/tools/llvm-objdump/ELFDump.cpp
+++ b/llvm/tools/llvm-objdump/ELFDump.cpp
@@ -248,13 +248,16 @@ static void printProgramHeaders(const ELFFile<ELFT> &Obj, StringRef FileName) {
outs() << " NOTE ";
break;
case ELF::PT_OPENBSD_BOOTDATA:
- outs() << " OPENBSD_BOOTDATA ";
+ outs() << "OPENBSD_BOOTDATA ";
+ break;
+ case ELF::PT_OPENBSD_MUTABLE:
+ outs() << "OPENBSD_MUTABLE ";
break;
case ELF::PT_OPENBSD_RANDOMIZE:
- outs() << " OPENBSD_RANDOMIZE ";
+ outs() << "OPENBSD_RANDOMIZE ";
break;
case ELF::PT_OPENBSD_WXNEEDED:
- outs() << " OPENBSD_WXNEEDED ";
+ outs() << "OPENBSD_WXNEEDED ";
break;
case ELF::PT_PHDR:
outs() << " PHDR ";
@@ -282,27 +285,28 @@ static void printProgramHeaders(const ELFFile<ELFT> &Obj, StringRef FileName) {
}
template <class ELFT>
-static void printSymbolVersionDependency(ArrayRef<uint8_t> Contents,
- StringRef StrTab) {
+static void printSymbolVersionDependency(StringRef FileName,
+ const ELFFile<ELFT> &Obj,
+ const typename ELFT::Shdr &Sec) {
outs() << "\nVersion References:\n";
- const uint8_t *Buf = Contents.data();
- while (Buf) {
- auto *Verneed = reinterpret_cast<const typename ELFT::Verneed *>(Buf);
- outs() << " required from "
- << StringRef(StrTab.drop_front(Verneed->vn_file).data()) << ":\n";
+ auto WarningHandler = [&](const Twine &Msg) {
+ reportWarning(Msg, FileName);
+ return Error::success();
+ };
+ Expected<std::vector<VerNeed>> V =
+ Obj.getVersionDependencies(Sec, WarningHandler);
+ if (!V) {
+ reportWarning(toString(V.takeError()), FileName);
+ return;
+ }
- const uint8_t *BufAux = Buf + Verneed->vn_aux;
- while (BufAux) {
- auto *Vernaux = reinterpret_cast<const typename ELFT::Vernaux *>(BufAux);
- outs() << " "
- << format("0x%08" PRIx32 " ", (uint32_t)Vernaux->vna_hash)
- << format("0x%02" PRIx16 " ", (uint16_t)Vernaux->vna_flags)
- << format("%02" PRIu16 " ", (uint16_t)Vernaux->vna_other)
- << StringRef(StrTab.drop_front(Vernaux->vna_name).data()) << '\n';
- BufAux = Vernaux->vna_next ? BufAux + Vernaux->vna_next : nullptr;
- }
- Buf = Verneed->vn_next ? Buf + Verneed->vn_next : nullptr;
+ raw_fd_ostream &OS = outs();
+ for (const VerNeed &VN : *V) {
+ OS << " required from " << VN.File << ":\n";
+ for (const VernAux &Aux : VN.AuxV)
+ OS << format(" 0x%08x 0x%02x %02u %s\n", Aux.Hash, Aux.Flags,
+ Aux.Other, Aux.Name.c_str());
}
}
@@ -355,7 +359,7 @@ static void printSymbolVersionInfo(const ELFFile<ELFT> &Elf,
StringRef StrTab = unwrapOrError(Elf.getStringTable(*StrTabSec), FileName);
if (Shdr.sh_type == ELF::SHT_GNU_verneed)
- printSymbolVersionDependency<ELFT>(Contents, StrTab);
+ printSymbolVersionDependency<ELFT>(FileName, Elf, Shdr);
else
printSymbolVersionDefinition<ELFT>(Shdr, Contents, StrTab);
}
diff --git a/llvm/tools/llvm-objdump/MachODump.cpp b/llvm/tools/llvm-objdump/MachODump.cpp
index cdbecd5ec243..fadc8367a8c1 100644
--- a/llvm/tools/llvm-objdump/MachODump.cpp
+++ b/llvm/tools/llvm-objdump/MachODump.cpp
@@ -78,9 +78,11 @@ bool objdump::UniversalHeaders;
static bool ArchiveMemberOffsets;
bool objdump::IndirectSymbols;
bool objdump::DataInCode;
-bool objdump::FunctionStarts;
+FunctionStartsMode objdump::FunctionStartsType =
+ objdump::FunctionStartsMode::None;
bool objdump::LinkOptHints;
bool objdump::InfoPlist;
+bool objdump::ChainedFixups;
bool objdump::DyldInfo;
bool objdump::DylibsUsed;
bool objdump::DylibId;
@@ -93,6 +95,8 @@ static std::vector<std::string> ArchFlags;
static bool ArchAll = false;
static std::string ThumbTripleName;
+static StringRef ordinalName(const object::MachOObjectFile *, int);
+
void objdump::parseMachOOptions(const llvm::opt::InputArgList &InputArgs) {
FirstPrivateHeader = InputArgs.hasArg(OBJDUMP_private_header);
ExportsTrie = InputArgs.hasArg(OBJDUMP_exports_trie);
@@ -109,9 +113,18 @@ void objdump::parseMachOOptions(const llvm::opt::InputArgList &InputArgs) {
ArchiveMemberOffsets = InputArgs.hasArg(OBJDUMP_archive_member_offsets);
IndirectSymbols = InputArgs.hasArg(OBJDUMP_indirect_symbols);
DataInCode = InputArgs.hasArg(OBJDUMP_data_in_code);
- FunctionStarts = InputArgs.hasArg(OBJDUMP_function_starts);
+ if (const opt::Arg *A = InputArgs.getLastArg(OBJDUMP_function_starts_EQ)) {
+ FunctionStartsType = StringSwitch<FunctionStartsMode>(A->getValue())
+ .Case("addrs", FunctionStartsMode::Addrs)
+ .Case("names", FunctionStartsMode::Names)
+ .Case("both", FunctionStartsMode::Both)
+ .Default(FunctionStartsMode::None);
+ if (FunctionStartsType == FunctionStartsMode::None)
+ invalidArgValue(A);
+ }
LinkOptHints = InputArgs.hasArg(OBJDUMP_link_opt_hints);
InfoPlist = InputArgs.hasArg(OBJDUMP_info_plist);
+ ChainedFixups = InputArgs.hasArg(OBJDUMP_chained_fixups);
DyldInfo = InputArgs.hasArg(OBJDUMP_dyld_info);
DylibsUsed = InputArgs.hasArg(OBJDUMP_dylibs_used);
DylibId = InputArgs.hasArg(OBJDUMP_dylib_id);
@@ -242,19 +255,19 @@ static uint64_t DumpDataInCode(const uint8_t *bytes, uint64_t Length,
case MachO::DICE_KIND_DATA:
if (Length >= 4) {
if (ShowRawInsn)
- dumpBytes(makeArrayRef(bytes, 4), outs());
+ dumpBytes(ArrayRef(bytes, 4), outs());
Value = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0];
outs() << "\t.long " << Value;
Size = 4;
} else if (Length >= 2) {
if (ShowRawInsn)
- dumpBytes(makeArrayRef(bytes, 2), outs());
+ dumpBytes(ArrayRef(bytes, 2), outs());
Value = bytes[1] << 8 | bytes[0];
outs() << "\t.short " << Value;
Size = 2;
} else {
if (ShowRawInsn)
- dumpBytes(makeArrayRef(bytes, 2), outs());
+ dumpBytes(ArrayRef(bytes, 2), outs());
Value = bytes[0];
outs() << "\t.byte " << Value;
Size = 1;
@@ -266,14 +279,14 @@ static uint64_t DumpDataInCode(const uint8_t *bytes, uint64_t Length,
break;
case MachO::DICE_KIND_JUMP_TABLE8:
if (ShowRawInsn)
- dumpBytes(makeArrayRef(bytes, 1), outs());
+ dumpBytes(ArrayRef(bytes, 1), outs());
Value = bytes[0];
outs() << "\t.byte " << format("%3u", Value) << "\t@ KIND_JUMP_TABLE8\n";
Size = 1;
break;
case MachO::DICE_KIND_JUMP_TABLE16:
if (ShowRawInsn)
- dumpBytes(makeArrayRef(bytes, 2), outs());
+ dumpBytes(ArrayRef(bytes, 2), outs());
Value = bytes[1] << 8 | bytes[0];
outs() << "\t.short " << format("%5u", Value & 0xffff)
<< "\t@ KIND_JUMP_TABLE16\n";
@@ -282,7 +295,7 @@ static uint64_t DumpDataInCode(const uint8_t *bytes, uint64_t Length,
case MachO::DICE_KIND_JUMP_TABLE32:
case MachO::DICE_KIND_ABS_JUMP_TABLE32:
if (ShowRawInsn)
- dumpBytes(makeArrayRef(bytes, 4), outs());
+ dumpBytes(ArrayRef(bytes, 4), outs());
Value = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0];
outs() << "\t.long " << Value;
if (Kind == MachO::DICE_KIND_JUMP_TABLE32)
@@ -1076,12 +1089,39 @@ static void PrintFunctionStarts(MachOObjectFile *O) {
}
}
+ DenseMap<uint64_t, StringRef> SymbolNames;
+ if (FunctionStartsType == FunctionStartsMode::Names ||
+ FunctionStartsType == FunctionStartsMode::Both) {
+ for (SymbolRef Sym : O->symbols()) {
+ if (Expected<uint64_t> Addr = Sym.getAddress()) {
+ if (Expected<StringRef> Name = Sym.getName()) {
+ SymbolNames[*Addr] = *Name;
+ }
+ }
+ }
+ }
+
for (uint64_t S : FunctionStarts) {
uint64_t Addr = BaseSegmentAddress + S;
- if (O->is64Bit())
- outs() << format("%016" PRIx64, Addr) << "\n";
- else
- outs() << format("%08" PRIx32, static_cast<uint32_t>(Addr)) << "\n";
+ if (FunctionStartsType == FunctionStartsMode::Names) {
+ auto It = SymbolNames.find(Addr);
+ if (It != SymbolNames.end())
+ outs() << It->second << "\n";
+ } else {
+ if (O->is64Bit())
+ outs() << format("%016" PRIx64, Addr);
+ else
+ outs() << format("%08" PRIx32, static_cast<uint32_t>(Addr));
+
+ if (FunctionStartsType == FunctionStartsMode::Both) {
+ auto It = SymbolNames.find(Addr);
+ if (It != SymbolNames.end())
+ outs() << " " << It->second;
+ else
+ outs() << " ?";
+ }
+ outs() << "\n";
+ }
}
}
@@ -1184,18 +1224,209 @@ static void PrintLinkOptHints(MachOObjectFile *O) {
}
}
-static void printMachOChainedFixups(object::MachOObjectFile *Obj) {
- Error Err = Error::success();
- for (const object::MachOChainedFixupEntry &Entry : Obj->fixupTable(Err)) {
- (void)Entry;
+static SmallVector<std::string> GetSegmentNames(object::MachOObjectFile *O) {
+ SmallVector<std::string> Ret;
+ for (const MachOObjectFile::LoadCommandInfo &Command : O->load_commands()) {
+ if (Command.C.cmd == MachO::LC_SEGMENT) {
+ MachO::segment_command SLC = O->getSegmentLoadCommand(Command);
+ Ret.push_back(SLC.segname);
+ } else if (Command.C.cmd == MachO::LC_SEGMENT_64) {
+ MachO::segment_command_64 SLC = O->getSegment64LoadCommand(Command);
+ Ret.push_back(SLC.segname);
+ }
}
- if (Err)
- reportError(std::move(Err), Obj->getFileName());
+ return Ret;
+}
+
+static void
+PrintChainedFixupsHeader(const MachO::dyld_chained_fixups_header &H) {
+ outs() << "chained fixups header (LC_DYLD_CHAINED_FIXUPS)\n";
+ outs() << " fixups_version = " << H.fixups_version << '\n';
+ outs() << " starts_offset = " << H.starts_offset << '\n';
+ outs() << " imports_offset = " << H.imports_offset << '\n';
+ outs() << " symbols_offset = " << H.symbols_offset << '\n';
+ outs() << " imports_count = " << H.imports_count << '\n';
+
+ outs() << " imports_format = " << H.imports_format;
+ switch (H.imports_format) {
+ case llvm::MachO::DYLD_CHAINED_IMPORT:
+ outs() << " (DYLD_CHAINED_IMPORT)";
+ break;
+ case llvm::MachO::DYLD_CHAINED_IMPORT_ADDEND:
+ outs() << " (DYLD_CHAINED_IMPORT_ADDEND)";
+ break;
+ case llvm::MachO::DYLD_CHAINED_IMPORT_ADDEND64:
+ outs() << " (DYLD_CHAINED_IMPORT_ADDEND64)";
+ break;
+ }
+ outs() << '\n';
+
+ outs() << " symbols_format = " << H.symbols_format;
+ if (H.symbols_format == llvm::MachO::DYLD_CHAINED_SYMBOL_ZLIB)
+ outs() << " (zlib compressed)";
+ outs() << '\n';
+}
+
+static constexpr std::array<StringRef, 13> PointerFormats{
+ "DYLD_CHAINED_PTR_ARM64E",
+ "DYLD_CHAINED_PTR_64",
+ "DYLD_CHAINED_PTR_32",
+ "DYLD_CHAINED_PTR_32_CACHE",
+ "DYLD_CHAINED_PTR_32_FIRMWARE",
+ "DYLD_CHAINED_PTR_64_OFFSET",
+ "DYLD_CHAINED_PTR_ARM64E_KERNEL",
+ "DYLD_CHAINED_PTR_64_KERNEL_CACHE",
+ "DYLD_CHAINED_PTR_ARM64E_USERLAND",
+ "DYLD_CHAINED_PTR_ARM64E_FIRMWARE",
+ "DYLD_CHAINED_PTR_X86_64_KERNEL_CACHE",
+ "DYLD_CHAINED_PTR_ARM64E_USERLAND24",
+};
+
+static void PrintChainedFixupsSegment(const ChainedFixupsSegment &Segment,
+ StringRef SegName) {
+ outs() << "chained starts in segment " << Segment.SegIdx << " (" << SegName
+ << ")\n";
+ outs() << " size = " << Segment.Header.size << '\n';
+ outs() << " page_size = " << format("0x%0" PRIx16, Segment.Header.page_size)
+ << '\n';
+
+ outs() << " pointer_format = " << Segment.Header.pointer_format;
+ if ((Segment.Header.pointer_format - 1) <
+ MachO::DYLD_CHAINED_PTR_ARM64E_USERLAND24)
+ outs() << " (" << PointerFormats[Segment.Header.pointer_format - 1] << ")";
+ outs() << '\n';
+
+ outs() << " segment_offset = "
+ << format("0x%0" PRIx64, Segment.Header.segment_offset) << '\n';
+ outs() << " max_valid_pointer = " << Segment.Header.max_valid_pointer
+ << '\n';
+ outs() << " page_count = " << Segment.Header.page_count << '\n';
+ for (auto [Index, PageStart] : enumerate(Segment.PageStarts)) {
+ outs() << " page_start[" << Index << "] = " << PageStart;
+ // FIXME: Support DYLD_CHAINED_PTR_START_MULTI (32-bit only)
+ if (PageStart == MachO::DYLD_CHAINED_PTR_START_NONE)
+ outs() << " (DYLD_CHAINED_PTR_START_NONE)";
+ outs() << '\n';
+ }
+}
+
+static void PrintChainedFixupTarget(ChainedFixupTarget &Target, size_t Idx,
+ int Format, MachOObjectFile *O) {
+ if (Format == MachO::DYLD_CHAINED_IMPORT)
+ outs() << "dyld chained import";
+ else if (Format == MachO::DYLD_CHAINED_IMPORT_ADDEND)
+ outs() << "dyld chained import addend";
+ else if (Format == MachO::DYLD_CHAINED_IMPORT_ADDEND64)
+ outs() << "dyld chained import addend64";
+ // FIXME: otool prints the encoded value as well.
+ outs() << '[' << Idx << "]\n";
+
+ outs() << " lib_ordinal = " << Target.libOrdinal() << " ("
+ << ordinalName(O, Target.libOrdinal()) << ")\n";
+ outs() << " weak_import = " << Target.weakImport() << '\n';
+ outs() << " name_offset = " << Target.nameOffset() << " ("
+ << Target.symbolName() << ")\n";
+ if (Format != MachO::DYLD_CHAINED_IMPORT)
+ outs() << " addend = " << (int64_t)Target.addend() << '\n';
+}
+
+static void PrintChainedFixups(MachOObjectFile *O) {
+ // MachOObjectFile::getChainedFixupsHeader() reads LC_DYLD_CHAINED_FIXUPS.
+ // FIXME: Support chained fixups in __TEXT,__chain_starts section too.
+ auto ChainedFixupHeader =
+ unwrapOrError(O->getChainedFixupsHeader(), O->getFileName());
+ if (!ChainedFixupHeader)
+ return;
+
+ PrintChainedFixupsHeader(*ChainedFixupHeader);
+
+ auto [SegCount, Segments] =
+ unwrapOrError(O->getChainedFixupsSegments(), O->getFileName());
+
+ auto SegNames = GetSegmentNames(O);
+
+ size_t StartsIdx = 0;
+ outs() << "chained starts in image\n";
+ outs() << " seg_count = " << SegCount << '\n';
+ for (size_t I = 0; I < SegCount; ++I) {
+ uint64_t SegOffset = 0;
+ if (StartsIdx < Segments.size() && I == Segments[StartsIdx].SegIdx) {
+ SegOffset = Segments[StartsIdx].Offset;
+ ++StartsIdx;
+ }
+
+ outs() << " seg_offset[" << I << "] = " << SegOffset << " ("
+ << SegNames[I] << ")\n";
+ }
+
+ for (const ChainedFixupsSegment &S : Segments)
+ PrintChainedFixupsSegment(S, SegNames[S.SegIdx]);
+
+ auto FixupTargets =
+ unwrapOrError(O->getDyldChainedFixupTargets(), O->getFileName());
+
+ uint32_t ImportsFormat = ChainedFixupHeader->imports_format;
+ for (auto [Idx, Target] : enumerate(FixupTargets))
+ PrintChainedFixupTarget(Target, Idx, ImportsFormat, O);
}
static void PrintDyldInfo(MachOObjectFile *O) {
- outs() << "dyld information:" << '\n';
- printMachOChainedFixups(O);
+ Error Err = Error::success();
+
+ size_t SegmentWidth = strlen("segment");
+ size_t SectionWidth = strlen("section");
+ size_t AddressWidth = strlen("address");
+ size_t AddendWidth = strlen("addend");
+ size_t DylibWidth = strlen("dylib");
+ const size_t PointerWidth = 2 + O->getBytesInAddress() * 2;
+
+ auto HexLength = [](uint64_t Num) {
+ return Num ? (size_t)divideCeil(Log2_64(Num), 4) : 1;
+ };
+ for (const object::MachOChainedFixupEntry &Entry : O->fixupTable(Err)) {
+ SegmentWidth = std::max(SegmentWidth, Entry.segmentName().size());
+ SectionWidth = std::max(SectionWidth, Entry.sectionName().size());
+ AddressWidth = std::max(AddressWidth, HexLength(Entry.address()) + 2);
+ if (Entry.isBind()) {
+ AddendWidth = std::max(AddendWidth, HexLength(Entry.addend()) + 2);
+ DylibWidth = std::max(DylibWidth, Entry.symbolName().size());
+ }
+ }
+ // Errors will be handled when printing the table.
+ if (Err)
+ consumeError(std::move(Err));
+
+ outs() << "dyld information:\n";
+ outs() << left_justify("segment", SegmentWidth) << ' '
+ << left_justify("section", SectionWidth) << ' '
+ << left_justify("address", AddressWidth) << ' '
+ << left_justify("pointer", PointerWidth) << " type "
+ << left_justify("addend", AddendWidth) << ' '
+ << left_justify("dylib", DylibWidth) << " symbol/vm address\n";
+ for (const object::MachOChainedFixupEntry &Entry : O->fixupTable(Err)) {
+ outs() << left_justify(Entry.segmentName(), SegmentWidth) << ' '
+ << left_justify(Entry.sectionName(), SectionWidth) << ' ' << "0x"
+ << left_justify(utohexstr(Entry.address()), AddressWidth - 2) << ' '
+ << format_hex(Entry.rawValue(), PointerWidth, true) << ' ';
+ if (Entry.isBind()) {
+ outs() << "bind "
+ << "0x" << left_justify(utohexstr(Entry.addend()), AddendWidth - 2)
+ << ' ' << left_justify(ordinalName(O, Entry.ordinal()), DylibWidth)
+ << ' ' << Entry.symbolName();
+ if (Entry.flags() & MachO::BIND_SYMBOL_FLAGS_WEAK_IMPORT)
+ outs() << " (weak import)";
+ outs() << '\n';
+ } else {
+ assert(Entry.isRebase());
+ outs() << "rebase";
+ outs().indent(AddendWidth + DylibWidth + 2);
+ outs() << format("0x%" PRIX64, Entry.pointerValue()) << '\n';
+ }
+ }
+ if (Err)
+ reportError(std::move(Err), O->getFileName());
+
+ // TODO: Print opcode-based fixups if the object uses those.
}
static void PrintDylibs(MachOObjectFile *O, bool JustId) {
@@ -1916,8 +2147,9 @@ static void ProcessMachO(StringRef Name, MachOObjectFile *MachOOF,
// UniversalHeaders or ArchiveHeaders.
if (Disassemble || Relocations || PrivateHeaders || ExportsTrie || Rebase ||
Bind || SymbolTable || LazyBind || WeakBind || IndirectSymbols ||
- DataInCode || FunctionStarts || LinkOptHints || DyldInfo || DylibsUsed ||
- DylibId || Rpaths || ObjcMetaData || (!FilterSections.empty())) {
+ DataInCode || FunctionStartsType != FunctionStartsMode::None ||
+ LinkOptHints || ChainedFixups || DyldInfo || DylibsUsed || DylibId ||
+ Rpaths || ObjcMetaData || (!FilterSections.empty())) {
if (LeadingHeaders) {
outs() << Name;
if (!ArchiveMemberName.empty())
@@ -1972,7 +2204,7 @@ static void ProcessMachO(StringRef Name, MachOObjectFile *MachOOF,
PrintIndirectSymbols(MachOOF, Verbose);
if (DataInCode)
PrintDataInCodeTable(MachOOF, Verbose);
- if (FunctionStarts)
+ if (FunctionStartsType != FunctionStartsMode::None)
PrintFunctionStarts(MachOOF);
if (LinkOptHints)
PrintLinkOptHints(MachOOF);
@@ -1988,6 +2220,8 @@ static void ProcessMachO(StringRef Name, MachOObjectFile *MachOOF,
DumpInfoPlistSectionContents(FileName, MachOOF);
if (DyldInfo)
PrintDyldInfo(MachOOF);
+ if (ChainedFixups)
+ PrintChainedFixups(MachOOF);
if (DylibsUsed)
PrintDylibs(MachOOF, false);
if (DylibId)
@@ -7189,6 +7423,108 @@ static void emitComments(raw_svector_ostream &CommentStream,
CommentsToEmit.clear();
}
+const MachOObjectFile *
+objdump::getMachODSymObject(const MachOObjectFile *MachOOF, StringRef Filename,
+ std::unique_ptr<Binary> &DSYMBinary,
+ std::unique_ptr<MemoryBuffer> &DSYMBuf) {
+ const MachOObjectFile *DbgObj = MachOOF;
+ std::string DSYMPath;
+
+ // Auto-detect w/o --dsym.
+ if (DSYMFile.empty()) {
+ sys::fs::file_status DSYMStatus;
+ Twine FilenameDSYM = Filename + ".dSYM";
+ if (!status(FilenameDSYM, DSYMStatus)) {
+ if (sys::fs::is_directory(DSYMStatus)) {
+ SmallString<1024> Path;
+ FilenameDSYM.toVector(Path);
+ sys::path::append(Path, "Contents", "Resources", "DWARF",
+ sys::path::filename(Filename));
+ DSYMPath = std::string(Path);
+ } else if (sys::fs::is_regular_file(DSYMStatus)) {
+ DSYMPath = FilenameDSYM.str();
+ }
+ }
+ }
+
+ if (DSYMPath.empty() && !DSYMFile.empty()) {
+ // If DSYMPath is a .dSYM directory, append the Mach-O file.
+ if (sys::fs::is_directory(DSYMFile) &&
+ sys::path::extension(DSYMFile) == ".dSYM") {
+ SmallString<128> ShortName(sys::path::filename(DSYMFile));
+ sys::path::replace_extension(ShortName, "");
+ SmallString<1024> FullPath(DSYMFile);
+ sys::path::append(FullPath, "Contents", "Resources", "DWARF", ShortName);
+ DSYMPath = FullPath.str();
+ } else {
+ DSYMPath = DSYMFile;
+ }
+ }
+
+ if (!DSYMPath.empty()) {
+ // Load the file.
+ ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
+ MemoryBuffer::getFileOrSTDIN(DSYMPath);
+ if (std::error_code EC = BufOrErr.getError()) {
+ reportError(errorCodeToError(EC), DSYMPath);
+ return nullptr;
+ }
+
+ // We need to keep the file alive, because we're replacing DbgObj with it.
+ DSYMBuf = std::move(BufOrErr.get());
+
+ Expected<std::unique_ptr<Binary>> BinaryOrErr =
+ createBinary(DSYMBuf.get()->getMemBufferRef());
+ if (!BinaryOrErr) {
+ reportError(BinaryOrErr.takeError(), DSYMPath);
+ return nullptr;
+ }
+
+ // We need to keep the Binary alive with the buffer
+ DSYMBinary = std::move(BinaryOrErr.get());
+ if (ObjectFile *O = dyn_cast<ObjectFile>(DSYMBinary.get())) {
+ // this is a Mach-O object file, use it
+ if (MachOObjectFile *MachDSYM = dyn_cast<MachOObjectFile>(&*O)) {
+ DbgObj = MachDSYM;
+ } else {
+ WithColor::error(errs(), "llvm-objdump")
+ << DSYMPath << " is not a Mach-O file type.\n";
+ return nullptr;
+ }
+ } else if (auto *UB = dyn_cast<MachOUniversalBinary>(DSYMBinary.get())) {
+ // this is a Universal Binary, find a Mach-O for this architecture
+ uint32_t CPUType, CPUSubType;
+ const char *ArchFlag;
+ if (MachOOF->is64Bit()) {
+ const MachO::mach_header_64 H_64 = MachOOF->getHeader64();
+ CPUType = H_64.cputype;
+ CPUSubType = H_64.cpusubtype;
+ } else {
+ const MachO::mach_header H = MachOOF->getHeader();
+ CPUType = H.cputype;
+ CPUSubType = H.cpusubtype;
+ }
+ Triple T = MachOObjectFile::getArchTriple(CPUType, CPUSubType, nullptr,
+ &ArchFlag);
+ Expected<std::unique_ptr<MachOObjectFile>> MachDSYM =
+ UB->getMachOObjectForArch(ArchFlag);
+ if (!MachDSYM) {
+ reportError(MachDSYM.takeError(), DSYMPath);
+ return nullptr;
+ }
+
+ // We need to keep the Binary alive with the buffer
+ DbgObj = &*MachDSYM.get();
+ DSYMBinary = std::move(*MachDSYM);
+ } else {
+ WithColor::error(errs(), "llvm-objdump")
+ << DSYMPath << " is not a Mach-O or Universal file type.\n";
+ return nullptr;
+ }
+ }
+ return DbgObj;
+}
+
static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
StringRef DisSegName, StringRef DisSectName) {
const char *McpuDefault = nullptr;
@@ -7363,90 +7699,15 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
std::unique_ptr<Binary> DSYMBinary;
std::unique_ptr<MemoryBuffer> DSYMBuf;
if (UseDbg) {
- ObjectFile *DbgObj = MachOOF;
-
- // A separate DSym file path was specified, parse it as a macho file,
+ // If separate DSym file path was specified, parse it as a macho file,
// get the sections and supply it to the section name parsing machinery.
- if (!DSYMFile.empty()) {
- std::string DSYMPath(DSYMFile);
-
- // If DSYMPath is a .dSYM directory, append the Mach-O file.
- if (llvm::sys::fs::is_directory(DSYMPath) &&
- llvm::sys::path::extension(DSYMPath) == ".dSYM") {
- SmallString<128> ShortName(llvm::sys::path::filename(DSYMPath));
- llvm::sys::path::replace_extension(ShortName, "");
- SmallString<1024> FullPath(DSYMPath);
- llvm::sys::path::append(FullPath, "Contents", "Resources", "DWARF",
- ShortName);
- DSYMPath = std::string(FullPath.str());
- }
-
- // Load the file.
- ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
- MemoryBuffer::getFileOrSTDIN(DSYMPath);
- if (std::error_code EC = BufOrErr.getError()) {
- reportError(errorCodeToError(EC), DSYMPath);
- return;
- }
-
- // We need to keep the file alive, because we're replacing DbgObj with it.
- DSYMBuf = std::move(BufOrErr.get());
-
- Expected<std::unique_ptr<Binary>> BinaryOrErr =
- createBinary(DSYMBuf.get()->getMemBufferRef());
- if (!BinaryOrErr) {
- reportError(BinaryOrErr.takeError(), DSYMPath);
- return;
- }
-
- // We need to keep the Binary alive with the buffer
- DSYMBinary = std::move(BinaryOrErr.get());
- if (ObjectFile *O = dyn_cast<ObjectFile>(DSYMBinary.get())) {
- // this is a Mach-O object file, use it
- if (MachOObjectFile *MachDSYM = dyn_cast<MachOObjectFile>(&*O)) {
- DbgObj = MachDSYM;
- }
- else {
- WithColor::error(errs(), "llvm-objdump")
- << DSYMPath << " is not a Mach-O file type.\n";
- return;
- }
- }
- else if (auto UB = dyn_cast<MachOUniversalBinary>(DSYMBinary.get())){
- // this is a Universal Binary, find a Mach-O for this architecture
- uint32_t CPUType, CPUSubType;
- const char *ArchFlag;
- if (MachOOF->is64Bit()) {
- const MachO::mach_header_64 H_64 = MachOOF->getHeader64();
- CPUType = H_64.cputype;
- CPUSubType = H_64.cpusubtype;
- } else {
- const MachO::mach_header H = MachOOF->getHeader();
- CPUType = H.cputype;
- CPUSubType = H.cpusubtype;
- }
- Triple T = MachOObjectFile::getArchTriple(CPUType, CPUSubType, nullptr,
- &ArchFlag);
- Expected<std::unique_ptr<MachOObjectFile>> MachDSYM =
- UB->getMachOObjectForArch(ArchFlag);
- if (!MachDSYM) {
- reportError(MachDSYM.takeError(), DSYMPath);
- return;
- }
-
- // We need to keep the Binary alive with the buffer
- DbgObj = &*MachDSYM.get();
- DSYMBinary = std::move(*MachDSYM);
- }
- else {
- WithColor::error(errs(), "llvm-objdump")
- << DSYMPath << " is not a Mach-O or Universal file type.\n";
- return;
- }
+ if (const ObjectFile *DbgObj =
+ getMachODSymObject(MachOOF, Filename, DSYMBinary, DSYMBuf)) {
+ // Setup the DIContext
+ diContext = DWARFContext::create(*DbgObj);
+ } else {
+ return;
}
-
- // Setup the DIContext
- diContext = DWARFContext::create(*DbgObj);
}
if (FilterSections.empty())
@@ -7655,7 +7916,7 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
Annotations);
if (gotInst) {
if (ShowRawInsn || Arch == Triple::arm) {
- dumpBytes(makeArrayRef(Bytes.data() + Index, Size), outs());
+ dumpBytes(ArrayRef(Bytes.data() + Index, Size), outs());
}
formatted_raw_ostream FormattedOS(outs());
StringRef AnnotationsStr = Annotations.str();
@@ -7736,7 +7997,7 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
}
if (ShowRawInsn || Arch == Triple::arm) {
outs() << "\t";
- dumpBytes(makeArrayRef(Bytes.data() + Index, InstSize), outs());
+ dumpBytes(ArrayRef(Bytes.data() + Index, InstSize), outs());
}
StringRef AnnotationsStr = Annotations.str();
IP->printInst(&Inst, PC, AnnotationsStr, *STI, outs());
@@ -8445,6 +8706,9 @@ static void PrintMachHeader(uint32_t magic, uint32_t cputype,
case MachO::MH_KEXT_BUNDLE:
outs() << " KEXTBUNDLE";
break;
+ case MachO::MH_FILESET:
+ outs() << " FILESET";
+ break;
default:
outs() << format(" %10u", filetype);
break;
@@ -8657,6 +8921,12 @@ static void PrintSegmentCommand(uint32_t cmd, uint32_t cmdsize,
outs() << " PROTECTED_VERSION_1";
flags &= ~MachO::SG_PROTECTED_VERSION_1;
}
+ if (flags & MachO::SG_READ_ONLY) {
+ // Apple's otool prints the SG_ prefix for this flag, but not for the
+ // others.
+ outs() << " SG_READ_ONLY";
+ flags &= ~MachO::SG_READ_ONLY;
+ }
if (flags)
outs() << format(" 0x%08" PRIx32, flags) << " (unknown flags)\n";
else
@@ -8754,6 +9024,8 @@ static void PrintSection(const char *sectname, const char *segname,
outs() << " S_THREAD_LOCAL_VARIABLE_POINTERS\n";
else if (section_type == MachO::S_THREAD_LOCAL_INIT_FUNCTION_POINTERS)
outs() << " S_THREAD_LOCAL_INIT_FUNCTION_POINTERS\n";
+ else if (section_type == MachO::S_INIT_FUNC_OFFSETS)
+ outs() << " S_INIT_FUNC_OFFSETS\n";
else
outs() << format("0x%08" PRIx32, section_type) << "\n";
outs() << "attributes";
@@ -10381,6 +10653,8 @@ static StringRef ordinalName(const object::MachOObjectFile *Obj, int Ordinal) {
return "main-executable";
case MachO::BIND_SPECIAL_DYLIB_FLAT_LOOKUP:
return "flat-namespace";
+ case MachO::BIND_SPECIAL_DYLIB_WEAK_LOOKUP:
+ return "weak";
default:
if (Ordinal > 0) {
std::error_code EC =
diff --git a/llvm/tools/llvm-objdump/MachODump.h b/llvm/tools/llvm-objdump/MachODump.h
index 12783e15b425..d9d3a70663f6 100644
--- a/llvm/tools/llvm-objdump/MachODump.h
+++ b/llvm/tools/llvm-objdump/MachODump.h
@@ -16,12 +16,14 @@ namespace llvm {
class Error;
class StringRef;
+class MemoryBuffer;
namespace object {
class MachOObjectFile;
class MachOUniversalBinary;
class ObjectFile;
class RelocationRef;
+class Binary;
} // namespace object
namespace opt {
@@ -32,17 +34,20 @@ namespace objdump {
void parseMachOOptions(const llvm::opt::InputArgList &InputArgs);
+enum class FunctionStartsMode { Addrs, Names, Both, None };
+
// MachO specific options
extern bool Bind;
extern bool DataInCode;
extern std::string DisSymName;
+extern bool ChainedFixups;
extern bool DyldInfo;
extern bool DylibId;
extern bool DylibsUsed;
extern bool ExportsTrie;
extern bool FirstPrivateHeader;
extern bool FullLeadingAddr;
-extern bool FunctionStarts;
+extern FunctionStartsMode FunctionStartsType;
extern bool IndirectSymbols;
extern bool InfoPlist;
extern bool LazyBind;
@@ -60,6 +65,11 @@ Error getMachORelocationValueString(const object::MachOObjectFile *Obj,
const object::RelocationRef &RelRef,
llvm::SmallVectorImpl<char> &Result);
+const object::MachOObjectFile *
+getMachODSymObject(const object::MachOObjectFile *O, StringRef Filename,
+ std::unique_ptr<object::Binary> &DSYMBinary,
+ std::unique_ptr<MemoryBuffer> &DSYMBuf);
+
void parseInputMachO(StringRef Filename);
void parseInputMachO(object::MachOUniversalBinary *UB);
diff --git a/llvm/tools/llvm-objdump/ObjdumpOpts.td b/llvm/tools/llvm-objdump/ObjdumpOpts.td
index 00d7d8ccff17..de7f883d24a8 100644
--- a/llvm/tools/llvm-objdump/ObjdumpOpts.td
+++ b/llvm/tools/llvm-objdump/ObjdumpOpts.td
@@ -1,5 +1,10 @@
include "llvm/Option/OptParser.td"
+multiclass B<string name, string help1, string help2> {
+ def NAME: Flag<["--"], name>, HelpText<help1>;
+ def no_ # NAME: Flag<["--"], "no-" # name>, HelpText<help2>;
+}
+
multiclass Eq<string name, string help> {
def NAME : Separate<["--"], name>;
def NAME #_eq : Joined<["--"], name #"=">,
@@ -33,12 +38,22 @@ def arch_name_EQ : Joined<["--"], "arch-name=">,
def archive_headers : Flag<["--"], "archive-headers">,
HelpText<"Display archive header information">;
+defm build_id :
+ Eq<"build-id", "Build ID to look up. Once found, added as an input file">,
+ MetaVarName<"<hex>">;
+
def : Flag<["-"], "a">, Alias<archive_headers>,
HelpText<"Alias for --archive-headers">;
def demangle : Flag<["--"], "demangle">, HelpText<"Demangle symbol names">;
def : Flag<["-"], "C">, Alias<demangle>, HelpText<"Alias for --demangle">;
+defm debug_file_directory :
+ Eq<"debug-file-directory", "Path to directory where to look for debug files">,
+ MetaVarName<"<dir>">;
+
+defm debuginfod : B<"debuginfod", "Use debuginfod to find debug files", "Don't use debuginfod to find debug files">;
+
def disassemble : Flag<["--"], "disassemble">,
HelpText<"Disassemble all executable sections found in the input files">;
def : Flag<["-"], "d">, Alias<disassemble>, HelpText<"Alias for --disassemble">;
@@ -118,7 +133,9 @@ def no_show_raw_insn : Flag<["--"], "no-show-raw-insn">,
"do not print the instruction bytes.">;
def no_leading_addr : Flag<["--"], "no-leading-addr">,
- HelpText<"When disassembling, do not print leading addresses">;
+ HelpText<"When disassembling, do not print leading addresses for instructions or inline relocations">;
+def : Flag<["--"], "no-addresses">, Alias<no_leading_addr>,
+ HelpText<"Alias for --no-leading-addr">;
def raw_clang_ast : Flag<["--"], "raw-clang-ast">,
HelpText<"Dump the raw binary contents of the clang AST section">;
@@ -153,6 +170,10 @@ def : Flag<["--"], "headers">, Alias<section_headers>,
def : Flag<["-"], "h">, Alias<section_headers>,
HelpText<"Alias for --section-headers">;
+def show_all_symbols : Flag<["--"], "show-all-symbols">,
+ HelpText<"Show all symbols during disassembly, even if multiple "
+ "symbols are defined at the same location">;
+
def show_lma : Flag<["--"], "show-lma">,
HelpText<"Display LMA column when dumping ELF section headers">;
@@ -284,11 +305,15 @@ def data_in_code : Flag<["--"], "data-in-code">,
HelpText<"Print the data in code table for Mach-O objects (requires --macho)">,
Group<grp_mach_o>;
-def function_starts : Flag<["--"], "function-starts">,
- HelpText<"Print the function starts table for "
- "Mach-O objects (requires --macho)">,
+def function_starts_EQ : Joined<["--"], "function-starts=">,
+ HelpText<"Print the function starts table for Mach-O objects. "
+ "Options: addrs (default), names, both (requires --macho)">,
+ Values<"addrs,names,both">,
Group<grp_mach_o>;
+def : Flag<["--"], "function-starts">, Alias<function_starts_EQ>,
+ AliasArgs<["addrs"]>, Group<grp_mach_o>;
+
def link_opt_hints : Flag<["--"], "link-opt-hints">,
HelpText<"Print the linker optimization hints for "
"Mach-O objects (requires --macho)">,
@@ -299,11 +324,15 @@ def info_plist : Flag<["--"], "info-plist">,
"Mach-O objects (requires --macho)">,
Group<grp_mach_o>;
-def dyld_info : Flag<["--"], "dyld_info">,
- HelpText<"Print bind and rebase information used by dyld to resolve "
- "external references in a final linked binary "
- "(requires --macho)">,
- Group<grp_mach_o>;
+def chained_fixups : Flag<["--"], "chained-fixups">,
+ HelpText<"Print chained fixup information (requires --macho)">,
+ Group<grp_mach_o>;
+
+def dyld_info : Flag<["--"], "dyld-info">,
+ HelpText<"Print bind and rebase information used by dyld to resolve "
+ "external references in a final linked binary "
+ "(requires --macho)">,
+ Group<grp_mach_o>;
def dylibs_used : Flag<["--"], "dylibs-used">,
HelpText<"Print the shared libraries used for linked "
diff --git a/llvm/tools/llvm-objdump/OffloadDump.cpp b/llvm/tools/llvm-objdump/OffloadDump.cpp
index 46334c249070..4ac6b99e79bb 100644
--- a/llvm/tools/llvm-objdump/OffloadDump.cpp
+++ b/llvm/tools/llvm-objdump/OffloadDump.cpp
@@ -10,6 +10,7 @@
/// This file implements the offloading-specific dumper for llvm-objdump.
///
//===----------------------------------------------------------------------===//
+
#include "OffloadDump.h"
#include "llvm-objdump.h"
#include "llvm/Object/ELFObjectFile.h"
@@ -46,67 +47,34 @@ static void printBinary(const OffloadBinary &OB, uint64_t Index) {
<< getOffloadKindName(OB.getOffloadKind()) << "\n";
}
-static Error visitAllBinaries(const OffloadBinary &OB) {
- uint64_t Offset = 0;
- uint64_t Index = 0;
- while (Offset < OB.getMemoryBufferRef().getBufferSize()) {
- MemoryBufferRef Buffer =
- MemoryBufferRef(OB.getData().drop_front(Offset), OB.getFileName());
- auto BinaryOrErr = OffloadBinary::create(Buffer);
- if (!BinaryOrErr)
- return BinaryOrErr.takeError();
-
- OffloadBinary &Binary = **BinaryOrErr;
- printBinary(Binary, Index++);
-
- Offset += Binary.getSize();
- }
- return Error::success();
-}
-
/// Print the embedded offloading contents of an ObjectFile \p O.
void llvm::dumpOffloadBinary(const ObjectFile &O) {
- if (!O.isELF()) {
- reportWarning("--offloading is currently only supported for ELF targets",
- O.getFileName());
+ if (!O.isELF() && !O.isCOFF()) {
+ reportWarning(
+ "--offloading is currently only supported for COFF and ELF targets",
+ O.getFileName());
return;
}
- for (ELFSectionRef Sec : O.sections()) {
- if (Sec.getType() != ELF::SHT_LLVM_OFFLOADING)
- continue;
-
- Expected<StringRef> Contents = Sec.getContents();
- if (!Contents)
- reportError(Contents.takeError(), O.getFileName());
-
- std::unique_ptr<MemoryBuffer> Buffer =
- MemoryBuffer::getMemBuffer(*Contents, O.getFileName(), false);
- if (!isAddrAligned(Align(OffloadBinary::getAlignment()),
- Buffer->getBufferStart()))
- Buffer = MemoryBuffer::getMemBufferCopy(Buffer->getBuffer(),
- Buffer->getBufferIdentifier());
- auto BinaryOrErr = OffloadBinary::create(*Buffer);
- if (!BinaryOrErr)
- reportError(O.getFileName(), "while extracting offloading files: " +
- toString(BinaryOrErr.takeError()));
- OffloadBinary &Binary = **BinaryOrErr;
+ SmallVector<OffloadFile> Binaries;
+ if (Error Err = extractOffloadBinaries(O.getMemoryBufferRef(), Binaries))
+ reportError(O.getFileName(), "while extracting offloading files: " +
+ toString(std::move(Err)));
- // Print out all the binaries that are contained in this buffer. If we fail
- // to parse a binary before reaching the end of the buffer emit a warning.
- if (Error Err = visitAllBinaries(Binary))
- reportWarning("while parsing offloading files: " +
- toString(std::move(Err)),
- O.getFileName());
- }
+ // Print out all the binaries that are contained in this buffer.
+ for (uint64_t I = 0, E = Binaries.size(); I != E; ++I)
+ printBinary(*Binaries[I].getBinary(), I);
}
/// Print the contents of an offload binary file \p OB. This may contain
/// multiple binaries stored in the same buffer.
void llvm::dumpOffloadSections(const OffloadBinary &OB) {
- // Print out all the binaries that are contained at this buffer. If we fail to
- // parse a binary before reaching the end of the buffer emit a warning.
- if (Error Err = visitAllBinaries(OB))
- reportWarning("while parsing offloading files: " + toString(std::move(Err)),
- OB.getFileName());
+ SmallVector<OffloadFile> Binaries;
+ if (Error Err = extractOffloadBinaries(OB.getMemoryBufferRef(), Binaries))
+ reportError(OB.getFileName(), "while extracting offloading files: " +
+ toString(std::move(Err)));
+
+ // Print out all the binaries that are contained in this buffer.
+ for (uint64_t I = 0, E = Binaries.size(); I != E; ++I)
+ printBinary(*Binaries[I].getBinary(), I);
}
diff --git a/llvm/tools/llvm-objdump/OtoolOpts.td b/llvm/tools/llvm-objdump/OtoolOpts.td
index e8bef284c0e9..dc7a5b445cff 100644
--- a/llvm/tools/llvm-objdump/OtoolOpts.td
+++ b/llvm/tools/llvm-objdump/OtoolOpts.td
@@ -37,13 +37,16 @@ def V : Flag<["-"], "V">,
def x : Flag<["-"], "x">, HelpText<"print all text sections">;
def X : Flag<["-"], "X">, HelpText<"omit leading addresses or headers">;
+def chained_fixups : Flag<["-"], "chained_fixups">,
+ HelpText<"print chained fixup information">;
+def dyld_info : Flag<["-"], "dyld_info">,
+ HelpText<"print bind and rebase information">;
+
// Not (yet?) implemented:
// def a : Flag<["-"], "a">, HelpText<"print archive header">;
// -c print argument strings of a core file
// -m don't use archive(member) syntax
-// -dyld_info
// -dyld_opcodes
-// -chained_fixups
// -addr_slide=arg
// -function_offsets
diff --git a/llvm/tools/llvm-objdump/SourcePrinter.cpp b/llvm/tools/llvm-objdump/SourcePrinter.cpp
index c8ea6b543245..6736cbc9ad5f 100644
--- a/llvm/tools/llvm-objdump/SourcePrinter.cpp
+++ b/llvm/tools/llvm-objdump/SourcePrinter.cpp
@@ -31,7 +31,7 @@ unsigned getInstStartColumn(const MCSubtargetInfo &STI) {
}
bool LiveVariable::liveAtAddress(object::SectionedAddress Addr) {
- if (LocExpr.Range == None)
+ if (LocExpr.Range == std::nullopt)
return false;
return LocExpr.Range->SectionIndex == Addr.SectionIndex &&
LocExpr.Range->LowPC <= Addr.Address &&
@@ -42,7 +42,17 @@ void LiveVariable::print(raw_ostream &OS, const MCRegisterInfo &MRI) const {
DataExtractor Data({LocExpr.Expr.data(), LocExpr.Expr.size()},
Unit->getContext().isLittleEndian(), 0);
DWARFExpression Expression(Data, Unit->getAddressByteSize());
- Expression.printCompact(OS, MRI);
+
+ auto GetRegName = [&MRI, &OS](uint64_t DwarfRegNum, bool IsEH) -> StringRef {
+ if (std::optional<unsigned> LLVMRegNum =
+ MRI.getLLVMRegNum(DwarfRegNum, IsEH))
+ if (const char *RegName = MRI.getName(*LLVMRegNum))
+ return StringRef(RegName);
+ OS << "<unknown register " << DwarfRegNum << ">";
+ return {};
+ };
+
+ Expression.printCompact(OS, GetRegName);
}
void LiveVariablePrinter::addVariable(DWARFDie FuncDie, DWARFDie VarDie) {
diff --git a/llvm/tools/llvm-objdump/SourcePrinter.h b/llvm/tools/llvm-objdump/SourcePrinter.h
index 29ef19c98c80..6209bb0e43e4 100644
--- a/llvm/tools/llvm-objdump/SourcePrinter.h
+++ b/llvm/tools/llvm-objdump/SourcePrinter.h
@@ -13,6 +13,7 @@
#include "llvm/ADT/StringSet.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/Symbolize/Symbolize.h"
+#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/Support/FormattedStream.h"
#include <unordered_map>
diff --git a/llvm/tools/llvm-objdump/XCOFFDump.cpp b/llvm/tools/llvm-objdump/XCOFFDump.cpp
index dd1570e1736c..7171e2eb6eb3 100644
--- a/llvm/tools/llvm-objdump/XCOFFDump.cpp
+++ b/llvm/tools/llvm-objdump/XCOFFDump.cpp
@@ -43,31 +43,31 @@ Error objdump::getXCOFFRelocationValueString(const XCOFFObjectFile &Obj,
return Error::success();
}
-Optional<XCOFF::StorageMappingClass>
+std::optional<XCOFF::StorageMappingClass>
objdump::getXCOFFSymbolCsectSMC(const XCOFFObjectFile &Obj,
const SymbolRef &Sym) {
const XCOFFSymbolRef SymRef = Obj.toSymbolRef(Sym.getRawDataRefImpl());
if (!SymRef.isCsectSymbol())
- return None;
+ return std::nullopt;
auto CsectAuxEntOrErr = SymRef.getXCOFFCsectAuxRef();
if (!CsectAuxEntOrErr)
- return None;
+ return std::nullopt;
return CsectAuxEntOrErr.get().getStorageMappingClass();
}
-Optional<object::SymbolRef>
+std::optional<object::SymbolRef>
objdump::getXCOFFSymbolContainingSymbolRef(const XCOFFObjectFile &Obj,
const SymbolRef &Sym) {
const XCOFFSymbolRef SymRef = Obj.toSymbolRef(Sym.getRawDataRefImpl());
if (!SymRef.isCsectSymbol())
- return None;
+ return std::nullopt;
Expected<XCOFFCsectAuxRef> CsectAuxEntOrErr = SymRef.getXCOFFCsectAuxRef();
if (!CsectAuxEntOrErr || !CsectAuxEntOrErr.get().isLabel())
- return None;
+ return std::nullopt;
uint32_t Idx =
static_cast<uint32_t>(CsectAuxEntOrErr.get().getSectionOrLength());
DataRefImpl DRI;
@@ -94,9 +94,9 @@ std::string objdump::getXCOFFSymbolDescription(const SymbolInfoTy &SymbolInfo,
std::string Result;
// Dummy symbols have no symbol index.
if (SymbolInfo.XCOFFSymInfo.Index)
- Result = ("(idx: " + Twine(SymbolInfo.XCOFFSymInfo.Index.value()) + ") " +
- SymbolName)
- .str();
+ Result =
+ ("(idx: " + Twine(*SymbolInfo.XCOFFSymInfo.Index) + ") " + SymbolName)
+ .str();
else
Result.append(SymbolName.begin(), SymbolName.end());
diff --git a/llvm/tools/llvm-objdump/XCOFFDump.h b/llvm/tools/llvm-objdump/XCOFFDump.h
index 461605940946..35d1c0f1ebbe 100644
--- a/llvm/tools/llvm-objdump/XCOFFDump.h
+++ b/llvm/tools/llvm-objdump/XCOFFDump.h
@@ -16,11 +16,11 @@ namespace llvm {
struct SymbolInfoTy;
namespace objdump {
-Optional<XCOFF::StorageMappingClass>
+std::optional<XCOFF::StorageMappingClass>
getXCOFFSymbolCsectSMC(const object::XCOFFObjectFile &Obj,
const object::SymbolRef &Sym);
-Optional<object::SymbolRef>
+std::optional<object::SymbolRef>
getXCOFFSymbolContainingSymbolRef(const object::XCOFFObjectFile &Obj,
const object::SymbolRef &Sym);
diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp
index fd83dc197fe9..930b132533cd 100644
--- a/llvm/tools/llvm-objdump/llvm-objdump.cpp
+++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp
@@ -25,7 +25,6 @@
#include "WasmDump.h"
#include "XCOFFDump.h"
#include "llvm/ADT/IndexedMap.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SetOperations.h"
#include "llvm/ADT/SmallSet.h"
@@ -36,6 +35,9 @@
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/Symbolize/SymbolizableModule.h"
#include "llvm/DebugInfo/Symbolize/Symbolize.h"
+#include "llvm/Debuginfod/BuildIDFetcher.h"
+#include "llvm/Debuginfod/Debuginfod.h"
+#include "llvm/Debuginfod/HTTPClient.h"
#include "llvm/Demangle/Demangle.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
@@ -51,6 +53,7 @@
#include "llvm/MC/MCTargetOptions.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Object/Archive.h"
+#include "llvm/Object/BuildID.h"
#include "llvm/Object/COFF.h"
#include "llvm/Object/COFFImportFile.h"
#include "llvm/Object/ELFObjectFile.h"
@@ -82,6 +85,7 @@
#include <algorithm>
#include <cctype>
#include <cstring>
+#include <optional>
#include <system_error>
#include <unordered_map>
#include <utility>
@@ -93,18 +97,19 @@ using namespace llvm::opt;
namespace {
-class CommonOptTable : public opt::OptTable {
+class CommonOptTable : public opt::GenericOptTable {
public:
CommonOptTable(ArrayRef<Info> OptionInfos, const char *Usage,
const char *Description)
- : OptTable(OptionInfos), Usage(Usage), Description(Description) {
+ : opt::GenericOptTable(OptionInfos), Usage(Usage),
+ Description(Description) {
setGroupedShortOptions(true);
}
void printHelp(StringRef Argv0, bool ShowHidden = false) const {
Argv0 = sys::path::filename(Argv0);
- opt::OptTable::printHelp(outs(), (Argv0 + Usage).str().c_str(), Description,
- ShowHidden, ShowHidden);
+ opt::GenericOptTable::printHelp(outs(), (Argv0 + Usage).str().c_str(),
+ Description, ShowHidden, ShowHidden);
// TODO Replace this with OptTable API once it adds extrahelp support.
outs() << "\nPass @FILE as argument to read options from FILE.\n";
}
@@ -115,28 +120,31 @@ private:
};
// ObjdumpOptID is in ObjdumpOptID.h
-
-#define PREFIX(NAME, VALUE) const char *const OBJDUMP_##NAME[] = VALUE;
+namespace objdump_opt {
+#define PREFIX(NAME, VALUE) \
+ static constexpr StringLiteral NAME##_init[] = VALUE; \
+ static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \
+ std::size(NAME##_init) - 1);
#include "ObjdumpOpts.inc"
#undef PREFIX
static constexpr opt::OptTable::Info ObjdumpInfoTable[] = {
-#define OBJDUMP_nullptr nullptr
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR, VALUES) \
- {OBJDUMP_##PREFIX, NAME, HELPTEXT, \
- METAVAR, OBJDUMP_##ID, opt::Option::KIND##Class, \
- PARAM, FLAGS, OBJDUMP_##GROUP, \
- OBJDUMP_##ALIAS, ALIASARGS, VALUES},
+ {PREFIX, NAME, HELPTEXT, \
+ METAVAR, OBJDUMP_##ID, opt::Option::KIND##Class, \
+ PARAM, FLAGS, OBJDUMP_##GROUP, \
+ OBJDUMP_##ALIAS, ALIASARGS, VALUES},
#include "ObjdumpOpts.inc"
#undef OPTION
-#undef OBJDUMP_nullptr
};
+} // namespace objdump_opt
class ObjdumpOptTable : public CommonOptTable {
public:
ObjdumpOptTable()
- : CommonOptTable(ObjdumpInfoTable, " [options] <input object files>",
+ : CommonOptTable(objdump_opt::ObjdumpInfoTable,
+ " [options] <input object files>",
"llvm object file dumper") {}
};
@@ -149,27 +157,30 @@ enum OtoolOptID {
#undef OPTION
};
-#define PREFIX(NAME, VALUE) const char *const OTOOL_##NAME[] = VALUE;
+namespace otool {
+#define PREFIX(NAME, VALUE) \
+ static constexpr StringLiteral NAME##_init[] = VALUE; \
+ static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \
+ std::size(NAME##_init) - 1);
#include "OtoolOpts.inc"
#undef PREFIX
static constexpr opt::OptTable::Info OtoolInfoTable[] = {
-#define OTOOL_nullptr nullptr
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR, VALUES) \
- {OTOOL_##PREFIX, NAME, HELPTEXT, \
- METAVAR, OTOOL_##ID, opt::Option::KIND##Class, \
- PARAM, FLAGS, OTOOL_##GROUP, \
- OTOOL_##ALIAS, ALIASARGS, VALUES},
+ {PREFIX, NAME, HELPTEXT, \
+ METAVAR, OTOOL_##ID, opt::Option::KIND##Class, \
+ PARAM, FLAGS, OTOOL_##GROUP, \
+ OTOOL_##ALIAS, ALIASARGS, VALUES},
#include "OtoolOpts.inc"
#undef OPTION
-#undef OTOOL_nullptr
};
+} // namespace otool
class OtoolOptTable : public CommonOptTable {
public:
OtoolOptTable()
- : CommonOptTable(OtoolInfoTable, " [option...] [file...]",
+ : CommonOptTable(otool::OtoolInfoTable, " [option...] [file...]",
"Mach-O object file displaying tool") {}
};
@@ -207,6 +218,7 @@ bool objdump::PrintImmHex;
bool objdump::PrivateHeaders;
std::vector<std::string> objdump::FilterSections;
bool objdump::SectionHeaders;
+static bool ShowAllSymbols;
static bool ShowLMA;
bool objdump::PrintSource;
@@ -232,6 +244,9 @@ static StringSet<> DisasmSymbolSet;
StringSet<> objdump::FoundSectionSet;
static StringRef ToolName;
+std::unique_ptr<BuildIDFetcher> BIDFetcher;
+ExitOnError ExitOnErr;
+
namespace {
struct FilterResult {
// True if the section should not be skipped.
@@ -454,16 +469,24 @@ static bool hasMappingSymbols(const ObjectFile &Obj) {
return isArmElf(Obj) || isAArch64Elf(Obj) || isCSKYElf(Obj) ;
}
+static bool isMappingSymbol(const SymbolInfoTy &Sym) {
+ return Sym.Name.startswith("$d") || Sym.Name.startswith("$x") ||
+ Sym.Name.startswith("$a") || Sym.Name.startswith("$t");
+}
+
static void printRelocation(formatted_raw_ostream &OS, StringRef FileName,
const RelocationRef &Rel, uint64_t Address,
bool Is64Bits) {
- StringRef Fmt = Is64Bits ? "\t\t%016" PRIx64 ": " : "\t\t\t%08" PRIx64 ": ";
+ StringRef Fmt = Is64Bits ? "%016" PRIx64 ": " : "%08" PRIx64 ": ";
SmallString<16> Name;
SmallString<32> Val;
Rel.getTypeName(Name);
if (Error E = getRelocationValueString(Rel, Val))
reportError(std::move(E), FileName);
- OS << format(Fmt.data(), Address) << Name << "\t" << Val;
+ OS << (Is64Bits || !LeadingAddr ? "\t\t" : "\t\t\t");
+ if (LeadingAddr)
+ OS << format(Fmt.data(), Address);
+ OS << Name << "\t" << Val;
}
static void AlignToInstStartColumn(size_t Start, const MCSubtargetInfo &STI,
@@ -631,10 +654,10 @@ public:
if (Bytes.size() >= 4) {
// D should be casted to uint32_t here as it is passed by format to
// snprintf as vararg.
- for (uint32_t D : makeArrayRef(
- reinterpret_cast<const support::little32_t *>(Bytes.data()),
- Bytes.size() / 4))
- OS << format(" %08" PRIX32, D);
+ for (uint32_t D :
+ ArrayRef(reinterpret_cast<const support::little32_t *>(Bytes.data()),
+ Bytes.size() / 4))
+ OS << format(" %08" PRIX32, D);
} else {
for (unsigned char B : Bytes)
OS << format(" %02" PRIX8, B);
@@ -690,14 +713,14 @@ public:
OS << ' '
<< format_hex_no_prefix(
llvm::support::endian::read<uint16_t>(
- Bytes.data() + Pos, llvm::support::little),
+ Bytes.data() + Pos, InstructionEndianness),
4);
} else {
for (; Pos + 4 <= End; Pos += 4)
OS << ' '
<< format_hex_no_prefix(
llvm::support::endian::read<uint32_t>(
- Bytes.data() + Pos, llvm::support::little),
+ Bytes.data() + Pos, InstructionEndianness),
8);
}
if (Pos < End) {
@@ -713,6 +736,13 @@ public:
} else
OS << "\t<unknown>";
}
+
+ void setInstructionEndianness(llvm::support::endianness Endianness) {
+ InstructionEndianness = Endianness;
+ }
+
+private:
+ llvm::support::endianness InstructionEndianness = llvm::support::little;
};
ARMPrettyPrinter ARMPrettyPrinterInst;
@@ -844,19 +874,19 @@ addDynamicElfSymbols(const ELFObjectFileBase &Obj,
llvm_unreachable("Unsupported binary format");
}
-static Optional<SectionRef> getWasmCodeSection(const WasmObjectFile &Obj) {
+static std::optional<SectionRef> getWasmCodeSection(const WasmObjectFile &Obj) {
for (auto SecI : Obj.sections()) {
const WasmSection &Section = Obj.getWasmSection(SecI);
if (Section.Type == wasm::WASM_SEC_CODE)
return SecI;
}
- return None;
+ return std::nullopt;
}
static void
addMissingWasmCodeSymbols(const WasmObjectFile &Obj,
std::map<SectionRef, SectionSymbolsTy> &AllSymbols) {
- Optional<SectionRef> Section = getWasmCodeSection(Obj);
+ std::optional<SectionRef> Section = getWasmCodeSection(Obj);
if (!Section)
return;
SectionSymbolsTy &Symbols = AllSymbols[*Section];
@@ -884,7 +914,7 @@ addMissingWasmCodeSymbols(const WasmObjectFile &Obj,
static void addPltEntries(const ObjectFile &Obj,
std::map<SectionRef, SectionSymbolsTy> &AllSymbols,
StringSaver &Saver) {
- Optional<SectionRef> Plt = None;
+ std::optional<SectionRef> Plt;
for (const SectionRef &Section : Obj.sections()) {
Expected<StringRef> SecNameOrErr = Section.getName();
if (!SecNameOrErr) {
@@ -1065,7 +1095,7 @@ SymbolInfoTy objdump::createSymbolInfo(const ObjectFile &Obj,
DataRefImpl SymbolDRI = Symbol.getRawDataRefImpl();
const uint32_t SymbolIndex = XCOFFObj.getSymbolIndex(SymbolDRI.p);
- Optional<XCOFF::StorageMappingClass> Smc =
+ std::optional<XCOFF::StorageMappingClass> Smc =
getXCOFFSymbolCsectSMC(XCOFFObj, Symbol);
return SymbolInfoTy(Addr, Name, Smc, SymbolIndex,
isLabel(XCOFFObj, Symbol));
@@ -1082,7 +1112,7 @@ static SymbolInfoTy createDummySymbolInfo(const ObjectFile &Obj,
const uint64_t Addr, StringRef &Name,
uint8_t Type) {
if (Obj.isXCOFF() && SymbolDescription)
- return SymbolInfoTy(Addr, Name, None, None, false);
+ return SymbolInfoTy(Addr, Name, std::nullopt, std::nullopt, false);
else
return SymbolInfoTy(Addr, Name, Type);
}
@@ -1172,8 +1202,9 @@ static void addSymbolizer(
for (size_t Index = 0; Index != Bytes.size();) {
MCInst Inst;
uint64_t Size;
- ArrayRef<uint8_t> ThisBytes = Bytes.slice(Index - SectionAddr);
- DisAsm->getInstruction(Inst, Size, ThisBytes, Index, nulls());
+ ArrayRef<uint8_t> ThisBytes = Bytes.slice(Index);
+ const uint64_t ThisAddr = SectionAddr + Index;
+ DisAsm->getInstruction(Inst, Size, ThisBytes, ThisAddr, nulls());
if (Size == 0)
Size = std::min<uint64_t>(ThisBytes.size(),
DisAsm->suggestBytesToSkip(ThisBytes, Index));
@@ -1250,8 +1281,27 @@ static void createFakeELFSections(ObjectFile &Obj) {
llvm_unreachable("Unsupported binary format");
}
+// Tries to fetch a more complete version of the given object file using its
+// Build ID. Returns std::nullopt if nothing was found.
+static std::optional<OwningBinary<Binary>>
+fetchBinaryByBuildID(const ObjectFile &Obj) {
+ std::optional<object::BuildIDRef> BuildID = getBuildID(&Obj);
+ if (!BuildID)
+ return std::nullopt;
+ std::optional<std::string> Path = BIDFetcher->fetch(*BuildID);
+ if (!Path)
+ return std::nullopt;
+ Expected<OwningBinary<Binary>> DebugBinary = createBinary(*Path);
+ if (!DebugBinary) {
+ reportWarning(toString(DebugBinary.takeError()), *Path);
+ return std::nullopt;
+ }
+ return std::move(*DebugBinary);
+}
+
static void disassembleObject(const Target *TheTarget, ObjectFile &Obj,
- MCContext &Ctx, MCDisassembler *PrimaryDisAsm,
+ const ObjectFile &DbgObj, MCContext &Ctx,
+ MCDisassembler *PrimaryDisAsm,
MCDisassembler *SecondaryDisAsm,
const MCInstrAnalysis *MIA, MCInstPrinter *IP,
const MCSubtargetInfo *PrimarySTI,
@@ -1376,7 +1426,7 @@ static void disassembleObject(const Target *TheTarget, ObjectFile &Obj,
LiveVariablePrinter LVP(*Ctx.getRegisterInfo(), *STI);
if (DbgVariables != DVDisabled) {
- DICtx = DWARFContext::create(Obj);
+ DICtx = DWARFContext::create(DbgObj);
for (const std::unique_ptr<DWARFUnit> &CU : DICtx->compile_units())
LVP.addCompileUnit(CU->getUnitDIE(false));
}
@@ -1384,13 +1434,13 @@ static void disassembleObject(const Target *TheTarget, ObjectFile &Obj,
LLVM_DEBUG(LVP.dump());
std::unordered_map<uint64_t, BBAddrMap> AddrToBBAddrMap;
- auto ReadBBAddrMap = [&](Optional<unsigned> SectionIndex = None) {
+ auto ReadBBAddrMap = [&](std::optional<unsigned> SectionIndex =
+ std::nullopt) {
AddrToBBAddrMap.clear();
if (const auto *Elf = dyn_cast<ELFObjectFileBase>(&Obj)) {
auto BBAddrMapsOrErr = Elf->readBBAddrMap(SectionIndex);
if (!BBAddrMapsOrErr)
- reportWarning(toString(BBAddrMapsOrErr.takeError()),
- Obj.getFileName());
+ reportWarning(toString(BBAddrMapsOrErr.takeError()), Obj.getFileName());
for (auto &FunctionBBAddrMap : *BBAddrMapsOrErr)
AddrToBBAddrMap.emplace(FunctionBBAddrMap.Addr,
std::move(FunctionBBAddrMap));
@@ -1474,28 +1524,118 @@ static void disassembleObject(const Target *TheTarget, ObjectFile &Obj,
std::vector<RelocationRef> Rels = RelocMap[Section];
std::vector<RelocationRef>::const_iterator RelCur = Rels.begin();
std::vector<RelocationRef>::const_iterator RelEnd = Rels.end();
- // Disassemble symbol by symbol.
- for (unsigned SI = 0, SE = Symbols.size(); SI != SE; ++SI) {
- std::string SymbolName = Symbols[SI].Name.str();
- if (Demangle)
- SymbolName = demangle(SymbolName);
-
- // Skip if --disassemble-symbols is not empty and the symbol is not in
- // the list.
- if (!DisasmSymbolSet.empty() && !DisasmSymbolSet.count(SymbolName))
- continue;
+ // Loop over each chunk of code between two points where at least
+ // one symbol is defined.
+ for (size_t SI = 0, SE = Symbols.size(); SI != SE;) {
+ // Advance SI past all the symbols starting at the same address,
+ // and make an ArrayRef of them.
+ unsigned FirstSI = SI;
uint64_t Start = Symbols[SI].Addr;
+ ArrayRef<SymbolInfoTy> SymbolsHere;
+ while (SI != SE && Symbols[SI].Addr == Start)
+ ++SI;
+ SymbolsHere = ArrayRef<SymbolInfoTy>(&Symbols[FirstSI], SI - FirstSI);
+
+ // Get the demangled names of all those symbols. We end up with a vector
+ // of StringRef that holds the names we're going to use, and a vector of
+ // std::string that stores the new strings returned by demangle(), if
+ // any. If we don't call demangle() then that vector can stay empty.
+ std::vector<StringRef> SymNamesHere;
+ std::vector<std::string> DemangledSymNamesHere;
+ if (Demangle) {
+ // Fetch the demangled names and store them locally.
+ for (const SymbolInfoTy &Symbol : SymbolsHere)
+ DemangledSymNamesHere.push_back(demangle(Symbol.Name.str()));
+ // Now we've finished modifying that vector, it's safe to make
+ // a vector of StringRefs pointing into it.
+ SymNamesHere.insert(SymNamesHere.begin(), DemangledSymNamesHere.begin(),
+ DemangledSymNamesHere.end());
+ } else {
+ for (const SymbolInfoTy &Symbol : SymbolsHere)
+ SymNamesHere.push_back(Symbol.Name);
+ }
+
+ // Distinguish ELF data from code symbols, which will be used later on to
+ // decide whether to 'disassemble' this chunk as a data declaration via
+ // dumpELFData(), or whether to treat it as code.
+ //
+ // If data _and_ code symbols are defined at the same address, the code
+ // takes priority, on the grounds that disassembling code is our main
+ // purpose here, and it would be a worse failure to _not_ interpret
+ // something that _was_ meaningful as code than vice versa.
+ //
+ // Any ELF symbol type that is not clearly data will be regarded as code.
+ // In particular, one of the uses of STT_NOTYPE is for branch targets
+ // inside functions, for which STT_FUNC would be inaccurate.
+ //
+ // So here, we spot whether there's any non-data symbol present at all,
+ // and only set the DisassembleAsData flag if there isn't. Also, we use
+ // this distinction to inform the decision of which symbol to print at
+ // the head of the section, so that if we're printing code, we print a
+ // code-related symbol name to go with it.
+ bool DisassembleAsData = false;
+ size_t DisplaySymIndex = SymbolsHere.size() - 1;
+ if (Obj.isELF() && !DisassembleAll && Section.isText()) {
+ DisassembleAsData = true; // unless we find a code symbol below
+
+ for (size_t i = 0; i < SymbolsHere.size(); ++i) {
+ uint8_t SymTy = SymbolsHere[i].Type;
+ if (SymTy != ELF::STT_OBJECT && SymTy != ELF::STT_COMMON) {
+ DisassembleAsData = false;
+ DisplaySymIndex = i;
+ }
+ }
+ }
+
+ // Decide which symbol(s) from this collection we're going to print.
+ std::vector<bool> SymsToPrint(SymbolsHere.size(), false);
+ // If the user has given the --disassemble-symbols option, then we must
+ // display every symbol in that set, and no others.
+ if (!DisasmSymbolSet.empty()) {
+ bool FoundAny = false;
+ for (size_t i = 0; i < SymbolsHere.size(); ++i) {
+ if (DisasmSymbolSet.count(SymNamesHere[i])) {
+ SymsToPrint[i] = true;
+ FoundAny = true;
+ }
+ }
+
+ // And if none of the symbols here is one that the user asked for, skip
+ // disassembling this entire chunk of code.
+ if (!FoundAny)
+ continue;
+ } else {
+ // Otherwise, print whichever symbol at this location is last in the
+ // Symbols array, because that array is pre-sorted in a way intended to
+ // correlate with priority of which symbol to display.
+ SymsToPrint[DisplaySymIndex] = true;
+ }
+
+ // Now that we know we're disassembling this section, override the choice
+ // of which symbols to display by printing _all_ of them at this address
+ // if the user asked for all symbols.
+ //
+ // That way, '--show-all-symbols --disassemble-symbol=foo' will print
+ // only the chunk of code headed by 'foo', but also show any other
+ // symbols defined at that address, such as aliases for 'foo', or the ARM
+ // mapping symbol preceding its code.
+ if (ShowAllSymbols) {
+ for (size_t i = 0; i < SymbolsHere.size(); ++i)
+ SymsToPrint[i] = true;
+ }
+
if (Start < SectionAddr || StopAddress <= Start)
continue;
- else
- FoundDisasmSymbolSet.insert(SymbolName);
+
+ for (size_t i = 0; i < SymbolsHere.size(); ++i)
+ FoundDisasmSymbolSet.insert(SymNamesHere[i]);
// The end is the section end, the beginning of the next symbol, or
// --stop-address.
uint64_t End = std::min<uint64_t>(SectionAddr + SectSize, StopAddress);
- if (SI + 1 < SE)
- End = std::min(End, Symbols[SI + 1].Addr);
+ if (SI < SE)
+ End = std::min(End, Symbols[SI].Addr);
if (Start >= End || End <= StartAddress)
continue;
Start -= SectionAddr;
@@ -1510,13 +1650,22 @@ static void disassembleObject(const Target *TheTarget, ObjectFile &Obj,
}
outs() << '\n';
- if (LeadingAddr)
- outs() << format(Is64Bits ? "%016" PRIx64 " " : "%08" PRIx64 " ",
- SectionAddr + Start + VMAAdjustment);
- if (Obj.isXCOFF() && SymbolDescription) {
- outs() << getXCOFFSymbolDescription(Symbols[SI], SymbolName) << ":\n";
- } else
- outs() << '<' << SymbolName << ">:\n";
+
+ for (size_t i = 0; i < SymbolsHere.size(); ++i) {
+ if (!SymsToPrint[i])
+ continue;
+
+ const SymbolInfoTy &Symbol = SymbolsHere[i];
+ const StringRef SymbolName = SymNamesHere[i];
+
+ if (LeadingAddr)
+ outs() << format(Is64Bits ? "%016" PRIx64 " " : "%08" PRIx64 " ",
+ SectionAddr + Start + VMAAdjustment);
+ if (Obj.isXCOFF() && SymbolDescription) {
+ outs() << getXCOFFSymbolDescription(Symbol, SymbolName) << ":\n";
+ } else
+ outs() << '<' << SymbolName << ">:\n";
+ }
// Don't print raw contents of a virtual section. A virtual section
// doesn't have any contents in the file.
@@ -1525,57 +1674,67 @@ static void disassembleObject(const Target *TheTarget, ObjectFile &Obj,
continue;
}
- auto Status = DisAsm->onSymbolStart(Symbols[SI], Size,
- Bytes.slice(Start, End - Start),
- SectionAddr + Start, CommentStream);
- // To have round trippable disassembly, we fall back to decoding the
- // remaining bytes as instructions.
- //
- // If there is a failure, we disassemble the failed region as bytes before
- // falling back. The target is expected to print nothing in this case.
- //
- // If there is Success or SoftFail i.e no 'real' failure, we go ahead by
- // Size bytes before falling back.
- // So if the entire symbol is 'eaten' by the target:
- // Start += Size // Now Start = End and we will never decode as
- // // instructions
- //
- // Right now, most targets return None i.e ignore to treat a symbol
- // separately. But WebAssembly decodes preludes for some symbols.
+ // See if any of the symbols defined at this location triggers target-
+ // specific disassembly behavior, e.g. of special descriptors or function
+ // prelude information.
//
- if (Status) {
- if (Status.value() == MCDisassembler::Fail) {
- outs() << "// Error in decoding " << SymbolName
+ // We stop this loop at the first symbol that triggers some kind of
+ // interesting behavior (if any), on the assumption that if two symbols
+ // defined at the same address trigger two conflicting symbol handlers,
+ // the object file is probably confused anyway, and it would make even
+ // less sense to present the output of _both_ handlers, because that
+ // would describe the same data twice.
+ for (size_t SHI = 0; SHI < SymbolsHere.size(); ++SHI) {
+ SymbolInfoTy Symbol = SymbolsHere[SHI];
+
+ auto Status =
+ DisAsm->onSymbolStart(Symbol, Size, Bytes.slice(Start, End - Start),
+ SectionAddr + Start, CommentStream);
+
+ if (!Status) {
+ // If onSymbolStart returns std::nullopt, that means it didn't trigger
+ // any interesting handling for this symbol. Try the other symbols
+ // defined at this address.
+ continue;
+ }
+
+ if (*Status == MCDisassembler::Fail) {
+ // If onSymbolStart returns Fail, that means it identified some kind
+ // of special data at this address, but wasn't able to disassemble it
+ // meaningfully. So we fall back to disassembling the failed region
+ // as bytes, assuming that the target detected the failure before
+ // printing anything.
+ //
+ // Return values Success or SoftFail (i.e no 'real' failure) are
+ // expected to mean that the target has emitted its own output.
+ //
+ // Either way, 'Size' will have been set to the amount of data
+ // covered by whatever prologue the target identified. So we advance
+ // our own position to beyond that. Sometimes that will be the entire
+ // distance to the next symbol, and sometimes it will be just a
+ // prologue and we should start disassembling instructions from where
+ // it left off.
+ outs() << "// Error in decoding " << SymNamesHere[SHI]
<< " : Decoding failed region as bytes.\n";
for (uint64_t I = 0; I < Size; ++I) {
outs() << "\t.byte\t " << format_hex(Bytes[I], 1, /*Upper=*/true)
<< "\n";
}
}
- } else {
- Size = 0;
+ Start += Size;
+ break;
}
- Start += Size;
-
Index = Start;
if (SectionAddr < StartAddress)
Index = std::max<uint64_t>(Index, StartAddress - SectionAddr);
- // If there is a data/common symbol inside an ELF text section and we are
- // only disassembling text (applicable all architectures), we are in a
- // situation where we must print the data and not disassemble it.
- if (Obj.isELF() && !DisassembleAll && Section.isText()) {
- uint8_t SymTy = Symbols[SI].Type;
- if (SymTy == ELF::STT_OBJECT || SymTy == ELF::STT_COMMON) {
- dumpELFData(SectionAddr, Index, End, Bytes);
- Index = End;
- }
+ if (DisassembleAsData) {
+ dumpELFData(SectionAddr, Index, End, Bytes);
+ Index = End;
+ continue;
}
- bool CheckARMELFData = hasMappingSymbols(Obj) &&
- Symbols[SI].Type != ELF::STT_OBJECT &&
- !DisassembleAll;
bool DumpARMELFData = false;
formatted_raw_ostream FOS(outs());
@@ -1593,7 +1752,7 @@ static void disassembleObject(const Target *TheTarget, ObjectFile &Obj,
// same section. We rely on the markers introduced to understand what
// we need to dump. If the data marker is within a function, it is
// denoted as a word/short etc.
- if (CheckARMELFData) {
+ if (!MappingSymbols.empty()) {
char Kind = getMappingSymbolKind(MappingSymbols, Index);
DumpARMELFData = Kind == 'd';
if (SecondarySTI) {
@@ -1675,7 +1834,7 @@ static void disassembleObject(const Target *TheTarget, ObjectFile &Obj,
bool PrintTarget =
MIA->evaluateBranch(Inst, SectionAddr + Index, Size, Target);
if (!PrintTarget)
- if (Optional<uint64_t> MaybeTarget =
+ if (std::optional<uint64_t> MaybeTarget =
MIA->evaluateMemoryOperandAddress(
Inst, STI, SectionAddr + Index, Size)) {
Target = *MaybeTarget;
@@ -1729,10 +1888,17 @@ static void disassembleObject(const Target *TheTarget, ObjectFile &Obj,
auto It = llvm::partition_point(
*TargetSymbols,
[=](const SymbolInfoTy &O) { return O.Addr <= Target; });
- if (It != TargetSymbols->begin()) {
- TargetSym = &*(It - 1);
- break;
+ while (It != TargetSymbols->begin()) {
+ --It;
+ // Skip mapping symbols to avoid possible ambiguity as they
+ // do not allow uniquely identifying the target address.
+ if (!hasMappingSymbols(Obj) || !isMappingSymbol(*It)) {
+ TargetSym = &*It;
+ break;
+ }
}
+ if (TargetSym)
+ break;
}
// Print the labels corresponding to the target if there's any.
@@ -1824,10 +1990,29 @@ static void disassembleObject(const Target *TheTarget, ObjectFile &Obj,
}
static void disassembleObject(ObjectFile *Obj, bool InlineRelocs) {
+ // If information useful for showing the disassembly is missing, try to find a
+ // more complete binary and disassemble that instead.
+ OwningBinary<Binary> FetchedBinary;
+ if (Obj->symbols().empty()) {
+ if (std::optional<OwningBinary<Binary>> FetchedBinaryOpt =
+ fetchBinaryByBuildID(*Obj)) {
+ if (auto *O = dyn_cast<ObjectFile>(FetchedBinaryOpt->getBinary())) {
+ if (!O->symbols().empty() ||
+ (!O->sections().empty() && Obj->sections().empty())) {
+ FetchedBinary = std::move(*FetchedBinaryOpt);
+ Obj = O;
+ }
+ }
+ }
+ }
+
const Target *TheTarget = getTarget(Obj);
// Package up features to be passed to target/subtarget
- SubtargetFeatures Features = Obj->getFeatures();
+ Expected<SubtargetFeatures> FeaturesValue = Obj->getFeatures();
+ if (!FeaturesValue)
+ reportError(FeaturesValue.takeError(), Obj->getFileName());
+ SubtargetFeatures Features = *FeaturesValue;
if (!MAttrs.empty()) {
for (unsigned I = 0; I != MAttrs.size(); ++I)
Features.AddFeature(MAttrs[I]);
@@ -1852,6 +2037,29 @@ static void disassembleObject(ObjectFile *Obj, bool InlineRelocs) {
if (MCPU.empty())
MCPU = Obj->tryGetCPUName().value_or("").str();
+ if (isArmElf(*Obj)) {
+ // When disassembling big-endian Arm ELF, the instruction endianness is
+ // determined in a complex way. In relocatable objects, AAELF32 mandates
+ // that instruction endianness matches the ELF file endianness; in
+ // executable images, that's true unless the file header has the EF_ARM_BE8
+ // flag, in which case instructions are little-endian regardless of data
+ // endianness.
+ //
+ // We must set the big-endian-instructions SubtargetFeature to make the
+ // disassembler read the instructions the right way round, and also tell
+ // our own prettyprinter to retrieve the encodings the same way to print in
+ // hex.
+ const auto *Elf32BE = dyn_cast<ELF32BEObjectFile>(Obj);
+
+ if (Elf32BE && (Elf32BE->isRelocatableObject() ||
+ !(Elf32BE->getPlatformFlags() & ELF::EF_ARM_BE8))) {
+ Features.AddFeature("+big-endian-instructions");
+ ARMPrettyPrinterInst.setInstructionEndianness(llvm::support::big);
+ } else {
+ ARMPrettyPrinterInst.setInstructionEndianness(llvm::support::little);
+ }
+ }
+
std::unique_ptr<const MCSubtargetInfo> STI(
TheTarget->createMCSubtargetInfo(TripleName, MCPU, Features.getString()));
if (!STI)
@@ -1903,16 +2111,42 @@ static void disassembleObject(ObjectFile *Obj, bool InlineRelocs) {
IP->setMCInstrAnalysis(MIA.get());
PrettyPrinter &PIP = selectPrettyPrinter(Triple(TripleName));
- SourcePrinter SP(Obj, TheTarget->getName());
+
+ const ObjectFile *DbgObj = Obj;
+ if (!FetchedBinary.getBinary() && !Obj->hasDebugInfo()) {
+ if (std::optional<OwningBinary<Binary>> DebugBinaryOpt =
+ fetchBinaryByBuildID(*Obj)) {
+ if (auto *FetchedObj =
+ dyn_cast<const ObjectFile>(DebugBinaryOpt->getBinary())) {
+ if (FetchedObj->hasDebugInfo()) {
+ FetchedBinary = std::move(*DebugBinaryOpt);
+ DbgObj = FetchedObj;
+ }
+ }
+ }
+ }
+
+ std::unique_ptr<object::Binary> DSYMBinary;
+ std::unique_ptr<MemoryBuffer> DSYMBuf;
+ if (!DbgObj->hasDebugInfo()) {
+ if (const MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&*Obj)) {
+ DbgObj = objdump::getMachODSymObject(MachOOF, Obj->getFileName(),
+ DSYMBinary, DSYMBuf);
+ if (!DbgObj)
+ return;
+ }
+ }
+
+ SourcePrinter SP(DbgObj, TheTarget->getName());
for (StringRef Opt : DisassemblerOptions)
if (!IP->applyTargetSpecificCLOption(Opt))
reportError(Obj->getFileName(),
"Unrecognized disassembler option: " + Opt);
- disassembleObject(TheTarget, *Obj, Ctx, DisAsm.get(), SecondaryDisAsm.get(),
- MIA.get(), IP.get(), STI.get(), SecondarySTI.get(), PIP, SP,
- InlineRelocs);
+ disassembleObject(TheTarget, *Obj, *DbgObj, Ctx, DisAsm.get(),
+ SecondaryDisAsm.get(), MIA.get(), IP.get(), STI.get(),
+ SecondarySTI.get(), PIP, SP, InlineRelocs);
}
void objdump::printRelocations(const ObjectFile *Obj) {
@@ -2026,6 +2260,9 @@ static size_t getMaxSectionNameWidth(const ObjectFile &Obj) {
}
void objdump::printSectionHeaders(ObjectFile &Obj) {
+ if (Obj.isELF() && Obj.sections().empty())
+ createFakeELFSections(Obj);
+
size_t NameWidth = getMaxSectionNameWidth(Obj);
size_t AddressWidth = 2 * Obj.getBytesInAddress();
bool HasLMAColumn = shouldDisplayLMA(Obj);
@@ -2038,9 +2275,6 @@ void objdump::printSectionHeaders(ObjectFile &Obj) {
outs() << "Idx " << left_justify("Name", NameWidth) << " Size "
<< left_justify("VMA", AddressWidth) << " Type\n";
- if (Obj.isELF() && Obj.sections().empty())
- createFakeELFSections(Obj);
-
uint64_t Idx;
for (const SectionRef &Section : ToolSectionFilter(Obj, &Idx)) {
StringRef Name = unwrapOrError(Section.getName(), Obj.getFileName());
@@ -2267,7 +2501,7 @@ void objdump::printSymbol(const ObjectFile &O, const SymbolRef &Symbol,
StringRef SectionName = unwrapOrError(Section->getName(), FileName);
outs() << SectionName;
if (O.isXCOFF()) {
- Optional<SymbolRef> SymRef =
+ std::optional<SymbolRef> SymRef =
getXCOFFSymbolContainingSymbolRef(cast<XCOFFObjectFile>(O), Symbol);
if (SymRef) {
@@ -2281,8 +2515,8 @@ void objdump::printSymbol(const ObjectFile &O, const SymbolRef &Symbol,
SymName = demangle(SymName);
if (SymbolDescription)
- SymName = getXCOFFSymbolDescription(
- createSymbolInfo(O, SymRef.value()), SymName);
+ SymName = getXCOFFSymbolDescription(createSymbolInfo(O, *SymRef),
+ SymName);
outs() << ' ' << SymName;
outs() << ") ";
@@ -2373,7 +2607,7 @@ static void printRawClangAST(const ObjectFile *Obj) {
ClangASTSectionName = "clangast";
}
- Optional<object::SectionRef> ClangASTSection;
+ std::optional<object::SectionRef> ClangASTSection;
for (auto Sec : ToolSectionFilter(*Obj)) {
StringRef Name;
if (Expected<StringRef> NameOrErr = Sec.getName())
@@ -2390,7 +2624,7 @@ static void printRawClangAST(const ObjectFile *Obj) {
return;
StringRef ClangASTContents =
- unwrapOrError(ClangASTSection.value().getContents(), Obj->getFileName());
+ unwrapOrError(ClangASTSection->getContents(), Obj->getFileName());
outs().write(ClangASTContents.data(), ClangASTContents.size());
}
@@ -2408,7 +2642,7 @@ static void printFaultMaps(const ObjectFile *Obj) {
return;
}
- Optional<object::SectionRef> FaultMapSection;
+ std::optional<object::SectionRef> FaultMapSection;
for (auto Sec : ToolSectionFilter(*Obj)) {
StringRef Name;
@@ -2705,7 +2939,18 @@ static void parseIntArg(const llvm::opt::InputArgList &InputArgs, int ID,
}
}
-static void invalidArgValue(const opt::Arg *A) {
+static object::BuildID parseBuildIDArg(const opt::Arg *A) {
+ StringRef V(A->getValue());
+ std::string Bytes;
+ if (!tryGetFromHex(V, Bytes))
+ reportCmdLineError(A->getSpelling() + ": expected a build ID, but got '" +
+ V + "'");
+ ArrayRef<uint8_t> BuildID(reinterpret_cast<const uint8_t *>(Bytes.data()),
+ Bytes.size());
+ return object::BuildID(BuildID.begin(), BuildID.end());
+}
+
+void objdump::invalidArgValue(const opt::Arg *A) {
reportCmdLineError("'" + StringRef(A->getValue()) +
"' is not a valid value for '" + A->getSpelling() + "'");
}
@@ -2757,6 +3002,9 @@ static void parseOtoolOptions(const llvm::opt::InputArgList &InputArgs) {
FilterSections.push_back(",__text");
LeadingAddr = LeadingHeaders = !InputArgs.hasArg(OTOOL_X);
+ ChainedFixups = InputArgs.hasArg(OTOOL_chained_fixups);
+ DyldInfo = InputArgs.hasArg(OTOOL_dyld_info);
+
InputFilenames = InputArgs.getAllArgValues(OTOOL_INPUT);
if (InputFilenames.empty())
reportCmdLineError("no input file");
@@ -2804,10 +3052,11 @@ static void parseObjdumpOptions(const llvm::opt::InputArgList &InputArgs) {
RawClangAST = InputArgs.hasArg(OBJDUMP_raw_clang_ast);
Relocations = InputArgs.hasArg(OBJDUMP_reloc);
PrintImmHex =
- InputArgs.hasFlag(OBJDUMP_print_imm_hex, OBJDUMP_no_print_imm_hex, false);
+ InputArgs.hasFlag(OBJDUMP_print_imm_hex, OBJDUMP_no_print_imm_hex, true);
PrivateHeaders = InputArgs.hasArg(OBJDUMP_private_headers);
FilterSections = InputArgs.getAllArgValues(OBJDUMP_section_EQ);
SectionHeaders = InputArgs.hasArg(OBJDUMP_section_headers);
+ ShowAllSymbols = InputArgs.hasArg(OBJDUMP_show_all_symbols);
ShowLMA = InputArgs.hasArg(OBJDUMP_show_lma);
PrintSource = InputArgs.hasArg(OBJDUMP_source);
parseIntArg(InputArgs, OBJDUMP_start_address_EQ, StartAddress);
@@ -2869,6 +3118,17 @@ static void parseObjdumpOptions(const llvm::opt::InputArgList &InputArgs) {
llvm::cl::ParseCommandLineOptions(2, Argv);
}
+ // Look up any provided build IDs, then append them to the input filenames.
+ for (const opt::Arg *A : InputArgs.filtered(OBJDUMP_build_id)) {
+ object::BuildID BuildID = parseBuildIDArg(A);
+ std::optional<std::string> Path = BIDFetcher->fetch(BuildID);
+ if (!Path) {
+ reportCmdLineError(A->getSpelling() + ": could not find build ID '" +
+ A->getValue() + "'");
+ }
+ InputFilenames.push_back(std::move(*Path));
+ }
+
// objdump defaults to a.out if no filenames specified.
if (InputFilenames.empty())
InputFilenames.push_back("a.out");
@@ -2936,6 +3196,23 @@ int main(int argc, char **argv) {
return 0;
}
+ // Initialize debuginfod.
+ const bool ShouldUseDebuginfodByDefault =
+ InputArgs.hasArg(OBJDUMP_build_id) ||
+ (HTTPClient::isAvailable() &&
+ !ExitOnErr(getDefaultDebuginfodUrls()).empty());
+ std::vector<std::string> DebugFileDirectories =
+ InputArgs.getAllArgValues(OBJDUMP_debug_file_directory);
+ if (InputArgs.hasFlag(OBJDUMP_debuginfod, OBJDUMP_no_debuginfod,
+ ShouldUseDebuginfodByDefault)) {
+ HTTPClient::initialize();
+ BIDFetcher =
+ std::make_unique<DebuginfodFetcher>(std::move(DebugFileDirectories));
+ } else {
+ BIDFetcher =
+ std::make_unique<BuildIDFetcher>(std::move(DebugFileDirectories));
+ }
+
if (Is("otool"))
parseOtoolOptions(InputArgs);
else
@@ -2960,11 +3237,12 @@ int main(int argc, char **argv) {
!DynamicRelocations && !FileHeaders && !PrivateHeaders && !RawClangAST &&
!Relocations && !SectionHeaders && !SectionContents && !SymbolTable &&
!DynamicSymbolTable && !UnwindInfo && !FaultMapSection && !Offloading &&
- !(MachOOpt && (Bind || DataInCode || DyldInfo || DylibId || DylibsUsed ||
- ExportsTrie || FirstPrivateHeader || FunctionStarts ||
- IndirectSymbols || InfoPlist || LazyBind || LinkOptHints ||
- ObjcMetaData || Rebase || Rpaths || UniversalHeaders ||
- WeakBind || !FilterSections.empty()))) {
+ !(MachOOpt &&
+ (Bind || DataInCode || ChainedFixups || DyldInfo || DylibId ||
+ DylibsUsed || ExportsTrie || FirstPrivateHeader ||
+ FunctionStartsType != FunctionStartsMode::None || IndirectSymbols ||
+ InfoPlist || LazyBind || LinkOptHints || ObjcMetaData || Rebase ||
+ Rpaths || UniversalHeaders || WeakBind || !FilterSections.empty()))) {
T->printHelp(ToolName);
return 2;
}
diff --git a/llvm/tools/llvm-objdump/llvm-objdump.h b/llvm/tools/llvm-objdump/llvm-objdump.h
index c64c042d513e..efb445195259 100644
--- a/llvm/tools/llvm-objdump/llvm-objdump.h
+++ b/llvm/tools/llvm-objdump/llvm-objdump.h
@@ -20,6 +20,10 @@ namespace llvm {
class StringRef;
class Twine;
+namespace opt {
+class Arg;
+} // namespace opt
+
namespace object {
class RelocationRef;
struct VersionEntry;
@@ -146,6 +150,8 @@ T unwrapOrError(Expected<T> EO, Ts &&... Args) {
reportError(EO.takeError(), std::forward<Ts>(Args)...);
}
+void invalidArgValue(const opt::Arg *A);
+
std::string getFileNameForError(const object::Archive::Child &C,
unsigned Index);
SymbolInfoTy createSymbolInfo(const object::ObjectFile &Obj,