Updated llvm-objdump to display local relocations in Mach-O binaries

Summary:
llvm-objdump's Mach-O parser was updated in r306037 to display external
relocations for MH_KEXT_BUNDLE file types. This change extends the Macho-O
parser to display local relocations for MH_PRELOAD files. When used with
the -macho option relocations will be displayed in a historical format.

All tests are passing for llvm, clang, and lld. llvm-objdump builds without
compiler warnings.

rdar://35778019

Reviewers: enderby

Reviewed By: enderby

Subscribers: llvm-commits

Differential Revision: https://reviews.llvm.org/D41199

llvm-svn: 320832
This commit is contained in:
Michael Trent 2017-12-15 17:57:40 +00:00
parent 237d4c2eab
commit a1703b1fc2
7 changed files with 371 additions and 11 deletions

View File

@ -329,6 +329,9 @@ public:
return make_range(extrel_begin(), extrel_end());
}
relocation_iterator locrel_begin() const;
relocation_iterator locrel_end() const;
void moveRelocationNext(DataRefImpl &Rel) const override;
uint64_t getRelocationOffset(DataRefImpl Rel) const override;
symbol_iterator getRelocationSymbol(DataRefImpl Rel) const override;

View File

@ -1960,6 +1960,7 @@ MachOObjectFile::section_rel_end(DataRefImpl Sec) const {
relocation_iterator MachOObjectFile::extrel_begin() const {
DataRefImpl Ret;
// for DYSYMTAB symbols, Ret.d.a == 0 for external relocations
Ret.d.a = 0; // Would normally be a section index.
Ret.d.b = 0; // Index into the external relocations
return relocation_iterator(RelocationRef(Ret, this));
@ -1968,11 +1969,29 @@ relocation_iterator MachOObjectFile::extrel_begin() const {
relocation_iterator MachOObjectFile::extrel_end() const {
MachO::dysymtab_command DysymtabLoadCmd = getDysymtabLoadCommand();
DataRefImpl Ret;
// for DYSYMTAB symbols, Ret.d.a == 0 for external relocations
Ret.d.a = 0; // Would normally be a section index.
Ret.d.b = DysymtabLoadCmd.nextrel; // Index into the external relocations
return relocation_iterator(RelocationRef(Ret, this));
}
relocation_iterator MachOObjectFile::locrel_begin() const {
DataRefImpl Ret;
// for DYSYMTAB symbols, Ret.d.a == 1 for local relocations
Ret.d.a = 1; // Would normally be a section index.
Ret.d.b = 0; // Index into the local relocations
return relocation_iterator(RelocationRef(Ret, this));
}
relocation_iterator MachOObjectFile::locrel_end() const {
MachO::dysymtab_command DysymtabLoadCmd = getDysymtabLoadCommand();
DataRefImpl Ret;
// for DYSYMTAB symbols, Ret.d.a == 1 for local relocations
Ret.d.a = 1; // Would normally be a section index.
Ret.d.b = DysymtabLoadCmd.nlocrel; // Index into the local relocations
return relocation_iterator(RelocationRef(Ret, this));
}
void MachOObjectFile::moveRelocationNext(DataRefImpl &Rel) const {
++Rel.d.b;
}
@ -4301,7 +4320,10 @@ MachOObjectFile::getRelocation(DataRefImpl Rel) const {
}
} else {
MachO::dysymtab_command DysymtabLoadCmd = getDysymtabLoadCommand();
Offset = DysymtabLoadCmd.extreloff; // Offset to the external relocations
if (Rel.d.a == 0)
Offset = DysymtabLoadCmd.extreloff; // Offset to the external relocations
else
Offset = DysymtabLoadCmd.locreloff; // Offset to the local relocations
}
auto P = reinterpret_cast<const MachO::any_relocation_info *>(

Binary file not shown.

View File

@ -0,0 +1,5 @@
// RUN: llvm-objdump -macho -r %p/Inputs/macho-preload-x86_64 | FileCheck %s
CHECK: Local relocation information 1 entries
CHECK: address pcrel length extern type scattered symbolnum/value
CHECK: 00000000 False quad False UNSIGND False 2 (__TEXT,__cstring)

View File

@ -1,7 +1,9 @@
RUN: llvm-objdump -macho -r %p/Inputs/hello.obj.macho-x86_64 | FileCheck %s
CHECK: RELOCATION RECORDS FOR [__text]:
CHECK: 0000000000000027 X86_64_RELOC_BRANCH _printf
CHECK: 000000000000000b X86_64_RELOC_SIGNED L_.str
CHECK: RELOCATION RECORDS FOR [__compact_unwind]:
CHECK: 0000000000000000 X86_64_RELOC_UNSIGNED __text
CHECK: Relocation information (__TEXT,__text) 2 entries
CHECK: address pcrel length extern type scattered symbolnum/value
CHECK: 00000027 True long True BRANCH False _printf
CHECK: 0000000b True long True SIGNED False L_.str
CHECK: Relocation information (__LD,__compact_unwind) 1 entries
CHECK: address pcrel length extern type scattered symbolnum/value
CHECK: 00000000 False quad False UNSIGND False 1 (__TEXT,__text)

View File

@ -68,4 +68,4 @@ RUN: not llvm-objdump -macho -objc-meta-data %p/Inputs/macho-invalid-bind-entry
INVALID-BIND-ENTRY: macho-invalid-bind-entry': truncated or malformed object (for BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB bad library ordinal: 83 (max 0) for opcode at: 0x0)
RUN: llvm-objdump -macho -r %p/Inputs/macho-invalid-reloc-section-index | FileCheck -check-prefix INVALID-RELOC-SECTION-INDEX %s
INVALID-RELOC-SECTION-INDEX: 0000000000000021 X86_64_RELOC_UNSIGNED 8388613 (?,?)
INVALID-RELOC-SECTION-INDEX: 00000021 False byte False UNSIGND False 8388613 (?,?)

View File

@ -467,6 +467,333 @@ static void PrintIndirectSymbols(MachOObjectFile *O, bool verbose) {
}
}
static void PrintRType(const uint64_t cputype, const unsigned r_type) {
static char const *generic_r_types[] = {
"VANILLA ", "PAIR ", "SECTDIF ", "PBLAPTR ", "LOCSDIF ", "TLV ",
" 6 (?) ", " 7 (?) ", " 8 (?) ", " 9 (?) ", " 10 (?) ", " 11 (?) ",
" 12 (?) ", " 13 (?) ", " 14 (?) ", " 15 (?) "
};
static char const *x86_64_r_types[] = {
"UNSIGND ", "SIGNED ", "BRANCH ", "GOT_LD ", "GOT ", "SUB ",
"SIGNED1 ", "SIGNED2 ", "SIGNED4 ", "TLV ", " 10 (?) ", " 11 (?) ",
" 12 (?) ", " 13 (?) ", " 14 (?) ", " 15 (?) "
};
static char const *arm_r_types[] = {
"VANILLA ", "PAIR ", "SECTDIFF", "LOCSDIF ", "PBLAPTR ",
"BR24 ", "T_BR22 ", "T_BR32 ", "HALF ", "HALFDIF ",
" 10 (?) ", " 11 (?) ", " 12 (?) ", " 13 (?) ", " 14 (?) ", " 15 (?) "
};
static char const *arm64_r_types[] = {
"UNSIGND ", "SUB ", "BR26 ", "PAGE21 ", "PAGOF12 ",
"GOTLDP ", "GOTLDPOF", "PTRTGOT ", "TLVLDP ", "TLVLDPOF",
"ADDEND ", " 11 (?) ", " 12 (?) ", " 13 (?) ", " 14 (?) ", " 15 (?) "
};
if (r_type > 0xf){
outs() << format("%-7u", r_type) << " ";
return;
}
switch (cputype) {
case MachO::CPU_TYPE_I386:
outs() << generic_r_types[r_type];
break;
case MachO::CPU_TYPE_X86_64:
outs() << x86_64_r_types[r_type];
break;
case MachO::CPU_TYPE_ARM:
outs() << arm_r_types[r_type];
break;
case MachO::CPU_TYPE_ARM64:
outs() << arm64_r_types[r_type];
break;
default:
outs() << format("%-7u ", r_type);
}
}
static void PrintRLength(const uint64_t cputype, const unsigned r_type,
const unsigned r_length, const bool previous_arm_half){
if (cputype == MachO::CPU_TYPE_ARM &&
(r_type == llvm::MachO::ARM_RELOC_HALF ||
r_type == llvm::MachO::ARM_RELOC_HALF_SECTDIFF ||
previous_arm_half == true)) {
if ((r_length & 0x1) == 0)
outs() << "lo/";
else
outs() << "hi/";
if ((r_length & 0x1) == 0)
outs() << "arm ";
else
outs() << "thm ";
} else {
switch (r_length) {
case 0:
outs() << "byte ";
break;
case 1:
outs() << "word ";
break;
case 2:
outs() << "long ";
break;
case 3:
if (cputype == MachO::CPU_TYPE_X86_64)
outs() << "quad ";
else
outs() << format("?(%2d) ", r_length);
break;
default:
outs() << format("?(%2d) ", r_length);
}
}
}
static void PrintRelocationEntries(const MachOObjectFile *O,
const relocation_iterator Begin,
const relocation_iterator End,
const uint64_t cputype,
const bool verbose) {
const MachO::symtab_command Symtab = O->getSymtabLoadCommand();
bool previous_arm_half = false;
bool previous_sectdiff = false;
uint32_t sectdiff_r_type = 0;
for (relocation_iterator Reloc = Begin; Reloc != End; ++Reloc) {
const DataRefImpl Rel = Reloc->getRawDataRefImpl();
const MachO::any_relocation_info RE = O->getRelocation(Rel);
const unsigned r_type = O->getAnyRelocationType(RE);
const bool r_scattered = O->isRelocationScattered(RE);
const unsigned r_pcrel = O->getAnyRelocationPCRel(RE);
const unsigned r_length = O->getAnyRelocationLength(RE);
const unsigned r_address = O->getAnyRelocationAddress(RE);
const bool r_extern = (r_scattered ? false :
O->getPlainRelocationExternal(RE));
const uint32_t r_value = (r_scattered ?
O->getScatteredRelocationValue(RE) : 0);
const unsigned r_symbolnum = (r_scattered ? 0 :
O->getPlainRelocationSymbolNum(RE));
if (r_scattered && cputype != MachO::CPU_TYPE_X86_64) {
if (verbose) {
// scattered: address
if ((cputype == MachO::CPU_TYPE_I386 &&
r_type == llvm::MachO::GENERIC_RELOC_PAIR) ||
(cputype == MachO::CPU_TYPE_ARM &&
r_type == llvm::MachO::ARM_RELOC_PAIR))
outs() << " ";
else
outs() << format("%08x ", (unsigned int)r_address);
// scattered: pcrel
if (r_pcrel)
outs() << "True ";
else
outs() << "False ";
// scattered: length
PrintRLength(cputype, r_type, r_length, previous_arm_half);
// scattered: extern & type
outs() << "n/a ";
PrintRType(cputype, r_type);
// scattered: scattered & value
outs() << format("True 0x%08x", (unsigned int)r_value);
if (previous_sectdiff == false) {
if ((cputype == MachO::CPU_TYPE_ARM &&
r_type == llvm::MachO::ARM_RELOC_PAIR))
outs() << format(" half = 0x%04x ", (unsigned int)r_address);
}
else if (cputype == MachO::CPU_TYPE_ARM &&
sectdiff_r_type == llvm::MachO::ARM_RELOC_HALF_SECTDIFF)
outs() << format(" other_half = 0x%04x ", (unsigned int)r_address);
if ((cputype == MachO::CPU_TYPE_I386 &&
(r_type == llvm::MachO::GENERIC_RELOC_SECTDIFF ||
r_type == llvm::MachO::GENERIC_RELOC_LOCAL_SECTDIFF)) ||
(cputype == MachO::CPU_TYPE_ARM &&
(sectdiff_r_type == llvm::MachO::ARM_RELOC_SECTDIFF ||
sectdiff_r_type == llvm::MachO::ARM_RELOC_LOCAL_SECTDIFF ||
sectdiff_r_type == llvm::MachO::ARM_RELOC_HALF_SECTDIFF))) {
previous_sectdiff = true;
sectdiff_r_type = r_type;
}
else {
previous_sectdiff = false;
sectdiff_r_type = 0;
}
if (cputype == MachO::CPU_TYPE_ARM &&
(r_type == llvm::MachO::ARM_RELOC_HALF ||
r_type == llvm::MachO::ARM_RELOC_HALF_SECTDIFF))
previous_arm_half = true;
else
previous_arm_half = false;
outs() << "\n";
}
else {
// scattered: address pcrel length extern type scattered value
outs() << format("%08x %1d %-2d n/a %-7d 1 0x%08x\n",
(unsigned int)r_address, r_pcrel, r_length, r_type,
(unsigned int)r_value);
}
}
else {
if (verbose) {
// plain: address
if (cputype == MachO::CPU_TYPE_ARM &&
r_type == llvm::MachO::ARM_RELOC_PAIR)
outs() << " ";
else
outs() << format("%08x ", (unsigned int)r_address);
// plain: pcrel
if (r_pcrel)
outs() << "True ";
else
outs() << "False ";
// plain: length
PrintRLength(cputype, r_type, r_length, previous_arm_half);
if (r_extern) {
// plain: extern & type & scattered
outs() << "True ";
PrintRType(cputype, r_type);
outs() << "False ";
// plain: symbolnum/value
if (r_symbolnum > Symtab.nsyms)
outs() << format("?(%d)\n", r_symbolnum);
else {
SymbolRef Symbol = *O->getSymbolByIndex(r_symbolnum);
Expected<StringRef> SymNameNext = Symbol.getName();
const char *name = NULL;
if (SymNameNext)
name = SymNameNext->data();
if (name == NULL)
outs() << format("?(%d)\n", r_symbolnum);
else
outs() << name << "\n";
}
}
else {
// plain: extern & type & scattered
outs() << "False ";
PrintRType(cputype, r_type);
outs() << "False ";
// plain: symbolnum/value
if (cputype == MachO::CPU_TYPE_ARM &&
r_type == llvm::MachO::ARM_RELOC_PAIR)
outs() << format("other_half = 0x%04x\n", (unsigned int)r_address);
else if (cputype == MachO::CPU_TYPE_ARM64 &&
r_type == llvm::MachO::ARM64_RELOC_ADDEND)
outs() << format("addend = 0x%06x\n", (unsigned int)r_symbolnum);
else {
outs() << format("%d ", r_symbolnum);
if (r_symbolnum == llvm::MachO::R_ABS)
outs() << "R_ABS\n";
else {
// in this case, r_symbolnum is actually a 1-based section number
uint32_t nsects = O->section_end()->getRawDataRefImpl().d.a;
if (r_symbolnum > 0 && r_symbolnum <= nsects) {
llvm::object::DataRefImpl DRI;
DRI.d.a = r_symbolnum-1;
StringRef SegName = O->getSectionFinalSegmentName(DRI);
StringRef SectName;
if (O->getSectionName(DRI, SectName))
outs() << "(?,?)\n";
else
outs() << "(" << SegName << "," << SectName << ")\n";
}
else {
outs() << "(?,?)\n";
}
}
}
}
if (cputype == MachO::CPU_TYPE_ARM &&
(r_type == llvm::MachO::ARM_RELOC_HALF ||
r_type == llvm::MachO::ARM_RELOC_HALF_SECTDIFF))
previous_arm_half = true;
else
previous_arm_half = false;
}
else {
// plain: address pcrel length extern type scattered symbolnum/section
outs() << format("%08x %1d %-2d %1d %-7d 0 %d\n",
(unsigned int)r_address, r_pcrel, r_length, r_extern,
r_type, r_symbolnum);
}
}
}
}
static void PrintRelocations(const MachOObjectFile *O, const bool verbose) {
const uint64_t cputype = O->getHeader().cputype;
const MachO::dysymtab_command Dysymtab = O->getDysymtabLoadCommand();
if (Dysymtab.nextrel != 0) {
outs() << "External relocation information " << Dysymtab.nextrel
<< " entries";
outs() << "\naddress pcrel length extern type scattered "
"symbolnum/value\n";
PrintRelocationEntries(O, O->extrel_begin(), O->extrel_end(), cputype,
verbose);
}
if (Dysymtab.nlocrel != 0) {
outs() << format("Local relocation information %u entries",
Dysymtab.nlocrel);
outs() << "\naddress pcrel length extern type scattered "
"symbolnum/value\n";
PrintRelocationEntries(O, O->locrel_begin(), O->locrel_end(), cputype,
verbose);
}
for (const auto &Load : O->load_commands()) {
if (Load.C.cmd == MachO::LC_SEGMENT_64) {
const MachO::segment_command_64 Seg = O->getSegment64LoadCommand(Load);
for (unsigned J = 0; J < Seg.nsects; ++J) {
const MachO::section_64 Sec = O->getSection64(Load, J);
if (Sec.nreloc != 0) {
DataRefImpl DRI;
DRI.d.a = J;
const StringRef SegName = O->getSectionFinalSegmentName(DRI);
StringRef SectName;
if (O->getSectionName(DRI, SectName))
outs() << "Relocation information (" << SegName << ",?) "
<< format("%u entries", Sec.nreloc);
else
outs() << "Relocation information (" << SegName << ","
<< SectName << format(") %u entries", Sec.nreloc);
outs() << "\naddress pcrel length extern type scattered "
"symbolnum/value\n";
PrintRelocationEntries(O, O->section_rel_begin(DRI),
O->section_rel_end(DRI), cputype, verbose);
}
}
} else if (Load.C.cmd == MachO::LC_SEGMENT) {
const MachO::segment_command Seg = O->getSegmentLoadCommand(Load);
for (unsigned J = 0; J < Seg.nsects; ++J) {
const MachO::section Sec = O->getSection(Load, J);
if (Sec.nreloc != 0) {
DataRefImpl DRI;
DRI.d.a = J;
const StringRef SegName = O->getSectionFinalSegmentName(DRI);
StringRef SectName;
if (O->getSectionName(DRI, SectName))
outs() << "Relocation information (" << SegName << ",?) "
<< format("%u entries", Sec.nreloc);
else
outs() << "Relocation information (" << SegName << ","
<< SectName << format(") %u entries", Sec.nreloc);
outs() << "\naddress pcrel length extern type scattered "
"symbolnum/value\n";
PrintRelocationEntries(O, O->section_rel_begin(DRI),
O->section_rel_end(DRI), cputype, verbose);
}
}
}
}
}
static void PrintDataInCodeTable(MachOObjectFile *O, bool verbose) {
MachO::linkedit_data_command DIC = O->getDataInCodeLoadCommand();
uint32_t nentries = DIC.datasize / sizeof(struct MachO::data_in_code_entry);
@ -1221,9 +1548,10 @@ static void ProcessMachO(StringRef Name, MachOObjectFile *MachOOF,
// If we are doing some processing here on the Mach-O file print the header
// info. And don't print it otherwise like in the case of printing the
// UniversalHeaders or ArchiveHeaders.
if (Disassemble || PrivateHeaders || ExportsTrie || Rebase || Bind || SymbolTable ||
LazyBind || WeakBind || IndirectSymbols || DataInCode || LinkOptHints ||
DylibsUsed || DylibId || ObjcMetaData || (FilterSections.size() != 0)) {
if (Disassemble || Relocations || PrivateHeaders || ExportsTrie || Rebase ||
Bind || SymbolTable || LazyBind || WeakBind || IndirectSymbols ||
DataInCode || LinkOptHints || DylibsUsed || DylibId || ObjcMetaData ||
(FilterSections.size() != 0)) {
if (!NoLeadingHeaders) {
outs() << Name;
if (!ArchiveMemberName.empty())
@ -1267,7 +1595,7 @@ static void ProcessMachO(StringRef Name, MachOObjectFile *MachOOF,
if (LinkOptHints)
PrintLinkOptHints(MachOOF);
if (Relocations)
PrintRelocations(MachOOF);
PrintRelocations(MachOOF, !NonVerbose);
if (SectionHeaders)
PrintSectionHeaders(MachOOF);
if (SectionContents)