~ubuntu-branches/ubuntu/utopic/moonshot-gss-eap/utopic-backports

« back to all changes in this revision

Viewing changes to libeap/src/utils/trace.c

  • Committer: Package Import Robot
  • Author(s): Sam Hartman
  • Date: 2014-09-16 08:38:39 UTC
  • Revision ID: package-import@ubuntu.com-20140916083839-ipqco3thb1wcwvs0
Tags: upstream-0.9.2
ImportĀ upstreamĀ versionĀ 0.9.2

Show diffs side-by-side

added added

removed removed

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