new function g_dataset_retrive_key. adjusted prealloc sizes, to take up
[platform/upstream/glib.git] / gbacktrace.c
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 Library 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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library 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 #include <signal.h>
20 #include <stdarg.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <sys/time.h>
24 #include <sys/times.h>
25 #include <sys/types.h>
26
27 #include <time.h>
28 #include <unistd.h>
29 #include "glib.h"
30
31 #ifdef HAVE_SYS_SELECT_H
32 #include <sys/select.h>
33 #endif /* HAVE_SYS_SELECT_H */
34
35 #ifdef STDC_HEADERS
36 #include <string.h> /* for bzero on BSD systems */
37 #endif
38
39 #define INTERACTIVE 0
40 #define STACK_TRACE 1
41
42
43 #ifndef NO_FD_SET
44 #  define SELECT_MASK fd_set
45 #else
46 #  ifndef _AIX
47      typedef long fd_mask;
48 #  endif
49 #  if defined(_IBMR2)
50 #    define SELECT_MASK void
51 #  else
52 #    define SELECT_MASK int
53 #  endif
54 #endif
55
56
57 static int  do_query (char *prompt);
58 static void debug (const gchar *progname, int method);
59 static void stack_trace (char **);
60 static void stack_trace_sigchld (int);
61
62
63 static int stack_trace_done;
64
65 void
66 g_debug (const gchar *progname)
67 {
68   char buf[32];
69
70   fprintf (stdout, "[n]othing, [e]xit, [s]tack trace, [a]ttach to process: ");
71   fflush (stdout);
72
73   fgets (buf, 32, stdin);
74   if (strcmp (buf, "n\n") == 0)
75     return;
76   else if (strcmp (buf, "s\n") == 0)
77     debug (progname, STACK_TRACE);
78   else if (strcmp (buf, "a\n") == 0)
79     debug (progname, INTERACTIVE);
80   else
81     exit (0);
82 }
83
84 void
85 g_attach_process (const gchar *progname,
86                   int          query)
87 {
88   if (!query || do_query ("attach to process"))
89     debug (progname, INTERACTIVE);
90 }
91
92 void
93 g_stack_trace (const gchar *progname,
94                int          query)
95 {
96   if (!query || do_query ("print stack trace"))
97     debug (progname, STACK_TRACE);
98 }
99
100 static int
101 do_query (char *prompt)
102 {
103   char buf[32];
104
105   fprintf (stdout, "%s (y/n) ", prompt);
106   fflush (stdout);
107
108   fgets (buf, 32, stdin);
109   if ((strcmp (buf, "yes\n") == 0) ||
110       (strcmp (buf, "y\n") == 0) ||
111       (strcmp (buf, "YES\n") == 0) ||
112       (strcmp (buf, "Y\n") == 0))
113     return TRUE;
114
115   return FALSE;
116 }
117
118 static void
119 debug (const char *progname,
120        int   method)
121 {
122   pid_t pid;
123   char buf[16];
124   char *args[4] = { "gdb", NULL, NULL, NULL };
125   volatile int x;
126
127   sprintf (buf, "%d", (int) getpid ());
128
129   args[1] = (gchar*) progname;
130   args[2] = buf;
131
132   switch (method)
133     {
134     case INTERACTIVE:
135       fprintf (stdout, "pid: %s\n", buf);
136       break;
137     case STACK_TRACE:
138       pid = fork ();
139       if (pid == 0)
140         {
141           stack_trace (args);
142           _exit (0);
143         }
144       else if (pid == (pid_t) -1)
145         {
146           perror ("could not fork");
147           return;
148         }
149       break;
150     }
151
152   x = 1;
153   while (x)
154     ;
155 }
156
157 static void
158 stack_trace (char **args)
159 {
160   pid_t pid;
161   int in_fd[2];
162   int out_fd[2];
163   SELECT_MASK fdset;
164   SELECT_MASK readset;
165   struct timeval tv;
166   int sel, index, state;
167   char buffer[256];
168   char c;
169
170   stack_trace_done = 0;
171   signal (SIGCHLD, stack_trace_sigchld);
172
173   if ((pipe (in_fd) == -1) || (pipe (out_fd) == -1))
174     {
175       perror ("could open pipe");
176       _exit (0);
177     }
178
179   pid = fork ();
180   if (pid == 0)
181     {
182       close (0); dup (in_fd[0]);   /* set the stdin to the in pipe */
183       close (1); dup (out_fd[1]);  /* set the stdout to the out pipe */
184       close (2); dup (out_fd[1]);  /* set the stderr to the out pipe */
185
186       execvp (args[0], args);      /* exec gdb */
187       perror ("exec failed");
188       _exit (0);
189     }
190   else if (pid == (pid_t) -1)
191     {
192       perror ("could not fork");
193       _exit (0);
194     }
195
196   FD_ZERO (&fdset);
197   FD_SET (out_fd[0], &fdset);
198
199   write (in_fd[1], "backtrace\n", 10);
200   write (in_fd[1], "p x = 0\n", 8);
201   write (in_fd[1], "quit\n", 5);
202
203   index = 0;
204   state = 0;
205
206   while (1)
207     {
208       readset = fdset;
209       tv.tv_sec = 1;
210       tv.tv_usec = 0;
211
212       sel = select (FD_SETSIZE, &readset, NULL, NULL, &tv);
213       if (sel == -1)
214         break;
215
216       if ((sel > 0) && (FD_ISSET (out_fd[0], &readset)))
217         {
218           if (read (out_fd[0], &c, 1))
219             {
220               switch (state)
221                 {
222                 case 0:
223                   if (c == '#')
224                     {
225                       state = 1;
226                       index = 0;
227                       buffer[index++] = c;
228                     }
229                   break;
230                 case 1:
231                   buffer[index++] = c;
232                   if ((c == '\n') || (c == '\r'))
233                     {
234                       buffer[index] = 0;
235                       fprintf (stdout, "%s", buffer);
236                       state = 0;
237                       index = 0;
238                     }
239                   break;
240                 default:
241                   break;
242                 }
243             }
244         }
245       else if (stack_trace_done)
246         break;
247     }
248
249   close (in_fd[0]);
250   close (in_fd[1]);
251   close (out_fd[0]);
252   close (out_fd[1]);
253   _exit (0);
254 }
255
256 static void
257 stack_trace_sigchld (int signum)
258 {
259   stack_trace_done = 1;
260 }