forked from OSchip/llvm-project
[llvm-objdump] Add -R option
This option prints dynamic relocation entries of the given file Differential Revision: https://reviews.llvm.org/D47493 llvm-svn: 334196
This commit is contained in:
parent
01ef4c2c64
commit
cb0f043cec
|
@ -15,6 +15,7 @@
|
|||
#define LLVM_OBJECT_ELFOBJECTFILE_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
|
@ -83,6 +84,8 @@ public:
|
|||
SubtargetFeatures getRISCVFeatures() const;
|
||||
|
||||
void setARMSubArch(Triple &TheTriple) const override;
|
||||
|
||||
virtual uint16_t getEType() const = 0;
|
||||
};
|
||||
|
||||
class ELFSectionRef : public SectionRef {
|
||||
|
@ -200,6 +203,7 @@ ELFObjectFileBase::symbols() const {
|
|||
|
||||
template <class ELFT> class ELFObjectFile : public ELFObjectFileBase {
|
||||
uint16_t getEMachine() const override;
|
||||
uint16_t getEType() const override;
|
||||
uint64_t getSymbolSize(DataRefImpl Sym) const override;
|
||||
|
||||
public:
|
||||
|
@ -256,6 +260,7 @@ protected:
|
|||
bool isSectionVirtual(DataRefImpl Sec) const override;
|
||||
relocation_iterator section_rel_begin(DataRefImpl Sec) const override;
|
||||
relocation_iterator section_rel_end(DataRefImpl Sec) const override;
|
||||
std::vector<SectionRef> dynamic_relocation_sections() const override;
|
||||
section_iterator getRelocatedSection(DataRefImpl Sec) const override;
|
||||
|
||||
void moveRelocationNext(DataRefImpl &Rel) const override;
|
||||
|
@ -507,6 +512,10 @@ uint16_t ELFObjectFile<ELFT>::getEMachine() const {
|
|||
return EF.getHeader()->e_machine;
|
||||
}
|
||||
|
||||
template <class ELFT> uint16_t ELFObjectFile<ELFT>::getEType() const {
|
||||
return EF.getHeader()->e_type;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
uint64_t ELFObjectFile<ELFT>::getSymbolSize(DataRefImpl Sym) const {
|
||||
return getSymbol(Sym)->st_size;
|
||||
|
@ -711,6 +720,35 @@ bool ELFObjectFile<ELFT>::isSectionBSS(DataRefImpl Sec) const {
|
|||
EShdr->sh_type == ELF::SHT_NOBITS;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
std::vector<SectionRef>
|
||||
ELFObjectFile<ELFT>::dynamic_relocation_sections() const {
|
||||
std::vector<SectionRef> Res;
|
||||
std::vector<uintptr_t> Offsets;
|
||||
|
||||
auto SectionsOrErr = EF.sections();
|
||||
if (!SectionsOrErr)
|
||||
return Res;
|
||||
|
||||
for (const Elf_Shdr &Sec : *SectionsOrErr) {
|
||||
if (Sec.sh_type != ELF::SHT_DYNAMIC)
|
||||
continue;
|
||||
Elf_Dyn *Dynamic =
|
||||
reinterpret_cast<Elf_Dyn *>((uintptr_t)base() + Sec.sh_offset);
|
||||
for (; Dynamic->d_tag != ELF::DT_NULL; Dynamic++) {
|
||||
if (Dynamic->d_tag == ELF::DT_REL || Dynamic->d_tag == ELF::DT_RELA ||
|
||||
Dynamic->d_tag == ELF::DT_JMPREL) {
|
||||
Offsets.push_back(Dynamic->d_un.d_val);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const Elf_Shdr &Sec : *SectionsOrErr) {
|
||||
if (is_contained(Offsets, Sec.sh_offset))
|
||||
Res.emplace_back(toDRI(&Sec), this);
|
||||
}
|
||||
return Res;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
bool ELFObjectFile<ELFT>::isSectionVirtual(DataRefImpl Sec) const {
|
||||
return getSection(Sec)->sh_type == ELF::SHT_NOBITS;
|
||||
|
@ -792,8 +830,6 @@ ELFObjectFile<ELFT>::getRelocationSymbol(DataRefImpl Rel) const {
|
|||
|
||||
template <class ELFT>
|
||||
uint64_t ELFObjectFile<ELFT>::getRelocationOffset(DataRefImpl Rel) const {
|
||||
assert(EF.getHeader()->e_type == ELF::ET_REL &&
|
||||
"Only relocatable object files have relocation offsets");
|
||||
const Elf_Shdr *sec = getRelSection(Rel);
|
||||
if (sec->sh_type == ELF::SHT_REL)
|
||||
return getRel(Rel)->r_offset;
|
||||
|
|
|
@ -262,6 +262,10 @@ public:
|
|||
return getCommonSymbolSizeImpl(Symb);
|
||||
}
|
||||
|
||||
virtual std::vector<SectionRef> dynamic_relocation_sections() const {
|
||||
return std::vector<SectionRef>();
|
||||
}
|
||||
|
||||
using symbol_iterator_range = iterator_range<symbol_iterator>;
|
||||
symbol_iterator_range symbols() const {
|
||||
return symbol_iterator_range(symbol_begin(), symbol_end());
|
||||
|
|
|
@ -93,6 +93,13 @@ static StringSet<> DisasmFuncsSet;
|
|||
cl::opt<bool>
|
||||
llvm::Relocations("r", cl::desc("Display the relocation entries in the file"));
|
||||
|
||||
cl::opt<bool>
|
||||
llvm::DynamicRelocations("dynamic-reloc",
|
||||
cl::desc("Display the dynamic relocation entries in the file"));
|
||||
static cl::alias
|
||||
DynamicRelocationsd("R", cl::desc("Alias for --dynamic-reloc"),
|
||||
cl::aliasopt(DynamicRelocations));
|
||||
|
||||
cl::opt<bool>
|
||||
llvm::SectionContents("s", cl::desc("Display the content of each section"));
|
||||
|
||||
|
@ -431,6 +438,10 @@ static std::error_code getRelocationValueString(const ELFObjectFile<ELFT> *Obj,
|
|||
return errorToErrorCode(StrTabOrErr.takeError());
|
||||
StringRef StrTab = *StrTabOrErr;
|
||||
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.
|
||||
bool undef = false;
|
||||
switch (Sec->sh_type) {
|
||||
default:
|
||||
return object_error::parse_failed;
|
||||
|
@ -441,27 +452,31 @@ static std::error_code getRelocationValueString(const ELFObjectFile<ELFT> *Obj,
|
|||
case ELF::SHT_RELA: {
|
||||
const Elf_Rela *ERela = Obj->getRela(Rel);
|
||||
addend = ERela->r_addend;
|
||||
undef = ERela->getSymbol(false) == 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
symbol_iterator SI = RelRef.getSymbol();
|
||||
const Elf_Sym *symb = Obj->getSymbol(SI->getRawDataRefImpl());
|
||||
StringRef Target;
|
||||
if (symb->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());
|
||||
Target = *SecName;
|
||||
} else {
|
||||
Expected<StringRef> SymName = symb->getName(StrTab);
|
||||
if (!SymName)
|
||||
return errorToErrorCode(SymName.takeError());
|
||||
Target = *SymName;
|
||||
}
|
||||
if (!undef) {
|
||||
symbol_iterator SI = RelRef.getSymbol();
|
||||
const Elf_Sym *symb = Obj->getSymbol(SI->getRawDataRefImpl());
|
||||
if (symb->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());
|
||||
Target = *SecName;
|
||||
} else {
|
||||
Expected<StringRef> SymName = symb->getName(StrTab);
|
||||
if (!SymName)
|
||||
return errorToErrorCode(SymName.takeError());
|
||||
Target = *SymName;
|
||||
}
|
||||
} else
|
||||
Target = "*ABS*";
|
||||
|
||||
// Default scheme is to print Target, as well as "+ <addend>" for nonzero
|
||||
// addend. Should be acceptable for all normal purposes.
|
||||
|
@ -1727,6 +1742,41 @@ void llvm::PrintRelocations(const ObjectFile *Obj) {
|
|||
}
|
||||
}
|
||||
|
||||
void llvm::PrintDynamicRelocations(const ObjectFile *Obj) {
|
||||
|
||||
// For the moment, this option is for ELF only
|
||||
if (!Obj->isELF())
|
||||
return;
|
||||
|
||||
const auto *Elf = dyn_cast<ELFObjectFileBase>(Obj);
|
||||
|
||||
if (!Elf || Elf->getEType() != ELF::ET_DYN) {
|
||||
error("not a dynamic object");
|
||||
return;
|
||||
}
|
||||
|
||||
StringRef Fmt = Obj->getBytesInAddress() > 4 ? "%016" PRIx64 : "%08" PRIx64;
|
||||
|
||||
std::vector<SectionRef> DynRelSec = Obj->dynamic_relocation_sections();
|
||||
if (DynRelSec.empty())
|
||||
return;
|
||||
|
||||
outs() << "DYNAMIC RELOCATION RECORDS\n";
|
||||
for (const SectionRef &Section : DynRelSec) {
|
||||
if (Section.relocation_begin() == Section.relocation_end())
|
||||
continue;
|
||||
for (const RelocationRef &Reloc : Section.relocations()) {
|
||||
uint64_t address = Reloc.getOffset();
|
||||
SmallString<32> relocname;
|
||||
SmallString<32> valuestr;
|
||||
Reloc.getTypeName(relocname);
|
||||
error(getRelocationValueString(Reloc, valuestr));
|
||||
outs() << format(Fmt.data(), address) << " " << relocname << " "
|
||||
<< valuestr << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void llvm::PrintSectionHeaders(const ObjectFile *Obj) {
|
||||
outs() << "Sections:\n"
|
||||
"Idx Name Size Address Type\n";
|
||||
|
@ -2069,6 +2119,8 @@ static void DumpObject(ObjectFile *o, const Archive *a = nullptr) {
|
|||
DisassembleObject(o, Relocations);
|
||||
if (Relocations && !Disassemble)
|
||||
PrintRelocations(o);
|
||||
if (DynamicRelocations)
|
||||
PrintDynamicRelocations(o);
|
||||
if (SectionHeaders)
|
||||
PrintSectionHeaders(o);
|
||||
if (SectionContents)
|
||||
|
@ -2186,6 +2238,7 @@ int main(int argc, char **argv) {
|
|||
Disassemble = true;
|
||||
if (!Disassemble
|
||||
&& !Relocations
|
||||
&& !DynamicRelocations
|
||||
&& !SectionHeaders
|
||||
&& !SectionContents
|
||||
&& !SymbolTable
|
||||
|
|
|
@ -56,6 +56,7 @@ extern cl::opt<bool> ObjcMetaData;
|
|||
extern cl::opt<std::string> DisSymName;
|
||||
extern cl::opt<bool> NonVerbose;
|
||||
extern cl::opt<bool> Relocations;
|
||||
extern cl::opt<bool> DynamicRelocations;
|
||||
extern cl::opt<bool> SectionHeaders;
|
||||
extern cl::opt<bool> SectionContents;
|
||||
extern cl::opt<bool> SymbolTable;
|
||||
|
@ -88,6 +89,7 @@ void printLazyBindTable(object::ObjectFile *o);
|
|||
void printWeakBindTable(object::ObjectFile *o);
|
||||
void printRawClangAST(const object::ObjectFile *o);
|
||||
void PrintRelocations(const object::ObjectFile *o);
|
||||
void PrintDynamicRelocations(const object::ObjectFile *o);
|
||||
void PrintSectionHeaders(const object::ObjectFile *o);
|
||||
void PrintSectionContents(const object::ObjectFile *o);
|
||||
void PrintSymbolTable(const object::ObjectFile *o, StringRef ArchiveName,
|
||||
|
|
Loading…
Reference in New Issue