LCOV - code coverage report
Current view: top level - libdw - dwarf_ranges.c (source / functions) Hit Total Coverage
Test: elfutils-0.173 Lines: 164 256 64.1 %
Date: 2018-06-29 23:49:12 Functions: 3 3 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Enumerate the PC ranges covered by a DIE.
       2             :    Copyright (C) 2005, 2007, 2009, 2018 Red Hat, Inc.
       3             :    This file is part of elfutils.
       4             : 
       5             :    This file is free software; you can redistribute it and/or modify
       6             :    it under the terms of either
       7             : 
       8             :      * the GNU Lesser General Public License as published by the Free
       9             :        Software Foundation; either version 3 of the License, or (at
      10             :        your option) any later version
      11             : 
      12             :    or
      13             : 
      14             :      * the GNU General Public License as published by the Free
      15             :        Software Foundation; either version 2 of the License, or (at
      16             :        your option) any later version
      17             : 
      18             :    or both in parallel, as here.
      19             : 
      20             :    elfutils is distributed in the hope that it will be useful, but
      21             :    WITHOUT ANY WARRANTY; without even the implied warranty of
      22             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      23             :    General Public License for more details.
      24             : 
      25             :    You should have received copies of the GNU General Public License and
      26             :    the GNU Lesser General Public License along with this program.  If
      27             :    not, see <http://www.gnu.org/licenses/>.  */
      28             : 
      29             : #ifdef HAVE_CONFIG_H
      30             : # include <config.h>
      31             : #endif
      32             : 
      33             : #include "libdwP.h"
      34             : #include <dwarf.h>
      35             : #include <assert.h>
      36             : 
      37             : /* Read up begin/end pair and increment read pointer.
      38             :     - If it's normal range record, set up `*beginp' and `*endp' and return 0.
      39             :     - If it's a default location, set `*beginp' (0), `*endp' (-1) and return 0.
      40             :     - If it's base address selection record, set up `*basep' and return 1.
      41             :     - If it's end of rangelist, don't set anything and return 2
      42             :     - If an error occurs, don't set anything and return -1.  */
      43             : internal_function int
      44     1732896 : __libdw_read_begin_end_pair_inc (Dwarf_CU *cu, int sec_index,
      45             :                                  const unsigned char **addrp,
      46             :                                  const unsigned char *addrend,
      47             :                                  int width,
      48             :                                  Dwarf_Addr *beginp, Dwarf_Addr *endp,
      49             :                                  Dwarf_Addr *basep)
      50             : {
      51     1732896 :   Dwarf *dbg = cu->dbg;
      52     1732896 :   if (sec_index == IDX_debug_loc
      53     1725443 :       && cu->version < 5
      54     1725443 :       && cu->unit_type == DW_UT_split_compile)
      55             :     {
      56             :       /* GNU DebugFission.  */
      57         208 :       const unsigned char *addr = *addrp;
      58         208 :       if (addrend - addr < 1)
      59             :         goto invalid;
      60             : 
      61         208 :       const char code = *addr++;
      62         208 :       uint64_t begin = 0, end = 0, base = *basep, addr_idx;
      63         208 :       switch (code)
      64             :         {
      65             :         case DW_LLE_GNU_end_of_list_entry:
      66          17 :           *addrp = addr;
      67         225 :           return 2;
      68             : 
      69             :         case DW_LLE_GNU_base_address_selection_entry:
      70           0 :           if (addrend - addr < 1)
      71             :             goto invalid;
      72           0 :           get_uleb128 (addr_idx, addr, addrend);
      73           0 :           if (__libdw_addrx (cu, addr_idx, &base) != 0)
      74             :             return -1;
      75           0 :           *basep = base;
      76           0 :           *addrp = addr;
      77           0 :           return 1;
      78             : 
      79             :         case DW_LLE_GNU_start_end_entry:
      80           0 :           if (addrend - addr < 1)
      81             :             goto invalid;
      82           0 :           get_uleb128 (addr_idx, addr, addrend);
      83           0 :           if (__libdw_addrx (cu, addr_idx, &begin) != 0)
      84             :             return -1;
      85           0 :           if (addrend - addr < 1)
      86             :             goto invalid;
      87           0 :           get_uleb128 (addr_idx, addr, addrend);
      88           0 :           if (__libdw_addrx (cu, addr_idx, &end) != 0)
      89             :             return -1;
      90             : 
      91           0 :           *beginp = begin;
      92           0 :           *endp = end;
      93           0 :           *addrp = addr;
      94           0 :           return 0;
      95             : 
      96             :         case DW_LLE_GNU_start_length_entry:
      97         191 :           if (addrend - addr < 1)
      98             :             goto invalid;
      99         191 :           get_uleb128 (addr_idx, addr, addrend);
     100         191 :           if (__libdw_addrx (cu, addr_idx, &begin) != 0)
     101             :             return -1;
     102         191 :           if (addrend - addr < 4)
     103             :             goto invalid;
     104         382 :           end = read_4ubyte_unaligned_inc (dbg, addr);
     105             : 
     106         191 :           *beginp = begin;
     107         191 :           *endp = begin + end;
     108         191 :           *addrp = addr;
     109         191 :           return 0;
     110             : 
     111             :         default:
     112             :           goto invalid;
     113             :         }
     114             :     }
     115     1732688 :   else if (sec_index == IDX_debug_ranges || sec_index == IDX_debug_loc)
     116             :     {
     117     1732355 :       Dwarf_Addr escape = (width == 8 ? (Elf64_Addr) -1
     118     1732355 :                            : (Elf64_Addr) (Elf32_Addr) -1);
     119             :       Dwarf_Addr begin;
     120             :       Dwarf_Addr end;
     121             : 
     122     1732355 :       const unsigned char *addr = *addrp;
     123     1732355 :       if (addrend - addr < width * 2)
     124             :         {
     125             :         invalid:
     126           0 :           __libdw_seterrno (DWARF_E_INVALID_DWARF);
     127           0 :           return -1;
     128             :         }
     129             : 
     130     3464710 :       bool begin_relocated = READ_AND_RELOCATE (__libdw_relocate_address,
     131             :                                                 begin);
     132     3464710 :       bool end_relocated = READ_AND_RELOCATE (__libdw_relocate_address,
     133             :                                               end);
     134     1732355 :       *addrp = addr;
     135             : 
     136             :       /* Unrelocated escape for begin means base address selection.  */
     137     1732355 :       if (begin == escape && !begin_relocated)
     138             :         {
     139           1 :           if (unlikely (end == escape))
     140             :             goto invalid;
     141             : 
     142           1 :           *basep = end;
     143           1 :           return 1;
     144             :         }
     145             : 
     146             :       /* Unrelocated pair of zeroes means end of range list.  */
     147     1732354 :       if (begin == 0 && end == 0 && !begin_relocated && !end_relocated)
     148             :         return 2;
     149             : 
     150             :       /* Don't check for begin_relocated == end_relocated.  Serve the data
     151             :          to the client even though it may be buggy.  */
     152     1672429 :       *beginp = begin + *basep;
     153     1672429 :       *endp = end + *basep;
     154             : 
     155     1672429 :       return 0;
     156             :     }
     157         333 :   else if (sec_index == IDX_debug_rnglists)
     158             :     {
     159          30 :       const unsigned char *addr = *addrp;
     160          30 :       if (addrend - addr < 1)
     161             :         goto invalid;
     162             : 
     163          30 :       const char code = *addr++;
     164          30 :       uint64_t begin = 0, end = 0, base = *basep, addr_idx;
     165          30 :       switch (code)
     166             :         {
     167             :         case DW_RLE_end_of_list:
     168           6 :           *addrp = addr;
     169          36 :           return 2;
     170             : 
     171             :         case DW_RLE_base_addressx:
     172           0 :           if (addrend - addr < 1)
     173             :             goto invalid;
     174           0 :           get_uleb128 (addr_idx, addr, addrend);
     175           0 :           if (__libdw_addrx (cu, addr_idx, &base) != 0)
     176             :             return -1;
     177             : 
     178           0 :           *basep = base;
     179           0 :           *addrp = addr;
     180           0 :           return 1;
     181             : 
     182             :         case DW_RLE_startx_endx:
     183           0 :           if (addrend - addr < 1)
     184             :             goto invalid;
     185           0 :           get_uleb128 (addr_idx, addr, addrend);
     186           0 :           if (__libdw_addrx (cu, addr_idx, &begin) != 0)
     187             :             return -1;
     188           0 :           if (addrend - addr < 1)
     189             :             goto invalid;
     190           0 :           get_uleb128 (addr_idx, addr, addrend);
     191           0 :           if (__libdw_addrx (cu, addr_idx, &end) != 0)
     192             :             return -1;
     193             : 
     194           0 :           *beginp = begin;
     195           0 :           *endp = end;
     196           0 :           *addrp = addr;
     197           0 :           return 0;
     198             : 
     199             :         case DW_RLE_startx_length:
     200           0 :           if (addrend - addr < 1)
     201             :             goto invalid;
     202           0 :           get_uleb128 (addr_idx, addr, addrend);
     203           0 :           if (__libdw_addrx (cu, addr_idx, &begin) != 0)
     204             :             return -1;
     205           0 :           if (addrend - addr < 1)
     206             :             goto invalid;
     207           0 :           get_uleb128 (end, addr, addrend);
     208             : 
     209           0 :           *beginp = begin;
     210           0 :           *endp = begin + end;
     211           0 :           *addrp = addr;
     212           0 :           return 0;
     213             : 
     214             :         case DW_RLE_offset_pair:
     215          18 :           if (addrend - addr < 1)
     216             :             goto invalid;
     217          18 :           get_uleb128 (begin, addr, addrend);
     218          18 :           if (addrend - addr < 1)
     219             :             goto invalid;
     220          18 :           get_uleb128 (end, addr, addrend);
     221             : 
     222          18 :           *beginp = begin + base;
     223          18 :           *endp = end + base;
     224          18 :           *addrp = addr;
     225          18 :           return 0;
     226             : 
     227             :         case DW_RLE_base_address:
     228           0 :           if (addrend - addr < width)
     229             :             goto invalid;
     230           0 :           __libdw_read_address_inc (dbg, sec_index, &addr, width, &base);
     231             : 
     232           0 :           *basep = base;
     233           0 :           *addrp = addr;
     234           0 :           return 1;
     235             : 
     236             :         case DW_RLE_start_end:
     237           0 :           if (addrend - addr < 2 * width)
     238             :             goto invalid;
     239           0 :           __libdw_read_address_inc (dbg, sec_index, &addr, width, &begin);
     240           0 :           __libdw_read_address_inc (dbg, sec_index, &addr, width, &end);
     241             : 
     242           0 :           *beginp = begin;
     243           0 :           *endp = end;
     244           0 :           *addrp = addr;
     245           0 :           return 0;
     246             : 
     247             :         case DW_RLE_start_length:
     248           6 :           if (addrend - addr < width)
     249             :             goto invalid;
     250           6 :           __libdw_read_address_inc (dbg, sec_index, &addr, width, &begin);
     251           6 :           if (addrend - addr < 1)
     252             :             goto invalid;
     253           6 :           get_uleb128 (end, addr, addrend);
     254             : 
     255           6 :           *beginp = begin;
     256           6 :           *endp = begin + end;
     257           6 :           *addrp = addr;
     258           6 :           return 0;
     259             : 
     260             :         default:
     261             :           goto invalid;
     262             :         }
     263             :     }
     264         303 :   else if (sec_index == IDX_debug_loclists)
     265             :     {
     266         303 :       const unsigned char *addr = *addrp;
     267         303 :       if (addrend - addr < 1)
     268             :         goto invalid;
     269             : 
     270         303 :       const char code = *addr++;
     271         303 :       uint64_t begin = 0, end = 0, base = *basep, addr_idx;
     272         303 :       switch (code)
     273             :         {
     274             :         case DW_LLE_end_of_list:
     275          26 :           *addrp = addr;
     276         329 :           return 2;
     277             : 
     278             :         case DW_LLE_base_addressx:
     279           0 :           if (addrend - addr < 1)
     280             :             goto invalid;
     281           0 :           get_uleb128 (addr_idx, addr, addrend);
     282           0 :           if (__libdw_addrx (cu, addr_idx, &base) != 0)
     283             :             return -1;
     284             : 
     285           0 :           *basep = base;
     286           0 :           *addrp = addr;
     287           0 :           return 1;
     288             : 
     289             :         case DW_LLE_startx_endx:
     290           0 :           if (addrend - addr < 1)
     291             :             goto invalid;
     292           0 :           get_uleb128 (addr_idx, addr, addrend);
     293           0 :           if (__libdw_addrx (cu, addr_idx, &begin) != 0)
     294             :             return -1;
     295           0 :           if (addrend - addr < 1)
     296             :             goto invalid;
     297           0 :           get_uleb128 (addr_idx, addr, addrend);
     298           0 :           if (__libdw_addrx (cu, addr_idx, &end) != 0)
     299             :             return -1;
     300             : 
     301           0 :           *beginp = begin;
     302           0 :           *endp = end;
     303           0 :           *addrp = addr;
     304           0 :           return 0;
     305             : 
     306             :         case DW_LLE_startx_length:
     307         129 :           if (addrend - addr < 1)
     308             :             goto invalid;
     309         129 :           get_uleb128 (addr_idx, addr, addrend);
     310         129 :           if (__libdw_addrx (cu, addr_idx, &begin) != 0)
     311             :             return -1;
     312         129 :           if (addrend - addr < 1)
     313             :             goto invalid;
     314         129 :           get_uleb128 (end, addr, addrend);
     315             : 
     316         129 :           *beginp = begin;
     317         129 :           *endp = begin + end;
     318         129 :           *addrp = addr;
     319         129 :           return 0;
     320             : 
     321             :         case DW_LLE_offset_pair:
     322         123 :           if (addrend - addr < 1)
     323             :             goto invalid;
     324         123 :           get_uleb128 (begin, addr, addrend);
     325         123 :           if (addrend - addr < 1)
     326             :             goto invalid;
     327         123 :           get_uleb128 (end, addr, addrend);
     328             : 
     329         123 :           *beginp = begin + base;
     330         123 :           *endp = end + base;
     331         123 :           *addrp = addr;
     332         123 :           return 0;
     333             : 
     334             :         case DW_LLE_default_location:
     335           0 :           *beginp = 0;
     336           0 :           *endp = (Dwarf_Addr) -1;
     337           0 :           *addrp = addr;
     338           0 :           return 0;
     339             : 
     340             :         case DW_LLE_base_address:
     341          19 :           if (addrend - addr < width)
     342             :             goto invalid;
     343          19 :           __libdw_read_address_inc (dbg, sec_index, &addr, width, &base);
     344             : 
     345          19 :           *basep = base;
     346          19 :           *addrp = addr;
     347          19 :           return 1;
     348             : 
     349             :         case DW_LLE_start_end:
     350           0 :           if (addrend - addr < 2 * width)
     351             :             goto invalid;
     352           0 :           __libdw_read_address_inc (dbg, sec_index, &addr, width, &begin);
     353           0 :           __libdw_read_address_inc (dbg, sec_index, &addr, width, &end);
     354             : 
     355           0 :           *beginp = begin;
     356           0 :           *endp = end;
     357           0 :           *addrp = addr;
     358           0 :           return 0;
     359             : 
     360             :         case DW_LLE_start_length:
     361           6 :           if (addrend - addr < width)
     362             :             goto invalid;
     363           6 :           __libdw_read_address_inc (dbg, sec_index, &addr, width, &begin);
     364           6 :           if (addrend - addr < 1)
     365             :             goto invalid;
     366           6 :           get_uleb128 (end, addr, addrend);
     367             : 
     368           6 :           *beginp = begin;
     369           6 :           *endp = begin + end;
     370           6 :           *addrp = addr;
     371           6 :           return 0;
     372             : 
     373             :         default:
     374             :           goto invalid;
     375             :         }
     376             :     }
     377             :   else
     378             :     {
     379           0 :       __libdw_seterrno (DWARF_E_INVALID_DWARF);
     380           0 :       return -1;
     381             :     }
     382             : }
     383             : 
     384             : static int
     385        6675 : initial_offset (Dwarf_Attribute *attr, ptrdiff_t *offset)
     386             : {
     387        6675 :   size_t secidx = (attr->cu->version < 5
     388             :                    ? IDX_debug_ranges : IDX_debug_rnglists);
     389             : 
     390             :   Dwarf_Word start_offset;
     391        6675 :   if (attr->form == DW_FORM_rnglistx)
     392             :     {
     393             :       Dwarf_Word idx;
     394           4 :       Dwarf_CU *cu = attr->cu;
     395           4 :       const unsigned char *datap = attr->valp;
     396           4 :       const unsigned char *endp = cu->endp;
     397           4 :       if (datap >= endp)
     398             :         {
     399           0 :           __libdw_seterrno (DWARF_E_INVALID_DWARF);
     400           0 :           return -1;
     401             :         }
     402           4 :       get_uleb128 (idx, datap, endp);
     403             : 
     404           4 :       Elf_Data *data = cu->dbg->sectiondata[secidx];
     405           4 :       if (data == NULL && cu->unit_type == DW_UT_split_compile)
     406             :         {
     407           4 :           cu = __libdw_find_split_unit (cu);
     408           4 :           if (cu != NULL)
     409           4 :             data = cu->dbg->sectiondata[secidx];
     410             :         }
     411             : 
     412           4 :       if (data == NULL)
     413             :         {
     414           0 :           __libdw_seterrno (secidx == IDX_debug_ranges
     415             :                             ? DWARF_E_NO_DEBUG_RANGES
     416             :                             : DWARF_E_NO_DEBUG_RNGLISTS);
     417           0 :           return -1;
     418             :         }
     419             : 
     420           4 :       Dwarf_Off range_base_off = __libdw_cu_ranges_base (cu);
     421             : 
     422             :       /* The section should at least contain room for one offset.  */
     423           4 :       size_t sec_size = cu->dbg->sectiondata[secidx]->d_size;
     424           4 :       size_t offset_size = cu->offset_size;
     425           4 :       if (offset_size > sec_size)
     426             :         {
     427             :         invalid_offset:
     428           0 :           __libdw_seterrno (DWARF_E_INVALID_OFFSET);
     429           0 :           return -1;
     430             :         }
     431             : 
     432             :       /* And the base offset should be at least inside the section.  */
     433           4 :       if (range_base_off > (sec_size - offset_size))
     434             :         goto invalid_offset;
     435             : 
     436           4 :       size_t max_idx = (sec_size - offset_size - range_base_off) / offset_size;
     437           4 :       if (idx > max_idx)
     438             :         goto invalid_offset;
     439             : 
     440           8 :       datap = (cu->dbg->sectiondata[secidx]->d_buf
     441           4 :                + range_base_off + (idx * offset_size));
     442           4 :       if (offset_size == 4)
     443           4 :         start_offset = read_4ubyte_unaligned (cu->dbg, datap);
     444             :       else
     445           0 :         start_offset = read_8ubyte_unaligned (cu->dbg, datap);
     446             : 
     447           4 :       start_offset += range_base_off;
     448             :     }
     449             :   else
     450             :     {
     451        6671 :       if (__libdw_formptr (attr, secidx,
     452             :                            (secidx == IDX_debug_ranges
     453             :                             ? DWARF_E_NO_DEBUG_RANGES
     454             :                             : DWARF_E_NO_DEBUG_RNGLISTS),
     455             :                            NULL, &start_offset) == NULL)
     456             :         return -1;
     457             :     }
     458             : 
     459        6675 :   *offset = start_offset;
     460        6675 :   return 0;
     461             : }
     462             : 
     463             : ptrdiff_t
     464     1481874 : dwarf_ranges (Dwarf_Die *die, ptrdiff_t offset, Dwarf_Addr *basep,
     465             :               Dwarf_Addr *startp, Dwarf_Addr *endp)
     466             : {
     467      504014 :   if (die == NULL)
     468             :     return -1;
     469             : 
     470      504014 :   if (offset == 0
     471             :       /* Usually there is a single contiguous range.  */
     472      500193 :       && INTUSE(dwarf_highpc) (die, endp) == 0
     473        3715 :       && INTUSE(dwarf_lowpc) (die, startp) == 0)
     474             :     /* A offset into .debug_ranges will never be 1, it must be at least a
     475             :        multiple of 4.  So we can return 1 as a special case value to mark
     476             :        there are no ranges to look for on the next call.  */
     477             :     return 1;
     478             : 
     479      500299 :   if (offset == 1)
     480             :     return 0;
     481             : 
     482             :   /* We have to look for a noncontiguous range.  */
     483      496952 :   Dwarf_CU *cu = die->cu;
     484      496952 :   if (cu == NULL)
     485             :     {
     486         879 :       __libdw_seterrno (DWARF_E_INVALID_DWARF);
     487         879 :       return -1;
     488             :     }
     489             : 
     490      496073 :   size_t secidx = (cu->version < 5 ? IDX_debug_ranges : IDX_debug_rnglists);
     491      496073 :   const Elf_Data *d = cu->dbg->sectiondata[secidx];
     492      496073 :   if (d == NULL && cu->unit_type == DW_UT_split_compile)
     493             :     {
     494         152 :       Dwarf_CU *skel = __libdw_find_split_unit (cu);
     495         152 :       if (skel != NULL)
     496             :         {
     497         152 :           cu = skel;
     498         152 :           d = cu->dbg->sectiondata[secidx];
     499             :         }
     500             :     }
     501             : 
     502             :   const unsigned char *readp;
     503             :   const unsigned char *readendp;
     504      496073 :   if (offset == 0)
     505             :     {
     506             :       Dwarf_Attribute attr_mem;
     507      495599 :       Dwarf_Attribute *attr = INTUSE(dwarf_attr) (die, DW_AT_ranges,
     508             :                                                   &attr_mem);
     509      495599 :       if (attr == NULL
     510      977860 :           && is_cudie (die)
     511           6 :           && die->cu->unit_type == DW_UT_split_compile)
     512           6 :         attr = INTUSE(dwarf_attr_integrate) (die, DW_AT_ranges, &attr_mem);
     513      495599 :       if (attr == NULL)
     514             :         /* No PC attributes in this DIE at all, so an empty range list.  */
     515      488924 :         return 0;
     516             : 
     517        6675 :       *basep = __libdw_cu_base_address (attr->cu);
     518        6675 :       if (*basep == (Dwarf_Addr) -1)
     519             :         return -1;
     520             : 
     521        6675 :       if (initial_offset (attr, &offset) != 0)
     522             :         return -1;
     523             :     }
     524             :   else
     525             :     {
     526         474 :       if (__libdw_offset_in_section (cu->dbg,
     527             :                                      secidx, offset, 1))
     528             :         return -1;
     529             :     }
     530             : 
     531        7149 :   readp = d->d_buf + offset;
     532        7149 :   readendp = d->d_buf + d->d_size;
     533             : 
     534             :   Dwarf_Addr begin;
     535             :   Dwarf_Addr end;
     536             : 
     537             :  next:
     538        7150 :   switch (__libdw_read_begin_end_pair_inc (cu, secidx,
     539             :                                            &readp, readendp,
     540        7150 :                                            cu->address_size,
     541             :                                            &begin, &end, basep))
     542             :     {
     543             :     case 0:
     544             :       break;
     545             :     case 1:
     546             :       goto next;
     547             :     case 2:
     548             :       return 0;
     549             :     default:
     550           0 :       return -1;
     551             :     }
     552             : 
     553        7008 :   *startp = begin;
     554        7008 :   *endp = end;
     555        7008 :   return readp - (unsigned char *) d->d_buf;
     556             : }
     557             : INTDEF (dwarf_ranges)

Generated by: LCOV version 1.13