1*4c3eb207Smrg /* Copyright (C) 2006-2020 Free Software Foundation, Inc.
2627f7eb2Smrg Contributed by François-Xavier Coudert
3627f7eb2Smrg
4627f7eb2Smrg This file is part of the GNU Fortran runtime library (libgfortran).
5627f7eb2Smrg
6627f7eb2Smrg Libgfortran is free software; you can redistribute it and/or modify
7627f7eb2Smrg it under the terms of the GNU General Public License as published by
8627f7eb2Smrg the Free Software Foundation; either version 3, or (at your option)
9627f7eb2Smrg any later version.
10627f7eb2Smrg
11627f7eb2Smrg Libgfortran is distributed in the hope that it will be useful,
12627f7eb2Smrg but WITHOUT ANY WARRANTY; without even the implied warranty of
13627f7eb2Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14627f7eb2Smrg GNU General Public License for more details.
15627f7eb2Smrg
16627f7eb2Smrg Under Section 7 of GPL version 3, you are granted additional
17627f7eb2Smrg permissions described in the GCC Runtime Library Exception, version
18627f7eb2Smrg 3.1, as published by the Free Software Foundation.
19627f7eb2Smrg
20627f7eb2Smrg You should have received a copy of the GNU General Public License and
21627f7eb2Smrg a copy of the GCC Runtime Library Exception along with this program;
22627f7eb2Smrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23627f7eb2Smrg <http://www.gnu.org/licenses/>. */
24627f7eb2Smrg
25627f7eb2Smrg #include "libgfortran.h"
26627f7eb2Smrg
27627f7eb2Smrg #include <gthr.h>
28627f7eb2Smrg
29627f7eb2Smrg #include <string.h>
30627f7eb2Smrg #include <errno.h>
31627f7eb2Smrg
32627f7eb2Smrg #ifdef HAVE_UNISTD_H
33627f7eb2Smrg #include <unistd.h>
34627f7eb2Smrg #endif
35627f7eb2Smrg
36627f7eb2Smrg #include "backtrace-supported.h"
37627f7eb2Smrg #include "backtrace.h"
38627f7eb2Smrg
39627f7eb2Smrg
40627f7eb2Smrg /* Store our own state while backtracing. */
41627f7eb2Smrg struct mystate
42627f7eb2Smrg {
43627f7eb2Smrg int frame;
44627f7eb2Smrg bool try_simple;
45627f7eb2Smrg bool in_signal_handler;
46627f7eb2Smrg };
47627f7eb2Smrg
48627f7eb2Smrg
49627f7eb2Smrg /* Does a function name have "_gfortran_" or "_gfortrani_" prefix, possibly
50627f7eb2Smrg with additional underscore(s) at the beginning? Cannot use strncmp()
51627f7eb2Smrg because we might be called from a signal handler. */
52627f7eb2Smrg
53627f7eb2Smrg static int
has_gfortran_prefix(const char * s)54627f7eb2Smrg has_gfortran_prefix (const char *s)
55627f7eb2Smrg {
56627f7eb2Smrg if (!s)
57627f7eb2Smrg return 0;
58627f7eb2Smrg
59627f7eb2Smrg while (*s == '_')
60627f7eb2Smrg s++;
61627f7eb2Smrg
62627f7eb2Smrg return (s[0] == 'g' && s[1] == 'f' && s[2] == 'o' && s[3] == 'r'
63627f7eb2Smrg && s[4] == 't' && s[5] == 'r' && s[6] == 'a' && s[7] == 'n'
64627f7eb2Smrg && (s[8] == '_' || (s[8] == 'i' && s[9] == '_')));
65627f7eb2Smrg }
66627f7eb2Smrg
67627f7eb2Smrg static void
error_callback(void * data,const char * msg,int errnum)68627f7eb2Smrg error_callback (void *data, const char *msg, int errnum)
69627f7eb2Smrg {
70627f7eb2Smrg struct mystate *state = (struct mystate *) data;
71627f7eb2Smrg struct iovec iov[5];
72627f7eb2Smrg #define ERRHDR "\nCould not print backtrace: "
73627f7eb2Smrg
74627f7eb2Smrg if (errnum < 0)
75627f7eb2Smrg {
76627f7eb2Smrg state->try_simple = true;
77627f7eb2Smrg return;
78627f7eb2Smrg }
79627f7eb2Smrg else if (errnum == 0)
80627f7eb2Smrg {
81627f7eb2Smrg iov[0].iov_base = (char*) ERRHDR;
82627f7eb2Smrg iov[0].iov_len = strlen (ERRHDR);
83627f7eb2Smrg iov[1].iov_base = (char*) msg;
84627f7eb2Smrg iov[1].iov_len = strlen (msg);
85627f7eb2Smrg iov[2].iov_base = (char*) "\n";
86627f7eb2Smrg iov[2].iov_len = 1;
87627f7eb2Smrg estr_writev (iov, 3);
88627f7eb2Smrg }
89627f7eb2Smrg else
90627f7eb2Smrg {
91627f7eb2Smrg char errbuf[256];
92627f7eb2Smrg if (state->in_signal_handler)
93627f7eb2Smrg {
94627f7eb2Smrg iov[0].iov_base = (char*) ERRHDR;
95627f7eb2Smrg iov[0].iov_len = strlen (ERRHDR);
96627f7eb2Smrg iov[1].iov_base = (char*) msg;
97627f7eb2Smrg iov[1].iov_len = strlen (msg);
98627f7eb2Smrg iov[2].iov_base = (char*) ", errno: ";
99627f7eb2Smrg iov[2].iov_len = strlen (iov[2].iov_base);
100627f7eb2Smrg const char *p = gfc_itoa (errnum, errbuf, sizeof (errbuf));
101627f7eb2Smrg iov[3].iov_base = (char*) p;
102627f7eb2Smrg iov[3].iov_len = strlen (p);
103627f7eb2Smrg iov[4].iov_base = (char*) "\n";
104627f7eb2Smrg iov[4].iov_len = 1;
105627f7eb2Smrg estr_writev (iov, 5);
106627f7eb2Smrg }
107627f7eb2Smrg else
108627f7eb2Smrg st_printf (ERRHDR "%s: %s\n", msg,
109627f7eb2Smrg gf_strerror (errnum, errbuf, sizeof (errbuf)));
110627f7eb2Smrg }
111627f7eb2Smrg }
112627f7eb2Smrg
113627f7eb2Smrg static int
simple_callback(void * data,uintptr_t pc)114627f7eb2Smrg simple_callback (void *data, uintptr_t pc)
115627f7eb2Smrg {
116627f7eb2Smrg struct mystate *state = (struct mystate *) data;
117627f7eb2Smrg st_printf ("#%d 0x%lx\n", state->frame, (unsigned long) pc);
118627f7eb2Smrg (state->frame)++;
119627f7eb2Smrg return 0;
120627f7eb2Smrg }
121627f7eb2Smrg
122627f7eb2Smrg static int
full_callback(void * data,uintptr_t pc,const char * filename,int lineno,const char * function)123627f7eb2Smrg full_callback (void *data, uintptr_t pc, const char *filename,
124627f7eb2Smrg int lineno, const char *function)
125627f7eb2Smrg {
126627f7eb2Smrg struct mystate *state = (struct mystate *) data;
127627f7eb2Smrg
128627f7eb2Smrg if (has_gfortran_prefix (function))
129627f7eb2Smrg return 0;
130627f7eb2Smrg
131627f7eb2Smrg st_printf ("#%d 0x%lx in %s\n", state->frame,
132627f7eb2Smrg (unsigned long) pc, function == NULL ? "???" : function);
133627f7eb2Smrg if (filename || lineno != 0)
134627f7eb2Smrg st_printf ("\tat %s:%d\n", filename == NULL ? "???" : filename, lineno);
135627f7eb2Smrg (state->frame)++;
136627f7eb2Smrg
137627f7eb2Smrg if (function != NULL && strcmp (function, "main") == 0)
138627f7eb2Smrg return 1;
139627f7eb2Smrg
140627f7eb2Smrg return 0;
141627f7eb2Smrg }
142627f7eb2Smrg
143627f7eb2Smrg
144627f7eb2Smrg /* Display the backtrace. */
145627f7eb2Smrg
146627f7eb2Smrg void
show_backtrace(bool in_signal_handler)147627f7eb2Smrg show_backtrace (bool in_signal_handler)
148627f7eb2Smrg {
149627f7eb2Smrg /* Note that libbacktrace allows the state to be accessed from
150627f7eb2Smrg multiple threads, so we don't need to use a TLS variable for the
151627f7eb2Smrg state here. */
152627f7eb2Smrg static struct backtrace_state *lbstate_saved;
153627f7eb2Smrg struct backtrace_state *lbstate;
154627f7eb2Smrg struct mystate state = { 0, false, in_signal_handler };
155627f7eb2Smrg
156627f7eb2Smrg lbstate = __atomic_load_n (&lbstate_saved, __ATOMIC_RELAXED);
157627f7eb2Smrg if (!lbstate)
158627f7eb2Smrg {
159627f7eb2Smrg lbstate = backtrace_create_state (NULL, __gthread_active_p (),
160627f7eb2Smrg error_callback, NULL);
161627f7eb2Smrg if (lbstate)
162627f7eb2Smrg __atomic_store_n (&lbstate_saved, lbstate, __ATOMIC_RELAXED);
163627f7eb2Smrg else
164627f7eb2Smrg return;
165627f7eb2Smrg }
166627f7eb2Smrg
167627f7eb2Smrg if (!BACKTRACE_SUPPORTED || (in_signal_handler && BACKTRACE_USES_MALLOC))
168627f7eb2Smrg {
169627f7eb2Smrg /* If symbolic backtrace is not supported on this target, or would
170627f7eb2Smrg require malloc() and we are in a signal handler, go with a
171627f7eb2Smrg simple backtrace. */
172627f7eb2Smrg
173627f7eb2Smrg backtrace_simple (lbstate, 0, simple_callback, error_callback, &state);
174627f7eb2Smrg }
175627f7eb2Smrg else
176627f7eb2Smrg {
177627f7eb2Smrg /* libbacktrace uses mmap, which is safe to call from a signal handler
178627f7eb2Smrg (in practice, if not in theory). Thus we can generate a symbolic
179627f7eb2Smrg backtrace, if debug symbols are available. */
180627f7eb2Smrg
181627f7eb2Smrg backtrace_full (lbstate, 0, full_callback, error_callback, &state);
182627f7eb2Smrg if (state.try_simple)
183627f7eb2Smrg backtrace_simple (lbstate, 0, simple_callback, error_callback, &state);
184627f7eb2Smrg }
185627f7eb2Smrg }
186627f7eb2Smrg
187627f7eb2Smrg
188627f7eb2Smrg
189627f7eb2Smrg /* Function called by the front-end translating the BACKTRACE intrinsic. */
190627f7eb2Smrg
191627f7eb2Smrg extern void backtrace (void);
192627f7eb2Smrg export_proto (backtrace);
193627f7eb2Smrg
194627f7eb2Smrg void
backtrace(void)195627f7eb2Smrg backtrace (void)
196627f7eb2Smrg {
197627f7eb2Smrg show_backtrace (false);
198627f7eb2Smrg }
199627f7eb2Smrg
200