public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* Re: [patch,libgfortran,toplevel] Use libbacktrace in libgfortran
@ 2015-08-14 13:19 Uros Bizjak
  2015-08-14 14:31 ` FX
  0 siblings, 1 reply; 24+ messages in thread
From: Uros Bizjak @ 2015-08-14 13:19 UTC (permalink / raw)
  To: gcc-patches; +Cc: Fortran List, FX Coudert

Hello!

> Use libbacktrace (instead of our own unwind-based code) to display backtraces from libgfortran
> upon error or user request.
>
>  1. In toplevel Makefile.def, make libgfortran depend on libbacktrace (needs global reviewer
> approval)
>   2. In gcc/fortran/config-lang.in, add libbacktrace to target_libs
>   3. In libgfortran, we remove our own code and substitute calls to libbacktrace
>
> Bootstrapped and regtested on x86_64-pc-linux-gnu (which has full libbacktrace support) and
> x86_64-apple-darwin14 (which has minimal libbacktrace support). OK to commit to trunk?

backtrace.ChangeLog is unreadable for me ...

Uros.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [patch,libgfortran,toplevel] Use libbacktrace in libgfortran
  2015-08-14 13:19 [patch,libgfortran,toplevel] Use libbacktrace in libgfortran Uros Bizjak
@ 2015-08-14 14:31 ` FX
  2015-08-23 20:14   ` Janne Blomqvist
                     ` (2 more replies)
  0 siblings, 3 replies; 24+ messages in thread
From: FX @ 2015-08-14 14:31 UTC (permalink / raw)
  To: Uros Bizjak; +Cc: gcc-patches, Fortran List

