source: trunk/third/glib2/glib/gbacktrace.c @ 18159

Revision 18159, 6.3 KB checked in by ghudson, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18158, which included commits to RCS files with non-trunk default branches.
Line 
1/* GLIB - Library of useful routines for C programming
2 * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 */
19
20/*
21 * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
22 * file for a list of people on the GLib Team.  See the ChangeLog
23 * files for a list of changes.  These files are distributed with
24 * GLib at ftp://ftp.gtk.org/pub/gtk/.
25 */
26
27/*
28 * MT safe ; except for g_on_error_stack_trace, but who wants thread safety
29 * then
30 */
31
32#include "config.h"
33
34#include <signal.h>
35#include <stdarg.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include "glib.h"
39#include "gprintfint.h"
40
41#ifdef HAVE_SYS_TIME_H
42#include <sys/time.h>
43#endif
44#ifdef HAVE_SYS_TIMES_H
45#include <sys/times.h>
46#endif
47#include <sys/types.h>
48
49#include <time.h>
50#ifdef HAVE_UNISTD_H
51#include <unistd.h>
52#endif
53
54#ifdef HAVE_SYS_SELECT_H
55#include <sys/select.h>
56#endif /* HAVE_SYS_SELECT_H */
57
58#ifdef STDC_HEADERS
59#include <string.h> /* for bzero on BSD systems */
60#endif
61
62#ifdef G_OS_WIN32
63#  define STRICT                /* Strict typing, please */
64#  include <windows.h>
65#  undef STRICT
66#endif
67
68#ifndef NO_FD_SET
69#  define SELECT_MASK fd_set
70#else
71#  if defined(_IBMR2)
72#    define SELECT_MASK void
73#  else
74#    define SELECT_MASK int
75#  endif
76#endif
77
78
79#ifndef G_OS_WIN32
80static void stack_trace (char **args);
81#endif
82
83extern volatile gboolean glib_on_error_halt;
84volatile gboolean glib_on_error_halt = TRUE;
85
86void
87g_on_error_query (const gchar *prg_name)
88{
89#ifndef G_OS_WIN32
90  static const gchar *query1 = "[E]xit, [H]alt";
91  static const gchar *query2 = ", show [S]tack trace";
92  static const gchar *query3 = " or [P]roceed";
93  gchar buf[16];
94
95  if (!prg_name)
96    prg_name = g_get_prgname ();
97 
98 retry:
99 
100  if (prg_name)
101    _g_fprintf (stdout,
102                "%s (pid:%u): %s%s%s: ",
103                prg_name,
104                (guint) getpid (),
105                query1,
106                query2,
107                query3);
108  else
109    _g_fprintf (stdout,
110                "(process:%u): %s%s: ",
111                (guint) getpid (),
112                query1,
113                query3);
114  fflush (stdout);
115 
116  if (isatty(0) && isatty(1))
117    fgets (buf, 8, stdin);
118  else
119    strcpy (buf, "E\n");
120
121  if ((buf[0] == 'E' || buf[0] == 'e')
122      && buf[1] == '\n')
123    _exit (0);
124  else if ((buf[0] == 'P' || buf[0] == 'p')
125           && buf[1] == '\n')
126    return;
127  else if (prg_name
128           && (buf[0] == 'S' || buf[0] == 's')
129           && buf[1] == '\n')
130    {
131      g_on_error_stack_trace (prg_name);
132      goto retry;
133    }
134  else if ((buf[0] == 'H' || buf[0] == 'h')
135           && buf[1] == '\n')
136    {
137      while (glib_on_error_halt)
138        ;
139      glib_on_error_halt = TRUE;
140      return;
141    }
142  else
143    goto retry;
144#else
145  if (!prg_name)
146    prg_name = g_get_prgname ();
147 
148  MessageBox (NULL, "g_on_error_query called, program terminating",
149              (prg_name && *prg_name) ? prg_name : NULL,
150              MB_OK|MB_ICONERROR);
151  _exit(0);
152#endif
153}
154
155void
156g_on_error_stack_trace (const gchar *prg_name)
157{
158#ifdef G_OS_UNIX
159  pid_t pid;
160  gchar buf[16];
161  gchar *args[4] = { "gdb", NULL, NULL, NULL };
162
163  if (!prg_name)
164    return;
165
166  _g_sprintf (buf, "%u", (guint) getpid ());
167
168  args[1] = (gchar*) prg_name;
169  args[2] = buf;
170
171  pid = fork ();
172  if (pid == 0)
173    {
174      stack_trace (args);
175      _exit (0);
176    }
177  else if (pid == (pid_t) -1)
178    {
179      perror ("unable to fork gdb");
180      return;
181    }
182 
183  while (glib_on_error_halt)
184    ;
185  glib_on_error_halt = TRUE;
186#else
187  abort ();
188#endif
189}
190
191#ifndef G_OS_WIN32
192
193static gboolean stack_trace_done = FALSE;
194
195static void
196stack_trace_sigchld (int signum)
197{
198  stack_trace_done = TRUE;
199}
200
201static void
202stack_trace (char **args)
203{
204  pid_t pid;
205  int in_fd[2];
206  int out_fd[2];
207  SELECT_MASK fdset;
208  SELECT_MASK readset;
209  struct timeval tv;
210  int sel, index, state;
211  char buffer[256];
212  char c;
213
214  stack_trace_done = FALSE;
215  signal (SIGCHLD, stack_trace_sigchld);
216
217  if ((pipe (in_fd) == -1) || (pipe (out_fd) == -1))
218    {
219      perror ("unable to open pipe");
220      _exit (0);
221    }
222
223  pid = fork ();
224  if (pid == 0)
225    {
226      close (0); dup (in_fd[0]);   /* set the stdin to the in pipe */
227      close (1); dup (out_fd[1]);  /* set the stdout to the out pipe */
228      close (2); dup (out_fd[1]);  /* set the stderr to the out pipe */
229
230      execvp (args[0], args);      /* exec gdb */
231      perror ("exec failed");
232      _exit (0);
233    }
234  else if (pid == (pid_t) -1)
235    {
236      perror ("unable to fork");
237      _exit (0);
238    }
239
240  FD_ZERO (&fdset);
241  FD_SET (out_fd[0], &fdset);
242
243  write (in_fd[1], "backtrace\n", 10);
244  write (in_fd[1], "p x = 0\n", 8);
245  write (in_fd[1], "quit\n", 5);
246
247  index = 0;
248  state = 0;
249
250  while (1)
251    {
252      readset = fdset;
253      tv.tv_sec = 1;
254      tv.tv_usec = 0;
255
256      sel = select (FD_SETSIZE, &readset, NULL, NULL, &tv);
257      if (sel == -1)
258        break;
259
260      if ((sel > 0) && (FD_ISSET (out_fd[0], &readset)))
261        {
262          if (read (out_fd[0], &c, 1))
263            {
264              switch (state)
265                {
266                case 0:
267                  if (c == '#')
268                    {
269                      state = 1;
270                      index = 0;
271                      buffer[index++] = c;
272                    }
273                  break;
274                case 1:
275                  buffer[index++] = c;
276                  if ((c == '\n') || (c == '\r'))
277                    {
278                      buffer[index] = 0;
279                      _g_fprintf (stdout, "%s", buffer);
280                      state = 0;
281                      index = 0;
282                    }
283                  break;
284                default:
285                  break;
286                }
287            }
288        }
289      else if (stack_trace_done)
290        break;
291    }
292
293  close (in_fd[0]);
294  close (in_fd[1]);
295  close (out_fd[0]);
296  close (out_fd[1]);
297  _exit (0);
298}
299
300#endif /* !G_OS_WIN32 */
Note: See TracBrowser for help on using the repository browser.