libdw: Allow .debug_frame only Dwarf.
authorMark Wielaard <mark@klomp.org>
Wed, 27 Jun 2018 12:41:22 +0000 (14:41 +0200)
committerMark Wielaard <mark@klomp.org>
Fri, 29 Jun 2018 10:12:21 +0000 (12:12 +0200)
.debug_frame is useful independent from the other .debug sections.

Add a simplified variant of the addrcfi testcase dwarfcfi.
dwarfcfi only uses dwarf_frame calls and no dwfl helpers.

Signed-off-by: Mark Wielaard <mark@klomp.org>
12 files changed:
libdw/ChangeLog
libdw/dwarf_begin_elf.c
tests/ChangeLog
tests/Makefile.am
tests/dwarfcfi.c [new file with mode: 0644]
tests/run-dwarfcfi.sh [new file with mode: 0755]
tests/testfile11-debugframe.bz2 [new file with mode: 0644]
tests/testfile12-debugframe.bz2 [new file with mode: 0644]
tests/testfileaarch64-debugframe.bz2 [new file with mode: 0755]
tests/testfilearm-debugframe.bz2 [new file with mode: 0755]
tests/testfileppc32-debugframe.bz2 [new file with mode: 0755]
tests/testfileppc64-debugframe.bz2 [new file with mode: 0755]

index 0ae1272..1e86e68 100644 (file)
@@ -1,3 +1,8 @@
+2018-06-27  Mark Wielaard  <mark@klomp.org>
+
+       * dwarf_begin_elf.c (check_section): Allow a single .debug_frame
+       section.
+
 2018-06-26  Mark Wielaard  <mark@klomp.org>
 
        * libdw.h (dwarf_getscn_info): Remove.
