OSDN Git Service

* combine.c (combine_max_regno): Remove. Remove all uses.
[pf3gnuchains/gcc-fork.git] / libgfortran / runtime / backtrace.c
1 /* Copyright (C) 2006, 2007 Free Software Foundation, Inc.
2    Contributed by François-Xavier Coudert
3
4 This file is part of the GNU Fortran 95 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 2, or (at your option)
9 any later version.
10
11 In addition to the permissions in the GNU General Public License, the
12 Free Software Foundation gives you unlimited permission to link the
13 compiled version of this file into combinations with other programs,
14 and to distribute those combinations without any restriction coming
15 from the use of this file.  (The General Public License restrictions
16 do apply in other respects; for example, they cover modification of
17 the file, and distribution when not linked into a combine
18 executable.)
19
20 Libgfortran is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23 GNU General Public License for more details.
24
25 You should have received a copy of the GNU General Public License
26 along with libgfortran; see the file COPYING.  If not, write to
27 the Free Software Foundation, 51 Franklin Street, Fifth Floor,
28 Boston, MA 02110-1301, USA.  */
29
30
31 #include "config.h"
32 #include <stdio.h>
33 #include <string.h>
34
35 #ifdef HAVE_STDLIB_H
36 #include <stdlib.h>
37 #endif
38
39 #ifdef HAVE_INTTYPES_H
40 #include <inttypes.h>
41 #endif
42
43 #ifdef HAVE_UNISTD_H
44 #include <unistd.h>
45 #endif
46
47 #ifdef HAVE_INTPTR_T
48 # define INTPTR_T intptr_t
49 #else
50 # define INTPTR_T int
51 #endif
52
53 #ifdef HAVE_EXECINFO_H
54 #include <execinfo.h>
55 #endif
56
57 #ifdef HAVE_SYS_WAIT_H
58 #include <sys/wait.h>
59 #endif
60
61 #ifdef HAVE_STRING_H
62 #include <string.h>
63 #endif
64
65 #include <ctype.h>
66
67 #include "libgfortran.h"
68
69
70
71 static char *
72 local_strcasestr (const char *s1, const char *s2)
73 {
74 #ifdef HAVE_STRCASESTR
75   return strcasestr (s1, s2);
76 #else
77
78   const char *p = s1;
79   const size_t len = strlen (s2);
80   const char u = *s2, v = isupper((int) *s2) ? tolower((int) *s2)
81                                   : (islower((int) *s2) ? toupper((int) *s2)
82                                                         : *s2);
83
84   while (1)
85     {
86       while (*p != u && *p != v && *p)
87         p++;
88       if (*p == 0)
89         return NULL;
90       if (strncasecmp (p, s2, len) == 0)
91         return (char *)p;
92     }
93 #endif
94 }
95
96 #define CAN_FORK (defined(HAVE_FORK) && defined(HAVE_EXECVP) \
97                   && defined(HAVE_WAIT))
98 #define GLIBC_BACKTRACE (defined(HAVE_BACKTRACE) \
99                          && defined(HAVE_BACKTRACE_SYMBOLS))
100 #define CAN_PIPE (CAN_FORK && defined(HAVE_PIPE) \
101                   && defined(HAVE_DUP2) && defined(HAVE_FDOPEN) \
102                   && defined(HAVE_CLOSE))
103
104
105 #if GLIBC_BACKTRACE
106 static void
107 dump_glibc_backtrace (int depth, char *str[])
108 {
109   int i;
110
111   for (i = 0; i < depth; i++)
112     st_printf ("  + %s\n", str[i]);
113
114   free (str);
115 }
116 #endif
117
118 /* show_backtrace displays the backtrace, currently obtained by means of
119    the glibc backtrace* functions.  */
120 void
121 show_backtrace (void)
122 {
123 #if GLIBC_BACKTRACE
124
125 #define DEPTH 50
126 #define BUFSIZE 1024
127
128   void *trace[DEPTH];
129   char **str;
130   int depth;
131
132   depth = backtrace (trace, DEPTH);
133   if (depth <= 0)
134     return;
135
136   str = backtrace_symbols (trace, depth);
137
138 #if CAN_PIPE
139
140 #ifndef STDIN_FILENO
141 #define STDIN_FILENO 0
142 #endif
143
144 #ifndef STDOUT_FILENO
145 #define STDOUT_FILENO 1
146 #endif
147
148 #ifndef STDERR_FILENO
149 #define STDERR_FILENO 2
150 #endif
151
152   /* We attempt to extract file and line information from addr2line.  */
153   do
154   {
155     /* Local variables.  */
156     int f[2], pid, line, i;
157     FILE *output;
158     char addr_buf[DEPTH][GFC_XTOA_BUF_SIZE], func[BUFSIZE], file[BUFSIZE];
159     char *p, *end;
160     const char *addr[DEPTH];
161
162     /* Write the list of addresses in hexadecimal format.  */
163     for (i = 0; i < depth; i++)
164       addr[i] = xtoa ((GFC_UINTEGER_LARGEST) (INTPTR_T) trace[i], addr_buf[i],
165                       sizeof (addr_buf[i]));
166
167     /* Don't output an error message if something goes wrong, we'll simply
168        fall back to the pstack and glibc backtraces.  */
169     if (pipe (f) != 0)
170       break;
171     if ((pid = fork ()) == -1)
172       break;
173
174     if (pid == 0)
175       {
176         /* Child process.  */
177 #define NUM_FIXEDARGS 5
178         char *arg[DEPTH+NUM_FIXEDARGS+1];
179
180         close (f[0]);
181         close (STDIN_FILENO);
182         close (STDERR_FILENO);
183
184         if (dup2 (f[1], STDOUT_FILENO) == -1)
185           _exit (0);
186         close (f[1]);
187
188         arg[0] = (char *) "addr2line";
189         arg[1] = (char *) "-e";
190         arg[2] = full_exe_path ();
191         arg[3] = (char *) "-f";
192         arg[4] = (char *) "-s";
193         for (i = 0; i < depth; i++)
194           arg[NUM_FIXEDARGS+i] = (char *) addr[i];
195         arg[NUM_FIXEDARGS+depth] = NULL;
196         execvp (arg[0], arg);
197         _exit (0);
198 #undef NUM_FIXEDARGS
199       }
200
201     /* Father process.  */
202     close (f[1]);
203     wait (NULL);
204     output = fdopen (f[0], "r");
205     i = -1;
206
207     if (fgets (func, sizeof(func), output))
208       {
209         st_printf ("\nBacktrace for this error:\n");
210
211         do
212           {
213             if (! fgets (file, sizeof(file), output))
214               goto fallback;
215
216             i++;
217
218             for (p = func; *p != '\n' && *p != '\r'; p++)
219               ;
220
221             *p = '\0';
222
223             /* Try to recognize the internal libgfortran functions.  */
224             if (strncasecmp (func, "*_gfortran", 10) == 0
225                 || strncasecmp (func, "_gfortran", 9) == 0
226                 || strcmp (func, "main") == 0 || strcmp (func, "_start") == 0)
227               continue;
228
229             if (local_strcasestr (str[i], "libgfortran.so") != NULL
230                 || local_strcasestr (str[i], "libgfortran.dylib") != NULL
231                 || local_strcasestr (str[i], "libgfortran.a") != NULL)
232               continue;
233
234             /* If we only have the address, use the glibc backtrace.  */
235             if (func[0] == '?' && func[1] == '?' && file[0] == '?'
236                 && file[1] == '?')
237               {
238                 st_printf ("  + %s\n", str[i]);
239                 continue;
240               }
241
242             /* Extract the line number.  */
243             for (end = NULL, p = file; *p; p++)
244               if (*p == ':')
245                 end = p;
246             if (end != NULL)
247               {
248                 *end = '\0';
249                 line = atoi (++end);
250               }
251             else
252               line = -1;
253
254             if (strcmp (func, "MAIN__") == 0)
255               st_printf ("  + in the main program\n");
256             else
257               st_printf ("  + function %s (0x%s)\n", func, addr[i]);
258
259             if (line <= 0 && strcmp (file, "??") == 0)
260               continue;
261
262             if (line <= 0)
263               st_printf ("    from file %s\n", file);
264             else
265               st_printf ("    at line %d of file %s\n", line, file);
266           }
267         while (fgets (func, sizeof(func), output));
268
269         free (str);
270         return;
271
272 fallback:
273         st_printf ("** Something went wrong while running addr2line. **\n"
274                    "** Falling back  to a simpler  backtrace scheme. **\n");
275       }
276     }
277   while (0);
278
279 #undef DEPTH
280 #undef BUFSIZE
281
282 #endif
283 #endif
284
285 #if CAN_FORK && defined(HAVE_GETPPID)
286   /* Try to call pstack.  */
287   do
288   {
289     /* Local variables.  */
290     int pid;
291
292     /* Don't output an error message if something goes wrong, we'll simply
293        fall back to the pstack and glibc backtraces.  */
294     if ((pid = fork ()) == -1)
295       break;
296
297     if (pid == 0)
298       {
299         /* Child process.  */
300 #define NUM_ARGS 2
301         char *arg[NUM_ARGS+1];
302         char buf[20];
303
304         st_printf ("\nBacktrace for this error:\n");
305         arg[0] = (char *) "pstack";
306 #ifdef HAVE_SNPRINTF
307         snprintf (buf, sizeof(buf), "%d", (int) getppid ());
308 #else
309         sprintf (buf, "%d", (int) getppid ());
310 #endif
311         arg[1] = buf;
312         arg[2] = NULL;
313         execvp (arg[0], arg);
314 #undef NUM_ARGS
315
316         /* pstack didn't work, so we fall back to dumping the glibc
317            backtrace if we can.  */
318 #if GLIBC_BACKTRACE
319         dump_glibc_backtrace (depth, str);
320 #else
321         st_printf ("  unable to produce a backtrace, sorry!\n");
322 #endif
323
324         _exit (0);
325       }
326
327     /* Father process.  */
328     wait (NULL);
329     return;
330   }
331   while(0);
332 #endif
333
334 #if GLIBC_BACKTRACE
335   /* Fallback to the glibc backtrace.  */
336   st_printf ("\nBacktrace for this error:\n");
337   dump_glibc_backtrace (depth, str);
338 #endif
339 }