3 * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
12 #endif /* WPA_TRACE_BCD */
20 static struct dl_list active_references =
21 { &active_references, &active_references };
26 #define DMGL_PARAMS (1 << 0)
27 #define DMGL_ANSI (1 << 1)
29 static char *prg_fname = NULL;
30 static bfd *cached_abfd = NULL;
31 static asymbol **syms = NULL;
32 static unsigned long start_offset;
33 static int start_offset_looked_up;
36 static int callback(struct dl_phdr_info *info, size_t size, void *data)
40 * "The first object visited by callback is the main program."
42 start_offset = info->dlpi_addr;
46 * "The dl_iterate_phdr() function walks through the list of an
47 * application's shared objects and calls the function callback
48 * once for each object, until either all shared objects have
49 * been processed or callback returns a nonzero value."
55 static void get_prg_fname(void)
57 char exe[50], fname[512];
59 os_snprintf(exe, sizeof(exe) - 1, "/proc/%u/exe", getpid());
60 len = readlink(exe, fname, sizeof(fname) - 1);
61 if (len < 0 || len >= (int) sizeof(fname)) {
62 wpa_printf(MSG_ERROR, "readlink: %s", strerror(errno));
66 prg_fname = strdup(fname);
70 static bfd * open_bfd(const char *fname)
75 abfd = bfd_openr(prg_fname, NULL);
77 wpa_printf(MSG_INFO, "bfd_openr failed");
81 if (bfd_check_format(abfd, bfd_archive)) {
82 wpa_printf(MSG_INFO, "bfd_check_format failed");
87 if (!bfd_check_format_matches(abfd, bfd_object, &matching)) {
88 wpa_printf(MSG_INFO, "bfd_check_format_matches failed");
98 static void read_syms(bfd *abfd)
100 long storage, symcount;
101 bfd_boolean dynamic = FALSE;
106 if (!(bfd_get_file_flags(abfd) & HAS_SYMS)) {
107 wpa_printf(MSG_INFO, "No symbols");
111 storage = bfd_get_symtab_upper_bound(abfd);
113 storage = bfd_get_dynamic_symtab_upper_bound(abfd);
117 wpa_printf(MSG_INFO, "Unknown symtab upper bound");
121 syms = malloc(storage);
123 wpa_printf(MSG_INFO, "Failed to allocate memory for symtab "
124 "(%ld bytes)", storage);
128 symcount = bfd_canonicalize_dynamic_symtab(abfd, syms);
130 symcount = bfd_canonicalize_symtab(abfd, syms);
132 wpa_printf(MSG_INFO, "Failed to canonicalize %ssymtab",
133 dynamic ? "dynamic " : "");
144 const char *filename;
145 const char *function;
150 static void find_addr_sect(bfd *abfd, asection *section, void *obj)
152 struct bfd_data *data = obj;
159 if (!(bfd_get_section_vma(abfd, section)))
162 vma = bfd_get_section_vma(abfd, section);
166 size = bfd_get_section_size(section);
167 if (data->pc >= vma + size)
170 data->found = bfd_find_nearest_line(abfd, section, syms,
178 static void wpa_trace_bfd_addr(void *pc)
180 bfd *abfd = cached_abfd;
181 struct bfd_data data;
184 const char *filename;
189 data.pc = (bfd_hostptr_t) (pc - start_offset);
191 bfd_map_over_sections(abfd, find_addr_sect, &data);
198 aname = bfd_demangle(abfd, data.function,
199 DMGL_ANSI | DMGL_PARAMS);
200 name = aname ? aname : data.function;
201 filename = data.filename;
203 char *end = os_strrchr(filename, '/');
205 while (*filename && *filename == prg_fname[i] &&
211 wpa_printf(MSG_INFO, " %s() %s:%u",
212 name, filename, data.line);
216 data.found = bfd_find_inliner_info(abfd, &data.filename,
217 &data.function, &data.line);
218 } while (data.found);
222 static const char * wpa_trace_bfd_addr2func(void *pc)
224 bfd *abfd = cached_abfd;
225 struct bfd_data data;
230 data.pc = (bfd_hostptr_t) (pc - start_offset);
232 bfd_map_over_sections(abfd, find_addr_sect, &data);
237 return data.function;
241 static void wpa_trace_bfd_init(void)
250 cached_abfd = open_bfd(prg_fname);
252 wpa_printf(MSG_INFO, "Failed to open bfd");
257 read_syms(cached_abfd);
259 wpa_printf(MSG_INFO, "Failed to read symbols");
263 if (!start_offset_looked_up) {
264 dl_iterate_phdr(callback, NULL);
265 start_offset_looked_up = 1;
270 void wpa_trace_dump_funcname(const char *title, void *pc)
272 wpa_printf(MSG_INFO, "WPA_TRACE: %s: %p", title, pc);
273 wpa_trace_bfd_init();
274 wpa_trace_bfd_addr(pc);
278 size_t wpa_trace_calling_func(const char *buf[], size_t len)
281 void *btrace_res[WPA_TRACE_LEN];
287 if (len > WPA_TRACE_LEN)
290 wpa_trace_bfd_init();
295 btrace_num = backtrace(btrace_res, len);
299 for (i = 0; i < btrace_num; i++) {
300 struct bfd_data data;
302 data.pc = (bfd_hostptr_t) (btrace_res[i] - start_offset);
304 bfd_map_over_sections(abfd, find_addr_sect, &data);
309 os_strcmp(data.function, __func__) != 0)) {
310 buf[pos++] = data.function;
315 data.found = bfd_find_inliner_info(abfd, &data.filename,
324 #else /* WPA_TRACE_BFD */
326 #define wpa_trace_bfd_init() do { } while (0)
327 #define wpa_trace_bfd_addr(pc) do { } while (0)
328 #define wpa_trace_bfd_addr2func(pc) NULL
330 #endif /* WPA_TRACE_BFD */
332 void wpa_trace_dump_func(const char *title, void **btrace, int btrace_num)
336 enum { TRACE_HEAD, TRACE_RELEVANT, TRACE_TAIL } state;
338 wpa_trace_bfd_init();
339 wpa_printf(MSG_INFO, "WPA_TRACE: %s - START", title);
340 sym = backtrace_symbols(btrace, btrace_num);
342 for (i = 0; i < btrace_num; i++) {
343 const char *func = wpa_trace_bfd_addr2func(btrace[i]);
344 if (state == TRACE_HEAD && func &&
345 (os_strcmp(func, "wpa_trace_add_ref_func") == 0 ||
346 os_strcmp(func, "wpa_trace_check_ref") == 0 ||
347 os_strcmp(func, "wpa_trace_show") == 0))
349 if (state == TRACE_TAIL && sym && sym[i] &&
350 os_strstr(sym[i], "__libc_start_main"))
352 if (state == TRACE_HEAD)
353 state = TRACE_RELEVANT;
355 wpa_printf(MSG_INFO, "[%d]: %s", i, sym[i]);
357 wpa_printf(MSG_INFO, "[%d]: ?? [%p]", i, btrace[i]);
358 wpa_trace_bfd_addr(btrace[i]);
359 if (state == TRACE_RELEVANT && func &&
360 os_strcmp(func, "main") == 0)
364 wpa_printf(MSG_INFO, "WPA_TRACE: %s - END", title);
368 void wpa_trace_show(const char *title)
373 wpa_trace_record(&info);
374 wpa_trace_dump(title, &info);
378 void wpa_trace_add_ref_func(struct wpa_trace_ref *ref, const void *addr)
383 wpa_trace_record(ref);
384 dl_list_add(&active_references, &ref->list);
388 void wpa_trace_check_ref(const void *addr)
390 struct wpa_trace_ref *ref;
391 dl_list_for_each(ref, &active_references, struct wpa_trace_ref, list) {
392 if (addr != ref->addr)
394 wpa_trace_show("Freeing referenced memory");
395 wpa_trace_dump("Reference registration", ref);
401 void wpa_trace_deinit(void)
406 #endif /* WPA_TRACE_BFD */
409 #endif /* WPA_TRACE */