[dsymutil] Fix .debug_addr index calculation
authorJonas Devlieghere <jonas@devlieghere.com>
Fri, 16 Jun 2023 19:24:27 +0000 (12:24 -0700)
committerJonas Devlieghere <jonas@devlieghere.com>
Fri, 16 Jun 2023 20:27:32 +0000 (13:27 -0700)
The DW_OP_addrx operation encodes a zero-based index into the
.debug_addr section. The index is relative to the DW_AT_addr_base
attribute of the associated compilation unit. In order to compute the
offset into the .debug_addr section and find the associated relocation,
we need to add the add the add base offset and multiply the index with
the address size.

This patch fixes a bug in this computation, where the multiplication was
omitted. This went unnoticed because for small test cases, the index for
interesting addresses (such as the main subprogram) is often zero.

rdar://110881668

Differential revision: https://reviews.llvm.org/D153162

llvm/test/tools/dsymutil/ARM/dwarf5-addrx-0x0-last.test [new file with mode: 0644]
llvm/test/tools/dsymutil/Inputs/private/tmp/dwarf5/dwarf5-addrx-0x0-last.o [new file with mode: 0644]
llvm/test/tools/dsymutil/Inputs/private/tmp/dwarf5/dwarf5-addrx-0x0-last.out [new file with mode: 0755]
llvm/tools/dsymutil/DwarfLinkerForBinary.cpp

diff --git a/llvm/test/tools/dsymutil/ARM/dwarf5-addrx-0x0-last.test b/llvm/test/tools/dsymutil/ARM/dwarf5-addrx-0x0-last.test
new file mode 100644 (file)
index 0000000..8769776
--- /dev/null
@@ -0,0 +1,45 @@
+$ cat dwarf5-addrx-0x0-last.c
+#include <stdio.h>
+
+int main (int argc, char const *argv[])
+{
+  int pass_me = argc + 10;
+  printf("Foo\n");
+  printf("Bar\n");
+
+  return 0;
+}
+
+$ clang -gdwarf-5 dwarf5-addrx-0x0-last.c -c -o dwarf5-addrx-0x0-last.o
+$ clang dwarf5-addrx-0x0-last.o -o dwarf5-addrx-0x0-last.out
+
+# Sanity check: make sure main's low PC (0x0) requires an index computation
+# into the .debug_addr section.
+RUN: llvm-dwarfdump -debug-addr %p/../Inputs/private/tmp/dwarf5/dwarf5-addrx-0x0-last.o | FileCheck %s --check-prefix DEBUGADDR
+
+DEBUGADDR: Addrs: [
+DEBUGADDR: 0x0000000000000054
+DEBUGADDR: 0x0000000000000059
+DEBUGADDR: 0x0000000000000000
+DEBUGADDR: ]
+
+RUN: dsymutil -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/dwarf5/dwarf5-addrx-0x0-last.out -o %t.dSYM 2>&1 | FileCheck %s --allow-empty
+RUN: llvm-dwarfdump --verify %t.dSYM 2>&1 | FileCheck %s
+RUN: llvm-dwarfdump --verbose -debug-info %t.dSYM | FileCheck %s --check-prefix DEBUGINFO
+RUN: llvm-dwarfdump --verbose -debug-line %t.dSYM | FileCheck %s --check-prefix DEBUGLINE
+
+CHECK-NOT: error:
+
+DEBUGINFO:   DW_TAG_subprogram
+DEBUGINFO:     DW_AT_low_pc [DW_FORM_addr]     (0x0000000100003f4c)
+DEBUGINFO:     DW_AT_high_pc [DW_FORM_data4]   (0x00000054)
+DEBUGINFO:     DW_AT_name [DW_FORM_strp]       ( .debug_str[0x0000011c] = "main")
+
+DEBUGLINE:  0x0000000100003f4c   4   0  {{.*}}  is_stmt
+DEBUGLINE:  0x0000000100003f6c   5  17  {{.*}}  is_stmt prologue_end
+DEBUGLINE:  0x0000000100003f70   5  22  {{.*}}
+DEBUGLINE:  0x0000000100003f74   5   7  {{.*}}
+DEBUGLINE:  0x0000000100003f78   6   3  {{.*}}  is_stmt
+DEBUGLINE:  0x0000000100003f84   7   3  {{.*}}  is_stmt
+DEBUGLINE:  0x0000000100003f94   9   3  {{.*}}  is_stmt epilogue_begin
+DEBUGLINE:  0x0000000100003fa0   9   3  {{.*}}  is_stmt end_sequence
diff --git a/llvm/test/tools/dsymutil/Inputs/private/tmp/dwarf5/dwarf5-addrx-0x0-last.o b/llvm/test/tools/dsymutil/Inputs/private/tmp/dwarf5/dwarf5-addrx-0x0-last.o
new file mode 100644 (file)
index 0000000..014d6bb
Binary files /dev/null and b/llvm/test/tools/dsymutil/Inputs/private/tmp/dwarf5/dwarf5-addrx-0x0-last.o differ
diff --git a/llvm/test/tools/dsymutil/Inputs/private/tmp/dwarf5/dwarf5-addrx-0x0-last.out b/llvm/test/tools/dsymutil/Inputs/private/tmp/dwarf5/dwarf5-addrx-0x0-last.out
new file mode 100755 (executable)
index 0000000..30d7637
Binary files /dev/null and b/llvm/test/tools/dsymutil/Inputs/private/tmp/dwarf5/dwarf5-addrx-0x0-last.out differ
index 9841890..dd1c42f 100644 (file)
@@ -1081,9 +1081,12 @@ std::optional<int64_t> DwarfLinkerForBinary::AddressManager<
     std::optional<DWARFFormValue> AddrValue = DIE.find(dwarf::DW_AT_low_pc);
     if (std::optional<uint64_t> AddrOffsetSectionBase =
             DIE.getDwarfUnit()->getAddrOffsetSectionBase()) {
-      uint64_t StartOffset = *AddrOffsetSectionBase + AddrValue->getRawUValue();
-      uint64_t EndOffset =
-          StartOffset + DIE.getDwarfUnit()->getAddressByteSize();
+      // Addrx is a index into the debug_addr section, not an offset, so we need
+      // to multiply by byte size.
+      const uint64_t ByteSize = DIE.getDwarfUnit()->getAddressByteSize();
+      const uint64_t StartOffset =
+          *AddrOffsetSectionBase + (AddrValue->getRawUValue() * ByteSize);
+      const uint64_t EndOffset = StartOffset + ByteSize;
       return hasValidRelocationAt(ValidDebugAddrRelocs, StartOffset, EndOffset);
     }