00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
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
00030 #include <libiberty/demangle.h>
00031 #endif
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
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
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