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. */
30 #include "libgfortran.h"
38 #ifdef HAVE_INTTYPES_H
47 # define INTPTR_T intptr_t
52 #ifdef HAVE_EXECINFO_H
56 #ifdef HAVE_SYS_WAIT_H
65 local_strcasestr (const char *s1, const char *s2)
67 #ifdef HAVE_STRCASESTR
68 return strcasestr (s1, s2);
72 const size_t len = strlen (s2);
73 const char u = *s2, v = isupper((int) *s2) ? tolower((int) *s2)
74 : (islower((int) *s2) ? toupper((int) *s2)
79 while (*p != u && *p != v && *p)
83 if (strncasecmp (p, s2, len) == 0)
89 #define CAN_FORK (defined(HAVE_FORK) && defined(HAVE_EXECVP) \
90 && defined(HAVE_WAIT))
91 #define GLIBC_BACKTRACE (defined(HAVE_BACKTRACE) \
92 && defined(HAVE_BACKTRACE_SYMBOLS))
93 #define CAN_PIPE (CAN_FORK && defined(HAVE_PIPE) \
94 && defined(HAVE_DUP2) && defined(HAVE_FDOPEN) \
95 && defined(HAVE_CLOSE))
100 dump_glibc_backtrace (int depth, char *str[])
104 for (i = 0; i < depth; i++)
105 st_printf (" + %s\n", str[i]);
111 /* show_backtrace displays the backtrace, currently obtained by means of
112 the glibc backtrace* functions. */
114 show_backtrace (void)
125 depth = backtrace (trace, DEPTH);
129 str = backtrace_symbols (trace, depth);
134 #define STDIN_FILENO 0
137 #ifndef STDOUT_FILENO
138 #define STDOUT_FILENO 1
141 #ifndef STDERR_FILENO
142 #define STDERR_FILENO 2
145 /* We attempt to extract file and line information from addr2line. */
148 /* Local variables. */
149 int f[2], pid, line, i;
151 char addr_buf[DEPTH][GFC_XTOA_BUF_SIZE], func[BUFSIZE], file[BUFSIZE];
153 const char *addr[DEPTH];
155 /* Write the list of addresses in hexadecimal format. */
156 for (i = 0; i < depth; i++)
157 addr[i] = xtoa ((GFC_UINTEGER_LARGEST) (INTPTR_T) trace[i], addr_buf[i],
158 sizeof (addr_buf[i]));
160 /* Don't output an error message if something goes wrong, we'll simply
161 fall back to the pstack and glibc backtraces. */
164 if ((pid = fork ()) == -1)
170 #define NUM_FIXEDARGS 5
171 char *arg[DEPTH+NUM_FIXEDARGS+1];
174 close (STDIN_FILENO);
175 close (STDERR_FILENO);
177 if (dup2 (f[1], STDOUT_FILENO) == -1)
181 arg[0] = (char *) "addr2line";
182 arg[1] = (char *) "-e";
183 arg[2] = full_exe_path ();
184 arg[3] = (char *) "-f";
185 arg[4] = (char *) "-s";
186 for (i = 0; i < depth; i++)
187 arg[NUM_FIXEDARGS+i] = (char *) addr[i];
188 arg[NUM_FIXEDARGS+depth] = NULL;
189 execvp (arg[0], arg);
194 /* Father process. */
197 output = fdopen (f[0], "r");
200 if (fgets (func, sizeof(func), output))
202 st_printf ("\nBacktrace for this error:\n");
206 if (! fgets (file, sizeof(file), output))
211 for (p = func; *p != '\n' && *p != '\r'; p++)
216 /* Try to recognize the internal libgfortran functions. */
217 if (strncasecmp (func, "*_gfortran", 10) == 0
218 || strncasecmp (func, "_gfortran", 9) == 0
219 || strcmp (func, "main") == 0 || strcmp (func, "_start") == 0
220 || strcmp (func, "_gfortrani_handler") == 0)
223 if (local_strcasestr (str[i], "libgfortran.so") != NULL
224 || local_strcasestr (str[i], "libgfortran.dylib") != NULL
225 || local_strcasestr (str[i], "libgfortran.a") != NULL)
228 /* If we only have the address, use the glibc backtrace. */
229 if (func[0] == '?' && func[1] == '?' && file[0] == '?'
232 st_printf (" + %s\n", str[i]);
236 /* Extract the line number. */
237 for (end = NULL, p = file; *p; p++)
248 if (strcmp (func, "MAIN__") == 0)
249 st_printf (" + in the main program\n");
251 st_printf (" + function %s (0x%s)\n", func, addr[i]);
253 if (line <= 0 && strcmp (file, "??") == 0)
257 st_printf (" from file %s\n", file);
259 st_printf (" at line %d of file %s\n", line, file);
261 while (fgets (func, sizeof(func), output));
267 st_printf ("** Something went wrong while running addr2line. **\n"
268 "** Falling back to a simpler backtrace scheme. **\n");
279 #if CAN_FORK && defined(HAVE_GETPPID)
280 /* Try to call pstack. */
283 /* Local variables. */
286 /* Don't output an error message if something goes wrong, we'll simply
287 fall back to the pstack and glibc backtraces. */
288 if ((pid = fork ()) == -1)
295 char *arg[NUM_ARGS+1];
298 st_printf ("\nBacktrace for this error:\n");
299 arg[0] = (char *) "pstack";
301 snprintf (buf, sizeof(buf), "%d", (int) getppid ());
303 sprintf (buf, "%d", (int) getppid ());
307 execvp (arg[0], arg);
310 /* pstack didn't work, so we fall back to dumping the glibc
311 backtrace if we can. */
313 dump_glibc_backtrace (depth, str);
315 st_printf (" unable to produce a backtrace, sorry!\n");
321 /* Father process. */
329 /* Fallback to the glibc backtrace. */
330 st_printf ("\nBacktrace for this error:\n");
331 dump_glibc_backtrace (depth, str);