LCOV - code coverage report
Current view: top level - libdw - dwarf_getaranges.c (source / functions) Hit Total Coverage
Test: elfutils-0.171 Lines: 77 95 81.1 %
Date: 2018-06-04 08:50:22 Functions: 2 2 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Return list address ranges.
       2             :    Copyright (C) 2000-2010, 2016, 2017 Red Hat, Inc.
       3             :    This file is part of elfutils.
       4             :    Written by Ulrich Drepper <drepper@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          46 : compare_aranges (const void *a, const void *b)
      48             : {
      49          46 :   struct arangelist *const *p1 = a, *const *p2 = b;
      50          46 :   struct arangelist *l1 = *p1, *l2 = *p2;
      51          46 :   if (l1->arange.addr != l2->arange.addr)
      52          46 :     return (l1->arange.addr < l2->arange.addr) ? -1 : 1;
      53             :   return 0;
      54             : }
      55             : 
      56             : int
      57          77 : dwarf_getaranges (Dwarf *dbg, Dwarf_Aranges **aranges, size_t *naranges)
      58             : {
      59          77 :   if (dbg == NULL)
      60             :     return -1;
      61             : 
      62          77 :   if (dbg->aranges != NULL)
      63             :     {
      64          13 :       *aranges = dbg->aranges;
      65          13 :       if (naranges != NULL)
      66          13 :         *naranges = dbg->aranges->naranges;
      67             :       return 0;
      68             :     }
      69             : 
      70          64 :   if (dbg->sectiondata[IDX_debug_aranges] == NULL)
      71             :     {
      72             :       /* No such section.  */
      73           4 :       *aranges = NULL;
      74           4 :       if (naranges != NULL)
      75           4 :         *naranges = 0;
      76             :       return 0;
      77             :     }
      78             : 
      79          60 :   if (dbg->sectiondata[IDX_debug_aranges]->d_buf == NULL)
      80             :     return -1;
      81             : 
      82          60 :   struct arangelist *arangelist = NULL;
      83          60 :   unsigned int narangelist = 0;
      84             : 
      85          60 :   const unsigned char *readp = dbg->sectiondata[IDX_debug_aranges]->d_buf;
      86          60 :   const unsigned char *readendp
      87          60 :     = readp + dbg->sectiondata[IDX_debug_aranges]->d_size;
      88             : 
      89         204 :   while (readp < readendp)
      90             :     {
      91          84 :       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          84 :       if (unlikely (readp + 4 > readendp))
     111             :         goto invalid;
     112             : 
     113          87 :       Dwarf_Word length = read_4ubyte_unaligned_inc (dbg, readp);
     114          84 :       unsigned int length_bytes = 4;
     115          84 :       if (length == DWARF3_LENGTH_64_BIT)
     116             :         {
     117           0 :           if (unlikely (readp + 8 > readendp))
     118             :             goto invalid;
     119             : 
     120           0 :           length = read_8ubyte_unaligned_inc (dbg, readp);
     121           0 :           length_bytes = 8;
     122             :         }
     123          84 :       else if (unlikely (length >= DWARF3_LENGTH_MIN_ESCAPE_CODE
     124             :                          && length <= DWARF3_LENGTH_MAX_ESCAPE_CODE))
     125             :         goto invalid;
     126             : 
     127          84 :       if (unlikely (readp + 2 > readendp))
     128             :         goto invalid;
     129             : 
     130          84 :       unsigned int version = read_2ubyte_unaligned_inc (dbg, readp);
     131          84 :       if (version != 2)
     132             :         {
     133           0 :         invalid:
     134           0 :           __libdw_seterrno (DWARF_E_INVALID_DWARF);
     135           0 :         fail:
     136           0 :           while (arangelist != NULL)
     137             :             {
     138           0 :               struct arangelist *next = arangelist->next;
     139           0 :               free (arangelist);
     140           0 :               arangelist = next;
     141             :             }
     142           0 :           return -1;
     143             :         }
     144             : 
     145          84 :       Dwarf_Word offset = 0;
     146          84 :       if (__libdw_read_offset_inc (dbg,
     147             :                                    IDX_debug_aranges, &readp,
     148             :                                    length_bytes, &offset, IDX_debug_info, 4))
     149             :         goto fail;
     150             : 
     151          84 :       unsigned int address_size = *readp++;
     152          84 :       if (unlikely (address_size != 4 && address_size != 8))
     153             :         goto invalid;
     154             : 
     155             :       /* We don't actually support segment selectors.  */
     156          84 :       unsigned int segment_size = *readp++;
     157          84 :       if (segment_size != 0)
     158             :         goto invalid;
     159             : 
     160             :       /* Round the address to the next multiple of 2*address_size.  */
     161         168 :       readp += ((2 * address_size - ((readp - hdrstart) % (2 * address_size)))
     162          84 :                 % (2 * address_size));
     163             : 
     164             :       while (1)
     165          97 :         {
     166             :           Dwarf_Word range_address;
     167             :           Dwarf_Word range_length;
     168             : 
     169         181 :           if (__libdw_read_address_inc (dbg, IDX_debug_aranges, &readp,
     170             :                                         address_size, &range_address))
     171             :             goto fail;
     172             : 
     173         181 :           if (readp + address_size > readendp)
     174             :             goto invalid;
     175             : 
     176         181 :           if (address_size == 4)
     177          94 :             range_length = read_4ubyte_unaligned_inc (dbg, readp);
     178             :           else
     179          93 :             range_length = read_8ubyte_unaligned_inc (dbg, readp);
     180             : 
     181             :           /* Two zero values mark the end.  */
     182         181 :           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          97 :           struct arangelist *new_arange = malloc (sizeof *new_arange);
     188          97 :           if (unlikely (new_arange == NULL))
     189             :             {
     190           0 :               __libdw_seterrno (DWARF_E_NOMEM);
     191           0 :               goto fail;
     192             :             }
     193             : 
     194          97 :           new_arange->arange.addr = range_address;
     195          97 :           new_arange->arange.length = range_length;
     196             : 
     197             :           /* We store the actual CU DIE offset, not the CU header offset.  */
     198          97 :           Dwarf_CU *cu = __libdw_findcu (dbg, offset, false);
     199          97 :           if (unlikely (cu == NULL))
     200             :             goto fail;
     201         194 :           new_arange->arange.offset = __libdw_first_die_off_from_cu (cu);
     202             : 
     203          97 :           new_arange->next = arangelist;
     204          97 :           arangelist = new_arange;
     205          97 :           ++narangelist;
     206             : 
     207             :           /* Sanity-check the data.  */
     208          97 :           if (unlikely (new_arange->arange.offset
     209             :                         >= dbg->sectiondata[IDX_debug_info]->d_size))
     210             :             goto invalid;
     211             :         }
     212             :     }
     213             : 
     214          60 :   if (narangelist == 0)
     215             :     {
     216           0 :       assert (arangelist == NULL);
     217           0 :       if (naranges != NULL)
     218           0 :         *naranges = 0;
     219           0 :       *aranges = NULL;
     220           0 :       return 0;
     221             :     }
     222             : 
     223             :   /* Allocate the array for the result.  */
     224          60 :   void *buf = libdw_alloc (dbg, Dwarf_Aranges,
     225             :                            sizeof (Dwarf_Aranges)
     226             :                            + narangelist * sizeof (Dwarf_Arange), 1);
     227             : 
     228             :   /* First use the buffer for the pointers, and sort the entries.
     229             :      We'll write the pointers in the end of the buffer, and then
     230             :      copy into the buffer from the beginning so the overlap works.  */
     231             :   assert (sizeof (Dwarf_Arange) >= sizeof (Dwarf_Arange *));
     232          60 :   struct arangelist **sortaranges
     233             :     = (buf + sizeof (Dwarf_Aranges)
     234          60 :        + ((sizeof (Dwarf_Arange) - sizeof sortaranges[0]) * narangelist));
     235             : 
     236             :   /* The list is in LIFO order and usually they come in clumps with
     237             :      ascending addresses.  So fill from the back to probably start with
     238             :      runs already in order before we sort.  */
     239          60 :   unsigned int i = narangelist;
     240         217 :   while (i-- > 0)
     241             :     {
     242          97 :       sortaranges[i] = arangelist;
     243          97 :       arangelist = arangelist->next;
     244             :     }
     245          60 :   assert (arangelist == NULL);
     246             : 
     247             :   /* Sort by ascending address.  */
     248          60 :   qsort (sortaranges, narangelist, sizeof sortaranges[0], &compare_aranges);
     249             : 
     250             :   /* Now that they are sorted, put them in the final array.
     251             :      The buffers overlap, so we've clobbered the early elements
     252             :      of SORTARANGES by the time we're reading the later ones.  */
     253          60 :   *aranges = buf;
     254          60 :   (*aranges)->dbg = dbg;
     255          60 :   (*aranges)->naranges = narangelist;
     256          60 :   dbg->aranges = *aranges;
     257          60 :   if (naranges != NULL)
     258          60 :     *naranges = narangelist;
     259          97 :   for (i = 0; i < narangelist; ++i)
     260             :     {
     261          97 :       struct arangelist *elt = sortaranges[i];
     262          97 :       (*aranges)->info[i] = elt->arange;
     263          97 :       free (elt);
     264             :     }
     265             : 
     266             :   return 0;
     267             : }
     268             : INTDEF(dwarf_getaranges)

Generated by: LCOV version 1.13