]> git.ipfire.org Git - thirdparty/gcc.git/blob - libbacktrace/fileline.c
Fix parsing of SVN commits in PRs.
[thirdparty/gcc.git] / libbacktrace / fileline.c
1 /* fileline.c -- Get file and line number information in a backtrace.
2 Copyright (C) 2012-2020 Free Software Foundation, Inc.
3 Written by Ian Lance Taylor, Google.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
8
9 (1) Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11
12 (2) Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in
14 the documentation and/or other materials provided with the
15 distribution.
16
17 (3) The name of the author may not be used to
18 endorse or promote products derived from this software without
19 specific prior written permission.
20
21 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
25 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30 IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE. */
32
33 #include "config.h"
34
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <stdlib.h>
40 #include <unistd.h>
41
42 #if defined (HAVE_KERN_PROC_ARGS) || defined (HAVE_KERN_PROC)
43 #include <sys/sysctl.h>
44 #endif
45
46 #include "backtrace.h"
47 #include "internal.h"
48
49 #ifndef HAVE_GETEXECNAME
50 #define getexecname() NULL
51 #endif
52
53 #if !defined (HAVE_KERN_PROC_ARGS) && !defined (HAVE_KERN_PROC)
54
55 #define sysctl_exec_name1(state, error_callback, data) NULL
56 #define sysctl_exec_name2(state, error_callback, data) NULL
57
58 #else /* defined (HAVE_KERN_PROC_ARGS) || |defined (HAVE_KERN_PROC) */
59
60 static char *
61 sysctl_exec_name (struct backtrace_state *state,
62 int mib0, int mib1, int mib2, int mib3,
63 backtrace_error_callback error_callback, void *data)
64 {
65 int mib[4];
66 size_t len;
67 char *name;
68 size_t rlen;
69
70 mib[0] = mib0;
71 mib[1] = mib1;
72 mib[2] = mib2;
73 mib[3] = mib3;
74
75 if (sysctl (mib, 4, NULL, &len, NULL, 0) < 0)
76 return NULL;
77 name = (char *) backtrace_alloc (state, len, error_callback, data);
78 if (name == NULL)
79 return NULL;
80 rlen = len;
81 if (sysctl (mib, 4, name, &rlen, NULL, 0) < 0)
82 {
83 backtrace_free (state, name, len, error_callback, data);
84 return NULL;
85 }
86 return name;
87 }
88
89 #ifdef HAVE_KERN_PROC_ARGS
90
91 static char *
92 sysctl_exec_name1 (struct backtrace_state *state,
93 backtrace_error_callback error_callback, void *data)
94 {
95 /* This variant is used on NetBSD. */
96 return sysctl_exec_name (state, CTL_KERN, KERN_PROC_ARGS, -1,
97 KERN_PROC_PATHNAME, error_callback, data);
98 }
99
100 #else
101
102 #define sysctl_exec_name1(state, error_callback, data) NULL
103
104 #endif
105
106 #ifdef HAVE_KERN_PROC
107
108 static char *
109 sysctl_exec_name2 (struct backtrace_state *state,
110 backtrace_error_callback error_callback, void *data)
111 {
112 /* This variant is used on FreeBSD. */
113 return sysctl_exec_name (state, CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1,
114 error_callback, data);
115 }
116
117 #else
118
119 #define sysctl_exec_name2(state, error_callback, data) NULL
120
121 #endif
122
123 #endif /* defined (HAVE_KERN_PROC_ARGS) || |defined (HAVE_KERN_PROC) */
124
125 /* Initialize the fileline information from the executable. Returns 1
126 on success, 0 on failure. */
127
128 static int
129 fileline_initialize (struct backtrace_state *state,
130 backtrace_error_callback error_callback, void *data)
131 {
132 int failed;
133 fileline fileline_fn;
134 int pass;
135 int called_error_callback;
136 int descriptor;
137 const char *filename;
138 char buf[64];
139
140 if (!state->threaded)
141 failed = state->fileline_initialization_failed;
142 else
143 failed = backtrace_atomic_load_int (&state->fileline_initialization_failed);
144
145 if (failed)
146 {
147 error_callback (data, "failed to read executable information", -1);
148 return 0;
149 }
150
151 if (!state->threaded)
152 fileline_fn = state->fileline_fn;
153 else
154 fileline_fn = backtrace_atomic_load_pointer (&state->fileline_fn);
155 if (fileline_fn != NULL)
156 return 1;
157
158 /* We have not initialized the information. Do it now. */
159
160 descriptor = -1;
161 called_error_callback = 0;
162 for (pass = 0; pass < 7; ++pass)
163 {
164 int does_not_exist;
165
166 switch (pass)
167 {
168 case 0:
169 filename = state->filename;
170 break;
171 case 1:
172 filename = getexecname ();
173 break;
174 case 2:
175 filename = "/proc/self/exe";
176 break;
177 case 3:
178 filename = "/proc/curproc/file";
179 break;
180 case 4:
181 snprintf (buf, sizeof (buf), "/proc/%ld/object/a.out",
182 (long) getpid ());
183 filename = buf;
184 break;
185 case 5:
186 filename = sysctl_exec_name1 (state, error_callback, data);
187 break;
188 case 6:
189 filename = sysctl_exec_name2 (state, error_callback, data);
190 break;
191 default:
192 abort ();
193 }
194
195 if (filename == NULL)
196 continue;
197
198 descriptor = backtrace_open (filename, error_callback, data,
199 &does_not_exist);
200 if (descriptor < 0 && !does_not_exist)
201 {
202 called_error_callback = 1;
203 break;
204 }
205 if (descriptor >= 0)
206 break;
207 }
208
209 if (descriptor < 0)
210 {
211 if (!called_error_callback)
212 {
213 if (state->filename != NULL)
214 error_callback (data, state->filename, ENOENT);
215 else
216 error_callback (data,
217 "libbacktrace could not find executable to open",
218 0);
219 }
220 failed = 1;
221 }
222
223 if (!failed)
224 {
225 if (!backtrace_initialize (state, filename, descriptor, error_callback,
226 data, &fileline_fn))
227 failed = 1;
228 }
229
230 if (failed)
231 {
232 if (!state->threaded)
233 state->fileline_initialization_failed = 1;
234 else
235 backtrace_atomic_store_int (&state->fileline_initialization_failed, 1);
236 return 0;
237 }
238
239 if (!state->threaded)
240 state->fileline_fn = fileline_fn;
241 else
242 {
243 backtrace_atomic_store_pointer (&state->fileline_fn, fileline_fn);
244
245 /* Note that if two threads initialize at once, one of the data
246 sets may be leaked. */
247 }
248
249 return 1;
250 }
251
252 /* Given a PC, find the file name, line number, and function name. */
253
254 int
255 backtrace_pcinfo (struct backtrace_state *state, uintptr_t pc,
256 backtrace_full_callback callback,
257 backtrace_error_callback error_callback, void *data)
258 {
259 if (!fileline_initialize (state, error_callback, data))
260 return 0;
261
262 if (state->fileline_initialization_failed)
263 return 0;
264
265 return state->fileline_fn (state, pc, callback, error_callback, data);
266 }
267
268 /* Given a PC, find the symbol for it, and its value. */
269
270 int
271 backtrace_syminfo (struct backtrace_state *state, uintptr_t pc,
272 backtrace_syminfo_callback callback,
273 backtrace_error_callback error_callback, void *data)
274 {
275 if (!fileline_initialize (state, error_callback, data))
276 return 0;
277
278 if (state->fileline_initialization_failed)
279 return 0;
280
281 state->syminfo_fn (state, pc, callback, error_callback, data);
282 return 1;
283 }