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