~ubuntu-branches/ubuntu/utopic/glib2.0/utopic

« back to all changes in this revision

Viewing changes to glib/gbacktrace.c

Tags: upstream-2.12.12
ImportĀ upstreamĀ versionĀ 2.12.12

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
#ifdef HAVE_SYS_WAIT_H
 
49
#include <sys/wait.h>
 
50
#endif
 
51
 
 
52
#include <time.h>
 
53
#ifdef HAVE_UNISTD_H
 
54
#include <unistd.h>
 
55
#endif
 
56
 
 
57
#ifdef HAVE_SYS_SELECT_H
 
58
#include <sys/select.h>
 
59
#endif /* HAVE_SYS_SELECT_H */
 
60
 
 
61
#ifdef STDC_HEADERS
 
62
#include <string.h> /* for bzero on BSD systems */
 
63
#endif
 
64
 
 
65
#ifdef G_OS_WIN32
 
66
#  define STRICT                /* Strict typing, please */
 
67
#  define _WIN32_WINDOWS 0x0401 /* to get IsDebuggerPresent */
 
68
#  include <windows.h>
 
69
#  undef STRICT
 
70
#endif
 
71
 
 
72
#ifndef NO_FD_SET
 
73
#  define SELECT_MASK fd_set
 
74
#else
 
75
#  if defined(_IBMR2)
 
76
#    define SELECT_MASK void
 
77
#  else
 
78
#    define SELECT_MASK int
 
79
#  endif
 
80
#endif
 
81
 
 
82
#include "galias.h"
 
83
 
 
84
#ifndef G_OS_WIN32
 
85
static void stack_trace (char **args);
 
86
#endif
 
87
 
 
88
extern volatile gboolean glib_on_error_halt;
 
89
volatile gboolean glib_on_error_halt = TRUE;
 
90
 
 
91
void
 
92
g_on_error_query (const gchar *prg_name)
 
93
{
 
94
#ifndef G_OS_WIN32
 
95
  static const gchar * const query1 = "[E]xit, [H]alt";
 
96
  static const gchar * const query2 = ", show [S]tack trace";
 
97
  static const gchar * const query3 = " or [P]roceed";
 
98
  gchar buf[16];
 
99
 
 
100
  if (!prg_name)
 
101
    prg_name = g_get_prgname ();
 
102
  
 
103
 retry:
 
104
  
 
105
  if (prg_name)
 
106
    _g_fprintf (stdout,
 
107
                "%s (pid:%u): %s%s%s: ",
 
108
                prg_name,
 
109
                (guint) getpid (),
 
110
                query1,
 
111
                query2,
 
112
                query3);
 
113
  else
 
114
    _g_fprintf (stdout,
 
115
                "(process:%u): %s%s: ",
 
116
                (guint) getpid (),
 
117
                query1,
 
118
                query3);
 
119
  fflush (stdout);
 
120
  
 
121
  if (isatty(0) && isatty(1))
 
122
    fgets (buf, 8, stdin); 
 
123
  else
 
124
    strcpy (buf, "E\n");
 
125
 
 
126
  if ((buf[0] == 'E' || buf[0] == 'e')
 
127
      && buf[1] == '\n')
 
128
    _exit (0);
 
129
  else if ((buf[0] == 'P' || buf[0] == 'p')
 
130
           && buf[1] == '\n')
 
131
    return;
 
132
  else if (prg_name
 
133
           && (buf[0] == 'S' || buf[0] == 's')
 
134
           && buf[1] == '\n')
 
135
    {
 
136
      g_on_error_stack_trace (prg_name);
 
137
      goto retry;
 
138
    }
 
139
  else if ((buf[0] == 'H' || buf[0] == 'h')
 
140
           && buf[1] == '\n')
 
141
    {
 
142
      while (glib_on_error_halt)
 
143
        ;
 
144
      glib_on_error_halt = TRUE;
 
145
      return;
 
146
    }
 
147
  else
 
148
    goto retry;
 
149
#else
 
150
  if (!prg_name)
 
151
    prg_name = g_get_prgname ();
 
152
  
 
153
  MessageBox (NULL, "g_on_error_query called, program terminating",
 
154
              (prg_name && *prg_name) ? prg_name : NULL,
 
155
              MB_OK|MB_ICONERROR);
 
156
  _exit(0);
 
157
#endif
 
158
}
 
159
 
 
160
void
 
161
g_on_error_stack_trace (const gchar *prg_name)
 
