xref: /netbsd-src/external/gpl3/gcc/dist/libgfortran/runtime/backtrace.c (revision b1e838363e3c6fc78a55519254d99869742dd33c)
1*b1e83836Smrg /* Copyright (C) 2006-2022 Free Software Foundation, Inc.
2181254a7Smrg    Contributed by François-Xavier Coudert
3181254a7Smrg 
4181254a7Smrg This file is part of the GNU Fortran runtime library (libgfortran).
5181254a7Smrg 
6181254a7Smrg Libgfortran is free software; you can redistribute it and/or modify
7181254a7Smrg it under the terms of the GNU General Public License as published by
8181254a7Smrg the Free Software Foundation; either version 3, or (at your option)
9181254a7Smrg any later version.
10181254a7Smrg 
11181254a7Smrg Libgfortran is distributed in the hope that it will be useful,
12181254a7Smrg but WITHOUT ANY WARRANTY; without even the implied warranty of
13181254a7Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14181254a7Smrg GNU General Public License for more details.
15181254a7Smrg 
16181254a7Smrg Under Section 7 of GPL version 3, you are granted additional
17181254a7Smrg permissions described in the GCC Runtime Library Exception, version
18181254a7Smrg 3.1, as published by the Free Software Foundation.
19181254a7Smrg 
20181254a7Smrg You should have received a copy of the GNU General Public License and
21181254a7Smrg a copy of the GCC Runtime Library Exception along with this program;
22181254a7Smrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23181254a7Smrg <http://www.gnu.org/licenses/>.  */
24181254a7Smrg 
25181254a7Smrg #include "libgfortran.h"
26181254a7Smrg 
27181254a7Smrg #include <gthr.h>
28181254a7Smrg 
29181254a7Smrg #include <string.h>
30181254a7Smrg #include <errno.h>
31181254a7Smrg 
32181254a7Smrg #ifdef HAVE_UNISTD_H
33181254a7Smrg #include <unistd.h>
34181254a7Smrg #endif
35181254a7Smrg 
36181254a7Smrg #include "backtrace-supported.h"
37181254a7Smrg #include "backtrace.h"
38181254a7Smrg 
39181254a7Smrg 
40181254a7Smrg /* Store our own state while backtracing.  */
41181254a7Smrg struct mystate
42181254a7Smrg {
43181254a7Smrg   int frame;
44181254a7Smrg   bool try_simple;
45181254a7Smrg   bool in_signal_handler;
46181254a7Smrg };
47181254a7Smrg 
48181254a7Smrg 
49181254a7Smrg /* Does a function name have "_gfortran_" or "_gfortrani_" prefix, possibly
50181254a7Smrg    with additional underscore(s) at the beginning?  Cannot use strncmp()
51181254a7Smrg    because we might be called from a signal handler.  */
52181254a7Smrg 
53181254a7Smrg static int
has_gfortran_prefix(const char * s)54181254a7Smrg has_gfortran_prefix (const char *s)
55181254a7Smrg {
56181254a7Smrg   if (!s)
57181254a7Smrg     return 0;
58181254a7Smrg 
59181254a7Smrg   while (*s == '_')
60181254a7Smrg     s++;
61181254a7Smrg 
62181254a7Smrg   return (s[0] == 'g' && s[1] == 'f' && s[2] == 'o' && s[3] == 'r'
63181254a7Smrg 	  && s[4] == 't' && s[5] == 'r' && s[6] == 'a' && s[7] == 'n'
64181254a7Smrg 	  && (s[8] == '_' || (s[8] == 'i' && s[9] == '_')));
65181254a7Smrg }
66181254a7Smrg 
67181254a7Smrg static void
error_callback(void * data,const char * msg,int errnum)68181254a7Smrg error_callback (void *data, const char *msg, int errnum)
69181254a7Smrg {
70181254a7Smrg   struct mystate *state = (struct mystate *) data;
71181254a7Smrg   struct iovec iov[5];
72181254a7Smrg #define ERRHDR "\nCould not print backtrace: "
73181254a7Smrg 
74181254a7Smrg   if (errnum < 0)
75181254a7Smrg     {
76181254a7Smrg       state->try_simple = true;
77181254a7Smrg       return;
78181254a7Smrg     }
79181254a7Smrg   else if (errnum == 0)
80181254a7Smrg     {
81181254a7Smrg       iov[0].iov_base = (char*) ERRHDR;
82181254a7Smrg       iov[0].iov_len = strlen (ERRHDR);
83181254a7Smrg       iov[1].iov_base = (char*) msg;
84181254a7Smrg       iov[1].iov_len = strlen (msg);
85181254a7Smrg       iov[2].iov_base = (char*) "\n";
86181254a7Smrg       iov[2].iov_len = 1;
87181254a7Smrg       estr_writev (iov, 3);
88181254a7Smrg     }
89181254a7Smrg   else
90181254a7Smrg     {
91181254a7Smrg       char errbuf[256];
92181254a7Smrg       if (state->in_signal_handler)
93181254a7Smrg 	{
94181254a7Smrg 	  iov[0].iov_base = (char*) ERRHDR;
95181254a7Smrg 	  iov[0].iov_len = strlen (ERRHDR);
96181254a7Smrg 	  iov[1].iov_base = (char*) msg;
97181254a7Smrg 	  iov[1].iov_len = strlen (msg);
98181254a7Smrg 	  iov[2].iov_base = (char*) ", errno: ";
99181254a7Smrg 	  iov[2].iov_len = strlen (iov[2].iov_base);
100*b1e83836Smrg 	  /* Async-signal-safe function, errnum must be positive.  */
101181254a7Smrg 	  const char *p = gfc_itoa (errnum, errbuf, sizeof (errbuf));
102181254a7Smrg 	  iov[3].iov_base = (char*) p;
103181254a7Smrg 	  iov[3].iov_len = strlen (p);
104181254a7Smrg 	  iov[4].iov_base = (char*) "\n";
105181254a7Smrg 	  iov[4].iov_len = 1;
106181254a7Smrg 	  estr_writev (iov, 5);
107181254a7Smrg 	}
108181254a7Smrg       else
109181254a7Smrg 	st_printf (ERRHDR "%s: %s\n", msg,
110181254a7Smrg 		  gf_strerror (errnum, errbuf, sizeof (errbuf)));
111181254a7Smrg     }
112181254a7Smrg }
113181254a7Smrg 
114181254a7Smrg static int
simple_callback(void * data,uintptr_t pc)115181254a7Smrg simple_callback (void *data, uintptr_t pc)
116181254a7Smrg {
117181254a7Smrg   struct mystate *state = (struct mystate *) data;
118181254a7Smrg   st_printf ("#%d  0x%lx\n", state->frame, (unsigned long) pc);
119181254a7Smrg   (state->frame)++;
120181254a7Smrg   return 0;
121181254a7Smrg }
122181254a7Smrg 
123181254a7Smrg static int
full_callback(void * data,uintptr_t pc,const char * filename,int lineno,const char * function)124181254a7Smrg full_callback (void *data, uintptr_t pc, const char *filename,
125181254a7Smrg 	       int lineno, const char *function)
126181254a7Smrg {
127181254a7Smrg   struct mystate *state = (struct mystate *) data;
128181254a7Smrg 
129181254a7Smrg   if (has_gfortran_prefix (function))
130181254a7Smrg     return 0;
131181254a7Smrg 
132181254a7Smrg   st_printf ("#%d  0x%lx in %s\n", state->frame,
133181254a7Smrg 	     (unsigned long) pc, function == NULL ? "???" : function);
134181254a7Smrg   if (filename || lineno != 0)
135181254a7Smrg     st_printf ("\tat %s:%d\n", filename == NULL ? "???" : filename, lineno);
136181254a7Smrg   (state->frame)++;
137181254a7Smrg 
138181254a7Smrg   if (function != NULL && strcmp (function, "main") == 0)
139181254a7Smrg     return 1;
140181254a7Smrg 
141181254a7Smrg   return 0;
142181254a7Smrg }
143181254a7Smrg 
144181254a7Smrg 
145181254a7Smrg /* Display the backtrace.  */
146181254a7Smrg 
147181254a7Smrg void
show_backtrace(bool in_signal_handler)148181254a7Smrg show_backtrace (bool in_signal_handler)
149181254a7Smrg {
150181254a7Smrg   /* Note that libbacktrace allows the state to be accessed from
151181254a7Smrg      multiple threads, so we don't need to use a TLS variable for the
152181254a7Smrg      state here.  */
153181254a7Smrg   static struct backtrace_state *lbstate_saved;
154181254a7Smrg   struct backtrace_state *lbstate;
155181254a7Smrg   struct mystate state = { 0, false, in_signal_handler };
156181254a7Smrg 
157181254a7Smrg   lbstate = __atomic_load_n (&lbstate_saved, __ATOMIC_RELAXED);
158181254a7Smrg   if (!lbstate)
159181254a7Smrg     {
160181254a7Smrg       lbstate = backtrace_create_state (NULL, __gthread_active_p (),
161181254a7Smrg 					error_callback, NULL);
162181254a7Smrg       if (lbstate)
163181254a7Smrg 	__atomic_store_n (&lbstate_saved, lbstate, __ATOMIC_RELAXED);
164181254a7Smrg       else
165181254a7Smrg 	return;
166181254a7Smrg     }
167181254a7Smrg 
168181254a7Smrg   if (!BACKTRACE_SUPPORTED || (in_signal_handler && BACKTRACE_USES_MALLOC))
169181254a7Smrg     {
170181254a7Smrg       /* If symbolic backtrace is not supported on this target, or would
171181254a7Smrg 	 require malloc() and we are in a signal handler, go with a
172181254a7Smrg 	 simple backtrace.  */
173181254a7Smrg 
174181254a7Smrg       backtrace_simple (lbstate, 0, simple_callback, error_callback, &state);
175181254a7Smrg     }
176181254a7Smrg   else
177181254a7Smrg     {
178181254a7Smrg       /* libbacktrace uses mmap, which is safe to call from a signal handler
179181254a7Smrg 	 (in practice, if not in theory).  Thus we can generate a symbolic
180181254a7Smrg 	 backtrace, if debug symbols are available.  */
181181254a7Smrg 
182181254a7Smrg       backtrace_full (lbstate, 0, full_callback, error_callback, &state);
183181254a7Smrg       if (state.try_simple)
184181254a7Smrg 	backtrace_simple (lbstate, 0, simple_callback, error_callback, &state);
185181254a7Smrg     }
186181254a7Smrg }
187181254a7Smrg 
188181254a7Smrg 
189181254a7Smrg 
190181254a7Smrg /* Function called by the front-end translating the BACKTRACE intrinsic.  */
191181254a7Smrg 
192181254a7Smrg extern void backtrace (void);
193181254a7Smrg export_proto (backtrace);
194181254a7Smrg 
195181254a7Smrg void
backtrace(void)196181254a7Smrg backtrace (void)
197181254a7Smrg {
198181254a7Smrg   show_backtrace (false);
199181254a7Smrg }
200181254a7Smrg 
201