OSDN Git Service

PR 49214 fd_gets should return NULL if nothing was read
[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           if (i == 0)
99             return NULL;
100           break;
101         }
102     }
103   return s;
104 }
105
106
107 /* show_backtrace displays the backtrace, currently obtained by means of
108    the glibc backtrace* functions.  */
109
110 void
111 show_backtrace (void)
112 {
113 #if GLIBC_BACKTRACE
114
115 #define DEPTH 50
116 #define BUFSIZE 1024
117
118   void *trace[DEPTH];
119   int depth;
120
121   depth = backtrace (trace, DEPTH);
122   if (depth <= 0)
123     return;
124
125 #if CAN_PIPE
126
127   /* We attempt to extract file and line information from addr2line.  */
128   do
129   {
130     /* Local variables.  */
131     int f[2], pid, bt[2], inp[2];
132     char addr_buf[GFC_XTOA_BUF_SIZE], func[BUFSIZE], file[BUFSIZE];
133     char *p;
134
135     /* Don't output an error message if something goes wrong, we'll simply
136        fall back to the pstack and glibc backtraces.  */
137     if (pipe (f) != 0)
138       break;
139     if (pipe (inp) != 0)
140       break;
141     if ((pid = fork ()) == -1)
142       break;
143
144     if (pid == 0)
145       {
146         /* Child process.  */
147 #define NUM_FIXEDARGS 7
148         char *arg[NUM_FIXEDARGS];
149
150         close (f[0]);
151
152         close (inp[1]);
153         if (dup2 (inp[0], STDIN_FILENO) == -1)
154           _exit (1);
155         close (inp[0]);
156
157         close (STDERR_FILENO);
158
159         if (dup2 (f[1], STDOUT_FILENO) == -1)
160           _exit (1);
161         close (f[1]);
162
163         arg[0] = (char *) "addr2line";
164         arg[1] = (char *) "-e";
165         arg[2] = full_exe_path ();
166         arg[3] = (char *) "-f";
167         arg[4] = (char *) "-s";
168         arg[5] = (char *) "-C";
169         arg[6] = NULL;
170         execvp (arg[0], arg);
171         _exit (1);
172 #undef NUM_FIXEDARGS
173       }
174
175     /* Father process.  */
176     close (f[1]);
177     close (inp[0]);
178     if (pipe (bt) != 0)
179       break;
180     backtrace_symbols_fd (trace, depth, bt[1]);
181     close (bt[1]);
182
183     estr_write ("\nBacktrace for this error:\n");
184     for (int j = 0; j < depth; j++)
185       {
186         const char *addr = gfc_xtoa 
187           ((GFC_UINTEGER_LARGEST) (intptr_t) trace[j], 
188            addr_buf, sizeof (addr_buf));
189
190         write (inp[1], addr, strlen (addr));
191         write (inp[1], "\n", 1);
192         
193         if (! fd_gets (func, sizeof(func), f[0]))
194           goto fallback;
195         if (! fd_gets (file, sizeof(file), f[0]))
196           goto fallback;
197             
198         for (p = func; *p != '\n' && *p != '\r'; p++)
199           ;
200         *p = '\0';
201         
202         /* If we only have the address, use the glibc backtrace.  */
203         if (func[0] == '?' && func[1] == '?' && file[0] == '?'
204             && file[1] == '?')
205           {
206             bt_header (j);
207             while (1)
208               {
209                 char bc;
210                 ssize_t nread = read (bt[0], &bc, 1);
211                 if (nread != 1 || bc == '\n')
212                   break;
213                 write (STDERR_FILENO, &bc, 1);
214               }
215             estr_write ("\n");
216             continue;
217           }
218         else
219           {
220             /* Forward to the next entry in the backtrace. */
221             while (1)
222               {
223                 char bc;
224                 ssize_t nread = read (bt[0], &bc, 1);
225                 if (nread != 1 || bc == '\n')
226                   break;
227               }
228           }
229
230         /* _start is a setup routine that calls main(), and main() is
231            the frontend routine that calls some setup stuff and then
232            calls MAIN__, so at this point we should stop.  */
233         if (strcmp (func, "_start") == 0 || strcmp (func, "main") == 0)
234           break;
235         
236         bt_header (j);
237         estr_write (full_exe_path ());
238         estr_write ("[0x");
239         estr_write (addr);
240         estr_write ("] in ");
241         estr_write (func);
242         
243         if (strncmp (file, "??", 2) == 0)
244           estr_write ("\n");
245         else
246           {
247             estr_write (" at ");
248             estr_write (file);
249           }
250       } /* Loop over each hex address.  */
251     close (inp[1]);
252     close (bt[0]);
253     wait (NULL);
254     return;
255
256 fallback:
257     estr_write ("** Something went wrong while running addr2line. **\n"
258                 "** Falling back  to a simpler  backtrace scheme. **\n");
259   }
260   while (0);
261
262 #undef DEPTH
263 #undef BUFSIZE
264
265 #endif /* CAN_PIPE */
266
267   /* Fallback to the glibc backtrace.  */
268   estr_write ("\nBacktrace for this error:\n");
269   backtrace_symbols_fd (trace, depth, STDERR_FILENO);
270   return;
271
272 #elif defined(CAN_FORK) && defined(HAVE_GETPPID)
273   /* Try to call pstack.  */
274   do
275   {
276     /* Local variables.  */
277     int pid;
278
279     /* Don't output an error message if something goes wrong, we'll simply
280        fall back to the pstack and glibc backtraces.  */
281     if ((pid = fork ()) == -1)
282       break;
283
284     if (pid == 0)
285       {
286         /* Child process.  */
287 #define NUM_ARGS 2
288         char *arg[NUM_ARGS+1];
289         char buf[20];
290
291         estr_write ("\nBacktrace for this error:\n");
292         arg[0] = (char *) "pstack";
293         snprintf (buf, sizeof(buf), "%d", (int) getppid ());
294         arg[1] = buf;
295         arg[2] = NULL;
296         execvp (arg[0], arg);
297 #undef NUM_ARGS
298
299         /* pstack didn't work.  */
300         estr_write ("  unable to produce a backtrace, sorry!\n");
301         _exit (1);
302       }
303
304     /* Father process.  */
305     wait (NULL);
306     return;
307   }
308   while(0);
309 #else
310   estr_write ("\nBacktrace not yet available on this platform, sorry!\n");
311 #endif
312 }