This is the mail archive of the elfutils-devel@sourceware.org mailing list for the elfutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

PATCH: dwarf_highpc: Handle DW_AT_high_pc being a constant offset from DW_AT_low_pc.


Hi,

The DWARF spec says (since version 4) that DW_AT_high_pc can be
represented by a constant form.

        If the value of the DW_AT_high_pc is of class address, it is the
        relocated address of the first location past the last
        instruction associated with the entity; if it is of class
        constant, the value is an unsigned integer offset which when
        added to the low PC gives the address of the first location past
        the last instruction associated with the entity.

I have a patch for gcc to encode DW_AT_high_pc this way (which saves a
lot of relocations) and jakub has a patch for dwz to encode
DW_AT_high_pc in the smallest possible constant form, which can save ~1%
on the size of debuginfo.

The attached patch adds a testcase for this and makes dwarf_highpc ()
handle the constant form.

Does this look OK?

Thanks,

Mark
commit 0569ad3036adb5c3e61ee212674cf8d3a24749bb
Author: Mark Wielaard <mjw@redhat.com>
Date:   Fri Apr 27 13:00:50 2012 +0200

    dwarf_highpc: Handle DW_AT_high_pc being a constant offset from DW_AT_low_pc.

diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index f96c0d1..3ff83e4 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,8 @@
+2012-04-27  Mark Wielaard  <mjw@redhat.com>
+
+	* libdw/dwarf_highpc.c (dwarf_highpc): Handle DW_AT_high_pc being
+	a constant offset from DW_AT_low_pc.
+
 2012-03-19  Tom Tromey  <tromey@redhat.com>
 
 	* libdw_findcu.c (findcu_cb): Move earlier.
diff --git a/libdw/dwarf_highpc.c b/libdw/dwarf_highpc.c
index c88e072..105fbee 100644
--- a/libdw/dwarf_highpc.c
+++ b/libdw/dwarf_highpc.c
@@ -1,5 +1,5 @@
 /* Return high PC attribute of DIE.
-   Copyright (C) 2003, 2005 Red Hat, Inc.
+   Copyright (C) 2003, 2005, 2012 Red Hat, Inc.
    This file is part of Red Hat elfutils.
    Written by Ulrich Drepper <drepper@redhat.com>, 2003.
 
@@ -63,8 +63,26 @@ dwarf_highpc (die, return_addr)
 {
   Dwarf_Attribute attr_mem;
 
-  return INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (die, DW_AT_high_pc,
-						     &attr_mem),
-				 return_addr);
+  if (INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (die, DW_AT_high_pc,
+						  &attr_mem),
+			      return_addr) == 0)
+    return 0;
+
+  /* DWARF 4 allows high_pc to be a constant offset from low_pc. */
+  if (INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (die, DW_AT_low_pc,
+						  &attr_mem),
+			      return_addr) == 0)
+    {
+      Dwarf_Word uval;
+      if (INTUSE(dwarf_formudata) (INTUSE(dwarf_attr) (die, DW_AT_high_pc,
+						       &attr_mem),
+				   &uval) == 0)
+	{
+	  *return_addr += uval;
+	  return 0;
+	}
+    }
+
+  return -1;
 }
 INTDEF(dwarf_highpc)
diff --git a/tests/ChangeLog b/tests/ChangeLog
index ffe61d5..abc7340 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,11 @@
+2012-04-27  Mark Wielaard  <mjw@redhat.com>
+
+	* Makefile.am (TESTS): Add run-low_high_pc.sh
+	(EXTRA_DIST): Add run-low_high_pc.sh and testfile_low_high_pc.bz2
+	(noinst_PROGRAMS): Add low_high_pc.
+	(low_high_pc_LDADD): New variable.
+	* low_high_pc.c: New test.
+
 2012-04-26  Mark Wielaard  <mjw@redhat.com>
 
 	* Makefile.am (EXTRA_DIST): Remove run-show-ciefde.sh.
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 835cc7a..61247e4 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -58,7 +58,7 @@ noinst_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \
 		  dwfl-addr-sect dwfl-bug-report early-offscn \
 		  dwfl-bug-getmodules dwarf-getmacros addrcfi \
 		  test-flag-nobits dwarf-getstring rerequest_tag \
-		  alldts md5-sha1-test typeiter
+		  alldts md5-sha1-test typeiter low_high_pc
 asm_TESTS = asm-tst1 asm-tst2 asm-tst3 asm-tst4 asm-tst5 \
 	    asm-tst6 asm-tst7 asm-tst8 asm-tst9
 
@@ -87,7 +87,7 @@ TESTS = run-arextract.sh run-arsymtest.sh newfile test-nlist \
 	run-early-offscn.sh run-dwarf-getmacros.sh \
 	run-test-flag-nobits.sh run-prelink-addr-test.sh \
 	run-dwarf-getstring.sh run-rerequest_tag.sh run-typeiter.sh \
-	run-readelf-d.sh run-unstrip-n.sh
+	run-readelf-d.sh run-unstrip-n.sh run-low_high_pc.sh
 
 if !STANDALONE
 noinst_PROGRAMS += msg_tst md5-sha1-test
@@ -164,7 +164,8 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
 	     testfile56.bz2 testfile57.bz2 testfile58.bz2 \
 	     run-typeiter.sh testfile59.bz2 \
 	     run-readelf-d.sh testlib_dynseg.so.bz2 \
