mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-29 14:20:29 +00:00
[llvm-readobj] Derive dynamic symtab size from DT_HASH
If the section headers have been removed by a tool such as llvm-objcopy or llvm-strip, previously llvm-readobj/llvm-readelf would not dump the dynamic symbols when --dyn-symbols was specified. However, the nchain value of the DT_HASH data specifies the number of dynamic symbols, so if it is present, we can use that. This patch implements this behaviour. Fixes https://bugs.llvm.org/show_bug.cgi?id=45089. Reviewed by: grimar, MaskRay Differential Revision: https://reviews.llvm.org/D76352
This commit is contained in:
parent
8380bdf23f
commit
8f87046c8a
@ -112,4 +112,5 @@ ProgramHeaders:
|
||||
Sections:
|
||||
- Section: .note.gnu.build-id
|
||||
Symbols: []
|
||||
DynamicSymbols: []
|
||||
DynamicSymbols:
|
||||
- Name: foo
|
||||
|
@ -0,0 +1,314 @@
|
||||
## This test shows how llvm-readobj uses the hash table section to derive the
|
||||
## size of a dynamic symbol table. This allows dumping of the dynamic symbol
|
||||
## table in the event of an object without section headers.
|
||||
|
||||
## Case 1a) Table size is derived from hash table, with DT_SYMTAB before DT_HASH.
|
||||
# RUN: yaml2obj --docnum=1 %s -o %t1a-64 -DBITS=64 \
|
||||
# RUN: -DTAG1=DT_SYMTAB -DTAG2=DT_HASH -DVAL1=0x400 -DVAL2=0x600
|
||||
# RUN: llvm-strip --strip-sections %t1a-64
|
||||
# RUN: llvm-readobj --dyn-symbols %t1a-64 2>&1 | \
|
||||
# RUN: FileCheck %s --check-prefixes=LLVM1,STRIP --implicit-check-not=warning:
|
||||
# RUN: llvm-readelf --dyn-symbols %t1a-64 2>&1 | \
|
||||
# RUN: FileCheck %s --check-prefixes=GNU1,GNU1-STRIP --implicit-check-not=warning:
|
||||
# RUN: yaml2obj --docnum=1 %s -o %t1a-32 -DBITS=32 \
|
||||
# RUN: -DTAG1=DT_SYMTAB -DTAG2=DT_HASH -DVAL1=0x400 -DVAL2=0x600
|
||||
# RUN: llvm-strip --strip-sections %t1a-32
|
||||
# RUN: llvm-readobj --dyn-symbols %t1a-32 2>&1 | \
|
||||
# RUN: FileCheck %s --check-prefixes=LLVM1,STRIP --implicit-check-not=warning:
|
||||
# RUN: llvm-readelf --dyn-symbols %t1a-32 2>&1 | \
|
||||
# RUN: FileCheck %s --check-prefixes=GNU1,GNU1-STRIP --implicit-check-not=warning:
|
||||
|
||||
## 1b) Table size is derived from hash table, with DT_HASH before DT_SYMTAB.
|
||||
## We don't bother testing 32 and 64-bit here. The above cases show that reading
|
||||
## the nchain value is correct for all formats, and other tests show the basic
|
||||
## printing behaviour.
|
||||
# RUN: yaml2obj --docnum=1 %s -o %t1b-64 -DBITS=64 \
|
||||
# RUN: -DTAG1=DT_HASH -DTAG2=DT_SYMTAB -DVAL1=0x600 -DVAL2=0x400
|
||||
# RUN: llvm-strip --strip-sections %t1b-64
|
||||
# RUN: llvm-readobj --dyn-symbols %t1b-64 2>&1 | \
|
||||
# RUN: FileCheck %s --check-prefixes=LLVM1,STRIP --implicit-check-not=warning:
|
||||
# RUN: llvm-readelf --dyn-symbols %t1b-64 2>&1 | \
|
||||
# RUN: FileCheck %s --check-prefixes=GNU1,GNU1-STRIP --implicit-check-not=warning:
|
||||
|
||||
# LLVM1: DynamicSymbols [
|
||||
# LLVM1-NEXT: Symbol {
|
||||
# LLVM1-NEXT: Name: (0)
|
||||
# LLVM1-NEXT: Value: 0x0
|
||||
# LLVM1-NEXT: Size: 0
|
||||
# LLVM1-NEXT: Binding: Local (0x0)
|
||||
# LLVM1-NEXT: Type: None (0x0)
|
||||
# LLVM1-NEXT: Other: 0
|
||||
# LLVM1-NEXT: Section: Undefined (0x0)
|
||||
# LLVM1-NEXT: }
|
||||
# LLVM1-NEXT: Symbol {
|
||||
# LLVM1-NEXT: Name: foo (5)
|
||||
# LLVM1-NEXT: Value: 0x100
|
||||
# LLVM1-NEXT: Size: 0
|
||||
# LLVM1-NEXT: Binding: Local (0x0)
|
||||
# LLVM1-NEXT: Type: Function (0x2)
|
||||
# LLVM1-NEXT: Other: 0
|
||||
# STRIP-NEXT: Section: <?> (0x1)
|
||||
# NOSTRIP-NEXT: Section: .text (0x1)
|
||||
# LLVM1-NEXT: }
|
||||
# LLVM1-NEXT: Symbol {
|
||||
# LLVM1-NEXT: Name: bar (1)
|
||||
# LLVM1-NEXT: Value: 0x200
|
||||
# LLVM1-NEXT: Size: 0
|
||||
# LLVM1-NEXT: Binding: Local (0x0)
|
||||
# LLVM1-NEXT: Type: Object (0x1)
|
||||
# LLVM1-NEXT: Other: 0
|
||||
# STRIP-NEXT: Section: <?> (0x2)
|
||||
# NOSTRIP-NEXT: Section: .data (0x2)
|
||||
# LLVM1-NEXT: }
|
||||
# LLVM1-NEXT: ]
|
||||
|
||||
# GNU1-STRIP: Symbol table for image contains 3 entries:
|
||||
# GNU1-NOSTRIP: Symbol table '.dynsym' contains 3 entries:
|
||||
# GNU1-NEXT: Num: Value Size Type Bind Vis Ndx Name
|
||||
# GNU1-NEXT: 0: {{0*}}00000000 0 NOTYPE LOCAL DEFAULT UND
|
||||
# GNU1-NEXT: 1: {{0*}}00000100 0 FUNC LOCAL DEFAULT 1 foo
|
||||
# GNU1-NEXT: 2: {{0*}}00000200 0 OBJECT LOCAL DEFAULT 2 bar
|
||||
# GNU1-EMPTY:
|
||||
|
||||
--- !ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS[[BITS]]
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_DYN
|
||||
Machine: EM_X86_64
|
||||
Sections:
|
||||
- Name: .text
|
||||
Type: SHT_PROGBITS
|
||||
- Name: .data
|
||||
Type: SHT_PROGBITS
|
||||
- Name: .dynsym
|
||||
Type: SHT_DYNSYM
|
||||
Flags: [ SHF_ALLOC ]
|
||||
Address: 0x400
|
||||
AddressAlign: 0x400
|
||||
- Name: .hash
|
||||
Type: SHT_HASH
|
||||
Flags: [ SHF_ALLOC ]
|
||||
Address: 0x600
|
||||
AddressAlign: 0x200
|
||||
Bucket: [ 1 ]
|
||||
Chain: [ 1, 2, 3 ]
|
||||
- Name: .dynstr
|
||||
Type: SHT_STRTAB
|
||||
Flags: [ SHF_ALLOC ]
|
||||
Address: 0x800
|
||||
AddressAlign: 0x200
|
||||
- Name: .dynamic
|
||||
Type: SHT_DYNAMIC
|
||||
Flags: [ SHF_ALLOC ]
|
||||
Address: 0xA00
|
||||
AddressAlign: 0x200
|
||||
Entries:
|
||||
- Tag: DT_STRTAB
|
||||
Value: 0x800
|
||||
- Tag: DT_STRSZ
|
||||
Value: 9
|
||||
- Tag: [[TAG1]]
|
||||
Value: [[VAL1]]
|
||||
- Tag: [[TAG2]]
|
||||
Value: [[VAL2]]
|
||||
- Tag: DT_NULL
|
||||
Value: 0
|
||||
DynamicSymbols:
|
||||
- Name: foo
|
||||
Type: STT_FUNC
|
||||
Section: .text
|
||||
Value: 0x100
|
||||
- Name: bar
|
||||
Type: STT_OBJECT
|
||||
Section: .data
|
||||
Value: 0x200
|
||||
ProgramHeaders:
|
||||
- Type: PT_LOAD
|
||||
VAddr: 0
|
||||
Sections:
|
||||
- Section: .text
|
||||
- Section: .data
|
||||
- Type: PT_LOAD
|
||||
VAddr: 0x400
|
||||
Sections:
|
||||
- Section: .dynsym
|
||||
- Section: .hash
|
||||
- Section: .dynstr
|
||||
- Section: .dynamic
|
||||
- Type: PT_DYNAMIC
|
||||
VAddr: 0xA00
|
||||
Sections:
|
||||
- Section: .dynamic
|
||||
|
||||
## Case 2: Table size from DT_HASH does not match size from section header.
|
||||
# RUN: yaml2obj --docnum=2 %s -o %t2-smaller -DCHAIN="[1, 2]"
|
||||
# RUN: llvm-readobj --dyn-symbols %t2-smaller 2>&1 | \
|
||||
# RUN: FileCheck %s --check-prefixes=LLVM2,WARN \
|
||||
# RUN: --implicit-check-not=warning: -DNCHAIN=2
|
||||
# RUN: llvm-readelf --dyn-symbols %t2-smaller 2>&1 | \
|
||||
# RUN: FileCheck %s --check-prefixes=GNU2,WARN \
|
||||
# RUN: --implicit-check-not=warning: -DNCHAIN=2
|
||||
|
||||
# RUN: yaml2obj --docnum=2 %s -o %t2-larger -DCHAIN="[1, 2, 3, 4]"
|
||||
# RUN: llvm-readobj --dyn-symbols %t2-larger 2>&1 | \
|
||||
# RUN: FileCheck %s --check-prefixes=LLVM2,LLVM2-MORE,LLVM2-ALL,WARN \
|
||||
# RUN: --implicit-check-not=warning: -DNCHAIN=4
|
||||
# RUN: llvm-readelf --dyn-symbols %t2-larger 2>&1 | \
|
||||
# RUN: FileCheck %s --check-prefixes=GNU2,GNU2-MORE,GNU2-ALL,WARN \
|
||||
# RUN: --implicit-check-not=warning: -DNCHAIN=4
|
||||
|
||||
## Show there's no warning if the sizes match
|
||||
# RUN: yaml2obj --docnum=2 %s -o %t2-same -DCHAIN="[1, 2, 3]"
|
||||
# RUN: llvm-readobj --dyn-symbols %t2-same 2>&1 | \
|
||||
# RUN: FileCheck %s --check-prefixes=LLVM2,LLVM2-MORE --implicit-check-not=warning:
|
||||
# RUN: llvm-readelf --dyn-symbols %t2-same 2>&1 | \
|
||||
# RUN: FileCheck %s --check-prefixes=GNU2,GNU2-MORE \
|
||||
# RUN: --implicit-check-not=warning: -DNCHAIN=3
|
||||
|
||||
# WARN: warning: '{{.*}}2-{{.*}}': hash table nchain ([[NCHAIN]]) differs from symbol count derived from SHT_DYNSYM section header (3)
|
||||
|
||||
# LLVM2: DynamicSymbols [
|
||||
# LLVM2-NEXT: Symbol {
|
||||
# LLVM2-NEXT: Name: (0)
|
||||
# LLVM2-NEXT: Value: 0x0
|
||||
# LLVM2-NEXT: Size: 0
|
||||
# LLVM2-NEXT: Binding: Local (0x0)
|
||||
# LLVM2-NEXT: Type: None (0x0)
|
||||
# LLVM2-NEXT: Other: 0
|
||||
# LLVM2-NEXT: Section: Undefined (0x0)
|
||||
# LLVM2-NEXT: }
|
||||
# LLVM2-NEXT: Symbol {
|
||||
# LLVM2-NEXT: Name: foo (9)
|
||||
# LLVM2-NEXT: Value: 0x100
|
||||
# LLVM2-NEXT: Size: 0
|
||||
# LLVM2-NEXT: Binding: Local (0x0)
|
||||
# LLVM2-NEXT: Type: Function (0x2)
|
||||
# LLVM2-NEXT: Other: 0
|
||||
# LLVM2-NEXT: Section: .text (0x1)
|
||||
# LLVM2-NEXT: }
|
||||
# LLVM2-MORE-NEXT: Symbol {
|
||||
# LLVM2-MORE-NEXT: Name: bar (5)
|
||||
# LLVM2-MORE-NEXT: Value: 0x200
|
||||
# LLVM2-MORE-NEXT: Size: 0
|
||||
# LLVM2-MORE-NEXT: Binding: Local (0x0)
|
||||
# LLVM2-MORE-NEXT: Type: Object (0x1)
|
||||
# LLVM2-MORE-NEXT: Other: 0
|
||||
# LLVM2-MORE-NEXT: Section: .data (0x2)
|
||||
# LLVM2-MORE-NEXT: }
|
||||
# LLVM2-ALL-NEXT: Symbol {
|
||||
# LLVM2-ALL-NEXT: Name: baz (1)
|
||||
# LLVM2-ALL-NEXT: Value: 0x300
|
||||
# LLVM2-ALL-NEXT: Size: 0
|
||||
# LLVM2-ALL-NEXT: Binding: Local (0x0)
|
||||
# LLVM2-ALL-NEXT: Type: Object (0x1)
|
||||
# LLVM2-ALL-NEXT: Other: 0
|
||||
# LLVM2-ALL-NEXT: Section: .data (0x2)
|
||||
# LLVM2-ALL-NEXT: }
|
||||
# LLVM2-NEXT: ]
|
||||
|
||||
# GNU2: Symbol table '.dynsym' contains [[NCHAIN]] entries:
|
||||
# GNU2-NEXT: Num: Value Size Type Bind Vis Ndx Name
|
||||
# GNU2-NEXT: 0: {{0*}}00000000 0 NOTYPE LOCAL DEFAULT UND
|
||||
# GNU2-NEXT: 1: {{0*}}00000100 0 FUNC LOCAL DEFAULT 1 foo
|
||||
# GNU2-MORE-NEXT: 2: {{0*}}00000200 0 OBJECT LOCAL DEFAULT 2 bar
|
||||
# GNU2-ALL-NEXT: 3: {{0*}}00000300 0 OBJECT LOCAL DEFAULT 2 baz
|
||||
# GNU2-EMPTY:
|
||||
|
||||
## In this YAML, we define 4 dynamic symbols (including the null symbol), but
|
||||
## constrain the .dynsym section header to say there are only 3. This means that
|
||||
## when a size of 4 is derived from the hash table, we still have a valid symbol
|
||||
## to dump.
|
||||
--- !ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_DYN
|
||||
Machine: EM_X86_64
|
||||
Sections:
|
||||
- Name: .text
|
||||
Type: SHT_PROGBITS
|
||||
- Name: .data
|
||||
Type: SHT_PROGBITS
|
||||
- Name: .dynsym
|
||||
Type: SHT_DYNSYM
|
||||
Flags: [ SHF_ALLOC ]
|
||||
ShSize: 0x48
|
||||
Address: 0x400
|
||||
AddressAlign: 0x400
|
||||
- Name: .hash
|
||||
Type: SHT_HASH
|
||||
Flags: [ SHF_ALLOC ]
|
||||
Address: 0x600
|
||||
AddressAlign: 0x200
|
||||
Bucket: [ 1 ]
|
||||
Chain: [[CHAIN]]
|
||||
- Name: .dynstr
|
||||
Type: SHT_STRTAB
|
||||
Flags: [ SHF_ALLOC ]
|
||||
Address: 0x800
|
||||
AddressAlign: 0x200
|
||||
- Name: .dynamic
|
||||
Type: SHT_DYNAMIC
|
||||
Flags: [ SHF_ALLOC ]
|
||||
Address: 0xA00
|
||||
AddressAlign: 0x200
|
||||
Entries:
|
||||
- Tag: DT_SYMTAB
|
||||
Value: 0x400
|
||||
- Tag: DT_HASH
|
||||
Value: 0x600
|
||||
- Tag: DT_STRTAB
|
||||
Value: 0x800
|
||||
- Tag: DT_STRSZ
|
||||
Value: 13
|
||||
- Tag: DT_NULL
|
||||
Value: 0
|
||||
DynamicSymbols:
|
||||
- Name: foo
|
||||
Type: STT_FUNC
|
||||
Section: .text
|
||||
Value: 0x100
|
||||
- Name: bar
|
||||
Type: STT_OBJECT
|
||||
Section: .data
|
||||
Value: 0x200
|
||||
- Name: baz
|
||||
Type: STT_OBJECT
|
||||
Section: .data
|
||||
Value: 0x300
|
||||
ProgramHeaders:
|
||||
- Type: PT_LOAD
|
||||
VAddr: 0
|
||||
Sections:
|
||||
- Section: .text
|
||||
- Section: .data
|
||||
- Type: PT_LOAD
|
||||
VAddr: 0x400
|
||||
Sections:
|
||||
- Section: .dynsym
|
||||
- Section: .hash
|
||||
- Section: .dynstr
|
||||
- Section: .dynamic
|
||||
- Type: PT_DYNAMIC
|
||||
VAddr: 0xA00
|
||||
Sections:
|
||||
- Section: .dynamic
|
||||
|
||||
## Case 3: DT_HASH is missing.
|
||||
## Show that no warning occurs if there are section headers.
|
||||
# RUN: yaml2obj --docnum=1 %s -o %t3 -DTAG1=DT_SYMTAB -DVAL1=0x400 -DTAG2=DT_NULL -DVAL2=0 -DBITS=64
|
||||
# RUN: llvm-readobj --dyn-symbols %t3 2>&1 | \
|
||||
# RUN: FileCheck %s --check-prefixes=LLVM1,NOSTRIP --implicit-check-not=warning:
|
||||
# RUN: llvm-readelf --dyn-symbols %t3 2>&1 | \
|
||||
# RUN: FileCheck %s --check-prefixes=GNU1,GNU1-NOSTRIP --implicit-check-not=warning:
|
||||
|
||||
## Show that size is treated as zero, if no section headers are present.
|
||||
# RUN: llvm-strip --strip-sections %t3
|
||||
# RUN: llvm-readobj --dyn-symbols %t3 2>&1 | \
|
||||
# RUN: FileCheck %s --check-prefix=LLVM3 --implicit-check-not=warning:
|
||||
# RUN: llvm-readelf --dyn-symbols %t3 2>&1 | \
|
||||
# RUN: FileCheck %s --implicit-check-not={{.}} --allow-empty
|
||||
|
||||
# LLVM3: DynamicSymbols [
|
||||
# LLVM3: ]
|
@ -283,7 +283,7 @@ private:
|
||||
DynRegionInfo DynRelaRegion;
|
||||
DynRegionInfo DynRelrRegion;
|
||||
DynRegionInfo DynPLTRelRegion;
|
||||
DynRegionInfo DynSymRegion;
|
||||
Optional<DynRegionInfo> DynSymRegion;
|
||||
DynRegionInfo DynamicTable;
|
||||
StringRef DynamicStringTable;
|
||||
std::string SOName = "<Not found>";
|
||||
@ -322,7 +322,9 @@ public:
|
||||
}
|
||||
|
||||
Elf_Sym_Range dynamic_symbols() const {
|
||||
return DynSymRegion.getAsArrayRef<Elf_Sym>();
|
||||
if (!DynSymRegion)
|
||||
return Elf_Sym_Range();
|
||||
return DynSymRegion->getAsArrayRef<Elf_Sym>();
|
||||
}
|
||||
|
||||
Elf_Rel_Range dyn_rels() const;
|
||||
@ -667,8 +669,8 @@ void ELFDumper<ELFT>::printSymbolsHelper(bool IsDynamic) const {
|
||||
StrTable = DynamicStringTable;
|
||||
Syms = dynamic_symbols();
|
||||
SymtabName = DynSymtabName;
|
||||
if (DynSymRegion.Addr)
|
||||
Entries = DynSymRegion.Size / DynSymRegion.EntSize;
|
||||
if (DynSymRegion)
|
||||
Entries = DynSymRegion->Size / DynSymRegion->EntSize;
|
||||
} else {
|
||||
if (!DotSymtabSec)
|
||||
return;
|
||||
@ -993,7 +995,7 @@ std::error_code createELFDumper(const object::ObjectFile *Obj,
|
||||
|
||||
template <class ELFT> Error ELFDumper<ELFT>::LoadVersionMap() const {
|
||||
// If there is no dynamic symtab or version table, there is nothing to do.
|
||||
if (!DynSymRegion.Addr || !SymbolVersionSection)
|
||||
if (!DynSymRegion || !SymbolVersionSection)
|
||||
return Error::success();
|
||||
|
||||
// Has the VersionMap already been loaded?
|
||||
@ -1043,10 +1045,11 @@ Expected<StringRef> ELFDumper<ELFT>::getSymbolVersion(const Elf_Sym *Sym,
|
||||
return "";
|
||||
}
|
||||
|
||||
assert(DynSymRegion && "DynSymRegion has not been initialised");
|
||||
// Determine the position in the symbol table of this entry.
|
||||
size_t EntryIndex = (reinterpret_cast<uintptr_t>(Sym) -
|
||||
reinterpret_cast<uintptr_t>(DynSymRegion.Addr)) /
|
||||
sizeof(Elf_Sym);
|
||||
reinterpret_cast<uintptr_t>(DynSymRegion->Addr)) /
|
||||
sizeof(Elf_Sym);
|
||||
|
||||
// Get the corresponding version index entry.
|
||||
const Elf_Versym *Versym = unwrapOrError(
|
||||
@ -1980,8 +1983,12 @@ ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> *ObjF,
|
||||
ScopedPrinter &Writer)
|
||||
: ObjDumper(Writer), ObjF(ObjF), DynRelRegion(ObjF->getFileName()),
|
||||
DynRelaRegion(ObjF->getFileName()), DynRelrRegion(ObjF->getFileName()),
|
||||
DynPLTRelRegion(ObjF->getFileName()), DynSymRegion(ObjF->getFileName()),
|
||||
DynamicTable(ObjF->getFileName()) {
|
||||
DynPLTRelRegion(ObjF->getFileName()), DynamicTable(ObjF->getFileName()) {
|
||||
if (opts::Output == opts::GNU)
|
||||
ELFDumperStyle.reset(new GNUStyle<ELFT>(Writer, this));
|
||||
else
|
||||
ELFDumperStyle.reset(new LLVMStyle<ELFT>(Writer, this));
|
||||
|
||||
const ELFFile<ELFT> *Obj = ObjF->getELFFile();
|
||||
typename ELFT::ShdrRange Sections =
|
||||
unwrapOrError(ObjF->getFileName(), Obj->sections());
|
||||
@ -1992,9 +1999,9 @@ ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> *ObjF,
|
||||
DotSymtabSec = &Sec;
|
||||
break;
|
||||
case ELF::SHT_DYNSYM:
|
||||
if (!DynSymRegion.Size) {
|
||||
if (!DynSymRegion) {
|
||||
DynSymRegion = createDRIFrom(&Sec);
|
||||
DynSymRegion.Context =
|
||||
DynSymRegion->Context =
|
||||
("section with index " + Twine(&Sec - &Sections.front())).str();
|
||||
// This is only used (if Elf_Shdr present)for naming section in GNU
|
||||
// style
|
||||
@ -2034,11 +2041,6 @@ ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> *ObjF,
|
||||
}
|
||||
|
||||
loadDynamicTable(Obj);
|
||||
|
||||
if (opts::Output == opts::GNU)
|
||||
ELFDumperStyle.reset(new GNUStyle<ELFT>(Writer, this));
|
||||
else
|
||||
ELFDumperStyle.reset(new LLVMStyle<ELFT>(Writer, this));
|
||||
}
|
||||
|
||||
template <typename ELFT>
|
||||
@ -2059,6 +2061,7 @@ void ELFDumper<ELFT>::parseDynamicTable(const ELFFile<ELFT> *Obj) {
|
||||
uint64_t SONameOffset = 0;
|
||||
const char *StringTableBegin = nullptr;
|
||||
uint64_t StringTableSize = 0;
|
||||
Optional<DynRegionInfo> DynSymFromTable;
|
||||
for (const Elf_Dyn &Dyn : dynamic_table()) {
|
||||
switch (Dyn.d_tag) {
|
||||
case ELF::DT_HASH:
|
||||
@ -2077,26 +2080,13 @@ void ELFDumper<ELFT>::parseDynamicTable(const ELFFile<ELFT> *Obj) {
|
||||
StringTableSize = Dyn.getVal();
|
||||
break;
|
||||
case ELF::DT_SYMTAB: {
|
||||
// Often we find the information about the dynamic symbol table
|
||||
// location in the SHT_DYNSYM section header. However, the value in
|
||||
// DT_SYMTAB has priority, because it is used by dynamic loaders to
|
||||
// locate .dynsym at runtime. The location we find in the section header
|
||||
// and the location we find here should match. If we can't map the
|
||||
// DT_SYMTAB value to an address (e.g. when there are no program headers), we
|
||||
// ignore its value.
|
||||
// If we can't map the DT_SYMTAB value to an address (e.g. when there are
|
||||
// no program headers), we ignore its value.
|
||||
if (const uint8_t *VA = toMappedAddr(Dyn.getTag(), Dyn.getPtr())) {
|
||||
// EntSize is non-zero if the dynamic symbol table has been found via a
|
||||
// section header.
|
||||
if (DynSymRegion.EntSize && VA != DynSymRegion.Addr)
|
||||
reportWarning(
|
||||
createError(
|
||||
"SHT_DYNSYM section header and DT_SYMTAB disagree about "
|
||||
"the location of the dynamic symbol table"),
|
||||
ObjF->getFileName());
|
||||
|
||||
DynSymRegion.Addr = VA;
|
||||
DynSymRegion.EntSize = sizeof(Elf_Sym);
|
||||
DynSymRegion.EntSizePrintName = "";
|
||||
DynSymFromTable.emplace(ObjF->getFileName());
|
||||
DynSymFromTable->Addr = VA;
|
||||
DynSymFromTable->EntSize = sizeof(Elf_Sym);
|
||||
DynSymFromTable->EntSizePrintName = "";
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -2176,6 +2166,48 @@ void ELFDumper<ELFT>::parseDynamicTable(const ELFFile<ELFT> *Obj) {
|
||||
if (StringTableBegin)
|
||||
DynamicStringTable = StringRef(StringTableBegin, StringTableSize);
|
||||
SOName = getDynamicString(SONameOffset);
|
||||
|
||||
if (DynSymRegion) {
|
||||
// Often we find the information about the dynamic symbol table
|
||||
// location in the SHT_DYNSYM section header. However, the value in
|
||||
// DT_SYMTAB has priority, because it is used by dynamic loaders to
|
||||
// locate .dynsym at runtime. The location we find in the section header
|
||||
// and the location we find here should match.
|
||||
if (DynSymFromTable && DynSymFromTable->Addr != DynSymRegion->Addr)
|
||||
ELFDumperStyle->reportUniqueWarning(
|
||||
createError("SHT_DYNSYM section header and DT_SYMTAB disagree about "
|
||||
"the location of the dynamic symbol table"));
|
||||
|
||||
// According to the ELF gABI: "The number of symbol table entries should
|
||||
// equal nchain". Check to see if the DT_HASH hash table nchain value
|
||||
// conflicts with the number of symbols in the dynamic symbol table
|
||||
// according to the section header.
|
||||
if (HashTable &&
|
||||
HashTable->nchain != DynSymRegion->Size / DynSymRegion->EntSize)
|
||||
ELFDumperStyle->reportUniqueWarning(createError(
|
||||
"hash table nchain (" + Twine(HashTable->nchain) +
|
||||
") differs from symbol count derived from SHT_DYNSYM section "
|
||||
"header (" +
|
||||
Twine(DynSymRegion->Size / DynSymRegion->EntSize) + ")"));
|
||||
}
|
||||
|
||||
// Delay the creation of the actual dynamic symbol table until now, so that
|
||||
// checks can always be made against the section header-based properties,
|
||||
// without worrying about tag order.
|
||||
if (DynSymFromTable) {
|
||||
if (!DynSymRegion) {
|
||||
DynSymRegion = DynSymFromTable;
|
||||
} else {
|
||||
DynSymRegion->Addr = DynSymFromTable->Addr;
|
||||
DynSymRegion->EntSize = DynSymFromTable->EntSize;
|
||||
DynSymRegion->EntSizePrintName = DynSymFromTable->EntSizePrintName;
|
||||
}
|
||||
}
|
||||
|
||||
// Derive the dynamic symbol table size from the DT_HASH hash table, if
|
||||
// present.
|
||||
if (HashTable && DynSymRegion)
|
||||
DynSymRegion->Size = HashTable->nchain * DynSymRegion->EntSize;
|
||||
}
|
||||
|
||||
template <typename ELFT>
|
||||
@ -2591,7 +2623,7 @@ template <typename ELFT> void ELFDumper<ELFT>::printGnuHashTable() {
|
||||
ArrayRef<Elf_Word> Buckets = GnuHashTable->buckets();
|
||||
W.printList("Buckets", Buckets);
|
||||
|
||||
if (!DynSymRegion.Addr) {
|
||||
if (!DynSymRegion) {
|
||||
reportWarning(createError("unable to dump 'Values' for the SHT_GNU_HASH "
|
||||
"section: no dynamic symbol table found"),
|
||||
ObjF->getFileName());
|
||||
@ -3689,10 +3721,10 @@ void GNUStyle<ELFT>::printSymtabMessage(const ELFO *Obj, StringRef Name,
|
||||
size_t Entries,
|
||||
bool NonVisibilityBitsUsed) {
|
||||
if (!Name.empty())
|
||||
OS << "\nSymbol table '" << Name << "' contains " << Entries
|
||||
<< " entries:\n";
|
||||
OS << "\nSymbol table '" << Name << "'";
|
||||
else
|
||||
OS << "\n Symbol table for image:\n";
|
||||
OS << "\nSymbol table for image";
|
||||
OS << " contains " << Entries << " entries:\n";
|
||||
|
||||
if (ELFT::Is64Bits)
|
||||
OS << " Num: Value Size Type Bind Vis";
|
||||
@ -5885,7 +5917,12 @@ void LLVMStyle<ELFT>::printSymbolSection(const Elf_Sym *Symbol,
|
||||
Expected<StringRef> SectionName =
|
||||
this->dumper()->getSymbolSectionName(Symbol, *SectionIndex);
|
||||
if (!SectionName) {
|
||||
this->reportUniqueWarning(SectionName.takeError());
|
||||
// Don't report an invalid section name if the section headers are missing.
|
||||
// In such situations, all sections will be "invalid".
|
||||
if (!this->dumper()->getElfObject()->sections().empty())
|
||||
this->reportUniqueWarning(SectionName.takeError());
|
||||
else
|
||||
consumeError(SectionName.takeError());
|
||||
W.printHex("Section", "<?>", *SectionIndex);
|
||||
} else {
|
||||
W.printHex("Section", *SectionName, *SectionIndex);
|
||||
|
Loading…
Reference in New Issue
Block a user