Patchwork [RFC] Make libbacktrace more standalone

login
register
mail settings
Submitter Alexander Monakov
Date May 8, 2013, 3:56 p.m.
Message ID <alpine.LNX.2.00.1305081907010.19752@monopod.intra.ispras.ru>
Download mbox | patch
Permalink /patch/242603/
State New
Headers show

Comments

Alexander Monakov - May 8, 2013, 3:56 p.m.
Hello,

I'd like to make libbacktrace easier to import for use in other software.
Right now it's mostly standalone, but depends on rest of GCC in the following:

1. Build system.
2. Trivially depends on "filenames.h".
3. Depends on "dwarf2.{def,h}" to obtain DW_* enumeration values.

My autotools-foo is not strong enough to elegantly resolve build system
dependencies (and for my intended use in APITrace I will need to write a
CMake-based build recipe anyhow).  To remove dependency on GCC dwarf2.h, I'm
proposing to enable building with system dwarf.h header.  However, in that
header the enums are anonymous, and some enum values may be missing.  My
preference is that references to named enums are retained, so I'm typedef'ing
those to 'int' if unavailable.

To deal with potentially missing enum values, I'm adding configure checks and
wrapping uses in HAVE_foo.  I'm also removing one use of DW_LNS_extended_op:
the standard does not seem to define that name, but instead says that value 0
is treated specially.

The following patch is the best compromise I have found between adding ugly
fixups and making libbacktrace buildable standalone (with the caveat that
either a different build system is used, or autotools files are hacked to
remove GCC dependencies).

Comments?

libbacktrace/Changelog:
2013-05-08  Alexander Monakov  <amonakov@ispras.ru>

	* btest.c: [!IN_GCC] (IS_DIR_SEPARATOR): Define.
	* configure.ac: (HAVE_DWARF2_FISSION, HAVE_DWARF2_DWZ_MULTIFILE): New
	tests.  Use ...
	* dwarf.c: (read_attribute): ... here.
	[!IN_GCC] Use system dwarf.h. 
	[!IN_GCC] (dwarf_attribute, dwarf_form, dwarf_tag): Typedef to int.
	Update all uses.
	[!IN_GCC] (IS_ABSOLUTE_PATH): Define.
	(read_line_program): Avoid use of DW_LNS_extended_op.
	* configure: Regenerate.
	* config.h.in: Regenerate.
	* Makefile.in: Regenerate.
Ian Taylor - May 8, 2013, 6:51 p.m.
On Wed, May 8, 2013 at 8:56 AM, Alexander Monakov <amonakov@ispras.ru> wrote:
>
> I'd like to make libbacktrace easier to import for use in other software.

> Comments?

> +#ifdef IN_GCC

Where is IN_GCC defined?


