LCOV - code coverage report
Current view: top level - libelf - nlist.c (source / functions) Hit Total Coverage
Test: elfutils-0.172 Lines: 60 69 87.0 %
Date: 2018-06-11 22:52:14 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             :   int fd;
      63             :   Elf *elf;
      64           2 :   Elf_Scn *scn = NULL;
      65           2 :   Elf_Scn *symscn = NULL;
      66             :   GElf_Shdr shdr_mem;
      67           2 :   GElf_Shdr *shdr = NULL;
      68             :   Elf_Data *data;
      69             :   struct nlist_fshash *table;
      70             :   size_t nsyms;
      71             :   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             :      if it hasn't happened yet.  */
      84           1 :   if (__libelf_version_initialized == 0)
      85           1 :     INTUSE(elf_version) (EV_CURRENT);
      86             : 
      87             :   /* Now get an ELF descriptor.  */
      88           1 :   elf = INTUSE(elf_begin) (fd, ELF_C_READ_MMAP, NULL);
      89           1 :   if (elf == NULL)
      90             :     goto fail_fd;
      91             : 
      92             :   /* Find a symbol table.  We prefer the real symbol table but if it
      93             :      does not exist use the dynamic symbol table.  */
      94          36 :   while ((scn = INTUSE(elf_nextscn) (elf, scn)) != NULL)
      95             :     {
      96          36 :       shdr = INTUSE(gelf_getshdr) (scn, &shdr_mem);
      97          36 :       if (shdr == NULL)
      98             :         goto fail_close;
      99             : 
     100             :       /* That is what we are looking for.  */
     101          36 :       if (shdr->sh_type == SHT_SYMTAB)
     102             :         {
     103             :           symscn = scn;
     104             :           break;
     105             :         }
     106             : 
     107             :       /* Better than nothing.  Remember this section.  */
     108          35 :       if (shdr->sh_type == SHT_DYNSYM)
     109           1 :         symscn = scn;
     110             :     }
     111             : 
     112           1 :   if (symscn == NULL)
     113             :     /* We haven't found anything.  Fail.  */
     114             :     goto fail_close;
     115             : 
     116             :   /* Re-get the section header in case we found only the dynamic symbol
     117             :      table.  */
     118           1 :   if (scn == NULL)
     119             :     {
     120           0 :       shdr = INTUSE(gelf_getshdr) (symscn, &shdr_mem);
     121           0 :       if (unlikely (shdr == NULL))
     122             :         goto fail_close;
     123             :     }
     124             :   /* SHDR->SH_LINK now contains the index of the string section.  */
     125             : 
     126             :   /* Get the data for the symbol section.  */
     127           1 :   data = INTUSE(elf_getdata) (symscn, NULL);
     128           1 :   if (data == NULL)
     129             :     goto fail_close;
     130             : 
     131             :   /* How many symbols are there?  */
     132           2 :   nsyms = (shdr->sh_size
     133           1 :            / INTUSE(gelf_fsize) (elf, ELF_T_SYM, 1, EV_CURRENT));
     134             : 
     135             :   /* Create the hash table.  */
     136           1 :   table = nlist_fshash_init (nsyms);
     137           1 :   if (table == NULL)
     138             :     {
     139           0 :       __libelf_seterrno (ELF_E_NOMEM);
     140           0 :       goto fail_close;
     141             :     }
     142             : 
     143             :   /* Iterate over all the symbols in the section.  */
     144         571 :   for (cnt = 0; cnt < nsyms; ++cnt)
     145             :     {
     146             :       struct hashentry mem;
     147             :       GElf_Sym *sym;
     148             : 
     149             :       /* Get the symbol.  */
     150         571 :       sym = INTUSE(gelf_getsym) (data, cnt, &mem.sym);
     151         571 :       if (sym == NULL)
     152             :         goto fail_dealloc;
     153             : 
     154             :       /* Get the name of the symbol.  */
     155         571 :       mem.str = INTUSE(elf_strptr) (elf, shdr->sh_link, sym->st_name);
     156         571 :       if (mem.str == NULL)
     157             :         goto fail_dealloc;
     158             : 
     159             :       /* Don't allow zero-length strings.  */
     160         571 :       if (mem.str[0] == '\0')
     161          37 :         continue;
     162             : 
     163             :       /* And add it to the hash table.  Note that we are using the
     164             :          overwrite version.  This will ensure that
     165             :          a) global symbols are preferred over local symbols since
     166             :             they are all located at the end
     167             :          b) if there are multiple local symbols with the same name
     168             :             the last one is used.
     169             :       */
     170         534 :       (void) nlist_fshash_overwrite (table, mem.str, 0, &mem);
     171             :     }
     172             : 
     173             :   /* Now it is time to look for the symbols the user asked for.
     174             :      XXX What is a `null name/null string'?  This is what the
     175             :      standard says terminates the list.  Is it a null pointer
     176             :      or a zero-length string?  We test for both...  */
     177           6 :   while (nl->n_name != NULL && nl->n_name[0] != '\0')
     178             :     {
     179             :       struct hashentry search;
     180             :       const struct hashentry *found;
     181             : 
     182             :       /* Search for a matching entry in the hash table.  */
     183           5 :       search.str = nl->n_name;
     184           5 :       found = nlist_fshash_find (table, nl->n_name, 0, &search);
     185             : 
     186           5 :       if (found != NULL)
     187             :         {
     188             :           /* Found it.  */
     189           4 :           nl->n_value = found->sym.st_value;
     190           4 :           nl->n_scnum = found->sym.st_shndx;
     191           4 :           nl->n_type = GELF_ST_TYPE (found->sym.st_info);
     192             :           /* XXX What shall we fill in the next fields?  */
     193           4 :           nl->n_sclass = 0;
     194           4 :           nl->n_numaux = 0;
     195             :         }
     196             :       else
     197             :         {
     198             :           /* Not there.  */
     199           1 :           nl->n_value = 0;
     200           1 :           nl->n_scnum = 0;
     201           1 :           nl->n_type = 0;
     202           1 :           nl->n_sclass = 0;
     203           1 :           nl->n_numaux = 0;
     204             :         }
     205             : 
     206             :       /* Next search request.  */
     207           5 :       ++nl;
     208             :     }
     209             : 
     210             :   /* Free the resources.  */
     211           1 :   nlist_fshash_fini (table);
     212             : 
     213             :   /* We do not need the ELF descriptor anymore.  */
     214           1 :   (void) INTUSE(elf_end) (elf);
     215             : 
     216             :   /* Neither the file descriptor.  */
     217           1 :   (void) close (fd);
     218             : 
     219           1 :   return 0;
     220             : 
     221           0 :  fail_dealloc:
     222             :   nlist_fshash_fini (table);
     223             : 
     224           0 :  fail_close:
     225             :   /* We do not need the ELF descriptor anymore.  */
     226           0 :   (void) INTUSE(elf_end) (elf);
     227             : 
     228           0 :  fail_fd:
     229             :   /* Neither the file descriptor.  */
     230           0 :   (void) close (fd);
     231             : 
     232             :  fail:
     233             :   /* We have to set all entries to zero.  */
     234           6 :   while (nl->n_name != NULL && nl->n_name[0] != '\0')
     235             :     {
     236           5 :       nl->n_value = 0;
     237           5 :       nl->n_scnum = 0;
     238           5 :       nl->n_type = 0;
     239           5 :       nl->n_sclass = 0;
     240           5 :       nl->n_numaux = 0;
     241             : 
     242             :       /* Next entry.  */
     243           5 :       ++nl;
     244             :     }
     245             : 
     246             :   return -1;
     247             : }

Generated by: LCOV version 1.13