mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-02-25 21:46:10 +08:00
PR 46686 Implement backtrace with _Unwind_Backtrace from libgcc.
2011-11-09 Janne Blomqvist <jb@gcc.gnu.org> PR fortran/46686 * configure.ac: Don't check execinfo.h, backtrace, backtrace_symbols_fd. Check execve instead of execvp. Call GCC_CHECK_UNWIND_GETIPINFO. * runtime/backtrace.c: Don't include unused headers, include limits.h and unwind.h. (CAN_FORK): Check execve instead of execvp. (GLIBC_BACKTRACE): Remove. (bt_header): Conform to gdb backtrace format. (struct bt_state): New struct. (trace_function): New function. (show_backtrace): Use _Unwind_Backtrace from libgcc instead of glibc backtrace functions. * Makefile.in: Regenerated. * aclocal.m4: Regenerated. * config.h.in: Regenerated. * configure: Regenerated. From-SVN: r181209
This commit is contained in:
parent
560bb0136f
commit
1ff101ff12
@ -1,3 +1,23 @@
|
||||
2011-11-09 Janne Blomqvist <jb@gcc.gnu.org>
|
||||
|
||||
PR fortran/46686
|
||||
* configure.ac: Don't check execinfo.h, backtrace,
|
||||
backtrace_symbols_fd. Check execve instead of execvp. Call
|
||||
GCC_CHECK_UNWIND_GETIPINFO.
|
||||
* runtime/backtrace.c: Don't include unused headers, include
|
||||
limits.h and unwind.h.
|
||||
(CAN_FORK): Check execve instead of execvp.
|
||||
(GLIBC_BACKTRACE): Remove.
|
||||
(bt_header): Conform to gdb backtrace format.
|
||||
(struct bt_state): New struct.
|
||||
(trace_function): New function.
|
||||
(show_backtrace): Use _Unwind_Backtrace from libgcc instead of
|
||||
glibc backtrace functions.
|
||||
* Makefile.in: Regenerated.
|
||||
* aclocal.m4: Regenerated.
|
||||
* config.h.in: Regenerated.
|
||||
* configure: Regenerated.
|
||||
|
||||
2011-11-09 Janne Blomqvist <jb@gcc.gnu.org>
|
||||
|
||||
PR libfortran/50016
|
||||
|
@ -51,6 +51,7 @@ am__aclocal_m4_deps = $(top_srcdir)/../config/depstand.m4 \
|
||||
$(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 \
|
||||
|
1
libgfortran/aclocal.m4
vendored
1
libgfortran/aclocal.m4
vendored
@ -974,6 +974,7 @@ 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])
|
||||
|
@ -81,12 +81,6 @@
|
||||
/* Define to 1 if the target supports __attribute__((visibility(...))). */
|
||||
#undef HAVE_ATTRIBUTE_VISIBILITY
|
||||
|
||||
/* Define to 1 if you have the `backtrace' function. */
|
||||
#undef HAVE_BACKTRACE
|
||||
|
||||
/* Define to 1 if you have the `backtrace_symbols_fd' function. */
|
||||
#undef HAVE_BACKTRACE_SYMBOLS_FD
|
||||
|
||||
/* Define if powf is broken. */
|
||||
#undef HAVE_BROKEN_POWF
|
||||
|
||||
@ -348,14 +342,11 @@
|
||||
/* libm includes erfl */
|
||||
#undef HAVE_ERFL
|
||||
|
||||
/* Define to 1 if you have the <execinfo.h> header file. */
|
||||
#undef HAVE_EXECINFO_H
|
||||
|
||||
/* Define to 1 if you have the `execl' function. */
|
||||
#undef HAVE_EXECL
|
||||
|
||||
/* Define to 1 if you have the `execvp' function. */
|
||||
#undef HAVE_EXECVP
|
||||
/* Define to 1 if you have the `execve' function. */
|
||||
#undef HAVE_EXECVE
|
||||
|
||||
/* libm includes exp */
|
||||
#undef HAVE_EXP
|
||||
@ -453,6 +444,9 @@
|
||||
/* 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
|
||||
|
||||
|
63
libgfortran/configure
vendored
63
libgfortran/configure
vendored
@ -766,6 +766,7 @@ with_gnu_ld
|
||||
enable_libtool_lock
|
||||
enable_largefile
|
||||
enable_libquadmath_support
|
||||
with_system_libunwind
|
||||
'
|
||||
ac_precious_vars='build_alias
|
||||
host_alias
|
||||
@ -1424,6 +1425,7 @@ 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
|
||||
@ -12112,7 +12114,7 @@ else
|
||||
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
|
||||
@ -12218,7 +12220,7 @@ else
|
||||
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
|
||||
@ -15919,7 +15921,7 @@ fi
|
||||
|
||||
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"
|
||||
@ -16419,7 +16421,7 @@ _ACEOF
|
||||
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"
|
||||
@ -16472,21 +16474,6 @@ fi
|
||||
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; }
|
||||
@ -25880,6 +25867,44 @@ $as_echo "#define HAVE_CRLF 1" >>confdefs.h
|
||||
|
||||
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
|
||||
|
@ -249,7 +249,7 @@ AC_HEADER_TIME
|
||||
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)
|
||||
|
||||
@ -261,14 +261,11 @@ AC_CHECK_MEMBERS([struct stat.st_rdev])
|
||||
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])])
|
||||
@ -559,6 +556,9 @@ 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
|
||||
|
@ -26,46 +26,38 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
|
||||
@ -106,24 +98,105 @@ fd_gets (char *s, int size, int fd)
|
||||
|
||||
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
|
||||
|
||||
@ -134,9 +207,7 @@ show_backtrace (void)
|
||||
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. */
|
||||
@ -182,139 +253,27 @@ show_backtrace (void)
|
||||
/* 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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user