]>
Commit | Line | Data |
---|---|---|
ecd3459e | 1 | /* fileline.c -- Get file and line number information in a backtrace. |
fbd26352 | 2 | Copyright (C) 2012-2019 Free Software Foundation, Inc. |
ecd3459e | 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 | |
75c399ef | 10 | notice, this list of conditions and the following disclaimer. |
ecd3459e | 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 | |
75c399ef | 15 | distribution. |
16 | ||
ecd3459e | 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> | |
686b3772 | 37 | #include <errno.h> |
ecd3459e | 38 | #include <fcntl.h> |
08a2d161 | 39 | #include <stdlib.h> |
e9e43806 | 40 | #include <unistd.h> |
ecd3459e | 41 | |
42 | #include "backtrace.h" | |
43 | #include "internal.h" | |
44 | ||
686b3772 | 45 | #ifndef HAVE_GETEXECNAME |
46 | #define getexecname() NULL | |
47 | #endif | |
48 | ||
ecd3459e | 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; | |
686b3772 | 58 | int pass; |
59 | int called_error_callback; | |
ecd3459e | 60 | int descriptor; |
b919941e | 61 | const char *filename; |
e9e43806 | 62 | char buf[64]; |
ecd3459e | 63 | |
bcafb4a8 | 64 | if (!state->threaded) |
65 | failed = state->fileline_initialization_failed; | |
66 | else | |
67 | failed = backtrace_atomic_load_int (&state->fileline_initialization_failed); | |
ecd3459e | 68 | |
69 | if (failed) | |
70 | { | |
babed505 | 71 | error_callback (data, "failed to read executable information", -1); |
ecd3459e | 72 | return 0; |
73 | } | |
74 | ||
bcafb4a8 | 75 | if (!state->threaded) |
76 | fileline_fn = state->fileline_fn; | |
77 | else | |
78 | fileline_fn = backtrace_atomic_load_pointer (&state->fileline_fn); | |
ecd3459e | 79 | if (fileline_fn != NULL) |
80 | return 1; | |
81 | ||
82 | /* We have not initialized the information. Do it now. */ | |
83 | ||
686b3772 | 84 | descriptor = -1; |
85 | called_error_callback = 0; | |
e9e43806 | 86 | for (pass = 0; pass < 5; ++pass) |
686b3772 | 87 | { |
686b3772 | 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; | |
e9e43806 | 104 | case 4: |
6930694d | 105 | snprintf (buf, sizeof (buf), "/proc/%ld/object/a.out", |
106 | (long) getpid ()); | |
e9e43806 | 107 | filename = buf; |
108 | break; | |
686b3772 | 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 | ||
ecd3459e | 127 | if (descriptor < 0) |
686b3772 | 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 | } | |
ecd3459e | 140 | |
141 | if (!failed) | |
142 | { | |
b919941e | 143 | if (!backtrace_initialize (state, filename, descriptor, error_callback, |
144 | data, &fileline_fn)) | |
ecd3459e | 145 | failed = 1; |
146 | } | |
147 | ||
148 | if (failed) | |
149 | { | |
150 | if (!state->threaded) | |
151 | state->fileline_initialization_failed = 1; | |
152 | else | |
bcafb4a8 | 153 | backtrace_atomic_store_int (&state->fileline_initialization_failed, 1); |
ecd3459e | 154 | return 0; |
155 | } | |
156 | ||
157 | if (!state->threaded) | |
158 | state->fileline_fn = fileline_fn; | |
159 | else | |
160 | { | |
bcafb4a8 | 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. */ | |
ecd3459e | 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 | } |