xref: /netbsd-src/external/gpl3/gcc.old/dist/libgfortran/runtime/backtrace.c (revision 4c3eb207d36f67d31994830c0a694161fc1ca39b)
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