forked from OSchip/llvm-project
[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:
parent
77364be497
commit
c196488531
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue