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 1401264779 Lines: 125 161 77.6 %
Date: 2014-05-28 Functions: 12 12 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           1 : static void get_prg_fname(void)
      30             : {
      31             :         char exe[50], fname[512];
      32             :         int len;
      33           1 :         os_snprintf(exe, sizeof(exe) - 1, "/proc/%u/exe", getpid());
      34           1 :         len = readlink(exe, fname, sizeof(fname) - 1);
      35           1 :         if (len < 0 || len >= (int) sizeof(fname)) {
      36           0 :                 perror("readlink");
      37           1 :                 return;
      38             :         }
      39           1 :         fname[len] = '\0';
      40           1 :         prg_fname = strdup(fname);
      41             : }
      42             : 
      43             : 
      44           1 : static bfd * open_bfd(const char *fname)
      45             : {
      46             :         bfd *abfd;
      47             :         char **matching;
      48             : 
      49           1 :         abfd = bfd_openr(prg_fname, NULL);
      50           1 :         if (abfd == NULL) {
      51           0 :                 wpa_printf(MSG_INFO, "bfd_openr failed");
      52           0 :                 return NULL;
      53             :         }
      54             : 
      55           1 :         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           1 :         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           1 :         return abfd;
      69             : }
      70             : 
      71             : 
      72           2 : static void read_syms(bfd *abfd)
      73             : {
      74             :         long storage, symcount;
      75           2 :         bfd_boolean dynamic = FALSE;
      76             : 
      77           2 :         if (syms)
      78           1 :                 return;
      79             : 
      80           1 :         if (!(bfd_get_file_flags(abfd) & HAS_SYMS)) {
      81           0 :                 wpa_printf(MSG_INFO, "No symbols");
      82           0 :                 return;
      83             :         }
      84             : 
      85           1 :         storage = bfd_get_symtab_upper_bound(abfd);
      86           1 :         if (storage == 0) {
      87           0 :                 storage = bfd_get_dynamic_symtab_upper_bound(abfd);
      88           0 :                 dynamic = TRUE;
      89             :         }
      90           1 :         if (storage < 0) {
      91           0 :                 wpa_printf(MSG_INFO, "Unknown symtab upper bound");
      92           0 :                 return;
      93             :         }
      94             : 
      95           1 :         syms = malloc(storage);
      96           1 :         if (syms == NULL) {
      97           0 :                 wpa_printf(MSG_INFO, "Failed to allocate memory for symtab "
      98             :                            "(%ld bytes)", storage);
      99           0 :                 return;
     100             :         }
     101           1 :         if (dynamic)
     102           0 :                 symcount = bfd_canonicalize_dynamic_symtab(abfd, syms);
     103             :         else
     104           1 :                 symcount = bfd_canonicalize_symtab(abfd, syms);
     105           1 :         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         672 : static void find_addr_sect(bfd *abfd, asection *section, void *obj)
     125             : {
     126         672 :         struct bfd_data *data = obj;
     127             :         bfd_vma vma;
     128             :         bfd_size_type size;
     129             : 
     130         672 :         if (data->found)
     131         380 :                 return;
     132             : 
     133         292 :         if (!(bfd_get_section_vma(abfd, section)))
     134           7 :                 return;
     135             : 
     136         285 :         vma = bfd_get_section_vma(abfd, section);
     137         285 :         if (data->pc < vma)
     138           0 :                 return;
     139             : 
     140         285 :         size = bfd_get_section_size(section);
     141         285 :         if (data->pc >= vma + size)
     142         265 :                 return;
     143             : 
     144          20 :         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_vma) 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_vma) 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           2 : static void wpa_trace_bfd_init(void)
     216             : {
     217           2 :         if (!prg_fname) {
     218           1 :                 get_prg_fname();
     219           1 :                 if (!prg_fname)
     220           0 :                         return;
     221             :         }
     222             : 
     223           2 :         if (!cached_abfd) {
     224           1 :                 cached_abfd = open_bfd(prg_fname);
     225           1 :                 if (!cached_abfd) {
     226           0 :                         wpa_printf(MSG_INFO, "Failed to open bfd");
     227           0 :                         return;
     228             :                 }
     229             :         }
     230             : 
     231           2 :         read_syms(cached_abfd);
     232           2 :         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             : #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           1 : 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           1 :         wpa_trace_bfd_init();
     261           1 :         wpa_printf(MSG_INFO, "WPA_TRACE: %s - START", title);
     262           1 :         sym = backtrace_symbols(btrace, btrace_num);
     263           1 :         state = TRACE_HEAD;
     264          11 :         for (i = 0; i < btrace_num; i++) {
     265          11 :                 const char *func = wpa_trace_bfd_addr2func(btrace[i]);
     266          13 :                 if (state == TRACE_HEAD && func &&
     267           4 :                     (os_strcmp(func, "wpa_trace_add_ref_func") == 0 ||
     268           4 :                      os_strcmp(func, "wpa_trace_check_ref") == 0 ||
     269           2 :                      os_strcmp(func, "wpa_trace_show") == 0))
     270           1 :                         continue;
     271          11 :                 if (state == TRACE_TAIL && sym && sym[i] &&
     272           1 :                     os_strstr(sym[i], "__libc_start_main"))
     273           1 :                         break;
     274           9 :                 if (state == TRACE_HEAD)
     275           1 :                         state = TRACE_RELEVANT;
     276           9 :                 if (sym)
     277           9 :                         wpa_printf(MSG_INFO, "[%d]: %s", i, sym[i]);
     278             :                 else
     279           0 :                         wpa_printf(MSG_INFO, "[%d]: ?? [%p]", i, btrace[i]);
     280           9 :                 wpa_trace_bfd_addr(btrace[i]);
     281          18 :                 if (state == TRACE_RELEVANT && func &&
     282           9 :                     os_strcmp(func, "main") == 0)
     283           1 :                         state = TRACE_TAIL;
     284             :         }
     285           1 :         free(sym);
     286           1 :         wpa_printf(MSG_INFO, "WPA_TRACE: %s - END", title);
     287           1 : }
     288             : 
     289             : 
     290           1 : void wpa_trace_show(const char *title)
     291             : {
     292             :         struct info {
     293             :                 WPA_TRACE_INFO
     294             :         } info;
     295           1 :         wpa_trace_record(&info);
     296           1 :         wpa_trace_dump(title, &info);
     297           1 : }
     298             : 
     299             : 
     300      349356 : void wpa_trace_add_ref_func(struct wpa_trace_ref *ref, const void *addr)
     301             : {
     302      349356 :         if (addr == NULL)
     303      469830 :                 return;
     304      228882 :         ref->addr = addr;
     305      228882 :         wpa_trace_record(ref);
     306      228882 :         dl_list_add(&active_references, &ref->list);
     307             : }
     308             : 
     309             : 
     310      876682 : void wpa_trace_check_ref(const void *addr)
     311             : {
     312             :         struct wpa_trace_ref *ref;
     313    36762132 :         dl_list_for_each(ref, &active_references, struct wpa_trace_ref, list) {
     314    17504384 :                 if (addr != ref->addr)
     315    17504384 :                         continue;
     316           0 :                 wpa_trace_show("Freeing referenced memory");
     317           0 :                 wpa_trace_dump("Reference registration", ref);
     318           0 :                 abort();
     319             :         }
     320      876682 : }
     321             : 
     322             : #endif /* WPA_TRACE */

Generated by: LCOV version 1.10