diff options
author | Jon TURNEY <jon.turney@dronecode.org.uk> | 2014-01-01 13:08:53 +0000 |
---|---|---|
committer | Jon TURNEY <jon.turney@dronecode.org.uk> | 2014-01-03 01:50:02 +0000 |
commit | 595ec7000430e71b7a24c703316c943557f0b257 (patch) | |
tree | 509e8b289fb0b7b44d6395bda1c5d22033632dcf /os | |
parent | 8cc917866448076795ea065d3450cfa7324010f6 (diff) |
os: Use an external tool for creating backtraces on crash, if available.
Make the code for fork/exec-ing a helper program to perform a backtrace more
generic, so it can be used to call /usr/bin/xorg-backtrace, a script which
invokes gdb to create reasonable backtraces. On errors it falls back to the
generic method.
v2: disable backtrace code on MinGW
Based on a patch by Matthias Hopf mhopf at suse.de
Signed-off-by: Jon TURNEY <jon.turney@dronecode.org.uk>
Reviewed-by: Yaakov Selkowitz <yselkowitz@users.sourceforge.net>
Diffstat (limited to 'os')
-rw-r--r-- | os/Makefile.am | 2 | ||||
-rw-r--r-- | os/backtrace.c | 54 |
2 files changed, 46 insertions, 10 deletions
diff --git a/os/Makefile.am b/os/Makefile.am index a1bbb4d1e..0b0eb79d1 100644 --- a/os/Makefile.am +++ b/os/Makefile.am @@ -1,6 +1,6 @@ noinst_LTLIBRARIES = libos.la -AM_CFLAGS = $(DIX_CFLAGS) $(SHA1_CFLAGS) +AM_CFLAGS = $(DIX_CFLAGS) $(SHA1_CFLAGS) -DBINDIR=\"$(bindir)\" SECURERPC_SRCS = rpcauth.c XDMCP_SRCS = xdmcp.c diff --git a/os/backtrace.c b/os/backtrace.c index 3d1195b86..3100d1a13 100644 --- a/os/backtrace.c +++ b/os/backtrace.c @@ -222,10 +222,25 @@ xorg_backtrace_frame(uintptr_t pc, int signo, void *arg) } #endif /* HAVE_WALKCONTEXT */ -#ifdef HAVE_PSTACK +#include <sys/types.h> +#if !defined(__WIN32__) || defined(__CYGWIN__) +#include <sys/wait.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +/* + fork/exec a program to create a backtrace + Returns 0 if successful. +*/ static int -xorg_backtrace_pstack(void) +xorg_backtrace_exec_wrapper(const char *path) { +#if defined(WIN32) && !defined(__CYGWIN__) + ErrorFSigSafe("Backtrace not implemented on Windows"); + return -1; +#else pid_t kidpid; int pipefd[2]; @@ -233,7 +248,7 @@ xorg_backtrace_pstack(void) return -1; } - kidpid = fork1(); + kidpid = fork(); if (kidpid == -1) { /* ERROR */ @@ -246,11 +261,13 @@ xorg_backtrace_pstack(void) seteuid(0); close(STDIN_FILENO); close(STDOUT_FILENO); + close(STDERR_FILENO); dup2(pipefd[1], STDOUT_FILENO); - closefrom(STDERR_FILENO); + dup2(pipefd[1], STDERR_FILENO); + close(pipefd[1]); snprintf(parent, sizeof(parent), "%d", getppid()); - execle("/usr/bin/pstack", "pstack", parent, NULL); + execle(path, path, parent, NULL, NULL); exit(1); } else { @@ -269,17 +286,35 @@ xorg_backtrace_pstack(void) btline[bytesread] = 0; ErrorFSigSafe("%s", btline); } - else if ((bytesread < 0) || ((errno != EINTR) && (errno != EAGAIN))) + else if ((bytesread == 0) || + ((errno != EINTR) && (errno != EAGAIN))) done = 1; } close(pipefd[0]); waitpid(kidpid, &kidstat, 0); - if (kidstat != 0) + if (!(WIFEXITED(kidstat) && WEXITSTATUS(kidstat) == 0)) { + ErrorFSigSafe("%s failed with returncode %d\n", path, + WEXITSTATUS(kidstat)); return -1; + } } return 0; +#endif +} + +#ifdef HAVE_PSTACK +static int +xorg_backtrace_pstack(void) +{ + return xorg_backtrace_exec_wrapper("/usr/bin/pstack"); +} +#endif + +static int +xorg_backtrace_script(void) +{ + return xorg_backtrace_exec_wrapper(BINDIR "/xorg-backtrace"); } -#endif /* HAVE_PSTACK */ #if defined(HAVE_PSTACK) || defined(HAVE_WALKCONTEXT) @@ -316,7 +351,8 @@ xorg_backtrace(void) void xorg_backtrace(void) { - return; + if (xorg_backtrace_script() == 0) + return; } #endif |