LCOV - code coverage report
Current view: top level - elfutils/libdwfl - dwfl_module_addrsym.c (source / functions) Hit Total Coverage
Test: lcov.out Lines: 79 79 100.0 %
Date: 2013-03-08 Functions: 3 3 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 83 98 84.7 %

           Branch data     Line data    Source code
       1                 :            : /* Find debugging and symbol information for a module in libdwfl.
       2                 :            :    Copyright (C) 2005-2012 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                 :     541451 : dwfl_module_addrsym (Dwfl_Module *mod, GElf_Addr addr,
      36                 :            :                      GElf_Sym *closest_sym, GElf_Word *shndxp)
      37                 :            : {
      38                 :     541451 :   int syments = INTUSE(dwfl_module_getsymtab) (mod);
      39         [ +  - ]:     541451 :   if (syments < 0)
      40                 :            :     return NULL;
      41                 :            : 
      42                 :            :   /* Return true iff we consider ADDR to lie in the same section as SYM.  */
      43                 :     541451 :   GElf_Word addr_shndx = SHN_UNDEF;
      44                 :     113476 :   inline bool same_section (const GElf_Sym *sym, struct dwfl_file *symfile,
      45                 :            :                             GElf_Word shndx)
      46                 :            :     {
      47                 :            :       /* For absolute symbols and the like, only match exactly.  */
      48         [ +  + ]:     113476 :       if (shndx >= SHN_LORESERVE)
      49                 :      28671 :         return sym->st_value == addr;
      50                 :            : 
      51                 :            :       /* Figure out what section ADDR lies in.  */
      52         [ +  + ]:      84805 :       if (addr_shndx == SHN_UNDEF)
      53                 :            :         {
      54                 :      79139 :           GElf_Addr mod_addr = dwfl_deadjust_st_value (mod, symfile, addr);
      55                 :      79139 :           Elf_Scn *scn = NULL;
      56                 :      79139 :           addr_shndx = SHN_ABS;
      57         [ +  + ]:    1050049 :           while ((scn = elf_nextscn (symfile->elf, scn)) != NULL)
      58                 :            :             {
      59                 :            :               GElf_Shdr shdr_mem;
      60                 :    1050048 :               GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
      61         [ +  - ]:    1050048 :               if (likely (shdr != NULL)
      62         [ +  + ]:    1050048 :                   && mod_addr >= shdr->sh_addr
      63         [ +  + ]:    1050047 :                   && mod_addr < shdr->sh_addr + shdr->sh_size)
      64                 :            :                 {
      65                 :    1050048 :                   addr_shndx = elf_ndxscn (scn);
      66                 :            :                   break;
      67                 :            :                 }
      68                 :            :             }
      69                 :            :         }
      70                 :            : 
      71                 :     113476 :       return shndx == addr_shndx;
      72                 :            :     }
      73                 :            : 
      74                 :            :   /* Keep track of the closest symbol we have seen so far.
      75                 :            :      Here we store only symbols with nonzero st_size.  */
      76                 :     541451 :   const char *closest_name = NULL;
      77                 :     541451 :   GElf_Word closest_shndx = SHN_UNDEF;
      78                 :            : 
      79                 :            :   /* Keep track of an eligible symbol with st_size == 0 as a fallback.  */
      80                 :     541451 :   const char *sizeless_name = NULL;
      81                 :     541451 :   GElf_Sym sizeless_sym = { 0, 0, 0, 0, 0, SHN_UNDEF };
      82                 :     541451 :   GElf_Word sizeless_shndx = SHN_UNDEF;
      83                 :            : 
      84                 :            :   /* Keep track of the lowest address a relevant sizeless symbol could have.  */
      85                 :     541451 :   GElf_Addr min_label = 0;
      86                 :            : 
      87                 :            :   /* Look through the symbol table for a matching symbol.  */
      88                 :     871474 :   inline void search_table (int start, int end)
      89                 :            :     {
      90         [ +  + ]:  464176758 :       for (int i = start; i < end; ++i)
      91                 :            :         {
      92                 :            :           GElf_Sym sym;
      93                 :            :           GElf_Word shndx;
      94                 :  463305284 :           const char *name = INTUSE(dwfl_module_getsym) (mod, i, &sym, &shndx);
      95 [ +  - ][ +  + ]:  463305284 :           if (name != NULL && name[0] != '\0'
      96         [ +  + ]:  451730788 :               && sym.st_shndx != SHN_UNDEF
      97         [ +  + ]:  403876031 :               && sym.st_value <= addr
      98         [ +  - ]:  115013138 :               && GELF_ST_TYPE (sym.st_info) != STT_SECTION
      99         [ +  + ]:  115013138 :               && GELF_ST_TYPE (sym.st_info) != STT_FILE
     100         [ +  + ]:   82048453 :               && GELF_ST_TYPE (sym.st_info) != STT_TLS)
     101                 :            :             {
     102                 :            :               /* Even if we don't choose this symbol, its existence excludes
     103                 :            :                  any sizeless symbol (assembly label) that is below its upper
     104                 :            :                  bound.  */
     105         [ +  + ]:   81526777 :               if (sym.st_value + sym.st_size > min_label)
     106                 :    7064829 :                 min_label = sym.st_value + sym.st_size;
     107                 :            : 
     108 [ +  + ][ +  + ]:   81526777 :               if (sym.st_size == 0 || addr - sym.st_value < sym.st_size)
     109                 :            :                 {
     110                 :            :                   /* Return GELF_ST_BIND as higher-is-better integer.  */
     111                 :            :                   inline int binding_value (const GElf_Sym *symp)
     112                 :            :                     {
     113 [ +  - ][ +  - ]:    1434405 :                       switch (GELF_ST_BIND (symp->st_info))
     114                 :            :                       {
     115                 :            :                         case STB_GLOBAL:
     116                 :            :                           return 3;
     117                 :            :                         case STB_WEAK:
     118                 :            :                           return 2;
     119                 :            :                         case STB_LOCAL:
     120                 :            :                           return 1;
     121                 :            :                         default:
     122                 :            :                           return 0;
     123                 :            :                       }
     124                 :            :                     }
     125                 :            :                   /* This symbol is a better candidate than the current one
     126                 :            :                      if it's closer to ADDR or is global when it was local.  */
     127         [ +  + ]:    3659962 :                   if (closest_name == NULL
     128         [ +  + ]:    1434411 :                       || closest_sym->st_value < sym.st_value
     129         [ +  + ]:    1434405 :                       || binding_value (closest_sym) < binding_value (&sym))
     130                 :            :                     {
     131         [ +  + ]:    2225559 :                       if (sym.st_size != 0)
     132                 :            :                         {
     133                 :     510592 :                           *closest_sym = sym;
     134                 :     510592 :                           closest_shndx = shndx;
     135                 :     510592 :                           closest_name = name;
     136                 :            :                         }
     137         [ +  + ]:    1714967 :                       else if (closest_name == NULL
     138         [ +  + ]:    1714965 :                                && sym.st_value >= min_label
     139 [ +  + ][ +  + ]:     113476 :                                && same_section (&sym,
     140                 :     113476 :                                                 ((size_t) i < mod->syments
     141                 :            :                                                  ? mod->symfile
     142                 :            :                                                  : &mod->aux_sym),
     143                 :            :                                                 shndx))
     144                 :            :                         {
     145                 :            :                           /* Handwritten assembly symbols sometimes have no
     146                 :            :                              st_size.  If no symbol with proper size includes
     147                 :            :                              the address, we'll use the closest one that is in
     148                 :            :                              the same section as ADDR.  */
     149                 :      79942 :                           sizeless_sym = sym;
     150                 :      79942 :                           sizeless_shndx = shndx;
     151                 :      79942 :                           sizeless_name = name;
     152                 :            :                         }
     153                 :            :                     }
     154                 :            :                   /* When the beginning of its range is no closer,
     155                 :            :                      the end of its range might be.  Otherwise follow
     156                 :            :                      GELF_ST_BIND preference.  If all are equal prefer
     157                 :            :                      the first symbol found.  */
     158         [ +  + ]:    1434403 :                   else if (sym.st_size != 0
     159         [ +  - ]:       5094 :                            && closest_sym->st_value == sym.st_value
     160         [ +  + ]:       5094 :                            && ((closest_sym->st_size > sym.st_size
     161 [ +  - ][ -  + ]:          8 :                                 && (binding_value (closest_sym)
     162         [ +  - ]:          4 :                                     <= binding_value (&sym)))
     163         [ +  - ]:       5090 :                                || (closest_sym->st_size >= sym.st_size
     164 [ +  - ][ -  + ]:      10180 :                                    && (binding_value (closest_sym)
     165         [ +  - ]:       5090 :                                        < binding_value (&sym)))))
     166                 :            :                     {
     167                 :          4 :                       *closest_sym = sym;
     168                 :          4 :                       closest_shndx = shndx;
     169                 :          4 :                       closest_name = name;
     170                 :            :                     }
     171                 :            :                 }
     172                 :            :             }
     173                 :            :         }
     174                 :     871474 :     }
     175                 :            : 
     176                 :            :   /* First go through global symbols.  mod->first_global and
     177                 :            :      mod->aux_first_global are setup by dwfl_module_getsymtab to the
     178                 :            :      index of the first global symbol in those symbol tables.  Both
     179                 :            :      are non-zero when the table exist, except when there is only a
     180                 :            :      dynsym table loaded through phdrs, then first_global is zero and
     181                 :            :      there will be no auxiliary table.  All symbols with local binding
     182                 :            :      come first in the symbol table, then all globals.  The zeroth,
     183                 :            :      null entry, in the auxiliary table is skipped if there is a main
     184                 :            :      table.  */
     185                 :     541451 :   int first_global = mod->first_global + mod->aux_first_global;
     186 [ +  + ][ +  + ]:     541451 :   if (mod->syments > 0 && mod->aux_syments > 0)
     187                 :         12 :     first_global--;
     188         [ +  + ]:     541451 :   search_table (first_global == 0 ? 1 : first_global, syments);
     189                 :            : 
     190                 :            :   /* If we found nothing searching the global symbols, then try the locals.
     191                 :            :      Unless we have a global sizeless symbol that matches exactly.  */
     192 [ +  + ][ +  - ]:     541451 :   if (closest_name == NULL && first_global > 1
     193 [ +  + ][ +  + ]:     330156 :       && (sizeless_name == NULL || sizeless_sym.st_value != addr))
     194                 :     330023 :     search_table (1, first_global);
     195                 :            : 
     196                 :            :   /* If we found no proper sized symbol to use, fall back to the best
     197                 :            :      candidate sizeless symbol we found, if any.  */
     198         [ +  + ]:     541451 :   if (closest_name == NULL
     199 [ +  + ][ +  + ]:      30865 :       && sizeless_name != NULL && sizeless_sym.st_value >= min_label)
     200                 :            :     {
     201                 :       2278 :       *closest_sym = sizeless_sym;
     202                 :       2278 :       closest_shndx = sizeless_shndx;
     203                 :       2278 :       closest_name = sizeless_name;
     204                 :            :     }
     205                 :            : 
     206         [ +  + ]:     541451 :   if (shndxp != NULL)
     207                 :        140 :     *shndxp = closest_shndx;
     208                 :     541451 :   return closest_name;
     209                 :            : }
     210                 :    1513544 : INTDEF (dwfl_module_addrsym)

Generated by: LCOV version 1.9