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"
72 static void stack_trace (const char * const *args
);
75 /* People want to hit this from their debugger... */
76 GLIB_AVAILABLE_IN_ALL
volatile gboolean glib_on_error_halt
;
77 volatile gboolean glib_on_error_halt
= TRUE
;
81 * @prg_name: the program name, needed by gdb for the "[S]tack trace"
82 * option. If @prg_name is %NULL, g_get_prgname() is called to get
83 * the program name (which will work correctly if gdk_init() or
84 * gtk_init() has been called)
86 * Prompts the user with
87 * `[E]xit, [H]alt, show [S]tack trace or [P]roceed`.
88 * This function is intended to be used for debugging use only.
89 * The following example shows how it can be used together with
90 * the g_log() functions.
92 * |[<!-- language="C" -->
96 * log_handler (const gchar *log_domain,
97 * GLogLevelFlags log_level,
98 * const gchar *message,
101 * g_log_default_handler (log_domain, log_level, message, user_data);
103 * g_on_error_query (MY_PROGRAM_NAME);
107 * main (int argc, char *argv[])
109 * g_log_set_handler (MY_LOG_DOMAIN,
110 * G_LOG_LEVEL_WARNING |
111 * G_LOG_LEVEL_ERROR |
112 * G_LOG_LEVEL_CRITICAL,
118 * If "[E]xit" is selected, the application terminates with a call
121 * If "[S]tack" trace is selected, g_on_error_stack_trace() is called.
122 * This invokes gdb, which attaches to the current process and shows
123 * a stack trace. The prompt is then shown again.
125 * If "[P]roceed" is selected, the function returns.
127 * This function may cause different actions on non-UNIX platforms.
130 g_on_error_query (const gchar
*prg_name
)
133 static const gchar
* const query1
= "[E]xit, [H]alt";
134 static const gchar
* const query2
= ", show [S]tack trace";
135 static const gchar
* const query3
= " or [P]roceed";
139 prg_name
= g_get_prgname ();
145 "%s (pid:%u): %s%s%s: ",
153 "(process:%u): %s%s: ",
159 if (isatty(0) && isatty(1))
160 fgets (buf
, 8, stdin
);
164 if ((buf
[0] == 'E' || buf
[0] == 'e')
167 else if ((buf
[0] == 'P' || buf
[0] == 'p')
171 && (buf
[0] == 'S' || buf
[0] == 's')
174 g_on_error_stack_trace (prg_name
);
177 else if ((buf
[0] == 'H' || buf
[0] == 'h')
180 while (glib_on_error_halt
)
182 glib_on_error_halt
= TRUE
;
189 prg_name
= g_get_prgname ();
191 MessageBox (NULL
, "g_on_error_query called, program terminating",
192 (prg_name
&& *prg_name
) ? prg_name
: NULL
,
199 * g_on_error_stack_trace:
200 * @prg_name: the program name, needed by gdb for the "[S]tack trace"
203 * Invokes gdb, which attaches to the current process and shows a
204 * stack trace. Called by g_on_error_query() when the "[S]tack trace"
205 * option is selected. You can get the current process's program name
206 * with g_get_prgname(), assuming that you have called gtk_init() or
209 * This function may cause different actions on non-UNIX platforms.
212 g_on_error_stack_trace (const gchar
*prg_name
)
214 #if defined(G_OS_UNIX)
217 const gchar
*args
[4] = { "gdb", NULL
, NULL
, NULL
};
223 _g_sprintf (buf
, "%u", (guint
) getpid ());
234 else if (pid
== (pid_t
) -1)
236 perror ("unable to fork gdb");
240 waitpid (pid
, &status
, 0);
242 if (IsDebuggerPresent ())
251 static gboolean stack_trace_done
= FALSE
;
254 stack_trace_sigchld (int signum
)
256 stack_trace_done
= TRUE
;
260 stack_trace (const char * const *args
)
272 stack_trace_done
= FALSE
;
273 signal (SIGCHLD
, stack_trace_sigchld
);
275 if ((pipe (in_fd
) == -1) || (pipe (out_fd
) == -1))
277 perror ("unable to open pipe");
284 /* Save stderr for printing failure below */
285 int old_err
= dup (2);
286 fcntl (old_err
, F_SETFD
, fcntl (old_err
, F_GETFD
) | FD_CLOEXEC
);
288 close (0); dup (in_fd
[0]); /* set the stdin to the in pipe */
289 close (1); dup (out_fd
[1]); /* set the stdout to the out pipe */
290 close (2); dup (out_fd
[1]); /* set the stderr to the out pipe */
292 execvp (args
[0], (char **) args
); /* exec gdb */
294 /* Print failure to original stderr */
295 close (2); dup (old_err
);
296 perror ("exec gdb failed");
299 else if (pid
== (pid_t
) -1)
301 perror ("unable to fork");
306 FD_SET (out_fd
[0], &fdset
);
308 write (in_fd
[1], "backtrace\n", 10);
309 write (in_fd
[1], "p x = 0\n", 8);
310 write (in_fd
[1], "quit\n", 5);
321 sel
= select (FD_SETSIZE
, &readset
, NULL
, NULL
, &tv
);
325 if ((sel
> 0) && (FD_ISSET (out_fd
[0], &readset
)))
327 if (read (out_fd
[0], &c
, 1))
341 if ((c
== '\n') || (c
== '\r'))
344 _g_fprintf (stdout
, "%s", buffer
);
354 else if (stack_trace_done
)
365 #endif /* !G_OS_WIN32 */