1 /* Copyright (C) 2006, 2007, 2009, 2011 Free Software Foundation, Inc.
2 Contributed by François-Xavier Coudert
4 This file is part of the GNU Fortran 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 3, or (at your option)
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.
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.
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/>. */
25 #include "libgfortran.h"
33 #ifdef HAVE_INTTYPES_H
41 #ifdef HAVE_EXECINFO_H
45 #ifdef HAVE_SYS_WAIT_H
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))
63 /* GDB style #NUM index for each stack frame. */
68 st_printf (" #%d ", num
);
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. */
77 fd_gets (char *s
, int size
, int fd
)
79 for (int i
= 0; i
< size
; i
++)
82 ssize_t nread
= read (fd
, &c
, 1);
105 /* show_backtrace displays the backtrace, currently obtained by means of
106 the glibc backtrace* functions. */
109 show_backtrace (void)
119 depth
= backtrace (trace
, DEPTH
);
125 /* We attempt to extract file and line information from addr2line. */
128 /* Local variables. */
129 int f
[2], pid
, bt
[2], inp
[2];
130 char addr_buf
[GFC_XTOA_BUF_SIZE
], func
[BUFSIZE
], file
[BUFSIZE
];
133 /* Don't output an error message if something goes wrong, we'll simply
134 fall back to the pstack and glibc backtraces. */
139 if ((pid
= fork ()) == -1)
145 #define NUM_FIXEDARGS 7
146 char *arg
[NUM_FIXEDARGS
];
151 if (dup2 (inp
[0], STDIN_FILENO
) == -1)
155 close (STDERR_FILENO
);
157 if (dup2 (f
[1], STDOUT_FILENO
) == -1)
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";
168 execvp (arg
[0], arg
);
173 /* Father process. */
178 backtrace_symbols_fd (trace
, depth
, bt
[1]);
181 estr_write ("\nBacktrace for this error:\n");
182 for (int j
= 0; j
< depth
; j
++)
184 const char *addr
= gfc_xtoa
185 ((GFC_UINTEGER_LARGEST
) (intptr_t) trace
[j
],
186 addr_buf
, sizeof (addr_buf
));
188 write (inp
[1], addr
, strlen (addr
));
189 write (inp
[1], "\n", 1);
191 if (! fd_gets (func
, sizeof(func
), f
[0]))
193 if (! fd_gets (file
, sizeof(file
), f
[0]))
196 for (p
= func
; *p
!= '\n' && *p
!= '\r'; p
++)
200 /* If we only have the address, use the glibc backtrace. */
201 if (func
[0] == '?' && func
[1] == '?' && file
[0] == '?'
208 ssize_t nread
= read (bt
[0], &bc
, 1);
209 if (nread
!= 1 || bc
== '\n')
211 write (STDERR_FILENO
, &bc
, 1);
218 /* Forward to the next entry in the backtrace. */
222 ssize_t nread
= read (bt
[0], &bc
, 1);
223 if (nread
!= 1 || bc
== '\n')
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)
235 estr_write (full_exe_path ());
238 estr_write ("] in ");
241 if (strncmp (file
, "??", 2) == 0)
248 } /* Loop over each hex address. */
255 estr_write ("** Something went wrong while running addr2line. **\n"
256 "** Falling back to a simpler backtrace scheme. **\n");
263 #endif /* CAN_PIPE */
265 /* Fallback to the glibc backtrace. */
266 estr_write ("\nBacktrace for this error:\n");
267 backtrace_symbols_fd (trace
, depth
, STDERR_FILENO
);
270 #elif defined(CAN_FORK) && defined(HAVE_GETPPID)
271 /* Try to call pstack. */
274 /* Local variables. */
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)
286 char *arg
[NUM_ARGS
+1];
289 estr_write ("\nBacktrace for this error:\n");
290 arg
[0] = (char *) "pstack";
291 snprintf (buf
, sizeof(buf
), "%d", (int) getppid ());
294 execvp (arg
[0], arg
);
297 /* pstack didn't work. */
298 estr_write (" unable to produce a backtrace, sorry!\n");
302 /* Father process. */
308 estr_write ("\nBacktrace not yet available on this platform, sorry!\n");