[PATCH] tests: Add varlocs-self and exprlocs-self tests.

Mark Wielaard mark@klomp.org
Fri Nov 10 16:12:00 GMT 2017


Make sure the testcases (library functions they use) don't crash,
triggers self-check/asserts or leaks memory under valgrind. This
also helps making sure newer DWARF constructs are handled (when
building with -gdwarf-5).

Signed-off-by: Mark Wielaard <mark@klomp.org>
---
 tests/ChangeLog            | 16 ++++++++++++
 tests/Makefile.am          |  2 ++
 tests/run-exprlocs-self.sh | 22 ++++++++++++++++
 tests/run-varlocs-self.sh  | 22 ++++++++++++++++
 tests/varlocs.c            | 64 ++++++++++++++++++++++++++++++++++------------
 5 files changed, 110 insertions(+), 16 deletions(-)
 create mode 100755 tests/run-exprlocs-self.sh
 create mode 100755 tests/run-varlocs-self.sh

diff --git a/tests/ChangeLog b/tests/ChangeLog
index f39a027..6c8a8e1 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,19 @@
+2017-11-10  Mark Wielaard  <mark@klomp.org>
+
+	* run-exprlocs-self.sh: New test.
+	* run-varlocs-self.sh: Likewise.
+	* Makefile.am (TESTS) Add run-exprlocs-self.sh and
+	run-varlocs-self.sh.
+	(EXTRA_DIST): Likewise.
+	* varlocs.c (cfi_debug_bias): New global variable.
+	(is_ET_REL): Likewise.
+	(print_expr): Don't crash and burn when CFI cannot be found for an
+	ET_REL file for DW_OP_call_frame_cfa.
+	(handle_die): If there is no entry_pc pick the lowest pc start range
+	for the DIE.
+	(main): Check at least one CU was found. Use dwfl_module_dwarf_cfi
+	and dwfl_module_eh_cfi to fix memory leak. Set is_ET_REL.
+
 2017-11-03  Mark Wielaard  <mark@klomp.org>
 
 	* run-exprlocs.sh: New test.
diff --git a/tests/Makefile.am b/tests/Makefile.am
index f992b12..d502054 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -92,6 +92,7 @@ TESTS = run-arextract.sh run-arsymtest.sh run-ar.sh newfile test-nlist \
 	run-addrscopes.sh run-strings-test.sh run-funcscopes.sh \
 	run-find-prologues.sh run-allregs.sh run-addrcfi.sh \
 	run-nm-self.sh run-readelf-self.sh \
+	run-varlocs-self.sh run-exprlocs-self.sh \
 	run-readelf-test1.sh run-readelf-test2.sh run-readelf-test3.sh \
 	run-readelf-test4.sh run-readelf-twofiles.sh \
 	run-readelf-macro.sh run-readelf-loc.sh \
@@ -189,6 +190,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \
 	     run-ranlib-test3.sh run-ranlib-test4.sh \
 	     run-addrscopes.sh run-strings-test.sh run-funcscopes.sh \
 	     run-nm-self.sh run-readelf-self.sh run-addrcfi.sh \
+	     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 \
 	     run-dwfl-addr-sect.sh run-early-offscn.sh \
diff --git a/tests/run-exprlocs-self.sh b/tests/run-exprlocs-self.sh
new file mode 100755
index 0000000..73d3ab9
--- /dev/null
+++ b/tests/run-exprlocs-self.sh
@@ -0,0 +1,22 @@
+#! /bin/sh
+# Copyright (C) 2017 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
+
+# Just makes sure exprlocs doesn't crash, triggers self-check/asserts
+# or leaks memory under valgrind.
+testrun_on_self_quiet ${abs_top_builddir}/tests/varlocs --exprlocs -e
diff --git a/tests/run-varlocs-self.sh b/tests/run-varlocs-self.sh
new file mode 100755
index 0000000..54b6a8d
--- /dev/null
+++ b/tests/run-varlocs-self.sh
@@ -0,0 +1,22 @@
+#! /bin/sh
+# Copyright (C) 2017 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
+
+# Make sure varlocs doesn't crash, doesn't trigger self-check/asserts
+# or leaks running under valgrind.
+testrun_on_self_quiet ${abs_top_builddir}/tests/varlocs -e
diff --git a/tests/varlocs.c b/tests/varlocs.c
index cc77559..3267198 100644
--- a/tests/varlocs.c
+++ b/tests/varlocs.c
@@ -39,9 +39,12 @@
 // Needed for DW_OP_call_frame_cfa.
 static Dwarf *dw;
 Dwarf_CFI *cfi_debug;
+Dwarf_Addr cfi_debug_bias;
 Dwarf_CFI *cfi_eh;
 Dwarf_Addr cfi_eh_bias;
 
+bool is_ET_REL;
+
 // Whether the current function has a DW_AT_frame_base defined.
 // Needed for DW_OP_fbreg.
 bool has_frame_base;
@@ -258,20 +261,29 @@ print_expr (Dwarf_Attribute *attr, Dwarf_Op *expr, Dwarf_Addr addr)
 	error (EXIT_FAILURE, 0, "DW_OP_call_frame_cfa used but no cfi found.");
 
       Dwarf_Frame *frame;