162
{
 
163
#if defined(G_OS_UNIX) || defined(G_OS_BEOS)
 
164
  pid_t pid;
 
165
  gchar buf[16];
 
166
  gchar *args[4] = { "gdb", NULL, NULL, NULL };
 
167
  int status;
 
168
 
 
169
  if (!prg_name)
 
170
    return;
 
171
 
 
172
  _g_sprintf (buf, "%u", (guint) getpid ());
 
173
 
 
174
  args[1] = (gchar*) prg_name;
 
175
  args[2] = buf;
 
176
 
 
177
  pid = fork ();
 
178
  if (pid == 0)
 
179
    {
 
180
      stack_trace (args);
 
181
      _exit (0);
 
182
    }
 
183
  else if (pid == (pid_t) -1)
 
184
    {
 
185
      perror ("unable to fork gdb");
 
186
      return;
 
187
    }
 
188
 
 
189
  waitpid (pid, &status, 0);
 
190
#else
 
191
  if (IsDebuggerPresent ())
 
192
    G_BREAKPOINT ();
 
193
  else
 
194
    abort ();
 
195
#endif
 
196
}
 
197
 
 
198
#ifndef G_OS_WIN32
 
199
 
 
200
static gboolean stack_trace_done = FALSE;
 
201
 
 
202
static void
 
203
stack_trace_sigchld (int signum)
 
204
{
 
205
  stack_trace_done = TRUE;
 
206
}
 
207
 
 
208
static void
 
209
stack_trace (char **args)
 
210
{
 
211
  pid_t pid;
 
212
  int in_fd[2];
 
213
  int out_fd[2];
 
214
  SELECT_MASK fdset;
 
215
  SELECT_MASK readset;
 
216
  struct timeval tv;
 
217
  int sel, index, state;
 
218
  char buffer[256];
 
219
  char c;
 
220
 
 
221
  stack_trace_done = FALSE;
 
222
  signal (SIGCHLD, stack_trace_sigchld);
 
223
 
 
224
  if ((pipe (in_fd) == -1) || (pipe (out_fd) == -1))
 
225
    {
 
226
      perror ("unable to open pipe");
 
227
      _exit (0);
 
228
    }
 
229
 
 
230
  pid = fork ();
 
231
  if (pid == 0)
 
232
    {
 
233
      close (0); dup (in_fd[0]);   /* set the stdin to the in pipe */
 
234
      close (1); dup (out_fd[1]);  /* set the stdout to the out pipe */
 
235
      close (2); dup (out_fd[1]);  /* set the stderr to the out pipe */
 
236
 
 
237
      execvp (args[0], args);      /* exec gdb */
 
238
      perror ("exec failed");
 
239
      _exit (0);
 
240
    }
 
241
  else if (pid == (pid_t) -1)
 
242
    {
 
243
      perror ("unable to fork");
 
244
      _exit (0);
 
245
    }
 
246
 
 
247
  FD_ZERO (&fdset);
 
248
  FD_SET (out_fd[0], &fdset);
 
249
 
 
250
  write (in_fd[1], "backtrace\n", 10);
 
251
  write (in_fd[1], "p x = 0\n", 8);
 
252
  write (in_fd[1], "quit\n", 5);
 
253
 
 
254
  index = 0;
 
255
  state = 0;
 
256
 
 
257
  while (1)
 
258
    {
 
259
      readset = fdset;
 
260
      tv.tv_sec = 1;
 
261
      tv.tv_usec = 0;
 
262
 
 
263
      sel = select (FD_SETSIZE, &readset, NULL, NULL, &tv);
 
264
      if (sel == -1)
 
265
        break;
 
266
 
 
267
      if ((sel > 0) && (FD_ISSET (out_fd[0], &readset)))
 
268
        {
 
269
          if (read (out_fd[0], &c, 1))
 
270
            {
 
271
              switch (state)
 
272
                {
 
273
                case 0:
 
274
                  if (c == '#')
 
275
                    {
 
276
                      state = 1;
 
277
                      index = 0;
 
278
                      buffer[index++] = c;
 
279
                    }
 
280
                  break;
 
281
                case 1:
 
282
                  buffer[index++] = c;
 
283
                  if ((c == '\n') || (c == '\r'))
 
284
                    {
 
285
                      buffer[index] = 0;
 
286
                      _g_fprintf (stdout, "%s", buffer);
 
287
                      state = 0;
 
288
                      index = 0;
 
289
                    }
 
290
                  break;
 
291
                default:
 
292
                  break;
 
293
                }
 
294
            }
 
295
        }
 
296
      else if (stack_trace_done)
 
297
        break;
 
298
    }
 
299
 
 
300
  close (in_fd[0]);
 
301
  close (in_fd[1]);
 
302
  close (out_fd[0]);
 
303
  close (out_fd[1]);
 
304
  _exit (0);
 
305
}
 
306
 
 
307
#endif /* !G_OS_WIN32 */
 
308
 
 
309
#define __G_BACKTRACE_C__
 
310
#include "galiasdef.c"