Line data Source code
1 : /*
2 : * Backtrace debugging
3 : * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
4 : *
5 : * This software may be distributed under the terms of the BSD license.
6 : * See README for more details.
7 : */
8 :
9 : #include "includes.h"
10 :
11 : #include "common.h"
12 : #include "trace.h"
13 :
14 : #ifdef WPA_TRACE
15 :
16 : static struct dl_list active_references =
17 : { &active_references, &active_references };
18 :
19 : #ifdef WPA_TRACE_BFD
20 : #include <bfd.h>
21 :
22 : #define DMGL_PARAMS (1 << 0)
23 : #define DMGL_ANSI (1 << 1)
24 :
25 : static char *prg_fname = NULL;
26 : static bfd *cached_abfd = NULL;
27 : static asymbol **syms = NULL;
28 :
29 13 : static void get_prg_fname(void)
30 : {
31 : char exe[50], fname[512];
32 : int len;
33 13 : os_snprintf(exe, sizeof(exe) - 1, "/proc/%u/exe", getpid());
34 13 : len = readlink(exe, fname, sizeof(fname) - 1);
35 13 : if (len < 0 || len >= (int) sizeof(fname)) {
36 0 : wpa_printf(MSG_ERROR, "readlink: %s", strerror(errno));
37 13 : return;
38 : }
39 13 : fname[len] = '\0';
40 13 : prg_fname = strdup(fname);
41 : }
42 :
43 :
44 13 : static bfd * open_bfd(const char *fname)
45 : {
46 : bfd *abfd;
47 : char **matching;
48 :
49 13 : abfd = bfd_openr(prg_fname, NULL);
50 13 : if (abfd == NULL) {
51 0 : wpa_printf(MSG_INFO, "bfd_openr failed");
52 0 : return NULL;
53 : }
54 :
55 13 : if (bfd_check_format(abfd, bfd_archive)) {
56 0 : wpa_printf(MSG_INFO, "bfd_check_format failed");
57 0 : bfd_close(abfd);
58 0 : return NULL;
59 : }
60 :
61 13 : if (!bfd_check_format_matches(abfd, bfd_object, &matching)) {
62 0 : wpa_printf(MSG_INFO, "bfd_check_format_matches failed");
63 0 : free(matching);
64 0 : bfd_close(abfd);
65 0 : return NULL;
66 : }
67 :
68 13 : return abfd;
69 : }
70 :
71 :
72 77134 : static void read_syms(bfd *abfd)
73 : {
74 : long storage, symcount;
75 77134 : bfd_boolean dynamic = FALSE;
76 :
77 77134 : if (syms)
78 77121 : return;
79 :
80 13 : if (!(bfd_get_file_flags(abfd) & HAS_SYMS)) {
81 0 : wpa_printf(MSG_INFO, "No symbols");
82 0 : return;
83 : }
84 :
85 13 : storage = bfd_get_symtab_upper_bound(abfd);
86 13 : if (storage == 0) {
87 0 : storage = bfd_get_dynamic_symtab_upper_bound(abfd);
88 0 : dynamic = TRUE;
89 : }
90 13 : if (storage < 0) {
91 0 : wpa_printf(MSG_INFO, "Unknown symtab upper bound");
92 0 : return;
93 : }
94 :
95 13 : syms = malloc(storage);
96 13 : if (syms == NULL) {
97 0 : wpa_printf(MSG_INFO, "Failed to allocate memory for symtab "
98 : "(%ld bytes)", storage);
99 0 : return;
100 : }
101 13 : if (dynamic)
102 0 : symcount = bfd_canonicalize_dynamic_symtab(abfd, syms);
103 : else
104 13 : symcount = bfd_canonicalize_symtab(abfd, syms);
105 13 : if (symcount < 0) {
106 0 : wpa_printf(MSG_INFO, "Failed to canonicalize %ssymtab",
107 : dynamic ? "dynamic " : "");
108 0 : free(syms);
109 0 : syms = NULL;
110 0 : return;
111 : }
112 : }
113 :
114 :
115 : struct bfd_data {
116 : bfd_vma pc;
117 : bfd_boolean found;
118 : const char *filename;
119 : const char *function;
120 : unsigned int line;
121 : };
122 :
123 :
124 37200192 : static void find_addr_sect(bfd *abfd, asection *section, void *obj)
125 : {
126 37200192 : struct bfd_data *data = obj;
127 : bfd_vma vma;
128 : bfd_size_type size;
129 :
130 37200192 : if (data->found)
131 20567082 : return;
132 :
133 16633110 : if (!(bfd_get_section_vma(abfd, section)))
134 560196 : return;
135 :
136 16072914 : vma = bfd_get_section_vma(abfd, section);
137 16072914 : if (data->pc < vma)
138 0 : return;
139 :
140 16072914 : size = bfd_get_section_size(section);
141 16072914 : if (data->pc >= vma + size)
142 14990436 : return;
143 :
144 1082478 : data->found = bfd_find_nearest_line(abfd, section, syms,
145 : data->pc - vma,
146 : &data->filename,
147 : &data->function,
148 : &data->line);
149 : }
150 :
151 :
152 10 : static void wpa_trace_bfd_addr(void *pc)
153 : {
154 10 : bfd *abfd = cached_abfd;
155 : struct bfd_data data;
156 : const char *name;
157 10 : char *aname = NULL;
158 : const char *filename;
159 :
160 10 : if (abfd == NULL)
161 0 : return;
162 :
163 10 : data.pc = (bfd_hostptr_t) pc;
164 10 : data.found = FALSE;
165 10 : bfd_map_over_sections(abfd, find_addr_sect, &data);
166 :
167 10 : if (!data.found)
168 0 : return;
169 :
170 : do {
171 10 : if (data.function)
172 10 : aname = bfd_demangle(abfd, data.function,
173 : DMGL_ANSI | DMGL_PARAMS);
174 10 : name = aname ? aname : data.function;
175 10 : filename = data.filename;
176 10 : if (filename) {
177 10 : char *end = os_strrchr(filename, '/');
178 10 : int i = 0;
179 385 : while (*filename && *filename == prg_fname[i] &&
180 : filename <= end) {
181 365 : filename++;
182 365 : i++;
183 : }
184 : }
185 10 : wpa_printf(MSG_INFO, " %s() %s:%u",
186 : name, filename, data.line);
187 10 : free(aname);
188 10 : aname = NULL;
189 :
190 10 : data.found = bfd_find_inliner_info(abfd, &data.filename,
191 : &data.function, &data.line);
192 10 : } while (data.found);
193 : }
194 :
195 :
196 11 : static const char * wpa_trace_bfd_addr2func(void *pc)
197 : {
198 11 : bfd *abfd = cached_abfd;
199 : struct bfd_data data;
200 :
201 11 : if (abfd == NULL)
202 0 : return NULL;
203 :
204 11 : data.pc = (bfd_hostptr_t) pc;
205 11 : data.found = FALSE;
206 11 : bfd_map_over_sections(abfd, find_addr_sect, &data);
207 :
208 11 : if (!data.found)
209 1 : return NULL;
210 :
211 10 : return data.function;
212 : }
213 :
214 :
215 77134 : static void wpa_trace_bfd_init(void)
216 : {
217 77134 : if (!prg_fname) {
218 13 : get_prg_fname();
219 13 : if (!prg_fname)
220 0 : return;
221 : }
222 :
223 77134 : if (!cached_abfd) {
224 13 : cached_abfd = open_bfd(prg_fname);
225 13 : if (!cached_abfd) {
226 0 : wpa_printf(MSG_INFO, "Failed to open bfd");
227 0 : return;
228 : }
229 : }
230 :
231 77134 : read_syms(cached_abfd);
232 77134 : if (!syms) {
233 0 : wpa_printf(MSG_INFO, "Failed to read symbols");
234 0 : return;
235 : }
236 : }
237 :
238 :
239 1 : void wpa_trace_dump_funcname(const char *title, void *pc)
240 : {
241 1 : wpa_printf(MSG_INFO, "WPA_TRACE: %s: %p", title, pc);
242 1 : wpa_trace_bfd_init();
243 1 : wpa_trace_bfd_addr(pc);
244 1 : }
245 :
246 :
247 77132 : size_t wpa_trace_calling_func(const char *buf[], size_t len)
248 : {
249 : bfd *abfd;
250 : void *btrace_res[WPA_TRACE_LEN];
251 : int i, btrace_num;
252 77132 : size_t pos = 0;
253 :
254 77132 : if (len == 0)
255 0 : return 0;
256 77132 : if (len > WPA_TRACE_LEN)
257 0 : len = WPA_TRACE_LEN;
258 :
259 77132 : wpa_trace_bfd_init();
260 77132 : abfd = cached_abfd;
261 77132 : if (!abfd)
262 0 : return 0;
263 :
264 77132 : btrace_num = backtrace(btrace_res, len);
265 77132 : if (btrace_num < 1)
266 0 : return 0;
267 :
268 1239617 : for (i = 0; i < btrace_num; i++) {
269 : struct bfd_data data;
270 :
271 1162485 : data.pc = (bfd_hostptr_t) btrace_res[i];
272 1162485 : data.found = FALSE;
273 1162485 : bfd_map_over_sections(abfd, find_addr_sect, &data);
274 :
275 3407428 : while (data.found) {
276 1082458 : if (data.function &&
277 154264 : (pos > 0 ||
278 154264 : os_strcmp(data.function, __func__) != 0)) {
279 1005326 : buf[pos++] = data.function;
280 1005326 : if (pos == len)
281 0 : return pos;
282 : }
283 :
284 1082458 : data.found = bfd_find_inliner_info(abfd, &data.filename,
285 : &data.function,
286 : &data.line);
287 : }
288 : }
289 :
290 77132 : return pos;
291 : }
292 :
293 : #else /* WPA_TRACE_BFD */
294 :
295 : #define wpa_trace_bfd_init() do { } while (0)
296 : #define wpa_trace_bfd_addr(pc) do { } while (0)
297 : #define wpa_trace_bfd_addr2func(pc) NULL
298 :
299 : #endif /* WPA_TRACE_BFD */
300 :
301 1 : void wpa_trace_dump_func(const char *title, void **btrace, int btrace_num)
302 : {
303 : char **sym;
304 : int i;
305 : enum { TRACE_HEAD, TRACE_RELEVANT, TRACE_TAIL } state;
306 :
307 1 : wpa_trace_bfd_init();
308 1 : wpa_printf(MSG_INFO, "WPA_TRACE: %s - START", title);
309 1 : sym = backtrace_symbols(btrace, btrace_num);
310 1 : state = TRACE_HEAD;
311 11 : for (i = 0; i < btrace_num; i++) {
312 11 : const char *func = wpa_trace_bfd_addr2func(btrace[i]);
313 13 : if (state == TRACE_HEAD && func &&
314 4 : (os_strcmp(func, "wpa_trace_add_ref_func") == 0 ||
315 4 : os_strcmp(func, "wpa_trace_check_ref") == 0 ||
316 2 : os_strcmp(func, "wpa_trace_show") == 0))
317 1 : continue;
318 11 : if (state == TRACE_TAIL && sym && sym[i] &&
319 1 : os_strstr(sym[i], "__libc_start_main"))
320 1 : break;
321 9 : if (state == TRACE_HEAD)
322 1 : state = TRACE_RELEVANT;
323 9 : if (sym)
324 9 : wpa_printf(MSG_INFO, "[%d]: %s", i, sym[i]);
325 : else
326 0 : wpa_printf(MSG_INFO, "[%d]: ?? [%p]", i, btrace[i]);
327 9 : wpa_trace_bfd_addr(btrace[i]);
328 18 : if (state == TRACE_RELEVANT && func &&
329 9 : os_strcmp(func, "main") == 0)
330 1 : state = TRACE_TAIL;
331 : }
332 1 : free(sym);
333 1 : wpa_printf(MSG_INFO, "WPA_TRACE: %s - END", title);
334 1 : }
335 :
336 :
337 1 : void wpa_trace_show(const char *title)
338 : {
339 : struct info {
340 : WPA_TRACE_INFO
341 : } info;
342 1 : wpa_trace_record(&info);
343 1 : wpa_trace_dump(title, &info);
344 1 : }
345 :
346 :
347 1508764 : void wpa_trace_add_ref_func(struct wpa_trace_ref *ref, const void *addr)
348 : {
349 1508764 : if (addr == NULL)
350 1998172 : return;
351 1019356 : ref->addr = addr;
352 1019356 : wpa_trace_record(ref);
353 1019356 : dl_list_add(&active_references, &ref->list);
354 : }
355 :
356 :
357 3588701 : void wpa_trace_check_ref(const void *addr)
358 : {
359 : struct wpa_trace_ref *ref;
360 380489350 : dl_list_for_each(ref, &active_references, struct wpa_trace_ref, list) {
361 186655974 : if (addr != ref->addr)
362 186655974 : continue;
363 0 : wpa_trace_show("Freeing referenced memory");
364 0 : wpa_trace_dump("Reference registration", ref);
365 0 : abort();
366 : }
367 3588701 : }
368 :
369 : #endif /* WPA_TRACE */
|