-      if (dwarf_cfi_addrframe (cfi_eh, addr + cfi_eh_bias, &frame) != 0
-	  && dwarf_cfi_addrframe (cfi_debug, addr, &frame) != 0)
+      if (dwarf_cfi_addrframe (cfi_eh, addr + cfi_eh_bias, &frame) == 0
+	  || dwarf_cfi_addrframe (cfi_debug, addr + cfi_debug_bias,
+				  &frame) == 0)
+	{
+	  Dwarf_Op *cfa_ops;
+	  size_t cfa_nops;
+	  if (dwarf_frame_cfa (frame, &cfa_ops, &cfa_nops) != 0)
+	    error (EXIT_FAILURE, 0, "dwarf_frame_cfa 0x%" PRIx64 ": %s",
+		   addr, dwarf_errmsg (-1));
+	  if (cfa_nops < 1)
+	    error (EXIT_FAILURE, 0, "dwarf_frame_cfa no ops");
+	  print_expr_block (NULL, cfa_ops, cfa_nops, 0);
+	  free (frame);
+	}
+      else if (is_ET_REL)
+	{
+	  /* XXX In ET_REL files there might be an .eh_frame with relocations
+	     we don't handle (e.g. X86_64_PC32). Maybe we should?  */
+	  printf ("{...}\n");
+	}
+      else
 	error (EXIT_FAILURE, 0, "dwarf_cfi_addrframe 0x%" PRIx64 ": %s",
 	       addr, dwarf_errmsg (-1));
-
-      Dwarf_Op *cfa_ops;
-      size_t cfa_nops;
-      if (dwarf_frame_cfa (frame, &cfa_ops, &cfa_nops) != 0)
-	error (EXIT_FAILURE, 0, "dwarf_frame_cfa 0x%" PRIx64 ": %s",
-	       addr, dwarf_errmsg (-1));
-      if (cfa_nops < 1)
-	error (EXIT_FAILURE, 0, "dwarf_frame_cfa no ops");
-      print_expr_block (NULL, cfa_ops, cfa_nops, 0);
-      free (frame);
       break;
 
     case DW_OP_push_object_address:
@@ -924,7 +936,14 @@ handle_die (Dwarf_Die *die, int depth, bool outer_has_frame_base,
      on address.  */
   Dwarf_Addr die_entrypc;
   if (dwarf_entrypc (die, &die_entrypc) != 0 || die_entrypc == 0)
-    die_entrypc = outer_entrypc;
+    {
+      /* Try to get the lowest address of the first range covered.  */
+      Dwarf_Addr base, start, end;
+      if (dwarf_ranges (die, 0, &base, &start, &end) <= 0 || start == 0)
+	die_entrypc = outer_entrypc;
+      else
+	die_entrypc = start;
+    }
   arg.entrypc = die_entrypc;
 
   /* Whether this or the any outer DIE has a frame base. Used as
@@ -973,6 +992,7 @@ main (int argc, char *argv[])
 
   Dwarf_Die *cu = NULL;
   Dwarf_Addr dwbias;
+  bool found_cu = false;
   while ((cu = dwfl_nextcu (dwfl, cu, &dwbias)) != NULL)
     {
       /* Only walk actual compile units (not partial units) that
@@ -982,6 +1002,8 @@ main (int argc, char *argv[])
       if (dwarf_tag (cu) == DW_TAG_compile_unit
 	  && (exprlocs || dwarf_lowpc (cu, &cubase) == 0))
 	{
+	  found_cu = true;
+
 	  Dwfl_Module *mod = dwfl_cumodule (cu);
 	  Dwarf_Addr modbias;
 	  dw = dwfl_module_getdwarf (mod, &modbias);
@@ -1006,9 +1028,16 @@ main (int argc, char *argv[])
 	  Elf *elf = dwfl_module_getelf (mod, &elfbias);
 
 	  // CFI. We need both since sometimes neither is complete.
-	  cfi_debug = dwarf_getcfi (dw); // No bias needed, same file.
-	  cfi_eh = dwarf_getcfi_elf (elf);
-	  cfi_eh_bias = dwbias - elfbias;
+	  cfi_debug = dwfl_module_dwarf_cfi (mod, &cfi_debug_bias);
+	  cfi_eh = dwfl_module_eh_cfi (mod, &cfi_eh_bias);
+
+	  assert (cfi_debug == 0); // No bias needed, same file.
+
+	  // We are a bit forgiving for object files.  There might be
+	  // relocations we don't handle that are needed in some
+	  // places...
+	  GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem);
+	  is_ET_REL = ehdr->e_type == ET_REL;
 
 	  // Get the actual CU DIE and walk all all DIEs (or just the
 	  // functions) inside it.
@@ -1037,6 +1066,9 @@ main (int argc, char *argv[])
 	}
     }
 
+  if (! found_cu)
+    error (EXIT_FAILURE, 0, "No DWARF CU found?");
+
   dwfl_end (dwfl);
   return 0;
 }
-- 
1.8.3.1



More information about the Elfutils-devel mailing list