forked from OSchip/llvm-project
[readobj] Handle ELF files with no section table or with no program headers.
This adds support for finding the dynamic table and dynamic symbol table via the section table or the program header table. If there's no section table an attempt is made to figure out the length of the dynamic symbol table. llvm-svn: 260488
This commit is contained in:
parent
60d82b269c
commit
582c4d2bab
|
@ -62,6 +62,8 @@ public:
|
|||
return reinterpret_cast<const uint8_t *>(Buf.data());
|
||||
}
|
||||
|
||||
size_t getBufSize() const { return Buf.size(); }
|
||||
|
||||
private:
|
||||
|
||||
StringRef Buf;
|
||||
|
@ -200,6 +202,9 @@ public:
|
|||
uint32_t getExtendedSymbolTableIndex(const Elf_Sym *Sym,
|
||||
const Elf_Shdr *SymTab,
|
||||
ArrayRef<Elf_Word> ShndxTable) const;
|
||||
uint32_t getExtendedSymbolTableIndex(const Elf_Sym *Sym,
|
||||
const Elf_Sym *FirstSym,
|
||||
ArrayRef<Elf_Word> ShndxTable) const;
|
||||
const Elf_Ehdr *getHeader() const { return Header; }
|
||||
ErrorOr<const Elf_Shdr *> getSection(const Elf_Sym *Sym,
|
||||
const Elf_Shdr *SymTab,
|
||||
|
@ -225,8 +230,15 @@ template <class ELFT>
|
|||
uint32_t ELFFile<ELFT>::getExtendedSymbolTableIndex(
|
||||
const Elf_Sym *Sym, const Elf_Shdr *SymTab,
|
||||
ArrayRef<Elf_Word> ShndxTable) const {
|
||||
return getExtendedSymbolTableIndex(Sym, symbol_begin(SymTab), ShndxTable);
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
uint32_t ELFFile<ELFT>::getExtendedSymbolTableIndex(
|
||||
const Elf_Sym *Sym, const Elf_Sym *FirstSym,
|
||||
ArrayRef<Elf_Word> ShndxTable) const {
|
||||
assert(Sym->st_shndx == ELF::SHN_XINDEX);
|
||||
unsigned Index = Sym - symbol_begin(SymTab);
|
||||
unsigned Index = Sym - FirstSym;
|
||||
|
||||
// The size of the table was checked in getSHNDXTable.
|
||||
return ShndxTable[Index];
|
||||
|
@ -238,7 +250,8 @@ ELFFile<ELFT>::getSection(const Elf_Sym *Sym, const Elf_Shdr *SymTab,
|
|||
ArrayRef<Elf_Word> ShndxTable) const {
|
||||
uint32_t Index = Sym->st_shndx;
|
||||
if (Index == ELF::SHN_XINDEX)
|
||||
return getSection(getExtendedSymbolTableIndex(Sym, SymTab, ShndxTable));
|
||||
return getSection(
|
||||
getExtendedSymbolTableIndex(Sym, symbol_begin(SymTab), ShndxTable));
|
||||
|
||||
if (Index == ELF::SHN_UNDEF || Index >= ELF::SHN_LORESERVE)
|
||||
return nullptr;
|
||||
|
|
Binary file not shown.
|
@ -38,24 +38,17 @@ RUN: FileCheck --check-prefix=PHENTSIZE %s
|
|||
|
||||
PHENTSIZE: Invalid program header size
|
||||
|
||||
RUN: not llvm-readobj -dynamic-table \
|
||||
RUN: %p/Inputs/corrupt-invalid-virtual-addr.elf.x86-64 2>&1 | \
|
||||
RUN: FileCheck --check-prefix=VIRTADDR %s
|
||||
|
||||
VIRTADDR: Virtual address is not in any segment
|
||||
|
||||
|
||||
RUN: not llvm-readobj -dyn-relocations \
|
||||
RUN: %p/Inputs/corrupt-invalid-relocation-size.elf.x86-64 2>&1 | \
|
||||
RUN: FileCheck --check-prefix=RELOC %s
|
||||
|
||||
RELOC: Invalid relocation entry size
|
||||
RELOC: Invalid entity size
|
||||
|
||||
RUN: not llvm-readobj -dyn-relocations \
|
||||
RUN: %p/Inputs/corrupt-invalid-dynamic-table-size.elf.x86-64 2>&1 | \
|
||||
RUN: FileCheck --check-prefix=DYN-TABLE-SIZE %s
|
||||
|
||||
DYN-TABLE-SIZE: Invalid dynamic table size
|
||||
DYN-TABLE-SIZE: Invalid entity size
|
||||
|
||||
|
||||
RUN: not llvm-readobj -dyn-relocations \
|
||||
|
|
|
@ -35,9 +35,11 @@ SECTION-NEXT: AddressAlignment:
|
|||
SECTION-NEXT: EntrySize: 32
|
||||
|
||||
RUN: not llvm-readobj -t %p/Inputs/invalid-sh_entsize.elf 2>&1 | FileCheck --check-prefix=INVALID-SYM-SIZE %s
|
||||
RUN: not llvm-readobj --dyn-symbols %p/Inputs/invalid-sh_entsize.elf 2>&1 | FileCheck --check-prefix=INVALID-SYM-SIZE %s
|
||||
INVALID-SYM-SIZE: Invalid symbol size
|
||||
|
||||
RUN: not llvm-readobj --dyn-symbols %p/Inputs/invalid-sh_entsize.elf 2>&1 | FileCheck --check-prefix=INVALID-DYNSYM-SIZE %s
|
||||
INVALID-DYNSYM-SIZE: Invalid entity size
|
||||
|
||||
RUN: not llvm-readobj -t %p/Inputs/invalid-section-index.elf 2>&1 | FileCheck --check-prefix=INVALID-SECTION-INDEX %s
|
||||
|
||||
INVALID-SECTION-INDEX: Invalid section index
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,198 @@
|
|||
RUN: llvm-readobj -dyn-symbols -dynamic-table \
|
||||
RUN: %S/Inputs/dynamic-table-exe-no-shdrs.x86 | FileCheck %s
|
||||
RUN: llvm-readobj -dyn-symbols -dynamic-table \
|
||||
RUN: %S/Inputs/dynamic-table-exe-no-phdrs.x86 | FileCheck %s
|
||||
|
||||
CHECK: File:
|
||||
CHECK-NEXT: Format: ELF32-i386
|
||||
CHECK-NEXT: Arch: i386
|
||||
CHECK-NEXT: AddressSize: 32bit
|
||||
CHECK-NEXT: LoadName:
|
||||
CHECK-NEXT: DynamicSymbols [
|
||||
CHECK-NEXT: Symbol {
|
||||
CHECK-NEXT: Name: @
|
||||
CHECK-NEXT: Value: 0x0
|
||||
CHECK-NEXT: Size: 0
|
||||
CHECK-NEXT: Binding: Local
|
||||
CHECK-NEXT: Type: None
|
||||
CHECK-NEXT: Other: 0
|
||||
CHECK-NEXT: Section: Undefined
|
||||
CHECK-NEXT: }
|
||||
CHECK-NEXT: Symbol {
|
||||
CHECK-NEXT: Name: __gmon_start__@
|
||||
CHECK-NEXT: Value: 0x0
|
||||
CHECK-NEXT: Size: 0
|
||||
CHECK-NEXT: Binding: Weak
|
||||
CHECK-NEXT: Type: None
|
||||
CHECK-NEXT: Other: 0
|
||||
CHECK-NEXT: Section: Undefined
|
||||
CHECK-NEXT: }
|
||||
CHECK-NEXT: Symbol {
|
||||
CHECK-NEXT: Name: _Jv_RegisterClasses@
|
||||
CHECK-NEXT: Value: 0x0
|
||||
CHECK-NEXT: Size: 0
|
||||
CHECK-NEXT: Binding: Weak
|
||||
CHECK-NEXT: Type: None
|
||||
CHECK-NEXT: Other: 0
|
||||
CHECK-NEXT: Section: Undefined
|
||||
CHECK-NEXT: }
|
||||
CHECK-NEXT: Symbol {
|
||||
CHECK-NEXT: Name: __libc_start_main@
|
||||
CHECK-NEXT: Value: 0x0
|
||||
CHECK-NEXT: Size: 0
|
||||
CHECK-NEXT: Binding: Global
|
||||
CHECK-NEXT: Type: Function
|
||||
CHECK-NEXT: Other: 0
|
||||
CHECK-NEXT: Section: Undefined
|
||||
CHECK-NEXT: }
|
||||
CHECK-NEXT: Symbol {
|
||||
CHECK-NEXT: Name: _ITM_deregisterTMCloneTable@
|
||||
CHECK-NEXT: Value: 0x0
|
||||
CHECK-NEXT: Size: 0
|
||||
CHECK-NEXT: Binding: Weak
|
||||
CHECK-NEXT: Type: None
|
||||
CHECK-NEXT: Other: 0
|
||||
CHECK-NEXT: Section: Undefined
|
||||
CHECK-NEXT: }
|
||||
CHECK-NEXT: Symbol {
|
||||
CHECK-NEXT: Name: _ITM_registerTMCloneTable@
|
||||
CHECK-NEXT: Value: 0x0
|
||||
CHECK-NEXT: Size: 0
|
||||
CHECK-NEXT: Binding: Weak
|
||||
CHECK-NEXT: Type: None
|
||||
CHECK-NEXT: Other: 0
|
||||
CHECK-NEXT: Section: Undefined
|
||||
CHECK-NEXT: }
|
||||
CHECK-NEXT: Symbol {
|
||||
CHECK-NEXT: Name: _ZNSt14basic_ifstreamIcSt11char_traitsIcEED1Ev@
|
||||
CHECK-NEXT: Value: 0x0
|
||||
CHECK-NEXT: Size: 0
|
||||
CHECK-NEXT: Binding: Global
|
||||
CHECK-NEXT: Type: Function
|
||||
CHECK-NEXT: Other: 0
|
||||
CHECK-NEXT: Section: Undefined
|
||||
CHECK-NEXT: }
|
||||
CHECK-NEXT: Symbol {
|
||||
CHECK-NEXT: Name: _ZNSt14basic_ifstreamIcSt11char_traitsIcEEC1EPKcSt13_Ios_Openmode@
|
||||
CHECK-NEXT: Value: 0x0
|
||||
CHECK-NEXT: Size: 0
|
||||
CHECK-NEXT: Binding: Global
|
||||
CHECK-NEXT: Type: Function
|
||||
CHECK-NEXT: Other: 0
|
||||
CHECK-NEXT: Section: Undefined
|
||||
CHECK-NEXT: }
|
||||
CHECK-NEXT: Symbol {
|
||||
CHECK-NEXT: Name: puts@
|
||||
CHECK-NEXT: Value: 0x0
|
||||
CHECK-NEXT: Size: 0
|
||||
CHECK-NEXT: Binding: Global
|
||||
CHECK-NEXT: Type: Function
|
||||
CHECK-NEXT: Other: 0
|
||||
CHECK-NEXT: Section: Undefined
|
||||
CHECK-NEXT: }
|
||||
CHECK-NEXT: Symbol {
|
||||
CHECK-NEXT: Name: __gxx_personality_v0@
|
||||
CHECK-NEXT: Value: 0x0
|
||||
CHECK-NEXT: Size: 0
|
||||
CHECK-NEXT: Binding: Global
|
||||
CHECK-NEXT: Type: Function
|
||||
CHECK-NEXT: Other: 0
|
||||
CHECK-NEXT: Section: Undefined
|
||||
CHECK-NEXT: }
|
||||
CHECK-NEXT: Symbol {
|
||||
CHECK-NEXT: Name: _Unwind_Resume@
|
||||
CHECK-NEXT: Value: 0x0
|
||||
CHECK-NEXT: Size: 0
|
||||
CHECK-NEXT: Binding: Global
|
||||
CHECK-NEXT: Type: Function
|
||||
CHECK-NEXT: Other: 0
|
||||
CHECK-NEXT: Section: Undefined
|
||||
CHECK-NEXT: }
|
||||
CHECK-NEXT: Symbol {
|
||||
CHECK-NEXT: Name: __cxa_finalize@
|
||||
CHECK-NEXT: Value: 0x0
|
||||
CHECK-NEXT: Size: 0
|
||||
CHECK-NEXT: Binding: Weak
|
||||
CHECK-NEXT: Type: Function
|
||||
CHECK-NEXT: Other: 0
|
||||
CHECK-NEXT: Section: Undefined
|
||||
CHECK-NEXT: }
|
||||
CHECK-NEXT: Symbol {
|
||||
CHECK-NEXT: Name: _end@
|
||||
CHECK-NEXT: Value: 0x1B68
|
||||
CHECK-NEXT: Size: 0
|
||||
CHECK-NEXT: Binding: Global
|
||||
CHECK-NEXT: Type: None
|
||||
CHECK-NEXT: Other: 0
|
||||
CHECK-NEXT: Section: Absolute
|
||||
CHECK-NEXT: }
|
||||
CHECK-NEXT: Symbol {
|
||||
CHECK-NEXT: Name: _edata@
|
||||
CHECK-NEXT: Value: 0x1B64
|
||||
CHECK-NEXT: Size: 0
|
||||
CHECK-NEXT: Binding: Global
|
||||
CHECK-NEXT: Type: None
|
||||
CHECK-NEXT: Other: 0
|
||||
CHECK-NEXT: Section: Absolute
|
||||
CHECK-NEXT: }
|
||||
CHECK-NEXT: Symbol {
|
||||
CHECK-NEXT: Name: _IO_stdin_used@
|
||||
CHECK-NEXT: Value: 0x93C
|
||||
CHECK-NEXT: Size: 4
|
||||
CHECK-NEXT: Binding: Global
|
||||
CHECK-NEXT: Type: Object
|
||||
CHECK-NEXT: Other: 0
|
||||
CHECK-NEXT: Section:
|
||||
CHECK-NEXT: }
|
||||
CHECK-NEXT: Symbol {
|
||||
CHECK-NEXT: Name: __bss_start@
|
||||
CHECK-NEXT: Value: 0x1B64
|
||||
CHECK-NEXT: Size: 0
|
||||
CHECK-NEXT: Binding: Global
|
||||
CHECK-NEXT: Type: None
|
||||
CHECK-NEXT: Other: 0
|
||||
CHECK-NEXT: Section: Absolute
|
||||
CHECK-NEXT: }
|
||||
CHECK-NEXT: Symbol {
|
||||
CHECK-NEXT: Name: main@
|
||||
CHECK-NEXT: Value: 0x850
|
||||
CHECK-NEXT: Size: 81
|
||||
CHECK-NEXT: Binding: Global
|
||||
CHECK-NEXT: Type: Function
|
||||
CHECK-NEXT: Other: 0
|
||||
CHECK-NEXT: Section:
|
||||
CHECK-NEXT: }
|
||||
CHECK-NEXT: ]
|
||||
CHECK-NEXT: DynamicSection [
|
||||
CHECK-NEXT: Tag Type Name/Value
|
||||
CHECK-NEXT: 0x00000001 NEEDED SharedLibrary (libstdc++.so.6)
|
||||
CHECK-NEXT: 0x00000001 NEEDED SharedLibrary (libgcc_s.so.1)
|
||||
CHECK-NEXT: 0x00000001 NEEDED SharedLibrary (libc.so.6)
|
||||
CHECK-NEXT: 0x0000000C INIT 0x62C
|
||||
CHECK-NEXT: 0x0000000D FINI 0x920
|
||||
CHECK-NEXT: 0x00000019 INIT_ARRAY 0x19FC
|
||||
CHECK-NEXT: 0x0000001B INIT_ARRAYSZ 4
|
||||
CHECK-NEXT: 0x0000001A FINI_ARRAY 0x1A00
|
||||
CHECK-NEXT: 0x0000001C FINI_ARRAYSZ 4
|
||||
CHECK-NEXT: 0x00000004 HASH 0x18C
|
||||
CHECK-NEXT: 0x6FFFFEF5 GNU_HASH 0x1E4
|
||||
CHECK-NEXT: 0x00000005 STRTAB 0x328
|
||||
CHECK-NEXT: 0x00000006 SYMTAB 0x218
|
||||
CHECK-NEXT: 0x0000000A STRSZ 408
|
||||
CHECK-NEXT: 0x0000000B SYMENT 16
|
||||
CHECK-NEXT: 0x00000015 DEBUG 0x0
|
||||
CHECK-NEXT: 0x00000003 PLTGOT 0x1B30
|
||||
CHECK-NEXT: 0x00000002 PLTRELSZ 64
|
||||
CHECK-NEXT: 0x00000014 PLTREL REL
|
||||
CHECK-NEXT: 0x00000017 JMPREL 0x5EC
|
||||
CHECK-NEXT: 0x00000011 REL 0x564
|
||||
CHECK-NEXT: 0x00000012 RELSZ 136
|
||||
CHECK-NEXT: 0x00000013 RELENT 8
|
||||
CHECK-NEXT: 0x00000016 TEXTREL 0x0
|
||||
CHECK-NEXT: 0x0000001E FLAGS TEXTREL
|
||||
CHECK-NEXT: 0x6FFFFFFE VERNEED 0x4E4
|
||||
CHECK-NEXT: 0x6FFFFFFF VERNEEDNUM 3
|
||||
CHECK-NEXT: 0x6FFFFFF0 VERSYM 0x4C0
|
||||
CHECK-NEXT: 0x6FFFFFFA RELCOUNT 6
|
||||
CHECK-NEXT: 0x00000000 NULL 0x0
|
||||
CHECK-NEXT: ]
|
|
@ -48,6 +48,28 @@ namespace {
|
|||
|
||||
template <class ELFT> class DumpStyle;
|
||||
|
||||
/// \brief Represents a region described by entries in the .dynamic table.
|
||||
struct DynRegionInfo {
|
||||
DynRegionInfo() : Addr(nullptr), Size(0), EntSize(0) {}
|
||||
DynRegionInfo(const void *A, uint64_t S, uint64_t ES)
|
||||
: Addr(A), Size(S), EntSize(ES) {}
|
||||
/// \brief Address in current address space.
|
||||
const void *Addr;
|
||||
/// \brief Size in bytes of the region.
|
||||
uint64_t Size;
|
||||
/// \brief Size of each entity in the region.
|
||||
uint64_t EntSize;
|
||||
|
||||
template <typename Type> iterator_range<const Type *> getAsRange() const {
|
||||
const Type *Start = reinterpret_cast<const Type *>(Addr);
|
||||
if (Size == 0)
|
||||
return {Start, Start};
|
||||
if (EntSize != sizeof(Type) || Size % EntSize)
|
||||
reportError("Invalid entity size");
|
||||
return {Start, Start + (Size / EntSize)};
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ELFT>
|
||||
class ELFDumper : public ObjDumper {
|
||||
public:
|
||||
|
@ -82,6 +104,7 @@ private:
|
|||
typedef ELFFile<ELFT> ELFO;
|
||||
typedef typename ELFO::Elf_Shdr Elf_Shdr;
|
||||
typedef typename ELFO::Elf_Sym Elf_Sym;
|
||||
typedef typename ELFO::Elf_Sym_Range Elf_Sym_Range;
|
||||
typedef typename ELFO::Elf_Dyn Elf_Dyn;
|
||||
typedef typename ELFO::Elf_Dyn_Range Elf_Dyn_Range;
|
||||
typedef typename ELFO::Elf_Rel Elf_Rel;
|
||||
|
@ -101,21 +124,25 @@ private:
|
|||
typedef typename ELFO::Elf_Verdef Elf_Verdef;
|
||||
typedef typename ELFO::Elf_Verdaux Elf_Verdaux;
|
||||
|
||||
/// \brief Represents a region described by entries in the .dynamic table.
|
||||
struct DynRegionInfo {
|
||||
DynRegionInfo() : Addr(nullptr), Size(0), EntSize(0) {}
|
||||
/// \brief Address in current address space.
|
||||
const void *Addr;
|
||||
/// \brief Size in bytes of the region.
|
||||
uintX_t Size;
|
||||
/// \brief Size of each entity in the region.
|
||||
uintX_t EntSize;
|
||||
};
|
||||
DynRegionInfo checkDRI(DynRegionInfo DRI) {
|
||||
if (DRI.Addr < Obj->base() ||
|
||||
(const uint8_t *)DRI.Addr + DRI.Size > Obj->base() + Obj->getBufSize())
|
||||
error(llvm::object::object_error::parse_failed);
|
||||
return DRI;
|
||||
}
|
||||
|
||||
DynRegionInfo createDRIFrom(const Elf_Phdr *P, uintX_t EntSize) {
|
||||
return checkDRI({Obj->base() + P->p_offset, P->p_filesz, EntSize});
|
||||
}
|
||||
|
||||
DynRegionInfo createDRIFrom(const Elf_Shdr *S) {
|
||||
return checkDRI({Obj->base() + S->sh_offset, S->sh_size, S->sh_entsize});
|
||||
}
|
||||
|
||||
void parseDynamicTable(ArrayRef<const Elf_Phdr *> LoadSegments);
|
||||
|
||||
void printSymbolsHelper(bool IsDynamic);
|
||||
void printSymbol(const Elf_Sym *Symbol, const Elf_Shdr *SymTab,
|
||||
void printSymbol(const Elf_Sym *Symbol, const Elf_Sym *FirstSym,
|
||||
StringRef StrTable, bool IsDynamic);
|
||||
|
||||
void printDynamicRelocation(Elf_Rela Rel);
|
||||
|
@ -123,23 +150,9 @@ private:
|
|||
void printRelocation(Elf_Rela Rel, const Elf_Shdr *SymTab);
|
||||
void printValue(uint64_t Type, uint64_t Value);
|
||||
|
||||
template <typename REL>
|
||||
static const REL *dyn_rel_begin(const DynRegionInfo ®ion);
|
||||
template <typename REL>
|
||||
static const REL *dyn_rel_end(const DynRegionInfo ®ion);
|
||||
Elf_Rel_Range dyn_rels() const;
|
||||
Elf_Rela_Range dyn_relas() const;
|
||||
StringRef getDynamicString(uint64_t Offset) const;
|
||||
const Elf_Dyn *dynamic_table_begin() const {
|
||||
ErrorOr<const Elf_Dyn *> Ret = Obj->dynamic_table_begin(DynamicProgHeader);
|
||||
error(Ret.getError());
|
||||
return *Ret;
|
||||
}
|
||||
const Elf_Dyn *dynamic_table_end() const {
|
||||
ErrorOr<const Elf_Dyn *> Ret = Obj->dynamic_table_end(DynamicProgHeader);
|
||||
error(Ret.getError());
|
||||
return *Ret;
|
||||
}
|
||||
StringRef getSymbolVersion(StringRef StrTab, const Elf_Sym *symb,
|
||||
bool &IsDefault);
|
||||
void LoadVersionMap();
|
||||
|
@ -147,15 +160,17 @@ private:
|
|||
void LoadVersionDefs(const Elf_Shdr *sec) const;
|
||||
|
||||
const ELFO *Obj;
|
||||
DynRegionInfo DynamicTable;
|
||||
|
||||
// Dynamic relocation info.
|
||||
DynRegionInfo DynRelRegion;
|
||||
DynRegionInfo DynRelaRegion;
|
||||
const Elf_Phdr *DynamicProgHeader = nullptr;
|
||||
|
||||
DynRegionInfo DynSymRegion;
|
||||
StringRef DynamicStringTable;
|
||||
const Elf_Sym *DynSymStart = nullptr;
|
||||
StringRef SOName;
|
||||
const Elf_Hash *HashTable = nullptr;
|
||||
const Elf_GnuHash *GnuHashTable = nullptr;
|
||||
const Elf_Shdr *DotDynSymSec = nullptr;
|
||||
const Elf_Shdr *DotSymtabSec = nullptr;
|
||||
ArrayRef<Elf_Word> ShndxTable;
|
||||
|
||||
|
@ -188,16 +203,18 @@ private:
|
|||
|
||||
public:
|
||||
Elf_Dyn_Range dynamic_table() const {
|
||||
ErrorOr<Elf_Dyn_Range> Ret = Obj->dynamic_table(DynamicProgHeader);
|
||||
error(Ret.getError());
|
||||
return *Ret;
|
||||
return DynamicTable.getAsRange<Elf_Dyn>();
|
||||
}
|
||||
|
||||
Elf_Sym_Range dynamic_symbols() const {
|
||||
return DynSymRegion.getAsRange<Elf_Sym>();
|
||||
}
|
||||
|
||||
std::string getFullSymbolName(const Elf_Sym *Symbol, StringRef StrTable,
|
||||
bool IsDynamic);
|
||||
const Elf_Shdr *getDotDynSymSec() const { return DotDynSymSec; }
|
||||
const Elf_Shdr *getDotSymtabSec() const { return DotSymtabSec; }
|
||||
ArrayRef<Elf_Word> getShndxTable() { return ShndxTable; }
|
||||
StringRef getDynamicStringTable() const { return DynamicStringTable; }
|
||||
};
|
||||
|
||||
template <typename ELFT> class DumpStyle {
|
||||
|
@ -340,7 +357,7 @@ void ELFDumper<ELFT>::LoadVersionDefs(const Elf_Shdr *sec) const {
|
|||
|
||||
template <class ELFT> void ELFDumper<ELFT>::LoadVersionMap() {
|
||||
// If there is no dynamic symtab or version table, there is nothing to do.
|
||||
if (!DynSymStart || !dot_gnu_version_sec)
|
||||
if (!DynSymRegion.Addr || !dot_gnu_version_sec)
|
||||
return;
|
||||
|
||||
// Has the VersionMap already been loaded?
|
||||
|
@ -374,18 +391,15 @@ static void printVersionSymbolSection(ELFDumper<ELFT> *Dumper,
|
|||
W.printHex("Offset", Sec->sh_offset);
|
||||
W.printNumber("Link", Sec->sh_link);
|
||||
|
||||
const typename ELFO::Elf_Shdr *DynSymSec = Dumper->getDotDynSymSec();
|
||||
const uint8_t *P = (const uint8_t *)Obj->base() + Sec->sh_offset;
|
||||
ErrorOr<StringRef> StrTableOrErr =
|
||||
Obj->getStringTableForSymtab(*DynSymSec);
|
||||
error(StrTableOrErr.getError());
|
||||
StringRef StrTable = Dumper->getDynamicStringTable();
|
||||
|
||||
// Same number of entries in the dynamic symbol table (DT_SYMTAB).
|
||||
ListScope Syms(W, "Symbols");
|
||||
for (const typename ELFO::Elf_Sym &Sym : Obj->symbols(DynSymSec)) {
|
||||
for (const typename ELFO::Elf_Sym &Sym : Dumper->dynamic_symbols()) {
|
||||
DictScope S(W, "Symbol");
|
||||
std::string FullSymbolName =
|
||||
Dumper->getFullSymbolName(&Sym, *StrTableOrErr, true /* IsDynamic */);
|
||||
Dumper->getFullSymbolName(&Sym, StrTable, true /* IsDynamic */);
|
||||
W.printNumber("Version", *P);
|
||||
W.printString("Name", FullSymbolName);
|
||||
P += sizeof(typename ELFO::Elf_Half);
|
||||
|
@ -461,7 +475,7 @@ StringRef ELFDumper<ELFT>::getSymbolVersion(StringRef StrTab,
|
|||
|
||||
// Determine the position in the symbol table of this entry.
|
||||
size_t entry_index = (reinterpret_cast<uintptr_t>(symb) -
|
||||
reinterpret_cast<uintptr_t>(DynSymStart)) /
|
||||
reinterpret_cast<uintptr_t>(DynSymRegion.Addr)) /
|
||||
sizeof(Elf_Sym);
|
||||
|
||||
// Get the corresponding version index entry
|
||||
|
@ -517,7 +531,7 @@ std::string ELFDumper<ELFT>::getFullSymbolName(const Elf_Sym *Symbol,
|
|||
template <typename ELFO>
|
||||
static void
|
||||
getSectionNameIndex(const ELFO &Obj, const typename ELFO::Elf_Sym *Symbol,
|
||||
const typename ELFO::Elf_Shdr *SymTab,
|
||||
const typename ELFO::Elf_Sym *FirstSym,
|
||||
ArrayRef<typename ELFO::Elf_Word> ShndxTable,
|
||||
StringRef &SectionName, unsigned &SectionIndex) {
|
||||
SectionIndex = Symbol->st_shndx;
|
||||
|
@ -536,7 +550,7 @@ getSectionNameIndex(const ELFO &Obj, const typename ELFO::Elf_Sym *Symbol,
|
|||
else {
|
||||
if (SectionIndex == SHN_XINDEX)
|
||||
SectionIndex =
|
||||
Obj.getExtendedSymbolTableIndex(Symbol, SymTab, ShndxTable);
|
||||
Obj.getExtendedSymbolTableIndex(Symbol, FirstSym, ShndxTable);
|
||||
ErrorOr<const typename ELFO::Elf_Shdr *> Sec = Obj.getSection(SectionIndex);
|
||||
error(Sec.getError());
|
||||
SectionName = errorOrDefault(Obj.getSectionName(*Sec));
|
||||
|
@ -990,7 +1004,7 @@ ELFDumper<ELFT>::ELFDumper(const ELFFile<ELFT> *Obj, StreamWriter &Writer)
|
|||
SmallVector<const Elf_Phdr *, 4> LoadSegments;
|
||||
for (const Elf_Phdr &Phdr : Obj->program_headers()) {
|
||||
if (Phdr.p_type == ELF::PT_DYNAMIC) {
|
||||
DynamicProgHeader = &Phdr;
|
||||
DynamicTable = createDRIFrom(&Phdr, sizeof(Elf_Dyn));
|
||||
continue;
|
||||
}
|
||||
if (Phdr.p_type != ELF::PT_LOAD || Phdr.p_filesz == 0)
|
||||
|
@ -1005,10 +1019,17 @@ ELFDumper<ELFT>::ELFDumper(const ELFFile<ELFT> *Obj, StreamWriter &Writer)
|
|||
reportError("Multilpe SHT_SYMTAB");
|
||||
DotSymtabSec = &Sec;
|
||||
break;
|
||||
case ELF::SHT_DYNAMIC: {
|
||||
if (DynamicTable.Addr == nullptr)
|
||||
DynamicTable = createDRIFrom(&Sec);
|
||||
const Elf_Shdr *DynStrSec = unwrapOrError(Obj->getSection(Sec.sh_link));
|
||||
DynamicStringTable = unwrapOrError(Obj->getStringTable(DynStrSec));
|
||||
break;
|
||||
}
|
||||
case ELF::SHT_DYNSYM:
|
||||
if (DotDynSymSec != nullptr)
|
||||
reportError("Multilpe SHT_DYNSYM");
|
||||
DotDynSymSec = &Sec;
|
||||
// The dynamic table does not contain the size of the dynamic symbol
|
||||
// table, so get that from the section table if present.
|
||||
DynSymRegion = createDRIFrom(&Sec);
|
||||
break;
|
||||
case ELF::SHT_SYMTAB_SHNDX: {
|
||||
ErrorOr<ArrayRef<Elf_Word>> TableOrErr = Obj->getSHNDXTable(Sec);
|
||||
|
@ -1049,12 +1070,12 @@ void ELFDumper<ELFT>::parseDynamicTable(
|
|||
const Elf_Phdr *const *I = std::upper_bound(
|
||||
LoadSegments.begin(), LoadSegments.end(), VAddr, compareAddr<ELFT>);
|
||||
if (I == LoadSegments.begin())
|
||||
report_fatal_error("Virtual address is not in any segment");
|
||||
return nullptr;
|
||||
--I;
|
||||
const Elf_Phdr &Phdr = **I;
|
||||
uint64_t Delta = VAddr - Phdr.p_vaddr;
|
||||
if (Delta >= Phdr.p_filesz)
|
||||
report_fatal_error("Virtual address is not in any segment");
|
||||
return nullptr;
|
||||
return Obj->base() + Phdr.p_offset + Delta;
|
||||
};
|
||||
|
||||
|
@ -1078,8 +1099,11 @@ void ELFDumper<ELFT>::parseDynamicTable(
|
|||
StringTableSize = Dyn.getVal();
|
||||
break;
|
||||
case ELF::DT_SYMTAB:
|
||||
DynSymStart =
|
||||
reinterpret_cast<const Elf_Sym *>(toMappedAddr(Dyn.getPtr()));
|
||||
if (DynSymRegion.Addr)
|
||||
break;
|
||||
DynSymRegion.Addr = toMappedAddr(Dyn.getPtr());
|
||||
DynSymRegion.EntSize = sizeof(Elf_Sym);
|
||||
// Figure out the size once we have scanned the entire dynamic table.
|
||||
break;
|
||||
case ELF::DT_RELA:
|
||||
DynRelaRegion.Addr = toMappedAddr(Dyn.getPtr());
|
||||
|
@ -1108,35 +1132,59 @@ void ELFDumper<ELFT>::parseDynamicTable(
|
|||
DynamicStringTable = StringRef(StringTableBegin, StringTableSize);
|
||||
if (SONameOffset)
|
||||
SOName = getDynamicString(SONameOffset);
|
||||
}
|
||||
if (DynSymRegion.Addr && !DynSymRegion.Size) {
|
||||
// There was no section table entry for the dynamic section, and there is
|
||||
// no DT entry describing its size, so attempt to guess at its size.
|
||||
// Initally guess that it ends at the end of the file.
|
||||
const void *Start = DynSymRegion.Addr;
|
||||
const void *End = Obj->base() + Obj->getBufSize();
|
||||
|
||||
template <typename ELFT>
|
||||
template <typename REL>
|
||||
const REL *ELFDumper<ELFT>::dyn_rel_begin(const DynRegionInfo &Region) {
|
||||
if (Region.Size && Region.EntSize != sizeof(REL))
|
||||
report_fatal_error("Invalid relocation entry size");
|
||||
return reinterpret_cast<const REL *>(Region.Addr);
|
||||
}
|
||||
// Check all the sections we know about.
|
||||
for (const Elf_Shdr &Sec : Obj->sections()) {
|
||||
const void *Addr = Obj->base() + Sec.sh_offset;
|
||||
if (Addr >= Start && Addr < End)
|
||||
End = Addr;
|
||||
}
|
||||
|
||||
template <typename ELFT>
|
||||
template <typename REL>
|
||||
const REL *ELFDumper<ELFT>::dyn_rel_end(const DynRegionInfo &Region) {
|
||||
uint64_t Size = Region.Size;
|
||||
if (Size % sizeof(REL))
|
||||
report_fatal_error("Invalid relocation table size");
|
||||
return dyn_rel_begin<REL>(Region) + Size / sizeof(REL);
|
||||
// Check all the dynamic regions we know about.
|
||||
auto CheckDRI = [&](DynRegionInfo DRI) {
|
||||
if (DRI.Addr >= Start && DRI.Addr < End)
|
||||
End = DRI.Addr;
|
||||
};
|
||||
|
||||
CheckDRI(DynamicTable);
|
||||
CheckDRI(DynRelRegion);
|
||||
CheckDRI(DynRelaRegion);
|
||||
|
||||
if (DynamicStringTable.data() >= Start && DynamicStringTable.data() < End)
|
||||
End = DynamicStringTable.data();
|
||||
|
||||
// Scan to the first invalid symbol.
|
||||
auto SymI = reinterpret_cast<const Elf_Sym *>(Start);
|
||||
for (; ((const char *)SymI + sizeof(Elf_Sym)) <= End; ++SymI) {
|
||||
uint32_t NameOffset = SymI->st_name;
|
||||
if (SymI > Start && !NameOffset)
|
||||
break;
|
||||
if (NameOffset >= DynamicStringTable.size())
|
||||
break;
|
||||
uint16_t SectionIndex = SymI->st_shndx;
|
||||
if ((Obj->getNumSections() && SectionIndex >= Obj->getNumSections()) &&
|
||||
SectionIndex < SHN_LORESERVE)
|
||||
break;
|
||||
}
|
||||
End = SymI;
|
||||
DynSymRegion.Size = (const char *)End - (const char *)Start;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ELFT>
|
||||
typename ELFDumper<ELFT>::Elf_Rel_Range ELFDumper<ELFT>::dyn_rels() const {
|
||||
return make_range(dyn_rel_begin<Elf_Rel>(DynRelRegion),
|
||||
dyn_rel_end<Elf_Rel>(DynRelRegion));
|
||||
return DynRelRegion.getAsRange<Elf_Rel>();
|
||||
}
|
||||
|
||||
template <typename ELFT>
|
||||
typename ELFDumper<ELFT>::Elf_Rela_Range ELFDumper<ELFT>::dyn_relas() const {
|
||||
return make_range(dyn_rel_begin<Elf_Rela>(DynRelaRegion),
|
||||
dyn_rel_end<Elf_Rela>(DynRelaRegion));
|
||||
return DynRelaRegion.getAsRange<Elf_Rela>();
|
||||
}
|
||||
|
||||
template<class ELFT>
|
||||
|
@ -1211,7 +1259,7 @@ void ELFDumper<ELFT>::printSections() {
|
|||
if (!SymSec)
|
||||
continue;
|
||||
if (*SymSec == &Sec)
|
||||
printSymbol(&Sym, Symtab, StrTable, false);
|
||||
printSymbol(&Sym, Obj->symbol_begin(Symtab), StrTable, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1328,7 +1376,8 @@ void ELFDumper<ELFT>::printDynamicRelocation(Elf_Rela Rel) {
|
|||
Obj->getRelocationTypeName(Rel.getType(Obj->isMips64EL()), RelocName);
|
||||
StringRef SymbolName;
|
||||
uint32_t SymIndex = Rel.getSymbol(Obj->isMips64EL());
|
||||
const Elf_Sym *Sym = DynSymStart + SymIndex;
|
||||
const Elf_Sym *Sym =
|
||||
DynSymRegion.getAsRange<Elf_Sym>().begin() + SymIndex;
|
||||
SymbolName = errorOrDefault(Sym->getName(DynamicStringTable));
|
||||
if (opts::ExpandRelocs) {
|
||||
DictScope Group(W, "Relocation");
|
||||
|
@ -1346,14 +1395,21 @@ void ELFDumper<ELFT>::printDynamicRelocation(Elf_Rela Rel) {
|
|||
|
||||
template<class ELFT>
|
||||
void ELFDumper<ELFT>::printSymbolsHelper(bool IsDynamic) {
|
||||
const Elf_Shdr *Symtab = (IsDynamic) ? DotDynSymSec : DotSymtabSec;
|
||||
if (!Symtab)
|
||||
return;
|
||||
ErrorOr<StringRef> StrTableOrErr = Obj->getStringTableForSymtab(*Symtab);
|
||||
error(StrTableOrErr.getError());
|
||||
StringRef StrTable = *StrTableOrErr;
|
||||
for (const Elf_Sym &Sym : Obj->symbols(Symtab))
|
||||
printSymbol(&Sym, Symtab, StrTable, IsDynamic);
|
||||
StringRef StrTable = DynamicStringTable;
|
||||
Elf_Sym_Range Syms(nullptr, nullptr);
|
||||
if (IsDynamic)
|
||||
Syms = DynSymRegion.getAsRange<Elf_Sym>();
|
||||
else {
|
||||
if (!DotSymtabSec)
|
||||
return;
|
||||
ErrorOr<StringRef> StrTableOrErr =
|
||||
Obj->getStringTableForSymtab(*DotSymtabSec);
|
||||
error(StrTableOrErr.getError());
|
||||
StrTable = *StrTableOrErr;
|
||||
Syms = Obj->symbols(DotSymtabSec);
|
||||
}
|
||||
for (const Elf_Sym &Sym : Syms)
|
||||
printSymbol(&Sym, Syms.begin(), StrTable, IsDynamic);
|
||||
}
|
||||
|
||||
template<class ELFT>
|
||||
|
@ -1369,11 +1425,12 @@ void ELFDumper<ELFT>::printDynamicSymbols() {
|
|||
}
|
||||
|
||||
template <class ELFT>
|
||||
void ELFDumper<ELFT>::printSymbol(const Elf_Sym *Symbol, const Elf_Shdr *SymTab,
|
||||
StringRef StrTable, bool IsDynamic) {
|
||||
void ELFDumper<ELFT>::printSymbol(const Elf_Sym *Symbol,
|
||||
const Elf_Sym *FirstSym, StringRef StrTable,
|
||||
bool IsDynamic) {
|
||||
unsigned SectionIndex = 0;
|
||||
StringRef SectionName;
|
||||
getSectionNameIndex(*Obj, Symbol, SymTab, ShndxTable, SectionName,
|
||||
getSectionNameIndex(*Obj, Symbol, FirstSym, ShndxTable, SectionName,
|
||||
SectionIndex);
|
||||
std::string FullSymbolName = getFullSymbolName(Symbol, StrTable, IsDynamic);
|
||||
unsigned char SymbolType = Symbol->getType();
|
||||
|
@ -1650,8 +1707,8 @@ template <> void ELFDumper<ELFType<support::little, false>>::printUnwindInfo() {
|
|||
|
||||
template<class ELFT>
|
||||
void ELFDumper<ELFT>::printDynamicTable() {
|
||||
auto I = dynamic_table_begin();
|
||||
auto E = dynamic_table_end();
|
||||
auto I = dynamic_table().begin();
|
||||
auto E = dynamic_table().end();
|
||||
|
||||
if (I == E)
|
||||
return;
|
||||
|
@ -1747,10 +1804,10 @@ void ELFDumper<ELFT>::printGnuHashTable() {
|
|||
W.printNumber("Shift Count", GnuHashTable->shift2);
|
||||
W.printHexList("Bloom Filter", GnuHashTable->filter());
|
||||
W.printList("Buckets", GnuHashTable->buckets());
|
||||
if (!DotDynSymSec)
|
||||
if (!DynSymRegion.Size || !DynSymRegion.EntSize)
|
||||
reportError("No dynamic symbol section");
|
||||
W.printHexList("Values",
|
||||
GnuHashTable->values(DotDynSymSec->getEntityCount()));
|
||||
W.printHexList(
|
||||
"Values", GnuHashTable->values(DynSymRegion.Size / DynSymRegion.EntSize));
|
||||
}
|
||||
|
||||
template <typename ELFT> void ELFDumper<ELFT>::printLoadName() {
|
||||
|
@ -1878,11 +1935,9 @@ template <class ELFT> void MipsGOTParser<ELFT>::parseGOT() {
|
|||
return;
|
||||
}
|
||||
|
||||
const Elf_Shdr *DynSymSec = Dumper->getDotDynSymSec();
|
||||
ErrorOr<StringRef> StrTable = Obj->getStringTableForSymtab(*DynSymSec);
|
||||
error(StrTable.getError());
|
||||
const Elf_Sym *DynSymBegin = Obj->symbol_begin(DynSymSec);
|
||||
const Elf_Sym *DynSymEnd = Obj->symbol_end(DynSymSec);
|
||||
StringRef StrTable = Dumper->getDynamicStringTable();
|
||||
const Elf_Sym *DynSymBegin = Dumper->dynamic_symbols().begin();
|
||||
const Elf_Sym *DynSymEnd = Dumper->dynamic_symbols().end();
|
||||
std::size_t DynSymTotal = std::size_t(std::distance(DynSymBegin, DynSymEnd));
|
||||
|
||||
if (*DtGotSym > DynSymTotal)
|
||||
|
@ -1942,8 +1997,8 @@ template <class ELFT> void MipsGOTParser<ELFT>::parseGOT() {
|
|||
const Elf_Sym *GotDynSym = DynSymBegin + *DtGotSym;
|
||||
for (; It != GotGlobalEnd; ++It) {
|
||||
DictScope D(W, "Entry");
|
||||
printGlobalGotEntry(GOTShdr->sh_addr, GotBegin, It, GotDynSym++,
|
||||
*StrTable, true);
|
||||
printGlobalGotEntry(GOTShdr->sh_addr, GotBegin, It, GotDynSym++, StrTable,
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2046,7 +2101,7 @@ void MipsGOTParser<ELFT>::printGlobalGotEntry(
|
|||
|
||||
unsigned SectionIndex = 0;
|
||||
StringRef SectionName;
|
||||
getSectionNameIndex(*Obj, Sym, Dumper->getDotDynSymSec(),
|
||||
getSectionNameIndex(*Obj, Sym, Dumper->dynamic_symbols().begin(),
|
||||
Dumper->getShndxTable(), SectionName, SectionIndex);
|
||||
W.printHex("Section", SectionName, SectionIndex);
|
||||
|
||||
|
@ -2080,7 +2135,7 @@ void MipsGOTParser<ELFT>::printPLTEntry(uint64_t PLTAddr,
|
|||
|
||||
unsigned SectionIndex = 0;
|
||||
StringRef SectionName;
|
||||
getSectionNameIndex(*Obj, Sym, Dumper->getDotDynSymSec(),
|
||||
getSectionNameIndex(*Obj, Sym, Dumper->dynamic_symbols().begin(),
|
||||
Dumper->getShndxTable(), SectionName, SectionIndex);
|
||||
W.printHex("Section", SectionName, SectionIndex);
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/ErrorOr.h"
|
||||
#include <string>
|
||||
|
||||
namespace llvm {
|
||||
|
@ -22,6 +23,11 @@ namespace llvm {
|
|||
// Various helper functions.
|
||||
LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg);
|
||||
void error(std::error_code ec);
|
||||
template <class T> T unwrapOrError(ErrorOr<T> EO) {
|
||||
if (EO)
|
||||
return *EO;
|
||||
reportError(EO.getError().message());
|
||||
}
|
||||
bool relocAddressLess(object::RelocationRef A,
|
||||
object::RelocationRef B);
|
||||
} // namespace llvm
|
||||
|
|
Loading…
Reference in New Issue