enable_libtool_lock
enable_largefile
enable_libquadmath_support
+with_system_libunwind
'
ac_precious_vars='build_alias
host_alias
--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
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 12115 "configure"
+#line 12117 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 12221 "configure"
+#line 12223 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
done
-for ac_header in fenv.h fptrap.h float.h execinfo.h pwd.h
+for ac_header in fenv.h fptrap.h float.h pwd.h
do :
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
fi
done
-for ac_func in wait setmode execvp pipe dup2 close fdopen strcasestr getrlimit
+for ac_func in wait setmode execve pipe dup2 close fdopen strcasestr getrlimit
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
done
-# Check for glibc backtrace functions
-for ac_func in backtrace backtrace_symbols_fd
-do :
- as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
-eval as_val=\$$as_ac_var
- if test "x$as_val" = x""yes; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
-
-fi
-done
-
-
# Check libc for getgid, getpid, getuid
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for getgid in -lc" >&5
$as_echo_n "checking for getgid in -lc... " >&6; }
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
AC_HAVE_HEADERS(stdio.h stdlib.h string.h unistd.h signal.h stdarg.h)
AC_CHECK_HEADERS(time.h sys/time.h sys/times.h sys/resource.h)
AC_CHECK_HEADERS(sys/types.h sys/stat.h sys/wait.h floatingpoint.h ieeefp.h)
-AC_CHECK_HEADERS(fenv.h fptrap.h float.h execinfo.h pwd.h)
+AC_CHECK_HEADERS(fenv.h fptrap.h float.h pwd.h)
AC_CHECK_HEADER([complex.h],[AC_DEFINE([HAVE_COMPLEX_H], [1], [complex.h exists])])
GCC_HEADER_STDINT(gstdint.h)
AC_CHECK_FUNCS(getrusage times mkstemp strtof strtold snprintf ftruncate chsize)
AC_CHECK_FUNCS(chdir strerror getlogin gethostname kill link symlink perror)
AC_CHECK_FUNCS(sleep time ttyname signal alarm clock access fork execl)
-AC_CHECK_FUNCS(wait setmode execvp pipe dup2 close fdopen strcasestr getrlimit)
+AC_CHECK_FUNCS(wait setmode execve pipe dup2 close fdopen strcasestr getrlimit)
AC_CHECK_FUNCS(gettimeofday stat fstat lstat getpwuid vsnprintf dup getcwd)
AC_CHECK_FUNCS(localtime_r gmtime_r strerror_r getpwuid_r ttyname_r)
AC_CHECK_FUNCS(clock_gettime strftime readlink)
-# Check for glibc backtrace functions
-AC_CHECK_FUNCS(backtrace backtrace_symbols_fd)
-
# Check libc for getgid, getpid, getuid
AC_CHECK_LIB([c],[getgid],[AC_DEFINE([HAVE_GETGID],[1],[libc includes getgid])])
AC_CHECK_LIB([c],[getpid],[AC_DEFINE([HAVE_GETPID],[1],[libc includes getpid])])
# 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
#include <string.h>
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-
-#ifdef HAVE_INTTYPES_H
-#include <inttypes.h>
-#endif
-
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
-#ifdef HAVE_EXECINFO_H
-#include <execinfo.h>
-#endif
-
#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
-#include <ctype.h>
+#include <limits.h>
+
+#include "unwind.h"
/* Macros for common sets of capabilities: can we fork and exec, can
we use glibc-style backtrace functions, and can we use pipes. */
-#define CAN_FORK (defined(HAVE_FORK) && defined(HAVE_EXECVP) \
+#define CAN_FORK (defined(HAVE_FORK) && defined(HAVE_EXECVE) \
&& defined(HAVE_WAIT))
-#define GLIBC_BACKTRACE (defined(HAVE_BACKTRACE) \
- && defined(HAVE_BACKTRACE_SYMBOLS_FD))
#define CAN_PIPE (CAN_FORK && defined(HAVE_PIPE) \
&& defined(HAVE_DUP2) && defined(HAVE_FDOPEN) \
&& defined(HAVE_CLOSE))
+#ifndef PATH_MAX
+#define PATH_MAX 4096
+#endif
+
/* GDB style #NUM index for each stack frame. */
static void
bt_header (int num)
{
- st_printf (" #%d ", num);
+ st_printf ("#%d ", num);
}
extern char *addr2line_path;
+/* Struct containing backtrace state. */
+typedef struct
+{
+ int frame_number;
+ int direct_output;
+ int outfd;
+ int infd;
+ int error;
+}
+bt_state;
-/* show_backtrace displays the backtrace, currently obtained by means of
- the glibc backtrace* functions. */
+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
+
+ if (state->direct_output)
+ {
+ bt_header(state->frame_number);
+ st_printf ("%p\n", (void*) ip);
+ }
+ 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);
+ }
+ }
+
+ done:
+
+ state->frame_number++;
+
+ return _URC_NO_REASON;
+}
+
+
+/* Display the backtrace. */
void
show_backtrace (void)
{
-#if GLIBC_BACKTRACE
+ bt_state state;
+ state.frame_number = 0;
+ state.error = 0;
-#define DEPTH 50
-#define BUFSIZE 1024
-
- void *trace[DEPTH];
- int depth;
-
- depth = backtrace (trace, DEPTH);
- if (depth <= 0)
- return;
+ estr_write ("\nA fatal error occurred! Backtrace for this error:\n");
#if CAN_PIPE
do
{
/* Local variables. */
- int f[2], pid, bt[2], inp[2];
- char addr_buf[GFC_XTOA_BUF_SIZE], func[BUFSIZE], file[BUFSIZE];
- char *p;
+ int f[2], pid, inp[2];
/* Don't output an error message if something goes wrong, we'll simply
fall back to the pstack and glibc backtraces. */
/* Father process. */
close (f[1]);
close (inp[0]);
- if (pipe (bt) != 0)
- break;
- backtrace_symbols_fd (trace, depth, bt[1]);
- close (bt[1]);
-
- estr_write ("\nBacktrace for this error:\n");
- for (int j = 0; j < depth; j++)
- {
- const char *addr = gfc_xtoa
- ((GFC_UINTEGER_LARGEST) (intptr_t) trace[j],
- addr_buf, sizeof (addr_buf));
-
- write (inp[1], addr, strlen (addr));
- write (inp[1], "\n", 1);
-
- if (! fd_gets (func, sizeof(func), f[0]))
- goto fallback;
- if (! fd_gets (file, sizeof(file), f[0]))
- goto fallback;
-
- for (p = func; *p != '\n' && *p != '\r'; p++)
- ;
- *p = '\0';
-
- /* If we only have the address, use the glibc backtrace. */
- if (func[0] == '?' && func[1] == '?' && file[0] == '?'
- && file[1] == '?')
- {
- bt_header (j);
- while (1)
- {
- char bc;
- ssize_t nread = read (bt[0], &bc, 1);
- if (nread != 1 || bc == '\n')
- break;
- write (STDERR_FILENO, &bc, 1);
- }
- estr_write ("\n");
- continue;
- }
- else
- {
- /* Forward to the next entry in the backtrace. */
- while (1)
- {
- char bc;
- ssize_t nread = read (bt[0], &bc, 1);
- if (nread != 1 || bc == '\n')
- break;
- }
- }
- /* _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)
- break;
-
- bt_header (j);
- estr_write (full_exe_path ());
- estr_write ("[0x");
- estr_write (addr);
- estr_write ("] in ");
- estr_write (func);
-
- if (strncmp (file, "??", 2) == 0)
- estr_write ("\n");
- else
- {
- estr_write (" at ");
- estr_write (file);
- }
- } /* Loop over each hex address. */
+ 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 (bt[0]);
wait (NULL);
return;
fallback:
estr_write ("** Something went wrong while running addr2line. **\n"
- "** Falling back to a simpler backtrace scheme. **\n");
+ "** Falling back to a simpler backtrace scheme. **\n");
}
while (0);
-#undef DEPTH
-#undef BUFSIZE
-
#endif /* CAN_PIPE */
fallback_noerr:
- /* Fallback to the glibc backtrace. */
- estr_write ("\nBacktrace for this error:\n");
- backtrace_symbols_fd (trace, depth, STDERR_FILENO);
- return;
-
-#elif defined(CAN_FORK) && defined(HAVE_GETPPID)
- /* Try to call pstack. */
- do
- {
- /* Local variables. */
- int pid;
-
- /* Don't output an error message if something goes wrong, we'll simply
- fall back to the pstack and glibc backtraces. */
- if ((pid = fork ()) == -1)
- break;
-
- if (pid == 0)
- {
- /* Child process. */
-#define NUM_ARGS 2
- char *arg[NUM_ARGS+1];
- char buf[20];
-
- estr_write ("\nBacktrace for this error:\n");
- arg[0] = (char *) "pstack";
- snprintf (buf, sizeof(buf), "%d", (int) getppid ());
- arg[1] = buf;
- arg[2] = NULL;
- execvp (arg[0], arg);
-#undef NUM_ARGS
-
- /* pstack didn't work. */
- estr_write (" unable to produce a backtrace, sorry!\n");
- _exit (1);
- }
-
- /* Father process. */
- wait (NULL);
- return;
- }
- while(0);
-#else
- estr_write ("\nBacktrace not yet available on this platform, sorry!\n");
-#endif
+ /* Fallback to the simple backtrace without addr2line. */
+ state.direct_output = 1;
+ _Unwind_Backtrace (trace_function, &state);
}