[-- Attachment #1: Type: text/plain, Size: 738 bytes --]

>> Use libbacktrace (instead of our own unwind-based code) to display backtraces from libgfortran
>> upon error or user request.
>> 
>> 1. In toplevel Makefile.def, make libgfortran depend on libbacktrace (needs global reviewer
>> approval)
>>  2. In gcc/fortran/config-lang.in, add libbacktrace to target_libs
>>  3. In libgfortran, we remove our own code and substitute calls to libbacktrace
>> 
>> Bootstrapped and regtested on x86_64-pc-linux-gnu (which has full libbacktrace support) and
>> x86_64-apple-darwin14 (which has minimal libbacktrace support). OK to commit to trunk?
> 
> backtrace.ChangeLog is unreadable for me …

Sending again, this time with .txt extension, hoping this makes it go through OK.

FX


[-- Attachment #2: backtrace.ChangeLog.txt --]
[-- Type: text/plain, Size: 1535 bytes --]

2015-08-14  Francois-Xavier Coudert  <fxcoudert@gcc.gnu.org>

	PR libfortran/54572
	* Makefile.def: Make libgfortran depend on libbacktrace.
	* Makefile.in: Regenerate.


2015-08-14  Francois-Xavier Coudert  <fxcoudert@gcc.gnu.org>

	PR libfortran/54572
	* config-lang.in: Add libbacktrace to target_libs.


2015-08-14  Francois-Xavier Coudert  <fxcoudert@gcc.gnu.org>

	PR libfortran/54572
	* Makefile.am (libgfortran_la_LDFLAGS): Link in libbacktrace.
	(AM_CPPFLAGS): Add libbacktrace directories to include paths.
	* Makefile.in: Regenerate.
	* aclocal.m4: Regenerate.
	* config.h.in: Regenerate.
	* configure: Regenerate.
	* configure.ac: Remove checks for strtok_r, wait, execve, pipe,
	and dup2. Remove call to GCC_CHECK_UNWIND_GETIPINFO.
	* libgfortran.h (full_exe_path, find_addr2line, backtrace): Remove
	prototypes.
	(show_backtrace): Add prototype.
	* runtime/backtrace.c: Rework file entirely.
	* runtime/compile_options.c (backtrace_handler): Rename backtrace
	to show_backtrace.
	(maybe_find_addr2line): Remove function.
	(set_options): Remove call to maybe_find_addr2line.
	* runtime/error.c (sys_abort): Rename backtrace to show_backtrace.
	* runtime/main.c (store_exe_path): Empty function body.
	(full_exe_path, gfstrtok_r, find_addr2line): Remove functions.
	(cleanup): Don't free removed variables.
	* runtime/minimal.c (full_exe_path): Remove function.
	(set_args): Don't set exe_path.


2015-08-14  Francois-Xavier Coudert  <fxcoudert@gcc.gnu.org>

	PR libfortran/54572
	* gfortran.dg/backtrace_1.f90: New test.


[-- Attachment #3: backtrace.diff --]
[-- Type: application/octet-stream, Size: 20876 bytes --]

Index: Makefile.def
===================================================================
--- Makefile.def	(revision 226823)
+++ Makefile.def	(working copy)
@@ -597,6 +597,7 @@ dependencies = { module=all-target-winsu
 dependencies = { module=configure-target-newlib; on=all-binutils; };
 dependencies = { module=configure-target-newlib; on=all-ld; };
 dependencies = { module=configure-target-libgfortran; on=all-target-libquadmath; };
+dependencies = { module=configure-target-libgfortran; on=all-target-libbacktrace; };
 
 languages = { language=c;	gcc-check-target=check-gcc; };
 languages = { language=c++;	gcc-check-target=check-c++;
Index: gcc/fortran/config-lang.in
===================================================================
--- gcc/fortran/config-lang.in	(revision 226823)
+++ gcc/fortran/config-lang.in	(working copy)
@@ -27,7 +27,7 @@ language="fortran"
 
 compilers="f951\$(exeext)"
 
-target_libs=target-libgfortran
+target_libs="target-libgfortran target-libbacktrace"
 
 gtfiles="\$(srcdir)/fortran/f95-lang.c \$(srcdir)/fortran/trans-decl.c \$(srcdir)/fortran/trans-intrinsic.c \$(srcdir)/fortran/trans-io.c \$(srcdir)/fortran/trans-stmt.c \$(srcdir)/fortran/trans-types.c \$(srcdir)/fortran/trans-types.h \$(srcdir)/fortran/trans.h \$(srcdir)/fortran/trans-const.h"
 
Index: libgfortran/Makefile.am
===================================================================
--- libgfortran/Makefile.am	(revision 226823)
+++ libgfortran/Makefile.am	(working copy)
@@ -37,7 +37,8 @@ toolexeclib_LTLIBRARIES = libgfortran.la
 toolexeclib_DATA = libgfortran.spec
 libgfortran_la_LINK = $(LINK) $(libgfortran_la_LDFLAGS)
 libgfortran_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` \
-	$(LTLDFLAGS) $(LIBQUADLIB) -lm $(extra_ldflags_libgfortran) \
+	$(LTLDFLAGS) $(LIBQUADLIB) ../libbacktrace/libbacktrace.la \
+	-lm $(extra_ldflags_libgfortran) \
 	$(version_arg) -Wc,-shared-libgcc
 libgfortran_la_DEPENDENCIES = $(version_dep) libgfortran.spec $(LIBQUADLIB_DEP)
 
@@ -59,7 +60,10 @@ AM_CPPFLAGS = -iquote$(srcdir)/io -I$(sr
 	      -I$(srcdir)/$(MULTISRCTOP)../gcc/config $(LIBQUADINCLUDE) \
 	      -I$(MULTIBUILDTOP)../../$(host_subdir)/gcc \
 	      -I$(srcdir)/$(MULTISRCTOP)../libgcc \
-	      -I$(MULTIBUILDTOP)../libgcc
+	      -I$(MULTIBUILDTOP)../libgcc \
+	      -I$(srcdir)/$(MULTISRCTOP)../libbacktrace \
+	      -I$(MULTIBUILDTOP)../libbacktrace \
+	      -I../libbacktrace
 
 # Fortran rules for complex multiplication and division
 AM_CFLAGS += -fcx-fortran-rules
Index: libgfortran/configure.ac
===================================================================
--- libgfortran/configure.ac	(revision 226823)
+++ libgfortran/configure.ac	(working copy)
@@ -287,7 +287,6 @@ if test "x${with_newlib}" = "xyes"; then
    AC_DEFINE(HAVE_GMTIME_R, 1, [Define if you have gmtime_r.])
    AC_DEFINE(HAVE_STRNLEN, 1, [Define if you have strnlen.])
    AC_DEFINE(HAVE_STRNDUP, 1, [Define if you have strndup.])
-   AC_DEFINE(HAVE_STRTOK_R, 1, [Define if you have strtok_r.])
 
    # At some point, we should differentiate between architectures
    # like x86, which have long double versions, and alpha/powerpc/etc.,
@@ -298,11 +297,11 @@ if test "x${with_newlib}" = "xyes"; then
 else
    AC_CHECK_FUNCS_ONCE(getrusage times mkstemp strtof strtold snprintf \
    ftruncate chsize chdir getlogin gethostname kill link symlink sleep ttyname \
-   alarm access fork execl wait setmode execve pipe dup2 close fcntl \
+   alarm access fork execl setmode close fcntl \
    strcasestr getrlimit gettimeofday stat fstat lstat getpwuid vsnprintf dup \
    getcwd localtime_r gmtime_r getpwuid_r ttyname_r clock_gettime \
    readlink getgid getpid getppid getuid geteuid umask getegid \
-   secure_getenv __secure_getenv mkostemp strnlen strndup strtok_r newlocale \
+   secure_getenv __secure_getenv mkostemp strnlen strndup newlocale \
    freelocale uselocale strerror_l)
 fi
 
@@ -610,9 +609,6 @@ LIBGFOR_CHECK_UNLINK_OPEN_FILE
 # Check whether line terminator is LF or CRLF
 LIBGFOR_CHECK_CRLF
 
-# Check whether we have _Unwind_GetIPInfo for backtrace
-GCC_CHECK_UNWIND_GETIPINFO
-
 AC_CACHE_SAVE
 
 if test ${multilib} = yes; then
Index: libgfortran/libgfortran.h
===================================================================
--- libgfortran/libgfortran.h	(revision 226823)
+++ libgfortran/libgfortran.h	(working copy)
@@ -649,16 +649,11 @@ internal_proto(get_args);
 extern void store_exe_path (const char *);
 export_proto(store_exe_path);
 
-extern char * full_exe_path (void);
-internal_proto(full_exe_path);
-
-extern void find_addr2line (void);
-internal_proto(find_addr2line);
-
 /* backtrace.c */
 
-extern void backtrace (void);
-iexport_proto(backtrace);
+extern void show_backtrace (int);
+internal_proto(show_backtrace);
+
 
 /* error.c */
 
Index: libgfortran/runtime/backtrace.c
===================================================================
--- libgfortran/runtime/backtrace.c	(revision 226823)
+++ libgfortran/runtime/backtrace.c	(working copy)
@@ -31,249 +31,122 @@ see the files COPYING3 and COPYING.RUNTI
 #include <unistd.h>
 #endif
 
-#ifdef HAVE_SYS_WAIT_H
-#include <sys/wait.h>
-#endif
+#include "backtrace-supported.h"
+#include "backtrace.h"
 
-#include <limits.h>
 
-#include "unwind.h"
+/* Store our own state while backtracing.  */
+struct mystate
+{
+  int try_simple;
+  int frame;
+};
 
 
-/* Macros for common sets of capabilities: can we fork and exec, and
-   can we use pipes to communicate with the subprocess.  */
-#define CAN_FORK (defined(HAVE_FORK) && defined(HAVE_EXECVE) \
-		  && defined(HAVE_WAIT))
-#define CAN_PIPE (CAN_FORK && defined(HAVE_PIPE) \
-		  && defined(HAVE_DUP2) && defined(HAVE_CLOSE))
+/* Does a function name have "_gfortran_" or "_gfortrani_" prefix, possibly
+   with additional underscore(s) at the beginning?  Cannot use strncmp()
+   because we might be called from a signal handler.  */
 
-#ifndef PATH_MAX
-#define PATH_MAX 4096
-#endif
+static int
+has_gfortran_prefix (const char *s)
+{
+  if (!s)
+    return 0;
 
+  while (*s == '_')
+    s++;
 
-/* GDB style #NUM index for each stack frame.  */
+  return (s[0] == 'g' && s[1] == 'f' && s[2] == 'o' && s[3] == 'r'
+	  && s[4] == 't' && s[5] == 'r' && s[6] == 'a' && s[7] == 'n'
+	  && (s[8] == '_' || (s[8] == 'i' && s[9] == '_')));
+}
 
-static void 
-bt_header (int num)
+static void
+error_callback (void *data, const char *msg, int errnum)
 {
-  st_printf ("#%d  ", num);
-}
+  struct mystate *state = (struct mystate *) data;
+  if (errnum < 0)
+    {
+      state->try_simple = 1;
+      return;
+    }
 
+  estr_write ("\nSomething went wrong while printing the backtrace: ");
+  estr_write (msg);
+  estr_write ("\n");
+}
 
-/* fgets()-like function that reads a line from a fd, without
-   needing to malloc() a buffer, and does not use locks, hence should
-   be async-signal-safe.  */
+static int
+simple_callback (void *data, uintptr_t pc)
+{
+  struct mystate *state = (struct mystate *) data;
+  st_printf ("#%d  0x%lx\n", state->frame, (unsigned long) pc);
+  (state->frame)++;
+  return 0;
+}
 
-static char *
-fd_gets (char *s, int size, int fd)
+static int
+full_callback (void *data, uintptr_t pc, const char *filename,
+	       int lineno, const char *function)
 {
-  for (int i = 0; i < size; i++)
-    {
-      char c;
-      ssize_t nread = read (fd, &c, 1);
-      if (nread == 1)
-	{
-	  s[i] = c;
-	  if (c == '\n')
-	    {
-	      if (i + 1 < size)
-		s[i+1] = '\0';
-	      else
-		s[i] = '\0';
-	      break;
-	    }
-	}
-      else
-	{
-	  s[i] = '\0';
-	  if (i == 0)
-	    return NULL;
-	  break;
-	}
-    }
-  return s;
+  struct mystate *state = (struct mystate *) data;
+
+  if (has_gfortran_prefix (function))
+    return 0;
+
+  st_printf ("#%d  0x%lx %s\n", state->frame,
+	     (unsigned long) pc, function == NULL ? "???" : function);
+  if (filename || lineno != 0)
+    st_printf ("\t%s:%d\n", filename == NULL ? "???" : filename, lineno);
+  (state->frame)++;
+
+  if (function != NULL && strcmp (function, "main") == 0)
+    return 1;
+
+  return 0;
 }
 
 
-extern char *addr2line_path;
+/* Display the backtrace.  */
 
-/* Struct containing backtrace state.  */
-typedef struct
+void
+show_backtrace (int in_signal_handler)
 {
-  int frame_number;
-  int direct_output;
-  int outfd;
-  int infd;
-  int error;
-}
-bt_state;
-
-static _Unwind_Reason_Code
-trace_function (struct _Unwind_Context *context, void *state_ptr)
-{
-  bt_state* state = (bt_state*) state_ptr;
-  _Unwind_Ptr ip;
-#ifdef HAVE_GETIPINFO
-  int ip_before_insn = 0;
-  ip = _Unwind_GetIPInfo (context, &ip_before_insn);
-  
-  /* If the unwinder gave us a 'return' address, roll it back a little
-     to ensure we get the correct line number for the call itself.  */
-  if (! ip_before_insn)
-    --ip;
-#else  
-  ip = _Unwind_GetIP (context);
-#endif
+  struct backtrace_state *lbstate;
+  struct mystate state = { 0, 0 };
+ 
+  lbstate = backtrace_create_state (NULL, 1, error_callback, NULL);
 
-  if (state->direct_output)
+  if (!BACKTRACE_SUPPORTED || (in_signal_handler && BACKTRACE_USES_MALLOC))
     {
-      bt_header(state->frame_number);
-      st_printf ("%p\n", (void*) ip);
+      /* If symbolic backtrace is not supported on this target, or would
+	 require malloc() and we are in a signal handler, go with a
+	 simple backtrace.  */
+
+      backtrace_simple (lbstate, 0, simple_callback, error_callback, &state);
     }
   else
     {
-      char addr_buf[GFC_XTOA_BUF_SIZE], func[1024], file[PATH_MAX];
-      char *p;
-      const char* addr = gfc_xtoa (ip, addr_buf, sizeof (addr_buf));
-      write (state->outfd, addr, strlen (addr));
-      write (state->outfd, "\n", 1);
-
-      if (! fd_gets (func, sizeof(func), state->infd))
-	{
-	  state->error = 1;
-	  goto done;
-	}
-      if (! fd_gets (file, sizeof(file), state->infd))
-	{
-	  state->error = 1;
-	  goto done;
-	}
-	    
-	for (p = func; *p != '\n' && *p != '\r'; p++)
-	  ;
-	*p = '\0';
-	
-	/* _start is a setup routine that calls main(), and main() is
-	   the frontend routine that calls some setup stuff and then
-	   calls MAIN__, so at this point we should stop.  */
-	if (strcmp (func, "_start") == 0 || strcmp (func, "main") == 0)
-	  return _URC_END_OF_STACK;
-	
-	bt_header (state->frame_number);
-	estr_write ("0x");
-	estr_write (addr);
-
-	if (func[0] != '?' && func[1] != '?')
-	  {
-	    estr_write (" in ");
-	    estr_write (func);
-	  }
-	
-	if (strncmp (file, "??", 2) == 0)
-	  estr_write ("\n");
-	else
-	  {
-	    estr_write (" at ");
-	    estr_write (file);
-	  }
+      /* libbacktrace uses mmap, which is safe to call from a signal handler
+	 (in practice, if not in theory).  Thus we can generate a symbolic
+	 backtrace, if debug symbols are available.  */
+
+      backtrace_full (lbstate, 0, full_callback, error_callback, &state);
+      if (state.try_simple)
+	backtrace_simple (lbstate, 0, simple_callback, error_callback, &state);
     }
+}
 
- done:
 
-  state->frame_number++;
-  
-  return _URC_NO_REASON;
-}
 
+/* Function called by the front-end translating the BACKTRACE intrinsic.  */
 
-/* Display the backtrace.  */
+extern void backtrace (void);
+export_proto (backtrace);
 
 void
 backtrace (void)
 {
-  bt_state state;
-  state.frame_number = 0;
-  state.error = 0;
-
-#if CAN_PIPE
-
-  if (addr2line_path == NULL)
-    goto fallback_noerr;
-
-  /* We attempt to extract file and line information from addr2line.  */
-  do
-  {
-    /* Local variables.  */
-    int f[2], pid, inp[2];
-
-    /* Don't output an error message if something goes wrong, we'll simply
-       fall back to printing the addresses.  */
-    if (pipe (f) != 0)
-      break;
-    if (pipe (inp) != 0)
-      break;
-    if ((pid = fork ()) == -1)
-      break;
-
-    if (pid == 0)
-      {
-	/* Child process.  */
-#define NUM_FIXEDARGS 7
-	char *arg[NUM_FIXEDARGS];
-	char *newenv[] = { NULL };
-
-	close (f[0]);
-
-	close (inp[1]);
-	if (dup2 (inp[0], STDIN_FILENO) == -1)
-	  _exit (1);
-	close (inp[0]);
-
-	close (STDERR_FILENO);
-
-	if (dup2 (f[1], STDOUT_FILENO) == -1)
-	  _exit (1);
-	close (f[1]);
-
-	arg[0] = addr2line_path;
-	arg[1] = (char *) "-e";
-	arg[2] = full_exe_path ();
-	arg[3] = (char *) "-f";
-	arg[4] = (char *) "-s";
-	arg[5] = (char *) "-C";
-	arg[6] = NULL;
-	execve (addr2line_path, arg, newenv);
-	_exit (1);
-#undef NUM_FIXEDARGS
-      }
-
-    /* Father process.  */
-    close (f[1]);
-    close (inp[0]);
-
-    state.outfd = inp[1];
-    state.infd = f[0];
-    state.direct_output = 0;
-    _Unwind_Backtrace (trace_function, &state);
-    if (state.error)
-      goto fallback;
-    close (inp[1]);
-    close (f[0]);
-    wait (NULL);
-    return;
-
-fallback:
-    estr_write ("** Something went wrong while running addr2line. **\n"
-		"** Falling back to a simpler backtrace scheme. **\n");
-  }
-  while (0);
-
-fallback_noerr:
-#endif /* CAN_PIPE */
-
-  /* Fallback to the simple backtrace without addr2line.  */
-  state.direct_output = 1;
-  _Unwind_Backtrace (trace_function, &state);
+  show_backtrace (0);
 }
-iexport(backtrace);
+
Index: libgfortran/runtime/compile_options.c
===================================================================
--- libgfortran/runtime/compile_options.c	(revision 226823)
+++ libgfortran/runtime/compile_options.c	(working copy)
@@ -30,7 +30,7 @@ see the files COPYING3 and COPYING.RUNTI
 compile_options_t compile_options;
 
 #ifndef LIBGFOR_MINIMAL
-volatile sig_atomic_t fatal_error_in_progress = 0;
+static volatile sig_atomic_t fatal_error_in_progress = 0;
 
 
 /* Helper function for backtrace_handler to write information about the
@@ -126,7 +126,7 @@ backtrace_handler (int signum)
 
   show_signal (signum);
   estr_write ("\nBacktrace for this error:\n");
-  backtrace ();
+  show_backtrace (1);
 
   /* Now reraise the signal.  We reactivate the signal's
      default handling, which is to terminate the process.
@@ -136,16 +136,6 @@ backtrace_handler (int signum)
   signal (signum, SIG_DFL);
   raise (signum);
 }
-
-
-/* Helper function for set_options because we need to access the
-   global variable options which is not seen in set_options.  */
-static void
-maybe_find_addr2line (void)
-{
-  if (options.backtrace == -1)
-    find_addr2line ();
-}
 #endif
 
 /* Set the usual compile-time options.  */
@@ -211,8 +201,6 @@ set_options (int num, int options[])
 #if defined(SIGXFSZ)
       signal (SIGXFSZ, backtrace_handler);
 #endif
-
-      maybe_find_addr2line ();
     }
 #endif
 }
Index: libgfortran/runtime/error.c
===================================================================
--- libgfortran/runtime/error.c	(revision 226823)
+++ libgfortran/runtime/error.c	(working copy)
@@ -173,7 +173,7 @@ sys_abort (void)
       || (options.backtrace == -1 && compile_options.backtrace == 1))
     {
       estr_write ("\nProgram aborted. Backtrace:\n");
-      backtrace ();
+      show_backtrace (0);
       signal (SIGABRT, SIG_DFL);
     }
 
Index: libgfortran/runtime/main.c
===================================================================
--- libgfortran/runtime/main.c	(revision 226823)
+++ libgfortran/runtime/main.c	(working copy)
@@ -70,162 +70,13 @@ determine_endianness (void)
 static int argc_save;
 static char **argv_save;
 
-static const char *exe_path;
-static bool please_free_exe_path_when_done;
 
-/* Save the path under which the program was called, for use in the
-   backtrace routines.  */
 void
-store_exe_path (const char * argv0)
+store_exe_path (const char * argv0 __attribute__ ((unused)))
 {
-#ifndef DIR_SEPARATOR   
-#define DIR_SEPARATOR '/'
-#endif
-
-  char *cwd, *path;
-
-  /* This can only happen if store_exe_path is called multiple times.  */
-  if (please_free_exe_path_when_done)
-    free ((char *) exe_path);
-
-  /* Reading the /proc/self/exe symlink is Linux-specific(?), but if
-     it works it gives the correct answer.  */
-#ifdef HAVE_READLINK
-  ssize_t len, psize = 256;
-  while (1)
-    {
-      path = xmalloc (psize);
-      len = readlink ("/proc/self/exe", path, psize);
-      if (len < 0)
-	{
-	  free (path);
-	  break;
-	}
-      else if (len < psize)
-	{
-	  path[len] = '\0';
-	  exe_path = strdup (path);
-	  free (path);
-	  please_free_exe_path_when_done = true;
-	  return;
-	}
-      /* The remaining option is len == psize.  */
-      free (path);
-      psize *= 4;
-    }
-#endif
-
-  /* If the path is absolute or on a simulator where argv is not set.  */
-#ifdef __MINGW32__
-  if (argv0 == NULL
-      || ('A' <= argv0[0] && argv0[0] <= 'Z' && argv0[1] == ':')
-      || ('a' <= argv0[0] && argv0[0] <= 'z' && argv0[1] == ':')
-      || (argv0[0] == '/' && argv0[1] == '/')
-      || (argv0[0] == '\\' && argv0[1] == '\\'))
-#else
-  if (argv0 == NULL || argv0[0] == DIR_SEPARATOR)
-#endif
-    {
-      exe_path = argv0;
-      please_free_exe_path_when_done = false;
-      return;
-    }
-
-#ifdef HAVE_GETCWD
-  size_t cwdsize = 256;
-  while (1)
-    {
-      cwd = xmalloc (cwdsize);
-      if (getcwd (cwd, cwdsize))
-	break;
-      else if (errno == ERANGE)
-	{
-	  free (cwd);
-	  cwdsize *= 4;
-	}
-      else
-	{
-	  free (cwd);
-	  cwd = NULL;
-	  break;
-	}
-    }
-#else
-  cwd = NULL;
-#endif
-
-  if (!cwd)
-    {
-      exe_path = argv0;
-      please_free_exe_path_when_done = false;
-      return;
-    }
-
-  /* exe_path will be cwd + "/" + argv[0] + "\0".  This will not work
-     if the executable is not in the cwd, but at this point we're out
-     of better ideas.  */
-  size_t pathlen = strlen (cwd) + 1 + strlen (argv0) + 1;
-  path = xmalloc (pathlen);
-  snprintf (path, pathlen, "%s%c%s", cwd, DIR_SEPARATOR, argv0);
-  free (cwd);
-  exe_path = path;
-  please_free_exe_path_when_done = true;
-}
-
-
-/* Return the full path of the executable.  */
-char *
-full_exe_path (void)
-{
-  return (char *) exe_path;
-}
-
-
-#ifndef HAVE_STRTOK_R
-static char*
-gfstrtok_r (char *str, const char *delim, 
-	    char **saveptr __attribute__ ((unused)))
-{
-  return strtok (str, delim);
-}
-#define strtok_r gfstrtok_r
-#endif
-
-char *addr2line_path;
-
-/* Find addr2line and store the path.  */
-
-void
-find_addr2line (void)
-{
-#ifdef HAVE_ACCESS
-#define A2L_LEN 11
-  char *path = secure_getenv ("PATH");
-  if (!path)
-    return;
-  char *tp = strdup (path);
-  if (!tp)
-    return;
-  size_t n = strlen (path);
-  char *ap = xmalloc (n + A2L_LEN);
-  char *saveptr;
-  for (char *str = tp;; str = NULL)
-    {
-      char *token = strtok_r (str, ":", &saveptr);
-      if (!token)
-	break;
-      size_t toklen = strlen (token);
-      memcpy (ap, token, toklen);
-      memcpy (ap + toklen, "/addr2line", A2L_LEN);
-      if (access (ap, R_OK|X_OK) == 0)
-	{
-	  addr2line_path = strdup (ap);
-	  break;
-	}
-    }
-  free (tp);
-  free (ap);
-#endif
+  /* This function is now useless, but is retained due to ABI compatibility.
+    Remove when bumping the library ABI.  */
+  ;
 }
 
 
@@ -236,7 +87,6 @@ set_args (int argc, char **argv)
 {
   argc_save = argc;
   argv_save = argv;
-  store_exe_path (argv[0]);
 }
 iexport(set_args);
 
@@ -279,9 +129,6 @@ init (void)
   /* if (argc > 1 && strcmp(argv[1], "--resume") == 0) resume();  */
 #endif
 
-  if (options.backtrace == 1)
-    find_addr2line ();
-
   random_seed_i4 (NULL, NULL, NULL);
 }
 
@@ -292,9 +139,4 @@ static void __attribute__((destructor))
 cleanup (void)
 {
   close_units ();
-  
-  if (please_free_exe_path_when_done)
-    free ((char *) exe_path);
-
-  free (addr2line_path);
 }
Index: libgfortran/runtime/minimal.c
===================================================================
--- libgfortran/runtime/minimal.c	(revision 226823)
+++ libgfortran/runtime/minimal.c	(working copy)
@@ -53,8 +53,6 @@ int big_endian = 0;
 static int argc_save;
 static char **argv_save;
 
-static const char *exe_path;
-
 /* recursion_check()-- It's possible for additional errors to occur
  * during fatal error processing.  We detect this condition here and
  * exit with code 4 immediately. */
@@ -163,14 +161,6 @@ internal_error (st_parameter_common *cmp
 }
 
 
-/* Return the full path of the executable.  */
-char *
-full_exe_path (void)
-{
-  return (char *) exe_path;
-}
-
-
 /* Set the saved values of the command line arguments.  */
 
 void
@@ -178,7 +168,6 @@ set_args (int argc, char **argv)
 {
   argc_save = argc;
   argv_save = argv;
-  exe_path = argv[0];
 }
 iexport(set_args);
 
Index: gcc/testsuite/gfortran.dg/backtrace_1.f90
===================================================================
--- gcc/testsuite/gfortran.dg/backtrace_1.f90	(revision 0)
+++ gcc/testsuite/gfortran.dg/backtrace_1.f90	(working copy)
@@ -0,0 +1,10 @@
+! { dg-do run }
+! 
+! Check that BACKTRACE is available on all targets. We cannot actually
+! check its output, but we should at least be able to call it, then exit
+! normally.
+!
+program test
+  call backtrace
+  stop
+end program test

[-- Attachment #4: backtrace_withregeneratedfiles.diff --]
[-- Type: application/octet-stream, Size: 28916 bytes --]

Index: Makefile.def
===================================================================
--- Makefile.def	(revision 226823)
+++ Makefile.def	(working copy)
@@ -597,6 +597,7 @@ dependencies = { module=all-target-winsu
 dependencies = { module=configure-target-newlib; on=all-binutils; };
 dependencies = { module=configure-target-newlib; on=all-ld; };
 dependencies = { module=configure-target-libgfortran; on=all-target-libquadmath; };
+dependencies = { module=configure-target-libgfortran; on=all-target-libbacktrace; };
 
 languages = { language=c;	gcc-check-target=check-gcc; };
 languages = { language=c++;	gcc-check-target=check-c++;
Index: Makefile.in
===================================================================
--- Makefile.in	(revision 226823)
+++ Makefile.in	(working copy)
@@ -50921,6 +50921,7 @@ all-target-winsup: maybe-all-target-libt
 configure-target-newlib: maybe-all-binutils
 configure-target-newlib: maybe-all-ld
 configure-target-libgfortran: maybe-all-target-libquadmath
+configure-target-libgfortran: maybe-all-target-libbacktrace
 
 
 # Dependencies for target modules on other target modules are
Index: gcc/fortran/config-lang.in
===================================================================
--- gcc/fortran/config-lang.in	(revision 226823)
+++ gcc/fortran/config-lang.in	(working copy)
@@ -27,7 +27,7 @@ language="fortran"
 
 compilers="f951\$(exeext)"
 
-target_libs=target-libgfortran
+target_libs="target-libgfortran target-libbacktrace"
 
 gtfiles="\$(srcdir)/fortran/f95-lang.c \$(srcdir)/fortran/trans-decl.c \$(srcdir)/fortran/trans-intrinsic.c \$(srcdir)/fortran/trans-io.c \$(srcdir)/fortran/trans-stmt.c \$(srcdir)/fortran/trans-types.c \$(srcdir)/fortran/trans-types.h \$(srcdir)/fortran/trans.h \$(srcdir)/fortran/trans-const.h"
 
Index: libgfortran/Makefile.am
===================================================================
--- libgfortran/Makefile.am	(revision 226823)
+++ libgfortran/Makefile.am	(working copy)
@@ -37,7 +37,8 @@ toolexeclib_LTLIBRARIES = libgfortran.la
 toolexeclib_DATA = libgfortran.spec
 libgfortran_la_LINK = $(LINK) $(libgfortran_la_LDFLAGS)
 libgfortran_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` \
-	$(LTLDFLAGS) $(LIBQUADLIB) -lm $(extra_ldflags_libgfortran) \
+	$(LTLDFLAGS) $(LIBQUADLIB) ../libbacktrace/libbacktrace.la \
+	-lm $(extra_ldflags_libgfortran) \
 	$(version_arg) -Wc,-shared-libgcc
 libgfortran_la_DEPENDENCIES = $(version_dep) libgfortran.spec $(LIBQUADLIB_DEP)
 
@@ -59,7 +60,10 @@ AM_CPPFLAGS = -iquote$(srcdir)/io -I$(sr
 	      -I$(srcdir)/$(MULTISRCTOP)../gcc/config $(LIBQUADINCLUDE) \
 	      -I$(MULTIBUILDTOP)../../$(host_subdir)/gcc \
 	      -I$(srcdir)/$(MULTISRCTOP)../libgcc \
-	      -I$(MULTIBUILDTOP)../libgcc
+	      -I$(MULTIBUILDTOP)../libgcc \
+	      -I$(srcdir)/$(MULTISRCTOP)../libbacktrace \
+	      -I$(MULTIBUILDTOP)../libbacktrace \
+	      -I../libbacktrace
 
 # Fortran rules for complex multiplication and division
 AM_CFLAGS += -fcx-fortran-rules
Index: libgfortran/Makefile.in
===================================================================
--- libgfortran/Makefile.in	(revision 226823)
+++ libgfortran/Makefile.in	(working copy)
@@ -132,7 +132,6 @@ am__aclocal_m4_deps = $(top_srcdir)/../c
 	$(top_srcdir)/../config/multi.m4 \
 	$(top_srcdir)/../config/override.m4 \
 	$(top_srcdir)/../config/stdint.m4 \
-	$(top_srcdir)/../config/unwind_ipinfo.m4 \
 	$(top_srcdir)/../ltoptions.m4 $(top_srcdir)/../ltsugar.m4 \
 	$(top_srcdir)/../ltversion.m4 $(top_srcdir)/../lt~obsolete.m4 \
 	$(top_srcdir)/acinclude.m4 $(top_srcdir)/../config/acx.m4 \
@@ -598,7 +597,8 @@ toolexeclib_LTLIBRARIES = libgfortran.la
 toolexeclib_DATA = libgfortran.spec
 libgfortran_la_LINK = $(LINK) $(libgfortran_la_LDFLAGS)
 libgfortran_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` \
-	$(LTLDFLAGS) $(LIBQUADLIB) -lm $(extra_ldflags_libgfortran) \
+	$(LTLDFLAGS) $(LIBQUADLIB) ../libbacktrace/libbacktrace.la \
+	-lm $(extra_ldflags_libgfortran) \
 	$(version_arg) -Wc,-shared-libgcc
 
 libgfortran_la_DEPENDENCIES = $(version_dep) libgfortran.spec $(LIBQUADLIB_DEP)
@@ -614,7 +614,10 @@ AM_CPPFLAGS = -iquote$(srcdir)/io -I$(sr
 	      -I$(srcdir)/$(MULTISRCTOP)../gcc/config $(LIBQUADINCLUDE) \
 	      -I$(MULTIBUILDTOP)../../$(host_subdir)/gcc \
 	      -I$(srcdir)/$(MULTISRCTOP)../libgcc \
-	      -I$(MULTIBUILDTOP)../libgcc
+	      -I$(MULTIBUILDTOP)../libgcc \
+	      -I$(srcdir)/$(MULTISRCTOP)../libbacktrace \
+	      -I$(MULTIBUILDTOP)../libbacktrace \
+	      -I../libbacktrace
 
 gfor_io_src = io/size_from_kind.c $(am__append_2)
 gfor_io_headers = \
Index: libgfortran/aclocal.m4
===================================================================
--- libgfortran/aclocal.m4	(revision 226823)
+++ libgfortran/aclocal.m4	(working copy)
@@ -1029,7 +1029,6 @@ m4_include([../config/lthostflags.m4])
 m4_include([../config/multi.m4])
 m4_include([../config/override.m4])
 m4_include([../config/stdint.m4])
-m4_include([../config/unwind_ipinfo.m4])
 m4_include([../ltoptions.m4])
 m4_include([../ltsugar.m4])
 m4_include([../ltversion.m4])
Index: libgfortran/config.h.in
===================================================================
--- libgfortran/config.h.in	(revision 226823)
+++ libgfortran/config.h.in	(working copy)
@@ -315,9 +315,6 @@
 /* Define to 1 if you have the `dup' function. */
 #undef HAVE_DUP
 
-/* Define to 1 if you have the `dup2' function. */
-#undef HAVE_DUP2
-
 /* Define to 1 if you have the `erf' function. */
 #undef HAVE_ERF
 
@@ -339,9 +336,6 @@
 /* Define to 1 if you have the `execl' function. */
 #undef HAVE_EXECL
 
-/* Define to 1 if you have the `execve' function. */
-#undef HAVE_EXECVE
-
 /* Define to 1 if you have the `exp' function. */
 #undef HAVE_EXP
 
@@ -462,9 +456,6 @@
 /* Define to 1 if you have the `gethostname' function. */
 #undef HAVE_GETHOSTNAME
 
-/* Define if _Unwind_GetIPInfo is available. */
-#undef HAVE_GETIPINFO
-
 /* Define to 1 if you have the `getlogin' function. */
 #undef HAVE_GETLOGIN
 
@@ -636,9 +627,6 @@
 /* Define to 1 if you have the `nextafterl' function. */
 #undef HAVE_NEXTAFTERL
 
-/* Define to 1 if you have the `pipe' function. */
-#undef HAVE_PIPE
-
 /* Define to 1 if we have POSIX getpwuid_r which takes 5 arguments. */
 #undef HAVE_POSIX_GETPWUID_R
 
@@ -753,9 +741,6 @@
 /* Define to 1 if you have the `strtof' function. */
 #undef HAVE_STRTOF
 
-/* Define to 1 if you have the `strtok_r' function. */
-#undef HAVE_STRTOK_R
-
 /* Define to 1 if you have the `strtold' function. */
 #undef HAVE_STRTOLD
 
@@ -855,9 +840,6 @@
 /* Define to 1 if you have the `vsnprintf' function. */
 #undef HAVE_VSNPRINTF
 
-/* Define to 1 if you have the `wait' function. */
-#undef HAVE_WAIT
-
 /* Define if target has a reliable stat. */
 #undef HAVE_WORKING_STAT
 
Index: libgfortran/configure
===================================================================
--- libgfortran/configure	(revision 226823)
+++ libgfortran/configure	(working copy)
@@ -776,7 +776,6 @@ with_gnu_ld
 enable_libtool_lock
 enable_largefile
 enable_libquadmath_support
-with_system_libunwind
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1435,7 +1434,6 @@ Optional Packages:
   --with-pic              try to use only PIC/non-PIC objects [default=use
                           both]
   --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
-  --with-system-libunwind use installed libunwind
 
 Some influential environment variables:
   CC          C compiler command
@@ -2572,11 +2570,7 @@ as_fn_append ac_func_list " alarm"
 as_fn_append ac_func_list " access"
 as_fn_append ac_func_list " fork"
 as_fn_append ac_func_list " execl"
-as_fn_append ac_func_list " wait"
 as_fn_append ac_func_list " setmode"
-as_fn_append ac_func_list " execve"
-as_fn_append ac_func_list " pipe"
-as_fn_append ac_func_list " dup2"
 as_fn_append ac_func_list " close"
 as_fn_append ac_func_list " fcntl"
 as_fn_append ac_func_list " strcasestr"
@@ -2607,7 +2601,6 @@ as_fn_append ac_func_list " __secure_get
 as_fn_append ac_func_list " mkostemp"
 as_fn_append ac_func_list " strnlen"
 as_fn_append ac_func_list " strndup"
-as_fn_append ac_func_list " strtok_r"
 as_fn_append ac_func_list " newlocale"
 as_fn_append ac_func_list " freelocale"
 as_fn_append ac_func_list " uselocale"
@@ -12376,7 +12369,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 12379 "configure"
+#line 12372 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -12482,7 +12475,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 12485 "configure"
+#line 12478 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -16514,9 +16507,6 @@ $as_echo "#define HAVE_STRNLEN 1" >>conf
 $as_echo "#define HAVE_STRNDUP 1" >>confdefs.h
 
 
-$as_echo "#define HAVE_STRTOK_R 1" >>confdefs.h
-
-
    # At some point, we should differentiate between architectures
    # like x86, which have long double versions, and alpha/powerpc/etc.,
    # which don't. For the time being, punt.
@@ -16653,16 +16643,6 @@ done
 
 
 
-
-
-
-
-
-
-
-
-
-
 fi
 
 # Check strerror_r, cannot be above as versions with two and three arguments exist
@@ -26584,44 +26564,6 @@ $as_echo "#define HAVE_CRLF 1" >>confdef
 
 fi
 
-# Check whether we have _Unwind_GetIPInfo for backtrace
-
-
-# Check whether --with-system-libunwind was given.
-if test "${with_system_libunwind+set}" = set; then :
-  withval=$with_system_libunwind;
-fi
-
-  # If system-libunwind was not specifically set, pick a default setting.
-  if test x$with_system_libunwind = x; then
-    case ${target} in
-      ia64-*-hpux*) with_system_libunwind=yes ;;
-      *) with_system_libunwind=no ;;
-    esac
-  fi
-  # Based on system-libunwind and target, do we have ipinfo?
-  if  test x$with_system_libunwind = xyes; then
-    case ${target} in
-      ia64-*-*) have_unwind_getipinfo=no ;;
-      *) have_unwind_getipinfo=yes ;;
-    esac
-  else
-    # Darwin before version 9 does not have _Unwind_GetIPInfo.
-
-    case ${target} in
-      *-*-darwin[3-8]|*-*-darwin[3-8].*) have_unwind_getipinfo=no ;;
-      *) have_unwind_getipinfo=yes ;;
-    esac
-
-  fi
-
-  if test x$have_unwind_getipinfo = xyes; then
-
-$as_echo "#define HAVE_GETIPINFO 1" >>confdefs.h
-
-  fi
-
-
 cat >confcache <<\_ACEOF
 # This file is a shell script that caches the results of configure
 # tests run on this system so they can be shared between configure
