diff --git a/hostapd/Makefile b/hostapd/Makefile index 0d52c81a2..ad4ad0578 100644 --- a/hostapd/Makefile +++ b/hostapd/Makefile @@ -51,6 +51,13 @@ CFLAGS += -DHOSTAPD ifdef CONFIG_WPA_TRACE CFLAGS += -DWPA_TRACE OBJS += ../src/utils/trace.o +LDFLAGS += -rdynamic +CFLAGS += -funwind-tables +ifdef CONFIG_WPA_TRACE_BFD +CFLAGS += -DWPA_TRACE_BFD +LIBS += -lbfd +LIBS_c += -lbfd +endif endif OBJS += ../src/utils/eloop.o @@ -725,7 +732,7 @@ OBJS_c += ../src/utils/trace.o OBJS_c += ../src/utils/wpa_debug.o endif hostapd_cli: $(OBJS_c) - $(CC) $(LDFLAGS) -o hostapd_cli $(OBJS_c) + $(CC) $(LDFLAGS) -o hostapd_cli $(OBJS_c) $(LIBS_c) NOBJS = nt_password_hash.o ../src/crypto/ms_funcs.o $(SHA1OBJS) ../src/crypto/rc4.o ../src/crypto/md5.o ifdef CONFIG_INTERNAL_MD5 diff --git a/src/utils/trace.c b/src/utils/trace.c index 18502e388..cf1001063 100644 --- a/src/utils/trace.c +++ b/src/utils/trace.c @@ -19,16 +19,228 @@ #ifdef WPA_TRACE +#ifdef WPA_TRACE_BFD +#include +#include + +static char *prg_fname = NULL; +static bfd *cached_abfd = NULL; +static asymbol **syms = NULL; + +static void get_prg_fname(void) +{ + char exe[50], fname[512]; + int len; + os_snprintf(exe, sizeof(exe) - 1, "/proc/%u/exe", getpid()); + len = readlink(exe, fname, sizeof(fname) - 1); + if (len < 0 || len >= (int) sizeof(fname)) { + perror("readlink"); + return; + } + fname[len] = '\0'; + prg_fname = strdup(fname); +} + + +static bfd * open_bfd(const char *fname) +{ + bfd *abfd; + char **matching; + + abfd = bfd_openr(prg_fname, NULL); + if (abfd == NULL) { + wpa_printf(MSG_INFO, "bfd_openr failed"); + return NULL; + } + + if (bfd_check_format(abfd, bfd_archive)) { + wpa_printf(MSG_INFO, "bfd_check_format failed"); + bfd_close(abfd); + return NULL; + } + + if (!bfd_check_format_matches(abfd, bfd_object, &matching)) { + wpa_printf(MSG_INFO, "bfd_check_format_matches failed"); + free(matching); + bfd_close(abfd); + return NULL; + } + + return abfd; +} + + +static void read_syms(bfd *abfd) +{ + long storage, symcount; + bfd_boolean dynamic = FALSE; + + if (syms) + return; + + if (!(bfd_get_file_flags(abfd) & HAS_SYMS)) { + wpa_printf(MSG_INFO, "No symbols"); + return; + } + + storage = bfd_get_symtab_upper_bound(abfd); + if (storage == 0) { + storage = bfd_get_dynamic_symtab_upper_bound(abfd); + dynamic = TRUE; + } + if (storage < 0) { + wpa_printf(MSG_INFO, "Unknown symtab upper bound"); + return; + } + + syms = malloc(storage); + if (syms == NULL) { + wpa_printf(MSG_INFO, "Failed to allocate memory for symtab " + "(%ld bytes)", storage); + return; + } + if (dynamic) + symcount = bfd_canonicalize_dynamic_symtab(abfd, syms); + else + symcount = bfd_canonicalize_symtab(abfd, syms); + if (symcount < 0) { + wpa_printf(MSG_INFO, "Failed to canonicalize %ssymtab", + dynamic ? "dynamic " : ""); + free(syms); + syms = NULL; + return; + } + wpa_printf(MSG_INFO, "BFD: Read %ld symbols (%ld bytes)", + symcount, storage); +} + + +struct bfd_data { + bfd_vma pc; + bfd_boolean found; + const char *filename; + const char *function; + unsigned int line; +}; + + +static void find_addr_sect(bfd *abfd, asection *section, void *obj) +{ + struct bfd_data *data = obj; + bfd_vma vma; + bfd_size_type size; + + if (data->found) + return; + + if (!(bfd_get_section_vma(abfd, section))) + return; + + vma = bfd_get_section_vma(abfd, section); + if (data->pc < vma) + return; + + size = bfd_get_section_size(section); + if (data->pc >= vma + size) + return; + + data->found = bfd_find_nearest_line(abfd, section, syms, + data->pc - vma, + &data->filename, + &data->function, + &data->line); +} + + +static void wpa_trace_bfd_addr(void *pc) +{ + bfd *abfd = cached_abfd; + struct bfd_data data; + const char *name; + char *aname = NULL; + const char *filename; + + if (abfd == NULL) + return; + + data.pc = (bfd_vma) pc; + data.found = FALSE; + bfd_map_over_sections(abfd, find_addr_sect, &data); + + if (!data.found) + return; + + do { + if (data.function) + aname = bfd_demangle(abfd, data.function, + DMGL_ANSI | DMGL_PARAMS); + name = aname ? aname : data.function; + filename = data.filename; + if (filename) { + char *end = os_strrchr(filename, '/'); + int i = 0; + while (*filename && *filename == prg_fname[i] && + filename <= end) { + filename++; + i++; + } + } + wpa_printf(MSG_INFO, " %s() %s:%u", + name, filename, data.line); + free(aname); + + data.found = bfd_find_inliner_info(abfd, &data.filename, + &data.function, &data.line); + } while (data.found); +} + + +static void wpa_trace_bfd_init(void) +{ + if (!prg_fname) { + get_prg_fname(); + if (!prg_fname) + return; + wpa_printf(MSG_INFO, "BFD[%s]", prg_fname); + } + + if (!cached_abfd) { + cached_abfd = open_bfd(prg_fname); + if (!cached_abfd) { + wpa_printf(MSG_INFO, "Failed to open bfd"); + return; + } + } + + read_syms(cached_abfd); + if (!syms) { + wpa_printf(MSG_INFO, "Failed to read symbols"); + return; + } +} + +#else /* WPA_TRACE_BFD */ + +#define wpa_trace_bfd_init() do { } while (0) +#define wpa_trace_bfd_addr(pc) do { } while (0) + +#endif /* WPA_TRACE_BFD */ + void wpa_trace_dump_func(const char *title, void **btrace, int btrace_num) { char **sym; int i; + wpa_trace_bfd_init(); wpa_printf(MSG_INFO, "WPA_TRACE: %s - START", title); sym = backtrace_symbols(btrace, btrace_num); - for (i = 0; i < btrace_num; i++) - wpa_printf(MSG_INFO, "[%d]: %p: %s", - i, btrace[i], sym ? sym[i] : ""); + for (i = 0; i < btrace_num; i++) { + if (sym) + wpa_printf(MSG_INFO, "[%d]: %s", i, sym[i]); + else + wpa_printf(MSG_INFO, "[%d]: ?? [%p]", i, btrace[i]); + wpa_trace_bfd_addr(btrace[i]); + } free(sym); wpa_printf(MSG_INFO, "WPA_TRACE: %s - END", title); } diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile index 783cbd9b8..f2c314803 100644 --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile @@ -74,6 +74,14 @@ OBJS += ../src/utils/trace.o OBJS_p += ../src/utils/trace.o OBJS_c += ../src/utils/trace.o OBJS_c += ../src/utils/wpa_debug.o +LDFLAGS += -rdynamic +CFLAGS += -funwind-tables +ifdef CONFIG_WPA_TRACE_BFD +CFLAGS += -DWPA_TRACE_BFD +LIBS += -lbfd +LIBS_p += -lbfd +LIBS_c += -lbfd +endif endif ifndef CONFIG_ELOOP