diff --git a/llvm/test/tools/llvm-readobj/ELF/ARM/unwind-non-relocatable.test b/llvm/test/tools/llvm-readobj/ELF/ARM/unwind-non-relocatable.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/ELF/ARM/unwind-non-relocatable.test @@ -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 diff --git a/llvm/tools/llvm-readobj/ARMEHABIPrinter.h b/llvm/tools/llvm-readobj/ARMEHABIPrinter.h --- a/llvm/tools/llvm-readobj/ARMEHABIPrinter.h +++ b/llvm/tools/llvm-readobj/ARMEHABIPrinter.h @@ -341,7 +341,8 @@ return Location + Place; } - ErrorOr FunctionAtAddress(unsigned Section, uint64_t Address) const; + ErrorOr FunctionAtAddress(uint64_t Address, + Optional SectionIndex) const; const Elf_Shdr *FindExceptionTable(unsigned IndexTableIndex, off_t IndexTableOffset) const; @@ -363,8 +364,8 @@ template ErrorOr -PrinterContext::FunctionAtAddress(unsigned Section, - uint64_t Address) const { +PrinterContext::FunctionAtAddress(uint64_t Address, + Optional SectionIndex) const { if (!Symtab) return inconvertibleErrorCode(); auto StrTableOrErr = ELF.getStringTableForSymtab(*Symtab); @@ -372,9 +373,11 @@ 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 @@ } return *NameOrErr; } + } + return inconvertibleErrorCode(); } @@ -485,7 +490,8 @@ uint64_t Address = PREL31(Word, EHT->sh_addr); SW.printHex("PersonalityRoutineAddress", Address); - if (ErrorOr Name = FunctionAtAddress(EHT->sh_link, Address)) + if (ErrorOr Name = + FunctionAtAddress(Address, (unsigned)EHT->sh_link)) SW.printString("PersonalityRoutineName", *Name); } } @@ -518,6 +524,7 @@ const support::ulittle32_t *Data = reinterpret_cast(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 @@ continue; } - const uint64_t Offset = PREL31(Word0, IT->sh_addr); - SW.printHex("FunctionAddress", Offset); - if (ErrorOr 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 SecIndex = + IsRelocatable ? Optional(IT->sh_link) : None; + if (ErrorOr Name = FunctionAtAddress(Address, SecIndex)) SW.printString("FunctionName", *Name); if (Word1 == EXIDX_CANTUNWIND) {