Index: libgfortran/configure.ac
===================================================================
--- libgfortran/configure.ac	(revision 226823)
+++ libgfortran/configure.ac	(working copy)
@@ -287,7 +287,6 @@ if test "x${with_newlib}" = "xyes"; then
    AC_DEFINE(HAVE_GMTIME_R, 1, [Define if you have gmtime_r.])
    AC_DEFINE(HAVE_STRNLEN, 1, [Define if you have strnlen.])
    AC_DEFINE(HAVE_STRNDUP, 1, [Define if you have strndup.])
-   AC_DEFINE(HAVE_STRTOK_R, 1, [Define if you have strtok_r.])
 
    # At some point, we should differentiate between architectures
    # like x86, which have long double versions, and alpha/powerpc/etc.,
@@ -298,11 +297,11 @@ if test "x${with_newlib}" = "xyes"; then
 else
    AC_CHECK_FUNCS_ONCE(getrusage times mkstemp strtof strtold snprintf \
    ftruncate chsize chdir getlogin gethostname kill link symlink sleep ttyname \
-   alarm access fork execl wait setmode execve pipe dup2 close fcntl \
+   alarm access fork execl setmode close fcntl \
    strcasestr getrlimit gettimeofday stat fstat lstat getpwuid vsnprintf dup \
    getcwd localtime_r gmtime_r getpwuid_r ttyname_r clock_gettime \
    readlink getgid getpid getppid getuid geteuid umask getegid \
-   secure_getenv __secure_getenv mkostemp strnlen strndup strtok_r newlocale \
+   secure_getenv __secure_getenv mkostemp strnlen strndup newlocale \
    freelocale uselocale strerror_l)
 fi
 
@@ -610,9 +609,6 @@ LIBGFOR_CHECK_UNLINK_OPEN_FILE
 # Check whether line terminator is LF or CRLF
 LIBGFOR_CHECK_CRLF
 
-# Check whether we have _Unwind_GetIPInfo for backtrace
-GCC_CHECK_UNWIND_GETIPINFO
-
 AC_CACHE_SAVE
 
 if test ${multilib} = yes; then
Index: libgfortran/libgfortran.h
===================================================================
--- libgfortran/libgfortran.h	(revision 226823)
+++ libgfortran/libgfortran.h	(working copy)
@@ -649,16 +649,11 @@ internal_proto(get_args);
 extern void store_exe_path (const char *);
 export_proto(store_exe_path);
 
-extern char * full_exe_path (void);
-internal_proto(full_exe_path);
-
-extern void find_addr2line (void);
-internal_proto(find_addr2line);
-
 /* backtrace.c */
 
-extern void backtrace (void);
-iexport_proto(backtrace);
+extern void show_backtrace (int);
+internal_proto(show_backtrace);
+
 
 /* error.c */
 
Index: libgfortran/runtime/backtrace.c
===================================================================
--- libgfortran/runtime/backtrace.c	(revision 226823)
+++ libgfortran/runtime/backtrace.c	(working copy)
@@ -31,249 +31,122 @@ see the files COPYING3 and COPYING.RUNTI
 #include <unistd.h>
 #endif
 
-#ifdef HAVE_SYS_WAIT_H
-#include <sys/wait.h>
-#endif
+#include "backtrace-supported.h"
+#include "backtrace.h"
 
-#include <limits.h>
 
-#include "unwind.h"
+/* Store our own state while backtracing.  */
+struct mystate
+{
+  int try_simple;
+  int frame;
+};
 
 
-/* Macros for common sets of capabilities: can we fork and exec, and
-   can we use pipes to communicate with the subprocess.  */
-#define CAN_FORK (defined(HAVE_FORK) && defined(HAVE_EXECVE) \
-		  && defined(HAVE_WAIT))
-#define CAN_PIPE (CAN_FORK && defined(HAVE_PIPE) \
-		  && defined(HAVE_DUP2) && defined(HAVE_CLOSE))
+/* Does a function name have "_gfortran_" or "_gfortrani_" prefix, possibly
+   with additional underscore(s) at the beginning?  Cannot use strncmp()
+   because we might be called from a signal handler.  */
 
-#ifndef PATH_MAX
-#define PATH_MAX 4096
-#endif
+static int
+has_gfortran_prefix (const char *s)
+{
+  if (!s)
+    return 0;
 
+  while (*s == '_')
+    s++;
 
-/* GDB style #NUM index for each stack frame.  */
+  return (s[0] == 'g' && s[1] == 'f' && s[2] == 'o' && s[3] == 'r'
+	  && s[4] == 't' && s[5] == 'r' && s[6] == 'a' && s[7] == 'n'
+	  && (s[8] == '_' || (s[8] == 'i' && s[9] == '_')));
+}
 
-static void 
-bt_header (int num)
+static void
+error_callback (void *data, const char *msg, int errnum)
 {
-  st_printf ("#%d  ", num);
-}
+  struct mystate *state = (struct mystate *) data;
+  if (errnum < 0)
+    {
+      state->try_simple = 1;
+      return;
+    }
 
+  estr_write ("\nSomething went wrong while printing the backtrace: ");
+  estr_write (msg);
+  estr_write ("\n");
+}
 
-/* fgets()-like function that reads a line from a fd, without
-   needing to malloc() a buffer, and does not use locks, hence should
-   be async-signal-safe.  */
+static int
+simple_callback (void *data, uintptr_t pc)
+{
+  struct mystate *state = (struct mystate *) data;
+  st_printf ("#%d  0x%lx\n", state->frame, (unsigned long) pc);
+  (state->frame)++;
+  return 0;
+}
 
-static char *
-fd_gets (char *s, int size, int fd)
+static int
+full_callback (void *data, uintptr_t pc, const char *filename,
+	       int lineno, const char *function)
 {
-  for (int i = 0; i < size; i++)
-    {
-      char c;
-      ssize_t nread = read (fd, &c, 1);
-      if (nread == 1)
-	{
-	  s[i] = c;
-	  if (c == '\n')
-	    {
-	      if (i + 1 < size)
-		s[i+1] = '\0';
-	      else
-		s[i] = '\0';
-	      break;
-	    }
-	}
-      else
-	{
-	  s[i] = '\0';
-	  if (i == 0)
-	    return NULL;
-	  break;
-	}
-    }
-  return s;
+  struct mystate *state = (struct mystate *) data;
+
+  if (has_gfortran_prefix (function))
+    return 0;
+
+  st_printf ("#%d  0x%lx %s\n", state->frame,
+	     (unsigned long) pc, function == NULL ? "???" : function);
+  if (filename || lineno != 0)
+    st_printf ("\t%s:%d\n", filename == NULL ? "???" : filename, lineno);
+  (state->frame)++;
+
+  if (function != NULL && strcmp (function, "main") == 0)
+    return 1;
+
+  return 0;
 }
 
 
-extern char *addr2line_path;
+/* Display the backtrace.  */
 
-/* Struct containing backtrace state.  */
-typedef struct
+void
+show_backtrace (int in_signal_handler)
 {
-  int frame_number;
-  int direct_output;
-  int outfd;
-  int infd;
-  int error;
-}
-bt_state;
-
-static _Unwind_Reason_Code
-trace_function (struct _Unwind_Context *context, void *state_ptr)
-{
-  bt_state* state = (bt_state*) state_ptr;
-  _Unwind_Ptr ip;
-#ifdef HAVE_GETIPINFO
-  int ip_before_insn = 0;
-  ip = _Unwind_GetIPInfo (context, &ip_before_insn);
-  
-  /* If the unwinder gave us a 'return' address, roll it back a little
-     to ensure we get the correct line number for the call itself.  */
-  if (! ip_before_insn)
-    --ip;
-#else  
-  ip = _Unwind_GetIP (context);
-#endif
+  struct backtrace_state *lbstate;
+  struct mystate state = { 0, 0 };
+ 
+  lbstate = backtrace_create_state (NULL, 1, error_callback, NULL);
 
-  if (state->direct_output)
+  if (!BACKTRACE_SUPPORTED || (in_signal_handler && BACKTRACE_USES_MALLOC))
     {
-      bt_header(state->frame_number);
-      st_printf ("%p\n", (void*) ip);
+      /* If symbolic backtrace is not supported on this target, or would
+	 require malloc() and we are in a signal handler, go with a
+	 simple backtrace.  */
+
+      backtrace_simple (lbstate, 0, simple_callback, error_callback, &state);
     }
   else
     {
-      char addr_buf[GFC_XTOA_BUF_SIZE], func[1024], file[PATH_MAX];
-      char *p;
-      const char* addr = gfc_xtoa (ip, addr_buf, sizeof (addr_buf));
-      write (state->outfd, addr, strlen (addr));
-      write (state->outfd, "\n", 1);
-
-      if (! fd_gets (func, sizeof(func), state->infd))
-	{
-	  state->error = 1;
-	  goto done;
-	}
-      if (! fd_gets (file, sizeof(file), state->infd))
-	{
-	  state->error = 1;
-	  goto done;
-	}
-	    
-	for (p = func; *p != '\n' && *p != '\r'; p++)
-	  ;
-	*p = '\0';
-	
-	/* _start is a setup routine that calls main(), and main() is
-	   the frontend routine that calls some setup stuff and then
-	   calls MAIN__, so at this point we should stop.  */
-	if (strcmp (func, "_start") == 0 || strcmp (func, "main") == 0)
-	  return _URC_END_OF_STACK;
-	
-	bt_header (state->frame_number);
-	estr_write ("0x");
-	estr_write (addr);
-
-	if (func[0] != '?' && func[1] != '?')
-	  {
-	    estr_write (" in ");
-	    estr_write (func);
-	  }
-	
-	if (strncmp (file, "??", 2) == 0)
-	  estr_write ("\n");
-	else
-	  {
-	    estr_write (" at ");
-	    estr_write (file);
-	  }
+      /* libbacktrace uses mmap, which is safe to call from a signal handler
+	 (in practice, if not in theory).  Thus we can generate a symbolic
+	 backtrace, if debug symbols are available.  */
+
+      backtrace_full (lbstate, 0, full_callback, error_callback, &state);
+      if (state.try_simple)
+	backtrace_simple (lbstate, 0, simple_callback, error_callback, &state);
     }
+}
 
- done:
 
-  state->frame_number++;
-  
-  return _URC_NO_REASON;
-}
 
+/* Function called by the front-end translating the BACKTRACE intrinsic.  */
 
-/* Display the backtrace.  */
+extern void backtrace (void);
+export_proto (backtrace);
 
 void
 backtrace (void)
 {
-  bt_state state;
-  state.frame_number = 0;
-  state.error = 0;
-
-#if CAN_PIPE
-
-  if (addr2line_path == NULL)
-    goto fallback_noerr;
-
-  /* We attempt to extract file and line information from addr2line.  */
-  do
-  {
-    /* Local variables.  */
-    int f[2], pid, inp[2];
-
-    /* Don't output an error message if something goes wrong, we'll simply
-       fall back to printing the addresses.  */
-    if (pipe (f) != 0)
-      break;
-    if (pipe (inp) != 0)
-      break;
-    if ((pid = fork ()) == -1)
-      break;
-
-    if (pid == 0)
-      {
-	/* Child process.  */
-#define NUM_FIXEDARGS 7
-	char *arg[NUM_FIXEDARGS];
-	char *newenv[] = { NULL };
-
-	close (f[0]);
-
-	close (inp[1]);
-	if (dup2 (inp[0], STDIN_FILENO) == -1)
-	  _exit (1);
-	close (inp[0]);
-
-	close (STDERR_FILENO);
-
-	if (dup2 (f[1], STDOUT_FILENO) == -1)
-	  _exit (1);
-	close (f[1]);
-
-	arg[0] = addr2line_path;
-	arg[1] = (char *) "-e";
-	arg[2] = full_exe_path ();
-	arg[3] = (char *) "-f";
-	arg[4] = (char *) "-s";
-	arg[5] = (char *) "-C";
-	arg[6] = NULL;
-	execve (addr2line_path, arg, newenv);
-	_exit (1);
-#undef NUM_FIXEDARGS
-      }
-
-    /* Father process.  */
-    close (f[1]);
-    close (inp[0]);
-
-    state.outfd = inp[1];
-    state.infd = f[0];
-    state.direct_output = 0;
-    _Unwind_Backtrace (trace_function, &state);
-    if (state.error)
-      goto fallback;
-    close (inp[1]);
-    close (f[0]);
-    wait (NULL);
-    return;
-
-fallback:
-    estr_write ("** Something went wrong while running addr2line. **\n"
-		"** Falling back to a simpler backtrace scheme. **\n");
-  }
-  while (0);
-
-fallback_noerr:
-#endif /* CAN_PIPE */
-
-  /* Fallback to the simple backtrace without addr2line.  */
-  state.direct_output = 1;
-  _Unwind_Backtrace (trace_function, &state);
+  show_backtrace (0);
 }
-iexport(backtrace);
+
Index: libgfortran/runtime/compile_options.c
===================================================================
--- libgfortran/runtime/compile_options.c	(revision 226823)
+++ libgfortran/runtime/compile_options.c	(working copy)
@@ -30,7 +30,7 @@ see the files COPYING3 and COPYING.RUNTI
 compile_options_t compile_options;
 
 #ifndef LIBGFOR_MINIMAL
-volatile sig_atomic_t fatal_error_in_progress = 0;
+static volatile sig_atomic_t fatal_error_in_progress = 0;
 
 
 /* Helper function for backtrace_handler to write information about the
@@ -126,7 +126,7 @@ backtrace_handler (int signum)
 
   show_signal (signum);
   estr_write ("\nBacktrace for this error:\n");
-  backtrace ();
+  show_backtrace (1);
 
   /* Now reraise the signal.  We reactivate the signal's
      default handling, which is to terminate the process.
@@ -136,16 +136,6 @@ backtrace_handler (int signum)
   signal (signum, SIG_DFL);
   raise (signum);
 }
-
-
-/* Helper function for set_options because we need to access the
-   global variable options which is not seen in set_options.  */
-static void
-maybe_find_addr2line (void)
-{
-  if (options.backtrace == -1)
-    find_addr2line ();
-}
 #endif
 
 /* Set the usual compile-time options.  */
@@ -211,8 +201,6 @@ set_options (int num, int options[])
 #if defined(SIGXFSZ)
       signal (SIGXFSZ, backtrace_handler);
 #endif
-
-      maybe_find_addr2line ();
     }
 #endif
 }
Index: libgfortran/runtime/error.c
===================================================================
--- libgfortran/runtime/error.c	(revision 226823)
+++ libgfortran/runtime/error.c	(working copy)
@@ -173,7 +173,7 @@ sys_abort (void)
       || (options.backtrace == -1 && compile_options.backtrace == 1))
     {
       estr_write ("\nProgram aborted. Backtrace:\n");
-      backtrace ();
+      show_backtrace (0);
       signal (SIGABRT, SIG_DFL);
     }
 
Index: libgfortran/runtime/main.c
===================================================================
--- libgfortran/runtime/main.c	(revision 226823)
+++ libgfortran/runtime/main.c	(working copy)
@@ -70,162 +70,13 @@ determine_endianness (void)
 static int argc_save;
 static char **argv_save;
 
-static const char *exe_path;
-static bool please_free_exe_path_when_done;
 
-/* Save the path under which the program was called, for use in the
-   backtrace routines.  */
 void
-store_exe_path (const char * argv0)
+store_exe_path (const char * argv0 __attribute__ ((unused)))
 {
-#ifndef DIR_SEPARATOR   
-#define DIR_SEPARATOR '/'
-#endif
-
-  char *cwd, *path;
-
-  /* This can only happen if store_exe_path is called multiple times.  */
-  if (please_free_exe_path_when_done)
-    free ((char *) exe_path);
-
-  /* Reading the /proc/self/exe symlink is Linux-specific(?), but if
-     it works it gives the correct answer.  */
-#ifdef HAVE_READLINK
-  ssize_t len, psize = 256;
-  while (1)
-    {
-      path = xmalloc (psize);
-      len = readlink ("/proc/self/exe", path, psize);
-      if (len < 0)
-	{
-	  free (path);
-	  break;
-	}
-      else if (len < psize)
-	{
-	  path[len] = '\0';
-	  exe_path = strdup (path);
-	  free (path);
-	  please_free_exe_path_when_done = true;
-	  return;
-	}
-      /* The remaining option is len == psize.  */
-      free (path);
-      psize *= 4;
-    }
-#endif
-
-  /* If the path is absolute or on a simulator where argv is not set.  */
-#ifdef __MINGW32__
-  if (argv0 == NULL
-      || ('A' <= argv0[0] && argv0[0] <= 'Z' && argv0[1] == ':')
-      || ('a' <= argv0[0] && argv0[0] <= 'z' && argv0[1] == ':')
-      || (argv0[0] == '/' && argv0[1] == '/')
-      || (argv0[0] == '\\' && argv0[1] == '\\'))
-#else
-  if (argv0 == NULL || argv0[0] == DIR_SEPARATOR)
-#endif
-    {
-      exe_path = argv0;
-      please_free_exe_path_when_done = false;
-      return;
-    }
-
-#ifdef HAVE_GETCWD
-  size_t cwdsize = 256;
-  while (1)
-    {
-      cwd = xmalloc (cwdsize);
-      if (getcwd (cwd, cwdsize))
-	break;
-      else if (errno == ERANGE)
-	{
-	  free (cwd);
-	  cwdsize *= 4;
-	}
-      else
-	{
-	  free (cwd);
-	  cwd = NULL;
-	  break;
-	}
-    }
-#else
-  cwd = NULL;
-#endif
-
-  if (!cwd)
-    {
-      exe_path = argv0;
-      please_free_exe_path_when_done = false;
-      return;
-    }
-
-  /* exe_path will be cwd + "/" + argv[0] + "\0".  This will not work
-     if the executable is not in the cwd, but at this point we're out
-     of better ideas.  */
-  size_t pathlen = strlen (cwd) + 1 + strlen (argv0) + 1;
-  path = xmalloc (pathlen);
-  snprintf (path, pathlen, "%s%c%s", cwd, DIR_SEPARATOR, argv0);
-  free (cwd);
-  exe_path = path;
-  please_free_exe_path_when_done = true;
-}
-
-
-/* Return the full path of the executable.  */
-char *
-full_exe_path (void)
-{
-  return (char *) exe_path;
-}
-
-
-#ifndef HAVE_STRTOK_R
-static char*
-gfstrtok_r (char *str, const char *delim, 
-	    char **saveptr __attribute__ ((unused)))
-{
-  return strtok (str, delim);
-}
-#define strtok_r gfstrtok_r
-#endif
-
-char *addr2line_path;
-
-/* Find addr2line and store the path.  */
-
-void
-find_addr2line (void)
-{
-#ifdef HAVE_ACCESS
-#define A2L_LEN 11
-  char *path = secure_getenv ("PATH");
-  if (!path)
-    return;
-  char *tp = strdup (path);
-  if (!tp)
-    return;
-  size_t n = strlen (path);
-  char *ap = xmalloc (n + A2L_LEN);
-  char *saveptr;
-  for (char *str = tp;; str = NULL)
-    {
-      char *token = strtok_r (str, ":", &saveptr);
-      if (!token)
-	break;
-      size_t toklen = strlen (token);
-      memcpy (ap, token, toklen);
-      memcpy (ap + toklen, "/addr2line", A2L_LEN);
-      if (access (ap, R_OK|X_OK) == 0)
-	{
-	  addr2line_path = strdup (ap);
-	  break;
-	}
-    }
-  free (tp);
-  free (ap);
-#endif
+  /* This function is now useless, but is retained due to ABI compatibility.
+    Remove when bumping the library ABI.  */
+  ;
 }
 
 
@@ -236,7 +87,6 @@ set_args (int argc, char **argv)
 {
   argc_save = argc;
   argv_save = argv;
-  store_exe_path (argv[0]);
 }
 iexport(set_args);
 
@@ -279,9 +129,6 @@ init (void)
   /* if (argc > 1 && strcmp(argv[1], "--resume") == 0) resume();  */
 #endif
 
-  if (options.backtrace == 1)
-    find_addr2line ();
-
   random_seed_i4 (NULL, NULL, NULL);
 }
 
@@ -292,9 +139,4 @@ static void __attribute__((destructor))
 cleanup (void)
 {
   close_units ();
-  
-  if (please_free_exe_path_when_done)
-    free ((char *) exe_path);
-
-  free (addr2line_path);
 }
Index: libgfortran/runtime/minimal.c
===================================================================
--- libgfortran/runtime/minimal.c	(revision 226823)
+++ libgfortran/runtime/minimal.c	(working copy)
@@ -53,8 +53,6 @@ int big_endian = 0;
 static int argc_save;
 static char **argv_save;
 
-static const char *exe_path;
-
 /* recursion_check()-- It's possible for additional errors to occur
  * during fatal error processing.  We detect this condition here and
  * exit with code 4 immediately. */
@@ -163,14 +161,6 @@ internal_error (st_parameter_common *cmp
 }
 
 
