]> git.ipfire.org Git - thirdparty/hostap.git/blame - src/utils/trace.c
trace: Filter out uninteresting functions from backtrace
[thirdparty/hostap.git] / src / utils / trace.c
CommitLineData
930f704a
JM
1/*
2 * Backtrace debugging
3 * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
4 *
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.
8 *
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
11 *
12 * See README and COPYING for more details.
13 */
14
15#include "includes.h"
16
17#include "common.h"
18#include "trace.h"
19
20#ifdef WPA_TRACE
21
a6ff0e08
JM
22static struct dl_list active_references =
23{ &active_references, &active_references };
24
f2f7d965
JM
25#ifdef WPA_TRACE_BFD
26#include <bfd.h>
27#include <demangle.h>
28
29static char *prg_fname = NULL;
30static bfd *cached_abfd = NULL;
31static asymbol **syms = NULL;
32
33static void get_prg_fname(void)
34{
35 char exe[50], fname[512];
36 int len;
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)) {
40 perror("readlink");
41 return;
42 }
43 fname[len] = '\0';
44 prg_fname = strdup(fname);
45}
46
47
48static bfd * open_bfd(const char *fname)
49{
50 bfd *abfd;
51 char **matching;
52
53 abfd = bfd_openr(prg_fname, NULL);
54 if (abfd == NULL) {
55 wpa_printf(MSG_INFO, "bfd_openr failed");
56 return NULL;
57 }
58
59 if (bfd_check_format(abfd, bfd_archive)) {
60 wpa_printf(MSG_INFO, "bfd_check_format failed");
61 bfd_close(abfd);
62 return NULL;
63 }
64
65 if (!bfd_check_format_matches(abfd, bfd_object, &matching)) {
66 wpa_printf(MSG_INFO, "bfd_check_format_matches failed");
67 free(matching);
68 bfd_close(abfd);
69 return NULL;
70 }
71
72 return abfd;
73}
74
75
76static void read_syms(bfd *abfd)
77{
78 long storage, symcount;
79 bfd_boolean dynamic = FALSE;
80
81 if (syms)
82 return;
83
84 if (!(bfd_get_file_flags(abfd) & HAS_SYMS)) {
85 wpa_printf(MSG_INFO, "No symbols");
86 return;
87 }
88
89 storage = bfd_get_symtab_upper_bound(abfd);
90 if (storage == 0) {
91 storage = bfd_get_dynamic_symtab_upper_bound(abfd);
92 dynamic = TRUE;
93 }
94 if (storage < 0) {
95 wpa_printf(MSG_INFO, "Unknown symtab upper bound");
96 return;
97 }
98
99 syms = malloc(storage);
100 if (syms == NULL) {
101 wpa_printf(MSG_INFO, "Failed to allocate memory for symtab "
102 "(%ld bytes)", storage);
103 return;
104 }
105 if (dynamic)
106 symcount = bfd_canonicalize_dynamic_symtab(abfd, syms);
107 else
108 symcount = bfd_canonicalize_symtab(abfd, syms);
109 if (symcount < 0) {
110 wpa_printf(MSG_INFO, "Failed to canonicalize %ssymtab",
111 dynamic ? "dynamic " : "");
112 free(syms);
113 syms = NULL;
114 return;
115 }
116 wpa_printf(MSG_INFO, "BFD: Read %ld symbols (%ld bytes)",
117 symcount, storage);
118}
119
120
121struct bfd_data {
122 bfd_vma pc;
123 bfd_boolean found;
124 const char *filename;
125 const char *function;
126 unsigned int line;
127};
128
129
130static void find_addr_sect(bfd *abfd, asection *section, void *obj)
131{
132 struct bfd_data *data = obj;
133 bfd_vma vma;
134 bfd_size_type size;
135
136 if (data->found)
137 return;
138
139 if (!(bfd_get_section_vma(abfd, section)))
140 return;
141
142 vma = bfd_get_section_vma(abfd, section);
143 if (data->pc < vma)
144 return;
145
146 size = bfd_get_section_size(section);
147 if (data->pc >= vma + size)
148 return;
149
150 data->found = bfd_find_nearest_line(abfd, section, syms,
151 data->pc - vma,
152 &data->filename,
153 &data->function,
154 &data->line);
155}
156
157
158static void wpa_trace_bfd_addr(void *pc)
159{
160 bfd *abfd = cached_abfd;
161 struct bfd_data data;
162 const char *name;
163 char *aname = NULL;
164 const char *filename;
165
166 if (abfd == NULL)
167 return;
168
169 data.pc = (bfd_vma) pc;
170 data.found = FALSE;
171 bfd_map_over_sections(abfd, find_addr_sect, &data);
172
173 if (!data.found)
174 return;
175
176 do {
177 if (data.function)
178 aname = bfd_demangle(abfd, data.function,
179 DMGL_ANSI | DMGL_PARAMS);
180 name = aname ? aname : data.function;
181 filename = data.filename;
182 if (filename) {
183 char *end = os_strrchr(filename, '/');
184 int i = 0;
185 while (*filename && *filename == prg_fname[i] &&
186 filename <= end) {
187 filename++;
188 i++;
189 }
190 }
191 wpa_printf(MSG_INFO, " %s() %s:%u",
192 name, filename, data.line);
193 free(aname);
194
195 data.found = bfd_find_inliner_info(abfd, &data.filename,
196 &data.function, &data.line);
197 } while (data.found);
198}
199
200
94caf8cd
JM
201static const char * wpa_trace_bfd_addr2func(void *pc)
202{
203 bfd *abfd = cached_abfd;
204 struct bfd_data data;
205
206 if (abfd == NULL)
207 return NULL;
208
209 data.pc = (bfd_vma) pc;
210 data.found = FALSE;
211 bfd_map_over_sections(abfd, find_addr_sect, &data);
212
213 if (!data.found)
214 return NULL;
215
216 return data.function;
217}
218
219
f2f7d965
JM
220static void wpa_trace_bfd_init(void)
221{
222 if (!prg_fname) {
223 get_prg_fname();
224 if (!prg_fname)
225 return;
226 wpa_printf(MSG_INFO, "BFD[%s]", prg_fname);
227 }
228
229 if (!cached_abfd) {
230 cached_abfd = open_bfd(prg_fname);
231 if (!cached_abfd) {
232 wpa_printf(MSG_INFO, "Failed to open bfd");
233 return;
234 }
235 }
236
237 read_syms(cached_abfd);
238 if (!syms) {
239 wpa_printf(MSG_INFO, "Failed to read symbols");
240 return;
241 }
242}
243
244#else /* WPA_TRACE_BFD */
245
246#define wpa_trace_bfd_init() do { } while (0)
247#define wpa_trace_bfd_addr(pc) do { } while (0)
94caf8cd 248#define wpa_trace_bfd_addr2func(pc) NULL
f2f7d965
JM
249
250#endif /* WPA_TRACE_BFD */
251
930f704a
JM
252void wpa_trace_dump_func(const char *title, void **btrace, int btrace_num)
253{
254 char **sym;
255 int i;
94caf8cd 256 enum { TRACE_HEAD, TRACE_RELEVANT, TRACE_TAIL } state;
930f704a 257
f2f7d965 258 wpa_trace_bfd_init();
930f704a
JM
259 wpa_printf(MSG_INFO, "WPA_TRACE: %s - START", title);
260 sym = backtrace_symbols(btrace, btrace_num);
94caf8cd 261 state = TRACE_HEAD;
f2f7d965 262 for (i = 0; i < btrace_num; i++) {
94caf8cd
JM
263 const char *func = wpa_trace_bfd_addr2func(btrace[i]);
264 if (state == TRACE_HEAD && func &&
265 (os_strcmp(func, "wpa_trace_add_ref_func") == 0 ||
266 os_strcmp(func, "wpa_trace_check_ref") == 0 ||
267 os_strcmp(func, "wpa_trace_show") == 0))
268 continue;
269 if (state == TRACE_TAIL && sym && sym[i] &&
270 os_strstr(sym[i], "__libc_start_main"))
271 break;
272 if (state == TRACE_HEAD)
273 state = TRACE_RELEVANT;
f2f7d965
JM
274 if (sym)
275 wpa_printf(MSG_INFO, "[%d]: %s", i, sym[i]);
276 else
277 wpa_printf(MSG_INFO, "[%d]: ?? [%p]", i, btrace[i]);
278 wpa_trace_bfd_addr(btrace[i]);
94caf8cd
JM
279 if (state == TRACE_RELEVANT && func &&
280 os_strcmp(func, "main") == 0)
281 state = TRACE_TAIL;
f2f7d965 282 }
fb4baa68 283 free(sym);
930f704a
JM
284 wpa_printf(MSG_INFO, "WPA_TRACE: %s - END", title);
285}
286
287
288void wpa_trace_show(const char *title)
289{
290 struct info {
291 WPA_TRACE_INFO
292 } info;
293 wpa_trace_record(&info);
294 wpa_trace_dump(title, &info);
295}
296
a6ff0e08
JM
297
298void wpa_trace_add_ref_func(struct wpa_trace_ref *ref, const void *addr)
299{
300 if (addr == NULL)
301 return;
302 ref->addr = addr;
303 wpa_trace_record(ref);
304 dl_list_add(&active_references, &ref->list);
305}
306
307
308void wpa_trace_check_ref(const void *addr)
309{
310 struct wpa_trace_ref *ref;
311 dl_list_for_each(ref, &active_references, struct wpa_trace_ref, list) {
312 if (addr != ref->addr)
313 continue;
314 wpa_trace_show("Freeing referenced memory");
315 wpa_trace_dump("Reference registration", ref);
316 abort();
317 }
318}
319
930f704a 320#endif /* WPA_TRACE */