backtrace.c (1515B)
1 /* Copyright ©2008-2010 Kris Maglione <maglione.k at Gmail> 2 * See LICENSE file for license details. 3 */ 4 #include <sys/types.h> 5 #include <sys/stat.h> 6 #include <sys/wait.h> 7 #include <fcntl.h> 8 #include <signal.h> 9 10 #include <bio.h> 11 #include <plan9.h> 12 #undef nelem 13 #include <stuff/util.h> 14 #include "debug.h" 15 16 #ifdef __linux__ 17 # define PROGTXT "exe" 18 #else 19 # define PROGTXT "file" 20 #endif 21 22 static void 23 _backtrace(int pid, char *btarg) { 24 char *proc, *spid, *gdbcmd; 25 int fd[3], p[2]; 26 int status, cmdfd; 27 28 gdbcmd = estrdup("/tmp/gdbcmd.XXXXXX"); 29 if(pipe(p) < 0) 30 goto done; 31 closeexec(p[0]); 32 33 cmdfd = mkstemp(gdbcmd); 34 if(cmdfd < 0) 35 goto done; 36 37 fprint(cmdfd, "bt %s\n", btarg); 38 fprint(cmdfd, "detach\n"); 39 close(cmdfd); 40 41 fd[0] = open("/dev/null", O_RDONLY); 42 fd[1] = p[1]; 43 fd[2] = dup(2); 44 45 proc = sxprint("/proc/%d/" PROGTXT, pid); 46 spid = sxprint("%d", pid); 47 if(spawn3l(fd, "gdb", "gdb", "-batch", "-x", gdbcmd, proc, spid, nil) < 0) { 48 unlink(gdbcmd); 49 goto done; 50 } 51 52 Biobuf bp; 53 char *s; 54 55 Binit(&bp, p[0], OREAD); 56 while((s = Brdstr(&bp, '\n', 1))) { 57 Dprint(DStack, "%s\n", s); 58 free(s); 59 } 60 unlink(gdbcmd); 61 62 done: 63 free(gdbcmd); 64 kill(pid, SIGKILL); 65 waitpid(pid, &status, 0); 66 } 67 68 void 69 backtrace(char *btarg) { 70 int pid; 71 72 /* Fork so we can backtrace the child. Keep this stack 73 * frame minimal, so the trace is fairly clean. 74 */ 75 Debug(DStack) 76 switch(pid = fork()) { 77 case -1: 78 return; 79 case 0: 80 kill(getpid(), SIGSTOP); 81 _exit(0); 82 default: 83 _backtrace(pid, btarg); 84 break; 85 } 86 87 }