1 /* Copyright (C) 2006, 2007, 2009, 2011, 2012 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"
34 #ifdef HAVE_SYS_WAIT_H
43 /* Macros for common sets of capabilities: can we fork and exec, can
44 we use glibc-style backtrace functions, and can we use pipes. */
45 #define CAN_FORK (defined(HAVE_FORK) && defined(HAVE_EXECVE) \
46 && defined(HAVE_WAIT))
47 #define CAN_PIPE (CAN_FORK && defined(HAVE_PIPE) \
48 && defined(HAVE_DUP2) && defined(HAVE_FDOPEN) \
49 && defined(HAVE_CLOSE))
56 /* GDB style #NUM index for each stack frame. */
61 st_printf ("#%d ", num);
65 /* fgets()-like function that reads a line from a fd, without
66 needing to malloc() a buffer, and does not use locks, hence should
67 be async-signal-safe. */
70 fd_gets (char *s, int size, int fd)
72 for (int i = 0; i < size; i++)
75 ssize_t nread = read (fd, &c, 1);
100 extern char *addr2line_path;
102 /* Struct containing backtrace state. */
113 static _Unwind_Reason_Code
114 trace_function (struct _Unwind_Context *context, void *state_ptr)
116 bt_state* state = (bt_state*) state_ptr;
118 #ifdef HAVE_GETIPINFO
119 int ip_before_insn = 0;
120 ip = _Unwind_GetIPInfo (context, &ip_before_insn);
122 /* If the unwinder gave us a 'return' address, roll it back a little
123 to ensure we get the correct line number for the call itself. */
124 if (! ip_before_insn)
127 ip = _Unwind_GetIP (context);
130 if (state->direct_output)
132 bt_header(state->frame_number);
133 st_printf ("%p\n", (void*) ip);
137 char addr_buf[GFC_XTOA_BUF_SIZE], func[1024], file[PATH_MAX];
139 const char* addr = gfc_xtoa (ip, addr_buf, sizeof (addr_buf));
140 write (state->outfd, addr, strlen (addr));
141 write (state->outfd, "\n", 1);
143 if (! fd_gets (func, sizeof(func), state->infd))
148 if (! fd_gets (file, sizeof(file), state->infd))
154 for (p = func; *p != '\n' && *p != '\r'; p++)
158 /* _start is a setup routine that calls main(), and main() is
159 the frontend routine that calls some setup stuff and then
160 calls MAIN__, so at this point we should stop. */
161 if (strcmp (func, "_start") == 0 || strcmp (func, "main") == 0)
162 return _URC_END_OF_STACK;
164 bt_header (state->frame_number);
168 if (func[0] != '?' && func[1] != '?')
174 if (strncmp (file, "??", 2) == 0)
185 state->frame_number++;
187 return _URC_NO_REASON;
191 /* Display the backtrace. */
194 show_backtrace (void)
197 state.frame_number = 0;
200 estr_write ("\nBacktrace for this error:\n");
204 if (addr2line_path == NULL)
207 /* We attempt to extract file and line information from addr2line. */
210 /* Local variables. */
211 int f[2], pid, inp[2];
213 /* Don't output an error message if something goes wrong, we'll simply
214 fall back to printing the addresses. */
219 if ((pid = fork ()) == -1)
225 #define NUM_FIXEDARGS 7
226 char *arg[NUM_FIXEDARGS];
227 char *newenv[] = { NULL };
232 if (dup2 (inp[0], STDIN_FILENO) == -1)
236 close (STDERR_FILENO);
238 if (dup2 (f[1], STDOUT_FILENO) == -1)
242 arg[0] = addr2line_path;
243 arg[1] = (char *) "-e";
244 arg[2] = full_exe_path ();
245 arg[3] = (char *) "-f";
246 arg[4] = (char *) "-s";
247 arg[5] = (char *) "-C";
249 execve (addr2line_path, arg, newenv);
254 /* Father process. */
258 state.outfd = inp[1];
260 state.direct_output = 0;
261 _Unwind_Backtrace (trace_function, &state);
269 estr_write ("** Something went wrong while running addr2line. **\n"
270 "** Falling back to a simpler backtrace scheme. **\n");
274 #endif /* CAN_PIPE */
277 /* Fallback to the simple backtrace without addr2line. */
278 state.direct_output = 1;
279 _Unwind_Backtrace (trace_function, &state);