-/* Return the full path of the executable.  */
-char *
-full_exe_path (void)
-{
-  return (char *) exe_path;
-}
-
-
 /* Set the saved values of the command line arguments.  */
 
 void
@@ -178,7 +168,6 @@ set_args (int argc, char **argv)
 {
   argc_save = argc;
   argv_save = argv;
-  exe_path = argv[0];
 }
 iexport(set_args);
 
Index: gcc/testsuite/gfortran.dg/backtrace_1.f90
===================================================================
--- gcc/testsuite/gfortran.dg/backtrace_1.f90	(revision 0)
+++ gcc/testsuite/gfortran.dg/backtrace_1.f90	(working copy)
@@ -0,0 +1,10 @@
+! { dg-do run }
+! 
+! Check that BACKTRACE is available on all targets. We cannot actually
+! check its output, but we should at least be able to call it, then exit
+! normally.
+!
+program test
+  call backtrace
+  stop
+end program test

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [patch,libgfortran,toplevel] Use libbacktrace in libgfortran
  2015-08-14 14:31 ` FX
@ 2015-08-23 20:14   ` Janne Blomqvist
  2015-08-23 20:59     ` FX
  2015-08-24 16:00   ` Fix libbacktrace -fPIC breakage from "Use libbacktrace in libgfortran" Hans-Peter Nilsson
  2015-08-24 16:04   ` Fix libbacktrace -fPIC breakage from "Use libbacktrace in libgfortran" Hans-Peter Nilsson
  2 siblings, 1 reply; 24+ messages in thread
From: Janne Blomqvist @ 2015-08-23 20:14 UTC (permalink / raw)
  To: FX; +Cc: Uros Bizjak, gcc-patches, Fortran List

On Fri, Aug 14, 2015 at 5:18 PM, FX <fxcoudert@gmail.com> wrote:
>>> Use libbacktrace (instead of our own unwind-based code) to display backtraces from libgfortran
>>> upon error or user request.
>>>
>>> 1. In toplevel Makefile.def, make libgfortran depend on libbacktrace (needs global reviewer
>>> approval)
>>>  2. In gcc/fortran/config-lang.in, add libbacktrace to target_libs
>>>  3. In libgfortran, we remove our own code and substitute calls to libbacktrace
>>>
>>> Bootstrapped and regtested on x86_64-pc-linux-gnu (which has full libbacktrace support) and
>>> x86_64-apple-darwin14 (which has minimal libbacktrace support). OK to commit to trunk?
>>
>> backtrace.ChangeLog is unreadable for me …
>
> Sending again, this time with .txt extension, hoping this makes it go through OK.

Awesome! Looks good. I only have one small bikeshed request: Can you
make the output format match the existing code?

(As there seems to be no GNU (or otherwise) standard how backtraces
should look, in order to minimize user confusion I made the current
code produce output matching gdb backtraces as close as seemed
reasonable.)

Ok with that change.

-- 
Janne Blomqvist

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [patch,libgfortran,toplevel] Use libbacktrace in libgfortran
  2015-08-23 20:14   ` Janne Blomqvist
@ 2015-08-23 20:59     ` FX
  2015-08-23 21:27       ` Janne Blomqvist
  0 siblings, 1 reply; 24+ messages in thread
From: FX @ 2015-08-23 20:59 UTC (permalink / raw)
  To: Janne Blomqvist; +Cc: Uros Bizjak, gcc-patches, Fortran List


> Awesome! Looks good. I only have one small bikeshed request: Can you
> make the output format match the existing code?

Problem with that is that ad the new backtrace uses full path for file names, the one-line format easily wraps in 80 column and make the output harder to read (in my opinion).

In realize this is mostly taste an very subjective, so with this nugget of extra input, I leave the final decision to you: let me know what you think best, between readability and "conformance" to GDB format.

Cheers,
FX

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [patch,libgfortran,toplevel] Use libbacktrace in libgfortran
  2015-08-23 20:59     ` FX
@ 2015-08-23 21:27       ` Janne Blomqvist
  2015-08-24  7:15         ` FX
  0 siblings, 1 reply; 24+ messages in thread
From: Janne Blomqvist @ 2015-08-23 21:27 UTC (permalink / raw)
  To: FX; +Cc: Uros Bizjak, gcc-patches, Fortran List

On Sun, Aug 23, 2015 at 11:14 PM, FX <fxcoudert@gmail.com> wrote:
>
>> Awesome! Looks good. I only have one small bikeshed request: Can you
>> make the output format match the existing code?
>
> Problem with that is that ad the new backtrace uses full path for file names, the one-line format easily wraps in 80 column and make the output harder to read (in my opinion).
>
> In realize this is mostly taste an very subjective, so with this nugget of extra input, I leave the final decision to you: let me know what you think best, between readability and "conformance" to GDB format.

Ah, I didn't realize that. I guess you're right, it's better to split
the filename:linenumber to a separate line. But still, I think it's
clearer if you keep the "in" and "at" like the current code & gdb
does. Thus, something like

#framenumber 0xADDRESS in funcname
    at filename:linenumber

And another thing which I previously missed: You have removed the
store_exe_path function as it's no longer used for anything. However,
that function is part of the libgfortran ABI and is found in
gfortran.map, so we have to keep it until we bump the so version. :(
Please also add a note to the libgfortran ABI cleanup wiki page so we
don't forget about it.

With these changes, Ok for trunk. Thanks a lot for working on this!


-- 
Janne Blomqvist

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [patch,libgfortran,toplevel] Use libbacktrace in libgfortran
  2015-08-23 21:27       ` Janne Blomqvist
@ 2015-08-24  7:15         ` FX
  0 siblings, 0 replies; 24+ messages in thread
From: FX @ 2015-08-24  7:15 UTC (permalink / raw)
  To: Janne Blomqvist; +Cc: Uros Bizjak, gcc-patches, Fortran List

> Ah, I didn't realize that. I guess you're right, it's better to split
> the filename:linenumber to a separate line. But still, I think it's
> clearer if you keep the "in" and "at" like the current code & gdb
> does. Thus, something like
> 
> #framenumber 0xADDRESS in funcname
>    at filename:linenumber

Done.


> And another thing which I previously missed: You have removed the
> store_exe_path function as it's no longer used for anything. However,
> that function is part of the libgfortran ABI and is found in
> gfortran.map, so we have to keep it until we bump the so version. :(

Which is what I did, though it’s not very clear from the .diff itself. The function is emptied but remains in libgfortran/runtime/main.c:

void
store_exe_path (const char * argv0 __attribute__ ((unused)))
{
  /* This function is now useless, but is retained due to ABI compatibility.
    Remove when bumping the library ABI.  */
  ;
}


> Please also add a note to the libgfortran ABI cleanup wiki page so we
> don't forget about it.

Done.


> With these changes, Ok for trunk. Thanks a lot for working on this!

Committed as revision 227106 with the changes above.
Thanks for reviewing the patch.

FX

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Fix libbacktrace -fPIC breakage from "Use libbacktrace in libgfortran"
  2015-08-14 14:31 ` FX
  2015-08-23 20:14   ` Janne Blomqvist
@ 2015-08-24 16:00   ` Hans-Peter Nilsson
  2015-08-24 16:08     ` FX
  2015-08-24 16:04   ` Fix libbacktrace -fPIC breakage from "Use libbacktrace in libgfortran" Hans-Peter Nilsson
  2 siblings, 1 reply; 24+ messages in thread
From: Hans-Peter Nilsson @ 2015-08-24 16:00 UTC (permalink / raw)
  To: gcc-patches; +Cc: ubizjak, ian, fortran

(Goofed on the CC line, sorry for the dup.)

There exists targets that support fortran but error on -fPIC,
for example cris-elf, which broke with the libbacktrace thingy.
(Emitting an error for -fPIC is a conscious choice; a
compilation error is better than e.g. to silently ignoring it.)
This fix causes build to pass the point of error for cris-elf.
Borderline obvious, but...

Ok to regtest passes on a native x86_64-linux?

libbacktrace:
	configure.ac: Only compile with -fPIC if the target
	supports it.

diff -upr /expvol/pp_slask/hp/checkout/gcchead/gcc/libbacktrace/configure.ac libbacktrace/configure.ac
--- /expvol/pp_slask/hp/checkout/gcchead/gcc/libbacktrace/configure.ac	2015-05-29 17:23:20.000000000 +0200
+++ libbacktrace/configure.ac	2015-08-24 17:31:18.000000000 +0200
@@ -163,10 +163,11 @@ fi
 
 # When building as a target library, shared libraries may want to link
 # this in.  We don't want to provide another shared library to
-# complicate dependencies.  Instead, we just compile with -fPIC.
+# complicate dependencies.  Instead, we just compile with -fPIC, if
+# the target supports compiling a function with that option.
 PIC_FLAG=
 if test -n "${with_target_subdir}"; then
