]> git.ipfire.org Git - thirdparty/hostap.git/blob - src/utils/trace.c
Remove the GPL notification from files contributed by Jouni Malinen
[thirdparty/hostap.git] / src / utils / trace.c
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
16 static 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
27 static char *prg_fname = NULL;
28 static bfd *cached_abfd = NULL;
29 static asymbol **syms = NULL;
30
31 static 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
46 static 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
74 static 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
117 struct 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
126 static 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
154 static 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
197 static 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
216 static 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
240 void 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
255 void 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
291 void 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
301 void 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
311 void 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 */