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.
16 static struct dl_list active_references =
17 { &active_references, &active_references };
24 #include <libiberty/demangle.h>
25 #endif /* __linux__ */
27 static char *prg_fname = NULL;
28 static bfd *cached_abfd = NULL;
29 static asymbol **syms = NULL;
31 static void get_prg_fname(void)
33 char exe[50], fname[512];
35 os_snprintf(exe, sizeof(exe) - 1, "/proc/%u/exe", getpid());
36 len = readlink(exe, fname, sizeof(fname) - 1);
37 if (len < 0 || len >= (int) sizeof(fname)) {
42 prg_fname = strdup(fname);
46 static bfd * open_bfd(const char *fname)
51 abfd = bfd_openr(prg_fname, NULL);
53 wpa_printf(MSG_INFO, "bfd_openr failed");
57 if (bfd_check_format(abfd, bfd_archive)) {
58 wpa_printf(MSG_INFO, "bfd_check_format failed");
63 if (!bfd_check_format_matches(abfd, bfd_object, &matching)) {
64 wpa_printf(MSG_INFO, "bfd_check_format_matches failed");
74 static void read_syms(bfd *abfd)
76 long storage, symcount;
77 bfd_boolean dynamic = FALSE;
82 if (!(bfd_get_file_flags(abfd) & HAS_SYMS)) {
83 wpa_printf(MSG_INFO, "No symbols");
87 storage = bfd_get_symtab_upper_bound(abfd);
89 storage = bfd_get_dynamic_symtab_upper_bound(abfd);
93 wpa_printf(MSG_INFO, "Unknown symtab upper bound");
97 syms = malloc(storage);
99 wpa_printf(MSG_INFO, "Failed to allocate memory for symtab "
100 "(%ld bytes)", storage);
104 symcount = bfd_canonicalize_dynamic_symtab(abfd, syms);
106 symcount = bfd_canonicalize_symtab(abfd, syms);
108 wpa_printf(MSG_INFO, "Failed to canonicalize %ssymtab",
109 dynamic ? "dynamic " : "");
120 const char *filename;
121 const char *function;
126 static void find_addr_sect(bfd *abfd, asection *section, void *obj)
128 struct bfd_data *data = obj;
135 if (!(bfd_get_section_vma(abfd, section)))
138 vma = bfd_get_section_vma(abfd, section);
142 size = bfd_get_section_size(section);
143 if (data->pc >= vma + size)
146 data->found = bfd_find_nearest_line(abfd, section, syms,
154 static void wpa_trace_bfd_addr(void *pc)
156 bfd *abfd = cached_abfd;
157 struct bfd_data data;
160 const char *filename;
165 data.pc = (bfd_vma) pc;
167 bfd_map_over_sections(abfd, find_addr_sect, &data);
174 aname = bfd_demangle(abfd, data.function,
175 DMGL_ANSI | DMGL_PARAMS);
176 name = aname ? aname : data.function;
177 filename = data.filename;
179 char *end = os_strrchr(filename, '/');
181 while (*filename && *filename == prg_fname[i] &&
187 wpa_printf(MSG_INFO, " %s() %s:%u",
188 name, filename, data.line);
191 data.found = bfd_find_inliner_info(abfd, &data.filename,
192 &data.function, &data.line);
193 } while (data.found);
197 static const char * wpa_trace_bfd_addr2func(void *pc)
199 bfd *abfd = cached_abfd;
200 struct bfd_data data;
205 data.pc = (bfd_vma) pc;
207 bfd_map_over_sections(abfd, find_addr_sect, &data);
212 return data.function;
216 static void wpa_trace_bfd_init(void)
225 cached_abfd = open_bfd(prg_fname);
227 wpa_printf(MSG_INFO, "Failed to open bfd");
232 read_syms(cached_abfd);
234 wpa_printf(MSG_INFO, "Failed to read symbols");
240 void wpa_trace_dump_funcname(const char *title, void *pc)
242 wpa_printf(MSG_INFO, "WPA_TRACE: %s: %p", title, pc);
243 wpa_trace_bfd_init();
244 wpa_trace_bfd_addr(pc);
247 #else /* WPA_TRACE_BFD */
249 #define wpa_trace_bfd_init() do { } while (0)
250 #define wpa_trace_bfd_addr(pc) do { } while (0)
251 #define wpa_trace_bfd_addr2func(pc) NULL
253 #endif /* WPA_TRACE_BFD */
255 void wpa_trace_dump_func(const char *title, void **btrace, int btrace_num)
259 enum { TRACE_HEAD, TRACE_RELEVANT, TRACE_TAIL } state;
261 wpa_trace_bfd_init();
262 wpa_printf(MSG_INFO, "WPA_TRACE: %s - START", title);
263 sym = backtrace_symbols(btrace, btrace_num);
265 for (i = 0; i < btrace_num; i++) {
266 const char *func = wpa_trace_bfd_addr2func(btrace[i]);
267 if (state == TRACE_HEAD && func &&
268 (os_strcmp(func, "wpa_trace_add_ref_func") == 0 ||
269 os_strcmp(func, "wpa_trace_check_ref") == 0 ||
270 os_strcmp(func, "wpa_trace_show") == 0))
272 if (state == TRACE_TAIL && sym && sym[i] &&
273 os_strstr(sym[i], "__libc_start_main"))
275 if (state == TRACE_HEAD)
276 state = TRACE_RELEVANT;
278 wpa_printf(MSG_INFO, "[%d]: %s", i, sym[i]);
280 wpa_printf(MSG_INFO, "[%d]: ?? [%p]", i, btrace[i]);
281 wpa_trace_bfd_addr(btrace[i]);
282 if (state == TRACE_RELEVANT && func &&
283 os_strcmp(func, "main") == 0)
287 wpa_printf(MSG_INFO, "WPA_TRACE: %s - END", title);
291 void wpa_trace_show(const char *title)
296 wpa_trace_record(&info);
297 wpa_trace_dump(title, &info);
301 void wpa_trace_add_ref_func(struct wpa_trace_ref *ref, const void *addr)
306 wpa_trace_record(ref);
307 dl_list_add(&active_references, &ref->list);
311 void wpa_trace_check_ref(const void *addr)
313 struct wpa_trace_ref *ref;
314 dl_list_for_each(ref, &active_references, struct wpa_trace_ref, list) {
315 if (addr != ref->addr)
317 wpa_trace_show("Freeing referenced memory");
318 wpa_trace_dump("Reference registration", ref);
323 #endif /* WPA_TRACE */