index e1542c7..184a6dc 100644 (file)
@@ -209,7 +209,8 @@ valid_p (Dwarf *result)
      Require at least one section that can be read "standalone".  */
   if (likely (result != NULL)
       && unlikely (result->sectiondata[IDX_debug_info] == NULL
-                  && result->sectiondata[IDX_debug_line] == NULL))
+                  && result->sectiondata[IDX_debug_line] == NULL
+                  && result->sectiondata[IDX_debug_frame] == NULL))
     {
       Dwarf_Sig8_Hash_free (&result->sig8_hash);
       __libdw_seterrno (DWARF_E_NO_DWARF);
index d660410..35a5d7e 100644 (file)
@@ -1,3 +1,20 @@
+2018-06-27  Mark Wielaard  <mark@klomp.org>
+
+       * dwarf_cfi.c: New file.
+       * run-dwarfcfi.sh: New test.
+       * testfile11-debugframe.bz2: New testfile.
+       * testfile12-debugframe.bz2: Likewise.
+       * testfileaarch64-debugframe.bz2: Likewise.
+       * testfilearm-debugframe.bz2: Likewise.
+       * testfileppc32-debugframe.bz2: Likewise.
+       * testfileppc64-debugframe.bz2: Likewise.
+       * Makefile.am (check_PROGRAMS): Add dwarfcfi.
+       (TESTS): Add run-dwarfcfi.sh.
+       (EXTRA_DIST): Add run-dwarfcfi.sh, testfile11-debugframe.bz2,
+       testfile12-debugframe.bz2, testfileaarch64-debugframe.bz2,
+       testfilearm-debugframe.bz2, testfileppc32-debugframe.bz2 and
+       testfileppc64-debugframe.bz2.
+
 2018-06-23  Mark Wielaard  <mark@klomp.org>
 
        * varlocs.c (print_expr): Take a new depth argument. Check it isn't
index 7b29fd8..47e5555 100644 (file)
@@ -46,6 +46,7 @@ check_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \
                  dwfl-bug-addr-overflow arls dwfl-bug-fd-leak \
                  dwfl-addr-sect dwfl-bug-report early-offscn \
                  dwfl-bug-getmodules dwarf-getmacros dwarf-ranges addrcfi \
+                 dwarfcfi \
                  test-flag-nobits dwarf-getstring rerequest_tag \
                  alldts typeiter typeiter2 low_high_pc \
                  test-elf_cntl_gelf_getshdr dwflsyms dwfllines \
@@ -95,6 +96,7 @@ TESTS = run-arextract.sh run-arsymtest.sh run-ar.sh newfile test-nlist \
        run-ranlib-test2.sh run-ranlib-test3.sh run-ranlib-test4.sh \
        run-addrscopes.sh run-strings-test.sh run-funcscopes.sh \
        run-find-prologues.sh run-allregs.sh run-addrcfi.sh \
+       run-dwarfcfi.sh \
        run-nm-self.sh run-readelf-self.sh run-readelf-info-plus.sh \
        run-readelf-const-values.sh \
        run-varlocs-self.sh run-exprlocs-self.sh \
@@ -205,7 +207,10 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \
             run-addrscopes.sh run-strings-test.sh run-funcscopes.sh \
             run-nm-self.sh run-readelf-self.sh run-readelf-info-plus.sh \
             run-readelf-const-values.sh testfile-const-values.debug.bz2 \
-            run-addrcfi.sh \
+            run-addrcfi.sh run-dwarfcfi.sh \
+            testfile11-debugframe.bz2 testfile12-debugframe.bz2 \
+            testfileaarch64-debugframe.bz2 testfilearm-debugframe.bz2 \
+            testfileppc32-debugframe.bz2 testfileppc64-debugframe.bz2 \
             run-varlocs-self.sh run-exprlocs-self.sh \
             run-find-prologues.sh run-allregs.sh run-native-test.sh \
             run-addrname-test.sh run-dwfl-bug-offline-rel.sh \
@@ -506,6 +511,7 @@ dwarf_getmacros_LDADD = $(libdw)
 dwarf_ranges_LDADD = $(libdw)
 dwarf_getstring_LDADD = $(libdw)
 addrcfi_LDADD = $(libdw) $(libebl) $(libelf) $(argp_LDADD) -ldl
+dwarfcfi_LDADD = $(libdw) $(libelf)
 test_flag_nobits_LDADD = $(libelf)
 rerequest_tag_LDADD = $(libdw)
 alldts_LDADD = $(libdw) $(libelf)
diff --git a/tests/dwarfcfi.c b/tests/dwarfcfi.c
new file mode 100644 (file)
index 0000000..db4a36f
--- /dev/null
@@ -0,0 +1,175 @@
+/* Test program for DWARF (.debug_frame) CFI handling.
+   Copyright (C) 2009-2010, 2013, 2015, 2018 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+#include <assert.h>
+#include <inttypes.h>
+#include <error.h>
+#include ELFUTILS_HEADER(dw)
+#include <dwarf.h>
+#include <argp.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <locale.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../libdw/known-dwarf.h"
+
+static const char *
+op_name (unsigned int code)
+{
+  static const char *const known[] =
+    {
+#define DWARF_ONE_KNOWN_DW_OP(NAME, CODE) [CODE] = #NAME,
+      DWARF_ALL_KNOWN_DW_OP
+#undef DWARF_ONE_KNOWN_DW_OP
+    };
+
+  if (likely (code < sizeof (known) / sizeof (known[0])))
+    return known[code];
+
+  return NULL;
+}
+
+static void
+print_detail (int result, const Dwarf_Op *ops, size_t nops)
+{
+  if (result < 0)
+    printf ("indeterminate (%s)\n", dwarf_errmsg (-1));
+  else if (nops == 0)
+    printf ("%s\n", ops == NULL ? "same_value" : "undefined");
+  else
+    {
+      printf ("%s expression:", result == 0 ? "location" : "value");
+      for (size_t i = 0; i < nops; ++i)
+       {
+         printf (" %s", op_name(ops[i].atom));
+         if (ops[i].number2 == 0)
+           {
+             if (ops[i].atom == DW_OP_addr)
+               printf ("(%#" PRIx64 ")", ops[i].number);
+             else if (ops[i].number != 0)
+               printf ("(%" PRId64 ")", ops[i].number);
+           }
+         else
+           printf ("(%" PRId64 ",%" PRId64 ")",
+                   ops[i].number, ops[i].number2);
+       }
+      puts ("");
+    }
+}
+
+static int
+handle_address (Dwarf_CFI *cfi, GElf_Addr pc)
+{
+  Dwarf_Frame *frame;
+  int result = dwarf_cfi_addrframe (cfi, pc, &frame);
+  if (result != 0)
+    {
+      printf ("dwarf_cfi_addrframe: %s\n", dwarf_errmsg (-1));
+      return 1;
+    }
+
+  Dwarf_Addr start = pc;
+  Dwarf_Addr end = pc;
+  bool signalp;
+  int ra_regno = dwarf_frame_info (frame, &start, &end, &signalp);
+
+  printf ("%#" PRIx64 " => [%#" PRIx64 ", %#" PRIx64 "):\n",
+         pc, start, end);
+
+  if (ra_regno < 0)
+    printf ("\treturn address register unavailable (%s)\n",
+           dwarf_errmsg (-1));
+  else
+    printf ("\treturn address in reg%u%s\n",
+           ra_regno, signalp ? " (signal frame)" : "");
+
+  // Point cfa_ops to dummy to match print_detail expectations.
+  // (nops == 0 && cfa_ops != NULL => "undefined")
+  Dwarf_Op dummy;
+  Dwarf_Op *cfa_ops = &dummy;
+  size_t cfa_nops;
+  result = dwarf_frame_cfa (frame, &cfa_ops, &cfa_nops);
+
+  printf ("\tCFA ");
+  print_detail (result, cfa_ops, cfa_nops);
+
+  // Print the location of the first 10 (DWARF nr) registers
+  for (int r = 0; r < 10; r++)
+    {
+      Dwarf_Op ops_mem[3];
+      Dwarf_Op *ops;
+      size_t nops;
+      printf ("\treg%d: ", r);
+      int reg_result = dwarf_frame_register (frame, r, ops_mem, &ops, &nops);
+      print_detail (reg_result, ops, nops);
+      result |= reg_result;
+    }
+
+  free (frame);
+  return result;
+}
+
+int
+main (int argc, char *argv[])
+{
+  if (argc <= 2)
+    error (EXIT_FAILURE, 0, "need file name argument and addresses");
+
+  int fd = open (argv[1], O_RDONLY);
+  if (fd == -1)
+    error (EXIT_FAILURE, errno, "cannot open input file `%s'", argv[1]);
+
+  elf_version (EV_CURRENT);
+
+  Elf *elf = elf_begin (fd, ELF_C_READ, NULL);
+  if (elf == NULL)
+    error (EXIT_FAILURE, 0, "cannot create ELF descriptor: %s",
+          elf_errmsg (-1));
+
+  Dwarf *dwarf = dwarf_begin_elf (elf, DWARF_C_READ, NULL);
+  if (dwarf == NULL)
+    error (EXIT_FAILURE, 0, "cannot create DWARF descriptor: %s",
+          dwarf_errmsg (-1));
+
+  Dwarf_CFI *cfi = dwarf_getcfi (dwarf);
+  if (cfi == NULL)
+    error (EXIT_FAILURE, 0, "cannot get DWARF CFI from .dwarf_frame: %s",
+          dwarf_errmsg (-1));
+
+  int result = 0;
+  int args = 2;
+  do
+    {
+      char *endp;
+      uintmax_t addr = strtoumax (argv[args], &endp, 0);
+      if (endp != argv[args])
+       result |= handle_address (cfi, addr);
+      else
+       result = 1;
+    }
+  while (args++ < argc - 1);
+
+  dwarf_end (dwarf);
+  elf_end (elf);
+
+  return result;
+}
diff --git a/tests/run-dwarfcfi.sh b/tests/run-dwarfcfi.sh
new file mode 100755 (executable)
index 0000000..98fa171
--- /dev/null
@@ -0,0 +1,133 @@
+#! /bin/sh
+# Test for dwarf_getcfi.
+# Copyright (C) 2018 Red Hat, Inc.
+# This file is part of elfutils.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# elfutils is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+. $srcdir/test-subr.sh
+
+# Test files come from run-addrcfi with all sections stripped except
+# the .debug_frame.
+# for i in <testfiles>
+#   eu-strip -f $i-debugframe $i
+#   eu-strip -g --remove-comment --keep-section=.debug_frame $i-debugframe
+# done
+testfiles testfile11-debugframe testfile12-debugframe
+testfiles testfileaarch64-debugframe
+testfiles testfilearm-debugframe
+testfiles testfileppc32-debugframe
+testfiles testfileppc64-debugframe
+
+testfiles testfile11-debugframe
+testrun_compare ${abs_builddir}/dwarfcfi testfile11-debugframe 0x080489b8 <<\EOF
+0x80489b8 => [0x80489b8, 0x80489b9):
+       return address in reg8
+       CFA location expression: bregx(4,4)
+       reg0: undefined
+       reg1: undefined
+       reg2: undefined
+       reg3: same_value
+       reg4: location expression: call_frame_cfa stack_value
+       reg5: same_value
+       reg6: same_value
+       reg7: same_value
+       reg8: location expression: call_frame_cfa plus_uconst(-4)
+       reg9: undefined
+EOF
+
+testfiles testfile12-debugframe
+testrun_compare ${abs_builddir}/dwarfcfi testfile12-debugframe 0x00000000000009d0 <<\EOF
+0x9d0 => [0x9d0, 0x9d1):
+       return address in reg16
+       CFA location expression: bregx(7,8)
+       reg0: same_value
+       reg1: undefined
+       reg2: undefined
+       reg3: undefined
+       reg4: undefined
+       reg5: undefined
+       reg6: same_value
+       reg7: location expression: call_frame_cfa stack_value
+       reg8: undefined
+       reg9: undefined
+EOF
+
+testfiles testfileppc32-debugframe
+testrun_compare ${abs_builddir}/dwarfcfi testfileppc32-debugframe 0x100004c0 <<\EOF
+0x100004c0 => [0x100004c0, 0x100004d0):
+       return address in reg65
+       CFA location expression: bregx(1)
+       reg0: undefined
+       reg1: location expression: call_frame_cfa stack_value
+       reg2: same_value
+       reg3: undefined
+       reg4: undefined
+       reg5: undefined
+       reg6: undefined
+       reg7: undefined
+       reg8: undefined
+       reg9: undefined
+EOF
+
+testfiles testfileppc64-debugframe
+testrun_compare ${abs_builddir}/dwarfcfi testfileppc64-debugframe 0x00000000100005b0 <<\EOF
+0x100005b0 => [0x100005b0, 0x100005d0):
+       return address in reg65
+       CFA location expression: bregx(1)
+       reg0: undefined
+       reg1: location expression: call_frame_cfa stack_value
+       reg2: same_value
+       reg3: undefined
+       reg4: undefined
+       reg5: undefined
+       reg6: undefined
+       reg7: undefined
+       reg8: undefined
+       reg9: undefined
+EOF
+
+testfiles testfilearm-debugframe
+testrun_compare ${abs_builddir}/dwarfcfi testfilearm-debugframe 0x00008510 <<\EOF
+0x8510 => [0x8510, 0x8524):
+       return address in reg14
+       CFA location expression: bregx(13)
+       reg0: undefined
+       reg1: undefined
+       reg2: undefined
+       reg3: undefined
+       reg4: same_value
+       reg5: same_value
+       reg6: same_value
+       reg7: same_value
+       reg8: same_value
+       reg9: undefined
+EOF
+
+testfiles testfileaarch64-debugframe
+testrun_compare ${abs_builddir}/dwarfcfi testfileaarch64-debugframe 0x400550 <<\EOF
+0x400550 => [0x400550, 0x400568):
+       return address in reg30
+       CFA location expression: bregx(31)
+       reg0: undefined
+       reg1: undefined
+       reg2: undefined
+       reg3: undefined
+       reg4: undefined
+       reg5: undefined
+       reg6: undefined
+       reg7: undefined
+       reg8: undefined
+       reg9: undefined
+EOF
diff --git a/tests/testfile11-debugframe.bz2 b/tests/testfile11-debugframe.bz2
new file mode 100644 (file)
index 0000000..5c07d16
Binary files /dev/null and b/tests/testfile11-debugframe.bz2 differ
diff --git a/tests/testfile12-debugframe.bz2 b/tests/testfile12-debugframe.bz2
new file mode 100644 (file)
index 0000000..b8cc19c
Binary files /dev/null and b/tests/testfile12-debugframe.bz2 differ
diff --git a/tests/testfileaarch64-debugframe.bz2 b/tests/testfileaarch64-debugframe.bz2
new file mode 100755 (executable)
index 0000000..e77494a
Binary files /dev/null and b/tests/testfileaarch64-debugframe.bz2 differ
diff --git a/tests/testfilearm-debugframe.bz2 b/tests/testfilearm-debugframe.bz2
new file mode 100755 (executable)
index 0000000..51ce2d3
Binary files /dev/null and b/tests/testfilearm-debugframe.bz2 differ
diff --git a/tests/testfileppc32-debugframe.bz2 b/tests/testfileppc32-debugframe.bz2
new file mode 100755 (executable)
index 0000000..b6ae4ea
Binary files /dev/null and b/tests/testfileppc32-debugframe.bz2 differ
diff --git a/tests/testfileppc64-debugframe.bz2 b/tests/testfileppc64-debugframe.bz2
new file mode 100755 (executable)
index 0000000..85c80ac
Binary files /dev/null and b/tests/testfileppc64-debugframe.bz2 differ