LCOV - code coverage report
Current view: top level - elfutils/libdwfl - dwfl_module_addrsym.c (source / functions) Hit Total Coverage
Test: lcov.out Lines: 75 75 100.0 %
Date: 2012-10-31 Functions: 3 3 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 77 92 83.7 %

           Branch data     Line data    Source code
       1                 :            : /* Find debugging and symbol information for a module in libdwfl.
       2                 :            :    Copyright (C) 2005-2011 Red Hat, Inc.
       3                 :            :    This file is part of elfutils.
       4                 :            : 
       5                 :            :    This file is free software; you can redistribute it and/or modify
       6                 :            :    it under the terms of either
       7                 :            : 
       8                 :            :      * the GNU Lesser General Public License as published by the Free
       9                 :            :        Software Foundation; either version 3 of the License, or (at
      10                 :            :        your option) any later version
      11                 :            : 
      12                 :            :    or
      13                 :            : 
      14                 :            :      * the GNU General Public License as published by the Free
      15                 :            :        Software Foundation; either version 2 of the License, or (at
      16                 :            :        your option) any later version
      17                 :            : 
      18                 :            :    or both in parallel, as here.
      19                 :            : 
      20                 :            :    elfutils is distributed in the hope that it will be useful, but
      21                 :            :    WITHOUT ANY WARRANTY; without even the implied warranty of
      22                 :            :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      23                 :            :    General Public License for more details.
      24                 :            : 
      25                 :            :    You should have received copies of the GNU General Public License and
      26                 :            :    the GNU Lesser General Public License along with this program.  If
      27                 :            :    not, see <http://www.gnu.org/licenses/>.  */
      28                 :            : 
      29                 :            : #include "libdwflP.h"
      30                 :            : 
      31                 :            : /* Returns the name of the symbol "closest" to ADDR.
      32                 :            :    Never returns symbols at addresses above ADDR.  */
      33                 :            : 
      34                 :            : const char *
      35                 :     525486 : dwfl_module_addrsym (Dwfl_Module *mod, GElf_Addr addr,
      36                 :            :                      GElf_Sym *closest_sym, GElf_Word *shndxp)
      37                 :            : {
      38                 :     525486 :   int syments = INTUSE(dwfl_module_getsymtab) (mod);
      39         [ +  - ]:     525486 :   if (syments < 0)
      40                 :            :     return NULL;
      41                 :            : 
      42                 :            :   /* Return true iff we consider ADDR to lie in the same section as SYM.  */
      43                 :     525486 :   GElf_Word addr_shndx = SHN_UNDEF;
      44                 :     685062 :   inline bool same_section (const GElf_Sym *sym, GElf_Word shndx)
      45                 :            :     {
      46                 :            :       /* For absolute symbols and the like, only match exactly.  */
      47         [ +  + ]:     685062 :       if (shndx >= SHN_LORESERVE)
      48                 :     536299 :         return sym->st_value == addr;
      49                 :            : 
      50                 :            :       /* Figure out what section ADDR lies in.  */
      51         [ +  + ]:     148763 :       if (addr_shndx == SHN_UNDEF)
      52                 :            :         {
      53                 :     154206 :           GElf_Addr mod_addr = dwfl_deadjust_st_value (mod, addr);
      54                 :      77103 :           Elf_Scn *scn = NULL;
      55                 :      77103 :           addr_shndx = SHN_ABS;
      56         [ +  + ]:    1047130 :           while ((scn = elf_nextscn (mod->symfile->elf, scn)) != NULL)
      57                 :            :             {
      58                 :            :               GElf_Shdr shdr_mem;
      59                 :    1046213 :               GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
      60         [ +  - ]:    1046213 :               if (likely (shdr != NULL)
      61         [ +  + ]:    1046213 :                   && mod_addr >= shdr->sh_addr
      62         [ +  + ]:    1046212 :                   && mod_addr < shdr->sh_addr + shdr->sh_size)
      63                 :            :                 {
      64                 :    1046213 :                   addr_shndx = elf_ndxscn (scn);
      65                 :            :                   break;
      66                 :            :                 }
      67                 :            :             }
      68                 :            :         }
      69                 :            : 
      70                 :     685062 :       return shndx == addr_shndx;
      71                 :            :     }
      72                 :            : 
      73                 :            :   /* Keep track of the closest symbol we have seen so far.
      74                 :            :      Here we store only symbols with nonzero st_size.  */
      75                 :     525486 :   const char *closest_name = NULL;
      76                 :     525486 :   GElf_Word closest_shndx = SHN_UNDEF;
      77                 :            : 
      78                 :            :   /* Keep track of an eligible symbol with st_size == 0 as a fallback.  */
      79                 :     525486 :   const char *sizeless_name = NULL;
      80                 :     525486 :   GElf_Sym sizeless_sym = { 0, 0, 0, 0, 0, SHN_UNDEF };
      81                 :     525486 :   GElf_Word sizeless_shndx = SHN_UNDEF;
      82                 :            : 
      83                 :            :   /* Keep track of the lowest address a relevant sizeless symbol could have.  */
      84                 :     525486 :   GElf_Addr min_label = 0;
      85                 :            : 
      86                 :            :   /* Look through the symbol table for a matching symbol.  */
      87                 :     858840 :   inline void search_table (int start, int end)
      88                 :            :     {
      89         [ +  + ]:  458911629 :       for (int i = start; i < end; ++i)
      90                 :            :         {
      91                 :            :           GElf_Sym sym;
      92                 :            :           GElf_Word shndx;
      93                 :  458052789 :           const char *name = INTUSE(dwfl_module_getsym) (mod, i, &sym, &shndx);
      94 [ +  - ][ +  + ]:  458052789 :           if (name != NULL && name[0] != '\0'
      95         [ +  + ]:  446690452 :               && sym.st_shndx != SHN_UNDEF
      96         [ +  + ]:  400580840 :               && sym.st_value <= addr
      97         [ +  - ]:  108493417 :               && GELF_ST_TYPE (sym.st_info) != STT_SECTION
      98         [ +  + ]:  108493417 :               && GELF_ST_TYPE (sym.st_info) != STT_FILE
      99         [ +  + ]:   74357300 :               && GELF_ST_TYPE (sym.st_info) != STT_TLS)
     100                 :            :             {
     101                 :            :               /* Even if we don't choose this symbol, its existence excludes
     102                 :            :                  any sizeless symbol (assembly label) that is below its upper
     103                 :            :                  bound.  */
     104         [ +  + ]:   73833078 :               if (sym.st_value + sym.st_size > min_label)
     105                 :    6225718 :                 min_label = sym.st_value + sym.st_size;
     106                 :            : 
     107 [ +  + ][ +  + ]:   73833078 :               if (sym.st_size == 0 || addr - sym.st_value < sym.st_size)
     108                 :            :                 {
     109                 :            :                   /* Return GELF_ST_BIND as higher-is-better integer.  */
     110                 :            :                   inline int binding_value (const GElf_Sym *symp)
     111                 :            :                     {
     112 [ +  - ][ +  - ]:    1220525 :                       switch (GELF_ST_BIND (symp->st_info))
     113                 :            :                       {
     114                 :            :                         case STB_GLOBAL:
     115                 :            :                           return 3;
     116                 :            :                         case STB_WEAK:
     117                 :            :                           return 2;
     118                 :            :                         case STB_LOCAL:
     119                 :            :                           return 1;
     120                 :            :                         default:
     121                 :            :                           return 0;
     122                 :            :                       }
     123                 :            :                     }
     124                 :            :                   /* This symbol is a better candidate than the current one
     125                 :            :                      if it's closer to ADDR or is global when it was local.  */
     126         [ +  + ]:    3636894 :                   if (closest_name == NULL
     127         [ +  + ]:    1220531 :                       || closest_sym->st_value < sym.st_value
     128         [ +  + ]:    1220525 :                       || binding_value (closest_sym) < binding_value (&sym))
     129                 :            :                     {
     130         [ +  + ]:    2416371 :                       if (sym.st_size != 0)
     131                 :            :                         {
     132                 :     442064 :                           *closest_sym = sym;
     133                 :     442064 :                           closest_shndx = shndx;
     134                 :     442064 :                           closest_name = name;
     135                 :            :                         }
     136         [ +  + ]:    1974307 :                       else if (closest_name == NULL
     137         [ +  + ]:    1974305 :                                && sym.st_value >= min_label
     138         [ +  + ]:     685062 :                                && same_section (&sym, shndx))
     139                 :            :                         {
     140                 :            :                           /* Handwritten assembly symbols sometimes have no
     141                 :            :                              st_size.  If no symbol with proper size includes
     142                 :            :                              the address, we'll use the closest one that is in
     143                 :            :                              the same section as ADDR.  */
     144                 :     149340 :                           sizeless_sym = sym;
     145                 :     149340 :                           sizeless_shndx = shndx;
     146                 :     149340 :                           sizeless_name = name;
     147                 :            :                         }
     148                 :            :                     }
     149                 :            :                   /* When the beginning of its range is no closer,
     150                 :            :                      the end of its range might be.  Otherwise follow
     151                 :            :                      GELF_ST_BIND preference.  If all are equal prefer
     152                 :            :                      the first symbol found.  */
     153         [ +  + ]:    1220523 :                   else if (sym.st_size != 0
     154         [ +  - ]:       3435 :                            && closest_sym->st_value == sym.st_value
     155         [ +  + ]:       3435 :                            && ((closest_sym->st_size > sym.st_size
     156 [ +  - ][ -  + ]:          8 :                                 && (binding_value (closest_sym)
     157         [ +  - ]:          4 :                                     <= binding_value (&sym)))
     158         [ +  - ]:       3431 :                                || (closest_sym->st_size >= sym.st_size
     159 [ +  - ][ -  + ]:       6862 :                                    && (binding_value (closest_sym)
     160         [ +  - ]:       3431 :                                        < binding_value (&sym)))))
     161                 :            :                     {
     162                 :          4 :                       *closest_sym = sym;
     163                 :          4 :                       closest_shndx = shndx;
     164                 :          4 :                       closest_name = name;
     165                 :            :                     }
     166                 :            :                 }
     167                 :            :             }
     168                 :            :         }
     169                 :     858840 :     }
     170                 :            : 
     171                 :            :   /* First go through global symbols.  mod->first_global is setup by
     172                 :            :      dwfl_module_getsymtab to the index of the first global symbol in
     173                 :            :      the module's symbol table, or -1 when unknown.  All symbols with
     174                 :            :      local binding come first in the symbol table, then all globals.  */
     175         [ +  + ]:     525486 :   search_table (mod->first_global < 0 ? 1 : mod->first_global, syments);
     176                 :            : 
     177                 :            :   /* If we found nothing searching the global symbols, then try the locals.
     178                 :            :      Unless we have a global sizeless symbol that matches exactly.  */
     179 [ +  + ][ +  - ]:     525486 :   if (closest_name == NULL && mod->first_global > 1
     180 [ +  + ][ +  + ]:     334346 :       && (sizeless_name == NULL || sizeless_sym.st_value != addr))
     181                 :     333354 :     search_table (1, mod->first_global);
     182                 :            : 
     183                 :            :   /* If we found no proper sized symbol to use, fall back to the best
     184                 :            :      candidate sizeless symbol we found, if any.  */
     185         [ +  + ]:     525486 :   if (closest_name == NULL
     186 [ +  + ][ +  + ]:      83428 :       && sizeless_name != NULL && sizeless_sym.st_value >= min_label)
     187                 :            :     {
     188                 :       3103 :       *closest_sym = sizeless_sym;
     189                 :       3103 :       closest_shndx = sizeless_shndx;
     190                 :       3103 :       closest_name = sizeless_name;
     191                 :            :     }
     192                 :            : 
     193         [ +  + ]:     525486 :   if (shndxp != NULL)
     194                 :         83 :     *shndxp = closest_shndx;
     195                 :     525486 :   return closest_name;
     196                 :            : }
     197                 :    1297628 : INTDEF (dwfl_module_addrsym)

Generated by: LCOV version 1.9