3 * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
22 static struct dl_list active_references
=
23 { &active_references
, &active_references
};
30 #include <libiberty/demangle.h>
31 #endif /* __linux__ */
33 static char *prg_fname
= NULL
;
34 static bfd
*cached_abfd
= NULL
;
35 static asymbol
**syms
= NULL
;
37 static void get_prg_fname(void)
39 char exe
[50], fname
[512];
41 os_snprintf(exe
, sizeof(exe
) - 1, "/proc/%u/exe", getpid());
42 len
= readlink(exe
, fname
, sizeof(fname
) - 1);
43 if (len
< 0 || len
>= (int) sizeof(fname
)) {
48 prg_fname
= strdup(fname
);
52 static bfd
* open_bfd(const char *fname
)
57 abfd
= bfd_openr(prg_fname
, NULL
);
59 wpa_printf(MSG_INFO
, "bfd_openr failed");
63 if (bfd_check_format(abfd
, bfd_archive
)) {
64 wpa_printf(MSG_INFO
, "bfd_check_format failed");
69 if (!bfd_check_format_matches(abfd
, bfd_object
, &matching
)) {
70 wpa_printf(MSG_INFO
, "bfd_check_format_matches failed");
80 static void read_syms(bfd
*abfd
)
82 long storage
, symcount
;
83 bfd_boolean dynamic
= FALSE
;
88 if (!(bfd_get_file_flags(abfd
) & HAS_SYMS
)) {
89 wpa_printf(MSG_INFO
, "No symbols");
93 storage
= bfd_get_symtab_upper_bound(abfd
);
95 storage
= bfd_get_dynamic_symtab_upper_bound(abfd
);
99 wpa_printf(MSG_INFO
, "Unknown symtab upper bound");
103 syms
= malloc(storage
);
105 wpa_printf(MSG_INFO
, "Failed to allocate memory for symtab "
106 "(%ld bytes)", storage
);
110 symcount
= bfd_canonicalize_dynamic_symtab(abfd
, syms
);
112 symcount
= bfd_canonicalize_symtab(abfd
, syms
);
114 wpa_printf(MSG_INFO
, "Failed to canonicalize %ssymtab",
115 dynamic
? "dynamic " : "");
126 const char *filename
;
127 const char *function
;
132 static void find_addr_sect(bfd
*abfd
, asection
*section
, void *obj
)
134 struct bfd_data
*data
= obj
;
141 if (!(bfd_get_section_vma(abfd
, section
)))
144 vma
= bfd_get_section_vma(abfd
, section
);
148 size
= bfd_get_section_size(section
);
149 if (data
->pc
>= vma
+ size
)
152 data
->found
= bfd_find_nearest_line(abfd
, section
, syms
,
160 static void wpa_trace_bfd_addr(void *pc
)
162 bfd
*abfd
= cached_abfd
;
163 struct bfd_data data
;
166 const char *filename
;
171 data
.pc
= (bfd_vma
) pc
;
173 bfd_map_over_sections(abfd
, find_addr_sect
, &data
);
180 aname
= bfd_demangle(abfd
, data
.function
,
181 DMGL_ANSI
| DMGL_PARAMS
);
182 name
= aname
? aname
: data
.function
;
183 filename
= data
.filename
;
185 char *end
= os_strrchr(filename
, '/');
187 while (*filename
&& *filename
== prg_fname
[i
] &&
193 wpa_printf(MSG_INFO
, " %s() %s:%u",
194 name
, filename
, data
.line
);
197 data
.found
= bfd_find_inliner_info(abfd
, &data
.filename
,
198 &data
.function
, &data
.line
);
199 } while (data
.found
);
203 static const char * wpa_trace_bfd_addr2func(void *pc
)
205 bfd
*abfd
= cached_abfd
;
206 struct bfd_data data
;
211 data
.pc
= (bfd_vma
) pc
;
213 bfd_map_over_sections(abfd
, find_addr_sect
, &data
);
218 return data
.function
;
222 static void wpa_trace_bfd_init(void)
231 cached_abfd
= open_bfd(prg_fname
);
233 wpa_printf(MSG_INFO
, "Failed to open bfd");
238 read_syms(cached_abfd
);
240 wpa_printf(MSG_INFO
, "Failed to read symbols");
246 void wpa_trace_dump_funcname(const char *title
, void *pc
)
248 wpa_printf(MSG_INFO
, "WPA_TRACE: %s: %p", title
, pc
);
249 wpa_trace_bfd_init();
250 wpa_trace_bfd_addr(pc
);
253 #else /* WPA_TRACE_BFD */
255 #define wpa_trace_bfd_init() do { } while (0)
256 #define wpa_trace_bfd_addr(pc) do { } while (0)
257 #define wpa_trace_bfd_addr2func(pc) NULL
259 #endif /* WPA_TRACE_BFD */
261 void wpa_trace_dump_func(const char *title
, void **btrace
, int btrace_num
)
265 enum { TRACE_HEAD
, TRACE_RELEVANT
, TRACE_TAIL
} state
;
267 wpa_trace_bfd_init();
268 wpa_printf(MSG_INFO
, "WPA_TRACE: %s - START", title
);
269 sym
= backtrace_symbols(btrace
, btrace_num
);
271 for (i
= 0; i
< btrace_num
; i
++) {
272 const char *func
= wpa_trace_bfd_addr2func(btrace
[i
]);
273 if (state
== TRACE_HEAD
&& func
&&
274 (os_strcmp(func
, "wpa_trace_add_ref_func") == 0 ||
275 os_strcmp(func
, "wpa_trace_check_ref") == 0 ||
276 os_strcmp(func
, "wpa_trace_show") == 0))
278 if (state
== TRACE_TAIL
&& sym
&& sym
[i
] &&
279 os_strstr(sym
[i
], "__libc_start_main"))
281 if (state
== TRACE_HEAD
)
282 state
= TRACE_RELEVANT
;
284 wpa_printf(MSG_INFO
, "[%d]: %s", i
, sym
[i
]);
286 wpa_printf(MSG_INFO
, "[%d]: ?? [%p]", i
, btrace
[i
]);
287 wpa_trace_bfd_addr(btrace
[i
]);
288 if (state
== TRACE_RELEVANT
&& func
&&
289 os_strcmp(func
, "main") == 0)
293 wpa_printf(MSG_INFO
, "WPA_TRACE: %s - END", title
);
297 void wpa_trace_show(const char *title
)
302 wpa_trace_record(&info
);
303 wpa_trace_dump(title
, &info
);
307 void wpa_trace_add_ref_func(struct wpa_trace_ref
*ref
, const void *addr
)
312 wpa_trace_record(ref
);
313 dl_list_add(&active_references
, &ref
->list
);
317 void wpa_trace_check_ref(const void *addr
)
319 struct wpa_trace_ref
*ref
;
320 dl_list_for_each(ref
, &active_references
, struct wpa_trace_ref
, list
) {
321 if (addr
!= ref
->addr
)
323 wpa_trace_show("Freeing referenced memory");
324 wpa_trace_dump("Reference registration", ref
);
329 #endif /* WPA_TRACE */