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 */