[llvm-objdump] - Move getRelocationValueString and dependenices out of the llvm-objdump.cpp

getRelocationValueString is a dispatcher function that calls the
corresponding ELF/COFF/Wasm/MachO implementations
that currently live in the llvm-objdump.cpp file.

These implementations better be moved to ELFDump.cpp,
COFFDump.cpp and other corresponding files, to move platform specific
implementation out from the common logic.

The patch does that. Also, I had to move ToolSectionFilter helper
and SectionFilterIterator, SectionFilter to a header to make them
available across the objdump code.

Differential revision: https://reviews.llvm.org/D56842

llvm-svn: 351545
This commit is contained in:
George Rimar 2019-01-18 11:33:26 +00:00
parent 77364be497
commit c196488531
6 changed files with 459 additions and 433 deletions

View File

@ -469,6 +469,19 @@ static bool getPDataSection(const COFFObjectFile *Obj,
return false;
}
std::error_code
llvm::getCOFFRelocationValueString(const COFFObjectFile *Obj,
const RelocationRef &Rel,
SmallVectorImpl<char> &Result) {
symbol_iterator SymI = Rel.getSymbol();
Expected<StringRef> SymNameOrErr = SymI->getName();
if (!SymNameOrErr)
return errorToErrorCode(SymNameOrErr.takeError());
StringRef SymName = *SymNameOrErr;
Result.append(SymName.begin(), SymName.end());
return std::error_code();
}
static void printWin64EHUnwindInfo(const Win64EH::UnwindInfo *UI) {
// The casts to int are required in order to output the value as number.
// Without the casts the value would be interpreted as char data (which

View File

@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "llvm-objdump.h"
#include "llvm/Demangle/Demangle.h"
#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/MathExtras.h"
@ -51,6 +52,87 @@ Expected<StringRef> getDynamicStrTab(const ELFFile<ELFT> *Elf) {
return createError("dynamic string table not found");
}
template <class ELFT>
static std::error_code getRelocationValueString(const ELFObjectFile<ELFT> *Obj,
const RelocationRef &RelRef,
SmallVectorImpl<char> &Result) {
typedef typename ELFObjectFile<ELFT>::Elf_Sym Elf_Sym;
typedef typename ELFObjectFile<ELFT>::Elf_Shdr Elf_Shdr;
typedef typename ELFObjectFile<ELFT>::Elf_Rela Elf_Rela;
const ELFFile<ELFT> &EF = *Obj->getELFFile();
DataRefImpl Rel = RelRef.getRawDataRefImpl();
auto SecOrErr = EF.getSection(Rel.d.a);
if (!SecOrErr)
return errorToErrorCode(SecOrErr.takeError());
int64_t Addend = 0;
// If there is no Symbol associated with the relocation, we set the undef
// boolean value to 'true'. This will prevent us from calling functions that
// requires the relocation to be associated with a symbol.
//
// In SHT_REL case we would need to read the addend from section data.
// GNU objdump does not do that and we just follow for simplicity atm.
bool Undef = false;
if ((*SecOrErr)->sh_type == ELF::SHT_RELA) {
const Elf_Rela *ERela = Obj->getRela(Rel);
Addend = ERela->r_addend;
Undef = ERela->getSymbol(false) == 0;
} else if ((*SecOrErr)->sh_type != ELF::SHT_REL) {
return object_error::parse_failed;
}
// Default scheme is to print Target, as well as "+ <addend>" for nonzero
// addend. Should be acceptable for all normal purposes.
std::string FmtBuf;
raw_string_ostream Fmt(FmtBuf);
if (!Undef) {
symbol_iterator SI = RelRef.getSymbol();
const Elf_Sym *Sym = Obj->getSymbol(SI->getRawDataRefImpl());
if (Sym->getType() == ELF::STT_SECTION) {
Expected<section_iterator> SymSI = SI->getSection();
if (!SymSI)
return errorToErrorCode(SymSI.takeError());
const Elf_Shdr *SymSec = Obj->getSection((*SymSI)->getRawDataRefImpl());
auto SecName = EF.getSectionName(SymSec);
if (!SecName)
return errorToErrorCode(SecName.takeError());
Fmt << *SecName;
} else {
Expected<StringRef> SymName = SI->getName();
if (!SymName)
return errorToErrorCode(SymName.takeError());
if (Demangle)
Fmt << demangle(*SymName);
else
Fmt << *SymName;
}
} else {
Fmt << "*ABS*";
}
if (Addend != 0)
Fmt << (Addend < 0 ? "" : "+") << Addend;
Fmt.flush();
Result.append(FmtBuf.begin(), FmtBuf.end());
return std::error_code();
}
std::error_code
llvm::getELFRelocationValueString(const ELFObjectFileBase *Obj,
const RelocationRef &Rel,
SmallVectorImpl<char> &Result) {
if (auto *ELF32LE = dyn_cast<ELF32LEObjectFile>(Obj))
return getRelocationValueString(ELF32LE, Rel, Result);
if (auto *ELF64LE = dyn_cast<ELF64LEObjectFile>(Obj))
return getRelocationValueString(ELF64LE, Rel, Result);
if (auto *ELF32BE = dyn_cast<ELF32BEObjectFile>(Obj))
return getRelocationValueString(ELF32BE, Rel, Result);
auto *ELF64BE = cast<ELF64BEObjectFile>(Obj);
return getRelocationValueString(ELF64BE, Rel, Result);
}
template <class ELFT>
void printDynamicSection(const ELFFile<ELFT> *Elf, StringRef Filename) {
auto ProgramHeaderOrError = Elf->program_headers();

View File

@ -342,6 +342,264 @@ static void getSectionsAndSymbols(MachOObjectFile *MachOObj,
}
}
static void printRelocationTargetName(const MachOObjectFile *O,
const MachO::any_relocation_info &RE,
raw_string_ostream &Fmt) {
// Target of a scattered relocation is an address. In the interest of
// generating pretty output, scan through the symbol table looking for a
// symbol that aligns with that address. If we find one, print it.
// Otherwise, we just print the hex address of the target.
if (O->isRelocationScattered(RE)) {
uint32_t Val = O->getPlainRelocationSymbolNum(RE);
for (const SymbolRef &Symbol : O->symbols()) {
Expected<uint64_t> Addr = Symbol.getAddress();
if (!Addr)
report_error(O->getFileName(), Addr.takeError());
if (*Addr != Val)
continue;
Expected<StringRef> Name = Symbol.getName();
if (!Name)
report_error(O->getFileName(), Name.takeError());
Fmt << *Name;
return;
}
// If we couldn't find a symbol that this relocation refers to, try
// to find a section beginning instead.
for (const SectionRef &Section : ToolSectionFilter(*O)) {
std::error_code ec;
StringRef Name;
uint64_t Addr = Section.getAddress();
if (Addr != Val)
continue;
if ((ec = Section.getName(Name)))
report_error(O->getFileName(), ec);
Fmt << Name;
return;
}
Fmt << format("0x%x", Val);
return;
}
StringRef S;
bool isExtern = O->getPlainRelocationExternal(RE);
uint64_t Val = O->getPlainRelocationSymbolNum(RE);
if (O->getAnyRelocationType(RE) == MachO::ARM64_RELOC_ADDEND) {
Fmt << format("0x%0" PRIx64, Val);
return;
}
if (isExtern) {
symbol_iterator SI = O->symbol_begin();
advance(SI, Val);
Expected<StringRef> SOrErr = SI->getName();
if (!SOrErr)
report_error(O->getFileName(), SOrErr.takeError());
S = *SOrErr;
} else {
section_iterator SI = O->section_begin();
// Adjust for the fact that sections are 1-indexed.
if (Val == 0) {
Fmt << "0 (?,?)";
return;
}
uint32_t I = Val - 1;
while (I != 0 && SI != O->section_end()) {
--I;
advance(SI, 1);
}
if (SI == O->section_end())
Fmt << Val << " (?,?)";
else
SI->getName(S);
}
Fmt << S;
}
std::error_code
llvm::getMachORelocationValueString(const MachOObjectFile *Obj,
const RelocationRef &RelRef,
SmallVectorImpl<char> &Result) {
DataRefImpl Rel = RelRef.getRawDataRefImpl();
MachO::any_relocation_info RE = Obj->getRelocation(Rel);
unsigned Arch = Obj->getArch();
std::string FmtBuf;
raw_string_ostream Fmt(FmtBuf);
unsigned Type = Obj->getAnyRelocationType(RE);
bool IsPCRel = Obj->getAnyRelocationPCRel(RE);
// Determine any addends that should be displayed with the relocation.
// These require decoding the relocation type, which is triple-specific.
// X86_64 has entirely custom relocation types.
if (Arch == Triple::x86_64) {
switch (Type) {
case MachO::X86_64_RELOC_GOT_LOAD:
case MachO::X86_64_RELOC_GOT: {
printRelocationTargetName(Obj, RE, Fmt);
Fmt << "@GOT";
if (IsPCRel)
Fmt << "PCREL";
break;
}
case MachO::X86_64_RELOC_SUBTRACTOR: {
DataRefImpl RelNext = Rel;
Obj->moveRelocationNext(RelNext);
MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);
// X86_64_RELOC_SUBTRACTOR must be followed by a relocation of type
// X86_64_RELOC_UNSIGNED.
// NOTE: Scattered relocations don't exist on x86_64.
unsigned RType = Obj->getAnyRelocationType(RENext);
if (RType != MachO::X86_64_RELOC_UNSIGNED)
report_error(Obj->getFileName(), "Expected X86_64_RELOC_UNSIGNED after "
"X86_64_RELOC_SUBTRACTOR.");
// The X86_64_RELOC_UNSIGNED contains the minuend symbol;
// X86_64_RELOC_SUBTRACTOR contains the subtrahend.
printRelocationTargetName(Obj, RENext, Fmt);
Fmt << "-";
printRelocationTargetName(Obj, RE, Fmt);
break;
}
case MachO::X86_64_RELOC_TLV:
printRelocationTargetName(Obj, RE, Fmt);
Fmt << "@TLV";
if (IsPCRel)
Fmt << "P";
break;
case MachO::X86_64_RELOC_SIGNED_1:
printRelocationTargetName(Obj, RE, Fmt);
Fmt << "-1";
break;
case MachO::X86_64_RELOC_SIGNED_2:
printRelocationTargetName(Obj, RE, Fmt);
Fmt << "-2";
break;
case MachO::X86_64_RELOC_SIGNED_4:
printRelocationTargetName(Obj, RE, Fmt);
Fmt << "-4";
break;
default:
printRelocationTargetName(Obj, RE, Fmt);
break;
}
// X86 and ARM share some relocation types in common.
} else if (Arch == Triple::x86 || Arch == Triple::arm ||
Arch == Triple::ppc) {
// Generic relocation types...
switch (Type) {
case MachO::GENERIC_RELOC_PAIR: // prints no info
return std::error_code();
case MachO::GENERIC_RELOC_SECTDIFF: {
DataRefImpl RelNext = Rel;
Obj->moveRelocationNext(RelNext);
MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);
// X86 sect diff's must be followed by a relocation of type
// GENERIC_RELOC_PAIR.
unsigned RType = Obj->getAnyRelocationType(RENext);
if (RType != MachO::GENERIC_RELOC_PAIR)
report_error(Obj->getFileName(), "Expected GENERIC_RELOC_PAIR after "
"GENERIC_RELOC_SECTDIFF.");
printRelocationTargetName(Obj, RE, Fmt);
Fmt << "-";
printRelocationTargetName(Obj, RENext, Fmt);
break;
}
}
if (Arch == Triple::x86 || Arch == Triple::ppc) {
switch (Type) {
case MachO::GENERIC_RELOC_LOCAL_SECTDIFF: {
DataRefImpl RelNext = Rel;
Obj->moveRelocationNext(RelNext);
MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);
// X86 sect diff's must be followed by a relocation of type
// GENERIC_RELOC_PAIR.
unsigned RType = Obj->getAnyRelocationType(RENext);
if (RType != MachO::GENERIC_RELOC_PAIR)
report_error(Obj->getFileName(), "Expected GENERIC_RELOC_PAIR after "
"GENERIC_RELOC_LOCAL_SECTDIFF.");
printRelocationTargetName(Obj, RE, Fmt);
Fmt << "-";
printRelocationTargetName(Obj, RENext, Fmt);
break;
}
case MachO::GENERIC_RELOC_TLV: {
printRelocationTargetName(Obj, RE, Fmt);
Fmt << "@TLV";
if (IsPCRel)
Fmt << "P";
break;
}
default:
printRelocationTargetName(Obj, RE, Fmt);
}
} else { // ARM-specific relocations
switch (Type) {
case MachO::ARM_RELOC_HALF:
case MachO::ARM_RELOC_HALF_SECTDIFF: {
// Half relocations steal a bit from the length field to encode
// whether this is an upper16 or a lower16 relocation.
bool isUpper = (Obj->getAnyRelocationLength(RE) & 0x1) == 1;
if (isUpper)
Fmt << ":upper16:(";
else
Fmt << ":lower16:(";
printRelocationTargetName(Obj, RE, Fmt);
DataRefImpl RelNext = Rel;
Obj->moveRelocationNext(RelNext);
MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);
// ARM half relocs must be followed by a relocation of type
// ARM_RELOC_PAIR.
unsigned RType = Obj->getAnyRelocationType(RENext);
if (RType != MachO::ARM_RELOC_PAIR)
report_error(Obj->getFileName(), "Expected ARM_RELOC_PAIR after "
"ARM_RELOC_HALF");
// NOTE: The half of the target virtual address is stashed in the
// address field of the secondary relocation, but we can't reverse
// engineer the constant offset from it without decoding the movw/movt
// instruction to find the other half in its immediate field.
// ARM_RELOC_HALF_SECTDIFF encodes the second section in the
// symbol/section pointer of the follow-on relocation.
if (Type == MachO::ARM_RELOC_HALF_SECTDIFF) {
Fmt << "-";
printRelocationTargetName(Obj, RENext, Fmt);
}
Fmt << ")";
break;
}
default: {
printRelocationTargetName(Obj, RE, Fmt);
}
}
}
} else
printRelocationTargetName(Obj, RE, Fmt);
Fmt.flush();
Result.append(FmtBuf.begin(), FmtBuf.end());
return std::error_code();
}
static void PrintIndirectSymbolTable(MachOObjectFile *O, bool verbose,
uint32_t n, uint32_t count,
uint32_t stride, uint64_t addr) {

View File

@ -26,3 +26,28 @@ void llvm::printWasmFileHeader(const object::ObjectFile *Obj) {
outs().write_hex(File->getHeader().Version);
outs() << "\n";
}
std::error_code
llvm::getWasmRelocationValueString(const WasmObjectFile *Obj,
const RelocationRef &RelRef,
SmallVectorImpl<char> &Result) {
const wasm::WasmRelocation &Rel = Obj->getWasmRelocation(RelRef);
symbol_iterator SI = RelRef.getSymbol();
std::string FmtBuf;
raw_string_ostream Fmt(FmtBuf);
if (SI == Obj->symbol_end()) {
// Not all wasm relocations have symbols associated with them.
// In particular R_WEBASSEMBLY_TYPE_INDEX_LEB.
Fmt << Rel.Index;
} else {
Expected<StringRef> SymNameOrErr = SI->getName();
if (!SymNameOrErr)
return errorToErrorCode(SymNameOrErr.takeError());
StringRef SymName = *SymNameOrErr;
Result.append(SymName.begin(), SymName.end());
}
Fmt << (Rel.Addend < 0 ? "" : "+") << Rel.Addend;
Fmt.flush();
Result.append(FmtBuf.begin(), FmtBuf.end());
return std::error_code();
}

View File

@ -281,56 +281,7 @@ static StringRef ToolName;
typedef std::vector<std::tuple<uint64_t, StringRef, uint8_t>> SectionSymbolsTy;
namespace {
typedef std::function<bool(llvm::object::SectionRef const &)> FilterPredicate;
class SectionFilterIterator {
public:
SectionFilterIterator(FilterPredicate P,
llvm::object::section_iterator const &I,
llvm::object::section_iterator const &E)
: Predicate(std::move(P)), Iterator(I), End(E) {
ScanPredicate();
}
const llvm::object::SectionRef &operator*() const { return *Iterator; }
SectionFilterIterator &operator++() {
++Iterator;
ScanPredicate();
return *this;
}
bool operator!=(SectionFilterIterator const &Other) const {
return Iterator != Other.Iterator;
}
private:
void ScanPredicate() {
while (Iterator != End && !Predicate(*Iterator)) {
++Iterator;
}
}
FilterPredicate Predicate;
llvm::object::section_iterator Iterator;
llvm::object::section_iterator End;
};
class SectionFilter {
public:
SectionFilter(FilterPredicate P, llvm::object::ObjectFile const &O)
: Predicate(std::move(P)), Object(O) {}
SectionFilterIterator begin() {
return SectionFilterIterator(Predicate, Object.section_begin(),
Object.section_end());
}
SectionFilterIterator end() {
return SectionFilterIterator(Predicate, Object.section_end(),
Object.section_end());
}
private:
FilterPredicate Predicate;
llvm::object::ObjectFile const &Object;
};
SectionFilter ToolSectionFilter(llvm::object::ObjectFile const &O) {
SectionFilter llvm::ToolSectionFilter(llvm::object::ObjectFile const &O) {
return SectionFilter(
[](llvm::object::SectionRef const &S) {
if (FilterSections.empty())
@ -343,7 +294,6 @@ SectionFilter ToolSectionFilter(llvm::object::ObjectFile const &O) {
},
O);
}
}
void llvm::error(std::error_code EC) {
if (!EC)
@ -464,388 +414,17 @@ bool llvm::isRelocAddressLess(RelocationRef A, RelocationRef B) {
return A.getOffset() < B.getOffset();
}
template <class ELFT>
static std::error_code getRelocationValueString(const ELFObjectFile<ELFT> *Obj,
const RelocationRef &RelRef,
SmallVectorImpl<char> &Result) {
typedef typename ELFObjectFile<ELFT>::Elf_Sym Elf_Sym;
typedef typename ELFObjectFile<ELFT>::Elf_Shdr Elf_Shdr;
typedef typename ELFObjectFile<ELFT>::Elf_Rela Elf_Rela;
const ELFFile<ELFT> &EF = *Obj->getELFFile();
DataRefImpl Rel = RelRef.getRawDataRefImpl();
auto SecOrErr = EF.getSection(Rel.d.a);
if (!SecOrErr)
return errorToErrorCode(SecOrErr.takeError());
int64_t Addend = 0;
// If there is no Symbol associated with the relocation, we set the undef
// boolean value to 'true'. This will prevent us from calling functions that
// requires the relocation to be associated with a symbol.
//
// In SHT_REL case we would need to read the addend from section data.
// GNU objdump does not do that and we just follow for simplicity.
bool Undef = false;
if ((*SecOrErr)->sh_type == ELF::SHT_RELA) {
const Elf_Rela *ERela = Obj->getRela(Rel);
Addend = ERela->r_addend;
Undef = ERela->getSymbol(false) == 0;
} else if ((*SecOrErr)->sh_type != ELF::SHT_REL) {
return object_error::parse_failed;
}
// Default scheme is to print Target, as well as "+ <addend>" for nonzero
// addend. Should be acceptable for all normal purposes.
std::string FmtBuf;
raw_string_ostream Fmt(FmtBuf);
if (!Undef) {
symbol_iterator SI = RelRef.getSymbol();
const Elf_Sym *Sym = Obj->getSymbol(SI->getRawDataRefImpl());
if (Sym->getType() == ELF::STT_SECTION) {
Expected<section_iterator> SymSI = SI->getSection();
if (!SymSI)
return errorToErrorCode(SymSI.takeError());
const Elf_Shdr *SymSec = Obj->getSection((*SymSI)->getRawDataRefImpl());
auto SecName = EF.getSectionName(SymSec);
if (!SecName)
return errorToErrorCode(SecName.takeError());
Fmt << *SecName;
} else {
Expected<StringRef> SymName = SI->getName();
if (!SymName)
return errorToErrorCode(SymName.takeError());
if (Demangle)
Fmt << demangle(*SymName);
else
Fmt << *SymName;
}
} else {
Fmt << "*ABS*";
}
if (Addend != 0)
Fmt << (Addend < 0 ? "" : "+") << Addend;
Fmt.flush();
Result.append(FmtBuf.begin(), FmtBuf.end());
return std::error_code();
}
static std::error_code getRelocationValueString(const ELFObjectFileBase *Obj,
const RelocationRef &Rel,
SmallVectorImpl<char> &Result) {
if (auto *ELF32LE = dyn_cast<ELF32LEObjectFile>(Obj))
return getRelocationValueString(ELF32LE, Rel, Result);
if (auto *ELF64LE = dyn_cast<ELF64LEObjectFile>(Obj))
return getRelocationValueString(ELF64LE, Rel, Result);
if (auto *ELF32BE = dyn_cast<ELF32BEObjectFile>(Obj))
return getRelocationValueString(ELF32BE, Rel, Result);
auto *ELF64BE = cast<ELF64BEObjectFile>(Obj);
return getRelocationValueString(ELF64BE, Rel, Result);
}
static std::error_code getRelocationValueString(const COFFObjectFile *Obj,
const RelocationRef &Rel,
SmallVectorImpl<char> &Result) {
symbol_iterator SymI = Rel.getSymbol();
Expected<StringRef> SymNameOrErr = SymI->getName();
if (!SymNameOrErr)
return errorToErrorCode(SymNameOrErr.takeError());
StringRef SymName = *SymNameOrErr;
Result.append(SymName.begin(), SymName.end());
return std::error_code();
}
static void printRelocationTargetName(const MachOObjectFile *O,
const MachO::any_relocation_info &RE,
raw_string_ostream &Fmt) {
// Target of a scattered relocation is an address. In the interest of
// generating pretty output, scan through the symbol table looking for a
// symbol that aligns with that address. If we find one, print it.
// Otherwise, we just print the hex address of the target.
if (O->isRelocationScattered(RE)) {
uint32_t Val = O->getPlainRelocationSymbolNum(RE);
for (const SymbolRef &Symbol : O->symbols()) {
Expected<uint64_t> Addr = Symbol.getAddress();
if (!Addr)
report_error(O->getFileName(), Addr.takeError());
if (*Addr != Val)
continue;
Expected<StringRef> Name = Symbol.getName();
if (!Name)
report_error(O->getFileName(), Name.takeError());
Fmt << *Name;
return;
}
// If we couldn't find a symbol that this relocation refers to, try
// to find a section beginning instead.
for (const SectionRef &Section : ToolSectionFilter(*O)) {
std::error_code ec;
StringRef Name;
uint64_t Addr = Section.getAddress();
if (Addr != Val)
continue;
if ((ec = Section.getName(Name)))
report_error(O->getFileName(), ec);
Fmt << Name;
return;
}
Fmt << format("0x%x", Val);
return;
}
StringRef S;
bool isExtern = O->getPlainRelocationExternal(RE);
uint64_t Val = O->getPlainRelocationSymbolNum(RE);
if (O->getAnyRelocationType(RE) == MachO::ARM64_RELOC_ADDEND) {
Fmt << format("0x%0" PRIx64, Val);
return;
}
if (isExtern) {
symbol_iterator SI = O->symbol_begin();
advance(SI, Val);
Expected<StringRef> SOrErr = SI->getName();
if (!SOrErr)
report_error(O->getFileName(), SOrErr.takeError());
S = *SOrErr;
} else {
section_iterator SI = O->section_begin();
// Adjust for the fact that sections are 1-indexed.
if (Val == 0) {
Fmt << "0 (?,?)";
return;
}
uint32_t I = Val - 1;
while (I != 0 && SI != O->section_end()) {
--I;
advance(SI, 1);
}
if (SI == O->section_end())
Fmt << Val << " (?,?)";
else
SI->getName(S);
}
Fmt << S;
}
static std::error_code getRelocationValueString(const WasmObjectFile *Obj,
const RelocationRef &RelRef,
SmallVectorImpl<char> &Result) {
const wasm::WasmRelocation& Rel = Obj->getWasmRelocation(RelRef);
symbol_iterator SI = RelRef.getSymbol();
std::string FmtBuf;
raw_string_ostream Fmt(FmtBuf);
if (SI == Obj->symbol_end()) {
// Not all wasm relocations have symbols associated with them.
// In particular R_WEBASSEMBLY_TYPE_INDEX_LEB.
Fmt << Rel.Index;
} else {
Expected<StringRef> SymNameOrErr = SI->getName();
if (!SymNameOrErr)
return errorToErrorCode(SymNameOrErr.takeError());
StringRef SymName = *SymNameOrErr;
Result.append(SymName.begin(), SymName.end());
}
Fmt << (Rel.Addend < 0 ? "" : "+") << Rel.Addend;
Fmt.flush();
Result.append(FmtBuf.begin(), FmtBuf.end());
return std::error_code();
}
static std::error_code getRelocationValueString(const MachOObjectFile *Obj,
const RelocationRef &RelRef,
SmallVectorImpl<char> &Result) {
DataRefImpl Rel = RelRef.getRawDataRefImpl();
MachO::any_relocation_info RE = Obj->getRelocation(Rel);
unsigned Arch = Obj->getArch();
std::string FmtBuf;
raw_string_ostream Fmt(FmtBuf);
unsigned Type = Obj->getAnyRelocationType(RE);
bool IsPCRel = Obj->getAnyRelocationPCRel(RE);
// Determine any addends that should be displayed with the relocation.
// These require decoding the relocation type, which is triple-specific.
// X86_64 has entirely custom relocation types.
if (Arch == Triple::x86_64) {
switch (Type) {
case MachO::X86_64_RELOC_GOT_LOAD:
case MachO::X86_64_RELOC_GOT: {
printRelocationTargetName(Obj, RE, Fmt);
Fmt << "@GOT";
if (IsPCRel)
Fmt << "PCREL";
break;
}
case MachO::X86_64_RELOC_SUBTRACTOR: {
DataRefImpl RelNext = Rel;
Obj->moveRelocationNext(RelNext);
MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);
// X86_64_RELOC_SUBTRACTOR must be followed by a relocation of type
// X86_64_RELOC_UNSIGNED.
// NOTE: Scattered relocations don't exist on x86_64.
unsigned RType = Obj->getAnyRelocationType(RENext);
if (RType != MachO::X86_64_RELOC_UNSIGNED)
report_error(Obj->getFileName(), "Expected X86_64_RELOC_UNSIGNED after "
"X86_64_RELOC_SUBTRACTOR.");
// The X86_64_RELOC_UNSIGNED contains the minuend symbol;
// X86_64_RELOC_SUBTRACTOR contains the subtrahend.
printRelocationTargetName(Obj, RENext, Fmt);
Fmt << "-";
printRelocationTargetName(Obj, RE, Fmt);
break;
}
case MachO::X86_64_RELOC_TLV:
printRelocationTargetName(Obj, RE, Fmt);
Fmt << "@TLV";
if (IsPCRel)
Fmt << "P";
break;
case MachO::X86_64_RELOC_SIGNED_1:
printRelocationTargetName(Obj, RE, Fmt);
Fmt << "-1";
break;
case MachO::X86_64_RELOC_SIGNED_2:
printRelocationTargetName(Obj, RE, Fmt);
Fmt << "-2";
break;
case MachO::X86_64_RELOC_SIGNED_4:
printRelocationTargetName(Obj, RE, Fmt);
Fmt << "-4";
break;
default:
printRelocationTargetName(Obj, RE, Fmt);
break;
}
// X86 and ARM share some relocation types in common.
} else if (Arch == Triple::x86 || Arch == Triple::arm ||
Arch == Triple::ppc) {
// Generic relocation types...
switch (Type) {
case MachO::GENERIC_RELOC_PAIR: // prints no info
return std::error_code();
case MachO::GENERIC_RELOC_SECTDIFF: {
DataRefImpl RelNext = Rel;
Obj->moveRelocationNext(RelNext);
MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);
// X86 sect diff's must be followed by a relocation of type
// GENERIC_RELOC_PAIR.
unsigned RType = Obj->getAnyRelocationType(RENext);
if (RType != MachO::GENERIC_RELOC_PAIR)
report_error(Obj->getFileName(), "Expected GENERIC_RELOC_PAIR after "
"GENERIC_RELOC_SECTDIFF.");
printRelocationTargetName(Obj, RE, Fmt);
Fmt << "-";
printRelocationTargetName(Obj, RENext, Fmt);
break;
}
}
if (Arch == Triple::x86 || Arch == Triple::ppc) {
switch (Type) {
case MachO::GENERIC_RELOC_LOCAL_SECTDIFF: {
DataRefImpl RelNext = Rel;
Obj->moveRelocationNext(RelNext);
MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);
// X86 sect diff's must be followed by a relocation of type
// GENERIC_RELOC_PAIR.
unsigned RType = Obj->getAnyRelocationType(RENext);
if (RType != MachO::GENERIC_RELOC_PAIR)
report_error(Obj->getFileName(), "Expected GENERIC_RELOC_PAIR after "
"GENERIC_RELOC_LOCAL_SECTDIFF.");
printRelocationTargetName(Obj, RE, Fmt);
Fmt << "-";
printRelocationTargetName(Obj, RENext, Fmt);
break;
}
case MachO::GENERIC_RELOC_TLV: {
printRelocationTargetName(Obj, RE, Fmt);
Fmt << "@TLV";
if (IsPCRel)
Fmt << "P";
break;
}
default:
printRelocationTargetName(Obj, RE, Fmt);
}
} else { // ARM-specific relocations
switch (Type) {
case MachO::ARM_RELOC_HALF:
case MachO::ARM_RELOC_HALF_SECTDIFF: {
// Half relocations steal a bit from the length field to encode
// whether this is an upper16 or a lower16 relocation.
bool isUpper = (Obj->getAnyRelocationLength(RE) & 0x1) == 1;
if (isUpper)
Fmt << ":upper16:(";
else
Fmt << ":lower16:(";
printRelocationTargetName(Obj, RE, Fmt);
DataRefImpl RelNext = Rel;
Obj->moveRelocationNext(RelNext);
MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);
// ARM half relocs must be followed by a relocation of type
// ARM_RELOC_PAIR.
unsigned RType = Obj->getAnyRelocationType(RENext);
if (RType != MachO::ARM_RELOC_PAIR)
report_error(Obj->getFileName(), "Expected ARM_RELOC_PAIR after "
"ARM_RELOC_HALF");
// NOTE: The half of the target virtual address is stashed in the
// address field of the secondary relocation, but we can't reverse
// engineer the constant offset from it without decoding the movw/movt
// instruction to find the other half in its immediate field.
// ARM_RELOC_HALF_SECTDIFF encodes the second section in the
// symbol/section pointer of the follow-on relocation.
if (Type == MachO::ARM_RELOC_HALF_SECTDIFF) {
Fmt << "-";
printRelocationTargetName(Obj, RENext, Fmt);
}
Fmt << ")";
break;
}
default: { printRelocationTargetName(Obj, RE, Fmt); }
}
}
} else
printRelocationTargetName(Obj, RE, Fmt);
Fmt.flush();
Result.append(FmtBuf.begin(), FmtBuf.end());
return std::error_code();
}
static std::error_code getRelocationValueString(const RelocationRef &Rel,
SmallVectorImpl<char> &Result) {
const ObjectFile *Obj = Rel.getObject();
if (auto *ELF = dyn_cast<ELFObjectFileBase>(Obj))
return getRelocationValueString(ELF, Rel, Result);
return getELFRelocationValueString(ELF, Rel, Result);
if (auto *COFF = dyn_cast<COFFObjectFile>(Obj))
return getRelocationValueString(COFF, Rel, Result);
return getCOFFRelocationValueString(COFF, Rel, Result);
if (auto *Wasm = dyn_cast<WasmObjectFile>(Obj))
return getRelocationValueString(Wasm, Rel, Result);
return getWasmRelocationValueString(Wasm, Rel, Result);
if (auto *MachO = dyn_cast<MachOObjectFile>(Obj))
return getRelocationValueString(MachO, Rel, Result);
return getMachORelocationValueString(MachO, Rel, Result);
llvm_unreachable("unknown object file format");
}

