re PR libfortran/54572 (Use libbacktrace library)
[gcc.git] / libgfortran / runtime / backtrace.c
1 /* Copyright (C) 2006-2015 Free Software Foundation, Inc.
2 Contributed by François-Xavier Coudert
3
4 This file is part of the GNU Fortran runtime library (libgfortran).
5
6 Libgfortran is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
10
11 Libgfortran is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 Under Section 7 of GPL version 3, you are granted additional
17 permissions described in the GCC Runtime Library Exception, version
18 3.1, as published by the Free Software Foundation.
19
20 You should have received a copy of the GNU General Public License and
21 a copy of the GCC Runtime Library Exception along with this program;
22 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 <http://www.gnu.org/licenses/>. */
24
25 #include "libgfortran.h"
26
27 #include <string.h>
28 #include <stdlib.h>
29
30 #ifdef HAVE_UNISTD_H
31 #include <unistd.h>
32 #endif
33
34 #include "backtrace-supported.h"
35 #include "backtrace.h"
36
37
38 /* Store our own state while backtracing. */
39 struct mystate
40 {
41 int try_simple;
42 int frame;
43 };
44
45
46 /* Does a function name have "_gfortran_" or "_gfortrani_" prefix, possibly
47 with additional underscore(s) at the beginning? Cannot use strncmp()
48 because we might be called from a signal handler. */
49
50 static int
51 has_gfortran_prefix (const char *s)
52 {
53 if (!s)
54 return 0;
55
56 while (*s == '_')
57 s++;
58
59 return (s[0] == 'g' && s[1] == 'f' && s[2] == 'o' && s[3] == 'r'
60 && s[4] == 't' && s[5] == 'r' && s[6] == 'a' && s[7] == 'n'
61 && (s[8] == '_' || (s[8] == 'i' && s[9] == '_')));
62 }
63
64 static void
65 error_callback (void *data, const char *msg, int errnum)
66 {
67 struct mystate *state = (struct mystate *) data;
68 if (errnum < 0)
69 {
70 state->try_simple = 1;
71 return;
72 }
73
74 estr_write ("\nSomething went wrong while printing the backtrace: ");
75 estr_write (msg);
76 estr_write ("\n");
77 }
78
79 static int
80 simple_callback (void *data, uintptr_t pc)
81 {
82 struct mystate *state = (struct mystate *) data;
83 st_printf ("#%d 0x%lx\n", state->frame, (unsigned long) pc);
84 (state->frame)++;
85 return 0;
86 }
87
88 static int
89 full_callback (void *data, uintptr_t pc, const char *filename,
90 int lineno, const char *function)
91 {
92 struct mystate *state = (struct mystate *) data;
93
94 if (has_gfortran_prefix (function))
95 return 0;
96
97 st_printf ("#%d 0x%lx in %s\n", state->frame,
98 (unsigned long) pc, function == NULL ? "???" : function);
99 if (filename || lineno != 0)
100 st_printf ("\tat %s:%d\n", filename == NULL ? "???" : filename, lineno);
101 (state->frame)++;
102
103 if (function != NULL && strcmp (function, "main") == 0)
104 return 1;
105
106 return 0;
107 }
108
109
110 /* Display the backtrace. */
111
112 void
113 show_backtrace (int in_signal_handler)
114 {
115 struct backtrace_state *lbstate;
116 struct mystate state = { 0, 0 };
117
118 lbstate = backtrace_create_state (NULL, 1, error_callback, NULL);
119
120 if (!BACKTRACE_SUPPORTED || (in_signal_handler && BACKTRACE_USES_MALLOC))
121 {
122 /* If symbolic backtrace is not supported on this target, or would
123 require malloc() and we are in a signal handler, go with a
124 simple backtrace. */
125
126 backtrace_simple (lbstate, 0, simple_callback, error_callback, &state);
127 }
128 else
129 {
130 /* libbacktrace uses mmap, which is safe to call from a signal handler
131 (in practice, if not in theory). Thus we can generate a symbolic
132 backtrace, if debug symbols are available. */
133
134 backtrace_full (lbstate, 0, full_callback, error_callback, &state);
135 if (state.try_simple)
136 backtrace_simple (lbstate, 0, simple_callback, error_callback, &state);
137 }
138 }
139
140
141
142 /* Function called by the front-end translating the BACKTRACE intrinsic. */
143
144 extern void backtrace (void);
145 export_proto (backtrace);
146
147 void
148 backtrace (void)
149 {
150 show_backtrace (0);
151 }
152