LCOV - code coverage report
Current view: top level - src/utils - trace.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1443382998 Lines: 146 187 78.1 %
Date: 2015-09-27 Functions: 13 13 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Backtrace debugging
       3             :  * Copyright (c) 2009, Jouni Malinen <j@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          13 : static void get_prg_fname(void)
      30             : {
      31             :         char exe[50], fname[512];
      32             :         int len;
      33          13 :         os_snprintf(exe, sizeof(exe) - 1, "/proc/%u/exe", getpid());
      34          13 :         len = readlink(exe, fname, sizeof(fname) - 1);
      35          13 :         if (len < 0 || len >= (int) sizeof(fname)) {
      36           0 :                 wpa_printf(MSG_ERROR, "readlink: %s", strerror(errno));
      37          13 :                 return;
      38             :         }
      39          13 :         fname[len] = '\0';
      40          13 :         prg_fname = strdup(fname);
      41             : }
      42             : 
      43             : 
      44          13 : static bfd * open_bfd(const char *fname)
      45             : {
      46             :         bfd *abfd;
      47             :         char **matching;
      48             : 
      49          13 :         abfd = bfd_openr(prg_fname, NULL);
      50          13 :         if (abfd == NULL) {
      51           0 :                 wpa_printf(MSG_INFO, "bfd_openr failed");
      52           0 :                 return NULL;
      53             :         }
      54             : 
      55          13 :         if (bfd_check_format(abfd, bfd_archive)) {
      56           0 :                 wpa_printf(MSG_INFO, "bfd_check_format failed");
      57           0 :                 bfd_close(abfd);
      58           0 :                 return NULL;
      59             :         }
      60             : 
      61          13 :         if (!bfd_check_format_matches(abfd, bfd_object, &matching)) {
      62           0 :                 wpa_printf(MSG_INFO, "bfd_check_format_matches failed");
      63           0 :                 free(matching);
      64           0 :                 bfd_close(abfd);
      65           0 :                 return NULL;
      66             :         }
      67             : 
      68          13 :         return abfd;
      69             : }
      70             : 
      71             : 
      72       77134 : static void read_syms(bfd *abfd)
      73             : {
      74             :         long storage, symcount;
      75       77134 :         bfd_boolean dynamic = FALSE;
      76             : 
      77       77134 :         if (syms)
      78       77121 :                 return;
      79             : 
      80          13 :         if (!(bfd_get_file_flags(abfd) & HAS_SYMS)) {
      81           0 :                 wpa_printf(MSG_INFO, "No symbols");
      82           0 :                 return;
      83             :         }
      84             : 
      85          13 :         storage = bfd_get_symtab_upper_bound(abfd);
      86          13 :         if (storage == 0) {
      87           0 :                 storage = bfd_get_dynamic_symtab_upper_bound(abfd);
      88           0 :                 dynamic = TRUE;
      89             :         }
      90          13 :         if (storage < 0) {
      91           0 :                 wpa_printf(MSG_INFO, "Unknown symtab upper bound");
      92           0 :                 return;
      93             :         }
      94             : 
      95          13 :         syms = malloc(storage);
      96          13 :         if (syms == NULL) {
      97           0 :                 wpa_printf(MSG_INFO, "Failed to allocate memory for symtab "
      98             :                            "(%ld bytes)", storage);
      99           0 :                 return;
     100             :         }
     101          13 :         if (dynamic)
     102           0 :                 symcount = bfd_canonicalize_dynamic_symtab(abfd, syms);
     103             :         else
     104          13 :                 symcount = bfd_canonicalize_symtab(abfd, syms);
     105          13 :         if (symcount < 0) {
     106           0 :                 wpa_printf(MSG_INFO, "Failed to canonicalize %ssymtab",
     107             :                            dynamic ? "dynamic " : "");
     108           0 :                 free(syms);
     109           0 :                 syms = NULL;
     110           0 :                 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    37200192 : static void find_addr_sect(bfd *abfd, asection *section, void *obj)
     125             : {
     126    37200192 :         struct bfd_data *data = obj;
     127             :         bfd_vma vma;
     128             :         bfd_size_type size;
     129             : 
     130    37200192 :         if (data->found)
     131    20567082 :                 return;
     132             : 
     133    16633110 :         if (!(bfd_get_section_vma(abfd, section)))
     134      560196 :                 return;
     135             : 
     136    16072914 :         vma = bfd_get_section_vma(abfd, section);
     137    16072914 :         if (data->pc < vma)
     138           0 :                 return;
     139             : 
     140    16072914 :         size = bfd_get_section_size(section);
     141    16072914 :         if (data->pc >= vma + size)
     142    14990436 :                 return;
     143             : 
     144     1082478 :         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          10 : static void wpa_trace_bfd_addr(void *pc)
     153             : {
     154          10 :         bfd *abfd = cached_abfd;
     155             :         struct bfd_data data;
     156             :         const char *name;
     157          10 :         char *aname = NULL;
     158             :         const char *filename;
     159             : 
     160          10 :         if (abfd == NULL)
     161           0 :                 return;
     162             : 
     163          10 :         data.pc = (bfd_hostptr_t) pc;
     164          10 :         data.found = FALSE;
     165          10 :         bfd_map_over_sections(abfd, find_addr_sect, &data);
     166             : 
     167          10 :         if (!data.found)
     168           0 :                 return;
     169             : 
     170             :         do {
     171          10 :                 if (data.function)
     172          10 :                         aname = bfd_demangle(abfd, data.function,
     173             :                                              DMGL_ANSI | DMGL_PARAMS);
     174          10 :                 name = aname ? aname : data.function;
     175          10 :                 filename = data.filename;
     176          10 :                 if (filename) {
     177          10 :                         char *end = os_strrchr(filename, '/');
     178          10 :                         int i = 0;
     179         385 :                         while (*filename && *filename == prg_fname[i] &&
     180             :                                filename <= end) {
     181         365 :                                 filename++;
     182         365 :                                 i++;
     183             :                         }
     184             :                 }
     185          10 :                 wpa_printf(MSG_INFO, "     %s() %s:%u",
     186             :                            name, filename, data.line);
     187          10 :                 free(aname);
     188          10 :                 aname = NULL;
     189             : 
     190          10 :                 data.found = bfd_find_inliner_info(abfd, &data.filename,
     191             :                                                    &data.function, &data.line);
     192          10 :         } while (data.found);
     193             : }
     194             : 
     195             : 
     196          11 : static const char * wpa_trace_bfd_addr2func(void *pc)
     197             : {
     198          11 :         bfd *abfd = cached_abfd;
     199             :         struct bfd_data data;
     200             : 
     201          11 :         if (abfd == NULL)
     202           0 :                 return NULL;
     203             : 
     204          11 :         data.pc = (bfd_hostptr_t) pc;
     205          11 :         data.found = FALSE;
     206          11 :         bfd_map_over_sections(abfd, find_addr_sect, &data);
     207             : 
     208          11 :         if (!data.found)
     209           1 :                 return NULL;
     210             : 
     211          10 :         return data.function;
     212             : }
     213             : 
     214             : 
     215       77134 : static void wpa_trace_bfd_init(void)
     216             : {
     217       77134 :         if (!prg_fname) {
     218          13 :                 get_prg_fname();
     219          13 :                 if (!prg_fname)
     220           0 :                         return;
     221             :         }
     222             : 
     223       77134 :         if (!cached_abfd) {
     224          13 :                 cached_abfd = open_bfd(prg_fname);
     225          13 :                 if (!cached_abfd) {
     226           0 :                         wpa_printf(MSG_INFO, "Failed to open bfd");
     227           0 :                         return;
     228             :                 }
     229             :         }
     230             : 
     231       77134 :         read_syms(cached_abfd);
     232       77134 :         if (!syms) {
     233           0 :                 wpa_printf(MSG_INFO, "Failed to read symbols");
     234           0 :                 return;
     235             :         }
     236             : }
     237             : 
     238             : 
     239           1 : void wpa_trace_dump_funcname(const char *title, void *pc)
     240             : {
     241           1 :         wpa_printf(MSG_INFO, "WPA_TRACE: %s: %p", title, pc);
     242           1 :         wpa_trace_bfd_init();
     243           1 :         wpa_trace_bfd_addr(pc);
     244           1 : }
     245             : 
     246             : 
     247       77132 : size_t wpa_trace_calling_func(const char *buf[], size_t len)
     248             : {
     249             :         bfd *abfd;
     250             :         void *btrace_res[WPA_TRACE_LEN];
     251             :         int i, btrace_num;
     252       77132 :         size_t pos = 0;
     253             : 
     254       77132 :         if (len == 0)
     255           0 :                 return 0;
     256       77132 :         if (len > WPA_TRACE_LEN)
     257           0 :                 len = WPA_TRACE_LEN;
     258             : 
     259       77132 :         wpa_trace_bfd_init();
     260       77132 :         abfd = cached_abfd;
     261       77132 :         if (!abfd)
     262           0 :                 return 0;
     263             : 
     264       77132 :         btrace_num = backtrace(btrace_res, len);
     265       77132 :         if (btrace_num < 1)
     266           0 :                 return 0;
     267             : 
     268     1239617 :         for (i = 0; i < btrace_num; i++) {
     269             :                 struct bfd_data data;
     270             : 
     271     1162485 :                 data.pc = (bfd_hostptr_t) btrace_res[i];
     272     1162485 :                 data.found = FALSE;
     273     1162485 :                 bfd_map_over_sections(abfd, find_addr_sect, &data);
     274             : 
     275     3407428 :                 while (data.found) {
     276     1082458 :                         if (data.function &&
     277      154264 :                             (pos > 0 ||
     278      154264 :                              os_strcmp(data.function, __func__) != 0)) {
     279     1005326 :                                 buf[pos++] = data.function;
     280     1005326 :                                 if (pos == len)
     281           0 :                                         return pos;
     282             :                         }
     283             : 
     284     1082458 :                         data.found = bfd_find_inliner_info(abfd, &data.filename,
     285             :                                                            &data.function,
     286             :                                                            &data.line);
     287             :                 }
     288             :         }
     289             : 
     290       77132 :         return pos;
     291             : }
     292             : 
     293             : #else /* WPA_TRACE_BFD */
     294             : 
     295             : #define wpa_trace_bfd_init() do { } while (0)
     296             : #define wpa_trace_bfd_addr(pc) do { } while (0)
     297             : #define wpa_trace_bfd_addr2func(pc) NULL
     298             : 
     299             : #endif /* WPA_TRACE_BFD */
     300             : 
     301           1 : void wpa_trace_dump_func(const char *title, void **btrace, int btrace_num)
     302             : {
     303             :         char **sym;
     304             :         int i;
     305             :         enum { TRACE_HEAD, TRACE_RELEVANT, TRACE_TAIL } state;
     306             : 
     307           1 :         wpa_trace_bfd_init();
     308           1 :         wpa_printf(MSG_INFO, "WPA_TRACE: %s - START", title);
     309           1 :         sym = backtrace_symbols(btrace, btrace_num);
     310           1 :         state = TRACE_HEAD;
     311          11 :         for (i = 0; i < btrace_num; i++) {
     312          11 :                 const char *func = wpa_trace_bfd_addr2func(btrace[i]);
     313          13 :                 if (state == TRACE_HEAD && func &&
     314           4 :                     (os_strcmp(func, "wpa_trace_add_ref_func") == 0 ||
     315           4 :                      os_strcmp(func, "wpa_trace_check_ref") == 0 ||
     316           2 :                      os_strcmp(func, "wpa_trace_show") == 0))
     317           1 :                         continue;
     318          11 :                 if (state == TRACE_TAIL && sym && sym[i] &&
     319           1 :                     os_strstr(sym[i], "__libc_start_main"))
     320           1 :                         break;
     321           9 :                 if (state == TRACE_HEAD)
     322           1 :                         state = TRACE_RELEVANT;
     323           9 :                 if (sym)
     324           9 :                         wpa_printf(MSG_INFO, "[%d]: %s", i, sym[i]);
     325             :                 else
     326           0 :                         wpa_printf(MSG_INFO, "[%d]: ?? [%p]", i, btrace[i]);
     327           9 :                 wpa_trace_bfd_addr(btrace[i]);
     328          18 :                 if (state == TRACE_RELEVANT && func &&
     329           9 :                     os_strcmp(func, "main") == 0)
     330           1 :                         state = TRACE_TAIL;
     331             :         }
     332           1 :         free(sym);
     333           1 :         wpa_printf(MSG_INFO, "WPA_TRACE: %s - END", title);
     334           1 : }
     335             : 
     336             : 
     337           1 : void wpa_trace_show(const char *title)
     338             : {
     339             :         struct info {
     340             :                 WPA_TRACE_INFO
     341             :         } info;
     342           1 :         wpa_trace_record(&info);
     343           1 :         wpa_trace_dump(title, &info);
     344           1 : }
     345             : 
     346             : 
     347     1508764 : void wpa_trace_add_ref_func(struct wpa_trace_ref *ref, const void *addr)
     348             : {
     349     1508764 :         if (addr == NULL)
     350     1998172 :                 return;
     351     1019356 :         ref->addr = addr;
     352     1019356 :         wpa_trace_record(ref);
     353     1019356 :         dl_list_add(&active_references, &ref->list);
     354             : }
     355             : 
     356             : 
     357     3588701 : void wpa_trace_check_ref(const void *addr)
     358             : {
     359             :         struct wpa_trace_ref *ref;
     360   380489350 :         dl_list_for_each(ref, &active_references, struct wpa_trace_ref, list) {
     361   186655974 :                 if (addr != ref->addr)
     362   186655974 :                         continue;
     363           0 :                 wpa_trace_show("Freeing referenced memory");
     364           0 :                 wpa_trace_dump("Reference registration", ref);
     365           0 :                 abort();
     366             :         }
     367     3588701 : }
     368             : 
     369             : #endif /* WPA_TRACE */

Generated by: LCOV version 1.10