-  PIC_FLAG=-fPIC
+  AC_TRY_COMPILE([void foo(void){}], [PIC_FLAG=-fPIC])
 fi
 # Similarly, use -fPIC with --enable-host-shared:
 AC_ARG_ENABLE(host-shared,

brgds, H-P

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Fix libbacktrace -fPIC breakage from "Use libbacktrace in libgfortran"
  2015-08-14 14:31 ` FX
  2015-08-23 20:14   ` Janne Blomqvist
  2015-08-24 16:00   ` Fix libbacktrace -fPIC breakage from "Use libbacktrace in libgfortran" Hans-Peter Nilsson
@ 2015-08-24 16:04   ` Hans-Peter Nilsson
  2 siblings, 0 replies; 24+ messages in thread
From: Hans-Peter Nilsson @ 2015-08-24 16:04 UTC (permalink / raw)
  To: gcc-patches; +Cc: ubizjak, ian@airs.com.fortran

There exists targets that support fortran but error on -fPIC,
for example cris-elf, which broke with the libbacktrace thingy.
(Emitting an error for -fPIC is a conscious choice; a
compilation error is better than e.g. to silently ignoring it.)
This fix causes build to pass the point of error for cris-elf.
Borderline obvious, but...

Ok to regtest passes on a native x86_64-linux?

libbacktrace:
	configure.ac: Only compile with -fPIC if the target
	supports it.

diff -upr /expvol/pp_slask/hp/checkout/gcchead/gcc/libbacktrace/configure.ac libbacktrace/configure.ac
--- /expvol/pp_slask/hp/checkout/gcchead/gcc/libbacktrace/configure.ac	2015-05-29 17:23:20.000000000 +0200
+++ libbacktrace/configure.ac	2015-08-24 17:31:18.000000000 +0200
@@ -163,10 +163,11 @@ fi
 
 # When building as a target library, shared libraries may want to link
 # this in.  We don't want to provide another shared library to
-# complicate dependencies.  Instead, we just compile with -fPIC.
+# complicate dependencies.  Instead, we just compile with -fPIC, if
+# the target supports compiling a function with that option.
 PIC_FLAG=
 if test -n "${with_target_subdir}"; then
-  PIC_FLAG=-fPIC
+  AC_TRY_COMPILE([void foo(void){}], [PIC_FLAG=-fPIC])
 fi
 # Similarly, use -fPIC with --enable-host-shared:
 AC_ARG_ENABLE(host-shared,

brgds, H-P

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Fix libbacktrace -fPIC breakage from "Use libbacktrace in libgfortran"
  2015-08-24 16:00   ` Fix libbacktrace -fPIC breakage from "Use libbacktrace in libgfortran" Hans-Peter Nilsson
@ 2015-08-24 16:08     ` FX
  2015-08-24 16:44       ` Hans-Peter Nilsson
  0 siblings, 1 reply; 24+ messages in thread
From: FX @ 2015-08-24 16:08 UTC (permalink / raw)
  To: Hans-Peter Nilsson; +Cc: gcc-patches, ubizjak, ian, fortran

> PIC_FLAG=
> if test -n "${with_target_subdir}"; then
> -  PIC_FLAG=-fPIC
> +  AC_TRY_COMPILE([void foo(void){}], [PIC_FLAG=-fPIC])
> fi

There’s something I don’t understand about this test. Shouldn’t AC_TRY_COMPILE take a first (empty) argument, “includes”? And shouldn’t you first set the -fPIC flag before try to compile with that?

FX

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Fix libbacktrace -fPIC breakage from "Use libbacktrace in libgfortran"
  2015-08-24 16:08     ` FX
@ 2015-08-24 16:44       ` Hans-Peter Nilsson
  2015-08-24 18:42         ` FX
  2015-08-25  3:29         ` Ian Lance Taylor
  0 siblings, 2 replies; 24+ messages in thread
From: Hans-Peter Nilsson @ 2015-08-24 16:44 UTC (permalink / raw)
  To: fxcoudert; +Cc: gcc-patches, ubizjak, ian, fortran

> From: FX <fxcoudert@gmail.com>
> Date: Mon, 24 Aug 2015 18:07:52 +0200

> > PIC_FLAG= 
> > if test -n "${with_target_subdir}"; then
> > -  PIC_FLAG=-fPIC
> > +  AC_TRY_COMPILE([void foo(void){}], [PIC_FLAG=-fPIC])
> > fi
> 
> There's something I don't understand about this
> test. Shouldn't AC_TRY_COMPILE take a first (empty) argument,
> "includes"? And shouldn't you first set the -fPIC flag before
> try to compile with that?

You're absolutely right on both accounts.  Also, the function
body is supposed to be a function body (...) or else we get a
nested function (i.e. foo inside main).  Might as well provide
both empty.  Also fixing the ChangeLog entry.  Sorry for
goofing.  (At least I had a look at config.log this time...)

	* configure.ac: Only compile with -fPIC if the target
	supports it.
	* configure: Regenerate.

diff -upr /expvol/pp_slask/hp/checkout/gcchead/gcc/libbacktrace/configure.ac libbacktrace/configure.ac
--- /expvol/pp_slask/hp/checkout/gcchead/gcc/libbacktrace/configure.ac	2015-05-29 17:23:20.000000000 +0200
+++ libbacktrace/configure.ac	2015-08-24 18:31:01.000000000 +0200
@@ -163,10 +163,14 @@ fi
 
 # When building as a target library, shared libraries may want to link
 # this in.  We don't want to provide another shared library to
-# complicate dependencies.  Instead, we just compile with -fPIC.
+# complicate dependencies.  Instead, we just compile with -fPIC, if
+# the target supports compiling with that option.
 PIC_FLAG=
 if test -n "${with_target_subdir}"; then
-  PIC_FLAG=-fPIC
+  ac_save_CFLAGS="$CFLAGS"
+  CFLAGS="$CFLAGS -fPIC"
+  AC_TRY_COMPILE([], [], [PIC_FLAG=-fPIC])
+  CFLAGS="$ac_save_CFLAGS"
 fi
 # Similarly, use -fPIC with --enable-host-shared:
 AC_ARG_ENABLE(host-shared,


brgds, H-P

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Fix libbacktrace -fPIC breakage from "Use libbacktrace in libgfortran"
  2015-08-24 16:44       ` Hans-Peter Nilsson
@ 2015-08-24 18:42         ` FX
  2015-08-25  3:29         ` Ian Lance Taylor
  1 sibling, 0 replies; 24+ messages in thread
From: FX @ 2015-08-24 18:42 UTC (permalink / raw)
  To: Hans-Peter Nilsson; +Cc: gcc-patches, ubizjak, ian, fortran

> You're absolutely right on both accounts.  Also, the function
> body is supposed to be a function body (...) or else we get a
> nested function (i.e. foo inside main).  Might as well provide
> both empty.  Also fixing the ChangeLog entry.  Sorry for
> goofing.  (At least I had a look at config.log this time…)

That looks better :)
But I can’t approve the patch.

FX

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Fix libbacktrace -fPIC breakage from "Use libbacktrace in libgfortran"
  2015-08-24 16:44       ` Hans-Peter Nilsson
  2015-08-24 18:42         ` FX
@ 2015-08-25  3:29         ` Ian Lance Taylor
  2015-08-25 13:25           ` Ulrich Weigand
  1 sibling, 1 reply; 24+ messages in thread
From: Ian Lance Taylor @ 2015-08-25  3:29 UTC (permalink / raw)
  To: Hans-Peter Nilsson; +Cc: fxcoudert, gcc-patches, ubizjak, fortran

Hans-Peter Nilsson <hans-peter.nilsson@axis.com> writes:

> 	* configure.ac: Only compile with -fPIC if the target
> 	supports it.
> 	* configure: Regenerate.

This is OK.

Thanks.

Ian

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Fix libbacktrace -fPIC breakage from "Use libbacktrace in libgfortran"
  2015-08-25  3:29         ` Ian Lance Taylor
@ 2015-08-25 13:25           ` Ulrich Weigand
  2015-08-25 17:09             ` Hans-Peter Nilsson
  0 siblings, 1 reply; 24+ messages in thread
From: Ulrich Weigand @ 2015-08-25 13:25 UTC (permalink / raw)
  To: Ian Lance Taylor
  Cc: Hans-Peter Nilsson, fxcoudert, gcc-patches, ubizjak, fortran

Ian Lance Taylor wrote:
> Hans-Peter Nilsson <hans-peter.nilsson@axis.com> writes:
> 
> > 	* configure.ac: Only compile with -fPIC if the target
> > 	supports it.
> > 	* configure: Regenerate.
> 
> This is OK.

I'm now running into the same problem on SPU, but unfortnately
this patch still doesn't fix the problem.

Now, the SPU does not support dynamic loading and the loader
does not support (most) run-time relocations.  There is no
support for shared libraries on the SPU.  On the SPU, all
GCC target libraries are built as static libraries, and
should be compiled without -fPIC.

However, the compiler actually does accept -fPIC.  If the flag is
present, we attempt to generate relocatable code, but only to the
extent the compiler can do that without support for run-time
relocations.  The most significant restriction is that statically
initializing a global variable to a pointer will not work.
(This is useful for some special cases of self-relocating code.
Such code normally can work around this restriction.)

Now, with the patch above, libbacktrace is still compiled with
-fPIC on SPU, but some files do in fact contain just such global
initializers, causing compilation to fail:

gcc-head/src/libbacktrace/elf.c:241:27: error: creating run-time relocation for '*.LC2'
 static const char * const debug_section_names[DEBUG_MAX] =
                           ^
The other GCC run-time libraries rely on libtool to figure out
that even though -fPIC works, dynamic libraries are still not
supported on the platform, and thus compile everything for
static linking (i.e. without -fPIC).

I'm wondering if we couldn't use the same libtool mechanism here:
if the architecture does not support dynamic linking at all, no
target library will be built as shared library, and thus there is
no need to build libbacktrace with -fPIC either.  (My understanding
is that we need to build libbacktrace with -fPIC because it might
get linked into some other shared target library.)

The libbacktrace configure script actually incorporates all the
libtool init code that makes this determination, and sets the
shell variable "can_build_shared" to "no" on SPU.  Would it be
valid to use this variable in the test whether to use -fPIC?
(I'm not sure which of the many libtool variables are intended
to be used outside, and which are private ...)

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU/Linux compilers and toolchain
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Fix libbacktrace -fPIC breakage from "Use libbacktrace in libgfortran"
  2015-08-25 13:25           ` Ulrich Weigand
@ 2015-08-25 17:09             ` Hans-Peter Nilsson
  2015-08-25 17:57               ` Ulrich Weigand
  0 siblings, 1 reply; 24+ messages in thread
From: Hans-Peter Nilsson @ 2015-08-25 17:09 UTC (permalink / raw)
  To: uweigand; +Cc: ian, fxcoudert, gcc-patches, ubizjak, fortran

TL;DR: See last...

> From: Ulrich Weigand <uweigand@de.ibm.com>
> Date: Tue, 25 Aug 2015 14:59:05 +0200

> However, the compiler actually does accept -fPIC.  If the flag is
> present, we attempt to generate relocatable code, but only to the
> extent the compiler can do that without support for run-time
> relocations.  The most significant restriction is that statically
> initializing a global variable to a pointer will not work.
> (This is useful for some special cases of self-relocating code.
> Such code normally can work around this restriction.)

Still, things like that is why I chose to emit a hard error for
-fPIC/-fpic where it's not supported for *all* code...


> Now, with the patch above, libbacktrace is still compiled with
> -fPIC on SPU, but some files do in fact contain just such global
> initializers, causing compilation to fail:
> 
> gcc-head/src/libbacktrace/elf.c:241:27: error: creating run-time relocation for '*.LC2'
>  static const char * const debug_section_names[DEBUG_MAX] =
>                            ^
> The other GCC run-time libraries rely on libtool to figure out
> that even though -fPIC works, dynamic libraries are still not
> supported on the platform, and thus compile everything for
> static linking (i.e. without -fPIC).

That's not what I see, at least not the "figuring out" part.
(They mostly use libtool as-is; some test tuples, but some test
version-script support and add it then.)

> I'm wondering if we couldn't use the same libtool mechanism here:
> if the architecture does not support dynamic linking at all, no
> target library will be built as shared library, and thus there is
> no need to build libbacktrace with -fPIC either.  (My understanding
> is that we need to build libbacktrace with -fPIC because it might
> get linked into some other shared target library.)

Yes, that's what the comment in the patch context says, as
happens for libgfortran.

> The libbacktrace configure script actually incorporates all the
> libtool init code that makes this determination, and sets the
> shell variable "can_build_shared" to "no" on SPU.  Would it be
> valid to use this variable in the test whether to use -fPIC?
> (I'm not sure which of the many libtool variables are intended
> to be used outside, and which are private ...)

I momentarily pondered this too, when I found the libtool
PIC-test-code grepping libtool/configure, but I chose the
simpler TRY_COMPILE test partly for the same
maybe-internal-variable reason.  A visit to the libtool
documentation shows can_build_shared is for some reason not
listed among the documented variables and a STFW doesn't yield
more information for the first few pages of hits (just some
indexed random libtool copies).  On the other hand, libtool.m4
is in the top directory, so we know if we switch to some version
without can_build_shared.

I'll leave that to you to sort out, but if you chose to use
$can_build_shared, consider also setting PIC_FLAG to $pic_flag
(instead of plain -fPIC).  In the meantime I'll commit my patch
as it solves *some* of the breakage; for targets erroring on -fPIC.

...but reading the libtool documention I think I found a much
better solution: Let's just add -prefer-pic when compiling
libbacktrace.  It leaves everything to libtool.  Can you please
test this?

libbacktrace:
	* configure.ac: Use libtool option -prefer-pic, not -fPIC.
	* configure: Regenerate.

diff -upr /expvol/pp_slask/hp/checkout/gcchead/gcc/libbacktrace/configure.ac libbacktrace/configure.ac
--- libbacktrace/configure.ac	2015-05-29 17:23:20.000000000 +0200
+++ libbacktrace/configure.ac	2015-08-24 17:31:18.000000000 +0200
@@ -163,10 +163,11 @@ fi

 # When building as a target library, shared libraries may want to link
 # this in.  We don't want to provide another shared library to
-# complicate dependencies.  Instead, we just compile with -fPIC.
+# complicate dependencies.  Instead, we prefer PIC, if the target
+# supports that through libtool.
 PIC_FLAG=
 if test -n "${with_target_subdir}"; then
-  PIC_FLAG=-fPIC
+  PIC_FLAG=-prefer-pic
 fi
 # Similarly, use -fPIC with --enable-host-shared:
 AC_ARG_ENABLE(host-shared,

brgds, H-P

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Fix libbacktrace -fPIC breakage from "Use libbacktrace in libgfortran"
  2015-08-25 17:09             ` Hans-Peter Nilsson
@ 2015-08-25 17:57               ` Ulrich Weigand
  2015-08-26  0:09                 ` Hans-Peter Nilsson
  0 siblings, 1 reply; 24+ messages in thread
From: Ulrich Weigand @ 2015-08-25 17:57 UTC (permalink / raw)
  To: Hans-Peter Nilsson; +Cc: ian, fxcoudert, gcc-patches, ubizjak, fortran

Hans-Peter Nilsson wrote:
> > From: Ulrich Weigand <uweigand@de.ibm.com>
> > Date: Tue, 25 Aug 2015 14:59:05 +0200
> 
> > The other GCC run-time libraries rely on libtool to figure out
> > that even though -fPIC works, dynamic libraries are still not
> > supported on the platform, and thus compile everything for
> > static linking (i.e. without -fPIC).
> 
> That's not what I see, at least not the "figuring out" part.
> (They mostly use libtool as-is; some test tuples, but some test
> version-script support and add it then.)

Well, the "figuring out" is implicit; because libtool knows the
platform does not support dynamic linking, it defaults to
--disable-shared, which means only static libraries are being
built; and the default compile option when building static
libraries does not use -fPIC.


> I'll leave that to you to sort out, but if you chose to use
> $can_build_shared, consider also setting PIC_FLAG to $pic_flag
> (instead of plain -fPIC).  In the meantime I'll commit my patch
> as it solves *some* of the breakage; for targets erroring on -fPIC.
> 
> ...but reading the libtool documention I think I found a much
> better solution: Let's just add -prefer-pic when compiling
> libbacktrace.  It leaves everything to libtool.  Can you please
> test this?

Hmm, reading the documentation an even simpler version that has
equivalent effect to yours should be just adding the pic-only
option when calling LT_INIT.

However, neither works for the SPU, because in both cases libtool
will only do the test whether the target supports the -fPIC option.
It will not test whether the target supports dynamic libraries.

[ It will do that test; and default to --disable-shared on SPU.
That is a no-op for libbacktrace however, since it calls LT_INIT
with the disable-shared option anyway.  When adding back the -fPIC
flag due to either the pic-only LT_INIT option or the -prefer-pic
libtool command line option, it does not check for that again.  ]

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU/Linux compilers and toolchain
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Fix libbacktrace -fPIC breakage from "Use libbacktrace in libgfortran"
  2015-08-25 17:57               ` Ulrich Weigand
@ 2015-08-26  0:09                 ` Hans-Peter Nilsson
  2015-08-26 12:17                   ` Ulrich Weigand
  0 siblings, 1 reply; 24+ messages in thread
From: Hans-Peter Nilsson @ 2015-08-26  0:09 UTC (permalink / raw)
  To: uweigand; +Cc: ian, fxcoudert, gcc-patches, ubizjak, fortran

> From: Ulrich Weigand <uweigand@de.ibm.com>
> Date: Tue, 25 Aug 2015 19:45:06 +0200

> Hans-Peter Nilsson wrote:

> However, neither works for the SPU, because in both cases libtool
> will only do the test whether the target supports the -fPIC option.
> It will not test whether the target supports dynamic libraries.
> 
> [ It will do that test; and default to --disable-shared on SPU.
> That is a no-op for libbacktrace however, since it calls LT_INIT
> with the disable-shared option anyway.

Maybe it shouldn't?

>  When adding back the -fPIC
> flag due to either the pic-only LT_INIT option or the -prefer-pic
> libtool command line option, it does not check for that again.  ]

Sounds like a bug somewhere, in libtool or its current use:
there *should* be a way to specify "I'd prefer PIC code in these
static libraries".

But, I'll have to leave solving this PIC-failing-at-linkage
problem to you; I committed the current approved fix for
PIC-failing-at-compilation.

brgds, H-P

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Fix libbacktrace -fPIC breakage from "Use libbacktrace in libgfortran"
  2015-08-26  0:09                 ` Hans-Peter Nilsson
@ 2015-08-26 12:17                   ` Ulrich Weigand
  2015-08-26 12:34                     ` Hans-Peter Nilsson
  0 siblings, 1 reply; 24+ messages in thread
From: Ulrich Weigand @ 2015-08-26 12:17 UTC (permalink / raw)
  To: Hans-Peter Nilsson; +Cc: ian, fxcoudert, gcc-patches, ubizjak, fortran

Hans-Peter Nilsson wrote:
> > From: Ulrich Weigand <uweigand@de.ibm.com>
> > Date: Tue, 25 Aug 2015 19:45:06 +0200
> 
> > However, neither works for the SPU, because in both cases libtool
> > will only do the test whether the target supports the -fPIC option.
> > It will not test whether the target supports dynamic libraries.
> > 
> > [ It will do that test; and default to --disable-shared on SPU.
> > That is a no-op for libbacktrace however, since it calls LT_INIT
> > with the disable-shared option anyway.
> 
> Maybe it shouldn't?

Huh?  We do want libbacktrace solely as static library, that's the
whole point ...

> >  When adding back the -fPIC
> > flag due to either the pic-only LT_INIT option or the -prefer-pic
> > libtool command line option, it does not check for that again.  ]
> 
> Sounds like a bug somewhere, in libtool or its current use:
> there *should* be a way to specify "I'd prefer PIC code in these
> static libraries".

But that's what the option *does*.

Let me try again, maybe we can reduce confusion a bit :-)

We've been discussing three potential sets of options to use with
the LT_INIT call here.   Those are:

A) LT_INIT    # no options
   Build both a static and a shared library.  If the target does not
   support shared libraries, build the static library only.  The code
   landing in the static library is built without -fPIC; code for the
   shared library is built with -fPIC (or the appropriate target flag).

B) LT_INIT([disable-shared])
   Build *solely* a static library.  Code is compiled without -fPIC.

C) LT_INIT([disable-shared,pic-only])
   Build solely a static library, but compile code with -fPIC or the
   appropriate target flag (may be none if the target does not support
   -fPIC).

[Note that in all cases, behaviour can be overridden via configure
options like --enable/disable-shared and --enable/disable-static.]

As I understand it, we deliberately do not use option A.  As the comment
in the libbacktrace configure.ac says:
 # When building as a target library, shared libraries may want to link
 # this in.  We don't want to provide another shared library to
 # complicate dependencies.  Instead, we just compile with -fPIC.

That's why libbacktrace currently uses option B and manually adds a
-fPIC flag.  Now, after the latest check-in, the behaviour is mostly
equivalent to using option C (and not manually changing PIC flags).

However, none of the options do exactly what would be right for
the SPU, which would be:

  Build solely a static library, using code that is compiled so that
  it can be linked as part of a second library (static or shared).

This is equivalent to:

  Build solely a static library, but compile code with -fPIC or the
  appropriate target flag *if the target supports shared libraries*.

This again is *mostly* equivalent to option C, *except* on targets
that support -fPIC but do not support shared libraries.

I'm not sure if it is worthwhile to try and change libtool to
support targets with that property (e.g. adding a new LT_INIT
option), if this in practice only affects SPU.

> But, I'll have to leave solving this PIC-failing-at-linkage
> problem to you; I committed the current approved fix for
> PIC-failing-at-compilation.

I guess we can always fall back to just hard-coding SPU once
more; that's certainly the simplest solution right now.

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU/Linux compilers and toolchain
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Fix libbacktrace -fPIC breakage from "Use libbacktrace in libgfortran"
  2015-08-26 12:17                   ` Ulrich Weigand
@ 2015-08-26 12:34                     ` Hans-Peter Nilsson
  2015-08-26 15:37                       ` [PATCH] Fix and simplify (Re: Fix libbacktrace -fPIC breakage from "Use libbacktrace in libgfortran") Ulrich Weigand
  0 siblings, 1 reply; 24+ messages in thread
From: Hans-Peter Nilsson @ 2015-08-26 12:34 UTC (permalink / raw)
  To: uweigand; +Cc: ian, fxcoudert, gcc-patches, ubizjak, fortran

> From: Ulrich Weigand <uweigand@de.ibm.com>
> Date: Wed, 26 Aug 2015 13:45:35 +0200

> Hans-Peter Nilsson wrote:
> > > From: Ulrich Weigand <uweigand@de.ibm.com>
> > > Date: Tue, 25 Aug 2015 19:45:06 +0200
> > 
> > > However, neither works for the SPU, because in both cases libtool
> > > will only do the test whether the target supports the -fPIC option.
> > > It will not test whether the target supports dynamic libraries.
> > > 
> > > [ It will do that test; and default to --disable-shared on SPU.
> > > That is a no-op for libbacktrace however, since it calls LT_INIT
> > > with the disable-shared option anyway.
> > 
> > Maybe it shouldn't?
> 
> Huh?  We do want libbacktrace solely as static library, that's the
> whole point ...

I meant that as a *suggestion for a possible workaround* to stop
libtool from refusing to compile with PIC, but then I take it
you don't need hints to try another angle than adjusting
compilation flags.

> > >  When adding back the -fPIC
> > > flag due to either the pic-only LT_INIT option or the -prefer-pic
> > > libtool command line option, it does not check for that again.  ]
> > 
> > Sounds like a bug somewhere, in libtool or its current use:
> > there *should* be a way to specify "I'd prefer PIC code in these
> > static libraries".
> 
> But that's what the option *does*.
> 
> Let me try again, maybe we can reduce confusion a bit :-)

I don't feel very confused, but I understand you've investigated
things down to a point where we can conclude that libtool can't
do what SPU needs without also at least fiddling with
compilation options.

> I guess we can always fall back to just hard-coding SPU once
> more; that's certainly the simplest solution right now.

Maybe.

brgds, H-P

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH] Fix and simplify (Re: Fix libbacktrace -fPIC breakage from "Use libbacktrace in libgfortran")
  2015-08-26 12:34                     ` Hans-Peter Nilsson
@ 2015-08-26 15:37                       ` Ulrich Weigand
  2015-08-27  4:02                         ` Ian Lance Taylor
  0 siblings, 1 reply; 24+ messages in thread
From: Ulrich Weigand @ 2015-08-26 15:37 UTC (permalink / raw)
  To: Hans-Peter Nilsson; +Cc: ian, fxcoudert, gcc-patches, ubizjak, fortran

Hans-Peter Nilsson wrote:

> I don't feel very confused, but I understand you've investigated
> things down to a point where we can conclude that libtool can't
> do what SPU needs without also at least fiddling with
> compilation options.

Well, looks like I was confused after all.  I missed one extra
feature of libtool that does indeed just make everything work
automatically: if a library is set up using the "noinst" flag,
libtool considers it a "convenience library" and will never
create a shared library in any case; but it will create two
sets of object files, one suitable for linking into a static
library and one suitable for linking into a shared library,
and will automatically use the correct set when linking any
other library against the "convenince library".

This is exactly what we want to happen for libbacktrace.  And
in fact, it is *already* set up as convenience library:
noinst_LTLIBRARIES = libbacktrace.la

This means the only thing we need to do is simply remove all
the special code: no more "disable-shared" and no more fiddling
with -fPIC (except for the --enable-host-shared case, which
remains special just like it does in all other libraries).

I've verified that this works on x86_64: the resulting
libgfortran.so uses the -fPIC version of the libbacktrace
object, while libgfortran.a uses the non-PIC versions.

On SPU, libtool will now automatically only generate the
non-PIC versions since the target does not support shared
library.  So everything works as expected.

OK for mainline?

Bye,
Ulrich

Index: libbacktrace/configure.ac
===================================================================
--- libbacktrace/configure.ac	(revision 227217)
+++ libbacktrace/configure.ac	(working copy)
@@ -79,7 +79,7 @@ case "$AWK" in
 "") AC_MSG_ERROR([can't build without awk]) ;;
 esac
 
-LT_INIT([disable-shared])
+LT_INIT
 AM_PROG_LIBTOOL
 
 backtrace_supported=yes
@@ -161,22 +161,11 @@ else
   fi
 fi
 
-# When building as a target library, shared libraries may want to link
-# this in.  We don't want to provide another shared library to
-# complicate dependencies.  Instead, we just compile with -fPIC, if
-# the target supports compiling with that option.
-PIC_FLAG=
-if test -n "${with_target_subdir}"; then
-  ac_save_CFLAGS="$CFLAGS"
-  CFLAGS="$CFLAGS -fPIC"
-  AC_TRY_COMPILE([], [], [PIC_FLAG=-fPIC])
-  CFLAGS="$ac_save_CFLAGS"
-fi
-# Similarly, use -fPIC with --enable-host-shared:
+# Enable --enable-host-shared.
 AC_ARG_ENABLE(host-shared,
 [AS_HELP_STRING([--enable-host-shared],
 		[build host code as shared libraries])],
-[PIC_FLAG=-fPIC], [])
+[PIC_FLAG=-fPIC], [PIC_FLAG=])
 AC_SUBST(PIC_FLAG)
 
 # Test for __sync support.

-- 
  Dr. Ulrich Weigand
  GNU/Linux compilers and toolchain
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] Fix and simplify (Re: Fix libbacktrace -fPIC breakage from "Use libbacktrace in libgfortran")
  2015-08-26 15:37                       ` [PATCH] Fix and simplify (Re: Fix libbacktrace -fPIC breakage from "Use libbacktrace in libgfortran") Ulrich Weigand
@ 2015-08-27  4:02                         ` Ian Lance Taylor
  2015-08-27 13:38                           ` Ulrich Weigand
  0 siblings, 1 reply; 24+ messages in thread
From: Ian Lance Taylor @ 2015-08-27  4:02 UTC (permalink / raw)
  To: Ulrich Weigand
  Cc: Hans-Peter Nilsson, fxcoudert, gcc-patches, ubizjak, fortran

"Ulrich Weigand" <uweigand@de.ibm.com> writes:

> I've verified that this works on x86_64: the resulting
> libgfortran.so uses the -fPIC version of the libbacktrace
> object, while libgfortran.a uses the non-PIC versions.
>
> On SPU, libtool will now automatically only generate the
> non-PIC versions since the target does not support shared
> library.  So everything works as expected.
>
> OK for mainline?

Can you verify that libgo works as expected?

Ian

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] Fix and simplify (Re: Fix libbacktrace -fPIC breakage from "Use libbacktrace in libgfortran")
  2015-08-27  4:02                         ` Ian Lance Taylor
@ 2015-08-27 13:38                           ` Ulrich Weigand
  2015-08-27 14:02                             ` Ian Lance Taylor
  0 siblings, 1 reply; 24+ messages in thread
From: Ulrich Weigand @ 2015-08-27 13:38 UTC (permalink / raw)
  To: Ian Lance Taylor
  Cc: Hans-Peter Nilsson, fxcoudert, gcc-patches, ubizjak, fortran

Ian Lance Taylor wrote:
> "Ulrich Weigand" <uweigand@de.ibm.com> writes:
> 
> > I've verified that this works on x86_64: the resulting
> > libgfortran.so uses the -fPIC version of the libbacktrace
> > object, while libgfortran.a uses the non-PIC versions.
> >
> > On SPU, libtool will now automatically only generate the
> > non-PIC versions since the target does not support shared
> > library.  So everything works as expected.
> >
> > OK for mainline?
> 
> Can you verify that libgo works as expected?

Looks correct to me: On x86_64, libgo.so contains -fPIC
versions of the backtrace routine, while libgo.a contains
non-PIC versions.  (There's no Go support on SPU.)

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU/Linux compilers and toolchain
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] Fix and simplify (Re: Fix libbacktrace -fPIC breakage from "Use libbacktrace in libgfortran")
  2015-08-27 13:38                           ` Ulrich Weigand
@ 2015-08-27 14:02                             ` Ian Lance Taylor
  0 siblings, 0 replies; 24+ messages in thread
From: Ian Lance Taylor @ 2015-08-27 14:02 UTC (permalink / raw)
  To: Ulrich Weigand
  Cc: Hans-Peter Nilsson, fxcoudert, gcc-patches, ubizjak, fortran

"Ulrich Weigand" <uweigand@de.ibm.com> writes:

> Ian Lance Taylor wrote:
>> "Ulrich Weigand" <uweigand@de.ibm.com> writes:
>> 
>> > I've verified that this works on x86_64: the resulting
>> > libgfortran.so uses the -fPIC version of the libbacktrace
>> > object, while libgfortran.a uses the non-PIC versions.
>> >
>> > On SPU, libtool will now automatically only generate the
>> > non-PIC versions since the target does not support shared
>> > library.  So everything works as expected.
>> >
>> > OK for mainline?
>> 
>> Can you verify that libgo works as expected?
>
> Looks correct to me: On x86_64, libgo.so contains -fPIC
> versions of the backtrace routine, while libgo.a contains
> non-PIC versions.  (There's no Go support on SPU.)

Your patch to libbacktrace is OK.

Thanks.

Ian

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [patch,libgfortran,toplevel] Use libbacktrace in libgfortran
  2015-08-14  9:23 [patch,libgfortran,toplevel] Use libbacktrace in libgfortran FX
@ 2015-08-14 14:19 ` Ian Lance Taylor
  0 siblings, 0 replies; 24+ messages in thread
From: Ian Lance Taylor @ 2015-08-14 14:19 UTC (permalink / raw)
  To: FX; +Cc: gcc-patches, gfortran

On Fri, Aug 14, 2015 at 1:32 AM, FX <fxcoudert@gmail.com> wrote:
> Use libbacktrace (instead of our own unwind-based code) to display backtraces from libgfortran upon error or user request.
>
>   1. In toplevel Makefile.def, make libgfortran depend on libbacktrace (needs global reviewer approval)

This change (and the corresponding change to Makefile.in) is OK.

Thanks.

