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