testsuite: fix g++.dg/pr112822.C
[official-gcc.git] / libbacktrace / fileline.c
blob773f3a92969aea34b7adddc8240fd411d120f50c
1 /* fileline.c -- Get file and line number information in a backtrace.
2 Copyright (C) 2012-2023 Free Software Foundation, Inc.
3 Written by Ian Lance Taylor, Google.
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
9 (1) Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
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.
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.
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. */
33 #include "config.h"
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>
42 #if defined (HAVE_KERN_PROC_ARGS) || defined (HAVE_KERN_PROC)
43 #include <sys/sysctl.h>
44 #endif
46 #ifdef HAVE_MACH_O_DYLD_H
47 #include <mach-o/dyld.h>
48 #endif
50 #ifdef HAVE_WINDOWS_H
51 #ifndef WIN32_MEAN_AND_LEAN
52 #define WIN32_MEAN_AND_LEAN
53 #endif
55 #ifndef NOMINMAX
56 #define NOMINMAX
57 #endif
59 #include <windows.h>
60 #endif
62 #include "backtrace.h"
63 #include "internal.h"
65 #ifndef HAVE_GETEXECNAME
66 #define getexecname() NULL
67 #endif
69 #if !defined (HAVE_KERN_PROC_ARGS) && !defined (HAVE_KERN_PROC)
71 #define sysctl_exec_name1(state, error_callback, data) NULL
72 #define sysctl_exec_name2(state, error_callback, data) NULL
74 #else /* defined (HAVE_KERN_PROC_ARGS) || |defined (HAVE_KERN_PROC) */
76 static char *
77 sysctl_exec_name (struct backtrace_state *state,
78 int mib0, int mib1, int mib2, int mib3,
79 backtrace_error_callback error_callback, void *data)
81 int mib[4];
82 size_t len;
83 char *name;
84 size_t rlen;
86 mib[0] = mib0;
87 mib[1] = mib1;
88 mib[2] = mib2;
89 mib[3] = mib3;
91 if (sysctl (mib, 4, NULL, &len, NULL, 0) < 0)
92 return NULL;
93 name = (char *) backtrace_alloc (state, len, error_callback, data);
94 if (name == NULL)
95 return NULL;
96 rlen = len;
97 if (sysctl (mib, 4, name, &rlen, NULL, 0) < 0)
99 backtrace_free (state, name, len, error_callback, data);
100 return NULL;
102 return name;
105 #ifdef HAVE_KERN_PROC_ARGS
107 static char *
108 sysctl_exec_name1 (struct backtrace_state *state,
109 backtrace_error_callback error_callback, void *data)
111 /* This variant is used on NetBSD. */
112 return sysctl_exec_name (state, CTL_KERN, KERN_PROC_ARGS, -1,
113 KERN_PROC_PATHNAME, error_callback, data);
116 #else
118 #define sysctl_exec_name1(state, error_callback, data) NULL
120 #endif
122 #ifdef HAVE_KERN_PROC
124 static char *
125 sysctl_exec_name2 (struct backtrace_state *state,
126 backtrace_error_callback error_callback, void *data)
128 /* This variant is used on FreeBSD. */
129 return sysctl_exec_name (state, CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1,
130 error_callback, data);
133 #else
135 #define sysctl_exec_name2(state, error_callback, data) NULL
137 #endif
139 #endif /* defined (HAVE_KERN_PROC_ARGS) || |defined (HAVE_KERN_PROC) */
141 #ifdef HAVE_MACH_O_DYLD_H
143 static char *
144 macho_get_executable_path (struct backtrace_state *state,
145 backtrace_error_callback error_callback, void *data)
147 uint32_t len;
148 char *name;
150 len = 0;
151 if (_NSGetExecutablePath (NULL, &len) == 0)
152 return NULL;
153 name = (char *) backtrace_alloc (state, len, error_callback, data);
154 if (name == NULL)
155 return NULL;
156 if (_NSGetExecutablePath (name, &len) != 0)
158 backtrace_free (state, name, len, error_callback, data);
159 return NULL;
161 return name;
164 #else /* !defined (HAVE_MACH_O_DYLD_H) */
166 #define macho_get_executable_path(state, error_callback, data) NULL
168 #endif /* !defined (HAVE_MACH_O_DYLD_H) */
170 #if HAVE_DECL__PGMPTR
172 #define windows_executable_filename() _pgmptr
174 #else /* !HAVE_DECL__PGMPTR */
176 #define windows_executable_filename() NULL
178 #endif /* !HAVE_DECL__PGMPTR */
180 #ifdef HAVE_WINDOWS_H
182 #define FILENAME_BUF_SIZE (MAX_PATH)
184 static char *
185 windows_get_executable_path (char *buf, backtrace_error_callback error_callback,
186 void *data)
188 size_t got;
189 int error;
191 got = GetModuleFileNameA (NULL, buf, FILENAME_BUF_SIZE - 1);
192 error = GetLastError ();
193 if (got == 0
194 || (got == FILENAME_BUF_SIZE - 1 && error == ERROR_INSUFFICIENT_BUFFER))
196 error_callback (data,
197 "could not get the filename of the current executable",
198 error);
199 return NULL;
201 return buf;
204 #else /* !defined (HAVE_WINDOWS_H) */
206 #define windows_get_executable_path(buf, error_callback, data) NULL
207 #define FILENAME_BUF_SIZE 64
209 #endif /* !defined (HAVE_WINDOWS_H) */
211 /* Initialize the fileline information from the executable. Returns 1
212 on success, 0 on failure. */
214 static int
215 fileline_initialize (struct backtrace_state *state,
216 backtrace_error_callback error_callback, void *data)
218 int failed;
219 fileline fileline_fn;
220 int pass;
221 int called_error_callback;
222 int descriptor;
223 const char *filename;
224 char buf[FILENAME_BUF_SIZE];
226 if (!state->threaded)
227 failed = state->fileline_initialization_failed;
228 else
229 failed = backtrace_atomic_load_int (&state->fileline_initialization_failed);
231 if (failed)
233 error_callback (data, "failed to read executable information", -1);
234 return 0;
237 if (!state->threaded)
238 fileline_fn = state->fileline_fn;
239 else
240 fileline_fn = backtrace_atomic_load_pointer (&state->fileline_fn);
241 if (fileline_fn != NULL)
242 return 1;
244 /* We have not initialized the information. Do it now. */
246 descriptor = -1;
247 called_error_callback = 0;
248 for (pass = 0; pass < 10; ++pass)
250 int does_not_exist;
252 switch (pass)
254 case 0:
255 filename = state->filename;
256 break;
257 case 1:
258 filename = getexecname ();
259 break;
260 case 2:
261 /* Test this before /proc/self/exe, as the latter exists but points
262 to the wine binary (and thus doesn't work). */
263 filename = windows_executable_filename ();
264 break;
265 case 3:
266 filename = "/proc/self/exe";
267 break;
268 case 4:
269 filename = "/proc/curproc/file";
270 break;
271 case 5:
272 snprintf (buf, sizeof (buf), "/proc/%ld/object/a.out",
273 (long) getpid ());
274 filename = buf;
275 break;
276 case 6:
277 filename = sysctl_exec_name1 (state, error_callback, data);
278 break;
279 case 7:
280 filename = sysctl_exec_name2 (state, error_callback, data);
281 break;
282 case 8:
283 filename = macho_get_executable_path (state, error_callback, data);
284 break;
285 case 9:
286 filename = windows_get_executable_path (buf, error_callback, data);
287 break;
288 default:
289 abort ();
292 if (filename == NULL)
293 continue;
295 descriptor = backtrace_open (filename, error_callback, data,
296 &does_not_exist);
297 if (descriptor < 0 && !does_not_exist)
299 called_error_callback = 1;
300 break;
302 if (descriptor >= 0)
303 break;
306 if (descriptor < 0)
308 if (!called_error_callback)
310 if (state->filename != NULL)
311 error_callback (data, state->filename, ENOENT);
312 else
313 error_callback (data,
314 "libbacktrace could not find executable to open",
317 failed = 1;
320 if (!failed)
322 if (!backtrace_initialize (state, filename, descriptor, error_callback,
323 data, &fileline_fn))
324 failed = 1;
327 if (failed)
329 if (!state->threaded)
330 state->fileline_initialization_failed = 1;
331 else
332 backtrace_atomic_store_int (&state->fileline_initialization_failed, 1);
333 return 0;
336 if (!state->threaded)
337 state->fileline_fn = fileline_fn;
338 else
340 backtrace_atomic_store_pointer (&state->fileline_fn, fileline_fn);
342 /* Note that if two threads initialize at once, one of the data
343 sets may be leaked. */
346 return 1;
349 /* Given a PC, find the file name, line number, and function name. */
352 backtrace_pcinfo (struct backtrace_state *state, uintptr_t pc,
353 backtrace_full_callback callback,
354 backtrace_error_callback error_callback, void *data)
356 if (!fileline_initialize (state, error_callback, data))
357 return 0;
359 if (state->fileline_initialization_failed)
360 return 0;
362 return state->fileline_fn (state, pc, callback, error_callback, data);
365 /* Given a PC, find the symbol for it, and its value. */
368 backtrace_syminfo (struct backtrace_state *state, uintptr_t pc,
369 backtrace_syminfo_callback callback,
370 backtrace_error_callback error_callback, void *data)
372 if (!fileline_initialize (state, error_callback, data))
373 return 0;
375 if (state->fileline_initialization_failed)
376 return 0;
378 state->syminfo_fn (state, pc, callback, error_callback, data);
379 return 1;
382 /* A backtrace_syminfo_callback that can call into a
383 backtrace_full_callback, used when we have a symbol table but no
384 debug info. */
386 void
387 backtrace_syminfo_to_full_callback (void *data, uintptr_t pc,
388 const char *symname,
389 uintptr_t symval ATTRIBUTE_UNUSED,
390 uintptr_t symsize ATTRIBUTE_UNUSED)
392 struct backtrace_call_full *bdata = (struct backtrace_call_full *) data;
394 bdata->ret = bdata->full_callback (bdata->full_data, pc, NULL, 0, symname);
397 /* An error callback that corresponds to
398 backtrace_syminfo_to_full_callback. */
400 void
401 backtrace_syminfo_to_full_error_callback (void *data, const char *msg,
402 int errnum)
404 struct backtrace_call_full *bdata = (struct backtrace_call_full *) data;
406 bdata->full_error_callback (bdata->full_data, msg, errnum);