diff options
Diffstat (limited to 'glib/gerror.c')
-rw-r--r-- | glib/gerror.c | 256 |
1 files changed, 256 insertions, 0 deletions
diff --git a/glib/gerror.c b/glib/gerror.c new file mode 100644 index 0000000000..96e1013e94 --- /dev/null +++ b/glib/gerror.c @@ -0,0 +1,256 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <signal.h> +#include <stdarg.h> +#include <stdio.h> +#include <sys/time.h> +#include <sys/times.h> +#include <sys/types.h> + +#include <time.h> +#include <unistd.h> +#include "glib.h" + +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif /* HAVE_SYS_SELECT_H */ + +#ifdef STDC_HEADERS +#include <string.h> /* for bzero on BSD systems */ +#endif + +#define INTERACTIVE 0 +#define STACK_TRACE 1 + + +#ifndef NO_FD_SET +# define SELECT_MASK fd_set +#else +# ifndef _AIX + typedef long fd_mask; +# endif +# if defined(_IBMR2) +# define SELECT_MASK void +# else +# define SELECT_MASK int +# endif +#endif + + +static int do_query (char *prompt); +static void debug (char *progname, int method); +static void stack_trace (char **); +static void stack_trace_sigchld (int); + + +static int stack_trace_done; + +void +g_debug (char *progname) +{ + char buf[32]; + + fprintf (stdout, "[n]othing, [e]xit, [s]tack trace, [a]ttach to process: "); + fflush (stdout); + + fgets (buf, 32, stdin); + if (strcmp (buf, "n\n") == 0) + return; + else if (strcmp (buf, "s\n") == 0) + debug (progname, STACK_TRACE); + else if (strcmp (buf, "a\n") == 0) + debug (progname, INTERACTIVE); + else + exit (0); +} + +void +g_attach_process (char *progname, int query) +{ + if (!query || do_query ("attach to process")) + debug (progname, INTERACTIVE); +} + +void +g_stack_trace (char *progname, int query) +{ + if (!query || do_query ("print stack trace")) + debug (progname, STACK_TRACE); +} + +static int +do_query (char *prompt) +{ + char buf[32]; + + fprintf (stdout, "%s (y/n) ", prompt); + fflush (stdout); + + fgets (buf, 32, stdin); + if ((strcmp (buf, "yes\n") == 0) || + (strcmp (buf, "y\n") == 0) || + (strcmp (buf, "YES\n") == 0) || + (strcmp (buf, "Y\n") == 0)) + return TRUE; + + return FALSE; +} + +static void +debug (char *progname, + int method) +{ + pid_t pid; + char buf[16]; + char *args[4] = { "gdb", NULL, NULL, NULL }; + volatile int x; + + sprintf (buf, "%d", (int) getpid ()); + + args[1] = progname; + args[2] = buf; + + switch (method) + { + case INTERACTIVE: + fprintf (stdout, "pid: %s\n", buf); + break; + case STACK_TRACE: + pid = fork (); + if (pid == 0) + { + stack_trace (args); + _exit (0); + } + else if (pid == (pid_t) -1) + { + perror ("could not fork"); + return; + } + break; + } + + x = 1; + while (x) + ; +} + +static void +stack_trace (char **args) +{ + pid_t pid; + int in_fd[2]; + int out_fd[2]; + SELECT_MASK fdset; + SELECT_MASK readset; + struct timeval tv; + int sel, index, state; + char buffer[256]; + char c; + + stack_trace_done = 0; + signal (SIGCHLD, stack_trace_sigchld); + + if ((pipe (in_fd) == -1) || (pipe (out_fd) == -1)) + { + perror ("could open pipe"); + _exit (0); + } + + pid = fork (); + if (pid == 0) + { + close (0); dup (in_fd[0]); /* set the stdin to the in pipe */ + close (1); dup (out_fd[1]); /* set the stdout to the out pipe */ + close (2); dup (out_fd[1]); /* set the stderr to the out pipe */ + + execvp (args[0], args); /* exec gdb */ + perror ("exec failed"); + _exit (0); + } + else if (pid == (pid_t) -1) + { + perror ("could not fork"); + _exit (0); + } + + FD_ZERO (&fdset); + FD_SET (out_fd[0], &fdset); + + write (in_fd[1], "backtrace\n", 10); + write (in_fd[1], "p x = 0\n", 8); + write (in_fd[1], "quit\n", 5); + + index = 0; + state = 0; + + while (1) + { + readset = fdset; + tv.tv_sec = 1; + tv.tv_usec = 0; + + sel = select (FD_SETSIZE, &readset, NULL, NULL, &tv); + if (sel == -1) + break; + + if ((sel > 0) && (FD_ISSET (out_fd[0], &readset))) + { + if (read (out_fd[0], &c, 1)) + { + switch (state) + { + case 0: + if (c == '#') + { + state = 1; + index = 0; + buffer[index++] = c; + } + break; + case 1: + buffer[index++] = c; + if ((c == '\n') || (c == '\r')) + { + buffer[index] = 0; + fprintf (stdout, "%s", buffer); + state = 0; + index = 0; + } + break; + default: + break; + } + } + } + else if (stack_trace_done) + break; + } + + close (in_fd[0]); + close (in_fd[1]); + close (out_fd[0]); + close (out_fd[1]); + _exit (0); +} + +static void +stack_trace_sigchld (int signum) +{ + stack_trace_done = 1; +} |