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