This calls /usr/bin/xorg-backtrace to create reasonable commented backtraces
with gdb. On errors it falls back to the generic method.

Signed-off-by: Matthias Hopf <[email protected]>
---
 os/backtrace.c |   82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 82 insertions(+), 0 deletions(-)

diff --git a/os/backtrace.c b/os/backtrace.c
index 7ca6dab..1e3201a 100644
--- a/os/backtrace.c
+++ b/os/backtrace.c
@@ -28,6 +28,81 @@
 #include "os.h"
 #include "misc.h"
 
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+#define XORG_BACKTRACE "/usr/bin/xorg-backtrace"
+
+/* Call gdb to create reasonable(!) backtrace. Returns 0 if successfull. */
+static int xorg_backtrace_gdb(void)
+{
+    static const char *xorg_backtrace = XORG_BACKTRACE;
+    char  pidstr[12];
+    char  fdname[] = "/tmp/xorg.XXXXXX";
+    char  buf[256];
+    pid_t pid;
+    int   fd, status = -1, ret;
+    FILE *f;
+
+    if (access (xorg_backtrace, R_OK | X_OK) != 0) {
+       ErrorF ("%s not found, using internal backtrace system\n", 
xorg_backtrace);
+       return 1;
+    }
+    if ( (fd = mkstemp (fdname)) == -1) {
+       ErrorF ("xorg_backtrace_gdb internal error 1\n");
+       return 1;
+    }
+    unlink (fdname);
+    snprintf (pidstr, 12, "%d", getpid());
+
+    switch ( (pid = fork()) ) {
+    case 0:
+       close (0);
+       close (1);
+       close (2);
+       dup2  (fd, 1);
+       dup2  (fd, 2);
+       close (fd);
+       execl (xorg_backtrace, xorg_backtrace, pidstr, NULL);
+       exit  (-1);
+    case -1:
+       close (fd);
+       return 1;
+    }
+
+    while (waitpid (pid, &status, 0) == -1 && errno == EINTR)
+       ;
+    if (WIFEXITED (status) && WEXITSTATUS (status) == 0)
+       ret = 0;
+    else {
+       ErrorF ("%s failed with returncode %d\n", xorg_backtrace, WEXITSTATUS 
(status));
+       ret = 1;
+    }
+
+    lseek (fd, 0, SEEK_SET);
+    if (! (f = fdopen (fd, "r"))) {
+       ErrorF ("xorg_backtrace_gdb internal error 2\n");
+       close (fd);
+       return 1;
+    }
+    status = 0;
+    while (fgets (buf, 256, f)) {
+       status++;
+       ErrorF("%s", buf);
+    }
+    fclose (f);
+    if (status < 10 && ret == 0) {
+       ErrorF ("%s only produced %d lines of output\n", xorg_backtrace, 
status);
+       return 1;
+    }
+
+    return ret;
+}
+
 #ifdef HAVE_BACKTRACE
 #ifndef _GNU_SOURCE
 #define _GNU_SOURCE
@@ -41,6 +116,10 @@ void xorg_backtrace(void)
     const char *mod;
     int size, i;
     Dl_info info;
+
+    if (xorg_backtrace_gdb () == 0)
+       return;
+
     ErrorF("\nBacktrace:\n");
     size = backtrace(array, 64);
     for (i = 0; i < size; i++) {
@@ -182,6 +261,9 @@ static int xorg_backtrace_pstack(void) {
 
 void xorg_backtrace(void) {
 
+    if (xorg_backtrace_gdb () == 0)
+       return;
+
     ErrorF("\nBacktrace:\n");
 
 #  ifdef HAVE_PSTACK
-- 
1.6.0.2

_______________________________________________
[email protected]: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: http://lists.x.org/mailman/listinfo/xorg-devel

Reply via email to