Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/libbacktrace/fileline.c
9902 views
1
/* fileline.c -- Get file and line number information in a backtrace.
2
Copyright (C) 2012-2021 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
#ifdef HAVE_MACH_O_DYLD_H
47
#include <mach-o/dyld.h>
48
#endif
49
50
#include "backtrace.h"
51
#include "internal.h"
52
53
#ifndef HAVE_GETEXECNAME
54
#define getexecname() NULL
55
#endif
56
57
#if !defined (HAVE_KERN_PROC_ARGS) && !defined (HAVE_KERN_PROC)
58
59
#define sysctl_exec_name1(state, error_callback, data) NULL
60
#define sysctl_exec_name2(state, error_callback, data) NULL
61
62
#else /* defined (HAVE_KERN_PROC_ARGS) || |defined (HAVE_KERN_PROC) */
63
64
static char *
65
sysctl_exec_name (struct backtrace_state *state,
66
int mib0, int mib1, int mib2, int mib3,
67
backtrace_error_callback error_callback, void *data)
68
{
69
int mib[4];
70
size_t len;
71
char *name;
72
size_t rlen;
73
74
mib[0] = mib0;
75
mib[1] = mib1;
76
mib[2] = mib2;
77
mib[3] = mib3;
78
79
if (sysctl (mib, 4, NULL, &len, NULL, 0) < 0)
80
return NULL;
81
name = (char *) backtrace_alloc (state, len, error_callback, data);
82
if (name == NULL)
83
return NULL;
84
rlen = len;
85
if (sysctl (mib, 4, name, &rlen, NULL, 0) < 0)
86
{
87
backtrace_free (state, name, len, error_callback, data);
88
return NULL;
89
}
90
return name;
91
}
92
93
#ifdef HAVE_KERN_PROC_ARGS
94
95
static char *
96
sysctl_exec_name1 (struct backtrace_state *state,
97
backtrace_error_callback error_callback, void *data)
98
{
99
/* This variant is used on NetBSD. */
100
return sysctl_exec_name (state, CTL_KERN, KERN_PROC_ARGS, -1,
101
KERN_PROC_PATHNAME, error_callback, data);
102
}
103
104
#else
105
106
#define sysctl_exec_name1(state, error_callback, data) NULL
107
108
#endif
109
110
#ifdef HAVE_KERN_PROC
111
112
static char *
113
sysctl_exec_name2 (struct backtrace_state *state,
114
backtrace_error_callback error_callback, void *data)
115
{
116
/* This variant is used on FreeBSD. */
117
return sysctl_exec_name (state, CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1,
118
error_callback, data);
119
}
120
121
#else
122
123
#define sysctl_exec_name2(state, error_callback, data) NULL
124
125
#endif
126
127
#endif /* defined (HAVE_KERN_PROC_ARGS) || |defined (HAVE_KERN_PROC) */
128
129
#ifdef HAVE_MACH_O_DYLD_H
130
131
static char *
132
macho_get_executable_path (struct backtrace_state *state,
133
backtrace_error_callback error_callback, void *data)
134
{
135
uint32_t len;
136
char *name;
137
138
len = 0;
139
if (_NSGetExecutablePath (NULL, &len) == 0)
140
return NULL;
141
name = (char *) backtrace_alloc (state, len, error_callback, data);
142
if (name == NULL)
143
return NULL;
144
if (_NSGetExecutablePath (name, &len) != 0)
145
{
146
backtrace_free (state, name, len, error_callback, data);
147
return NULL;
148
}
149
return name;
150
}
151
152
#else /* !defined (HAVE_MACH_O_DYLD_H) */
153
154
#define macho_get_executable_path(state, error_callback, data) NULL
155
156
#endif /* !defined (HAVE_MACH_O_DYLD_H) */
157
158
/* Initialize the fileline information from the executable. Returns 1
159
on success, 0 on failure. */
160
161
static int
162
fileline_initialize (struct backtrace_state *state,
163
backtrace_error_callback error_callback, void *data)
164
{
165
int failed;
166
fileline fileline_fn;
167
int pass;
168
int called_error_callback;
169
int descriptor;
170
const char *filename;
171
char buf[64];
172
173
if (!state->threaded)
174
failed = state->fileline_initialization_failed;
175
else
176
failed = backtrace_atomic_load_int (&state->fileline_initialization_failed);
177
178
if (failed)
179
{
180
error_callback (data, "failed to read executable information", -1);
181
return 0;
182
}
183
184
if (!state->threaded)
185
fileline_fn = state->fileline_fn;
186
else
187
fileline_fn = backtrace_atomic_load_pointer (&state->fileline_fn);
188
if (fileline_fn != NULL)
189
return 1;
190
191
/* We have not initialized the information. Do it now. */
192
193
descriptor = -1;
194
called_error_callback = 0;
195
for (pass = 0; pass < 8; ++pass)
196
{
197
int does_not_exist;
198
199
switch (pass)
200
{
201
case 0:
202
filename = state->filename;
203
break;
204
case 1:
205
filename = getexecname ();
206
break;
207
case 2:
208
filename = "/proc/self/exe";
209
break;
210
case 3:
211
filename = "/proc/curproc/file";
212
break;
213
case 4:
214
snprintf (buf, sizeof (buf), "/proc/%ld/object/a.out",
215
(long) getpid ());
216
filename = buf;
217
break;
218
case 5:
219
filename = sysctl_exec_name1 (state, error_callback, data);
220
break;
221
case 6:
222
filename = sysctl_exec_name2 (state, error_callback, data);
223
break;
224
case 7:
225
filename = macho_get_executable_path (state, error_callback, data);
226
break;
227
default:
228
abort ();
229
}
230
231
if (filename == NULL)
232
continue;
233
234
descriptor = backtrace_open (filename, error_callback, data,
235
&does_not_exist);
236
if (descriptor < 0 && !does_not_exist)
237
{
238
called_error_callback = 1;
239
break;
240
}
241
if (descriptor >= 0)
242
break;
243
}
244
245
if (descriptor < 0)
246
{
247
if (!called_error_callback)
248
{
249
if (state->filename != NULL)
250
error_callback (data, state->filename, ENOENT);
251
else
252
error_callback (data,
253
"libbacktrace could not find executable to open",
254
0);
255
}
256
failed = 1;
257
}
258
259
if (!failed)
260
{
261
if (!backtrace_initialize (state, filename, descriptor, error_callback,
262
data, &fileline_fn))
263
failed = 1;
264
}
265
266
if (failed)
267
{
268
if (!state->threaded)
269
state->fileline_initialization_failed = 1;
270
else
271
backtrace_atomic_store_int (&state->fileline_initialization_failed, 1);
272
return 0;
273
}
274
275
if (!state->threaded)
276
state->fileline_fn = fileline_fn;
277
else
278
{
279
backtrace_atomic_store_pointer (&state->fileline_fn, fileline_fn);
280
281
/* Note that if two threads initialize at once, one of the data
282
sets may be leaked. */
283
}
284
285
return 1;
286
}
287
288
/* Given a PC, find the file name, line number, and function name. */
289
290
int
291
backtrace_pcinfo (struct backtrace_state *state, uintptr_t pc,
292
backtrace_full_callback callback,
293
backtrace_error_callback error_callback, void *data)
294
{
295
if (!fileline_initialize (state, error_callback, data))
296
return 0;
297
298
if (state->fileline_initialization_failed)
299
return 0;
300
301
return state->fileline_fn (state, pc, callback, error_callback, data);
302
}
303
304
/* Given a PC, find the symbol for it, and its value. */
305
306
int
307
backtrace_syminfo (struct backtrace_state *state, uintptr_t pc,
308
backtrace_syminfo_callback callback,
309
backtrace_error_callback error_callback, void *data)
310
{
311
if (!fileline_initialize (state, error_callback, data))
312
return 0;
313
314
if (state->fileline_initialization_failed)
315
return 0;
316
317
state->syminfo_fn (state, pc, callback, error_callback, data);
318
return 1;
319
}
320
321
/* A backtrace_syminfo_callback that can call into a
322
backtrace_full_callback, used when we have a symbol table but no
323
debug info. */
324
325
void
326
backtrace_syminfo_to_full_callback (void *data, uintptr_t pc,
327
const char *symname,
328
uintptr_t symval ATTRIBUTE_UNUSED,
329
uintptr_t symsize ATTRIBUTE_UNUSED)
330
{
331
struct backtrace_call_full *bdata = (struct backtrace_call_full *) data;
332
333
bdata->ret = bdata->full_callback (bdata->full_data, pc, NULL, 0, symname);
334
}
335
336
/* An error callback that corresponds to
337
backtrace_syminfo_to_full_callback. */
338
339
void
340
backtrace_syminfo_to_full_error_callback (void *data, const char *msg,
341
int errnum)
342
{
343
struct backtrace_call_full *bdata = (struct backtrace_call_full *) data;
344
345
bdata->full_error_callback (bdata->full_data, msg, errnum);
346
}
347
348