1 /* Copyright (C) 2006, 2007 Free Software Foundation, Inc.
2 Contributed by François-Xavier Coudert
4 This file is part of the GNU Fortran 95 runtime library (libgfortran).
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)
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
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.
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. */
39 #ifdef HAVE_INTTYPES_H
48 # define INTPTR_T intptr_t
53 #ifdef HAVE_EXECINFO_H
57 #ifdef HAVE_SYS_WAIT_H
67 #include "libgfortran.h"
72 local_strcasestr (const char *s1, const char *s2)
74 #ifdef HAVE_STRCASESTR
75 return strcasestr (s1, s2);
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)
86 while (*p != u && *p != v && *p)
90 if (strncasecmp (p, s2, len) == 0)
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))
107 dump_glibc_backtrace (int depth, char *str[])
111 for (i = 0; i < depth; i++)
112 st_printf (" + %s\n", str[i]);
118 /* show_backtrace displays the backtrace, currently obtained by means of
119 the glibc backtrace* functions. */
121 show_backtrace (void)
132 depth = backtrace (trace, DEPTH);
136 str = backtrace_symbols (trace, depth);
141 #define STDIN_FILENO 0
144 #ifndef STDOUT_FILENO
145 #define STDOUT_FILENO 1
148 #ifndef STDERR_FILENO
149 #define STDERR_FILENO 2
152 /* We attempt to extract file and line information from addr2line. */
155 /* Local variables. */
156 int f[2], pid, line, i;
158 char addr_buf[DEPTH][GFC_XTOA_BUF_SIZE], func[BUFSIZE], file[BUFSIZE];
160 const char *addr[DEPTH];
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]));
167 /* Don't output an error message if something goes wrong, we'll simply
168 fall back to the pstack and glibc backtraces. */
171 if ((pid = fork ()) == -1)
177 #define NUM_FIXEDARGS 5
178 char *arg[DEPTH+NUM_FIXEDARGS+1];
181 close (STDIN_FILENO);
182 close (STDERR_FILENO);
184 if (dup2 (f[1], STDOUT_FILENO) == -1)
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);
201 /* Father process. */
204 output = fdopen (f[0], "r");
207 if (fgets (func, sizeof(func), output))
209 st_printf ("\nBacktrace for this error:\n");
213 if (! fgets (file, sizeof(file), output))
218 for (p = func; *p != '\n' && *p != '\r'; p++)
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)
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)
234 /* If we only have the address, use the glibc backtrace. */
235 if (func[0] == '?' && func[1] == '?' && file[0] == '?'
238 st_printf (" + %s\n", str[i]);
242 /* Extract the line number. */
243 for (end = NULL, p = file; *p; p++)
254 if (strcmp (func, "MAIN__") == 0)
255 st_printf (" + in the main program\n");
257 st_printf (" + function %s (0x%s)\n", func, addr[i]);
259 if (line <= 0 && strcmp (file, "??") == 0)
263 st_printf (" from file %s\n", file);
265 st_printf (" at line %d of file %s\n", line, file);
267 while (fgets (func, sizeof(func), output));
273 st_printf ("** Something went wrong while running addr2line. **\n"
274 "** Falling back to a simpler backtrace scheme. **\n");
285 #if CAN_FORK && defined(HAVE_GETPPID)
286 /* Try to call pstack. */
289 /* Local variables. */
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)
301 char *arg[NUM_ARGS+1];
304 st_printf ("\nBacktrace for this error:\n");
305 arg[0] = (char *) "pstack";
307 snprintf (buf, sizeof(buf), "%d", (int) getppid ());
309 sprintf (buf, "%d", (int) getppid ());
313 execvp (arg[0], arg);
316 /* pstack didn't work, so we fall back to dumping the glibc
317 backtrace if we can. */
319 dump_glibc_backtrace (depth, str);
321 st_printf (" unable to produce a backtrace, sorry!\n");
327 /* Father process. */
335 /* Fallback to the glibc backtrace. */
336 st_printf ("\nBacktrace for this error:\n");
337 dump_glibc_backtrace (depth, str);