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
};
29 static char *prg_fname
= NULL
;
30 static bfd
*cached_abfd
= NULL
;
31 static asymbol
**syms
= NULL
;
33 static void get_prg_fname(void)
35 char exe
[50], fname
[512];
37 os_snprintf(exe
, sizeof(exe
) - 1, "/proc/%u/exe", getpid());
38 len
= readlink(exe
, fname
, sizeof(fname
) - 1);
39 if (len
< 0 || len
>= (int) sizeof(fname
)) {
44 prg_fname
= strdup(fname
);
48 static bfd
* open_bfd(const char *fname
)
53 abfd
= bfd_openr(prg_fname
, NULL
);
55 wpa_printf(MSG_INFO
, "bfd_openr failed");
59 if (bfd_check_format(abfd
, bfd_archive
)) {
60 wpa_printf(MSG_INFO
, "bfd_check_format failed");
65 if (!bfd_check_format_matches(abfd
, bfd_object
, &matching
)) {
66 wpa_printf(MSG_INFO
, "bfd_check_format_matches failed");
76 static void read_syms(bfd
*abfd
)
78 long storage
, symcount
;
79 bfd_boolean dynamic
= FALSE
;
84 if (!(bfd_get_file_flags(abfd
) & HAS_SYMS
)) {
85 wpa_printf(MSG_INFO
, "No symbols");
89 storage
= bfd_get_symtab_upper_bound(abfd
);
91 storage
= bfd_get_dynamic_symtab_upper_bound(abfd
);
95 wpa_printf(MSG_INFO
, "Unknown symtab upper bound");
99 syms
= malloc(storage
);
101 wpa_printf(MSG_INFO
, "Failed to allocate memory for symtab "
102 "(%ld bytes)", storage
);
106 symcount
= bfd_canonicalize_dynamic_symtab(abfd
, syms
);
108 symcount
= bfd_canonicalize_symtab(abfd
, syms
);
110 wpa_printf(MSG_INFO
, "Failed to canonicalize %ssymtab",
111 dynamic
? "dynamic " : "");
122 const char *filename
;
123 const char *function
;
128 static void find_addr_sect(bfd
*abfd
, asection
*section
, void *obj
)
130 struct bfd_data
*data
= obj
;
137 if (!(bfd_get_section_vma(abfd
, section
)))
140 vma
= bfd_get_section_vma(abfd
, section
);
144 size
= bfd_get_section_size(section
);
145 if (data
->pc
>= vma
+ size
)
148 data
->found
= bfd_find_nearest_line(abfd
, section
, syms
,
156 static void wpa_trace_bfd_addr(void *pc
)
158 bfd
*abfd
= cached_abfd
;
159 struct bfd_data data
;
162 const char *filename
;
167 data
.pc
= (bfd_vma
) pc
;
169 bfd_map_over_sections(abfd
, find_addr_sect
, &data
);
176 aname
= bfd_demangle(abfd
, data
.function
,
177 DMGL_ANSI
| DMGL_PARAMS
);
178 name
= aname
? aname
: data
.function
;
179 filename
= data
.filename
;
181 char *end
= os_strrchr(filename
, '/');
183 while (*filename
&& *filename
== prg_fname
[i
] &&
189 wpa_printf(MSG_INFO
, " %s() %s:%u",
190 name
, filename
, data
.line
);
193 data
.found
= bfd_find_inliner_info(abfd
, &data
.filename
,
194 &data
.function
, &data
.line
);
195 } while (data
.found
);
199 static const char * wpa_trace_bfd_addr2func(void *pc
)
201 bfd
*abfd
= cached_abfd
;
202 struct bfd_data data
;
207 data
.pc
= (bfd_vma
) pc
;
209 bfd_map_over_sections(abfd
, find_addr_sect
, &data
);
214 return data
.function
;
218 static void wpa_trace_bfd_init(void)
227 cached_abfd
= open_bfd(prg_fname
);
229 wpa_printf(MSG_INFO
, "Failed to open bfd");
234 read_syms(cached_abfd
);
236 wpa_printf(MSG_INFO
, "Failed to read symbols");
242 void wpa_trace_dump_funcname(const char *title
, void *pc
)
244 wpa_printf(MSG_INFO
, "WPA_TRACE: %s: %p", title
, pc
);
245 wpa_trace_bfd_init();
246 wpa_trace_bfd_addr(pc
);
249 #else /* WPA_TRACE_BFD */
251 #define wpa_trace_bfd_init() do { } while (0)
252 #define wpa_trace_bfd_addr(pc) do { } while (0)
253 #define wpa_trace_bfd_addr2func(pc) NULL
255 #endif /* WPA_TRACE_BFD */
257 void wpa_trace_dump_func(const char *title
, void **btrace
, int btrace_num
)
261 enum { TRACE_HEAD
, TRACE_RELEVANT
, TRACE_TAIL
} state
;
263 wpa_trace_bfd_init();
264 wpa_printf(MSG_INFO
, "WPA_TRACE: %s - START", title
);
265 sym
= backtrace_symbols(btrace
, btrace_num
);
267 for (i
= 0; i
< btrace_num
; i
++) {
268 const char *func
= wpa_trace_bfd_addr2func(btrace
[i
]);
269 if (state
== TRACE_HEAD
&& func
&&
270 (os_strcmp(func
, "wpa_trace_add_ref_func") == 0 ||
271 os_strcmp(func
, "wpa_trace_check_ref") == 0 ||
272 os_strcmp(func
, "wpa_trace_show") == 0))
274 if (state
== TRACE_TAIL
&& sym
&& sym
[i
] &&
275 os_strstr(sym
[i
], "__libc_start_main"))
277 if (state
== TRACE_HEAD
)
278 state
= TRACE_RELEVANT
;
280 wpa_printf(MSG_INFO
, "[%d]: %s", i
, sym
[i
]);
282 wpa_printf(MSG_INFO
, "[%d]: ?? [%p]", i
, btrace
[i
]);
283 wpa_trace_bfd_addr(btrace
[i
]);
284 if (state
== TRACE_RELEVANT
&& func
&&
285 os_strcmp(func
, "main") == 0)
289 wpa_printf(MSG_INFO
, "WPA_TRACE: %s - END", title
);
293 void wpa_trace_show(const char *title
)
298 wpa_trace_record(&info
);
299 wpa_trace_dump(title
, &info
);
303 void wpa_trace_add_ref_func(struct wpa_trace_ref
*ref
, const void *addr
)
308 wpa_trace_record(ref
);
309 dl_list_add(&active_references
, &ref
->list
);
313 void wpa_trace_check_ref(const void *addr
)
315 struct wpa_trace_ref
*ref
;
316 dl_list_for_each(ref
, &active_references
, struct wpa_trace_ref
, list
) {
317 if (addr
!= ref
->addr
)
319 wpa_trace_show("Freeing referenced memory");
320 wpa_trace_dump("Reference registration", ref
);
325 #endif /* WPA_TRACE */