Merge branch 'fix-gdbus-unix-addresses-test' into 'master'
[glib.git] / glib / gbacktrace.c
blobe83079985ea88c534868fcf6bae0158faebb768c
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
27 * then
30 #include "config.h"
31 #include "glibconfig.h"
33 #include <signal.h>
34 #include <stdarg.h>
35 #include <stdio.h>
36 #include <stdlib.h>
38 #ifdef HAVE_SYS_TIME_H
39 #include <sys/time.h>
40 #endif
41 #include <sys/types.h>
43 #include <time.h>
45 #ifdef G_OS_UNIX
46 #include <unistd.h>
47 #include <sys/wait.h>
48 #ifdef HAVE_SYS_SELECT_H
49 #include <sys/select.h>
50 #endif /* HAVE_SYS_SELECT_H */
51 #endif
53 #include <string.h>
55 #ifdef G_OS_WIN32
56 # define STRICT /* Strict typing, please */
57 # define _WIN32_WINDOWS 0x0401 /* to get IsDebuggerPresent */
58 # include <windows.h>
59 # undef STRICT
60 #else
61 # include <fcntl.h>
62 #endif
64 #include "gbacktrace.h"
66 #include "gtypes.h"
67 #include "gmain.h"
68 #include "gprintfint.h"
69 #include "gutils.h"
71 #ifndef G_OS_WIN32
72 static void stack_trace (const char * const *args);
73 #endif
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;
79 /**
80 * g_on_error_query:
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" -->
93 * #include <glib.h>
95 * static void
96 * log_handler (const gchar *log_domain,
97 * GLogLevelFlags log_level,
98 * const gchar *message,
99 * gpointer user_data)
101 * g_log_default_handler (log_domain, log_level, message, user_data);
103 * g_on_error_query (MY_PROGRAM_NAME);
106 * int
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,
113 * log_handler,
114 * NULL);
115 * ...
116 * ]|
118 * If "[E]xit" is selected, the application terminates with a call
119 * to _exit(0).
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.
129 void
130 g_on_error_query (const gchar *prg_name)
132 #ifndef G_OS_WIN32
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";
136 gchar buf[16];
138 if (!prg_name)
139 prg_name = g_get_prgname ();
141 retry:
143 if (prg_name)
144 _g_fprintf (stdout,
145 "%s (pid:%u): %s%s%s: ",
146 prg_name,
147 (guint) getpid (),
148 query1,
149 query2,
150 query3);
151 else
152 _g_fprintf (stdout,
153 "(process:%u): %s%s: ",
154 (guint) getpid (),
155 query1,
156 query3);
157 fflush (stdout);
159 if (isatty(0) && isatty(1))
160 fgets (buf, 8, stdin);
161 else
162 strcpy (buf, "E\n");
164 if ((buf[0] == 'E' || buf[0] == 'e')
165 && buf[1] == '\n')
166 _exit (0);
167 else if ((buf[0] == 'P' || buf[0] == 'p')
168 && buf[1] == '\n')
169 return;
170 else if (prg_name
171 && (buf[0] == 'S' || buf[0] == 's')
172 && buf[1] == '\n')
174 g_on_error_stack_trace (prg_name);
175 goto retry;
177 else if ((buf[0] == 'H' || buf[0] == 'h')
178 && buf[1] == '\n')
180 while (glib_on_error_halt)
182 glib_on_error_halt = TRUE;
183 return;
185 else
186 goto retry;
187 #else
188 if (!prg_name)
189 prg_name = g_get_prgname ();
191 MessageBox (NULL, "g_on_error_query called, program terminating",
192 (prg_name && *prg_name) ? prg_name : NULL,
193 MB_OK|MB_ICONERROR);
194 _exit(0);
195 #endif
199 * g_on_error_stack_trace:
200 * @prg_name: the program name, needed by gdb for the "[S]tack trace"
201 * option
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
207 * gdk_init().
209 * This function may cause different actions on non-UNIX platforms.
211 void
212 g_on_error_stack_trace (const gchar *prg_name)
214 #if defined(G_OS_UNIX)
215 pid_t pid;
216 gchar buf[16];
217 const gchar *args[4] = { "gdb", NULL, NULL, NULL };
218 int status;
220 if (!prg_name)
221 return;
223 _g_sprintf (buf, "%u", (guint) getpid ());
225 args[1] = prg_name;
226 args[2] = buf;
228 pid = fork ();
229 if (pid == 0)
231 stack_trace (args);
232 _exit (0);
234 else if (pid == (pid_t) -1)
236 perror ("unable to fork gdb");
237 return;
240 waitpid (pid, &status, 0);
241 #else
242 if (IsDebuggerPresent ())
243 G_BREAKPOINT ();
244 else
245 g_abort ();
246 #endif
249 #ifndef G_OS_WIN32
251 static gboolean stack_trace_done = FALSE;
253 static void
254 stack_trace_sigchld (int signum)
256 stack_trace_done = TRUE;
259 static void
260 stack_trace (const char * const *args)
262 pid_t pid;
263 int in_fd[2];
264 int out_fd[2];
265 fd_set fdset;
266 fd_set readset;
267 struct timeval tv;
268 int sel, idx, state;
269 char buffer[256];
270 char c;
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");
278 _exit (0);
281 pid = fork ();
282 if (pid == 0)
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");
297 _exit (0);
299 else if (pid == (pid_t) -1)
301 perror ("unable to fork");
302 _exit (0);
305 FD_ZERO (&fdset);
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);
312 idx = 0;
313 state = 0;
315 while (1)
317 readset = fdset;
318 tv.tv_sec = 1;
319 tv.tv_usec = 0;
321 sel = select (FD_SETSIZE, &readset, NULL, NULL, &tv);
322 if (sel == -1)
323 break;
325 if ((sel > 0) && (FD_ISSET (out_fd[0], &readset)))
327 if (read (out_fd[0], &c, 1))
329 switch (state)
331 case 0:
332 if (c == '#')
334 state = 1;
335 idx = 0;
336 buffer[idx++] = c;
338 break;
339 case 1:
340 buffer[idx++] = c;
341 if ((c == '\n') || (c == '\r'))
343 buffer[idx] = 0;
344 _g_fprintf (stdout, "%s", buffer);
345 state = 0;
346 idx = 0;
348 break;
349 default:
350 break;
354 else if (stack_trace_done)
355 break;
358 close (in_fd[0]);
359 close (in_fd[1]);
360 close (out_fd[0]);
361 close (out_fd[1]);
362 _exit (0);
365 #endif /* !G_OS_WIN32 */