Ian

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [patch,libgfortran,toplevel] Use libbacktrace in libgfortran
@ 2015-08-14  9:23 FX
  2015-08-14 14:19 ` Ian Lance Taylor
  0 siblings, 1 reply; 24+ messages in thread
From: FX @ 2015-08-14  9:23 UTC (permalink / raw)
  To: gcc-patches; +Cc: gfortran

[-- Attachment #1: Type: text/plain, Size: 2491 bytes --]

Use libbacktrace (instead of our own unwind-based code) to display backtraces from libgfortran upon error or user request.

  1. In toplevel Makefile.def, make libgfortran depend on libbacktrace (needs global reviewer approval)
  2. In gcc/fortran/config-lang.in, add libbacktrace to target_libs
  3. In libgfortran, we remove our own code and substitute calls to libbacktrace

Bootstrapped and regtested on x86_64-pc-linux-gnu (which has full libbacktrace support) and x86_64-apple-darwin14 (which has minimal libbacktrace support). OK to commit to trunk?

FX

------

The fine print:

This is a great simplification of the library code, because we get rid of the unwind code, and don’t need all the code to find out our executable’s absolute path, find addr2line, pipe-fork-exec addr2line, etc. Just libgfortran/runtime/backtrace.c’s size is reduced by half. And we will benefit from future possible improvements in libbacktrace.

One choice I have made is to not display in backtraces the libgfortran functions, i.e. anything starting with _gfortran_ or _gfortrani_ is simply not printed. I think this is more convenient for some users, because it will avoid them being confused by symbols they don’t recognize. It means, however, that runtime backtraces are a little less useful for us in debugging… but then, we know how to use gdb :)  I am open to being convinced otherwise and remove these few lines of code.

Other than that deliberate choice, no functionality is lost. On dwarf/elf targets (the majority), we get beautiful backtraces as before if code is compiled with “-g”:

#0  0x4006f5 __foo_MOD_gee
	/home/fx/gcc/irun/a.f90:4
#1  0x400706 bar
	/home/fx/gcc/irun/a.f90:16
#2  0x40072e foo
	/home/fx/gcc/irun/a.f90:12
#3  0x400715 test
	/home/fx/gcc/irun/a.f90:9
#4  0x400765 main
	/home/fx/gcc/irun/a.f90:9

and if not compiled with “-g”, we get the nonsymbolic backtrace, as before:

#0  0x4010bd ???
#1  0x4010ce ???
#2  0x4010f6 ???
#3  0x4010dd ???
#4  0x40112d ???
#5  0x42a6b3 ???
#6  0x400fbc ???


We will get backtraces on PE/COFF targets (i.e. Windows), where I don’t think we had them before (but cannot test).
And on non-elf targets such as Mac OS X, we stay with the same as before, i.e. non-symbolic backtraces.



PS: This is probably one of the last of my “summer” gfortran projects for this year. The end of holidays is near, and I’ll have to get back to work. It was fun, as always!



[-- Attachment #2: backtrace.ChangeLog --]
[-- Type: application/applefile, Size: 79 bytes --]

[-- Attachment #3: backtrace.diff --]
[-- Type: application/octet-stream, Size: 20876 bytes --]

Index: Makefile.def
===================================================================
--- Makefile.def	(revision 226823)
+++ Makefile.def	(working copy)
@@ -597,6 +597,7 @@ dependencies = { module=all-target-winsu
 dependencies = { module=configure-target-newlib; on=all-binutils; };
 dependencies = { module=configure-target-newlib; on=all-ld; };
 dependencies = { module=configure-target-libgfortran; on=all-target-libquadmath; };
+dependencies = { module=configure-target-libgfortran; on=all-target-libbacktrace; };
 
 languages = { language=c;	gcc-check-target=check-gcc; };
 languages = { language=c++;	gcc-check-target=check-c++;
Index: gcc/fortran/config-lang.in
===================================================================
--- gcc/fortran/config-lang.in	(revision 226823)
+++ gcc/fortran/config-lang.in	(working copy)
@@ -27,7 +27,7 @@ language="fortran"
 
 compilers="f951\$(exeext)"
 
-target_libs=target-libgfortran
+target_libs="target-libgfortran target-libbacktrace"
 
 gtfiles="\$(srcdir)/fortran/f95-lang.c \$(srcdir)/fortran/trans-decl.c \$(srcdir)/fortran/trans-intrinsic.c \$(srcdir)/fortran/trans-io.c \$(srcdir)/fortran/trans-stmt.c \$(srcdir)/fortran/trans-types.c \$(srcdir)/fortran/trans-types.h \$(srcdir)/fortran/trans.h \$(srcdir)/fortran/trans-const.h"
 
Index: libgfortran/Makefile.am
===================================================================
--- libgfortran/Makefile.am	(revision 226823)
+++ libgfortran/Makefile.am	(working copy)
@@ -37,7 +37,8 @@ toolexeclib_LTLIBRARIES = libgfortran.la
 toolexeclib_DATA = libgfortran.spec
 libgfortran_la_LINK = $(LINK) $(libgfortran_la_LDFLAGS)
 libgfortran_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` \
-	$(LTLDFLAGS) $(LIBQUADLIB) -lm $(extra_ldflags_libgfortran) \
+	$(LTLDFLAGS) $(LIBQUADLIB) ../libbacktrace/libbacktrace.la \
+	-lm $(extra_ldflags_libgfortran) \
 	$(version_arg) -Wc,-shared-libgcc
 libgfortran_la_DEPENDENCIES = $(version_dep) libgfortran.spec $(LIBQUADLIB_DEP)
 
@@ -59,7 +60,10 @@ AM_CPPFLAGS = -iquote$(srcdir)/io -I$(sr
 	      -I$(srcdir)/$(MULTISRCTOP)../gcc/config $(LIBQUADINCLUDE) \
 	      -I$(MULTIBUILDTOP)../../$(host_subdir)/gcc \
 	      -I$(srcdir)/$(MULTISRCTOP)../libgcc \
-	      -I$(MULTIBUILDTOP)../libgcc
+	      -I$(MULTIBUILDTOP)../libgcc \
+	      -I$(srcdir)/$(MULTISRCTOP)../libbacktrace \
+	      -I$(MULTIBUILDTOP)../libbacktrace \
+	      -I../libbacktrace
 
 # Fortran rules for complex multiplication and division
 AM_CFLAGS += -fcx-fortran-rules
Index: libgfortran/configure.ac
===================================================================
--- libgfortran/configure.ac	(revision 226823)
+++ libgfortran/configure.ac	(working copy)
@@ -287,7 +287,6 @@ if test "x${with_newlib}" = "xyes"; then
    AC_DEFINE(HAVE_GMTIME_R, 1, [Define if you have gmtime_r.])
    AC_DEFINE(HAVE_STRNLEN, 1, [Define if you have strnlen.])
    AC_DEFINE(HAVE_STRNDUP, 1, [Define if you have strndup.])
-   AC_DEFINE(HAVE_STRTOK_R, 1, [Define if you have strtok_r.])
 
    # At some point, we should differentiate between architectures
    # like x86, which have long double versions, and alpha/powerpc/etc.,
@@ -298,11 +297,11 @@ if test "x${with_newlib}" = "xyes"; then
 else
    AC_CHECK_FUNCS_ONCE(getrusage times mkstemp strtof strtold snprintf \
    ftruncate chsize chdir getlogin gethostname kill link symlink sleep ttyname \
-   alarm access fork execl wait setmode execve pipe dup2 close fcntl \
+   alarm access fork execl setmode close fcntl \
    strcasestr getrlimit gettimeofday stat fstat lstat getpwuid vsnprintf dup \
    getcwd localtime_r gmtime_r getpwuid_r ttyname_r clock_gettime \
    readlink getgid getpid getppid getuid geteuid umask getegid \
-   secure_getenv __secure_getenv mkostemp strnlen strndup strtok_r newlocale \
+   secure_getenv __secure_getenv mkostemp strnlen strndup newlocale \
    freelocale uselocale strerror_l)
 fi
 
@@ -610,9 +609,6 @@ LIBGFOR_CHECK_UNLINK_OPEN_FILE
 # Check whether line terminator is LF or CRLF
 LIBGFOR_CHECK_CRLF
 
-# Check whether we have _Unwind_GetIPInfo for backtrace
-GCC_CHECK_UNWIND_GETIPINFO
-
 AC_CACHE_SAVE
 
 if test ${multilib} = yes; then
Index: libgfortran/libgfortran.h
===================================================================
--- libgfortran/libgfortran.h	(revision 226823)
+++ libgfortran/libgfortran.h	(working copy)
@@ -649,16 +649,11 @@ internal_proto(get_args);
 extern void store_exe_path (const char *);
 export_proto(store_exe_path);
 
-extern char * full_exe_path (void);
-internal_proto(full_exe_path);
-
-extern void find_addr2line (void);
-internal_proto(find_addr2line);
-
 /* backtrace.c */
 
-extern void backtrace (void);
-iexport_proto(backtrace);
+extern void show_backtrace (int);
+internal_proto(show_backtrace);
+
 
 /* error.c */
 
Index: libgfortran/runtime/backtrace.c
===================================================================
--- libgfortran/runtime/backtrace.c	(revision 226823)
+++ libgfortran/runtime/backtrace.c	(working copy)
@@ -31,249 +31,122 @@ see the files COPYING3 and COPYING.RUNTI
 #include <unistd.h>
 #endif
 
-#ifdef HAVE_SYS_WAIT_H
-#include <sys/wait.h>
-#endif
+#include "backtrace-supported.h"
+#include "backtrace.h"
 
-#include <limits.h>
 
-#include "unwind.h"
+/* Store our own state while backtracing.  */
+struct mystate
+{
+  int try_simple;
+  int frame;
+};
 
 
-/* Macros for common sets of capabilities: can we fork and exec, and
-   can we use pipes to communicate with the subprocess.  */
-#define CAN_FORK (defined(HAVE_FORK) && defined(HAVE_EXECVE) \
-		  && defined(HAVE_WAIT))
-#define CAN_PIPE (CAN_FORK && defined(HAVE_PIPE) \
-		  && defined(HAVE_DUP2) && defined(HAVE_CLOSE))
+/* Does a function name have "_gfortran_" or "_gfortrani_" prefix, possibly
+   with additional underscore(s) at the beginning?  Cannot use strncmp()
+   because we might be called from a signal handler.  */
 
-#ifndef PATH_MAX
-#define PATH_MAX 4096
-#endif
+static int
+has_gfortran_prefix (const char *s)
+{
+  if (!s)
+    return 0;
 
+  while (*s == '_')
+    s++;
 
-/* GDB style #NUM index for each stack frame.  */
+  return (s[0] == 'g' && s[1] == 'f' && s[2] == 'o' && s[3] == 'r'
+	  && s[4] == 't' && s[5] == 'r' && s[6] == 'a' && s[7] == 'n'
+	  && (s[8] == '_' || (s[8] == 'i' && s[9] == '_')));
+}
 
-static void 
-bt_header (int num)
+static void
+error_callback (void *data, const char *msg, int errnum)
 {
-  st_printf ("#%d  ", num);
-}
+  struct mystate *state = (struct mystate *) data;
+  if (errnum < 0)
+    {
+      state->try_simple = 1;
+      return;
+    }
 
+  estr_write ("\nSomething went wrong while printing the backtrace: ");
+  estr_write (msg);
+  estr_write ("\n");
+}
 
-/* fgets()-like function that reads a line from a fd, without
-   needing to malloc() a buffer, and does not use locks, hence should
-   be async-signal-safe.  */
+static int
+simple_callback (void *data, uintptr_t pc)
+{
+  struct mystate *state = (struct mystate *) data;
+  st_printf ("#%d  0x%lx\n", state->frame, (unsigned long) pc);
+  (state->frame)++;
+  return 0;
+}
 
-static char *
-fd_gets (char *s, int size, int fd)
+static int
+full_callback (void *data, uintptr_t pc, const char *filename,
+	       int lineno, const char *function)
 {
-  for (int i = 0; i < size; i++)
-    {
-      char c;
-      ssize_t nread = read (fd, &c, 1);
-      if (nread == 1)
-	{
-	  s[i] = c;
-	  if (c == '\n')
-	    {
-	      if (i + 1 < size)
-		s[i+1] = '\0';
-	      else
-		s[i] = '\0';
-	      break;
-	    }
-	}
-      else
-	{
-	  s[i] = '\0';
-	  if (i == 0)
-	    return NULL;
-	  break;
-	}
-    }
-  return s;
+  struct mystate *state = (struct mystate *) data;
+
+  if (has_gfortran_prefix (function))
+    return 0;
+
+  st_printf ("#%d  0x%lx %s\n", state->frame,
+	     (unsigned long) pc, function == NULL ? "???" : function);
+  if (filename || lineno != 0)
+    st_printf ("\t%s:%d\n", filename == NULL ? "???" : filename, lineno);
+  (state->frame)++;
+
+  if (function != NULL && strcmp (function, "main") == 0)
+    return 1;
+
+  return 0;
 }
 
 
-extern char *addr2line_path;
+/* Display the backtrace.  */
 
-/* Struct containing backtrace state.  */
-typedef struct
+void
+show_backtrace (int in_signal_handler)
 {
-  int frame_number;
-  int direct_output;
-  int outfd;
-  int infd;
-  int error;
-}
-bt_state;
-
-static _Unwind_Reason_Code
-trace_function (struct _Unwind_Context *context, void *state_ptr)
-{
-  bt_state* state = (bt_state*) state_ptr;
-  _Unwind_Ptr ip;
-#ifdef HAVE_GETIPINFO
-  int ip_before_insn = 0;
-  ip = _Unwind_GetIPInfo (context, &ip_before_insn);
-  
-  /* If the unwinder gave us a 'return' address, roll it back a little
-     to ensure we get the correct line number for the call itself.  */
-  if (! ip_before_insn)
-    --ip;
-#else  
-  ip = _Unwind_GetIP (context);
-#endif
+  struct backtrace_state *lbstate;
+  struct mystate state = { 0, 0 };
+ 
+  lbstate = backtrace_create_state (NULL, 1, error_callback, NULL);
 
-  if (state->direct_output)
+  if (!BACKTRACE_SUPPORTED || (in_signal_handler && BACKTRACE_USES_MALLOC))
     {
-      bt_header(state->frame_number);
-      st_printf ("%p\n", (void*) ip);
+      /* If symbolic backtrace is not supported on this target, or would
+	 require malloc() and we are in a signal handler, go with a
+	 simple backtrace.  */
+
+      backtrace_simple (lbstate, 0, simple_callback, error_callback, &state);
     }
   else
     {
-      char addr_buf[GFC_XTOA_BUF_SIZE], func[1024], file[PATH_MAX];
-      char *p;
-      const char* addr = gfc_xtoa (ip, addr_buf, sizeof (addr_buf));
-      write (state->outfd, addr, strlen (addr));
-      write (state->outfd, "\n", 1);
-
-      if (! fd_gets (func, sizeof(func), state->infd))
-	{
-	  state->error = 1;
-	  goto done;
-	}
-      if (! fd_gets (file, sizeof(file), state->infd))
-	{
-	  state->error = 1;
-	  goto done;
-	}
-	    
-	for (p = func; *p != '\n' && *p != '\r'; p++)
-	  ;
-	*p = '\0';
-	
-	/* _start is a setup routine that calls main(), and main() is
-	   the frontend routine that calls some setup stuff and then
-	   calls MAIN__, so at this point we should stop.  */
-	if (strcmp (func, "_start") == 0 || strcmp (func, "main") == 0)
-	  return _URC_END_OF_STACK;
-	
-	bt_header (state->frame_number);
-	estr_write ("0x");
-	estr_write (addr);
-
-	if (func[0] != '?' && func[1] != '?')
-	  {
-	    estr_write (" in ");
-	    estr_write (func);
-	  }
-	
-	if (strncmp (file, "??", 2) == 0)
-	  estr_write ("\n");
-	else
-	  {
-	    estr_write (" at ");
-	    estr_write (file);
-	  }
+      /* libbacktrace uses mmap, which is safe to call from a signal handler
+	 (in practice, if not in theory).  Thus we can generate a symbolic
+	 backtrace, if debug symbols are available.  */
+
+      backtrace_full (lbstate, 0, full_callback, error_callback, &state);
+      if (state.try_simple)
+	backtrace_simple (lbstate, 0, simple_callback, error_callback, &state);
     }
+}
 
- done:
 
-  state->frame_number++;
-  
-  return _URC_NO_REASON;
-}
 
+/* Function called by the front-end translating the BACKTRACE intrinsic.  */
 
-/* Display the backtrace.  */
+extern void backtrace (void);
+export_proto (backtrace);
 
 void
 backtrace (void)
 {
-  bt_state state;
-  state.frame_number = 0;
-  state.error = 0;
-
-#if CAN_PIPE
-
-  if (addr2line_path == NULL)
-    goto fallback_noerr;
-
-  /* We attempt to extract file and line information from addr2line.  */
-  do
-  {
-    /* Local variables.  */
-    int f[2], pid, inp[2];
-
-    /* Don't output an error message if something goes wrong, we'll simply
-       fall back to printing the addresses.  */
-    if (pipe (f) != 0)
-      break;
-    if (pipe (inp) != 0)
-      break;
-    if ((pid = fork ()) == -1)
-      break;
-
-    if (pid == 0)
-      {
-	/* Child process.  */
-#define NUM_FIXEDARGS 7
-	char *arg[NUM_FIXEDARGS];
-	char *newenv[] = { NULL };
-
-	close (f[0]);
-
-	close (inp[1]);
-	if (dup2 (inp[0], STDIN_FILENO) == -1)
-	  _exit (1);
-	close (inp[0]);
-
-	close (STDERR_FILENO);
-
-	if (dup2 (f[1], STDOUT_FILENO) == -1)
-	  _exit (1);
-	close (f[1]);
-
-	arg[0] = addr2line_path;
-	arg[1] = (char *) "-e";
-	arg[2] = full_exe_path ();
-	arg[3] = (char *) "-f";
-	arg[4] = (char *) "-s";
-	arg[5] = (char *) "-C";
-	arg[6] = NULL;
-	execve (addr2line_path, arg, newenv);
-	_exit (1);
-#undef NUM_FIXEDARGS
-      }
-
-    /* Father process.  */
-    close (f[1]);
-    close (inp[0]);
-
-    state.outfd = inp[1];
-    state.infd = f[0];
-    state.direct_output = 0;
-    _Unwind_Backtrace (trace_function, &state);
-    if (state.error)
-      goto fallback;
-    close (inp[1]);
-    close (f[0]);
-    wait (NULL);
-    return;
-
-fallback:
-    estr_write ("** Something went wrong while running addr2line. **\n"
-		"** Falling back to a simpler backtrace scheme. **\n");
-  }
-  while (0);
-
-fallback_noerr:
-#endif /* CAN_PIPE */
-
-  /* Fallback to the simple backtrace without addr2line.  */
-  state.direct_output = 1;
-  _Unwind_Backtrace (trace_function, &state);
+  show_backtrace (0);
 }
-iexport(backtrace);
+
Index: libgfortran/runtime/compile_options.c
===================================================================
--- libgfortran/runtime/compile_options.c	(revision 226823)
+++ libgfortran/runtime/compile_options.c	(working copy)
@@ -30,7 +30,7 @@ see the files COPYING3 and COPYING.RUNTI
 compile_options_t compile_options;
 
 #ifndef LIBGFOR_MINIMAL
-volatile sig_atomic_t fatal_error_in_progress = 0;
+static volatile sig_atomic_t fatal_error_in_progress = 0;
 
 
 /* Helper function for backtrace_handler to write information about the
@@ -126,7 +126,7 @@ backtrace_handler (int signum)
 
   show_signal (signum);
   estr_write ("\nBacktrace for this error:\n");
-  backtrace ();
+  show_backtrace (1);
 
   /* Now reraise the signal.  We reactivate the signal's
      default handling, which is to terminate the process.
@@ -136,16 +136,6 @@ backtrace_handler (int signum)
   signal (signum, SIG_DFL);
   raise (signum);
 }
-
-
-/* Helper function for set_options because we need to access the
-   global variable options which is not seen in set_options.  */
-static void
-maybe_find_addr2line (void)
-{
-  if (options.backtrace == -1)
-    find_addr2line ();
-}
 #endif
 
 /* Set the usual compile-time options.  */
@@ -211,8 +201,6 @@ set_options (int num, int options[])
 #if defined(SIGXFSZ)
       signal (SIGXFSZ, backtrace_handler);
 #endif
-
-      maybe_find_addr2line ();
     }
 #endif
 }
Index: libgfortran/runtime/error.c
===================================================================
--- libgfortran/runtime/error.c	(revision 226823)
+++ libgfortran/runtime/error.c	(working copy)
@@ -173,7 +173,7 @@ sys_abort (void)
       || (options.backtrace == -1 && compile_options.backtrace == 1))
     {
       estr_write ("\nProgram aborted. Backtrace:\n");
-      backtrace ();
+      show_backtrace (0);
       signal (SIGABRT, SIG_DFL);
     }
 
Index: libgfortran/runtime/main.c
===================================================================
--- libgfortran/runtime/main.c	(revision 226823)
+++ libgfortran/runtime/main.c	(working copy)
@@ -70,162 +70,13 @@ determine_endianness (void)
 static int argc_save;
 static char **argv_save;
 
-static const char *exe_path;
-static bool please_free_exe_path_when_done;
 
-/* Save the path under which the program was called, for use in the
-   backtrace routines.  */
 void
