trace.c
Go to the documentation of this file.
00001 /*
00002  * Backtrace debugging
00003  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License version 2 as
00007  * published by the Free Software Foundation.
00008  *
00009  * Alternatively, this software may be distributed under the terms of BSD
00010  * license.
00011  *
00012  * See README and COPYING for more details.
00013  */
00014 
00015 #include "includes.h"
00016 
00017 #include "common.h"
00018 #include "trace.h"
00019 
00020 #ifdef WPA_TRACE
00021 
00022 static struct dl_list active_references =
00023 { &active_references, &active_references };
00024 
00025 #ifdef WPA_TRACE_BFD
00026 #include <bfd.h>
00027 #ifdef __linux__
00028 #include <demangle.h>
00029 #else /* __linux__ */
00030 #include <libiberty/demangle.h>
00031 #endif /* __linux__ */
00032 
00033 static char *prg_fname = NULL;
00034 static bfd *cached_abfd = NULL;
00035 static asymbol **syms = NULL;
00036 
00037 static void get_prg_fname(void)
00038 {
00039         char exe[50], fname[512];
00040         int len;
00041         os_snprintf(exe, sizeof(exe) - 1, "/proc/%u/exe", getpid());
00042         len = readlink(exe, fname, sizeof(fname) - 1);
00043         if (len < 0 || len >= (int) sizeof(fname)) {
00044                 perror("readlink");
00045                 return;
00046         }
00047         fname[len] = '\0';
00048         prg_fname = strdup(fname);
00049 }
00050 
00051 
00052 static bfd * open_bfd(const char *fname)
00053 {
00054         bfd *abfd;
00055         char **matching;
00056 
00057         abfd = bfd_openr(prg_fname, NULL);
00058         if (abfd == NULL) {
00059                 wpa_printf(MSG_INFO, "bfd_openr failed");
00060                 return NULL;
00061         }
00062 
00063         if (bfd_check_format(abfd, bfd_archive)) {
00064                 wpa_printf(MSG_INFO, "bfd_check_format failed");
00065                 bfd_close(abfd);
00066                 return NULL;
00067         }
00068 
00069         if (!bfd_check_format_matches(abfd, bfd_object, &matching)) {
00070                 wpa_printf(MSG_INFO, "bfd_check_format_matches failed");
00071                 free(matching);
00072                 bfd_close(abfd);
00073                 return NULL;
00074         }
00075 
00076         return abfd;
00077 }
00078 
00079 
00080 static void read_syms(bfd *abfd)
00081 {
00082         long storage, symcount;
00083         bfd_boolean dynamic = FALSE;
00084 
00085         if (syms)
00086                 return;
00087 
00088         if (!(bfd_get_file_flags(abfd) & HAS_SYMS)) {
00089                 wpa_printf(MSG_INFO, "No symbols");
00090                 return;
00091         }
00092 
00093         storage = bfd_get_symtab_upper_bound(abfd);
00094         if (storage == 0) {
00095                 storage = bfd_get_dynamic_symtab_upper_bound(abfd);
00096                 dynamic = TRUE;
00097         }
00098         if (storage < 0) {
00099                 wpa_printf(MSG_INFO, "Unknown symtab upper bound");
00100                 return;
00101         }
00102 
00103         syms = malloc(storage);
00104         if (syms == NULL) {
00105                 wpa_printf(MSG_INFO, "Failed to allocate memory for symtab "
00106                            "(%ld bytes)", storage);
00107                 return;
00108         }
00109         if (dynamic)
00110                 symcount = bfd_canonicalize_dynamic_symtab(abfd, syms);
00111         else
00112                 symcount = bfd_canonicalize_symtab(abfd, syms);
00113         if (symcount < 0) {
00114                 wpa_printf(MSG_INFO, "Failed to canonicalize %ssymtab",
00115                            dynamic ? "dynamic " : "");
00116                 free(syms);
00117                 syms = NULL;
00118                 return;
00119         }
00120 }
00121 
00122 
00123 struct bfd_data {
00124         bfd_vma pc;
00125         bfd_boolean found;
00126         const char *filename;
00127         const char *function;
00128         unsigned int line;
00129 };
00130 
00131 
00132 static void find_addr_sect(bfd *abfd, asection *section, void *obj)
00133 {
00134         struct bfd_data *data = obj;
00135         bfd_vma vma;
00136         bfd_size_type size;
00137 
00138         if (data->found)
00139                 return;
00140 
00141         if (!(bfd_get_section_vma(abfd, section)))
00142                 return;
00143 
00144         vma = bfd_get_section_vma(abfd, section);
00145         if (data->pc < vma)
00146                 return;
00147 
00148         size = bfd_get_section_size(section);
00149         if (data->pc >= vma + size)
00150                 return;
00151 
00152         data->found = bfd_find_nearest_line(abfd, section, syms,
00153                                             data->pc - vma,
00154                                             &data->filename,
00155                                             &data->function,
00156                                             &data->line);
00157 }
00158 
00159 
00160 static void wpa_trace_bfd_addr(void *pc)
00161 {
00162         bfd *abfd = cached_abfd;
00163         struct bfd_data data;
00164         const char *name;
00165         char *aname = NULL;
00166         const char *filename;
00167 
00168         if (abfd == NULL)
00169                 return;
00170 
00171         data.pc = (bfd_vma) pc;
00172         data.found = FALSE;
00173         bfd_map_over_sections(abfd, find_addr_sect, &data);
00174 
00175         if (!data.found)
00176                 return;
00177 
00178         do {
00179                 if (data.function)
00180                         aname = bfd_demangle(abfd, data.function,
00181                                              DMGL_ANSI | DMGL_PARAMS);
00182                 name = aname ? aname : data.function;
00183                 filename = data.filename;
00184                 if (filename) {
00185                         char *end = os_strrchr(filename, '/');
00186                         int i = 0;
00187                         while (*filename && *filename == prg_fname[i] &&
00188                                filename <= end) {
00189                                 filename++;
00190                                 i++;
00191                         }
00192                 }
00193                 wpa_printf(MSG_INFO, "     %s() %s:%u",
00194                            name, filename, data.line);
00195                 free(aname);
00196 
00197                 data.found = bfd_find_inliner_info(abfd, &data.filename,
00198                                                    &data.function, &data.line);
00199         } while (data.found);
00200 }
00201 
00202 
00203 static const char * wpa_trace_bfd_addr2func(void *pc)
00204 {
00205         bfd *abfd = cached_abfd;
00206         struct bfd_data data;
00207 
00208         if (abfd == NULL)
00209                 return NULL;
00210 
00211         data.pc = (bfd_vma) pc;
00212         data.found = FALSE;
00213         bfd_map_over_sections(abfd, find_addr_sect, &data);
00214 
00215         if (!data.found)
00216                 return NULL;
00217 
00218         return data.function;
00219 }
00220 
00221 
00222 static void wpa_trace_bfd_init(void)
00223 {
00224         if (!prg_fname) {
00225                 get_prg_fname();
00226                 if (!prg_fname)
00227                         return;
00228         }
00229 
00230         if (!cached_abfd) {
00231                 cached_abfd = open_bfd(prg_fname);
00232                 if (!cached_abfd) {
00233                         wpa_printf(MSG_INFO, "Failed to open bfd");
00234                         return;
00235                 }
00236         }
00237 
00238         read_syms(cached_abfd);
00239         if (!syms) {
00240                 wpa_printf(MSG_INFO, "Failed to read symbols");
00241                 return;
00242         }
00243 }
00244 
00245 
00246 void wpa_trace_dump_funcname(const char *title, void *pc)
00247 {
00248         wpa_printf(MSG_INFO, "WPA_TRACE: %s: %p", title, pc);
00249         wpa_trace_bfd_init();
00250         wpa_trace_bfd_addr(pc);
00251 }
00252 
00253 #else /* WPA_TRACE_BFD */
00254 
00255 #define wpa_trace_bfd_init() do { } while (0)
00256 #define wpa_trace_bfd_addr(pc) do { } while (0)
00257 #define wpa_trace_bfd_addr2func(pc) NULL
00258 
00259 #endif /* WPA_TRACE_BFD */
00260 
00261 void wpa_trace_dump_func(const char *title, void **btrace, int btrace_num)
00262 {
00263         char **sym;
00264         int i;
00265         enum { TRACE_HEAD, TRACE_RELEVANT, TRACE_TAIL } state;
00266 
00267         wpa_trace_bfd_init();
00268         wpa_printf(MSG_INFO, "WPA_TRACE: %s - START", title);
00269         sym = backtrace_symbols(btrace, btrace_num);
00270         state = TRACE_HEAD;
00271         for (i = 0; i < btrace_num; i++) {
00272                 const char *func = wpa_trace_bfd_addr2func(btrace[i]);
00273                 if (state == TRACE_HEAD && func &&
00274                     (os_strcmp(func, "wpa_trace_add_ref_func") == 0 ||
00275                      os_strcmp(func, "wpa_trace_check_ref") == 0 ||
00276                      os_strcmp(func, "wpa_trace_show") == 0))
00277                         continue;
00278                 if (state == TRACE_TAIL && sym && sym[i] &&
00279                     os_strstr(sym[i], "__libc_start_main"))
00280                         break;
00281                 if (state == TRACE_HEAD)
00282                         state = TRACE_RELEVANT;
00283                 if (sym)
00284                         wpa_printf(MSG_INFO, "[%d]: %s", i, sym[i]);
00285                 else
00286                         wpa_printf(MSG_INFO, "[%d]: ?? [%p]", i, btrace[i]);
00287                 wpa_trace_bfd_addr(btrace[i]);
00288                 if (state == TRACE_RELEVANT && func &&
00289                     os_strcmp(func, "main") == 0)
00290                         state = TRACE_TAIL;
00291         }
00292         free(sym);
00293         wpa_printf(MSG_INFO, "WPA_TRACE: %s - END", title);
00294 }
00295 
00296 
00297 void wpa_trace_show(const char *title)
00298 {
00299         struct info {
00300                 WPA_TRACE_INFO
00301         } info;
00302         wpa_trace_record(&info);
00303         wpa_trace_dump(title, &info);
00304 }
00305 
00306 
00307 void wpa_trace_add_ref_func(struct wpa_trace_ref *ref, const void *addr)
00308 {
00309         if (addr == NULL)
00310                 return;
00311         ref->addr = addr;
00312         wpa_trace_record(ref);
00313         dl_list_add(&active_references, &ref->list);
00314 }
00315 
00316 
00317 void wpa_trace_check_ref(const void *addr)
00318 {
00319         struct wpa_trace_ref *ref;
00320         dl_list_for_each(ref, &active_references, struct wpa_trace_ref, list) {
00321                 if (addr != ref->addr)
00322                         continue;
00323                 wpa_trace_show("Freeing referenced memory");
00324                 wpa_trace_dump("Reference registration", ref);
00325                 abort();
00326         }
00327 }
00328 
00329 #endif /* WPA_TRACE */


wpa_supplicant_node
Author(s): Package maintained by Blaise Gassend
autogenerated on Thu Jan 2 2014 11:25:15