X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=glib%2Fgbacktrace.c;h=c59d18e1fdd192faaaac2b73827715b1981bceab;hb=9f5afe3966d31ef6f1e880d950206a0325e6c777;hp=2615ce2b4923573745b9a64a83bd2e87b0aaec41;hpb=931ea952650b013b834041b91b0c37a748ffd449;p=platform%2Fupstream%2Fglib.git diff --git a/glib/gbacktrace.c b/glib/gbacktrace.c index 2615ce2..c59d18e 100644 --- a/glib/gbacktrace.c +++ b/glib/gbacktrace.c @@ -2,66 +2,76 @@ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public + * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. + * Lesser General Public License for more details. * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . */ -/* - * MT safe ; except for g_on_error_stack_trace, but who wants thread safety +/* + * Modified by the GLib Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GLib Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +/* + * MT safe ; except for g_on_error_stack_trace, but who wants thread safety * then */ -#ifdef HAVE_CONFIG_H -#include -#endif +#include "config.h" +#include "glibconfig.h" #include #include #include #include -#include "glib.h" + #ifdef HAVE_SYS_TIME_H #include #endif -#ifdef HAVE_SYS_TIMES_H -#include -#endif #include #include -#ifdef HAVE_UNISTD_H -#include -#endif +#ifdef G_OS_UNIX +#include +#include #ifdef HAVE_SYS_SELECT_H #include #endif /* HAVE_SYS_SELECT_H */ - -#ifdef STDC_HEADERS -#include /* for bzero on BSD systems */ #endif -#ifdef _MSC_VER -#include /* For _getpid() */ +#include + +#ifdef G_OS_WIN32 +# define STRICT /* Strict typing, please */ +# define _WIN32_WINDOWS 0x0401 /* to get IsDebuggerPresent */ +# include +# undef STRICT +#else +# include #endif +#include "gbacktrace.h" + +#include "gtypes.h" +#include "gmain.h" +#include "gprintfint.h" +#include "gutils.h" + + #ifndef NO_FD_SET # define SELECT_MASK fd_set #else -# ifndef _AIX - typedef long fd_mask; -# endif # if defined(_IBMR2) # define SELECT_MASK void # else @@ -70,79 +80,159 @@ #endif +#ifndef G_OS_WIN32 static void stack_trace (char **args); +#endif -extern volatile gboolean glib_on_error_halt; +/* People want to hit this from their debugger... */ +GLIB_AVAILABLE_IN_ALL volatile gboolean glib_on_error_halt; volatile gboolean glib_on_error_halt = TRUE; +/** + * g_on_error_query: + * @prg_name: the program name, needed by gdb for the "[S]tack trace" + * option. If @prg_name is %NULL, g_get_prgname() is called to get + * the program name (which will work correctly if gdk_init() or + * gtk_init() has been called) + * + * Prompts the user with + * `[E]xit, [H]alt, show [S]tack trace or [P]roceed`. + * This function is intended to be used for debugging use only. + * The following example shows how it can be used together with + * the g_log() functions. + * + * |[ + * #include + * + * static void + * log_handler (const gchar *log_domain, + * GLogLevelFlags log_level, + * const gchar *message, + * gpointer user_data) + * { + * g_log_default_handler (log_domain, log_level, message, user_data); + * + * g_on_error_query (MY_PROGRAM_NAME); + * } + * + * int + * main (int argc, char *argv[]) + * { + * g_log_set_handler (MY_LOG_DOMAIN, + * G_LOG_LEVEL_WARNING | + * G_LOG_LEVEL_ERROR | + * G_LOG_LEVEL_CRITICAL, + * log_handler, + * NULL); + * ... + * ]| + * + * If "[E]xit" is selected, the application terminates with a call + * to _exit(0). + * + * If "[S]tack" trace is selected, g_on_error_stack_trace() is called. + * This invokes gdb, which attaches to the current process and shows + * a stack trace. The prompt is then shown again. + * + * If "[P]roceed" is selected, the function returns. + * + * This function may cause different actions on non-UNIX platforms. + */ void g_on_error_query (const gchar *prg_name) { - static const gchar *query1 = "[E]xit, [H]alt"; - static const gchar *query2 = ", show [S]tack trace"; - static const gchar *query3 = " or [P]roceed"; +#ifndef G_OS_WIN32 + static const gchar * const query1 = "[E]xit, [H]alt"; + static const gchar * const query2 = ", show [S]tack trace"; + static const gchar * const query3 = " or [P]roceed"; gchar buf[16]; if (!prg_name) prg_name = g_get_prgname (); - + retry: - + if (prg_name) - fprintf (stdout, - "%s (pid:%u): %s%s%s: ", - prg_name, - (guint) getpid (), - query1, - query2, - query3); + _g_fprintf (stdout, + "%s (pid:%u): %s%s%s: ", + prg_name, + (guint) getpid (), + query1, + query2, + query3); else - fprintf (stdout, - "(process:%u): %s%s: ", - (guint) getpid (), - query1, - query3); + _g_fprintf (stdout, + "(process:%u): %s%s: ", + (guint) getpid (), + query1, + query3); fflush (stdout); - - fgets (buf, 8, stdin); + + if (isatty(0) && isatty(1)) + fgets (buf, 8, stdin); + else + strcpy (buf, "E\n"); if ((buf[0] == 'E' || buf[0] == 'e') && buf[1] == '\n') _exit (0); else if ((buf[0] == 'P' || buf[0] == 'p') - && buf[1] == '\n') + && buf[1] == '\n') return; else if (prg_name - && (buf[0] == 'S' || buf[0] == 's') - && buf[1] == '\n') + && (buf[0] == 'S' || buf[0] == 's') + && buf[1] == '\n') { g_on_error_stack_trace (prg_name); goto retry; } else if ((buf[0] == 'H' || buf[0] == 'h') - && buf[1] == '\n') + && buf[1] == '\n') { while (glib_on_error_halt) - ; + ; glib_on_error_halt = TRUE; return; } else goto retry; +#else + if (!prg_name) + prg_name = g_get_prgname (); + + MessageBox (NULL, "g_on_error_query called, program terminating", + (prg_name && *prg_name) ? prg_name : NULL, + MB_OK|MB_ICONERROR); + _exit(0); +#endif } +/** + * g_on_error_stack_trace: + * @prg_name: the program name, needed by gdb for the "[S]tack trace" + * option + * + * Invokes gdb, which attaches to the current process and shows a + * stack trace. Called by g_on_error_query() when the "[S]tack trace" + * option is selected. You can get the current process's program name + * with g_get_prgname(), assuming that you have called gtk_init() or + * gdk_init(). + * + * This function may cause different actions on non-UNIX platforms. + */ void g_on_error_stack_trace (const gchar *prg_name) { -#ifndef NATIVE_WIN32 +#if defined(G_OS_UNIX) pid_t pid; gchar buf[16]; gchar *args[4] = { "gdb", NULL, NULL, NULL }; + int status; if (!prg_name) return; - sprintf (buf, "%u", (guint) getpid ()); + _g_sprintf (buf, "%u", (guint) getpid ()); args[1] = (gchar*) prg_name; args[2] = buf; @@ -158,15 +248,18 @@ g_on_error_stack_trace (const gchar *prg_name) perror ("unable to fork gdb"); return; } - - while (glib_on_error_halt) - ; - glib_on_error_halt = TRUE; + + waitpid (pid, &status, 0); #else - abort (); + if (IsDebuggerPresent ()) + G_BREAKPOINT (); + else + abort (); #endif } +#ifndef G_OS_WIN32 + static gboolean stack_trace_done = FALSE; static void @@ -178,14 +271,13 @@ stack_trace_sigchld (int signum) static void stack_trace (char **args) { -#ifndef NATIVE_WIN32 pid_t pid; int in_fd[2]; int out_fd[2]; SELECT_MASK fdset; SELECT_MASK readset; struct timeval tv; - int sel, index, state; + int sel, idx, state; char buffer[256]; char c; @@ -201,12 +293,19 @@ stack_trace (char **args) pid = fork (); if (pid == 0) { + /* Save stderr for printing failure below */ + int old_err = dup (2); + fcntl (old_err, F_SETFD, fcntl (old_err, F_GETFD) | FD_CLOEXEC); + close (0); dup (in_fd[0]); /* set the stdin to the in pipe */ close (1); dup (out_fd[1]); /* set the stdout to the out pipe */ close (2); dup (out_fd[1]); /* set the stderr to the out pipe */ execvp (args[0], args); /* exec gdb */ - perror ("exec failed"); + + /* Print failure to original stderr */ + close (2); dup (old_err); + perror ("exec gdb failed"); _exit (0); } else if (pid == (pid_t) -1) @@ -222,7 +321,7 @@ stack_trace (char **args) write (in_fd[1], "p x = 0\n", 8); write (in_fd[1], "quit\n", 5); - index = 0; + idx = 0; state = 0; while (1) @@ -245,18 +344,18 @@ stack_trace (char **args) if (c == '#') { state = 1; - index = 0; - buffer[index++] = c; + idx = 0; + buffer[idx++] = c; } break; case 1: - buffer[index++] = c; + buffer[idx++] = c; if ((c == '\n') || (c == '\r')) { - buffer[index] = 0; - fprintf (stdout, "%s", buffer); + buffer[idx] = 0; + _g_fprintf (stdout, "%s", buffer); state = 0; - index = 0; + idx = 0; } break; default: @@ -273,7 +372,6 @@ stack_trace (char **args) close (out_fd[0]); close (out_fd[1]); _exit (0); -#else - abort (); -#endif } + +#endif /* !G_OS_WIN32 */