View File

@ -19,13 +19,14 @@ namespace llvm {
class StringRef;
namespace object {
class COFFObjectFile;
class COFFImportFile;
class MachOObjectFile;
class MachOUniversalBinary;
class ObjectFile;
class Archive;
class RelocationRef;
class COFFObjectFile;
class COFFImportFile;
class ELFObjectFileBase;
class MachOObjectFile;
class MachOUniversalBinary;
class ObjectFile;
class Archive;
class RelocationRef;
}
extern cl::opt<std::string> TripleName;
@ -68,7 +69,75 @@ extern cl::opt<bool> UnwindInfo;
extern cl::opt<bool> PrintImmHex;
extern cl::opt<DIDumpType> DwarfDumpType;
typedef std::function<bool(llvm::object::SectionRef const &)> FilterPredicate;
class SectionFilterIterator {
public:
SectionFilterIterator(FilterPredicate P,
llvm::object::section_iterator const &I,
llvm::object::section_iterator const &E)
: Predicate(std::move(P)), Iterator(I), End(E) {
ScanPredicate();
}
const llvm::object::SectionRef &operator*() const { return *Iterator; }
SectionFilterIterator &operator++() {
++Iterator;
ScanPredicate();
return *this;
}
bool operator!=(SectionFilterIterator const &Other) const {
return Iterator != Other.Iterator;
}
private:
void ScanPredicate() {
while (Iterator != End && !Predicate(*Iterator)) {
++Iterator;
}
}
FilterPredicate Predicate;
llvm::object::section_iterator Iterator;
llvm::object::section_iterator End;
};
class SectionFilter {
public:
SectionFilter(FilterPredicate P, llvm::object::ObjectFile const &O)
: Predicate(std::move(P)), Object(O) {}
SectionFilterIterator begin() {
return SectionFilterIterator(Predicate, Object.section_begin(),
Object.section_end());
}
SectionFilterIterator end() {
return SectionFilterIterator(Predicate, Object.section_end(),
Object.section_end());
}
private:
FilterPredicate Predicate;
llvm::object::ObjectFile const &Object;
};
// Various helper functions.
SectionFilter ToolSectionFilter(llvm::object::ObjectFile const &O);
std::error_code
getELFRelocationValueString(const object::ELFObjectFileBase *Obj,
const object::RelocationRef &Rel,
llvm::SmallVectorImpl<char> &Result);
std::error_code
getCOFFRelocationValueString(const object::COFFObjectFile *Obj,
const object::RelocationRef &Rel,
llvm::SmallVectorImpl<char> &Result);
std::error_code
getWasmRelocationValueString(const object::WasmObjectFile *Obj,
const object::RelocationRef &RelRef,
llvm::SmallVectorImpl<char> &Result);
std::error_code
getMachORelocationValueString(const object::MachOObjectFile *Obj,
const object::RelocationRef &RelRef,
llvm::SmallVectorImpl<char> &Result);
void error(std::error_code ec);
bool isRelocAddressLess(object::RelocationRef A, object::RelocationRef B);
void parseInputMachO(StringRef Filename);