LCOV - code coverage report
Current view: top level - libdw - dwarf_getaranges.c (source / functions) Hit Total Coverage
Test: elfutils-0.178 Lines: 84 114 73.7 %
Date: 2019-11-26 23:55:16 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          63 :     return (l1->arange.addr < l2->arange.addr) ? -1 : 1;
      53             :   return 0;
      54             : }
      55             : 
      56             : int
      57          81 : dwarf_getaranges (Dwarf *dbg, Dwarf_Aranges **aranges, size_t *naranges)
      58             : {
      59          81 :   if (dbg == NULL)
      60             :     return -1;
      61             : 
      62          81 :   if (dbg->aranges != NULL)
      63             :     {
      64          13 :       *aranges = dbg->aranges;
      65          13 :       if (naranges != NULL)
      66          13 :         *naranges = dbg->aranges->naranges;
      67          13 :       return 0;
      68             :     }
      69             : 
      70          68 :   if (dbg->sectiondata[IDX_debug_aranges] == NULL)
      71             :     {
      72             :       /* No such section.  */
      73           8 :       *aranges = NULL;
      74           8 :       if (naranges != NULL)
      75           8 :         *naranges = 0;
      76           8 :       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         120 :   const unsigned char *readendp
      87          60 :     = readp + dbg->sectiondata[IDX_debug_aranges]->d_size;
      88             : 
      89         144 :   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           0 :         goto invalid;
     112             : 
     113          84 :       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           0 :             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           0 :         goto invalid;
     126             : 
     127          84 :       if (unlikely (readp + 2 > readendp))
     128           0 :         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             :         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           0 :         goto fail;
     150             : 
     151             :       /* Next up two bytes for address and segment size.  */
     152          84 :       if (readp + 2 > readendp)
     153           0 :         goto invalid;
     154             : 
     155          84 :       unsigned int address_size = *readp++;
     156          84 :       if (unlikely (address_size != 4 && address_size != 8))
     157           0 :         goto invalid;
     158             : 
     159             :       /* We don't actually support segment selectors.  */
     160          84 :       unsigned int segment_size = *readp++;
     161          84 :       if (segment_size != 0)
     162           0 :         goto invalid;
     163             : 
     164             :       /* Round the address to the next multiple of 2*address_size.  */
     165         168 :       readp += ((2 * address_size - ((readp - hdrstart) % (2 * address_size)))
     166          84 :                 % (2 * address_size));
     167             : 
     168         181 :       while (1)
     169          97 :         {
     170         181 :           Dwarf_Word range_address;
     171         181 :           Dwarf_Word range_length;
     172             : 
     173         181 :           if (__libdw_read_address_inc (dbg, IDX_debug_aranges, &readp,
     174             :                                         address_size, &range_address))
     175           0 :             goto fail;
     176             : 
     177         181 :           if (readp + address_size > readendp)
     178           0 :             goto invalid;
     179             : 
     180         181 :           if (address_size == 4)
     181          88 :             range_length = read_4ubyte_unaligned_inc (dbg, readp);
     182             :           else
     183          93 :             range_length = read_8ubyte_unaligned_inc (dbg, readp);
     184             : 
     185             :           /* Two zero values mark the end.  */
     186         181 :           if (range_address == 0 && range_length == 0)
     187             :             break;
     188             : 
     189             :           /* We don't use alloca for these temporary structures because
     190             :              the total number of them can be quite large.  */
     191          97 :           struct arangelist *new_arange = malloc (sizeof *new_arange);
     192          97 :           if (unlikely (new_arange == NULL))
     193             :             {
     194           0 :               __libdw_seterrno (DWARF_E_NOMEM);
     195           0 :               goto fail;
     196             :             }
     197             : 
     198          97 :           new_arange->arange.addr = range_address;
     199          97 :           new_arange->arange.length = range_length;
     200             : 
     201             :           /* We store the actual CU DIE offset, not the CU header offset.  */
     202          97 :           Dwarf_CU *cu = __libdw_findcu (dbg, offset, false);
     203          97 :           if (unlikely (cu == NULL))
     204             :             {
     205             :               /* We haven't gotten a chance to link in the new_arange
     206             :                  into the arangelist, don't leak it.  */
     207           0 :               free (new_arange);
     208           0 :               goto fail;
     209             :             }
     210          97 :           new_arange->arange.offset = __libdw_first_die_off_from_cu (cu);
     211             : 
     212          97 :           new_arange->next = arangelist;
     213          97 :           arangelist = new_arange;
     214          97 :           ++narangelist;
     215             : 
     216             :           /* Sanity-check the data.  */
     217          97 :           if (unlikely (new_arange->arange.offset
     218             :                         >= dbg->sectiondata[IDX_debug_info]->d_size))
     219           0 :             goto invalid;
     220             :         }
     221             :     }
     222             : 
     223          60 :   if (narangelist == 0)
     224             :     {
     225           0 :       assert (arangelist == NULL);
     226           0 :       if (naranges != NULL)
     227           0 :         *naranges = 0;
     228           0 :       *aranges = NULL;
     229           0 :       return 0;
     230             :     }
     231             : 
     232             :   /* Allocate the array for the result.  */
     233          60 :   void *buf = libdw_alloc (dbg, Dwarf_Aranges,
     234             :                            sizeof (Dwarf_Aranges)
     235             :                            + narangelist * sizeof (Dwarf_Arange), 1);
     236             : 
     237             :   /* First use the buffer for the pointers, and sort the entries.
     238             :      We'll write the pointers in the end of the buffer, and then
     239             :      copy into the buffer from the beginning so the overlap works.  */
     240          60 :   assert (sizeof (Dwarf_Arange) >= sizeof (Dwarf_Arange *));
     241         120 :   struct arangelist **sortaranges
     242             :     = (buf + sizeof (Dwarf_Aranges)
     243          60 :        + ((sizeof (Dwarf_Arange) - sizeof sortaranges[0]) * narangelist));
     244             : 
     245             :   /* The list is in LIFO order and usually they come in clumps with
     246             :      ascending addresses.  So fill from the back to probably start with
     247             :      runs already in order before we sort.  */
     248          60 :   unsigned int i = narangelist;
     249         157 :   while (i-- > 0)
     250             :     {
     251          97 :       sortaranges[i] = arangelist;
     252          97 :       arangelist = arangelist->next;
     253             :     }
     254          60 :   assert (arangelist == NULL);
     255             : 
     256             :   /* Sort by ascending address.  */
     257          60 :   qsort (sortaranges, narangelist, sizeof sortaranges[0], &compare_aranges);
     258             : 
     259             :   /* Now that they are sorted, put them in the final array.
     260             :      The buffers overlap, so we've clobbered the early elements
     261             :      of SORTARANGES by the time we're reading the later ones.  */
     262          60 :   *aranges = buf;
     263          60 :   (*aranges)->dbg = dbg;
     264          60 :   (*aranges)->naranges = narangelist;
     265          60 :   dbg->aranges = *aranges;
     266          60 :   if (naranges != NULL)
     267          60 :     *naranges = narangelist;
     268         157 :   for (i = 0; i < narangelist; ++i)
     269             :     {
     270          97 :       struct arangelist *elt = sortaranges[i];
     271          97 :       (*aranges)->info[i] = elt->arange;
     272          97 :       free (elt);
     273             :     }
     274             : 
     275             :   return 0;
     276             : }
     277             : INTDEF(dwarf_getaranges)

Generated by: LCOV version 1.13