1 /* GLIB - Library of useful routines for C programming
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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.1 of the License, or (at your option) any later version.
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.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 * Modified by the GLib Team and others 1997-2000. See the AUTHORS
20 * file for a list of people on the GLib Team. See the ChangeLog
21 * files for a list of changes. These files are distributed with
22 * GLib at ftp://ftp.gtk.org/pub/gtk/.
26 * MT safe ; except for g_on_error_stack_trace, but who wants thread safety
31 #include "glibconfig.h"
38 #ifdef HAVE_SYS_TIME_H
41 #include <sys/types.h>
48 #ifdef HAVE_SYS_SELECT_H
49 #include <sys/select.h>
50 #endif /* HAVE_SYS_SELECT_H */
56 # define STRICT /* Strict typing, please */
57 # define _WIN32_WINDOWS 0x0401 /* to get IsDebuggerPresent */
64 #include "gbacktrace.h"
68 #include "gprintfint.h"
73 # define SELECT_MASK fd_set
76 # define SELECT_MASK void
78 # define SELECT_MASK int
84 static void stack_trace (const char * const *args
);
87 /* People want to hit this from their debugger... */
88 GLIB_AVAILABLE_IN_ALL
volatile gboolean glib_on_error_halt
;
89 volatile gboolean glib_on_error_halt
= TRUE
;
93 * @prg_name: the program name, needed by gdb for the "[S]tack trace"
94 * option. If @prg_name is %NULL, g_get_prgname() is called to get
95 * the program name (which will work correctly if gdk_init() or
96 * gtk_init() has been called)
98 * Prompts the user with
99 * `[E]xit, [H]alt, show [S]tack trace or [P]roceed`.
100 * This function is intended to be used for debugging use only.
101 * The following example shows how it can be used together with
102 * the g_log() functions.
104 * |[<!-- language="C" -->
108 * log_handler (const gchar *log_domain,
109 * GLogLevelFlags log_level,
110 * const gchar *message,
111 * gpointer user_data)
113 * g_log_default_handler (log_domain, log_level, message, user_data);
115 * g_on_error_query (MY_PROGRAM_NAME);
119 * main (int argc, char *argv[])
121 * g_log_set_handler (MY_LOG_DOMAIN,
122 * G_LOG_LEVEL_WARNING |
123 * G_LOG_LEVEL_ERROR |
124 * G_LOG_LEVEL_CRITICAL,
130 * If "[E]xit" is selected, the application terminates with a call
133 * If "[S]tack" trace is selected, g_on_error_stack_trace() is called.
134 * This invokes gdb, which attaches to the current process and shows
135 * a stack trace. The prompt is then shown again.
137 * If "[P]roceed" is selected, the function returns.
139 * This function may cause different actions on non-UNIX platforms.
142 g_on_error_query (const gchar
*prg_name
)
145 static const gchar
* const query1
= "[E]xit, [H]alt";
146 static const gchar
* const query2
= ", show [S]tack trace";
147 static const gchar
* const query3
= " or [P]roceed";
151 prg_name
= g_get_prgname ();
157 "%s (pid:%u): %s%s%s: ",
165 "(process:%u): %s%s: ",
171 if (isatty(0) && isatty(1))
172 fgets (buf
, 8, stdin
);
176 if ((buf
[0] == 'E' || buf
[0] == 'e')
179 else if ((buf
[0] == 'P' || buf
[0] == 'p')
183 && (buf
[0] == 'S' || buf
[0] == 's')
186 g_on_error_stack_trace (prg_name
);
189 else if ((buf
[0] == 'H' || buf
[0] == 'h')
192 while (glib_on_error_halt
)
194 glib_on_error_halt
= TRUE
;
201 prg_name
= g_get_prgname ();
203 MessageBox (NULL
, "g_on_error_query called, program terminating",
204 (prg_name
&& *prg_name
) ? prg_name
: NULL
,
211 * g_on_error_stack_trace:
212 * @prg_name: the program name, needed by gdb for the "[S]tack trace"
215 * Invokes gdb, which attaches to the current process and shows a
216 * stack trace. Called by g_on_error_query() when the "[S]tack trace"
217 * option is selected. You can get the current process's program name
218 * with g_get_prgname(), assuming that you have called gtk_init() or
221 * This function may cause different actions on non-UNIX platforms.
224 g_on_error_stack_trace (const gchar
*prg_name
)
226 #if defined(G_OS_UNIX)
229 const gchar
*args
[4] = { "gdb", NULL
, NULL
, NULL
};
235 _g_sprintf (buf
, "%u", (guint
) getpid ());
246 else if (pid
== (pid_t
) -1)
248 perror ("unable to fork gdb");
252 waitpid (pid
, &status
, 0);
254 if (IsDebuggerPresent ())
263 static gboolean stack_trace_done
= FALSE
;
266 stack_trace_sigchld (int signum
)
268 stack_trace_done
= TRUE
;
272 stack_trace (const char * const *args
)
284 stack_trace_done
= FALSE
;
285 signal (SIGCHLD
, stack_trace_sigchld
);
287 if ((pipe (in_fd
) == -1) || (pipe (out_fd
) == -1))
289 perror ("unable to open pipe");
296 /* Save stderr for printing failure below */
297 int old_err
= dup (2);
298 fcntl (old_err
, F_SETFD
, fcntl (old_err
, F_GETFD
) | FD_CLOEXEC
);
300 close (0); dup (in_fd
[0]); /* set the stdin to the in pipe */
301 close (1); dup (out_fd
[1]); /* set the stdout to the out pipe */
302 close (2); dup (out_fd
[1]); /* set the stderr to the out pipe */
304 execvp (args
[0], (char **) args
); /* exec gdb */
306 /* Print failure to original stderr */
307 close (2); dup (old_err
);
308 perror ("exec gdb failed");
311 else if (pid
== (pid_t
) -1)
313 perror ("unable to fork");
318 FD_SET (out_fd
[0], &fdset
);
320 write (in_fd
[1], "backtrace\n", 10);
321 write (in_fd
[1], "p x = 0\n", 8);
322 write (in_fd
[1], "quit\n", 5);
333 sel
= select (FD_SETSIZE
, &readset
, NULL
, NULL
, &tv
);
337 if ((sel
> 0) && (FD_ISSET (out_fd
[0], &readset
)))
339 if (read (out_fd
[0], &c
, 1))
353 if ((c
== '\n') || (c
== '\r'))
356 _g_fprintf (stdout
, "%s", buffer
);
366 else if (stack_trace_done
)
377 #endif /* !G_OS_WIN32 */