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
) ((u8
*) 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
) ((u8
*) 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
) ((u8
*) 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 */