forked from OSchip/llvm-project
[llvm-readelf/obj] - Stop printing wrong addresses for arm32 unwind info for non-relocatable objects.
This is the first patch for https://bugs.llvm.org/show_bug.cgi?id=47581. Currently -u does not compute function addresses correctly and dumps broken addresses for non-relocatable objects. ARM spec says: "An index table entry consists of 2 words. The first word contains a prel31 offset (see Relocations) to the start of a function, with bit 31 clear." ... "The relocated 31 bits form a place-relative signed offset to the referenced entity. For brevity, this document will refer to the results of these relocations as "prel31 offsets"." (https://developer.arm.com/documentation/ihi0038/c/?lang=en#index-table-entries) (https://developer.arm.com/documentation/ihi0038/c/?lang=en#relocations) Currently we use an address of the SHT_ARM_EXIDX section instead of an address of an entry in computations. As a result we compute an offset that is not really "place-relative", but section relative, what is wrong. The patch fixes this issue. Differential revision: https://reviews.llvm.org/D88076
This commit is contained in:
parent
5bddaf6dbf
commit
bb0597067d
|
@ -0,0 +1,94 @@
|
|||
## Check that we dump the unwind information for a non-relocatable input properly.
|
||||
|
||||
## Check that we correctly decode function addresses and that we are able to
|
||||
## locate corresponding STT_FUNC symbols and dump function names properly.
|
||||
# RUN: yaml2obj %s -o %t
|
||||
# RUN: llvm-readobj -u %t | FileCheck --check-prefix=UNWIND %s
|
||||
# RUN: llvm-readelf -u %t | FileCheck --check-prefix=UNWIND %s
|
||||
|
||||
# UNWIND: UnwindInformation {
|
||||
# UNWIND-NEXT: UnwindIndexTable {
|
||||
# UNWIND-NEXT: SectionIndex: 2
|
||||
# UNWIND-NEXT: SectionName: .ARM.exidx
|
||||
# UNWIND-NEXT: SectionOffset: 0x34
|
||||
# UNWIND-NEXT: Entries [
|
||||
# UNWIND-NEXT: Entry {
|
||||
# UNWIND-NEXT: FunctionAddress: 0x230
|
||||
# UNWIND-NEXT: FunctionName: func1
|
||||
# UNWIND-NEXT: Model: Compact (Inline)
|
||||
# UNWIND-NEXT: PersonalityIndex: 0
|
||||
# UNWIND-NEXT: Opcodes [
|
||||
# UNWIND-NEXT: 0xB0 ; finish
|
||||
# UNWIND-NEXT: 0xB0 ; finish
|
||||
# UNWIND-NEXT: 0xB0 ; finish
|
||||
# UNWIND-NEXT: ]
|
||||
# UNWIND-NEXT: }
|
||||
# UNWIND-NEXT: Entry {
|
||||
# UNWIND-NEXT: FunctionAddress: 0x234
|
||||
# UNWIND-NEXT: FunctionName: func2
|
||||
# UNWIND-NEXT: Model: Compact (Inline)
|
||||
# UNWIND-NEXT: PersonalityIndex: 0
|
||||
# UNWIND-NEXT: Opcodes [
|
||||
# UNWIND-NEXT: 0x9B ; vsp = r11
|
||||
# UNWIND-NEXT: 0x84 0x80 ; pop {fp, lr}
|
||||
# UNWIND-NEXT: ]
|
||||
# UNWIND-NEXT: }
|
||||
# UNWIND-NEXT: Entry {
|
||||
# UNWIND-NEXT: FunctionAddress: 0x248
|
||||
# UNWIND-NEXT: FunctionName: func3
|
||||
# UNWIND-NEXT: Model: Compact (Inline)
|
||||
# UNWIND-NEXT: PersonalityIndex: 0
|
||||
# UNWIND-NEXT: Opcodes [
|
||||
# UNWIND-NEXT: 0xB0 ; finish
|
||||
# UNWIND-NEXT: 0xB0 ; finish
|
||||
# UNWIND-NEXT: 0xB0 ; finish
|
||||
# UNWIND-NEXT: ]
|
||||
# UNWIND-NEXT: }
|
||||
# UNWIND-NEXT: Entry {
|
||||
# UNWIND-NEXT: FunctionAddress: 0x24C
|
||||
# UNWIND-NEXT: Model: CantUnwind
|
||||
# UNWIND-NEXT: }
|
||||
# UNWIND-NEXT: ]
|
||||
# UNWIND-NEXT: }
|
||||
# UNWIND-NEXT: }
|
||||
|
||||
--- !ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS32
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_DYN
|
||||
Machine: EM_ARM
|
||||
Sections:
|
||||
- Name: .text
|
||||
Type: SHT_PROGBITS
|
||||
Address: 0x230
|
||||
- Name: .ARM.exidx
|
||||
Type: SHT_ARM_EXIDX
|
||||
Address: 0x24C
|
||||
ContentArray: [
|
||||
## Entry 1. Address of .ARM.exidx (0x24C) + entry offset (0) + 0x7fffffe4 == 0x230 (func1).
|
||||
0xE4, 0xFF, 0xFF, 0x7F, ## Word(0) = 0x7fffffe4 (31 bit).
|
||||
0xB0, 0xB0, 0xB0, 0x80, ## Word(1): arbitrary opcodes.
|
||||
## Entry 2. Address of .ARM.exidx (0x24C) + entry offset (8) + 0x7fffffe0 == 0x234 (func2).
|
||||
0xE0, 0xFF, 0xFF, 0x7F, ## Word(0) = 0x7fffffe0 (31 bit).
|
||||
0x80, 0x84, 0x9B, 0x80, ## Word(1): arbitrary opcodes.
|
||||
## Entry 3. Address of .ARM.exidx (0x24C) + entry offset (16) + 0x7fffffec == 0x248 (func2).
|
||||
0xEC, 0xFF, 0xFF, 0x7F, ## Word(0) = 0x7fffffec (31 bit).
|
||||
0xB0, 0xB0, 0xB0, 0x80, ## Word(1): arbitrary opcodes.
|
||||
## Entry 4. Address of .ARM.exidx (0x24C) + entry offset (24) + 0x7fffffe8 == 0x24C.
|
||||
0xE8, 0xFF, 0xFF, 0x7F, ## Word(0) = 0x7fffffe8 (31 bit).
|
||||
0x01, 0x00, 0x00, 0x00 ## Word(1) == EXIDX_CANTUNWIND
|
||||
]
|
||||
Symbols:
|
||||
- Name: func1
|
||||
Type: STT_FUNC
|
||||
Section: .text
|
||||
Value: 0x230
|
||||
- Name: func2
|
||||
Type: STT_FUNC
|
||||
Section: .text
|
||||
Value: 0x234
|
||||
- Name: func3
|
||||
Type: STT_FUNC
|
||||
Section: .text
|
||||
Value: 0x248
|
|
@ -341,7 +341,8 @@ class PrinterContext {
|
|||
return Location + Place;
|
||||
}
|
||||
|
||||
ErrorOr<StringRef> FunctionAtAddress(unsigned Section, uint64_t Address) const;
|
||||
ErrorOr<StringRef> FunctionAtAddress(uint64_t Address,
|
||||
Optional<unsigned> SectionIndex) const;
|
||||
const Elf_Shdr *FindExceptionTable(unsigned IndexTableIndex,
|
||||
off_t IndexTableOffset) const;
|
||||
|
||||
|
@ -363,8 +364,8 @@ const size_t PrinterContext<ET>::IndexTableEntrySize = 8;
|
|||
|
||||
template <typename ET>
|
||||
ErrorOr<StringRef>
|
||||
PrinterContext<ET>::FunctionAtAddress(unsigned Section,
|
||||
uint64_t Address) const {
|
||||
PrinterContext<ET>::FunctionAtAddress(uint64_t Address,
|
||||
Optional<unsigned> SectionIndex) const {
|
||||
if (!Symtab)
|
||||
return inconvertibleErrorCode();
|
||||
auto StrTableOrErr = ELF.getStringTableForSymtab(*Symtab);
|
||||
|
@ -372,9 +373,11 @@ PrinterContext<ET>::FunctionAtAddress(unsigned Section,
|
|||
reportError(StrTableOrErr.takeError(), FileName);
|
||||
StringRef StrTable = *StrTableOrErr;
|
||||
|
||||
for (const Elf_Sym &Sym : unwrapOrError(FileName, ELF.symbols(Symtab)))
|
||||
if (Sym.st_shndx == Section && Sym.st_value == Address &&
|
||||
Sym.getType() == ELF::STT_FUNC) {
|
||||
for (const Elf_Sym &Sym : unwrapOrError(FileName, ELF.symbols(Symtab))) {
|
||||
if (SectionIndex && *SectionIndex != Sym.st_shndx)
|
||||
continue;
|
||||
|
||||
if (Sym.st_value == Address && Sym.getType() == ELF::STT_FUNC) {
|
||||
auto NameOrErr = Sym.getName(StrTable);
|
||||
if (!NameOrErr) {
|
||||
// TODO: Actually report errors helpfully.
|
||||
|
@ -383,6 +386,8 @@ PrinterContext<ET>::FunctionAtAddress(unsigned Section,
|
|||
}
|
||||
return *NameOrErr;
|
||||
}
|
||||
}
|
||||
|
||||
return inconvertibleErrorCode();
|
||||
}
|
||||
|
||||
|
@ -485,7 +490,8 @@ void PrinterContext<ET>::PrintExceptionTable(const Elf_Shdr *IT,
|
|||
|
||||
uint64_t Address = PREL31(Word, EHT->sh_addr);
|
||||
SW.printHex("PersonalityRoutineAddress", Address);
|
||||
if (ErrorOr<StringRef> Name = FunctionAtAddress(EHT->sh_link, Address))
|
||||
if (ErrorOr<StringRef> Name =
|
||||
FunctionAtAddress(Address, (unsigned)EHT->sh_link))
|
||||
SW.printString("PersonalityRoutineName", *Name);
|
||||
}
|
||||
}
|
||||
|
@ -518,6 +524,7 @@ void PrinterContext<ET>::PrintIndexTable(unsigned SectionIndex,
|
|||
const support::ulittle32_t *Data =
|
||||
reinterpret_cast<const support::ulittle32_t *>(Contents->data());
|
||||
const unsigned Entries = IT->sh_size / IndexTableEntrySize;
|
||||
const bool IsRelocatable = ELF.getHeader().e_type == ELF::ET_REL;
|
||||
|
||||
ListScope E(SW, "Entries");
|
||||
for (unsigned Entry = 0; Entry < Entries; ++Entry) {
|
||||
|
@ -533,9 +540,31 @@ void PrinterContext<ET>::PrintIndexTable(unsigned SectionIndex,
|
|||
continue;
|
||||
}
|
||||
|
||||
const uint64_t Offset = PREL31(Word0, IT->sh_addr);
|
||||
SW.printHex("FunctionAddress", Offset);
|
||||
if (ErrorOr<StringRef> Name = FunctionAtAddress(IT->sh_link, Offset))
|
||||
// FIXME: For a relocatable object ideally we might want to:
|
||||
// 1) Find a relocation for the offset of Word0.
|
||||
// 2) Verify this relocation is of an expected type (R_ARM_PREL31) and
|
||||
// verify the symbol index.
|
||||
// 3) Resolve the relocation using it's symbol value, addend etc.
|
||||
// Currently the code assumes that Word0 contains an addend of a
|
||||
// R_ARM_PREL31 REL relocation that references a section symbol. RELA
|
||||
// relocations are not supported and it works because addresses of sections
|
||||
// are nulls in relocatable objects.
|
||||
//
|
||||
// For a non-relocatable object, Word0 contains a place-relative signed
|
||||
// offset to the referenced entity.
|
||||
const uint64_t Address =
|
||||
IsRelocatable
|
||||
? PREL31(Word0, IT->sh_addr)
|
||||
: PREL31(Word0, IT->sh_addr + Entry * IndexTableEntrySize);
|
||||
SW.printHex("FunctionAddress", Address);
|
||||
|
||||
// In a relocatable output we might have many .ARM.exidx sections linked to
|
||||
// their code sections via the sh_link field. For a non-relocatable ELF file
|
||||
// the sh_link field is not reliable, because we have one .ARM.exidx section
|
||||
// normally, but might have many code sections.
|
||||
Optional<unsigned> SecIndex =
|
||||
IsRelocatable ? Optional<unsigned>(IT->sh_link) : None;
|
||||
if (ErrorOr<StringRef> Name = FunctionAtAddress(Address, SecIndex))
|
||||
SW.printString("FunctionName", *Name);
|
||||
|
||||
if (Word1 == EXIDX_CANTUNWIND) {
|
||||
|
|
Loading…
Reference in New Issue