1 /* fileline.c -- Get file and line number information in a backtrace.
2 Copyright (C) 2012-2024 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
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
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. */
35 #include <sys/types.h>
42 #if defined (HAVE_KERN_PROC_ARGS) || defined (HAVE_KERN_PROC)
43 #include <sys/sysctl.h>
46 #ifdef HAVE_MACH_O_DYLD_H
47 #include <mach-o/dyld.h>
51 #ifndef WIN32_MEAN_AND_LEAN
52 #define WIN32_MEAN_AND_LEAN
62 #include "backtrace.h"
65 #ifndef HAVE_GETEXECNAME
66 #define getexecname() NULL
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) */
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
)
91 if (sysctl (mib
, 4, NULL
, &len
, NULL
, 0) < 0)
93 name
= (char *) backtrace_alloc (state
, len
, error_callback
, data
);
97 if (sysctl (mib
, 4, name
, &rlen
, NULL
, 0) < 0)
99 backtrace_free (state
, name
, len
, error_callback
, data
);
105 #ifdef HAVE_KERN_PROC_ARGS
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
);
118 #define sysctl_exec_name1(state, error_callback, data) NULL
122 #ifdef HAVE_KERN_PROC
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
);
135 #define sysctl_exec_name2(state, error_callback, data) NULL
139 #endif /* defined (HAVE_KERN_PROC_ARGS) || |defined (HAVE_KERN_PROC) */
141 #ifdef HAVE_MACH_O_DYLD_H
144 macho_get_executable_path (struct backtrace_state
*state
,
145 backtrace_error_callback error_callback
, void *data
)
151 if (_NSGetExecutablePath (NULL
, &len
) == 0)
153 name
= (char *) backtrace_alloc (state
, len
, error_callback
, data
);
156 if (_NSGetExecutablePath (name
, &len
) != 0)
158 backtrace_free (state
, name
, len
, error_callback
, data
);
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)
185 windows_get_executable_path (char *buf
, backtrace_error_callback error_callback
,
191 got
= GetModuleFileNameA (NULL
, buf
, FILENAME_BUF_SIZE
- 1);
192 error
= GetLastError ();
194 || (got
== FILENAME_BUF_SIZE
- 1 && error
== ERROR_INSUFFICIENT_BUFFER
))
196 error_callback (data
,
197 "could not get the filename of the current executable",
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. */
215 fileline_initialize (struct backtrace_state
*state
,
216 backtrace_error_callback error_callback
, void *data
)
219 fileline fileline_fn
;
221 int called_error_callback
;
223 const char *filename
;
224 char buf
[FILENAME_BUF_SIZE
];
226 if (!state
->threaded
)
227 failed
= state
->fileline_initialization_failed
;
229 failed
= backtrace_atomic_load_int (&state
->fileline_initialization_failed
);
233 error_callback (data
, "failed to read executable information", -1);
237 if (!state
->threaded
)
238 fileline_fn
= state
->fileline_fn
;
240 fileline_fn
= backtrace_atomic_load_pointer (&state
->fileline_fn
);
241 if (fileline_fn
!= NULL
)
244 /* We have not initialized the information. Do it now. */
247 called_error_callback
= 0;
248 for (pass
= 0; pass
< 10; ++pass
)
255 filename
= state
->filename
;
258 filename
= getexecname ();
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 ();
266 filename
= "/proc/self/exe";
269 filename
= "/proc/curproc/file";
272 snprintf (buf
, sizeof (buf
), "/proc/%ld/object/a.out",
277 filename
= sysctl_exec_name1 (state
, error_callback
, data
);
280 filename
= sysctl_exec_name2 (state
, error_callback
, data
);
283 filename
= macho_get_executable_path (state
, error_callback
, data
);
286 filename
= windows_get_executable_path (buf
, error_callback
, data
);
292 if (filename
== NULL
)
295 descriptor
= backtrace_open (filename
, error_callback
, data
,
297 if (descriptor
< 0 && !does_not_exist
)
299 called_error_callback
= 1;
308 if (!called_error_callback
)
310 if (state
->filename
!= NULL
)
311 error_callback (data
, state
->filename
, ENOENT
);
313 error_callback (data
,
314 "libbacktrace could not find executable to open",
322 if (!backtrace_initialize (state
, filename
, descriptor
, error_callback
,
329 if (!state
->threaded
)
330 state
->fileline_initialization_failed
= 1;
332 backtrace_atomic_store_int (&state
->fileline_initialization_failed
, 1);
336 if (!state
->threaded
)
337 state
->fileline_fn
= fileline_fn
;
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. */
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
))
359 if (state
->fileline_initialization_failed
)
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
))
375 if (state
->fileline_initialization_failed
)
378 state
->syminfo_fn (state
, pc
, callback
, error_callback
, data
);
382 /* A backtrace_syminfo_callback that can call into a
383 backtrace_full_callback, used when we have a symbol table but no
387 backtrace_syminfo_to_full_callback (void *data
, uintptr_t pc
,
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. */
401 backtrace_syminfo_to_full_error_callback (void *data
, const char *msg
,
404 struct backtrace_call_full
*bdata
= (struct backtrace_call_full
*) data
;
406 bdata
->full_error_callback (bdata
->full_data
, msg
, errnum
);