[llvm] bb05970 - [llvm-readelf/obj] - Stop printing wrong addresses for arm32 unwind info for non-relocatable objects.

Georgii Rymar via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 24 03:32:02 PDT 2020


Author: Georgii Rymar
Date: 2020-09-24T13:21:00+03:00
New Revision: bb0597067d1e7410e67d8c7d8a4c0ec9e6b26cd0

URL: https://github.com/llvm/llvm-project/commit/bb0597067d1e7410e67d8c7d8a4c0ec9e6b26cd0
DIFF: https://github.com/llvm/llvm-project/commit/bb0597067d1e7410e67d8c7d8a4c0ec9e6b26cd0.diff

LOG: [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

Added: 
    llvm/test/tools/llvm-readobj/ELF/ARM/unwind-non-relocatable.test

Modified: 
    llvm/tools/llvm-readobj/ARMEHABIPrinter.h

Removed: 
    


################################################################################
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
index 000000000000..3ceeab1f2d95
--- /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
index a743d808845e..e4ac16a882c7 100644
--- a/llvm/tools/llvm-readobj/ARMEHABIPrinter.h
+++ b/llvm/tools/llvm-readobj/ARMEHABIPrinter.h
@@ -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) {


        


More information about the llvm-commits mailing list