Home | History | Annotate | Download | only in libdw
      1 /* Get public symbol information.
      2    Copyright (C) 2002, 2003, 2004 Red Hat, Inc.
      3    Written by Ulrich Drepper <drepper (at) redhat.com>, 2002.
      4 
      5    This program is Open Source software; you can redistribute it and/or
      6    modify it under the terms of the Open Software License version 1.0 as
      7    published by the Open Source Initiative.
      8 
      9    You should have received a copy of the Open Software License along
     10    with this program; if not, you may obtain a copy of the Open Software
     11    License version 1.0 from http://www.opensource.org/licenses/osl.php or
     12    by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
     13    3001 King Ranch Road, Ukiah, CA 95482.   */
     14 
     15 #ifdef HAVE_CONFIG_H
     16 # include <config.h>
     17 #endif
     18 
     19 #include <assert.h>
     20 #include <stdlib.h>
     21 #include <string.h>
     22 #include <sys/param.h>
     23 
     24 #include <libdwP.h>
     25 
     26 
     27 static int
     28 get_offsets (Dwarf *dbg)
     29 {
     30   size_t allocated = 0;
     31   size_t cnt = 0;
     32   struct pubnames_s *mem = NULL;
     33   const size_t entsize = sizeof (struct pubnames_s);
     34   unsigned char *const startp = dbg->sectiondata[IDX_debug_pubnames]->d_buf;
     35   unsigned char *readp = startp;
     36   unsigned char *endp = readp + dbg->sectiondata[IDX_debug_pubnames]->d_size;
     37 
     38   while (readp + 14 < endp)
     39     {
     40       /* If necessary, allocate more entries.  */
     41       if (cnt >= allocated)
     42 	{
     43 	  allocated = MAX (10, 2 * allocated);
     44 	  struct pubnames_s *newmem
     45 	    = (struct pubnames_s *) realloc (mem, allocated * entsize);
     46 	  if (newmem == NULL)
     47 	    {
     48 	      __libdw_seterrno (DWARF_E_NOMEM);
     49 	    err_return:
     50 	      free (mem);
     51 	      return -1;
     52 	    }
     53 
     54 	  mem = newmem;
     55 	}
     56 
     57       /* Read the set header.  */
     58       int len_bytes = 4;
     59       Dwarf_Off len = read_4ubyte_unaligned_inc (dbg, readp);
     60       if (len == 0xffffffff)
     61 	{
     62 	  len = read_8ubyte_unaligned_inc (dbg, readp);
     63 	  len_bytes = 8;
     64 	}
     65 
     66       /* Now we know the offset of the first offset/name pair.  */
     67       mem[cnt].set_start = readp + 2 + 2 * len_bytes - startp;
     68       mem[cnt].address_len = len_bytes;
     69       if (mem[cnt].set_start >= dbg->sectiondata[IDX_debug_pubnames]->d_size)
     70 	/* Something wrong, the first entry is beyond the end of
     71 	   the section.  */
     72 	break;
     73 
     74       /* Read the version.  It better be two for now.  */
     75       uint16_t version = read_2ubyte_unaligned (dbg, readp);
     76       if (version != 2)
     77 	{
     78 	  __libdw_seterrno (DWARF_E_INVALID_VERSION);
     79 	  goto err_return;
     80 	}
     81 
     82       /* Get the CU offset.  */
     83       if (len_bytes == 4)
     84 	mem[cnt].cu_offset = read_4ubyte_unaligned (dbg, readp + 2);
     85       else
     86 	mem[cnt].cu_offset = read_8ubyte_unaligned (dbg, readp + 2);
     87 
     88       /* Determine the size of the CU header.  */
     89       assert (dbg->sectiondata[IDX_debug_info] != NULL);
     90       assert (dbg->sectiondata[IDX_debug_info]->d_buf != NULL);
     91       assert (mem[cnt].cu_offset + 3
     92 	      < dbg->sectiondata[IDX_debug_info]->d_size);
     93       unsigned char *infop
     94 	= ((unsigned char *) dbg->sectiondata[IDX_debug_info]->d_buf
     95 	   + mem[cnt].cu_offset);
     96       if (read_4ubyte_unaligned_noncvt (infop) == 0xffffffff)
     97 	mem[cnt].cu_header_size = 23;
     98       else
     99 	mem[cnt].cu_header_size = 11;
    100 
    101       ++cnt;
    102 
    103       /* Advance to the next set.  */
    104       readp += len;
    105     }
    106 
    107   if (mem == NULL)
    108     {
    109       __libdw_seterrno (DWARF_E_NO_ENTRY);
    110       return -1;
    111     }
    112 
    113   dbg->pubnames_sets = (struct pubnames_s *) realloc (mem, cnt * entsize);
    114   dbg->pubnames_nsets = cnt;
    115 
    116   return 0;
    117 }
    118 
    119 
    120 ptrdiff_t
    121 dwarf_getpubnames (dbg, callback, arg, offset)
    122      Dwarf *dbg;
    123      int (*callback) (Dwarf *, Dwarf_Global *, void *);
    124      void *arg;
    125      ptrdiff_t offset;
    126 {
    127   if (dbg == NULL)
    128     return -1l;
    129 
    130   /* Make sure it is a valid offset.  */
    131   if (unlikely (dbg->sectiondata[IDX_debug_pubnames] == NULL
    132 		|| offset >= dbg->sectiondata[IDX_debug_pubnames]->d_size))
    133     /* No (more) entry.  */
    134     return 0;
    135 
    136   /* If necessary read the set information.  */
    137   if (dbg->pubnames_nsets == 0 && get_offsets (dbg) != 0)
    138     return -1l;
    139 
    140   /* Find the place where to start.  */
    141   size_t cnt;
    142   if (offset == 0)
    143     {
    144       cnt = 0;
    145       offset = dbg->pubnames_sets[0].set_start;
    146     }
    147   else
    148     {
    149       for (cnt = 0; cnt + 1 < dbg->pubnames_nsets; ++cnt)
    150 	if (offset >= dbg->pubnames_sets[cnt].set_start)
    151 	  {
    152 	    assert (offset < dbg->pubnames_sets[cnt + 1].set_start);
    153 	    break;
    154 	  }
    155       assert (cnt + 1 < dbg->pubnames_nsets);
    156     }
    157 
    158   unsigned char *startp
    159     = (unsigned char *) dbg->sectiondata[IDX_debug_pubnames]->d_buf;
    160   unsigned char *readp = startp + offset;
    161   while (1)
    162     {
    163       Dwarf_Global gl;
    164 
    165       gl.cu_offset = (dbg->pubnames_sets[cnt].cu_offset
    166 		      + dbg->pubnames_sets[cnt].cu_header_size);
    167 
    168       while (1)
    169 	{
    170 	  /* READP points to the next offset/name pair.  */
    171 	  if (dbg->pubnames_sets[cnt].address_len == 4)
    172 	    gl.die_offset = read_4ubyte_unaligned_inc (dbg, readp);
    173 	  else
    174 	    gl.die_offset = read_8ubyte_unaligned_inc (dbg, readp);
    175 
    176 	  /* If the offset is zero we reached the end of the set.  */
    177 	  if (gl.die_offset == 0)
    178 	    break;
    179 
    180 	  /* Add the CU offset.  */
    181 	  gl.die_offset += dbg->pubnames_sets[cnt].cu_offset;
    182 
    183 	  gl.name = (char *) readp;
    184 	  readp = (unsigned char *) rawmemchr (gl.name, '\0') + 1;
    185 
    186 	  /* We found name and DIE offset.  Report it.  */
    187 	  if (callback (dbg, &gl, arg) != DWARF_CB_OK)
    188 	    {
    189 	      /* The user wants us to stop.  Return the offset of the
    190 		 next entry.  */
    191 	      return readp - startp;
    192 	    }
    193 	}
    194 
    195       if (++cnt == dbg->pubnames_nsets)
    196 	/* This was the last set.  */
    197 	break;
    198 
    199       startp = (unsigned char *) dbg->sectiondata[IDX_debug_pubnames]->d_buf;
    200       readp = startp + dbg->pubnames_sets[cnt].set_start;
    201     }
    202 
    203   /* We are done.  No more entries.  */
    204   return 0;
    205 }
    206