summaryrefslogtreecommitdiff
path: root/os/backtrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'os/backtrace.c')
-rw-r--r--os/backtrace.c54
1 files changed, 45 insertions, 9 deletions
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