Home | History | Annotate | Download | only in libdw
      1 /* Return list address ranges.
      2    Copyright (C) 2000-2010 Red Hat, Inc.
      3    This file is part of elfutils.
      4    Written by Ulrich Drepper <drepper (at) redhat.com>, 2000.
      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 <stdlib.h>
     35 #include <assert.h>
     36 #include "libdwP.h"
     37 #include <dwarf.h>
     38 
     39 struct arangelist
     40 {
     41   Dwarf_Arange arange;
     42   struct arangelist *next;
     43 };
     44 
     45 /* Compare by Dwarf_Arange.addr, given pointers into an array of pointeers.  */
     46 static int
     47 compare_aranges (const void *a, const void *b)
     48 {
     49   struct arangelist *const *p1 = a, *const *p2 = b;
     50   struct arangelist *l1 = *p1, *l2 = *p2;
     51   if (l1->arange.addr != l2->arange.addr)
     52     return (l1->arange.addr < l2->arange.addr) ? -1 : 1;
     53   return 0;
     54 }
     55 
     56 int
     57 dwarf_getaranges (Dwarf *dbg, Dwarf_Aranges **aranges, size_t *naranges)
     58 {
     59   if (dbg == NULL)
     60     return -1;
     61 
     62   if (dbg->aranges != NULL)
     63     {
     64       *aranges = dbg->aranges;
     65       if (naranges != NULL)
     66 	*naranges = dbg->aranges->naranges;
     67       return 0;
     68     }
     69 
     70   if (dbg->sectiondata[IDX_debug_aranges] == NULL)
     71     {
     72       /* No such section.  */
     73       *aranges = NULL;
     74       if (naranges != NULL)
     75 	*naranges = 0;
     76       return 0;
     77     }
     78 
     79   if (dbg->sectiondata[IDX_debug_aranges]->d_buf == NULL)
     80     return -1;
     81 
     82   struct arangelist *arangelist = NULL;
     83   unsigned int narangelist = 0;
     84 
     85   const unsigned char *readp = dbg->sectiondata[IDX_debug_aranges]->d_buf;
     86   const unsigned char *readendp
     87     = readp + dbg->sectiondata[IDX_debug_aranges]->d_size;
     88 
     89   while (readp < readendp)
     90     {
     91       const unsigned char *hdrstart = readp;
     92 
     93       /* Each entry starts with a header:
     94 
     95 	 1. A 4-byte or 12-byte length containing the length of the
     96 	 set of entries for this compilation unit, not including the
     97 	 length field itself. [...]
     98 
     99 	 2. A 2-byte version identifier containing the value 2 for
    100 	 DWARF Version 2.1.
    101 
    102 	 3. A 4-byte or 8-byte offset into the .debug_info section. [...]
    103 
    104 	 4. A 1-byte unsigned integer containing the size in bytes of
    105 	 an address (or the offset portion of an address for segmented
    106 	 addressing) on the target system.
    107 
    108 	 5. A 1-byte unsigned integer containing the size in bytes of
    109 	 a segment descriptor on the target system.  */
    110       if (unlikely (readp + 4 > readendp))
    111 	goto invalid;
    112 
    113       Dwarf_Word length = read_4ubyte_unaligned_inc (dbg, readp);
    114       unsigned int length_bytes = 4;
    115       if (length == DWARF3_LENGTH_64_BIT)
    116 	{
    117 	  if (unlikely (readp + 8 > readendp))
    118 	    goto invalid;
    119 
    120 	  length = read_8ubyte_unaligned_inc (dbg, readp);
    121 	  length_bytes = 8;
    122 	}
    123       else if (unlikely (length >= DWARF3_LENGTH_MIN_ESCAPE_CODE
    124 			 && length <= DWARF3_LENGTH_MAX_ESCAPE_CODE))
    125 	goto invalid;
    126 
    127       if (unlikely (readp + 2 > readendp))
    128 	goto invalid;
    129 
    130       unsigned int version = read_2ubyte_unaligned_inc (dbg, readp);
    131       if (version != 2)
    132 	{
    133 	invalid:
    134 	  __libdw_seterrno (DWARF_E_INVALID_DWARF);
    135 	fail:
    136 	  while (arangelist != NULL)
    137 	    {
    138 	      struct arangelist *next = arangelist->next;
    139 	      free (arangelist);
    140 	      arangelist = next;
    141 	    }
    142 	  return -1;
    143 	}
    144 
    145       Dwarf_Word offset = 0;
    146       if (__libdw_read_offset_inc (dbg,
    147 				   IDX_debug_aranges, &readp,
    148 				   length_bytes, &offset, IDX_debug_info, 4))
    149 	goto fail;
    150 
    151       unsigned int address_size = *readp++;
    152       if (unlikely (address_size != 4 && address_size != 8))
    153 	goto invalid;
    154 
    155       /* We don't actually support segment selectors.  */
    156       unsigned int segment_size = *readp++;
    157       if (segment_size != 0)
    158 	goto invalid;
    159 
    160       /* Round the address to the next multiple of 2*address_size.  */
    161       readp += ((2 * address_size - ((readp - hdrstart) % (2 * address_size)))
    162 		% (2 * address_size));
    163 
    164       while (1)
    165 	{
    166 	  Dwarf_Word range_address;
    167 	  Dwarf_Word range_length;
    168 
    169 	  if (__libdw_read_address_inc (dbg, IDX_debug_aranges, &readp,
    170 					address_size, &range_address))
    171 	    goto fail;
    172 
    173 	  if (readp + address_size > readendp)
    174 	    goto invalid;
    175 
    176 	  if (address_size == 4)
    177 	    range_length = read_4ubyte_unaligned_inc (dbg, readp);
    178 	  else
    179 	    range_length = read_8ubyte_unaligned_inc (dbg, readp);
    180 
    181 	  /* Two zero values mark the end.  */
    182 	  if (range_address == 0 && range_length == 0)
    183 	    break;
    184 
    185 	  /* We don't use alloca for these temporary structures because
    186 	     the total number of them can be quite large.  */
    187 	  struct arangelist *new_arange = malloc (sizeof *new_arange);
    188 	  if (unlikely (new_arange == NULL))
    189 	    {
    190 	      __libdw_seterrno (DWARF_E_NOMEM);
    191 	      goto fail;
    192 	    }
    193 
    194 	  new_arange->arange.addr = range_address;
    195 	  new_arange->arange.length = range_length;
    196 
    197 	  /* We store the actual CU DIE offset, not the CU header offset.  */
    198 	  const char *cu_header = (dbg->sectiondata[IDX_debug_info]->d_buf
    199 				   + offset);
    200 	  unsigned int offset_size;
    201 	  if (read_4ubyte_unaligned_noncvt (cu_header) == DWARF3_LENGTH_64_BIT)
    202 	    offset_size = 8;
    203 	  else
    204 	    offset_size = 4;
    205 	  new_arange->arange.offset = DIE_OFFSET_FROM_CU_OFFSET (offset,
    206 								 offset_size,
    207 								 false);
    208 
    209 	  new_arange->next = arangelist;
    210 	  arangelist = new_arange;
    211 	  ++narangelist;
    212 
    213 	  /* Sanity-check the data.  */
    214 	  if (unlikely (new_arange->arange.offset
    215 			>= dbg->sectiondata[IDX_debug_info]->d_size))
    216 	    goto invalid;
    217 	}
    218     }
    219 
    220   if (narangelist == 0)
    221     {
    222       assert (arangelist == NULL);
    223       if (naranges != NULL)
    224 	*naranges = 0;
    225       *aranges = NULL;
    226       return 0;
    227     }
    228 
    229   /* Allocate the array for the result.  */
    230   void *buf = libdw_alloc (dbg, Dwarf_Aranges,
    231 			   sizeof (Dwarf_Aranges)
    232 			   + narangelist * sizeof (Dwarf_Arange), 1);
    233 
    234   /* First use the buffer for the pointers, and sort the entries.
    235      We'll write the pointers in the end of the buffer, and then
    236      copy into the buffer from the beginning so the overlap works.  */
    237   assert (sizeof (Dwarf_Arange) >= sizeof (Dwarf_Arange *));
    238   struct arangelist **sortaranges
    239     = (buf + sizeof (Dwarf_Aranges)
    240        + ((sizeof (Dwarf_Arange) - sizeof sortaranges[0]) * narangelist));
    241 
    242   /* The list is in LIFO order and usually they come in clumps with
    243      ascending addresses.  So fill from the back to probably start with
    244      runs already in order before we sort.  */
    245   unsigned int i = narangelist;
    246   while (i-- > 0)
    247     {
    248       sortaranges[i] = arangelist;
    249       arangelist = arangelist->next;
    250     }
    251   assert (arangelist == NULL);
    252 
    253   /* Sort by ascending address.  */
    254   qsort (sortaranges, narangelist, sizeof sortaranges[0], &compare_aranges);
    255 
    256   /* Now that they are sorted, put them in the final array.
    257      The buffers overlap, so we've clobbered the early elements
    258      of SORTARANGES by the time we're reading the later ones.  */
    259   *aranges = buf;
    260   (*aranges)->dbg = dbg;
    261   (*aranges)->naranges = narangelist;
    262   dbg->aranges = *aranges;
    263   if (naranges != NULL)
    264     *naranges = narangelist;
    265   for (i = 0; i < narangelist; ++i)
    266     {
    267       struct arangelist *elt = sortaranges[i];
    268       (*aranges)->info[i] = elt->arange;
    269       free (elt);
    270     }
    271 
    272   return 0;
    273 }
    274 INTDEF(dwarf_getaranges)
    275