]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgfortran/runtime/backtrace.c
Update copyright years in libgfortran.
[thirdparty/gcc.git] / libgfortran / runtime / backtrace.c
CommitLineData
e3c063ce 1/* Copyright (C) 2006-2013 Free Software Foundation, Inc.
868d75db
FXC
2 Contributed by François-Xavier Coudert
3
d30fe1c5 4This file is part of the GNU Fortran runtime library (libgfortran).
868d75db
FXC
5
6Libgfortran is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
748086b7 8the Free Software Foundation; either version 3, or (at your option)
868d75db
FXC
9any later version.
10
868d75db
FXC
11Libgfortran is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
748086b7
JJ
16Under Section 7 of GPL version 3, you are granted additional
17permissions described in the GCC Runtime Library Exception, version
183.1, as published by the Free Software Foundation.
19
20You should have received a copy of the GNU General Public License and
21a copy of the GCC Runtime Library Exception along with this program;
22see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23<http://www.gnu.org/licenses/>. */
868d75db 24
36ae8a61 25#include "libgfortran.h"
868d75db 26
868d75db 27#include <string.h>
74544378 28#include <stdlib.h>
868d75db 29
868d75db
FXC
30#ifdef HAVE_UNISTD_H
31#include <unistd.h>
32#endif
33
868d75db
FXC
34#ifdef HAVE_SYS_WAIT_H
35#include <sys/wait.h>
36#endif
37
1ff101ff
JB
38#include <limits.h>
39
40#include "unwind.h"
868d75db 41
868d75db 42
869eea24
JB
43/* Macros for common sets of capabilities: can we fork and exec, and
44 can we use pipes to communicate with the subprocess. */
1ff101ff 45#define CAN_FORK (defined(HAVE_FORK) && defined(HAVE_EXECVE) \
1cc0507d 46 && defined(HAVE_WAIT))
1cc0507d 47#define CAN_PIPE (CAN_FORK && defined(HAVE_PIPE) \
869eea24 48 && defined(HAVE_DUP2) && defined(HAVE_CLOSE))
868d75db 49
1ff101ff
JB
50#ifndef PATH_MAX
51#define PATH_MAX 4096
52#endif
53
1cc0507d 54
eec2794c 55/* GDB style #NUM index for each stack frame. */
c861db66 56
eec2794c
JB
57static void
58bt_header (int num)
59{
1ff101ff 60 st_printf ("#%d ", num);
c861db66 61}
868d75db
FXC
62
63
eec2794c
JB
64/* fgets()-like function that reads a line from a fd, without
65 needing to malloc() a buffer, and does not use locks, hence should
66 be async-signal-safe. */
868d75db 67
eec2794c
JB
68static char *
69fd_gets (char *s, int size, int fd)
70{
71 for (int i = 0; i < size; i++)
1028b2bd 72 {
eec2794c
JB
73 char c;
74 ssize_t nread = read (fd, &c, 1);
75 if (nread == 1)
76 {
77 s[i] = c;
78 if (c == '\n')
79 {
80 if (i + 1 < size)
81 s[i+1] = '\0';
82 else
83 s[i] = '\0';
84 break;
85 }
86 }
87 else
88 {
89 s[i] = '\0';
8bea6ce4
JB
90 if (i == 0)
91 return NULL;
eec2794c
JB
92 break;
93 }
1028b2bd 94 }
eec2794c 95 return s;
868d75db 96}
eec2794c 97
868d75db 98
155732f5
JB
99extern char *addr2line_path;
100
1ff101ff
JB
101/* Struct containing backtrace state. */
102typedef struct
103{
104 int frame_number;
105 int direct_output;
106 int outfd;
107 int infd;
108 int error;
109}
110bt_state;
155732f5 111
1ff101ff
JB
112static _Unwind_Reason_Code
113trace_function (struct _Unwind_Context *context, void *state_ptr)
114{
115 bt_state* state = (bt_state*) state_ptr;
116 _Unwind_Ptr ip;
117#ifdef HAVE_GETIPINFO
118 int ip_before_insn = 0;
119 ip = _Unwind_GetIPInfo (context, &ip_before_insn);
120
121 /* If the unwinder gave us a 'return' address, roll it back a little
122 to ensure we get the correct line number for the call itself. */
123 if (! ip_before_insn)
124 --ip;
125#else
126 ip = _Unwind_GetIP (context);
127#endif
128
129 if (state->direct_output)
130 {
131 bt_header(state->frame_number);
132 st_printf ("%p\n", (void*) ip);
133 }
134 else
135 {
136 char addr_buf[GFC_XTOA_BUF_SIZE], func[1024], file[PATH_MAX];
137 char *p;
138 const char* addr = gfc_xtoa (ip, addr_buf, sizeof (addr_buf));
139 write (state->outfd, addr, strlen (addr));
140 write (state->outfd, "\n", 1);
141
142 if (! fd_gets (func, sizeof(func), state->infd))
143 {
144 state->error = 1;
145 goto done;
146 }
147 if (! fd_gets (file, sizeof(file), state->infd))
148 {
149 state->error = 1;
150 goto done;
151 }
152
153 for (p = func; *p != '\n' && *p != '\r'; p++)
154 ;
155 *p = '\0';
156
157 /* _start is a setup routine that calls main(), and main() is
158 the frontend routine that calls some setup stuff and then
159 calls MAIN__, so at this point we should stop. */
160 if (strcmp (func, "_start") == 0 || strcmp (func, "main") == 0)
161 return _URC_END_OF_STACK;
162
163 bt_header (state->frame_number);
164 estr_write ("0x");
165 estr_write (addr);
166
167 if (func[0] != '?' && func[1] != '?')
168 {
169 estr_write (" in ");
170 estr_write (func);
171 }
172
173 if (strncmp (file, "??", 2) == 0)
174 estr_write ("\n");
175 else
176 {
177 estr_write (" at ");
178 estr_write (file);
179 }
180 }
181
182 done:
183
184 state->frame_number++;
185
186 return _URC_NO_REASON;
187}
188
189
190/* Display the backtrace. */
eec2794c 191
868d75db 192void
f0f67c96 193backtrace (void)
868d75db 194{
1ff101ff
JB
195 bt_state state;
196 state.frame_number = 0;
197 state.error = 0;
868d75db 198
868d75db
FXC
199#if CAN_PIPE
200
155732f5
JB
201 if (addr2line_path == NULL)
202 goto fallback_noerr;
203
868d75db
FXC
204 /* We attempt to extract file and line information from addr2line. */
205 do
206 {
207 /* Local variables. */
1ff101ff 208 int f[2], pid, inp[2];
868d75db
FXC
209
210 /* Don't output an error message if something goes wrong, we'll simply
161f270d 211 fall back to printing the addresses. */
868d75db
FXC
212 if (pipe (f) != 0)
213 break;
eec2794c
JB
214 if (pipe (inp) != 0)
215 break;
868d75db
FXC
216 if ((pid = fork ()) == -1)
217 break;
218
219 if (pid == 0)
220 {
221 /* Child process. */
eec2794c
JB
222#define NUM_FIXEDARGS 7
223 char *arg[NUM_FIXEDARGS];
155732f5 224 char *newenv[] = { NULL };
868d75db
FXC
225
226 close (f[0]);
eec2794c
JB
227
228 close (inp[1]);
229 if (dup2 (inp[0], STDIN_FILENO) == -1)
230 _exit (1);
231 close (inp[0]);
232
868d75db
FXC
233 close (STDERR_FILENO);
234
235 if (dup2 (f[1], STDOUT_FILENO) == -1)
eec2794c 236 _exit (1);
868d75db
FXC
237 close (f[1]);
238
155732f5 239 arg[0] = addr2line_path;
868d75db
FXC
240 arg[1] = (char *) "-e";
241 arg[2] = full_exe_path ();
242 arg[3] = (char *) "-f";
243 arg[4] = (char *) "-s";
eec2794c
JB
244 arg[5] = (char *) "-C";
245 arg[6] = NULL;
155732f5 246 execve (addr2line_path, arg, newenv);
eec2794c 247 _exit (1);
868d75db
FXC
248#undef NUM_FIXEDARGS
249 }
250
251 /* Father process. */
252 close (f[1]);
eec2794c 253 close (inp[0]);
868d75db 254
1ff101ff
JB
255 state.outfd = inp[1];
256 state.infd = f[0];
257 state.direct_output = 0;
258 _Unwind_Backtrace (trace_function, &state);
259 if (state.error)
260 goto fallback;
eec2794c 261 close (inp[1]);
f0f67c96 262 close (f[0]);
eec2794c
JB
263 wait (NULL);
264 return;
868d75db
FXC
265
266fallback:
eec2794c 267 estr_write ("** Something went wrong while running addr2line. **\n"
1ff101ff 268 "** Falling back to a simpler backtrace scheme. **\n");
eec2794c 269 }
868d75db
FXC
270 while (0);
271
7ed26a67 272fallback_noerr:
eec2794c
JB
273#endif /* CAN_PIPE */
274
1ff101ff
JB
275 /* Fallback to the simple backtrace without addr2line. */
276 state.direct_output = 1;
277 _Unwind_Backtrace (trace_function, &state);
868d75db 278}
f0f67c96 279iexport(backtrace);