LCOV - code coverage report
Current view: top level - libdw - dwarf_ranges.c (source / functions) Hit Total Coverage
Test: elfutils-0.181 Lines: 186 295 63.1 %
Date: 2020-09-08 14:07:57 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     2331898 : __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     2331898 :   Dwarf *dbg = cu->dbg;
      52     2331898 :   if (sec_index == IDX_debug_loc
      53     2324736 :       && cu->version < 5
      54     2324736 :       && 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           0 :         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          17 :         case DW_LLE_GNU_end_of_list_entry:
      66          17 :           *addrp = addr;
      67         208 :           return 2;
      68             : 
      69           0 :         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           0 :         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         191 :         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         191 :           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     2331690 :   else if (sec_index == IDX_debug_ranges || sec_index == IDX_debug_loc)
     116             :     {
     117     4662714 :       Dwarf_Addr escape = (width == 8 ? (Elf64_Addr) -1
     118     2331357 :                            : (Elf64_Addr) (Elf32_Addr) -1);
     119     2331357 :       Dwarf_Addr begin;
     120     2331357 :       Dwarf_Addr end;
     121             : 
     122     2331357 :       const unsigned char *addr = *addrp;
     123     2331357 :       if (addrend - addr < width * 2)
     124             :         {
     125           0 :         invalid:
     126           0 :           __libdw_seterrno (DWARF_E_INVALID_DWARF);
     127           0 :           return -1;
     128             :         }
     129             : 
     130     2331357 :       bool begin_relocated = READ_AND_RELOCATE (__libdw_relocate_address,
     131             :                                                 begin);
     132     2331357 :       bool end_relocated = READ_AND_RELOCATE (__libdw_relocate_address,
     133             :                                               end);
     134     2331357 :       *addrp = addr;
     135             : 
     136             :       /* Unrelocated escape for begin means base address selection.  */
     137     2331357 :       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     2331356 :       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     2265837 :       *beginp = begin + *basep;
     153     2265837 :       *endp = end + *basep;
     154             : 
     155     2265837 :       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           0 :         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           6 :         case DW_RLE_end_of_list:
     168           6 :           *addrp = addr;
     169          30 :           return 2;
     170             : 
     171           0 :         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           0 :         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           0 :         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          18 :         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           0 :         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           0 :         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           6 :         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           0 :         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          26 :         case DW_LLE_end_of_list:
     275          26 :           *addrp = addr;
     276         303 :           return 2;
     277             : 
     278           0 :         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           0 :         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         129 :         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         123 :         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           0 :         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          19 :         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           0 :         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           6 :         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        6801 : initial_offset (Dwarf_Attribute *attr, ptrdiff_t *offset)
     386             : {
     387       13602 :   size_t secidx = (attr->cu->version < 5
     388        6801 :                    ? IDX_debug_ranges : IDX_debug_rnglists);
     389             : 
     390        6801 :   Dwarf_Word start_offset;
     391        6801 :   if (attr->form == DW_FORM_rnglistx)
     392             :     {
     393           4 :       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           0 :         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        6803 :       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        6801 :   *offset = start_offset;
     460        6801 :   return 0;
     461             : }
     462             : 
     463             : ptrdiff_t
     464      661282 : dwarf_ranges (Dwarf_Die *die, ptrdiff_t offset, Dwarf_Addr *basep,
     465             :               Dwarf_Addr *startp, Dwarf_Addr *endp)
     466             : {
     467      661282 :   if (die == NULL)
     468             :     return -1;
     469             : 
     470      661282 :   if (offset == 0
     471             :       /* Usually there is a single contiguous range.  */
     472      657426 :       && INTUSE(dwarf_highpc) (die, endp) == 0
     473        4169 :       && 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      657113 :   if (offset == 1)
     480             :     return 0;
     481             : 
     482             :   /* We have to look for a noncontiguous range.  */
     483      653314 :   Dwarf_CU *cu = die->cu;
     484      653314 :   if (cu == NULL)
     485             :     {
     486        1132 :       __libdw_seterrno (DWARF_E_INVALID_DWARF);
     487        1132 :       return -1;
     488             :     }
     489             : 
     490      652182 :   size_t secidx = (cu->version < 5 ? IDX_debug_ranges : IDX_debug_rnglists);
     491      652182 :   const Elf_Data *d = cu->dbg->sectiondata[secidx];
     492      652182 :   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      652182 :   const unsigned char *readp;
     503      652182 :   const unsigned char *readendp;
     504      652182 :   if (offset == 0)
     505             :     {
     506      652125 :       Dwarf_Attribute attr_mem;
     507      652125 :       Dwarf_Attribute *attr = INTUSE(dwarf_attr) (die, DW_AT_ranges,
     508             :                                                   &attr_mem);
     509             :       /* Note that above we use dwarf_attr, not dwarf_attr_integrate.
     510             :          The only case where the ranges can come from another DIE
     511             :          attribute are the split CU case. In that case we also have a
     512             :          different CU to check against. But that is already set up
     513             :          above using __libdw_find_split_unit.  */
     514      652125 :       if (attr == NULL
     515      645330 :           && is_cudie (die)
     516           6 :           && die->cu->unit_type == DW_UT_split_compile)
     517           6 :         attr = INTUSE(dwarf_attr_integrate) (die, DW_AT_ranges, &attr_mem);
     518      652125 :       if (attr == NULL)
     519             :         /* No PC attributes in this DIE at all, so an empty range list.  */
     520      645324 :         return 0;
     521             : 
     522        6801 :       *basep = __libdw_cu_base_address (attr->cu);
     523        6801 :       if (*basep == (Dwarf_Addr) -1)
     524             :         return -1;
     525             : 
     526        6801 :       if (initial_offset (attr, &offset) != 0)
     527             :         return -1;
     528             :     }
     529             :   else
     530             :     {
     531          57 :       if (__libdw_offset_in_section (cu->dbg,
     532             :                                      secidx, offset, 1))
     533             :         return -1;
     534             :     }
     535             : 
     536        6858 :   readp = d->d_buf + offset;
     537        6858 :   readendp = d->d_buf + d->d_size;
     538             : 
     539        6859 :   Dwarf_Addr begin;
     540        6859 :   Dwarf_Addr end;
     541             : 
     542        6859 :  next:
     543        6859 :   switch (__libdw_read_begin_end_pair_inc (cu, secidx,
     544             :                                            &readp, readendp,
     545        6859 :                                            cu->address_size,
     546             :                                            &begin, &end, basep))
     547             :     {
     548             :     case 0:
     549        6836 :       break;
     550             :     case 1:
     551             :       goto next;
     552             :     case 2:
     553             :       return 0;
     554           0 :     default:
     555           0 :       return -1;
     556             :     }
     557             : 
     558        6836 :   *startp = begin;
     559        6836 :   *endp = end;
     560        6836 :   return readp - (unsigned char *) d->d_buf;
     561             : }
     562             : INTDEF (dwarf_ranges)

Generated by: LCOV version 1.13