> +# Test if DWARF2 extensions enumeration values are declared
> +if test -n "${with_target_subdir}"; then
> +  have_dwarf2_fission=yes
> +  have_dwarf2_dwz_multifile=yes
> +else
> +  AC_CHECK_HEADER([dwarf.h],
> +    [
> +      AC_MSG_CHECKING([for DW_FORM_GNU_addr_index])
> +      AC_COMPILE_IFELSE(
> +       [AC_LANG_PROGRAM(
> +         [#include <dwarf.h>],
> +         [int i = DW_FORM_GNU_addr_index;])],
> +       [have_dwarf2_fission=yes],
> +       [have_dwarf2_fission=no])
> +      AC_MSG_RESULT([$have_dwarf2_fission])
> +      AC_MSG_CHECKING([for DW_FORM_GNU_ref_alt])
> +      AC_COMPILE_IFELSE(
> +       [AC_LANG_PROGRAM(
> +         [#include <dwarf.h>],
> +         [int i = DW_FORM_GNU_ref_alt;])],
> +       [have_dwarf2_dwz_multifile=yes],
> +       [have_dwarf2_dwz_multifile=no])
> +      AC_MSG_RESULT([$have_dwarf2_dwz_multifile])],
> +    [AC_MSG_ERROR([dwarf.h required for standalone build])])
> +fi

This isn't right.  Using test -n "${with_target_subdir}" tests whether
libbacktrace is being built as a target library, using the newly built
compiler.  It does not test whether it is being used in a standalone
build.  with_target_subdir will be empty when building libbacktrace as
part of the host compiler.  In that case we still want to use
include/dwarf2.def, and we do not want to give an error if the system
does not have dwarf.h.


> +#include "backtrace.h"
> +#include "internal.h"

Please keep these after the #include of the other header files.


> +#ifdef IN_GCC
>  #include "dwarf2.h"
>  #include "filenames.h"
> +#else
> +#include <dwarf.h>
> +typedef int dwarf_attribute;
> +typedef int dwarf_form;
> +typedef int dwarf_tag;
>
> -#include "backtrace.h"
> -#include "internal.h"
> +#define IS_ABSOLUTE_PATH(f) ((f)[0] == '/')
> +#endif

In the case where IN_GCC is defined, where are the types
dwarf_attribute, dwarf_form, and dwarf_tag defined?

When IN_GCC is defined, something needs to ensure that
HAVE_DWARF2_FISSION and HAVE_DWARF2_DWZ_MULTIFILE are defined.

Ian
Ondrej Bilka - May 8, 2013, 9:35 p.m.
On Wed, May 08, 2013 at 07:56:18PM +0400, Alexander Monakov wrote:
> Hello,
> 
> I'd like to make libbacktrace easier to import for use in other software.
> Right now it's mostly standalone, but depends on rest of GCC in the following:
> 
> 1. Build system.
> 2. Trivially depends on "filenames.h".
> 3. Depends on "dwarf2.{def,h}" to obtain DW_* enumeration values.
> 
> My autotools-foo is not strong enough to elegantly resolve build system
> dependencies (and for my intended use in APITrace I will need to write a
> CMake-based build recipe anyhow).  To remove dependency on GCC dwarf2.h, I'm
> proposing to enable building with system dwarf.h header.  However, in that
> header the enums are anonymous, and some enum values may be missing.  My
> preference is that references to named enums are retained, so I'm typedef'ing
> those to 'int' if unavailable.
> 
> To deal with potentially missing enum values, I'm adding configure checks and
> wrapping uses in HAVE_foo.  I'm also removing one use of DW_LNS_extended_op:
> the standard does not seem to define that name, but instead says that value 0
> is treated specially.
> 
> The following patch is the best compromise I have found between adding ugly
> fixups and making libbacktrace buildable standalone (with the caveat that
> either a different build system is used, or autotools files are hacked to
> remove GCC dependencies).
> 
> Comments?

Is it possible to link staticaly without external dependencies? This
simplifies generating backtrace when inside linker.
Ian Taylor - May 8, 2013, 9:58 p.m.
On Wed, May 8, 2013 at 2:35 PM, Ondřej Bílka <neleai@seznam.cz> wrote:
>
> Is it possible to link staticaly without external dependencies? This
> simplifies generating backtrace when inside linker.

I'm not sure I understand the question.  Is it possible to link
libbacktrace statically?  Sure.  That is what happens by default.

Ian

Patch

diff --git a/libbacktrace/btest.c b/libbacktrace/btest.c
index cc647b8..1516099 100644
--- a/libbacktrace/btest.c
+++ b/libbacktrace/btest.c
@@ -38,7 +38,11 @@  POSSIBILITY OF SUCH DAMAGE.  */
 #include <stdlib.h>
 #include <string.h>
 
+#ifdef IN_GCC
 #include "filenames.h"
+#else
+#define IS_DIR_SEPARATOR(c) ((c) == '/')
+#endif
 
 #include "backtrace.h"
 #include "backtrace-supported.h"
diff --git a/libbacktrace/configure.ac b/libbacktrace/configure.ac
index 28b2a1c..2728d4d 100644
--- a/libbacktrace/configure.ac
+++ b/libbacktrace/configure.ac
@@ -72,7 +72,7 @@  AC_PROG_RANLIB
 
 AC_PROG_AWK
 case "$AWK" in
-"") AC_MSG_ERROR([can't build without awk]) ;;
+"") AC_MSG_ERROR([cannot build without awk]) ;;
 esac
 
 LT_INIT([disable-shared])
@@ -314,6 +314,40 @@  if test "$have_getexecname" = "yes"; then
   AC_DEFINE(HAVE_GETEXECNAME, 1, [Define if getexecname is available.])
 fi
 
+# Test if DWARF2 extensions enumeration values are declared
+if test -n "${with_target_subdir}"; then
+  have_dwarf2_fission=yes
+  have_dwarf2_dwz_multifile=yes
+else
+  AC_CHECK_HEADER([dwarf.h],
+    [
+      AC_MSG_CHECKING([for DW_FORM_GNU_addr_index])
+      AC_COMPILE_IFELSE(
+	[AC_LANG_PROGRAM(
+	  [#include <dwarf.h>],
+	  [int i = DW_FORM_GNU_addr_index;])],
+	[have_dwarf2_fission=yes],
+	[have_dwarf2_fission=no])
+      AC_MSG_RESULT([$have_dwarf2_fission])
+      AC_MSG_CHECKING([for DW_FORM_GNU_ref_alt])
+      AC_COMPILE_IFELSE(
+	[AC_LANG_PROGRAM(
+	  [#include <dwarf.h>],
+	  [int i = DW_FORM_GNU_ref_alt;])],
+	[have_dwarf2_dwz_multifile=yes],
+	[have_dwarf2_dwz_multifile=no])
+      AC_MSG_RESULT([$have_dwarf2_dwz_multifile])],
+    [AC_MSG_ERROR([dwarf.h required for standalone build])])
+fi
+if test "$have_dwarf2_fission" = "yes"; then
+  AC_DEFINE(HAVE_DWARF2_FISSION, 1,
+	    [Define if DWARF2 Fission enumeration values are defined.])
+fi
+if test "$have_dwarf2_dwz_multifile" = "yes"; then
+  AC_DEFINE(HAVE_DWARF2_DWZ_MULTIFILE, 1,
+	    [Define if DWARF2 DWZ multifile enumeration values are defined.])
+fi
+
 AC_CACHE_CHECK([whether tests can run],
   [libbacktrace_cv_sys_native],
   [AC_RUN_IFELSE([AC_LANG_PROGRAM([], [return 0;])],
diff --git a/libbacktrace/dwarf.c b/libbacktrace/dwarf.c
index 501afe5..49a57a3 100644
--- a/libbacktrace/dwarf.c
+++ b/libbacktrace/dwarf.c
@@ -37,11 +37,20 @@  POSSIBILITY OF SUCH DAMAGE.  */
 #include <string.h>
 #include <sys/types.h>
 
+#include "backtrace.h"
+#include "internal.h"
+
+#ifdef IN_GCC
 #include "dwarf2.h"
 #include "filenames.h"
+#else
+#include <dwarf.h>
+typedef int dwarf_attribute;
+typedef int dwarf_form;
+typedef int dwarf_tag;
 
-#include "backtrace.h"
-#include "internal.h"
+#define IS_ABSOLUTE_PATH(f) ((f)[0] == '/')
+#endif
 
 #if !defined(HAVE_DECL_STRNLEN) || !HAVE_DECL_STRNLEN
 
@@ -89,9 +98,9 @@  struct dwarf_buf
 struct attr
 {
   /* The attribute name.  */
-  enum dwarf_attribute name;
+  dwarf_attribute name;
   /* The attribute form.  */
-  enum dwarf_form form;
+  dwarf_form form;
 };
 
 /* A single DWARF abbreviation.  */
@@ -101,7 +110,7 @@  struct abbrev
   /* The abbrev code--the number used to refer to the abbrev.  */
   uint64_t code;
   /* The entry tag.  */
-  enum dwarf_tag tag;
+  dwarf_tag tag;
   /* Non-zero if this abbrev has child entries.  */
   int has_children;
   /* The number of attributes.  */
@@ -653,7 +662,7 @@  free_abbrevs (struct backtrace_state *state, struct abbrevs *abbrevs,
    forms, because we don't care about them.  */
 
 static int
-read_attribute (enum dwarf_form form, struct dwarf_buf *buf,
+read_attribute (dwarf_form form, struct dwarf_buf *buf,
 		int is_dwarf64, int version, int addrsize,
 		const unsigned char *dwarf_str, size_t dwarf_str_size,
 		struct attr_val *val)
@@ -760,7 +769,7 @@  read_attribute (enum dwarf_form form, struct dwarf_buf *buf,
 	uint64_t form;
 
 	form = read_uleb128 (buf);
-	return read_attribute ((enum dwarf_form) form, buf, is_dwarf64,
+	return read_attribute ((dwarf_form) form, buf, is_dwarf64,
 			       version, addrsize, dwarf_str, dwarf_str_size,
 			       val);
       }
@@ -779,6 +788,7 @@  read_attribute (enum dwarf_form form, struct dwarf_buf *buf,
       val->encoding = ATTR_VAL_REF_TYPE;
       val->u.uint = read_uint64 (buf);
       return 1;
+#ifdef HAVE_DWARF2_FISSION
     case DW_FORM_GNU_addr_index:
       val->encoding = ATTR_VAL_REF_SECTION;
       val->u.uint = read_uleb128 (buf);
@@ -787,6 +797,8 @@  read_attribute (enum dwarf_form form, struct dwarf_buf *buf,
       val->encoding = ATTR_VAL_REF_SECTION;
       val->u.uint = read_uleb128 (buf);
       return 1;
+#endif
+#ifdef HAVE_DWARF2_DWZ_MULTIFILE
     case DW_FORM_GNU_ref_alt:
       val->encoding = ATTR_VAL_REF_SECTION;
       val->u.uint = read_offset (buf, is_dwarf64);
@@ -795,6 +807,7 @@  read_attribute (enum dwarf_form form, struct dwarf_buf *buf,
       val->encoding = ATTR_VAL_REF_SECTION;
       val->u.uint = read_offset (buf, is_dwarf64);
       return 1;
+#endif
     default:
       dwarf_buf_error (buf, "unrecognized DWARF form");
       return 0;
@@ -1087,7 +1100,7 @@  read_abbrevs (struct backtrace_state *state, uint64_t abbrev_offset,
 	break;
 
       a.code = code;
-      a.tag = (enum dwarf_tag) read_uleb128 (&abbrev_buf);
+      a.tag = (dwarf_tag) read_uleb128 (&abbrev_buf);
       a.has_children = read_byte (&abbrev_buf);
 
       count_buf = abbrev_buf;
@@ -1121,8 +1134,8 @@  read_abbrevs (struct backtrace_state *state, uint64_t abbrev_offset,
 	      form = read_uleb128 (&abbrev_buf);
 	      if (name == 0)
 		break;
-	      attrs[num_attrs].name = (enum dwarf_attribute) name;
-	      attrs[num_attrs].form = (enum dwarf_form) form;
+	      attrs[num_attrs].name = (dwarf_attribute) name;
+	      attrs[num_attrs].form = (dwarf_form) form;
 	      ++num_attrs;
 	    }
 	}
@@ -1746,10 +1759,11 @@  read_line_program (struct backtrace_state *state, struct dwarf_data *ddata,
 	  add_line (state, ddata, address, filename, lineno,
 		    line_buf->error_callback, line_buf->data, vec);
 	}
-      else if (op == DW_LNS_extended_op)
+      else if (!op)
 	{
 	  uint64_t len;
 
+	  /* Extended opcode.  */
 	  len = read_uleb128 (line_buf);
 	  op = read_byte (line_buf);
 	  switch (op)
diff --git a/libbacktrace/configure b/libbacktrace/configure
index 46ad9ee..26ef020 100755
--- a/libbacktrace/configure
+++ b/libbacktrace/configure
@@ -5011,7 +5011,7 @@  fi
 done
 
 case "$AWK" in
-"") as_fn_error "can't build without awk" "$LINENO" 5 ;;
+"") as_fn_error "cannot build without awk" "$LINENO" 5 ;;
 esac
 
 case `pwd` in
@@ -12371,6 +12371,73 @@  $as_echo "#define HAVE_GETEXECNAME 1" >>confdefs.h
 
 fi
 
+# Check for DWARF2 extensions
+if test -n "${with_target_subdir}"; then
+  have_dwarf2_fission=yes
+  have_dwarf2_dwz_multifile=yes
+else
+  ac_fn_c_check_header_mongrel "$LINENO" "dwarf.h" "ac_cv_header_dwarf_h" "$ac_includes_default"
+if test "x$ac_cv_header_dwarf_h" = x""yes; then :
+
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking for DW_FORM_GNU_addr_index" >&5
+$as_echo_n "checking for DW_FORM_GNU_addr_index... " >&6; }
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <dwarf.h>
+int
+main ()
+{
+int i = DW_FORM_GNU_addr_index;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  have_dwarf2_fission=yes
+else
+  have_dwarf2_fission=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_dwarf2_fission" >&5
+$as_echo "$have_dwarf2_fission" >&6; }
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking for DW_FORM_GNU_ref_alt" >&5
+$as_echo_n "checking for DW_FORM_GNU_ref_alt... " >&6; }
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <dwarf.h>
+int
+main ()
+{
+int i = DW_FORM_GNU_ref_alt;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  have_dwarf2_dwz_multifile=yes
+else
+  have_dwarf2_dwz_multifile=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_dwarf2_dwz_multifile" >&5
+$as_echo "$have_dwarf2_dwz_multifile" >&6; }
+else
+  as_fn_error "dwarf.h required when building standalone" "$LINENO" 5
+fi
+
+
+fi
+if test "$have_dwarf2_fission" = "yes"; then
+
+$as_echo "#define HAVE_DWARF2_FISSION 1" >>confdefs.h
+
+fi
+if test "$have_dwarf2_dwz_multifile" = "yes"; then
+
+$as_echo "#define HAVE_DWARF2_DWZ_MULTIFILE 1" >>confdefs.h
+
+fi
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether tests can run" >&5
 $as_echo_n "checking whether tests can run... " >&6; }
 if test "${libbacktrace_cv_sys_native+set}" = set; then :
diff --git a/libbacktrace/config.h.in b/libbacktrace/config.h.in
index 48ff63f..46a3a65 100644
--- a/libbacktrace/config.h.in
+++ b/libbacktrace/config.h.in
@@ -13,6 +13,12 @@ 
 /* Define if dl_iterate_phdr is available. */
 #undef HAVE_DL_ITERATE_PHDR
 
+/* Define if DWARF2 DWZ multifile enumeration values are defined. */
+#undef HAVE_DWARF2_DWZ_MULTIFILE
+
+/* Define if DWARF2 Fission enumeration values are defined. */
+#undef HAVE_DWARF2_FISSION
+
 /* Define to 1 if you have the fcntl function */
 #undef HAVE_FCNTL
 
diff --git a/libbacktrace/Makefile.in b/libbacktrace/Makefile.in
index 971406b..eff3ba9 100644
--- a/libbacktrace/Makefile.in
+++ b/libbacktrace/Makefile.in
@@ -16,7 +16,7 @@ 
 @SET_MAKE@
 
 # Makefile.am -- Backtrace Makefile.
-# Copyright (C) 2012 Free Software Foundation, Inc.
+# Copyright (C) 2012-2013 Free Software Foundation, Inc.
 
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions are