]>
Commit | Line | Data |
---|---|---|
eff02e4f | 1 | /* fileline.c -- Get file and line number information in a backtrace. |
a5544970 | 2 | Copyright (C) 2012-2019 Free Software Foundation, Inc. |
eff02e4f ILT |
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 | |
84ebf639 | 10 | notice, this list of conditions and the following disclaimer. |
eff02e4f ILT |
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 | |
84ebf639 CL |
15 | distribution. |
16 | ||
eff02e4f ILT |
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> | |
33521509 | 37 | #include <errno.h> |
eff02e4f | 38 | #include <fcntl.h> |
c0558468 | 39 | #include <stdlib.h> |
b3530b94 | 40 | #include <unistd.h> |
eff02e4f ILT |
41 | |
42 | #include "backtrace.h" | |
43 | #include "internal.h" | |
44 | ||
33521509 ILT |
45 | #ifndef HAVE_GETEXECNAME |
46 | #define getexecname() NULL | |
47 | #endif | |
48 | ||
eff02e4f ILT |
49 | /* Initialize the fileline information from the executable. Returns 1 |
50 | on success, 0 on failure. */ | |
51 | ||
52 | static int | |
53 | fileline_initialize (struct backtrace_state *state, | |
54 | backtrace_error_callback error_callback, void *data) | |
55 | { | |
56 | int failed; | |
57 | fileline fileline_fn; | |
33521509 ILT |
58 | int pass; |
59 | int called_error_callback; | |
eff02e4f | 60 | int descriptor; |
9283471b | 61 | const char *filename; |
b3530b94 | 62 | char buf[64]; |
eff02e4f | 63 | |
49579c7e ILT |
64 | if (!state->threaded) |
65 | failed = state->fileline_initialization_failed; | |
66 | else | |
67 | failed = backtrace_atomic_load_int (&state->fileline_initialization_failed); | |
eff02e4f ILT |
68 | |
69 | if (failed) | |
70 | { | |
8a447b3d | 71 | error_callback (data, "failed to read executable information", -1); |
eff02e4f ILT |
72 | return 0; |
73 | } | |
74 | ||
49579c7e ILT |
75 | if (!state->threaded) |
76 | fileline_fn = state->fileline_fn; | |
77 | else | |
78 | fileline_fn = backtrace_atomic_load_pointer (&state->fileline_fn); | |
eff02e4f ILT |
79 | if (fileline_fn != NULL) |
80 | return 1; | |
81 | ||
82 | /* We have not initialized the information. Do it now. */ | |
83 | ||
33521509 ILT |
84 | descriptor = -1; |
85 | called_error_callback = 0; | |
b3530b94 | 86 | for (pass = 0; pass < 5; ++pass) |
33521509 | 87 | { |
33521509 ILT |
88 | int does_not_exist; |
89 | ||
90 | switch (pass) | |
91 | { | |
92 | case 0: | |
93 | filename = state->filename; | |
94 | break; | |
95 | case 1: | |
96 | filename = getexecname (); | |
97 | break; | |
98 | case 2: | |
99 | filename = "/proc/self/exe"; | |
100 | break; | |
101 | case 3: | |
102 | filename = "/proc/curproc/file"; | |
103 | break; | |
b3530b94 | 104 | case 4: |
cf311b03 RO |
105 | snprintf (buf, sizeof (buf), "/proc/%ld/object/a.out", |
106 | (long) getpid ()); | |
b3530b94 TR |
107 | filename = buf; |
108 | break; | |
33521509 ILT |
109 | default: |
110 | abort (); | |
111 | } | |
112 | ||
113 | if (filename == NULL) | |
114 | continue; | |
115 | ||
116 | descriptor = backtrace_open (filename, error_callback, data, | |
117 | &does_not_exist); | |
118 | if (descriptor < 0 && !does_not_exist) | |
119 | { | |
120 | called_error_callback = 1; | |
121 | break; | |
122 | } | |
123 | if (descriptor >= 0) | |
124 | break; | |
125 | } | |
126 | ||
eff02e4f | 127 | if (descriptor < 0) |
33521509 ILT |
128 | { |
129 | if (!called_error_callback) | |
130 | { | |
131 | if (state->filename != NULL) | |
132 | error_callback (data, state->filename, ENOENT); | |
133 | else | |
134 | error_callback (data, | |
135 | "libbacktrace could not find executable to open", | |
136 | 0); | |
137 | } | |
138 | failed = 1; | |
139 | } | |
eff02e4f ILT |
140 | |
141 | if (!failed) | |
142 | { | |
9283471b ILT |
143 | if (!backtrace_initialize (state, filename, descriptor, error_callback, |
144 | data, &fileline_fn)) | |
eff02e4f ILT |
145 | failed = 1; |
146 | } | |
147 | ||
148 | if (failed) | |
149 | { | |
150 | if (!state->threaded) | |
151 | state->fileline_initialization_failed = 1; | |
152 | else | |
49579c7e | 153 | backtrace_atomic_store_int (&state->fileline_initialization_failed, 1); |
eff02e4f ILT |
154 | return 0; |
155 | } | |
156 | ||
157 | if (!state->threaded) | |
158 | state->fileline_fn = fileline_fn; | |
159 | else | |
160 | { | |
49579c7e ILT |
161 | backtrace_atomic_store_pointer (&state->fileline_fn, fileline_fn); |
162 | ||
163 | /* Note that if two threads initialize at once, one of the data | |
164 | sets may be leaked. */ | |
eff02e4f ILT |
165 | } |
166 | ||
167 | return 1; | |
168 | } | |
169 | ||
170 | /* Given a PC, find the file name, line number, and function name. */ | |
171 | ||
172 | int | |
173 | backtrace_pcinfo (struct backtrace_state *state, uintptr_t pc, | |
174 | backtrace_full_callback callback, | |
175 | backtrace_error_callback error_callback, void *data) | |
176 | { | |
177 | if (!fileline_initialize (state, error_callback, data)) | |
178 | return 0; | |
179 | ||
180 | if (state->fileline_initialization_failed) | |
181 | return 0; | |
182 | ||
183 | return state->fileline_fn (state, pc, callback, error_callback, data); | |
184 | } | |
185 | ||
186 | /* Given a PC, find the symbol for it, and its value. */ | |
187 | ||
188 | int | |
189 | backtrace_syminfo (struct backtrace_state *state, uintptr_t pc, | |
190 | backtrace_syminfo_callback callback, | |
191 | backtrace_error_callback error_callback, void *data) | |
192 | { | |
193 | if (!fileline_initialize (state, error_callback, data)) | |
194 | return 0; | |
195 | ||
196 | if (state->fileline_initialization_failed) | |
197 | return 0; | |
198 | ||
199 | state->syminfo_fn (state, pc, callback, error_callback, data); | |
200 | return 1; | |
201 | } |