-store_exe_path (const char * argv0)
+store_exe_path (const char * argv0 __attribute__ ((unused)))
 {
-#ifndef DIR_SEPARATOR   
-#define DIR_SEPARATOR '/'
-#endif
-
-  char *cwd, *path;
-
-  /* This can only happen if store_exe_path is called multiple times.  */
-  if (please_free_exe_path_when_done)
-    free ((char *) exe_path);
-
-  /* Reading the /proc/self/exe symlink is Linux-specific(?), but if
-     it works it gives the correct answer.  */
-#ifdef HAVE_READLINK
-  ssize_t len, psize = 256;
-  while (1)
-    {
-      path = xmalloc (psize);
-      len = readlink ("/proc/self/exe", path, psize);
-      if (len < 0)
-	{
-	  free (path);
-	  break;
-	}
-      else if (len < psize)
-	{
-	  path[len] = '\0';
-	  exe_path = strdup (path);
-	  free (path);
-	  please_free_exe_path_when_done = true;
-	  return;
-	}
-      /* The remaining option is len == psize.  */
-      free (path);
-      psize *= 4;
-    }
-#endif
-
-  /* If the path is absolute or on a simulator where argv is not set.  */
-#ifdef __MINGW32__
-  if (argv0 == NULL
-      || ('A' <= argv0[0] && argv0[0] <= 'Z' && argv0[1] == ':')
-      || ('a' <= argv0[0] && argv0[0] <= 'z' && argv0[1] == ':')
-      || (argv0[0] == '/' && argv0[1] == '/')
-      || (argv0[0] == '\\' && argv0[1] == '\\'))
-#else
-  if (argv0 == NULL || argv0[0] == DIR_SEPARATOR)
-#endif
-    {
-      exe_path = argv0;
-      please_free_exe_path_when_done = false;
-      return;
-    }
-
-#ifdef HAVE_GETCWD
-  size_t cwdsize = 256;
-  while (1)
-    {
-      cwd = xmalloc (cwdsize);
-      if (getcwd (cwd, cwdsize))
-	break;
-      else if (errno == ERANGE)
-	{
-	  free (cwd);
-	  cwdsize *= 4;
-	}
-      else
-	{
-	  free (cwd);
-	  cwd = NULL;
-	  break;
-	}
-    }
-#else
-  cwd = NULL;
-#endif
-
-  if (!cwd)
-    {
-      exe_path = argv0;
-      please_free_exe_path_when_done = false;
-      return;
-    }
-
-  /* exe_path will be cwd + "/" + argv[0] + "\0".  This will not work
-     if the executable is not in the cwd, but at this point we're out
-     of better ideas.  */
-  size_t pathlen = strlen (cwd) + 1 + strlen (argv0) + 1;
-  path = xmalloc (pathlen);
-  snprintf (path, pathlen, "%s%c%s", cwd, DIR_SEPARATOR, argv0);
-  free (cwd);
-  exe_path = path;
-  please_free_exe_path_when_done = true;
-}
-
-
-/* Return the full path of the executable.  */
-char *
-full_exe_path (void)
-{
-  return (char *) exe_path;
-}
-
-
-#ifndef HAVE_STRTOK_R
-static char*
-gfstrtok_r (char *str, const char *delim, 
-	    char **saveptr __attribute__ ((unused)))
-{
-  return strtok (str, delim);
-}
-#define strtok_r gfstrtok_r
-#endif
-
-char *addr2line_path;
-
-/* Find addr2line and store the path.  */
-
-void
-find_addr2line (void)
-{
-#ifdef HAVE_ACCESS
-#define A2L_LEN 11
-  char *path = secure_getenv ("PATH");
-  if (!path)
-    return;
-  char *tp = strdup (path);
-  if (!tp)
-    return;
-  size_t n = strlen (path);
-  char *ap = xmalloc (n + A2L_LEN);
-  char *saveptr;
-  for (char *str = tp;; str = NULL)
-    {
-      char *token = strtok_r (str, ":", &saveptr);
-      if (!token)
-	break;
-      size_t toklen = strlen (token);
-      memcpy (ap, token, toklen);
-      memcpy (ap + toklen, "/addr2line", A2L_LEN);
-      if (access (ap, R_OK|X_OK) == 0)
-	{
-	  addr2line_path = strdup (ap);
-	  break;
-	}
-    }
-  free (tp);
-  free (ap);
-#endif
+  /* This function is now useless, but is retained due to ABI compatibility.
+    Remove when bumping the library ABI.  */
+  ;
 }
 
 
@@ -236,7 +87,6 @@ set_args (int argc, char **argv)
 {
   argc_save = argc;
   argv_save = argv;
-  store_exe_path (argv[0]);
 }
 iexport(set_args);
 
@@ -279,9 +129,6 @@ init (void)
   /* if (argc > 1 && strcmp(argv[1], "--resume") == 0) resume();  */
 #endif
 
-  if (options.backtrace == 1)
-    find_addr2line ();
-
   random_seed_i4 (NULL, NULL, NULL);
 }
 
@@ -292,9 +139,4 @@ static void __attribute__((destructor))
 cleanup (void)
 {
   close_units ();
-  
-  if (please_free_exe_path_when_done)
-    free ((char *) exe_path);
-
-  free (addr2line_path);
 }
Index: libgfortran/runtime/minimal.c
===================================================================
--- libgfortran/runtime/minimal.c	(revision 226823)
+++ libgfortran/runtime/minimal.c	(working copy)
@@ -53,8 +53,6 @@ int big_endian = 0;
 static int argc_save;
 static char **argv_save;
 
-static const char *exe_path;
-
 /* recursion_check()-- It's possible for additional errors to occur
  * during fatal error processing.  We detect this condition here and
  * exit with code 4 immediately. */
@@ -163,14 +161,6 @@ internal_error (st_parameter_common *cmp
 }
 
 
-/* Return the full path of the executable.  */
-char *
-full_exe_path (void)
-{
-  return (char *) exe_path;
-}
-
-
 /* Set the saved values of the command line arguments.  */
 
 void
@@ -178,7 +168,6 @@ set_args (int argc, char **argv)
 {
   argc_save = argc;
   argv_save = argv;
-  exe_path = argv[0];
 }
 iexport(set_args);
 
Index: gcc/testsuite/gfortran.dg/backtrace_1.f90
===================================================================
--- gcc/testsuite/gfortran.dg/backtrace_1.f90	(revision 0)
+++ gcc/testsuite/gfortran.dg/backtrace_1.f90	(working copy)
@@ -0,0 +1,10 @@
+! { dg-do run }
+! 
+! Check that BACKTRACE is available on all targets. We cannot actually
+! check its output, but we should at least be able to call it, then exit
+! normally.
+!
+program test
+  call backtrace
+  stop
+end program test

[-- Attachment #4: backtrace_withregeneratedfiles.diff --]
[-- Type: application/octet-stream, Size: 28916 bytes --]

Index: Makefile.def
===================================================================
--- Makefile.def	(revision 226823)
+++ Makefile.def	(working copy)
@@ -597,6 +597,7 @@ dependencies = { module=all-target-winsu
 dependencies = { module=configure-target-newlib; on=all-binutils; };
 dependencies = { module=configure-target-newlib; on=all-ld; };
 dependencies = { module=configure-target-libgfortran; on=all-target-libquadmath; };
+dependencies = { module=configure-target-libgfortran; on=all-target-libbacktrace; };
 
 languages = { language=c;	gcc-check-target=check-gcc; };
 languages = { language=c++;	gcc-check-target=check-c++;
Index: Makefile.in
===================================================================
--- Makefile.in	(revision 226823)
+++ Makefile.in	(working copy)
@@ -50921,6 +50921,7 @@ all-target-winsup: maybe-all-target-libt
 configure-target-newlib: maybe-all-binutils
 configure-target-newlib: maybe-all-ld
 configure-target-libgfortran: maybe-all-target-libquadmath
+configure-target-libgfortran: maybe-all-target-libbacktrace
 
 
 # Dependencies for target modules on other target modules are
Index: gcc/fortran/config-lang.in
===================================================================
--- gcc/fortran/config-lang.in	(revision 226823)
+++ gcc/fortran/config-lang.in	(working copy)
@@ -27,7 +27,7 @@ language="fortran"
 
 compilers="f951\$(exeext)"
 
-target_libs=target-libgfortran
+target_libs="target-libgfortran target-libbacktrace"
 
 gtfiles="\$(srcdir)/fortran/f95-lang.c \$(srcdir)/fortran/trans-decl.c \$(srcdir)/fortran/trans-intrinsic.c \$(srcdir)/fortran/trans-io.c \$(srcdir)/fortran/trans-stmt.c \$(srcdir)/fortran/trans-types.c \$(srcdir)/fortran/trans-types.h \$(srcdir)/fortran/trans.h \$(srcdir)/fortran/trans-const.h"
 
Index: libgfortran/Makefile.am
===================================================================
--- libgfortran/Makefile.am	(revision 226823)
+++ libgfortran/Makefile.am	(working copy)
@@ -37,7 +37,8 @@ toolexeclib_LTLIBRARIES = libgfortran.la
 toolexeclib_DATA = libgfortran.spec
 libgfortran_la_LINK = $(LINK) $(libgfortran_la_LDFLAGS)
 libgfortran_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` \
-	$(LTLDFLAGS) $(LIBQUADLIB) -lm $(extra_ldflags_libgfortran) \
+	$(LTLDFLAGS) $(LIBQUADLIB) ../libbacktrace/libbacktrace.la \
+	-lm $(extra_ldflags_libgfortran) \
 	$(version_arg) -Wc,-shared-libgcc
 libgfortran_la_DEPENDENCIES = $(version_dep) libgfortran.spec $(LIBQUADLIB_DEP)
 
@@ -59,7 +60,10 @@ AM_CPPFLAGS = -iquote$(srcdir)/io -I$(sr
 	      -I$(srcdir)/$(MULTISRCTOP)../gcc/config $(LIBQUADINCLUDE) \
 	      -I$(MULTIBUILDTOP)../../$(host_subdir)/gcc \
 	      -I$(srcdir)/$(MULTISRCTOP)../libgcc \
-	      -I$(MULTIBUILDTOP)../libgcc
+	      -I$(MULTIBUILDTOP)../libgcc \
+	      -I$(srcdir)/$(MULTISRCTOP)../libbacktrace \
+	      -I$(MULTIBUILDTOP)../libbacktrace \
+	      -I../libbacktrace
 
 # Fortran rules for complex multiplication and division
 AM_CFLAGS += -fcx-fortran-rules
Index: libgfortran/Makefile.in
===================================================================
--- libgfortran/Makefile.in	(revision 226823)
+++ libgfortran/Makefile.in	(working copy)
@@ -132,7 +132,6 @@ am__aclocal_m4_deps = $(top_srcdir)/../c
 	$(top_srcdir)/../config/multi.m4 \
 	$(top_srcdir)/../config/override.m4 \
 	$(top_srcdir)/../config/stdint.m4 \
-	$(top_srcdir)/../config/unwind_ipinfo.m4 \
 	$(top_srcdir)/../ltoptions.m4 $(top_srcdir)/../ltsugar.m4 \
 	$(top_srcdir)/../ltversion.m4 $(top_srcdir)/../lt~obsolete.m4 \
 	$(top_srcdir)/acinclude.m4 $(top_srcdir)/../config/acx.m4 \
@@ -598,7 +597,8 @@ toolexeclib_LTLIBRARIES = libgfortran.la
 toolexeclib_DATA = libgfortran.spec
 libgfortran_la_LINK = $(LINK) $(libgfortran_la_LDFLAGS)
 libgfortran_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` \
-	$(LTLDFLAGS) $(LIBQUADLIB) -lm $(extra_ldflags_libgfortran) \
+	$(LTLDFLAGS) $(LIBQUADLIB) ../libbacktrace/libbacktrace.la \
+	-lm $(extra_ldflags_libgfortran) \
 	$(version_arg) -Wc,-shared-libgcc
 
 libgfortran_la_DEPENDENCIES = $(version_dep) libgfortran.spec $(LIBQUADLIB_DEP)
@@ -614,7 +614,10 @@ AM_CPPFLAGS = -iquote$(srcdir)/io -I$(sr
 	      -I$(srcdir)/$(MULTISRCTOP)../gcc/config $(LIBQUADINCLUDE) \
 	      -I$(MULTIBUILDTOP)../../$(host_subdir)/gcc \
 	      -I$(srcdir)/$(MULTISRCTOP)../libgcc \
-	      -I$(MULTIBUILDTOP)../libgcc
+	      -I$(MULTIBUILDTOP)../libgcc \
+	      -I$(srcdir)/$(MULTISRCTOP)../libbacktrace \
+	      -I$(MULTIBUILDTOP)../libbacktrace \
+	      -I../libbacktrace
 
 gfor_io_src = io/size_from_kind.c $(am__append_2)
 gfor_io_headers = \
Index: libgfortran/aclocal.m4
===================================================================
--- libgfortran/aclocal.m4	(revision 226823)
+++ libgfortran/aclocal.m4	(working copy)
@@ -1029,7 +1029,6 @@ m4_include([../config/lthostflags.m4])
 m4_include([../config/multi.m4])
 m4_include([../config/override.m4])
 m4_include([../config/stdint.m4])
-m4_include([../config/unwind_ipinfo.m4])
 m4_include([../ltoptions.m4])
 m4_include([../ltsugar.m4])
 m4_include([../ltversion.m4])
Index: libgfortran/config.h.in
===================================================================
--- libgfortran/config.h.in	(revision 226823)
+++ libgfortran/config.h.in	(working copy)
@@ -315,9 +315,6 @@
 /* Define to 1 if you have the `dup' function. */
 #undef HAVE_DUP
 
-/* Define to 1 if you have the `dup2' function. */
-#undef HAVE_DUP2
-
 /* Define to 1 if you have the `erf' function. */
 #undef HAVE_ERF
 
@@ -339,9 +336,6 @@
 /* Define to 1 if you have the `execl' function. */
 #undef HAVE_EXECL
 
-/* Define to 1 if you have the `execve' function. */
-#undef HAVE_EXECVE
-
 /* Define to 1 if you have the `exp' function. */
 #undef HAVE_EXP
 
@@ -462,9 +456,6 @@
 /* Define to 1 if you have the `gethostname' function. */
 #undef HAVE_GETHOSTNAME
 
-/* Define if _Unwind_GetIPInfo is available. */
-#undef HAVE_GETIPINFO
-
 /* Define to 1 if you have the `getlogin' function. */
 #undef HAVE_GETLOGIN
 
@@ -636,9 +627,6 @@
 /* Define to 1 if you have the `nextafterl' function. */
 #undef HAVE_NEXTAFTERL
 
-/* Define to 1 if you have the `pipe' function. */
-#undef HAVE_PIPE
-
 /* Define to 1 if we have POSIX getpwuid_r which takes 5 arguments. */
 #undef HAVE_POSIX_GETPWUID_R
 
@@ -753,9 +741,6 @@
 /* Define to 1 if you have the `strtof' function. */
 #undef HAVE_STRTOF
 
-/* Define to 1 if you have the `strtok_r' function. */
-#undef HAVE_STRTOK_R
-
 /* Define to 1 if you have the `strtold' function. */
 #undef HAVE_STRTOLD
 
@@ -855,9 +840,6 @@
 /* Define to 1 if you have the `vsnprintf' function. */
 #undef HAVE_VSNPRINTF
 
-/* Define to 1 if you have the `wait' function. */
-#undef HAVE_WAIT
-
 /* Define if target has a reliable stat. */
 #undef HAVE_WORKING_STAT
 
Index: libgfortran/configure
===================================================================
--- libgfortran/configure	(revision 226823)
+++ libgfortran/configure	(working copy)
@@ -776,7 +776,6 @@ with_gnu_ld
 enable_libtool_lock
 enable_largefile
 enable_libquadmath_support
-with_system_libunwind
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1435,7 +1434,6 @@ Optional Packages:
   --with-pic              try to use only PIC/non-PIC objects [default=use
                           both]
   --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
-  --with-system-libunwind use installed libunwind
 
 Some influential environment variables:
   CC          C compiler command
@@ -2572,11 +2570,7 @@ as_fn_append ac_func_list " alarm"
 as_fn_append ac_func_list " access"
 as_fn_append ac_func_list " fork"
 as_fn_append ac_func_list " execl"
-as_fn_append ac_func_list " wait"
 as_fn_append ac_func_list " setmode"
-as_fn_append ac_func_list " execve"
-as_fn_append ac_func_list " pipe"
-as_fn_append ac_func_list " dup2"
 as_fn_append ac_func_list " close"
 as_fn_append ac_func_list " fcntl"
 as_fn_append ac_func_list " strcasestr"
@@ -2607,7 +2601,6 @@ as_fn_append ac_func_list " __secure_get
 as_fn_append ac_func_list " mkostemp"
 as_fn_append ac_func_list " strnlen"
 as_fn_append ac_func_list " strndup"
-as_fn_append ac_func_list " strtok_r"
 as_fn_append ac_func_list " newlocale"
 as_fn_append ac_func_list " freelocale"
 as_fn_append ac_func_list " uselocale"
@@ -12376,7 +12369,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 12379 "configure"
+#line 12372 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -12482,7 +12475,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 12485 "configure"
+#line 12478 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -16514,9 +16507,6 @@ $as_echo "#define HAVE_STRNLEN 1" >>conf
 $as_echo "#define HAVE_STRNDUP 1" >>confdefs.h
 
 
-$as_echo "#define HAVE_STRTOK_R 1" >>confdefs.h
-
-
    # At some point, we should differentiate between architectures
    # like x86, which have long double versions, and alpha/powerpc/etc.,
    # which don't. For the time being, punt.
@@ -16653,16 +16643,6 @@ done
 
 
 
-
-
-
-
-
-
-
-
-
-
 fi
 
 # Check strerror_r, cannot be above as versions with two and three arguments exist
@@ -26584,44 +26564,6 @@ $as_echo "#define HAVE_CRLF 1" >>confdef
 
 fi
 
-# Check whether we have _Unwind_GetIPInfo for backtrace
-
-
-# Check whether --with-system-libunwind was given.
-if test "${with_system_libunwind+set}" = set; then :
-  withval=$with_system_libunwind;
-fi
-
-  # If system-libunwind was not specifically set, pick a default setting.
-  if test x$with_system_libunwind = x; then
-    case ${target} in
-      ia64-*-hpux*) with_system_libunwind=yes ;;
-      *) with_system_libunwind=no ;;
-    esac
-  fi
-  # Based on system-libunwind and target, do we have ipinfo?
-  if  test x$with_system_libunwind = xyes; then
-    case ${target} in
-      ia64-*-*) have_unwind_getipinfo=no ;;
-      *) have_unwind_getipinfo=yes ;;
-    esac
-  else
-    # Darwin before version 9 does not have _Unwind_GetIPInfo.
-
-    case ${target} in
-      *-*-darwin[3-8]|*-*-darwin[3-8].*) have_unwind_getipinfo=no ;;
-      *) have_unwind_getipinfo=yes ;;
-    esac
-
-  fi
-
-  if test x$have_unwind_getipinfo = xyes; then
-
-$as_echo "#define HAVE_GETIPINFO 1" >>confdefs.h
-
-  fi
-
-
 cat >confcache <<\_ACEOF
 # This file is a shell script that caches the results of configure
 # tests run on this system so they can be shared between configure
Index: libgfortran/configure.ac
===================================================================
--- libgfortran/configure.ac	(revision 226823)
+++ libgfortran/configure.ac	(working copy)
@@ -287,7 +287,6 @@ if test "x${with_newlib}" = "xyes"; then
    AC_DEFINE(HAVE_GMTIME_R, 1, [Define if you have gmtime_r.])
    AC_DEFINE(HAVE_STRNLEN, 1, [Define if you have strnlen.])
    AC_DEFINE(HAVE_STRNDUP, 1, [Define if you have strndup.])
-   AC_DEFINE(HAVE_STRTOK_R, 1, [Define if you have strtok_r.])
 
    # At some point, we should differentiate between architectures
    # like x86, which have long double versions, and alpha/powerpc/etc.,
@@ -298,11 +297,11 @@ if test "x${with_newlib}" = "xyes"; then
 else
    AC_CHECK_FUNCS_ONCE(getrusage times mkstemp strtof strtold snprintf \
    ftruncate chsize chdir getlogin gethostname kill link symlink sleep ttyname \
-   alarm access fork execl wait setmode execve pipe dup2 close fcntl \
+   alarm access fork execl setmode close fcntl \
    strcasestr getrlimit gettimeofday stat fstat lstat getpwuid vsnprintf dup \
    getcwd localtime_r gmtime_r getpwuid_r ttyname_r clock_gettime \
    readlink getgid getpid getppid getuid geteuid umask getegid \
-   secure_getenv __secure_getenv mkostemp strnlen strndup strtok_r newlocale \
+   secure_getenv __secure_getenv mkostemp strnlen strndup newlocale \
    freelocale uselocale strerror_l)
 fi
 
@@ -610,9 +609,6 @@ LIBGFOR_CHECK_UNLINK_OPEN_FILE
 # Check whether line terminator is LF or CRLF
 LIBGFOR_CHECK_CRLF
 
-# Check whether we have _Unwind_GetIPInfo for backtrace
-GCC_CHECK_UNWIND_GETIPINFO
-
 AC_CACHE_SAVE
 
 if test ${multilib} = yes; then
Index: libgfortran/libgfortran.h
===================================================================
--- libgfortran/libgfortran.h	(revision 226823)
+++ libgfortran/libgfortran.h	(working copy)
@@ -649,16 +649,11 @@ internal_proto(get_args);
 extern void store_exe_path (const char *);
 export_proto(store_exe_path);
 
-extern char * full_exe_path (void);
-internal_proto(full_exe_path);
-
-extern void find_addr2line (void);
-internal_proto(find_addr2line);
-
 /* backtrace.c */
 
