Blame libdw/dwarf_ranges.c

Packit Service 97d2fb
/* Enumerate the PC ranges covered by a DIE.
Packit Service 97d2fb
   Copyright (C) 2005, 2007, 2009, 2018 Red Hat, Inc.
Packit Service 97d2fb
   This file is part of elfutils.
Packit Service 97d2fb
Packit Service 97d2fb
   This file is free software; you can redistribute it and/or modify
Packit Service 97d2fb
   it under the terms of either
Packit Service 97d2fb
Packit Service 97d2fb
     * the GNU Lesser General Public License as published by the Free
Packit Service 97d2fb
       Software Foundation; either version 3 of the License, or (at
Packit Service 97d2fb
       your option) any later version
Packit Service 97d2fb
Packit Service 97d2fb
   or
Packit Service 97d2fb
Packit Service 97d2fb
     * the GNU General Public License as published by the Free
Packit Service 97d2fb
       Software Foundation; either version 2 of the License, or (at
Packit Service 97d2fb
       your option) any later version
Packit Service 97d2fb
Packit Service 97d2fb
   or both in parallel, as here.
Packit Service 97d2fb
Packit Service 97d2fb
   elfutils is distributed in the hope that it will be useful, but
Packit Service 97d2fb
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 97d2fb
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 97d2fb
   General Public License for more details.
Packit Service 97d2fb
Packit Service 97d2fb
   You should have received copies of the GNU General Public License and
Packit Service 97d2fb
   the GNU Lesser General Public License along with this program.  If
Packit Service 97d2fb
   not, see <http://www.gnu.org/licenses/>.  */
Packit Service 97d2fb
Packit Service 97d2fb
#ifdef HAVE_CONFIG_H
Packit Service 97d2fb
# include <config.h>
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
#include "libdwP.h"
Packit Service 97d2fb
#include <dwarf.h>
Packit Service 97d2fb
#include <assert.h>
Packit Service 97d2fb
Packit Service 97d2fb
/* Read up begin/end pair and increment read pointer.
Packit Service 97d2fb
    - If it's normal range record, set up `*beginp' and `*endp' and return 0.
Packit Service 97d2fb
    - If it's a default location, set `*beginp' (0), `*endp' (-1) and return 0.
Packit Service 97d2fb
    - If it's base address selection record, set up `*basep' and return 1.
Packit Service 97d2fb
    - If it's end of rangelist, don't set anything and return 2
Packit Service 97d2fb
    - If an error occurs, don't set anything and return -1.  */
Packit Service 97d2fb
internal_function int
Packit Service 97d2fb
__libdw_read_begin_end_pair_inc (Dwarf_CU *cu, int sec_index,
Packit Service 97d2fb
				 const unsigned char **addrp,
Packit Service 97d2fb
				 const unsigned char *addrend,
Packit Service 97d2fb
				 int width,
Packit Service 97d2fb
				 Dwarf_Addr *beginp, Dwarf_Addr *endp,
Packit Service 97d2fb
				 Dwarf_Addr *basep)
