OSDN Git Service

dff4466aa56d46bc00f2df32952bcd892d380f94
[pf3gnuchains/gcc-fork.git] / libgfortran / runtime / backtrace.c
1 /* Copyright (C) 2006, 2007, 2009, 2011 Free Software Foundation, Inc.
2    Contributed by François-Xavier Coudert
3
4 This file is part of the GNU Fortran runtime library (libgfortran).
5
6 Libgfortran is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
10
11 Libgfortran is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 Under Section 7 of GPL version 3, you are granted additional
17 permissions described in the GCC Runtime Library Exception, version
18 3.1, as published by the Free Software Foundation.
19
20 You should have received a copy of the GNU General Public License and
21 a copy of the GCC Runtime Library Exception along with this program;
22 see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23 <http://www.gnu.org/licenses/>.  */
24
25 #include "libgfortran.h"
26
27 #include <string.h>
28
29 #ifdef HAVE_STDLIB_H
30 #include <stdlib.h>
31 #endif
32
33 #ifdef HAVE_INTTYPES_H
34 #include <inttypes.h>
35 #endif
36
37 #ifdef HAVE_UNISTD_H
38 #include <unistd.h>
39 #endif
40
41 #ifdef HAVE_EXECINFO_H
42 #include <execinfo.h>
43 #endif
44
45 #ifdef HAVE_SYS_WAIT_H
46 #include <sys/wait.h>
47 #endif
48
49 #include <ctype.h>
50
51
52 /* Macros for common sets of capabilities: can we fork and exec, can
53    we use glibc-style backtrace functions, and can we use pipes.  */
54 #define CAN_FORK (defined(HAVE_FORK) && defined(HAVE_EXECVP) \
55                   && defined(HAVE_WAIT))
56 #define GLIBC_BACKTRACE (defined(HAVE_BACKTRACE) \
57                          && defined(HAVE_BACKTRACE_SYMBOLS_FD))
58 #define CAN_PIPE (CAN_FORK && defined(HAVE_PIPE) \
59                   && defined(HAVE_DUP2) && defined(HAVE_FDOPEN) \
60                   && defined(HAVE_CLOSE))
61
62
63 /* GDB style #NUM index for each stack frame.  */
64
65 static void 
66 bt_header (int num)
67 {
68   st_printf (" #%d  ", num);
69 }
70
71
72 /* fgets()-like function that reads a line from a fd, without
73    needing to malloc() a buffer, and does not use locks, hence should
74    be async-signal-safe.  */
75
76 static char *
77 fd_gets (char *s, int size, int fd)
78 {
79   for (int i = 0; i < size; i++)
80     {
81       char c;
82       ssize_t nread = read (fd, &c, 1);
83       if (nread == 1)
84         {
85           s[i] = c;
86           if (c == '\n')
87             {
88               if (i + 1 < size)
89                 s[i+1] = '\0';
90               else
91                 s[i] = '\0';
92               break;
93             }
94         }
95       else
96         {
97           s[i] = '\0';
98           break;
99         }
100     }
101   return s;
102 }
103
104
105 /* show_backtrace displays the backtrace, currently obtained by means of
106    the glibc backtrace* functions.  */
107
108 void
109 show_backtrace (void)
110 {
111 #if GLIBC_BACKTRACE
112
113 #define DEPTH 50
114 #define BUFSIZE 1024
115
116   void *trace[DEPTH];
117   int depth;
118
119   depth = backtrace (trace, DEPTH);
120   if (depth <= 0)
121     return;
122
123 #if CAN_PIPE
124
125   /* We attempt to extract file and line information from addr2line.  */
126   do
127   {
128     /* Local variables.  */
129     int f[2], pid, bt[2], inp[2];
130     char addr_buf[GFC_XTOA_BUF_SIZE], func[BUFSIZE], file[BUFSIZE];
131     char *p;
132
133     /* Don't output an error message if something goes wrong, we'll simply
134        fall back to the pstack and glibc backtraces.  */
135     if (pipe (f) != 0)
136       break;
137     if (pipe (inp) != 0)
138       break;
139     if ((pid = fork ()) == -1)
140       break;
141
142     if (pid == 0)
143       {
144         /* Child process.  */
145 #define NUM_FIXEDARGS 7
146         char *arg[NUM_FIXEDARGS];
147
148         close (f[0]);
149
150         close (inp[1]);
151         if (dup2 (inp[0], STDIN_FILENO) == -1)
152           _exit (1);
153         close (inp[0]);
154
155         close (STDERR_FILENO);
156
157         if (dup2 (f[1], STDOUT_FILENO) == -1)
158           _exit (1);
159         close (f[1]);
160
161         arg[0] = (char *) "addr2line";
162         arg[1] = (char *) "-e";
163         arg[2] = full_exe_path ();
164         arg[3] = (char *) "-f";
165         arg[4] = (char *) "-s";
166         arg[5] = (char *) "-C";
167         arg[6] = NULL;
168         execvp (arg[0], arg);
169         _exit (1);
170 #undef NUM_FIXEDARGS
171       }
172
173     /* Father process.  */
174     close (f[1]);
175     close (inp[0]);
176     if (pipe (bt) != 0)
177       break;
178     backtrace_symbols_fd (trace, depth, bt[1]);
179     close (bt[1]);
180
181     estr_write ("\nBacktrace for this error:\n");
182     for (int j = 0; j < depth; j++)
183       {
184         const char *addr = gfc_xtoa 
185           ((GFC_UINTEGER_LARGEST) (intptr_t) trace[j], 
186            addr_buf, sizeof (addr_buf));
187
188         write (inp[1], addr, strlen (addr));
189         write (inp[1], "\n", 1);
190         
191         if (! fd_gets (func, sizeof(func), f[0]))
192           goto fallback;
193         if (! fd_gets (file, sizeof(file), f[0]))
194           goto fallback;
195             
196         for (p = func; *p != '\n' && *p != '\r'; p++)
197           ;
198         *p = '\0';
199         
200         /* If we only have the address, use the glibc backtrace.  */
201         if (func[0] == '?' && func[1] == '?' && file[0] == '?'
202             && file[1] == '?')
203           {
204             bt_header (j);
205             while (1)
206               {
207                 char bc;
208                 ssize_t nread = read (bt[0], &bc, 1);
209                 if (nread != 1 || bc == '\n')
210                   break;
211                 write (STDERR_FILENO, &bc, 1);
212               }
213             estr_write ("\n");
214             continue;
215           }
216         else
217           {
218             /* Forward to the next entry in the backtrace. */
219             while (1)
220               {
221                 char bc;
222                 ssize_t nread = read (bt[0], &bc, 1);
223                 if (nread != 1 || bc == '\n')
224                   break;
225               }
226           }
227
228         /* _start is a setup routine that calls main(), and main() is
229            the frontend routine that calls some setup stuff and then
230            calls MAIN__, so at this point we should stop.  */
231         if (strcmp (func, "_start") == 0 || strcmp (func, "main") == 0)
232           break;
233         
234         bt_header (j);
235         estr_write (full_exe_path ());
236         estr_write ("[0x");
237         estr_write (addr);
238         estr_write ("] in ");
239         estr_write (func);
240         
241         if (strncmp (file, "??", 2) == 0)
242           estr_write ("\n");
243         else
244           {
245             estr_write (" at ");
246             estr_write (file);
247           }
248       } /* Loop over each hex address.  */
249     close (inp[1]);
250     close (bt[0]);
251     wait (NULL);
252     return;
253
254 fallback:
255     estr_write ("** Something went wrong while running addr2line. **\n"
256                 "** Falling back  to a simpler  backtrace scheme. **\n");
257   }
258   while (0);
259
260 #undef DEPTH
261 #undef BUFSIZE
262
263 #endif /* CAN_PIPE */
264
265   /* Fallback to the glibc backtrace.  */
266   estr_write ("\nBacktrace for this error:\n");
267   backtrace_symbols_fd (trace, depth, STDERR_FILENO);
268   return;
269
270 #elif defined(CAN_FORK) && defined(HAVE_GETPPID)
271   /* Try to call pstack.  */
272   do
273   {
274     /* Local variables.  */
275     int pid;
276
277     /* Don't output an error message if something goes wrong, we'll simply
278        fall back to the pstack and glibc backtraces.  */
279     if ((pid = fork ()) == -1)
280       break;
281
282     if (pid == 0)
283       {
284         /* Child process.  */
285 #define NUM_ARGS 2
286         char *arg[NUM_ARGS+1];
287         char buf[20];
288
289         estr_write ("\nBacktrace for this error:\n");
290         arg[0] = (char *) "pstack";
291         snprintf (buf, sizeof(buf), "%d", (int) getppid ());
292         arg[1] = buf;
293         arg[2] = NULL;
294         execvp (arg[0], arg);
295 #undef NUM_ARGS
296
297         /* pstack didn't work.  */
298         estr_write ("  unable to produce a backtrace, sorry!\n");
299         _exit (1);
300       }
301
302     /* Father process.  */
303     wait (NULL);
304     return;
305   }
306   while(0);
307 #else
308   estr_write ("\nBacktrace not yet available on this platform, sorry!\n");
309 #endif
310 }