annotate libgfortran/runtime/backtrace.c @ 158:494b0b89df80 default tip

...
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 25 May 2020 18:13:55 +0900
parents 1830386684a0
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1 /* Copyright (C) 2006-2020 Free Software Foundation, Inc.
111
kono
parents:
diff changeset
2 Contributed by François-Xavier Coudert
kono
parents:
diff changeset
3
kono
parents:
diff changeset
4 This file is part of the GNU Fortran runtime library (libgfortran).
kono
parents:
diff changeset
5
kono
parents:
diff changeset
6 Libgfortran is free software; you can redistribute it and/or modify
kono
parents:
diff changeset
7 it under the terms of the GNU General Public License as published by
kono
parents:
diff changeset
8 the Free Software Foundation; either version 3, or (at your option)
kono
parents:
diff changeset
9 any later version.
kono
parents:
diff changeset
10
kono
parents:
diff changeset
11 Libgfortran is distributed in the hope that it will be useful,
kono
parents:
diff changeset
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
kono
parents:
diff changeset
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
kono
parents:
diff changeset
14 GNU General Public License for more details.
kono
parents:
diff changeset
15
kono
parents:
diff changeset
16 Under Section 7 of GPL version 3, you are granted additional
kono
parents:
diff changeset
17 permissions described in the GCC Runtime Library Exception, version
kono
parents:
diff changeset
18 3.1, as published by the Free Software Foundation.
kono
parents:
diff changeset
19
kono
parents:
diff changeset
20 You should have received a copy of the GNU General Public License and
kono
parents:
diff changeset
21 a copy of the GCC Runtime Library Exception along with this program;
kono
parents:
diff changeset
22 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
kono
parents:
diff changeset
23 <http://www.gnu.org/licenses/>. */
kono
parents:
diff changeset
24
kono
parents:
diff changeset
25 #include "libgfortran.h"
kono
parents:
diff changeset
26
kono
parents:
diff changeset
27 #include <gthr.h>
kono
parents:
diff changeset
28
kono
parents:
diff changeset
29 #include <string.h>
kono
parents:
diff changeset
30 #include <errno.h>
kono
parents:
diff changeset
31
kono
parents:
diff changeset
32 #ifdef HAVE_UNISTD_H
kono
parents:
diff changeset
33 #include <unistd.h>
kono
parents:
diff changeset
34 #endif
kono
parents:
diff changeset
35
kono
parents:
diff changeset
36 #include "backtrace-supported.h"
kono
parents:
diff changeset
37 #include "backtrace.h"
kono
parents:
diff changeset
38
kono
parents:
diff changeset
39
kono
parents:
diff changeset
40 /* Store our own state while backtracing. */
kono
parents:
diff changeset
41 struct mystate
kono
parents:
diff changeset
42 {
kono
parents:
diff changeset
43 int frame;
kono
parents:
diff changeset
44 bool try_simple;
kono
parents:
diff changeset
45 bool in_signal_handler;
kono
parents:
diff changeset
46 };
kono
parents:
diff changeset
47
kono
parents:
diff changeset
48
kono
parents:
diff changeset
49 /* Does a function name have "_gfortran_" or "_gfortrani_" prefix, possibly
kono
parents:
diff changeset
50 with additional underscore(s) at the beginning? Cannot use strncmp()
kono
parents:
diff changeset
51 because we might be called from a signal handler. */
kono
parents:
diff changeset
52
kono
parents:
diff changeset
53 static int
kono
parents:
diff changeset
54 has_gfortran_prefix (const char *s)
kono
parents:
diff changeset
55 {
kono
parents:
diff changeset
56 if (!s)
kono
parents:
diff changeset
57 return 0;
kono
parents:
diff changeset
58
kono
parents:
diff changeset
59 while (*s == '_')
kono
parents:
diff changeset
60 s++;
kono
parents:
diff changeset
61
kono
parents:
diff changeset
62 return (s[0] == 'g' && s[1] == 'f' && s[2] == 'o' && s[3] == 'r'
kono
parents:
diff changeset
63 && s[4] == 't' && s[5] == 'r' && s[6] == 'a' && s[7] == 'n'
kono
parents:
diff changeset
64 && (s[8] == '_' || (s[8] == 'i' && s[9] == '_')));
kono
parents:
diff changeset
65 }
kono
parents:
diff changeset
66
kono
parents:
diff changeset
67 static void
kono
parents:
diff changeset
68 error_callback (void *data, const char *msg, int errnum)
kono
parents:
diff changeset
69 {
kono
parents:
diff changeset
70 struct mystate *state = (struct mystate *) data;
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
71 struct iovec iov[5];
111
kono
parents:
diff changeset
72 #define ERRHDR "\nCould not print backtrace: "
kono
parents:
diff changeset
73
kono
parents:
diff changeset
74 if (errnum < 0)
kono
parents:
diff changeset
75 {
kono
parents:
diff changeset
76 state->try_simple = true;
kono
parents:
diff changeset
77 return;
kono
parents:
diff changeset
78 }
kono
parents:
diff changeset
79 else if (errnum == 0)
kono
parents:
diff changeset
80 {
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
81 iov[0].iov_base = (char*) ERRHDR;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
82 iov[0].iov_len = strlen (ERRHDR);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
83 iov[1].iov_base = (char*) msg;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
84 iov[1].iov_len = strlen (msg);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
85 iov[2].iov_base = (char*) "\n";
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
86 iov[2].iov_len = 1;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
87 estr_writev (iov, 3);
111
kono
parents:
diff changeset
88 }
kono
parents:
diff changeset
89 else
kono
parents:
diff changeset
90 {
kono
parents:
diff changeset
91 char errbuf[256];
kono
parents:
diff changeset
92 if (state->in_signal_handler)
kono
parents:
diff changeset
93 {
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
94 iov[0].iov_base = (char*) ERRHDR;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
95 iov[0].iov_len = strlen (ERRHDR);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
96 iov[1].iov_base = (char*) msg;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
97 iov[1].iov_len = strlen (msg);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
98 iov[2].iov_base = (char*) ", errno: ";
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
99 iov[2].iov_len = strlen (iov[2].iov_base);
111
kono
parents:
diff changeset
100 const char *p = gfc_itoa (errnum, errbuf, sizeof (errbuf));
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
101 iov[3].iov_base = (char*) p;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
102 iov[3].iov_len = strlen (p);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
103 iov[4].iov_base = (char*) "\n";
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
104 iov[4].iov_len = 1;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
105 estr_writev (iov, 5);
111
kono
parents:
diff changeset
106 }
kono
parents:
diff changeset
107 else
kono
parents:
diff changeset
108 st_printf (ERRHDR "%s: %s\n", msg,
kono
parents:
diff changeset
109 gf_strerror (errnum, errbuf, sizeof (errbuf)));
kono
parents:
diff changeset
110 }
kono
parents:
diff changeset
111 }
kono
parents:
diff changeset
112
kono
parents:
diff changeset
113 static int
kono
parents:
diff changeset
114 simple_callback (void *data, uintptr_t pc)
kono
parents:
diff changeset
115 {
kono
parents:
diff changeset
116 struct mystate *state = (struct mystate *) data;
kono
parents:
diff changeset
117 st_printf ("#%d 0x%lx\n", state->frame, (unsigned long) pc);
kono
parents:
diff changeset
118 (state->frame)++;
kono
parents:
diff changeset
119 return 0;
kono
parents:
diff changeset
120 }
kono
parents:
diff changeset
121
kono
parents:
diff changeset
122 static int
kono
parents:
diff changeset
123 full_callback (void *data, uintptr_t pc, const char *filename,
kono
parents:
diff changeset
124 int lineno, const char *function)
kono
parents:
diff changeset
125 {
kono
parents:
diff changeset
126 struct mystate *state = (struct mystate *) data;
kono
parents:
diff changeset
127
kono
parents:
diff changeset
128 if (has_gfortran_prefix (function))
kono
parents:
diff changeset
129 return 0;
kono
parents:
diff changeset
130
kono
parents:
diff changeset
131 st_printf ("#%d 0x%lx in %s\n", state->frame,
kono
parents:
diff changeset
132 (unsigned long) pc, function == NULL ? "???" : function);
kono
parents:
diff changeset
133 if (filename || lineno != 0)
kono
parents:
diff changeset
134 st_printf ("\tat %s:%d\n", filename == NULL ? "???" : filename, lineno);
kono
parents:
diff changeset
135 (state->frame)++;
kono
parents:
diff changeset
136
kono
parents:
diff changeset
137 if (function != NULL && strcmp (function, "main") == 0)
kono
parents:
diff changeset
138 return 1;
kono
parents:
diff changeset
139
kono
parents:
diff changeset
140 return 0;
kono
parents:
diff changeset
141 }
kono
parents:
diff changeset
142
kono
parents:
diff changeset
143
kono
parents:
diff changeset
144 /* Display the backtrace. */
kono
parents:
diff changeset
145
kono
parents:
diff changeset
146 void
kono
parents:
diff changeset
147 show_backtrace (bool in_signal_handler)
kono
parents:
diff changeset
148 {
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
149 /* Note that libbacktrace allows the state to be accessed from
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
150 multiple threads, so we don't need to use a TLS variable for the
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
151 state here. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
152 static struct backtrace_state *lbstate_saved;
111
kono
parents:
diff changeset
153 struct backtrace_state *lbstate;
kono
parents:
diff changeset
154 struct mystate state = { 0, false, in_signal_handler };
kono
parents:
diff changeset
155
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
156 lbstate = __atomic_load_n (&lbstate_saved, __ATOMIC_RELAXED);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
157 if (!lbstate)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
158 {
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
159 lbstate = backtrace_create_state (NULL, __gthread_active_p (),
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
160 error_callback, NULL);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
161 if (lbstate)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
162 __atomic_store_n (&lbstate_saved, lbstate, __ATOMIC_RELAXED);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
163 else
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
164 return;
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
165 }
111
kono
parents:
diff changeset
166
kono
parents:
diff changeset
167 if (!BACKTRACE_SUPPORTED || (in_signal_handler && BACKTRACE_USES_MALLOC))
kono
parents:
diff changeset
168 {
kono
parents:
diff changeset
169 /* If symbolic backtrace is not supported on this target, or would
kono
parents:
diff changeset
170 require malloc() and we are in a signal handler, go with a
kono
parents:
diff changeset
171 simple backtrace. */
kono
parents:
diff changeset
172
kono
parents:
diff changeset
173 backtrace_simple (lbstate, 0, simple_callback, error_callback, &state);
kono
parents:
diff changeset
174 }
kono
parents:
diff changeset
175 else
kono
parents:
diff changeset
176 {
kono
parents:
diff changeset
177 /* libbacktrace uses mmap, which is safe to call from a signal handler
kono
parents:
diff changeset
178 (in practice, if not in theory). Thus we can generate a symbolic
kono
parents:
diff changeset
179 backtrace, if debug symbols are available. */
kono
parents:
diff changeset
180
kono
parents:
diff changeset
181 backtrace_full (lbstate, 0, full_callback, error_callback, &state);
kono
parents:
diff changeset
182 if (state.try_simple)
kono
parents:
diff changeset
183 backtrace_simple (lbstate, 0, simple_callback, error_callback, &state);
kono
parents:
diff changeset
184 }
kono
parents:
diff changeset
185 }
kono
parents:
diff changeset
186
kono
parents:
diff changeset
187
kono
parents:
diff changeset
188
kono
parents:
diff changeset
189 /* Function called by the front-end translating the BACKTRACE intrinsic. */
kono
parents:
diff changeset
190
kono
parents:
diff changeset
191 extern void backtrace (void);
kono
parents:
diff changeset
192 export_proto (backtrace);
kono
parents:
diff changeset
193
kono
parents:
diff changeset
194 void
kono
parents:
diff changeset
195 backtrace (void)
kono
parents:
diff changeset
196 {
kono
parents:
diff changeset
197 show_backtrace (false);
kono
parents:
diff changeset
198 }
kono
parents:
diff changeset
199