-	     run-unstrip-n.sh testcore-rtlib.bz2
+	     run-unstrip-n.sh testcore-rtlib.bz2 \
+	     run-low_high_pc.sh testfile_low_high_pc.bz2
 
 installed_TESTS_ENVIRONMENT = libdir=$(DESTDIR)$(libdir) \
 			      bindir=$(DESTDIR)$(bindir) \
@@ -262,6 +263,7 @@ rerequest_tag_LDADD = $(libdw) $(libmudflap)
 alldts_LDADD = $(libebl) $(libelf) $(libmudflap)
 md5_sha1_test_LDADD = $(libeu)
 typeiter_LDADD = $(libdw) $(libelf) $(libmudflap)
+low_high_pc_LDADD = $(libdw) $(libelf) $(libmudflap)
 
 if GCOV
 check: check-am coverage
diff --git a/tests/low_high_pc.c b/tests/low_high_pc.c
new file mode 100644
index 0000000..3054046
--- /dev/null
+++ b/tests/low_high_pc.c
@@ -0,0 +1,114 @@
+/* Test program for dwarf_lowpc and dwarf_highpc
+   Copyright (C) 2012 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+
+   Red Hat elfutils 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; version 2 of the License.
+
+   Red Hat 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 Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#include <config.h>
+#include <assert.h>
+#include <inttypes.h>
+#include ELFUTILS_HEADER(dwfl)
+#include <dwarf.h>
+#include <argp.h>
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <locale.h>
+#include <stdlib.h>
+#include <error.h>
+#include <string.h>
+#include <fnmatch.h>
+
+struct args
+{
+  Dwfl *dwfl;
+  Dwarf_Die *cu;
+  Dwarf_Addr dwbias;
+  char **argv;
+  const char *file;
+};
+
+static struct args *args;
+
+static void
+fail(Dwarf_Off off, const char *name, const char *msg)
+{
+  printf("%s: [%lx] '%s' %s\n", args->file, off, name, msg);
+  exit(-1);
+}
+
+static int
+handle_die (Dwarf_Die *die, void *arg)
+{
+  args = arg;
+  Dwarf_Off off = dwarf_dieoffset (die);
+
+  const char *name = dwarf_diename (die);
+  if (name == NULL)
+    fail (off, "<no name>", "die without a name");
+
+  Dwarf_Addr lowpc = 0;
+  Dwarf_Addr highpc = 0;
+  if (dwarf_lowpc (die, &lowpc) != 0 && dwarf_hasattr (die, DW_AT_low_pc))
+    fail (off, name, "has DW_AT_low_pc but dwarf_lowpc fails");
+  if (dwarf_highpc (die, &highpc) != 0 && dwarf_hasattr (die, DW_AT_high_pc))
+    fail (off, name, "has DW_AT_high_pc but dwarf_highpc fails");
+
+  if (dwarf_hasattr (die, DW_AT_low_pc)
+      && dwarf_hasattr (die, DW_AT_high_pc)
+      && highpc <= lowpc)
+    {
+      printf("lowpc: %lx, highpc: %lx\n", lowpc, highpc);
+      fail (off, name, "highpc <= lowpc");
+    }
+
+  return 0;
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  int remaining;
+
+  /* Set locale.  */
+  (void) setlocale (LC_ALL, "");
+
+  struct args a = { .dwfl = NULL, .cu = NULL };
+
+  (void) argp_parse (dwfl_standard_argp (), argc, argv, 0, &remaining,
+		     &a.dwfl);
+  assert (a.dwfl != NULL);
+  a.argv = &argv[remaining];
+
+  int result = 0;
+
+  while ((a.cu = dwfl_nextcu (a.dwfl, a.cu, &a.dwbias)) != NULL)
+    {
+      a.file = dwarf_diename (a.cu);
+      handle_die (a.cu, &a);
+      dwarf_getfuncs (a.cu, &handle_die, &a, 0);
+    }
+
+  dwfl_end (a.dwfl);
+
+  return result;
+}
diff --git a/tests/run-low_high_pc.sh b/tests/run-low_high_pc.sh
new file mode 100755
index 0000000..8d891f1
--- /dev/null
+++ b/tests/run-low_high_pc.sh
@@ -0,0 +1,42 @@
+#! /bin/sh
+# Copyright (C) 2005 Red Hat, Inc.
+# This file is part of Red Hat elfutils.
+#
+# Red Hat elfutils 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; version 2 of the License.
+#
+# Red Hat 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 Red Hat elfutils; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+#
+# Red Hat elfutils is an included package of the Open Invention Network.
+# An included package of the Open Invention Network is a package for which
+# Open Invention Network licensees cross-license their patents.  No patent
+# license is granted, either expressly or impliedly, by designation as an
+# included package.  Should you wish to participate in the Open Invention
+# Network licensing program, please visit www.openinventionnetwork.com
+# <http://www.openinventionnetwork.com>.
+
+. $srcdir/test-subr.sh
+
+# int
+# main (int argc, char **argv)
+# {
+#   return 0;
+# }
+# gcc -g -o main main.c
+testfiles testfile_low_high_pc
+
+testrun ./low_high_pc -e ./testfile_low_high_pc
+testrun ./low_high_pc -e ./low_high_pc
+testrun ./low_high_pc -e ../src/strip
+testrun ./low_high_pc -e ../src/strip.o
+testrun ./low_high_pc -e ../libelf/libelf.so
+
+exit 0
diff --git a/tests/testfile_low_high_pc.bz2 b/tests/testfile_low_high_pc.bz2
new file mode 100755
index 0000000..f20814a
Binary files /dev/null and b/tests/testfile_low_high_pc.bz2 differ

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]