Packit Service 97d2fb
{
Packit Service 97d2fb
  Dwarf *dbg = cu->dbg;
Packit Service 97d2fb
  if (sec_index == IDX_debug_loc
Packit Service 97d2fb
      && cu->version < 5
Packit Service 97d2fb
      && cu->unit_type == DW_UT_split_compile)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* GNU DebugFission.  */
Packit Service 97d2fb
      const unsigned char *addr = *addrp;
Packit Service 97d2fb
      if (addrend - addr < 1)
Packit Service 97d2fb
	goto invalid;
Packit Service 97d2fb
Packit Service 97d2fb
      const char code = *addr++;
Packit Service 97d2fb
      uint64_t begin = 0, end = 0, base = *basep, addr_idx;
Packit Service 97d2fb
      switch (code)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	case DW_LLE_GNU_end_of_list_entry:
Packit Service 97d2fb
	  *addrp = addr;
Packit Service 97d2fb
	  return 2;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_LLE_GNU_base_address_selection_entry:
Packit Service 97d2fb
	  if (addrend - addr < 1)
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
	  get_uleb128 (addr_idx, addr, addrend);
Packit Service 97d2fb
	  if (__libdw_addrx (cu, addr_idx, &base) != 0)
Packit Service 97d2fb
	    return -1;
Packit Service 97d2fb
	  *basep = base;
Packit Service 97d2fb
	  *addrp = addr;
Packit Service 97d2fb
	  return 1;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_LLE_GNU_start_end_entry:
Packit Service 97d2fb
	  if (addrend - addr < 1)
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
	  get_uleb128 (addr_idx, addr, addrend);
Packit Service 97d2fb
	  if (__libdw_addrx (cu, addr_idx, &begin) != 0)
Packit Service 97d2fb
	    return -1;
Packit Service 97d2fb
	  if (addrend - addr < 1)
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
	  get_uleb128 (addr_idx, addr, addrend);
Packit Service 97d2fb
	  if (__libdw_addrx (cu, addr_idx, &end) != 0)
Packit Service 97d2fb
	    return -1;
Packit Service 97d2fb
Packit Service 97d2fb
	  *beginp = begin;
Packit Service 97d2fb
	  *endp = end;
Packit Service 97d2fb
	  *addrp = addr;
Packit Service 97d2fb
	  return 0;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_LLE_GNU_start_length_entry:
Packit Service 97d2fb
	  if (addrend - addr < 1)
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
	  get_uleb128 (addr_idx, addr, addrend);
Packit Service 97d2fb
	  if (__libdw_addrx (cu, addr_idx, &begin) != 0)
Packit Service 97d2fb
	    return -1;
Packit Service 97d2fb
	  if (addrend - addr < 4)
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
	  end = read_4ubyte_unaligned_inc (dbg, addr);
Packit Service 97d2fb
Packit Service 97d2fb
	  *beginp = begin;
Packit Service 97d2fb
	  *endp = begin + end;
Packit Service 97d2fb
	  *addrp = addr;
Packit Service 97d2fb
	  return 0;
Packit Service 97d2fb
Packit Service 97d2fb
	default:
Packit Service 97d2fb
	  goto invalid;
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else if (sec_index == IDX_debug_ranges || sec_index == IDX_debug_loc)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      Dwarf_Addr escape = (width == 8 ? (Elf64_Addr) -1
Packit Service 97d2fb
			   : (Elf64_Addr) (Elf32_Addr) -1);
Packit Service 97d2fb
      Dwarf_Addr begin;
Packit Service 97d2fb
      Dwarf_Addr end;
Packit Service 97d2fb
Packit Service 97d2fb
      const unsigned char *addr = *addrp;
Packit Service 97d2fb
      if (addrend - addr < width * 2)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	invalid:
Packit Service 97d2fb
	  __libdw_seterrno (DWARF_E_INVALID_DWARF);
Packit Service 97d2fb
	  return -1;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      bool begin_relocated = READ_AND_RELOCATE (__libdw_relocate_address,
Packit Service 97d2fb
						begin);
Packit Service 97d2fb
      bool end_relocated = READ_AND_RELOCATE (__libdw_relocate_address,
Packit Service 97d2fb
					      end);
Packit Service 97d2fb
      *addrp = addr;
Packit Service 97d2fb
Packit Service 97d2fb
      /* Unrelocated escape for begin means base address selection.  */
Packit Service 97d2fb
      if (begin == escape && !begin_relocated)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  if (unlikely (end == escape))
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
Packit Service 97d2fb
	  *basep = end;
Packit Service 97d2fb
	  return 1;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* Unrelocated pair of zeroes means end of range list.  */
Packit Service 97d2fb
      if (begin == 0 && end == 0 && !begin_relocated && !end_relocated)
Packit Service 97d2fb
	return 2;
Packit Service 97d2fb
Packit Service 97d2fb
      /* Don't check for begin_relocated == end_relocated.  Serve the data
Packit Service 97d2fb
	 to the client even though it may be buggy.  */
Packit Service 97d2fb
      *beginp = begin + *basep;
Packit Service 97d2fb
      *endp = end + *basep;
Packit Service 97d2fb
Packit Service 97d2fb
      return 0;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else if (sec_index == IDX_debug_rnglists)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      const unsigned char *addr = *addrp;
Packit Service 97d2fb
      if (addrend - addr < 1)
Packit Service 97d2fb
	goto invalid;
Packit Service 97d2fb
Packit Service 97d2fb
      const char code = *addr++;
Packit Service 97d2fb
      uint64_t begin = 0, end = 0, base = *basep, addr_idx;
Packit Service 97d2fb
      switch (code)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	case DW_RLE_end_of_list:
Packit Service 97d2fb
	  *addrp = addr;
Packit Service 97d2fb
	  return 2;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_RLE_base_addressx:
Packit Service 97d2fb
	  if (addrend - addr < 1)
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
	  get_uleb128 (addr_idx, addr, addrend);
Packit Service 97d2fb
	  if (__libdw_addrx (cu, addr_idx, &base) != 0)
Packit Service 97d2fb
	    return -1;
Packit Service 97d2fb
Packit Service 97d2fb
	  *basep = base;
Packit Service 97d2fb
	  *addrp = addr;
Packit Service 97d2fb
	  return 1;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_RLE_startx_endx:
Packit Service 97d2fb
	  if (addrend - addr < 1)
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
	  get_uleb128 (addr_idx, addr, addrend);
Packit Service 97d2fb
	  if (__libdw_addrx (cu, addr_idx, &begin) != 0)
Packit Service 97d2fb
	    return -1;
Packit Service 97d2fb
	  if (addrend - addr < 1)
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
	  get_uleb128 (addr_idx, addr, addrend);
Packit Service 97d2fb
	  if (__libdw_addrx (cu, addr_idx, &end) != 0)
Packit Service 97d2fb
	    return -1;
Packit Service 97d2fb
Packit Service 97d2fb
	  *beginp = begin;
Packit Service 97d2fb
	  *endp = end;
Packit Service 97d2fb
	  *addrp = addr;
Packit Service 97d2fb
	  return 0;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_RLE_startx_length:
Packit Service 97d2fb
	  if (addrend - addr < 1)
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
	  get_uleb128 (addr_idx, addr, addrend);
Packit Service 97d2fb
	  if (__libdw_addrx (cu, addr_idx, &begin) != 0)
Packit Service 97d2fb
	    return -1;
Packit Service 97d2fb
	  if (addrend - addr < 1)
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
	  get_uleb128 (end, addr, addrend);
Packit Service 97d2fb
Packit Service 97d2fb
	  *beginp = begin;
Packit Service 97d2fb
	  *endp = begin + end;
Packit Service 97d2fb
	  *addrp = addr;
Packit Service 97d2fb
	  return 0;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_RLE_offset_pair:
Packit Service 97d2fb
	  if (addrend - addr < 1)
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
	  get_uleb128 (begin, addr, addrend);
Packit Service 97d2fb
	  if (addrend - addr < 1)
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
	  get_uleb128 (end, addr, addrend);
Packit Service 97d2fb
Packit Service 97d2fb
	  *beginp = begin + base;
Packit Service 97d2fb
	  *endp = end + base;
Packit Service 97d2fb
	  *addrp = addr;
Packit Service 97d2fb
	  return 0;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_RLE_base_address:
Packit Service 97d2fb
	  if (addrend - addr < width)
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
	  __libdw_read_address_inc (dbg, sec_index, &addr, width, &base);
Packit Service 97d2fb
Packit Service 97d2fb
	  *basep = base;
Packit Service 97d2fb
	  *addrp = addr;
Packit Service 97d2fb
	  return 1;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_RLE_start_end:
Packit Service 97d2fb
	  if (addrend - addr < 2 * width)
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
	  __libdw_read_address_inc (dbg, sec_index, &addr, width, &begin);
Packit Service 97d2fb
	  __libdw_read_address_inc (dbg, sec_index, &addr, width, &end;;
Packit Service 97d2fb
Packit Service 97d2fb
	  *beginp = begin;
Packit Service 97d2fb
	  *endp = end;
Packit Service 97d2fb
	  *addrp = addr;
Packit Service 97d2fb
	  return 0;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_RLE_start_length:
Packit Service 97d2fb
	  if (addrend - addr < width)
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
	  __libdw_read_address_inc (dbg, sec_index, &addr, width, &begin);
Packit Service 97d2fb
	  if (addrend - addr < 1)
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
	  get_uleb128 (end, addr, addrend);
Packit Service 97d2fb
Packit Service 97d2fb
	  *beginp = begin;
Packit Service 97d2fb
	  *endp = begin + end;
Packit Service 97d2fb
	  *addrp = addr;
Packit Service 97d2fb
	  return 0;
Packit Service 97d2fb
Packit Service 97d2fb
	default:
Packit Service 97d2fb
	  goto invalid;
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else if (sec_index == IDX_debug_loclists)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      const unsigned char *addr = *addrp;
Packit Service 97d2fb
      if (addrend - addr < 1)
Packit Service 97d2fb
	goto invalid;
Packit Service 97d2fb
Packit Service 97d2fb
      const char code = *addr++;
Packit Service 97d2fb
      uint64_t begin = 0, end = 0, base = *basep, addr_idx;
Packit Service 97d2fb
      switch (code)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	case DW_LLE_end_of_list:
Packit Service 97d2fb
	  *addrp = addr;
Packit Service 97d2fb
	  return 2;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_LLE_base_addressx:
Packit Service 97d2fb
	  if (addrend - addr < 1)
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
	  get_uleb128 (addr_idx, addr, addrend);
Packit Service 97d2fb
	  if (__libdw_addrx (cu, addr_idx, &base) != 0)
Packit Service 97d2fb
	    return -1;
Packit Service 97d2fb
Packit Service 97d2fb
	  *basep = base;
Packit Service 97d2fb
	  *addrp = addr;
Packit Service 97d2fb
	  return 1;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_LLE_startx_endx:
Packit Service 97d2fb
	  if (addrend - addr < 1)
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
	  get_uleb128 (addr_idx, addr, addrend);
Packit Service 97d2fb
	  if (__libdw_addrx (cu, addr_idx, &begin) != 0)
Packit Service 97d2fb
	    return -1;
Packit Service 97d2fb
	  if (addrend - addr < 1)
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
	  get_uleb128 (addr_idx, addr, addrend);
Packit Service 97d2fb
	  if (__libdw_addrx (cu, addr_idx, &end) != 0)
Packit Service 97d2fb
	    return -1;
Packit Service 97d2fb
Packit Service 97d2fb
	  *beginp = begin;
Packit Service 97d2fb
	  *endp = end;
Packit Service 97d2fb
	  *addrp = addr;
Packit Service 97d2fb
	  return 0;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_LLE_startx_length:
Packit Service 97d2fb
	  if (addrend - addr < 1)
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
	  get_uleb128 (addr_idx, addr, addrend);
Packit Service 97d2fb
	  if (__libdw_addrx (cu, addr_idx, &begin) != 0)
Packit Service 97d2fb
	    return -1;
Packit Service 97d2fb
	  if (addrend - addr < 1)
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
	  get_uleb128 (end, addr, addrend);
Packit Service 97d2fb
Packit Service 97d2fb
	  *beginp = begin;
Packit Service 97d2fb
	  *endp = begin + end;
Packit Service 97d2fb
	  *addrp = addr;
Packit Service 97d2fb
	  return 0;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_LLE_offset_pair:
Packit Service 97d2fb
	  if (addrend - addr < 1)
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
	  get_uleb128 (begin, addr, addrend);
Packit Service 97d2fb
	  if (addrend - addr < 1)
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
	  get_uleb128 (end, addr, addrend);
Packit Service 97d2fb
Packit Service 97d2fb
	  *beginp = begin + base;
Packit Service 97d2fb
	  *endp = end + base;
Packit Service 97d2fb
	  *addrp = addr;
Packit Service 97d2fb
	  return 0;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_LLE_default_location:
Packit Service 97d2fb
	  *beginp = 0;
Packit Service 97d2fb
	  *endp = (Dwarf_Addr) -1;
Packit Service 97d2fb
	  *addrp = addr;
Packit Service 97d2fb
	  return 0;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_LLE_base_address:
Packit Service 97d2fb
	  if (addrend - addr < width)
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
	  __libdw_read_address_inc (dbg, sec_index, &addr, width, &base);
Packit Service 97d2fb
Packit Service 97d2fb
	  *basep = base;
Packit Service 97d2fb
	  *addrp = addr;
Packit Service 97d2fb
	  return 1;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_LLE_start_end:
Packit Service 97d2fb
	  if (addrend - addr < 2 * width)
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
	  __libdw_read_address_inc (dbg, sec_index, &addr, width, &begin);
Packit Service 97d2fb
	  __libdw_read_address_inc (dbg, sec_index, &addr, width, &end;;
Packit Service 97d2fb
Packit Service 97d2fb
	  *beginp = begin;
Packit Service 97d2fb
	  *endp = end;
Packit Service 97d2fb
	  *addrp = addr;
Packit Service 97d2fb
	  return 0;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_LLE_start_length:
Packit Service 97d2fb
	  if (addrend - addr < width)
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
	  __libdw_read_address_inc (dbg, sec_index, &addr, width, &begin);
Packit Service 97d2fb
	  if (addrend - addr < 1)
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
	  get_uleb128 (end, addr, addrend);
Packit Service 97d2fb
Packit Service 97d2fb
	  *beginp = begin;
Packit Service 97d2fb
	  *endp = begin + end;
Packit Service 97d2fb
	  *addrp = addr;
Packit Service 97d2fb
	  return 0;
Packit Service 97d2fb
Packit Service 97d2fb
	default:
Packit Service 97d2fb
	  goto invalid;
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else
Packit Service 97d2fb
    {
Packit Service 97d2fb
      __libdw_seterrno (DWARF_E_INVALID_DWARF);
Packit Service 97d2fb
      return -1;
Packit Service 97d2fb
    }
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
initial_offset (Dwarf_Attribute *attr, ptrdiff_t *offset)
Packit Service 97d2fb
{
Packit Service 97d2fb
  size_t secidx = (attr->cu->version < 5
Packit Service 97d2fb
		   ? IDX_debug_ranges : IDX_debug_rnglists);
Packit Service 97d2fb
Packit Service 97d2fb
  Dwarf_Word start_offset;
Packit Service 97d2fb
  if (attr->form == DW_FORM_rnglistx)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      Dwarf_Word idx;
Packit Service 97d2fb
      Dwarf_CU *cu = attr->cu;
Packit Service 97d2fb
      const unsigned char *datap = attr->valp;
Packit Service 97d2fb
      const unsigned char *endp = cu->endp;
Packit Service 97d2fb
      if (datap >= endp)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  __libdw_seterrno (DWARF_E_INVALID_DWARF);
Packit Service 97d2fb
	  return -1;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      get_uleb128 (idx, datap, endp);
Packit Service 97d2fb
Packit Service 97d2fb
      Elf_Data *data = cu->dbg->sectiondata[secidx];
Packit Service 97d2fb
      if (data == NULL && cu->unit_type == DW_UT_split_compile)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  cu = __libdw_find_split_unit (cu);
Packit Service 97d2fb
	  if (cu != NULL)
Packit Service 97d2fb
	    data = cu->dbg->sectiondata[secidx];
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      if (data == NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  __libdw_seterrno (secidx == IDX_debug_ranges
Packit Service 97d2fb
                            ? DWARF_E_NO_DEBUG_RANGES
Packit Service 97d2fb
                            : DWARF_E_NO_DEBUG_RNGLISTS);
Packit Service 97d2fb
	  return -1;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      Dwarf_Off range_base_off = __libdw_cu_ranges_base (cu);
Packit Service 97d2fb
Packit Service 97d2fb
      /* The section should at least contain room for one offset.  */
Packit Service 97d2fb
      size_t sec_size = cu->dbg->sectiondata[secidx]->d_size;
Packit Service 97d2fb
      size_t offset_size = cu->offset_size;
Packit Service 97d2fb
      if (offset_size > sec_size)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	invalid_offset:
Packit Service 97d2fb
	  __libdw_seterrno (DWARF_E_INVALID_OFFSET);
Packit Service 97d2fb
	  return -1;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* And the base offset should be at least inside the section.  */
Packit Service 97d2fb
      if (range_base_off > (sec_size - offset_size))
Packit Service 97d2fb
	goto invalid_offset;
Packit Service 97d2fb
Packit Service 97d2fb
      size_t max_idx = (sec_size - offset_size - range_base_off) / offset_size;
Packit Service 97d2fb
      if (idx > max_idx)
Packit Service 97d2fb
	goto invalid_offset;
Packit Service 97d2fb
Packit Service 97d2fb
      datap = (cu->dbg->sectiondata[secidx]->d_buf
Packit Service 97d2fb
	       + range_base_off + (idx * offset_size));
Packit Service 97d2fb
      if (offset_size == 4)
Packit Service 97d2fb
	start_offset = read_4ubyte_unaligned (cu->dbg, datap);
Packit Service 97d2fb
      else
Packit Service 97d2fb
	start_offset = read_8ubyte_unaligned (cu->dbg, datap);
Packit Service 97d2fb
Packit Service 97d2fb
      start_offset += range_base_off;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (__libdw_formptr (attr, secidx,
Packit Service 97d2fb
			   (secidx == IDX_debug_ranges
Packit Service 97d2fb
			    ? DWARF_E_NO_DEBUG_RANGES
Packit Service 97d2fb
			    : DWARF_E_NO_DEBUG_RNGLISTS),
Packit Service 97d2fb
			   NULL, &start_offset) == NULL)
Packit Service 97d2fb
	return -1;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  *offset = start_offset;
Packit Service 97d2fb
  return 0;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
ptrdiff_t
Packit Service 97d2fb
dwarf_ranges (Dwarf_Die *die, ptrdiff_t offset, Dwarf_Addr *basep,
Packit Service 97d2fb
	      Dwarf_Addr *startp, Dwarf_Addr *endp)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (die == NULL)
Packit Service 97d2fb
    return -1;
Packit Service 97d2fb
Packit Service 97d2fb
  if (offset == 0
Packit Service 97d2fb
      /* Usually there is a single contiguous range.  */
Packit Service 97d2fb
      && INTUSE(dwarf_highpc) (die, endp) == 0
Packit Service 97d2fb
      && INTUSE(dwarf_lowpc) (die, startp) == 0)
Packit Service 97d2fb
    /* A offset into .debug_ranges will never be 1, it must be at least a
Packit Service 97d2fb
       multiple of 4.  So we can return 1 as a special case value to mark
Packit Service 97d2fb
       there are no ranges to look for on the next call.  */
Packit Service 97d2fb
    return 1;
Packit Service 97d2fb
Packit Service 97d2fb
  if (offset == 1)
Packit Service 97d2fb
    return 0;
Packit Service 97d2fb
Packit Service 97d2fb
  /* We have to look for a noncontiguous range.  */
Packit Service 97d2fb
  Dwarf_CU *cu = die->cu;
Packit Service 97d2fb
  if (cu == NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      __libdw_seterrno (DWARF_E_INVALID_DWARF);
Packit Service 97d2fb
      return -1;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  size_t secidx = (cu->version < 5 ? IDX_debug_ranges : IDX_debug_rnglists);
Packit Service 97d2fb
  const Elf_Data *d = cu->dbg->sectiondata[secidx];
Packit Service 97d2fb
  if (d == NULL && cu->unit_type == DW_UT_split_compile)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      Dwarf_CU *skel = __libdw_find_split_unit (cu);
Packit Service 97d2fb
      if (skel != NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  cu = skel;
Packit Service 97d2fb
	  d = cu->dbg->sectiondata[secidx];
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  const unsigned char *readp;
Packit Service 97d2fb
  const unsigned char *readendp;
Packit Service 97d2fb
  if (offset == 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      Dwarf_Attribute attr_mem;
Packit Service 97d2fb
      Dwarf_Attribute *attr = INTUSE(dwarf_attr) (die, DW_AT_ranges,
Packit Service 97d2fb
						  &attr_mem);
Packit Service 97d2fb
      /* Note that above we use dwarf_attr, not dwarf_attr_integrate.
Packit Service 97d2fb
	 The only case where the ranges can come from another DIE
Packit Service 97d2fb
	 attribute are the split CU case. In that case we also have a
Packit Service 97d2fb
	 different CU to check against. But that is already set up
Packit Service 97d2fb
	 above using __libdw_find_split_unit.  */
Packit Service 97d2fb
      if (attr == NULL
Packit Service 97d2fb
	  && is_cudie (die)
Packit Service 97d2fb
	  && die->cu->unit_type == DW_UT_split_compile)
Packit Service 97d2fb
	attr = INTUSE(dwarf_attr_integrate) (die, DW_AT_ranges, &attr_mem);
Packit Service 97d2fb
      if (attr == NULL)
Packit Service 97d2fb
	/* No PC attributes in this DIE at all, so an empty range list.  */
Packit Service 97d2fb
	return 0;
Packit Service 97d2fb
Packit Service 97d2fb
      *basep = __libdw_cu_base_address (attr->cu);
Packit Service 97d2fb
      if (*basep == (Dwarf_Addr) -1)
Packit Service 97d2fb
	return -1;
Packit Service 97d2fb
Packit Service 97d2fb
      if (initial_offset (attr, &offset) != 0)
Packit Service 97d2fb
	return -1;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (__libdw_offset_in_section (cu->dbg,
Packit Service 97d2fb
				     secidx, offset, 1))
Packit Service 97d2fb
	return -1;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  readp = d->d_buf + offset;
Packit Service 97d2fb
  readendp = d->d_buf + d->d_size;
Packit Service 97d2fb
Packit Service 97d2fb
  Dwarf_Addr begin;
Packit Service 97d2fb
  Dwarf_Addr end;
Packit Service 97d2fb
Packit Service 97d2fb
 next:
Packit Service 97d2fb
  switch (__libdw_read_begin_end_pair_inc (cu, secidx,
Packit Service 97d2fb
					   &readp, readendp,
Packit Service 97d2fb
					   cu->address_size,
Packit Service 97d2fb
					   &begin, &end, basep))
Packit Service 97d2fb
    {
Packit Service 97d2fb
    case 0:
Packit Service 97d2fb
      break;
Packit Service 97d2fb
    case 1:
Packit Service 97d2fb
      goto next;
Packit Service 97d2fb
    case 2:
Packit Service 97d2fb
      return 0;
Packit Service 97d2fb
    default:
Packit Service 97d2fb
      return -1;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  *startp = begin;
Packit Service 97d2fb
  *endp = end;
Packit Service 97d2fb
  return readp - (unsigned char *) d->d_buf;
Packit Service 97d2fb
}
Packit Service 97d2fb
INTDEF (dwarf_ranges)