-extern void backtrace (void);
-iexport_proto(backtrace);
+extern void show_backtrace (int);
+internal_proto(show_backtrace);
+
 
 /* error.c */
 
Index: libgfortran/runtime/backtrace.c
===================================================================
--- libgfortran/runtime/backtrace.c	(revision 226823)
+++ libgfortran/runtime/backtrace.c	(working copy)
@@ -31,249 +31,122 @@ see the files COPYING3 and COPYING.RUNTI
 #include <unistd.h>
 #endif
 
-#ifdef HAVE_SYS_WAIT_H
-#include <sys/wait.h>
-#endif
+#include "backtrace-supported.h"
+#include "backtrace.h"
 
-#include <limits.h>
 
-#include "unwind.h"
+/* Store our own state while backtracing.  */
+struct mystate
+{
+  int try_simple;
+  int frame;
+};
 
 
-/* Macros for common sets of capabilities: can we fork and exec, and
-   can we use pipes to communicate with the subprocess.  */
-#define CAN_FORK (defined(HAVE_FORK) && defined(HAVE_EXECVE) \
-		  && defined(HAVE_WAIT))
-#define CAN_PIPE (CAN_FORK && defined(HAVE_PIPE) \
-		  && defined(HAVE_DUP2) && defined(HAVE_CLOSE))
+/* Does a function name have "_gfortran_" or "_gfortrani_" prefix, possibly
+   with additional underscore(s) at the beginning?  Cannot use strncmp()
+   because we might be called from a signal handler.  */
 
-#ifndef PATH_MAX
-#define PATH_MAX 4096
-#endif
+static int
+has_gfortran_prefix (const char *s)
+{
+  if (!s)
+    return 0;
 
+  while (*s == '_')
+    s++;
 
-/* GDB style #NUM index for each stack frame.  */
+  return (s[0] == 'g' && s[1] == 'f' && s[2] == 'o' && s[3] == 'r'
+	  && s[4] == 't' && s[5] == 'r' && s[6] == 'a' && s[7] == 'n'
+	  && (s[8] == '_' || (s[8] == 'i' && s[9] == '_')));
+}
 
-static void 
-bt_header (int num)
+static void
+error_callback (void *data, const char *msg, int errnum)
 {
-  st_printf ("#%d  ", num);
-}
+  struct mystate *state = (struct mystate *) data;
+  if (errnum < 0)
+    {
+      state->try_simple = 1;
+      return;
+    }
 
+  estr_write ("\nSomething went wrong while printing the backtrace: ");
+  estr_write (msg);
+  estr_write ("\n");
+}
 
-/* fgets()-like function that reads a line from a fd, without
-   needing to malloc() a buffer, and does not use locks, hence should
-   be async-signal-safe.  */
+static int
+simple_callback (void *data, uintptr_t pc)
+{
+  struct mystate *state = (struct mystate *) data;
+  st_printf ("#%d  0x%lx\n", state->frame, (unsigned long) pc);
+  (state->frame)++;
+  return 0;
+}
 
-static char *
-fd_gets (char *s, int size, int fd)
+static int
+full_callback (void *data, uintptr_t pc, const char *filename,
+	       int lineno, const char *function)
 {
-  for (int i = 0; i < size; i++)
-    {
-      char c;
-      ssize_t nread = read (fd, &c, 1);
-      if (nread == 1)
-	{
-	  s[i] = c;
-	  if (c == '\n')
-	    {
-	      if (i + 1 < size)
-		s[i+1] = '\0';
-	      else
-		s[i] = '\0';
-	      break;
-	    }
-	}
-      else
-	{
-	  s[i] = '\0';
-	  if (i == 0)
-	    return NULL;
-	  break;
-	}
-    }
-  return s;
+  struct mystate *state = (struct mystate *) data;
+
+  if (has_gfortran_prefix (function))
+    return 0;
+
+  st_printf ("#%d  0x%lx %s\n", state->frame,
+	     (unsigned long) pc, function == NULL ? "???" : function);
+  if (filename || lineno != 0)
+    st_printf ("\t%s:%d\n", filename == NULL ? "???" : filename, lineno);
+  (state->frame)++;
+
+  if (function != NULL && strcmp (function, "main") == 0)
+    return 1;
+
+  return 0;
 }
 
 
-extern char *addr2line_path;
+/* Display the backtrace.  */
 
-/* Struct containing backtrace state.  */
-typedef struct
+void
+show_backtrace (int in_signal_handler)
 {
-  int frame_number;
-  int direct_output;
-  int outfd;
-  int infd;
-  int error;
-}
-bt_state;
-
-static _Unwind_Reason_Code
-trace_function (struct _Unwind_Context *context, void *state_ptr)
-{
-  bt_state* state = (bt_state*) state_ptr;
-  _Unwind_Ptr ip;
-#ifdef HAVE_GETIPINFO
-  int ip_before_insn = 0;
-  ip = _Unwind_GetIPInfo (context, &ip_before_insn);
-  
-  /* If the unwinder gave us a 'return' address, roll it back a little
-     to ensure we get the correct line number for the call itself.  */
-  if (! ip_before_insn)
-    --ip;
-#else  
-  ip = _Unwind_GetIP (context);
-#endif
+  struct backtrace_state *lbstate;
+  struct mystate state = { 0, 0 };
+ 
+  lbstate = backtrace_create_state (NULL, 1, error_callback, NULL);
 
-  if (state->direct_output)
+  if (!BACKTRACE_SUPPORTED || (in_signal_handler && BACKTRACE_USES_MALLOC))
     {
-      bt_header(state->frame_number);
-      st_printf ("%p\n", (void*) ip);
+      /* If symbolic backtrace is not supported on this target, or would
+	 require malloc() and we are in a signal handler, go with a
+	 simple backtrace.  */
+
+      backtrace_simple (lbstate, 0, simple_callback, error_callback, &state);
     }
   else
     {
-      char addr_buf[GFC_XTOA_BUF_SIZE], func[1024], file[PATH_MAX];
-      char *p;
-      const char* addr = gfc_xtoa (ip, addr_buf, sizeof (addr_buf));
-      write (state->outfd, addr, strlen (addr));
-      write (state->outfd, "\n", 1);
-
-      if (! fd_gets (func, sizeof(func), state->infd))
-	{
-	  state->error = 1;
-	  goto done;
-	}
-      if (! fd_gets (file, sizeof(file), state->infd))
-	{
-	  state->error = 1;
-	  goto done;
-	}
-	    
-	for (p = func; *p != '\n' && *p != '\r'; p++)
-	  ;
-	*p = '\0';
-	
-	/* _start is a setup routine that calls main(), and main() is
-	   the frontend routine that calls some setup stuff and then
-	   calls MAIN__, so at this point we should stop.  */
-	if (strcmp (func, "_start") == 0 || strcmp (func, "main") == 0)
-	  return _URC_END_OF_STACK;
-	
-	bt_header (state->frame_number);
-	estr_write ("0x");
-	estr_write (addr);
-
-	if (func[0] != '?' && func[1] != '?')
-	  {
-	    estr_write (" in ");
-	    estr_write (func);
-	  }
-	
-	if (strncmp (file, "??", 2) == 0)
-	  estr_write ("\n");
-	else
-	  {
-	    estr_write (" at ");
-	    estr_write (file);
-	  }
+      /* libbacktrace uses mmap, which is safe to call from a signal handler
+	 (in practice, if not in theory).  Thus we can generate a symbolic
+	 backtrace, if debug symbols are available.  */
+
+      backtrace_full (lbstate, 0, full_callback, error_callback, &state);
+      if (state.try_simple)
+	backtrace_simple (lbstate, 0, simple_callback, error_callback, &state);
     }
+}
 
- done:
 
-  state->frame_number++;
-  
-  return _URC_NO_REASON;
-}
 
+/* Function called by the front-end translating the BACKTRACE intrinsic.  */
 
-/* Display the backtrace.  */
+extern void backtrace (void);
+export_proto (backtrace);
 
 void
 backtrace (void)
 {
-  bt_state state;
-  state.frame_number = 0;
-  state.error = 0;
-
-#if CAN_PIPE
-
-  if (addr2line_path == NULL)
-    goto fallback_noerr;
-
-  /* We attempt to extract file and line information from addr2line.  */
-  do
-  {
-    /* Local variables.  */
-    int f[2], pid, inp[2];
-
-    /* Don't output an error message if something goes wrong, we'll simply
-       fall back to printing the addresses.  */
-    if (pipe (f) != 0)
-      break;
-    if (pipe (inp) != 0)
-      break;
-    if ((pid = fork ()) == -1)
-      break;
-
-    if (pid == 0)
-      {
-	/* Child process.  */
-#define NUM_FIXEDARGS 7
-	char *arg[NUM_FIXEDARGS];
-	char *newenv[] = { NULL };
-
-	close (f[0]);
-
-	close (inp[1]);
-	if (dup2 (inp[0], STDIN_FILENO) == -1)
-	  _exit (1);
-	close (inp[0]);
-
-	close (STDERR_FILENO);
-
-	if (dup2 (f[1], STDOUT_FILENO) == -1)
-	  _exit (1);
-	close (f[1]);
-
-	arg[0] = addr2line_path;
-	arg[1] = (char *) "-e";
-	arg[2] = full_exe_path ();
-	arg[3] = (char *) "-f";
-	arg[4] = (char *) "-s";
-	arg[5] = (char *) "-C";
-	arg[6] = NULL;
-	execve (addr2line_path, arg, newenv);
-	_exit (1);
-#undef NUM_FIXEDARGS
-      }
-
-    /* Father process.  */
-    close (f[1]);
-    close (inp[0]);
-
-    state.outfd = inp[1];
-    state.infd = f[0];
-    state.direct_output = 0;
-    _Unwind_Backtrace (trace_function, &state);
-    if (state.error)
-      goto fallback;
-    close (inp[1]);
-    close (f[0]);
-    wait (NULL);
-    return;
-
-fallback:
-    estr_write ("** Something went wrong while running addr2line. **\n"
-		"** Falling back to a simpler backtrace scheme. **\n");
-  }
-  while (0);
-
-fallback_noerr:
-#endif /* CAN_PIPE */
-
-  /* Fallback to the simple backtrace without addr2line.  */
-  state.direct_output = 1;
-  _Unwind_Backtrace (trace_function, &state);
+  show_backtrace (0);
 }
-iexport(backtrace);
+
Index: libgfortran/runtime/compile_options.c
===================================================================
--- libgfortran/runtime/compile_options.c	(revision 226823)
+++ libgfortran/runtime/compile_options.c	(working copy)
@@ -30,7 +30,7 @@ see the files COPYING3 and COPYING.RUNTI
 compile_options_t compile_options;
 
 #ifndef LIBGFOR_MINIMAL
-volatile sig_atomic_t fatal_error_in_progress = 0;
+static volatile sig_atomic_t fatal_error_in_progress = 0;
 
 
 /* Helper function for backtrace_handler to write information about the
@@ -126,7 +126,7 @@ backtrace_handler (int signum)
 
   show_signal (signum);
   estr_write ("\nBacktrace for this error:\n");
-  backtrace ();
+  show_backtrace (1);
 
   /* Now reraise the signal.  We reactivate the signal's
      default handling, which is to terminate the process.
@@ -136,16 +136,6 @@ backtrace_handler (int signum)
   signal (signum, SIG_DFL);
   raise (signum);
 }
-
-
-/* Helper function for set_options because we need to access the
-   global variable options which is not seen in set_options.  */
-static void
-maybe_find_addr2line (void)
-{
-  if (options.backtrace == -1)
-    find_addr2line ();
-}
 #endif
 
 /* Set the usual compile-time options.  */
@@ -211,8 +201,6 @@ set_options (int num, int options[])
 #if defined(SIGXFSZ)
       signal (SIGXFSZ, backtrace_handler);
 #endif
-
-      maybe_find_addr2line ();
     }
 #endif
 }
Index: libgfortran/runtime/error.c
===================================================================
--- libgfortran/runtime/error.c	(revision 226823)
+++ libgfortran/runtime/error.c	(working copy)
@@ -173,7 +173,7 @@ sys_abort (void)
       || (options.backtrace == -1 && compile_options.backtrace == 1))
     {
       estr_write ("\nProgram aborted. Backtrace:\n");
-      backtrace ();
+      show_backtrace (0);
       signal (SIGABRT, SIG_DFL);
     }
 
Index: libgfortran/runtime/main.c
===================================================================
--- libgfortran/runtime/main.c	(revision 226823)
+++ libgfortran/runtime/main.c	(working copy)
@@ -70,162 +70,13 @@ determine_endianness (void)
 static int argc_save;
 static char **argv_save;
 
-static const char *exe_path;
-static bool please_free_exe_path_when_done;
 
-/* Save the path under which the program was called, for use in the
-   backtrace routines.  */
 void
-store_exe_path (const char * argv0)
+store_exe_path (const char * argv0 __attribute__ ((unused)))
 {
-#ifndef DIR_SEPARATOR   
-#define DIR_SEPARATOR '/'
-#endif
-
-  char *cwd, *path;
-
-  /* This can only happen if store_exe_path is called multiple times.  */
-  if (please_free_exe_path_when_done)
-    free ((char *) exe_path);
-
-  /* Reading the /proc/self/exe symlink is Linux-specific(?), but if
-     it works it gives the correct answer.  */
-#ifdef HAVE_READLINK
-  ssize_t len, psize = 256;
-  while (1)
-    {
-      path = xmalloc (psize);
-      len = readlink ("/proc/self/exe", path, psize);
-      if (len < 0)
-	{
-	  free (path);
-	  break;
-	}
-      else if (len < psize)
-	{
-	  path[len] = '\0';
-	  exe_path = strdup (path);
-	  free (path);
-	  please_free_exe_path_when_done = true;
-	  return;
-	}
-      /* The remaining option is len == psize.  */
-      free (path);
-      psize *= 4;
-    }
-#endif
-
-  /* If the path is absolute or on a simulator where argv is not set.  */
-#ifdef __MINGW32__
-  if (argv0 == NULL
-      || ('A' <= argv0[0] && argv0[0] <= 'Z' && argv0[1] == ':')
-      || ('a' <= argv0[0] && argv0[0] <= 'z' && argv0[1] == ':')
-      || (argv0[0] == '/' && argv0[1] == '/')
-      || (argv0[0] == '\\' && argv0[1] == '\\'))
-#else
-  if (argv0 == NULL || argv0[0] == DIR_SEPARATOR)
-#endif
-    {
-      exe_path = argv0;
-      please_free_exe_path_when_done = false;
-      return;
-    }
-
-#ifdef HAVE_GETCWD
-  size_t cwdsize = 256;
-  while (1)
-    {
-      cwd = xmalloc (cwdsize);
-      if (getcwd (cwd, cwdsize))
-	break;
-      else if (errno == ERANGE)
-	{
-	  free (cwd);
-	  cwdsize *= 4;
-	}
-      else
-	{
-	  free (cwd);
-	  cwd = NULL;
-	  break;
-	}
-    }
-#else
-  cwd = NULL;
-#endif
-
-  if (!cwd)
-    {
-      exe_path = argv0;
-      please_free_exe_path_when_done = false;
-      return;
-    }
-
-  /* exe_path will be cwd + "/" + argv[0] + "\0".  This will not work
-     if the executable is not in the cwd, but at this point we're out
-     of better ideas.  */
-  size_t pathlen = strlen (cwd) + 1 + strlen (argv0) + 1;
-  path = xmalloc (pathlen);
-  snprintf (path, pathlen, "%s%c%s", cwd, DIR_SEPARATOR, argv0);
-  free (cwd);
-  exe_path = path;
-  please_free_exe_path_when_done = true;
-}
-
-
-/* Return the full path of the executable.  */
-char *
-full_exe_path (void)
-{
-  return (char *) exe_path;
-}
-
-
-#ifndef HAVE_STRTOK_R
-static char*
-gfstrtok_r (char *str, const char *delim, 
-	    char **saveptr __attribute__ ((unused)))
-{
-  return strtok (str, delim);
-}
-#define strtok_r gfstrtok_r
-#endif
-
-char *addr2line_path;
-
-/* Find addr2line and store the path.  */
-
-void
-find_addr2line (void)
-{
-#ifdef HAVE_ACCESS
-#define A2L_LEN 11
-  char *path = secure_getenv ("PATH");
-  if (!path)
-    return;
-  char *tp = strdup (path);
-  if (!tp)
-    return;
-  size_t n = strlen (path);
-  char *ap = xmalloc (n + A2L_LEN);
-  char *saveptr;
-  for (char *str = tp;; str = NULL)
-    {
-      char *token = strtok_r (str, ":", &saveptr);
-      if (!token)
-	break;
-      size_t toklen = strlen (token);
-      memcpy (ap, token, toklen);
-      memcpy (ap + toklen, "/addr2line", A2L_LEN);
-      if (access (ap, R_OK|X_OK) == 0)
-	{
-	  addr2line_path = strdup (ap);
-	  break;
-	}
-    }
-  free (tp);
-  free (ap);
-#endif
+  /* This function is now useless, but is retained due to ABI compatibility.
+    Remove when bumping the library ABI.  */
+  ;
 }
 
 
@@ -236,7 +87,6 @@ set_args (int argc, char **argv)
 {
   argc_save = argc;
   argv_save = argv;
-  store_exe_path (argv[0]);
 }
 iexport(set_args);
 
@@ -279,9 +129,6 @@ init (void)
   /* if (argc > 1 && strcmp(argv[1], "--resume") == 0) resume();  */
 #endif
 
-  if (options.backtrace == 1)
-    find_addr2line ();
-
   random_seed_i4 (NULL, NULL, NULL);
 }
 
@@ -292,9 +139,4 @@ static void __attribute__((destructor))
 cleanup (void)
 {
   close_units ();
-  
-  if (please_free_exe_path_when_done)
-    free ((char *) exe_path);
-
-  free (addr2line_path);
 }
Index: libgfortran/runtime/minimal.c
===================================================================
--- libgfortran/runtime/minimal.c	(revision 226823)
+++ libgfortran/runtime/minimal.c	(working copy)
@@ -53,8 +53,6 @@ int big_endian = 0;
 static int argc_save;
 static char **argv_save;
 
-static const char *exe_path;
-
 /* recursion_check()-- It's possible for additional errors to occur
  * during fatal error processing.  We detect this condition here and
  * exit with code 4 immediately. */
@@ -163,14 +161,6 @@ internal_error (st_parameter_common *cmp
 }
 
 
-/* Return the full path of the executable.  */
-char *
-full_exe_path (void)
-{
-  return (char *) exe_path;
-}
-
-
 /* Set the saved values of the command line arguments.  */
 
 void
@@ -178,7 +168,6 @@ set_args (int argc, char **argv)
 {
   argc_save = argc;
   argv_save = argv;
-  exe_path = argv[0];
 }
 iexport(set_args);
 
Index: gcc/testsuite/gfortran.dg/backtrace_1.f90
===================================================================
--- gcc/testsuite/gfortran.dg/backtrace_1.f90	(revision 0)
+++ gcc/testsuite/gfortran.dg/backtrace_1.f90	(working copy)
@@ -0,0 +1,10 @@
+! { dg-do run }
+! 
+! Check that BACKTRACE is available on all targets. We cannot actually
+! check its output, but we should at least be able to call it, then exit
+! normally.
+!
+program test
+  call backtrace
+  stop
+end program test

^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2015-08-27 13:48 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-08-14 13:19 [patch,libgfortran,toplevel] Use libbacktrace in libgfortran Uros Bizjak
2015-08-14 14:31 ` FX
2015-08-23 20:14   ` Janne Blomqvist
2015-08-23 20:59     ` FX
2015-08-23 21:27       ` Janne Blomqvist
2015-08-24  7:15         ` FX
2015-08-24 16:00   ` Fix libbacktrace -fPIC breakage from "Use libbacktrace in libgfortran" Hans-Peter Nilsson
2015-08-24 16:08     ` FX
2015-08-24 16:44       ` Hans-Peter Nilsson
2015-08-24 18:42         ` FX
2015-08-25  3:29         ` Ian Lance Taylor
2015-08-25 13:25           ` Ulrich Weigand
2015-08-25 17:09             ` Hans-Peter Nilsson
2015-08-25 17:57               ` Ulrich Weigand
2015-08-26  0:09                 ` Hans-Peter Nilsson
2015-08-26 12:17                   ` Ulrich Weigand
2015-08-26 12:34                     ` Hans-Peter Nilsson
2015-08-26 15:37                       ` [PATCH] Fix and simplify (Re: Fix libbacktrace -fPIC breakage from "Use libbacktrace in libgfortran") Ulrich Weigand
2015-08-27  4:02                         ` Ian Lance Taylor
2015-08-27 13:38                           ` Ulrich Weigand
2015-08-27 14:02                             ` Ian Lance Taylor
2015-08-24 16:04   ` Fix libbacktrace -fPIC breakage from "Use libbacktrace in libgfortran" Hans-Peter Nilsson
  -- strict thread matches above, loose matches on Subject: below --
2015-08-14  9:23 [patch,libgfortran,toplevel] Use libbacktrace in libgfortran FX
2015-08-14 14:19 ` Ian Lance Taylor

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).