LCOV - code coverage report
Current view: top level - libelf - nlist.c (source / functions) Hit Total Coverage
Test: elfutils-0.177 Lines: 70 81 86.4 %
Date: 2019-08-14 14:28:26 Functions: 1 1 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Extract symbol list from binary.
       2             :    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2005, 2007, 2015 Red Hat, Inc.
       3             :    This file is part of elfutils.
       4             :    Written by Ulrich Drepper <drepper@redhat.com>, 1998.
       5             : 
       6             :    This file is free software; you can redistribute it and/or modify
       7             :    it under the terms of either
       8             : 
       9             :      * the GNU Lesser General Public License as published by the Free
      10             :        Software Foundation; either version 3 of the License, or (at
      11             :        your option) any later version
      12             : 
      13             :    or
      14             : 
      15             :      * the GNU General Public License as published by the Free
      16             :        Software Foundation; either version 2 of the License, or (at
      17             :        your option) any later version
      18             : 
      19             :    or both in parallel, as here.
      20             : 
      21             :    elfutils is distributed in the hope that it will be useful, but
      22             :    WITHOUT ANY WARRANTY; without even the implied warranty of
      23             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      24             :    General Public License for more details.
      25             : 
      26             :    You should have received copies of the GNU General Public License and
      27             :    the GNU Lesser General Public License along with this program.  If
      28             :    not, see <http://www.gnu.org/licenses/>.  */
      29             : 
      30             : #ifdef HAVE_CONFIG_H
      31             : # include <config.h>
      32             : #endif
      33             : 
      34             : #include <fcntl.h>
      35             : #include <gelf.h>
      36             : #include <libelf.h>
      37             : #include <nlist.h>
      38             : #include <unistd.h>
      39             : 
      40             : #include "libelfP.h"
      41             : 
      42             : 
      43             : struct hashentry
      44             : {
      45             :   const char *str;
      46             :   GElf_Sym sym;
      47             : };
      48             : #define TYPE struct hashentry
      49             : /* XXX Use a better hash function some day.  */
      50             : #define HASHFCT(str, len) INTUSE(elf_hash) (str)
      51             : #define COMPARE(p1, p2) strcmp ((p1)->str, (p2)->str)
      52             : #define CLASS static
      53             : #define PREFIX nlist_
      54             : #define xcalloc(n, m) calloc (n, m)
      55             : #define next_prime(s) __libelf_next_prime (s)
      56             : #include <fixedsizehash.h>
      57             : 
      58             : 
      59             : int
      60           2 : nlist (const char *filename, struct nlist *nl)
      61             : {
      62           2 :   int fd;
      63           2 :   Elf *elf;
      64           2 :   Elf_Scn *scn = NULL;
      65           2 :   Elf_Scn *symscn = NULL;
      66           2 :   GElf_Shdr shdr_mem;
      67           2 :   GElf_Shdr *shdr = NULL;
      68           2 :   Elf_Data *data;
      69           2 :   struct nlist_fshash *table;
      70           2 :   size_t nsyms;
      71           2 :   size_t cnt;
      72             : 
      73             :   /* Open the file.  */
      74           2 :   fd = open (filename, O_RDONLY);
      75           2 :   if (fd == -1)
      76             :     {
      77           1 :       __libelf_seterrno (ELF_E_NOFILE);
      78           1 :       goto fail;
      79             :     }
      80             : 
      81             :   /* For compatibility reasons (`nlist' existed before ELF and libelf)
      82             :      we don't expect the caller to set the ELF version.  Do this here
      83             :      as if it hasn't happened yet.  */
      84           1 :   INTUSE(elf_version) (EV_CURRENT);
      85             : 
      86             :   /* Now get an ELF descriptor.  */
      87           1 :   elf = INTUSE(elf_begin) (fd, ELF_C_READ_MMAP, NULL);
      88           1 :   if (elf == NULL)
      89             :     goto fail_fd;
      90             : 
      91             :   /* Find a symbol table.  We prefer the real symbol table but if it
      92             :      does not exist use the dynamic symbol table.  */
      93          36 :   while ((scn = INTUSE(elf_nextscn) (elf, scn)) != NULL)
      94             :     {
      95          36 :       shdr = INTUSE(gelf_getshdr) (scn, &shdr_mem);
      96          36 :       if (shdr == NULL)
      97             :         goto fail_close;
      98             : 
      99             :       /* That is what we are looking for.  */
     100          36 :       if (shdr->sh_type == SHT_SYMTAB)
     101             :         {
     102             :           symscn = scn;
     103             :           break;
     104             :         }
     105             : 
     106             :       /* Better than nothing.  Remember this section.  */
     107          35 :       if (shdr->sh_type == SHT_DYNSYM)
     108           1 :         symscn = scn;
     109             :     }
     110             : 
     111           1 :   if (symscn == NULL)
     112             :     /* We haven't found anything.  Fail.  */
     113             :     goto fail_close;
     114             : 
     115             :   /* Re-get the section header in case we found only the dynamic symbol
     116             :      table.  */
     117           1 :   if (scn == NULL)
     118             :     {
     119           0 :       shdr = INTUSE(gelf_getshdr) (symscn, &shdr_mem);
     120           0 :       if (unlikely (shdr == NULL))
     121             :         goto fail_close;
     122             :     }
     123             :   /* SHDR->SH_LINK now contains the index of the string section.  */
     124             : 
     125             :   /* Get the data for the symbol section.  */
     126           1 :   data = INTUSE(elf_getdata) (symscn, NULL);
     127           1 :   if (data == NULL)
     128             :     goto fail_close;
     129             : 
     130             :   /* How many symbols are there?  */
     131           2 :   nsyms = (shdr->sh_size
     132           1 :            / INTUSE(gelf_fsize) (elf, ELF_T_SYM, 1, EV_CURRENT));
     133             : 
     134             :   /* Create the hash table.  */
     135           1 :   table = nlist_fshash_init (nsyms);
     136           1 :   if (table == NULL)
     137             :     {
     138           0 :       __libelf_seterrno (ELF_E_NOMEM);
     139           0 :       goto fail_close;
     140             :     }
     141             : 
     142             :   /* Iterate over all the symbols in the section.  */
     143         577 :   for (cnt = 0; cnt < nsyms; ++cnt)
     144             :     {
     145         576 :       struct hashentry mem;
     146         576 :       GElf_Sym *sym;
     147             : 
     148             :       /* Get the symbol.  */
     149         576 :       sym = INTUSE(gelf_getsym) (data, cnt, &mem.sym);
     150         576 :       if (sym == NULL)
     151           0 :         goto fail_dealloc;
     152             : 
     153             :       /* Get the name of the symbol.  */
     154         576 :       mem.str = INTUSE(elf_strptr) (elf, shdr->sh_link, sym->st_name);
     155         576 :       if (mem.str == NULL)
     156             :         goto fail_dealloc;
     157             : 
     158             :       /* Don't allow zero-length strings.  */
     159         576 :       if (mem.str[0] == '\0')
     160          37 :         continue;
     161             : 
     162             :       /* And add it to the hash table.  Note that we are using the
     163             :          overwrite version.  This will ensure that
     164             :          a) global symbols are preferred over local symbols since
     165             :             they are all located at the end
     166             :          b) if there are multiple local symbols with the same name
     167             :             the last one is used.
     168             :       */
     169         539 :       (void) nlist_fshash_overwrite (table, mem.str, 0, &mem);
     170             :     }
     171             : 
     172             :   /* Now it is time to look for the symbols the user asked for.
     173             :      XXX What is a `null name/null string'?  This is what the
     174             :      standard says terminates the list.  Is it a null pointer
     175             :      or a zero-length string?  We test for both...  */
     176           6 :   while (nl->n_name != NULL && nl->n_name[0] != '\0')
     177             :     {
     178           5 :       struct hashentry search;
     179           5 :       const struct hashentry *found;
     180             : 
     181             :       /* Search for a matching entry in the hash table.  */
     182           5 :       search.str = nl->n_name;
     183           5 :       found = nlist_fshash_find (table, nl->n_name, 0, &search);
     184             : 
     185           5 :       if (found != NULL)
     186             :         {
     187             :           /* Found it.  */
     188           4 :           nl->n_value = found->sym.st_value;
     189           4 :           nl->n_scnum = found->sym.st_shndx;
     190           4 :           nl->n_type = GELF_ST_TYPE (found->sym.st_info);
     191             :           /* XXX What shall we fill in the next fields?  */
     192           4 :           nl->n_sclass = 0;
     193           4 :           nl->n_numaux = 0;
     194             :         }
     195             :       else
     196             :         {
     197             :           /* Not there.  */
     198           1 :           nl->n_value = 0;
     199           1 :           nl->n_scnum = 0;
     200           1 :           nl->n_type = 0;
     201           1 :           nl->n_sclass = 0;
     202           1 :           nl->n_numaux = 0;
     203             :         }
     204             : 
     205             :       /* Next search request.  */
     206           5 :       ++nl;
     207             :     }
     208             : 
     209             :   /* Free the resources.  */
     210           1 :   nlist_fshash_fini (table);
     211             : 
     212             :   /* We do not need the ELF descriptor anymore.  */
     213           1 :   (void) INTUSE(elf_end) (elf);
     214             : 
     215             :   /* Neither the file descriptor.  */
     216           1 :   (void) close (fd);
     217             : 
     218           1 :   return 0;
     219             : 
     220           0 :  fail_dealloc:
     221           0 :   nlist_fshash_fini (table);
     222             : 
     223           0 :  fail_close:
     224             :   /* We do not need the ELF descriptor anymore.  */
     225           0 :   (void) INTUSE(elf_end) (elf);
     226             : 
     227           0 :  fail_fd:
     228             :   /* Neither the file descriptor.  */
     229           0 :   (void) close (fd);
     230             : 
     231             :  fail:
     232             :   /* We have to set all entries to zero.  */
     233           6 :   while (nl->n_name != NULL && nl->n_name[0] != '\0')
     234             :     {
     235           5 :       nl->n_value = 0;
     236           5 :       nl->n_scnum = 0;
     237           5 :       nl->n_type = 0;
     238           5 :       nl->n_sclass = 0;
     239           5 :       nl->n_numaux = 0;
     240             : 
     241             :       /* Next entry.  */
     242           5 :       ++nl;
     243             :     }
     244             : 
     245             :   return -1;
     246             : }

Generated by: LCOV version 1.13