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);
107 extern char *addr2line_path
;
110 /* show_backtrace displays the backtrace, currently obtained by means of
111 the glibc backtrace* functions. */
114 show_backtrace (void)
124 depth
= backtrace (trace
, DEPTH
);
130 if (addr2line_path
== NULL
)
133 /* We attempt to extract file and line information from addr2line. */
136 /* Local variables. */
137 int f
[2], pid
, bt
[2], inp
[2];
138 char addr_buf
[GFC_XTOA_BUF_SIZE
], func
[BUFSIZE
], file
[BUFSIZE
];
141 /* Don't output an error message if something goes wrong, we'll simply
142 fall back to the pstack and glibc backtraces. */
147 if ((pid
= fork ()) == -1)
153 #define NUM_FIXEDARGS 7
154 char *arg
[NUM_FIXEDARGS
];
155 char *newenv
[] = { NULL
};
160 if (dup2 (inp
[0], STDIN_FILENO
) == -1)
164 close (STDERR_FILENO
);
166 if (dup2 (f
[1], STDOUT_FILENO
) == -1)
170 arg
[0] = addr2line_path
;
171 arg
[1] = (char *) "-e";
172 arg
[2] = full_exe_path ();
173 arg
[3] = (char *) "-f";
174 arg
[4] = (char *) "-s";
175 arg
[5] = (char *) "-C";
177 execve (addr2line_path
, arg
, newenv
);
182 /* Father process. */
187 backtrace_symbols_fd (trace
, depth
, bt
[1]);
190 estr_write ("\nBacktrace for this error:\n");
191 for (int j
= 0; j
< depth
; j
++)
193 const char *addr
= gfc_xtoa
194 ((GFC_UINTEGER_LARGEST
) (intptr_t) trace
[j
],
195 addr_buf
, sizeof (addr_buf
));
197 write (inp
[1], addr
, strlen (addr
));
198 write (inp
[1], "\n", 1);
200 if (! fd_gets (func
, sizeof(func
), f
[0]))
202 if (! fd_gets (file
, sizeof(file
), f
[0]))
205 for (p
= func
; *p
!= '\n' && *p
!= '\r'; p
++)
209 /* If we only have the address, use the glibc backtrace. */
210 if (func
[0] == '?' && func
[1] == '?' && file
[0] == '?'
217 ssize_t nread
= read (bt
[0], &bc
, 1);
218 if (nread
!= 1 || bc
== '\n')
220 write (STDERR_FILENO
, &bc
, 1);
227 /* Forward to the next entry in the backtrace. */
231 ssize_t nread
= read (bt
[0], &bc
, 1);
232 if (nread
!= 1 || bc
== '\n')
237 /* _start is a setup routine that calls main(), and main() is
238 the frontend routine that calls some setup stuff and then
239 calls MAIN__, so at this point we should stop. */
240 if (strcmp (func
, "_start") == 0 || strcmp (func
, "main") == 0)
244 estr_write (full_exe_path ());
247 estr_write ("] in ");
250 if (strncmp (file
, "??", 2) == 0)
257 } /* Loop over each hex address. */
264 estr_write ("** Something went wrong while running addr2line. **\n"
265 "** Falling back to a simpler backtrace scheme. **\n");
272 #endif /* CAN_PIPE */
275 /* Fallback to the glibc backtrace. */
276 estr_write ("\nBacktrace for this error:\n");
277 backtrace_symbols_fd (trace
, depth
, STDERR_FILENO
);
280 #elif defined(CAN_FORK) && defined(HAVE_GETPPID)
281 /* Try to call pstack. */
284 /* Local variables. */
287 /* Don't output an error message if something goes wrong, we'll simply
288 fall back to the pstack and glibc backtraces. */
289 if ((pid
= fork ()) == -1)
296 char *arg
[NUM_ARGS
+1];
299 estr_write ("\nBacktrace for this error:\n");
300 arg
[0] = (char *) "pstack";
301 snprintf (buf
, sizeof(buf
), "%d", (int) getppid ());
304 execvp (arg
[0], arg
);
307 /* pstack didn't work. */
308 estr_write (" unable to produce a backtrace, sorry!\n");
312 /* Father process. */
318 estr_write ("\nBacktrace not yet available on this platform, sorry!\n");