Blame libdw/dwarf_getlocation.c

Packit Service 97d2fb
/* Return location expression list.
Packit Service 97d2fb
   Copyright (C) 2000-2010, 2013-2015, 2017, 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 <dwarf.h>
Packit Service 97d2fb
#include <search.h>
Packit Service 97d2fb
#include <stdlib.h>
Packit Service 97d2fb
#include <assert.h>
Packit Service 97d2fb
Packit Service 97d2fb
#include <libdwP.h>
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
static bool
Packit Service 97d2fb
attr_ok (Dwarf_Attribute *attr)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (attr == NULL)
Packit Service 97d2fb
    return false;
Packit Service 97d2fb
Packit Service 97d2fb
  /* If it is an exprloc, it is obviously OK.  */
Packit Service 97d2fb
  if (dwarf_whatform (attr) == DW_FORM_exprloc)
Packit Service 97d2fb
    return true;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Otherwise must be one of the attributes listed below.  Older
Packit Service 97d2fb
     DWARF versions might have encoded the exprloc as block, and we
Packit Service 97d2fb
     cannot easily distinquish attributes in the loclist class because
Packit Service 97d2fb
     the same forms are used for different classes.  */
Packit Service 97d2fb
  switch (attr->code)
Packit Service 97d2fb
    {
Packit Service 97d2fb
    case DW_AT_location:
Packit Service 97d2fb
    case DW_AT_byte_size:
Packit Service 97d2fb
    case DW_AT_bit_offset:
Packit Service 97d2fb
    case DW_AT_bit_size:
Packit Service 97d2fb
    case DW_AT_lower_bound:
Packit Service 97d2fb
    case DW_AT_bit_stride:
Packit Service 97d2fb
    case DW_AT_upper_bound:
Packit Service 97d2fb
    case DW_AT_count:
Packit Service 97d2fb
    case DW_AT_allocated:
Packit Service 97d2fb
    case DW_AT_associated:
Packit Service 97d2fb
    case DW_AT_data_location:
Packit Service 97d2fb
    case DW_AT_byte_stride:
Packit Service 97d2fb
    case DW_AT_rank:
Packit Service 97d2fb
    case DW_AT_call_value:
Packit Service 97d2fb
    case DW_AT_call_target:
Packit Service 97d2fb
    case DW_AT_call_target_clobbered:
Packit Service 97d2fb
    case DW_AT_call_data_location:
Packit Service 97d2fb
    case DW_AT_call_data_value:
Packit Service 97d2fb
    case DW_AT_data_member_location:
Packit Service 97d2fb
    case DW_AT_vtable_elem_location:
Packit Service 97d2fb
    case DW_AT_string_length:
Packit Service 97d2fb
    case DW_AT_use_location:
Packit Service 97d2fb
    case DW_AT_frame_base:
Packit Service 97d2fb
    case DW_AT_return_addr:
Packit Service 97d2fb
    case DW_AT_static_link:
Packit Service 97d2fb
    case DW_AT_segment:
Packit Service 97d2fb
    case DW_AT_GNU_call_site_value:
Packit Service 97d2fb
    case DW_AT_GNU_call_site_data_value:
Packit Service 97d2fb
    case DW_AT_GNU_call_site_target:
Packit Service 97d2fb
    case DW_AT_GNU_call_site_target_clobbered:
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    default:
Packit Service 97d2fb
      __libdw_seterrno (DWARF_E_NO_LOC_VALUE);
Packit Service 97d2fb
      return false;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return true;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
struct loclist
Packit Service 97d2fb
{
Packit Service 97d2fb
  uint8_t atom;
Packit Service 97d2fb
  Dwarf_Word number;
Packit Service 97d2fb
  Dwarf_Word number2;
Packit Service 97d2fb
  Dwarf_Word offset;
Packit Service 97d2fb
  struct loclist *next;
Packit Service 97d2fb
};
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
loc_compare (const void *p1, const void *p2)
Packit Service 97d2fb
{
Packit Service 97d2fb
  const struct loc_s *l1 = (const struct loc_s *) p1;
Packit Service 97d2fb
  const struct loc_s *l2 = (const struct loc_s *) p2;
Packit Service 97d2fb
Packit Service 97d2fb
  if ((uintptr_t) l1->addr < (uintptr_t) l2->addr)
Packit Service 97d2fb
    return -1;
Packit Service 97d2fb
  if ((uintptr_t) l1->addr > (uintptr_t) l2->addr)
Packit Service 97d2fb
    return 1;
Packit Service 97d2fb
Packit Service 97d2fb
  return 0;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* For each DW_OP_implicit_value, we store a special entry in the cache.
Packit Service 97d2fb
   This points us directly to the block data for later fetching.
Packit Service 97d2fb
   Returns zero on success, -1 on bad DWARF or 1 if tsearch failed.  */
Packit Service 97d2fb
static int
Packit Service 97d2fb
store_implicit_value (Dwarf *dbg, void **cache, Dwarf_Op *op)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (dbg == NULL)
Packit Service 97d2fb
    return -1;
Packit Service 97d2fb
  struct loc_block_s *block = libdw_alloc (dbg, struct loc_block_s,
Packit Service 97d2fb
					   sizeof (struct loc_block_s), 1);
Packit Service 97d2fb
  const unsigned char *data = (const unsigned char *) (uintptr_t) op->number2;
Packit Service 97d2fb
  /* Skip the block length.  */
Packit Service 97d2fb
  __libdw_get_uleb128_unchecked (&data);
Packit Service 97d2fb
  block->addr = op;
Packit Service 97d2fb
  block->data = (unsigned char *) data;
Packit Service 97d2fb
  block->length = op->number;
Packit Service 97d2fb
  if (unlikely (tsearch (block, cache, loc_compare) == NULL))
Packit Service 97d2fb
    return 1;
Packit Service 97d2fb
  return 0;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
int
Packit Service 97d2fb
dwarf_getlocation_implicit_value (Dwarf_Attribute *attr, const Dwarf_Op *op,
Packit Service 97d2fb
				  Dwarf_Block *return_block)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (attr == NULL)
Packit Service 97d2fb
    return -1;
Packit Service 97d2fb
Packit Service 97d2fb
  struct loc_block_s fake = { .addr = (void *) op };
Packit Service 97d2fb
  struct loc_block_s **found = tfind (&fake, &attr->cu->locs, loc_compare);
Packit Service 97d2fb
  if (unlikely (found == NULL))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      __libdw_seterrno (DWARF_E_NO_BLOCK);
Packit Service 97d2fb
      return -1;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return_block->length = (*found)->length;
Packit Service 97d2fb
  return_block->data = (*found)->data;
Packit Service 97d2fb
  return 0;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* If the given attribute is DW_AT_data_member_location and it has constant
Packit Service 97d2fb
   form then create a fake location using DW_OP_plus_uconst and the offset
Packit Service 97d2fb
   value.  On success returns zero and fills in llbuf (when not NULL) and
Packit Service 97d2fb
   sets listlen to 1.  Returns 1 when this isn't a DW_AT_data_member_location
Packit Service 97d2fb
   offset.  Returns -1 and sets dwarf_errno on failure (bad DWARF data).  */
Packit Service 97d2fb
static int
Packit Service 97d2fb
is_constant_offset (Dwarf_Attribute *attr,
Packit Service 97d2fb
		    Dwarf_Op **llbuf, size_t *listlen)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (attr->code != DW_AT_data_member_location)
Packit Service 97d2fb
    return 1;
Packit Service 97d2fb
Packit Service 97d2fb
  switch (attr->form)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* Punt for any non-constant form.  */
Packit Service 97d2fb
    default:
Packit Service 97d2fb
      return 1;
Packit Service 97d2fb
Packit Service 97d2fb
      /* Note, we don't regard DW_FORM_data16 as a constant form,
Packit Service 97d2fb
	 even though technically it is according to the standard.  */
Packit Service 97d2fb
    case DW_FORM_data1:
Packit Service 97d2fb
    case DW_FORM_data2:
Packit Service 97d2fb
    case DW_FORM_data4:
Packit Service 97d2fb
    case DW_FORM_data8:
Packit Service 97d2fb
    case DW_FORM_sdata:
Packit Service 97d2fb
    case DW_FORM_udata:
Packit Service 97d2fb
      break;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Check whether we already cached this location.  */
Packit Service 97d2fb
  struct loc_s fake = { .addr = attr->valp };
Packit Service 97d2fb
  struct loc_s **found = tfind (&fake, &attr->cu->locs, loc_compare);
Packit Service 97d2fb
Packit Service 97d2fb
  if (found == NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      Dwarf_Word offset;
Packit Service 97d2fb
      if (INTUSE(dwarf_formudata) (attr, &offset) != 0)
Packit Service 97d2fb
	return -1;
Packit Service 97d2fb
Packit Service 97d2fb
      Dwarf_Op *result = libdw_alloc (attr->cu->dbg,
Packit Service 97d2fb
				      Dwarf_Op, sizeof (Dwarf_Op), 1);
Packit Service 97d2fb
Packit Service 97d2fb
      result->atom = DW_OP_plus_uconst;
Packit Service 97d2fb
      result->number = offset;
Packit Service 97d2fb
      result->number2 = 0;
Packit Service 97d2fb
      result->offset = 0;
Packit Service 97d2fb
Packit Service 97d2fb
      /* Insert a record in the search tree so we can find it again later.  */
Packit Service 97d2fb
      struct loc_s *newp = libdw_alloc (attr->cu->dbg,
Packit Service 97d2fb
					struct loc_s, sizeof (struct loc_s),
Packit Service 97d2fb
					1);
Packit Service 97d2fb
      newp->addr = attr->valp;
Packit Service 97d2fb
      newp->loc = result;
Packit Service 97d2fb
      newp->nloc = 1;
Packit Service 97d2fb
Packit Service 97d2fb
      found = tsearch (newp, &attr->cu->locs, loc_compare);
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  assert ((*found)->nloc == 1);
Packit Service 97d2fb
Packit Service 97d2fb
  if (llbuf != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      *llbuf = (*found)->loc;
Packit Service 97d2fb
      *listlen = 1;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return 0;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
int
Packit Service 97d2fb
internal_function
Packit Service 97d2fb
__libdw_intern_expression (Dwarf *dbg, bool other_byte_order,
Packit Service 97d2fb
			   unsigned int address_size, unsigned int ref_size,
Packit Service 97d2fb
			   void **cache, const Dwarf_Block *block,
Packit Service 97d2fb
			   bool cfap, bool valuep,
Packit Service 97d2fb
			   Dwarf_Op **llbuf, size_t *listlen, int sec_index)
Packit Service 97d2fb
{
Packit Service 97d2fb
  /* Empty location expressions don't have any ops to intern.  */
Packit Service 97d2fb
  if (block->length == 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      *listlen = 0;
Packit Service 97d2fb
      return 0;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Check whether we already looked at this list.  */
Packit Service 97d2fb
  struct loc_s fake = { .addr = block->data };
Packit Service 97d2fb
  struct loc_s **found = tfind (&fake, cache, loc_compare);
Packit Service 97d2fb
  if (found != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* We already saw it.  */
Packit Service 97d2fb
      *llbuf = (*found)->loc;
Packit Service 97d2fb
      *listlen = (*found)->nloc;
Packit Service 97d2fb
Packit Service 97d2fb
      if (valuep)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  assert (*listlen > 1);
Packit Service 97d2fb
	  assert ((*llbuf)[*listlen - 1].atom == DW_OP_stack_value);
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      return 0;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  const unsigned char *data = block->data;
Packit Service 97d2fb
  const unsigned char *const end_data = data + block->length;
Packit Service 97d2fb
Packit Service 97d2fb
  const struct { bool other_byte_order; } bo = { other_byte_order };
Packit Service 97d2fb
Packit Service 97d2fb
  struct loclist *loclist = NULL;
Packit Service 97d2fb
  unsigned int n = 0;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Stack allocate at most this many locs.  */
Packit Service 97d2fb
#define MAX_STACK_LOCS 256
Packit Service 97d2fb
  struct loclist stack_locs[MAX_STACK_LOCS];
Packit Service 97d2fb
#define NEW_LOC() ({ struct loclist *ll;			\
Packit Service 97d2fb
		     ll = (likely (n < MAX_STACK_LOCS)		\
Packit Service 97d2fb
			   ? &stack_locs[n]			\
Packit Service 97d2fb
			   : malloc (sizeof (struct loclist)));	\
Packit Service 97d2fb
		     if (unlikely (ll == NULL))			\
Packit Service 97d2fb
		       goto nomem;				\
Packit Service 97d2fb
		     n++;					\
Packit Service 97d2fb
		     ll->next = loclist;			\
Packit Service 97d2fb
		     loclist = ll;				\
Packit Service 97d2fb
		     ll; })
Packit Service 97d2fb
Packit Service 97d2fb
  if (cfap)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* Synthesize the operation to push the CFA before the expression.  */
Packit Service 97d2fb
      struct loclist *newloc = NEW_LOC ();
Packit Service 97d2fb
      newloc->atom = DW_OP_call_frame_cfa;
Packit Service 97d2fb
      newloc->number = 0;
Packit Service 97d2fb
      newloc->number2 = 0;
Packit Service 97d2fb
      newloc->offset = -1;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Decode the opcodes.  It is possible in some situations to have a
Packit Service 97d2fb
     block of size zero.  */
Packit Service 97d2fb
  while (data < end_data)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      struct loclist *newloc;
Packit Service 97d2fb
      newloc = NEW_LOC ();
Packit Service 97d2fb
      newloc->number = 0;
Packit Service 97d2fb
      newloc->number2 = 0;
Packit Service 97d2fb
      newloc->offset = data - block->data;
Packit Service 97d2fb
Packit Service 97d2fb
      switch ((newloc->atom = *data++))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	case DW_OP_addr:
Packit Service 97d2fb
	  /* Address, depends on address size of CU.  */
Packit Service 97d2fb
	  if (dbg == NULL)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      // XXX relocation?
Packit Service 97d2fb
	      if (address_size == 4)
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  if (unlikely (data + 4 > end_data))
Packit Service 97d2fb
		    goto invalid;
Packit Service 97d2fb
		  else
Packit Service 97d2fb
		    newloc->number = read_4ubyte_unaligned_inc (&bo, data);
Packit Service 97d2fb
		}
Packit Service 97d2fb
	      else
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  if (unlikely (data + 8 > end_data))
Packit Service 97d2fb
		    goto invalid;
Packit Service 97d2fb
		  else
Packit Service 97d2fb
		    newloc->number = read_8ubyte_unaligned_inc (&bo, data);
Packit Service 97d2fb
		}
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	  else if (__libdw_read_address_inc (dbg, sec_index, &data,
Packit Service 97d2fb
					     address_size, &newloc->number))
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_OP_call_ref:
Packit Service 97d2fb
	case DW_OP_GNU_variable_value:
Packit Service 97d2fb
	  /* DW_FORM_ref_addr, depends on offset size of CU.  */
Packit Service 97d2fb
	  if (dbg == NULL || __libdw_read_offset_inc (dbg, sec_index, &data,
Packit Service 97d2fb
						      ref_size,
Packit Service 97d2fb
						      &newloc->number,
Packit Service 97d2fb
						      IDX_debug_info, 0))
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_OP_deref:
Packit Service 97d2fb
	case DW_OP_dup:
Packit Service 97d2fb
	case DW_OP_drop:
Packit Service 97d2fb
	case DW_OP_over:
Packit Service 97d2fb
	case DW_OP_swap:
Packit Service 97d2fb
	case DW_OP_rot:
Packit Service 97d2fb
	case DW_OP_xderef:
Packit Service 97d2fb
	case DW_OP_abs:
Packit Service 97d2fb
	case DW_OP_and:
Packit Service 97d2fb
	case DW_OP_div:
Packit Service 97d2fb
	case DW_OP_minus:
Packit Service 97d2fb
	case DW_OP_mod:
Packit Service 97d2fb
	case DW_OP_mul:
Packit Service 97d2fb
	case DW_OP_neg:
Packit Service 97d2fb
	case DW_OP_not:
Packit Service 97d2fb
	case DW_OP_or:
Packit Service 97d2fb
	case DW_OP_plus:
Packit Service 97d2fb
	case DW_OP_shl:
Packit Service 97d2fb
	case DW_OP_shr:
Packit Service 97d2fb
	case DW_OP_shra:
Packit Service 97d2fb
	case DW_OP_xor:
Packit Service 97d2fb
	case DW_OP_eq:
Packit Service 97d2fb
	case DW_OP_ge:
Packit Service 97d2fb
	case DW_OP_gt:
Packit Service 97d2fb
	case DW_OP_le:
Packit Service 97d2fb
	case DW_OP_lt:
Packit Service 97d2fb
	case DW_OP_ne:
Packit Service 97d2fb
	case DW_OP_lit0 ... DW_OP_lit31:
Packit Service 97d2fb
	case DW_OP_reg0 ... DW_OP_reg31:
Packit Service 97d2fb
	case DW_OP_nop:
Packit Service 97d2fb
	case DW_OP_push_object_address:
Packit Service 97d2fb
	case DW_OP_call_frame_cfa:
Packit Service 97d2fb
	case DW_OP_form_tls_address:
Packit Service 97d2fb
	case DW_OP_GNU_push_tls_address:
Packit Service 97d2fb
	case DW_OP_stack_value:
Packit Service 97d2fb
	  /* No operand.  */
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_OP_const1u:
Packit Service 97d2fb
	case DW_OP_pick:
Packit Service 97d2fb
	case DW_OP_deref_size:
Packit Service 97d2fb
	case DW_OP_xderef_size:
Packit Service 97d2fb
	  if (unlikely (data >= end_data))
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	    invalid:
Packit Service 97d2fb
	      __libdw_seterrno (DWARF_E_INVALID_DWARF);
Packit Service 97d2fb
	    returnmem:
Packit Service 97d2fb
	      /* Free any dynamicly allocated loclists, if any.  */
Packit Service 97d2fb
	      while (n > MAX_STACK_LOCS)
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  struct loclist *loc = loclist;
Packit Service 97d2fb
		  loclist = loc->next;
Packit Service 97d2fb
		  free (loc);
Packit Service 97d2fb
		  n--;
Packit Service 97d2fb
		}
Packit Service 97d2fb
	      return -1;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  newloc->number = *data++;
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_OP_const1s:
Packit Service 97d2fb
	  if (unlikely (data >= end_data))
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
Packit Service 97d2fb
	  newloc->number = *((int8_t *) data);
Packit Service 97d2fb
	  ++data;
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_OP_const2u:
Packit Service 97d2fb
	  if (unlikely (data + 2 > end_data))
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
Packit Service 97d2fb
	  newloc->number = read_2ubyte_unaligned_inc (&bo, data);
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_OP_const2s:
Packit Service 97d2fb
	case DW_OP_skip:
Packit Service 97d2fb
	case DW_OP_bra:
Packit Service 97d2fb
	case DW_OP_call2:
Packit Service 97d2fb
	  if (unlikely (data + 2 > end_data))
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
Packit Service 97d2fb
	  newloc->number = read_2sbyte_unaligned_inc (&bo, data);
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_OP_const4u:
Packit Service 97d2fb
	  if (unlikely (data + 4 > end_data))
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
Packit Service 97d2fb
	  newloc->number = read_4ubyte_unaligned_inc (&bo, data);
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_OP_const4s:
Packit Service 97d2fb
	case DW_OP_call4:
Packit Service 97d2fb
	case DW_OP_GNU_parameter_ref:
Packit Service 97d2fb
	  if (unlikely (data + 4 > end_data))
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
Packit Service 97d2fb
	  newloc->number = read_4sbyte_unaligned_inc (&bo, data);
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_OP_const8u:
Packit Service 97d2fb
	  if (unlikely (data + 8 > end_data))
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
Packit Service 97d2fb
	  newloc->number = read_8ubyte_unaligned_inc (&bo, data);
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_OP_const8s:
Packit Service 97d2fb
	  if (unlikely (data + 8 > end_data))
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
Packit Service 97d2fb
	  newloc->number = read_8sbyte_unaligned_inc (&bo, data);
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_OP_constu:
Packit Service 97d2fb
	case DW_OP_plus_uconst:
Packit Service 97d2fb
	case DW_OP_regx:
Packit Service 97d2fb
	case DW_OP_piece:
Packit Service 97d2fb
	case DW_OP_convert:
Packit Service 97d2fb
	case DW_OP_GNU_convert:
Packit Service 97d2fb
	case DW_OP_reinterpret:
Packit Service 97d2fb
	case DW_OP_GNU_reinterpret:
Packit Service 97d2fb
	case DW_OP_addrx:
Packit Service 97d2fb
	case DW_OP_GNU_addr_index:
Packit Service 97d2fb
	case DW_OP_constx:
Packit Service 97d2fb
	case DW_OP_GNU_const_index:
Packit Service 97d2fb
	  get_uleb128 (newloc->number, data, end_data);
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_OP_consts:
Packit Service 97d2fb
	case DW_OP_breg0 ... DW_OP_breg31:
Packit Service 97d2fb
	case DW_OP_fbreg:
Packit Service 97d2fb
	  get_sleb128 (newloc->number, data, end_data);
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_OP_bregx:
Packit Service 97d2fb
	  get_uleb128 (newloc->number, data, end_data);
Packit Service 97d2fb
	  if (unlikely (data >= end_data))
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
	  get_sleb128 (newloc->number2, data, end_data);
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_OP_bit_piece:
Packit Service 97d2fb
	case DW_OP_regval_type:
Packit Service 97d2fb
	case DW_OP_GNU_regval_type:
Packit Service 97d2fb
	  get_uleb128 (newloc->number, data, end_data);
Packit Service 97d2fb
	  if (unlikely (data >= end_data))
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
	  get_uleb128 (newloc->number2, data, end_data);
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_OP_implicit_value:
Packit Service 97d2fb
	case DW_OP_entry_value:
Packit Service 97d2fb
	case DW_OP_GNU_entry_value:
Packit Service 97d2fb
	  /* This cannot be used in a CFI expression.  */
Packit Service 97d2fb
	  if (unlikely (dbg == NULL))
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
Packit Service 97d2fb
	  /* start of block inc. len.  */
Packit Service 97d2fb
	  newloc->number2 = (Dwarf_Word) (uintptr_t) data;
Packit Service 97d2fb
	  get_uleb128 (newloc->number, data, end_data); /* Block length.  */
Packit Service 97d2fb
	  if (unlikely ((Dwarf_Word) (end_data - data) < newloc->number))
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
	  data += newloc->number;		/* Skip the block.  */
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_OP_implicit_pointer:
Packit Service 97d2fb
	case DW_OP_GNU_implicit_pointer:
Packit Service 97d2fb
	  /* DW_FORM_ref_addr, depends on offset size of CU.  */
Packit Service 97d2fb
	  if (dbg == NULL || __libdw_read_offset_inc (dbg, sec_index, &data,
Packit Service 97d2fb
						      ref_size,
Packit Service 97d2fb
						      &newloc->number,
Packit Service 97d2fb
						      IDX_debug_info, 0))
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
	  if (unlikely (data >= end_data))
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
	  get_uleb128 (newloc->number2, data, end_data); /* Byte offset.  */
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_OP_deref_type:
Packit Service 97d2fb
	case DW_OP_GNU_deref_type:
Packit Service 97d2fb
	case DW_OP_xderef_type:
Packit Service 97d2fb
	  if (unlikely (data + 1 >= end_data))
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
	  newloc->number = *data++;
Packit Service 97d2fb
	  get_uleb128 (newloc->number2, data, end_data);
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
Packit Service 97d2fb
	case DW_OP_const_type:
Packit Service 97d2fb
	case DW_OP_GNU_const_type:
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    size_t size;
Packit Service 97d2fb
	    get_uleb128 (newloc->number, data, end_data);
Packit Service 97d2fb
	    if (unlikely (data >= end_data))
Packit Service 97d2fb
	      goto invalid;
Packit Service 97d2fb
Packit Service 97d2fb
	    /* start of block inc. len.  */
Packit Service 97d2fb
	    newloc->number2 = (Dwarf_Word) (uintptr_t) data;
Packit Service 97d2fb
	    size = *data++;
Packit Service 97d2fb
	    if (unlikely ((Dwarf_Word) (end_data - data) < size))
Packit Service 97d2fb
	      goto invalid;
Packit Service 97d2fb
	    data += size;		/* Skip the block.  */
Packit Service 97d2fb
	  }
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
Packit Service 97d2fb
	default:
Packit Service 97d2fb
	  goto invalid;
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (unlikely (n == 0))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* This is not allowed.
Packit Service 97d2fb
	 It would mean an empty location expression, which we handled
Packit Service 97d2fb
	 already as a special case above.  */
Packit Service 97d2fb
      goto invalid;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (valuep)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      struct loclist *newloc = NEW_LOC ();
Packit Service 97d2fb
      newloc->atom = DW_OP_stack_value;
Packit Service 97d2fb
      newloc->number = 0;
Packit Service 97d2fb
      newloc->number2 = 0;
Packit Service 97d2fb
      newloc->offset = data - block->data;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Allocate the array.  */
Packit Service 97d2fb
  Dwarf_Op *result;
Packit Service 97d2fb
  if (dbg != NULL)
Packit Service 97d2fb
    result = libdw_alloc (dbg, Dwarf_Op, sizeof (Dwarf_Op), n);
Packit Service 97d2fb
  else
Packit Service 97d2fb
    {
Packit Service 97d2fb
      result = malloc (sizeof *result * n);
Packit Service 97d2fb
      if (result == NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	nomem:
Packit Service 97d2fb
	  __libdw_seterrno (DWARF_E_NOMEM);
Packit Service 97d2fb
	  goto returnmem;
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Store the result.  */
Packit Service 97d2fb
  *llbuf = result;
Packit Service 97d2fb
  *listlen = n;
Packit Service 97d2fb
Packit Service 97d2fb
  do
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* We populate the array from the back since the list is backwards.  */
Packit Service 97d2fb
      --n;
Packit Service 97d2fb
      result[n].atom = loclist->atom;
Packit Service 97d2fb
      result[n].number = loclist->number;
Packit Service 97d2fb
      result[n].number2 = loclist->number2;
Packit Service 97d2fb
      result[n].offset = loclist->offset;
Packit Service 97d2fb
Packit Service 97d2fb
      if (result[n].atom == DW_OP_implicit_value)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  int store = store_implicit_value (dbg, cache, &result[n]);
Packit Service 97d2fb
	  if (unlikely (store != 0))
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      if (store < 0)
Packit Service 97d2fb
	        goto invalid;
Packit Service 97d2fb
	      else
Packit Service 97d2fb
		goto nomem;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      struct loclist *loc = loclist;
Packit Service 97d2fb
      loclist = loclist->next;
Packit Service 97d2fb
      if (unlikely (n + 1 > MAX_STACK_LOCS))
Packit Service 97d2fb
	free (loc);
Packit Service 97d2fb
    }
Packit Service 97d2fb
  while (n > 0);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Insert a record in the search tree so that we can find it again later.  */
Packit Service 97d2fb
  struct loc_s *newp;
Packit Service 97d2fb
  if (dbg != NULL)
Packit Service 97d2fb
    newp = libdw_alloc (dbg, struct loc_s, sizeof (struct loc_s), 1);
Packit Service 97d2fb
  else
Packit Service 97d2fb
    {
Packit Service 97d2fb
      newp = malloc (sizeof *newp);
Packit Service 97d2fb
      if (newp == NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  free (result);
Packit Service 97d2fb
	  goto nomem;
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  newp->addr = block->data;
Packit Service 97d2fb
  newp->loc = result;
Packit Service 97d2fb
  newp->nloc = *listlen;
Packit Service 97d2fb
  (void) tsearch (newp, cache, loc_compare);
Packit Service 97d2fb
Packit Service 97d2fb
  /* We did it.  */
Packit Service 97d2fb
  return 0;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block,
Packit Service 97d2fb
	     Dwarf_Op **llbuf, size_t *listlen, int sec_index)
Packit Service 97d2fb
{
Packit Service 97d2fb
  /* Empty location expressions don't have any ops to intern.
Packit Service 97d2fb
     Note that synthetic empty_cu doesn't have an associated DWARF dbg.  */
Packit Service 97d2fb
  if (block->length == 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      *listlen = 0;
Packit Service 97d2fb
      return 0;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return __libdw_intern_expression (cu->dbg, cu->dbg->other_byte_order,
Packit Service 97d2fb
				    cu->address_size, (cu->version == 2
Packit Service 97d2fb
						       ? cu->address_size
Packit Service 97d2fb
						       : cu->offset_size),
Packit Service 97d2fb
				    &cu->locs, block,
Packit Service 97d2fb
				    false, false,
Packit Service 97d2fb
				    llbuf, listlen, sec_index);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
int
Packit Service 97d2fb
dwarf_getlocation (Dwarf_Attribute *attr, Dwarf_Op **llbuf, size_t *listlen)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (! attr_ok (attr))
Packit Service 97d2fb
    return -1;
Packit Service 97d2fb
Packit Service 97d2fb
  int result = is_constant_offset (attr, llbuf, listlen);
Packit Service 97d2fb
  if (result != 1)
Packit Service 97d2fb
    return result; /* Either success 0, or -1 to indicate error.  */
Packit Service 97d2fb
Packit Service 97d2fb
  /* If it has a block form, it's a single location expression.
Packit Service 97d2fb
     Except for DW_FORM_data16, which is a 128bit constant.  */
Packit Service 97d2fb
  if (attr->form == DW_FORM_data16)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      __libdw_seterrno (DWARF_E_NO_BLOCK);
Packit Service 97d2fb
      return -1;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  Dwarf_Block block;
Packit Service 97d2fb
  if (INTUSE(dwarf_formblock) (attr, &block) != 0)
Packit Service 97d2fb
    return -1;
Packit Service 97d2fb
Packit Service 97d2fb
  return getlocation (attr->cu, &block, llbuf, listlen, cu_sec_idx (attr->cu));
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Dwarf_Addr
Packit Service 97d2fb
__libdw_cu_base_address (Dwarf_CU *cu)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (cu->base_address == (Dwarf_Addr) -1)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      Dwarf_Addr base;
Packit Service 97d2fb
Packit Service 97d2fb
      /* Fetch the CU's base address.  */
Packit Service 97d2fb
      Dwarf_Die cudie = CUDIE (cu);
Packit Service 97d2fb
Packit Service 97d2fb
      /* Find the base address of the compilation unit.  It will
Packit Service 97d2fb
	 normally be specified by DW_AT_low_pc.  In DWARF-3 draft 4,
Packit Service 97d2fb
	 the base address could be overridden by DW_AT_entry_pc.  It's
Packit Service 97d2fb
	 been removed, but GCC emits DW_AT_entry_pc and not DW_AT_lowpc
Packit Service 97d2fb
	 for compilation units with discontinuous ranges.  */
Packit Service 97d2fb
      Dwarf_Attribute attr_mem;
Packit Service 97d2fb
      if (INTUSE(dwarf_lowpc) (&cudie, &base) != 0
Packit Service 97d2fb
	  && INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (&cudie,
Packit Service 97d2fb
							 DW_AT_entry_pc,
Packit Service 97d2fb
							 &attr_mem),
Packit Service 97d2fb
				     &base) != 0)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* The compiler provided no base address when it should
Packit Service 97d2fb
	     have.  Buggy GCC does this when it used absolute
Packit Service 97d2fb
	     addresses in the location list and no DW_AT_ranges.  */
Packit Service 97d2fb
	   base = 0;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      cu->base_address = base;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return cu->base_address;
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_loc : IDX_debug_loclists);
Packit Service 97d2fb
Packit Service 97d2fb
  Dwarf_Word start_offset;
Packit Service 97d2fb
  if (attr->form == DW_FORM_loclistx)
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_loc
Packit Service 97d2fb
                            ? DWARF_E_NO_DEBUG_LOC
Packit Service 97d2fb
                            : DWARF_E_NO_DEBUG_LOCLISTS);
Packit Service 97d2fb
	  return -1;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      Dwarf_Off loc_base_off = __libdw_cu_locs_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 (loc_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 - loc_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
	       + loc_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 += loc_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_loc
Packit Service 97d2fb
			    ? DWARF_E_NO_DEBUG_LOC
Packit Service 97d2fb
			    : DWARF_E_NO_DEBUG_LOCLISTS),
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
static ptrdiff_t
Packit Service 97d2fb
getlocations_addr (Dwarf_Attribute *attr, ptrdiff_t offset,
Packit Service 97d2fb
		   Dwarf_Addr *basep, Dwarf_Addr *startp, Dwarf_Addr *endp,
Packit Service 97d2fb
		   Dwarf_Addr address, const Elf_Data *locs, Dwarf_Op **expr,
Packit Service 97d2fb
		   size_t *exprlen)
Packit Service 97d2fb
{
Packit Service 97d2fb
  Dwarf_CU *cu = attr->cu;
Packit Service 97d2fb
  Dwarf *dbg = cu->dbg;
Packit Service 97d2fb
  size_t secidx = cu->version < 5 ? IDX_debug_loc : IDX_debug_loclists;
Packit Service 97d2fb
  const unsigned char *readp = locs->d_buf + offset;
Packit Service 97d2fb
  const unsigned char *readendp = locs->d_buf + locs->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: /* got location range. */
Packit Service 97d2fb
      break;
Packit Service 97d2fb
    case 1: /* base address setup. */
Packit Service 97d2fb
      goto next;
Packit Service 97d2fb
    case 2: /* end of loclist */
Packit Service 97d2fb
      return 0;
Packit Service 97d2fb
    default: /* error */
Packit Service 97d2fb
      return -1;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* We have a location expression.  */
Packit Service 97d2fb
  Dwarf_Block block;
Packit Service 97d2fb
  if (secidx == IDX_debug_loc)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (readendp - readp < 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
      block.length = read_2ubyte_unaligned_inc (dbg, readp);
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (readendp - readp < 1)
Packit Service 97d2fb
	goto invalid;
Packit Service 97d2fb
      get_uleb128 (block.length, readp, readendp);
Packit Service 97d2fb
    }
Packit Service 97d2fb
  block.data = (unsigned char *) readp;
Packit Service 97d2fb
  if (readendp - readp < (ptrdiff_t) block.length)
Packit Service 97d2fb
    goto invalid;
Packit Service 97d2fb
  readp += block.length;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Note these addresses include any base (if necessary) already.  */
Packit Service 97d2fb
  *startp = begin;
Packit Service 97d2fb
  *endp = end;
Packit Service 97d2fb
Packit Service 97d2fb
  /* If address is minus one we want them all, otherwise only matching.  */
Packit Service 97d2fb
  if (address != (Dwarf_Word) -1 && (address < *startp || address >= *endp))
Packit Service 97d2fb
    goto next;
Packit Service 97d2fb
Packit Service 97d2fb
  if (getlocation (cu, &block, expr, exprlen, secidx) != 0)
Packit Service 97d2fb
    return -1;
Packit Service 97d2fb
Packit Service 97d2fb
  return readp - (unsigned char *) locs->d_buf;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
int
Packit Service 97d2fb
dwarf_getlocation_addr (Dwarf_Attribute *attr, Dwarf_Addr address,
Packit Service 97d2fb
			Dwarf_Op **llbufs, size_t *listlens, size_t maxlocs)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (! attr_ok (attr))
Packit Service 97d2fb
    return -1;
Packit Service 97d2fb
Packit Service 97d2fb
  if (llbufs == NULL)
Packit Service 97d2fb
    maxlocs = SIZE_MAX;
Packit Service 97d2fb
Packit Service 97d2fb
  /* If it has a block form, it's a single location expression.
Packit Service 97d2fb
     Except for DW_FORM_data16, which is a 128bit constant.  */
Packit Service 97d2fb
  Dwarf_Block block;
Packit Service 97d2fb
  if (attr->form != DW_FORM_data16
Packit Service 97d2fb
      && INTUSE(dwarf_formblock) (attr, &block) == 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (maxlocs == 0)
Packit Service 97d2fb
	return 0;
Packit Service 97d2fb
      if (llbufs != NULL &&
Packit Service 97d2fb
	  getlocation (attr->cu, &block, &llbufs[0], &listlens[0],
Packit Service 97d2fb
		       cu_sec_idx (attr->cu)) != 0)
Packit Service 97d2fb
	return -1;
Packit Service 97d2fb
      return listlens[0] == 0 ? 0 : 1;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (attr->form != DW_FORM_data16)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      int error = INTUSE(dwarf_errno) ();
Packit Service 97d2fb
      if (unlikely (error != DWARF_E_NO_BLOCK))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  __libdw_seterrno (error);
Packit Service 97d2fb
	  return -1;
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* If is_constant_offset is successful, we are done with 1 result.  */
Packit Service 97d2fb
  int result = is_constant_offset (attr, llbufs, listlens);
Packit Service 97d2fb
  if (result != 1)
Packit Service 97d2fb
    return result ?: 1;
Packit Service 97d2fb
Packit Service 97d2fb
  Dwarf_Addr base, start, end;
Packit Service 97d2fb
  Dwarf_Op *expr;
Packit Service 97d2fb
  size_t expr_len;
Packit Service 97d2fb
  ptrdiff_t off = 0;
Packit Service 97d2fb
  size_t got = 0;
Packit Service 97d2fb
Packit Service 97d2fb
  /* This is a true loclistptr, fetch the initial base address and offset.  */
Packit Service 97d2fb
  base = __libdw_cu_base_address (attr->cu);
Packit Service 97d2fb
  if (base == (Dwarf_Addr) -1)
Packit Service 97d2fb
    return -1;
Packit Service 97d2fb
Packit Service 97d2fb
  if (initial_offset (attr, &off) != 0)
Packit Service 97d2fb
    return -1;
Packit Service 97d2fb
Packit Service 97d2fb
  size_t secidx = attr->cu->version < 5 ? IDX_debug_loc : IDX_debug_loclists;
Packit Service 97d2fb
  const Elf_Data *d = attr->cu->dbg->sectiondata[secidx];
Packit Service 97d2fb
Packit Service 97d2fb
  while (got < maxlocs
Packit Service 97d2fb
         && (off = getlocations_addr (attr, off, &base, &start, &end,
Packit Service 97d2fb
				      address, d, &expr, &expr_len)) > 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* This one matches the address.  */
Packit Service 97d2fb
      if (llbufs != NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  llbufs[got] = expr;
Packit Service 97d2fb
	  listlens[got] = expr_len;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      ++got;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* We might stop early, so off can be zero or positive on success.  */
Packit Service 97d2fb
  if (off < 0)
Packit Service 97d2fb
    return -1;
Packit Service 97d2fb
Packit Service 97d2fb
  return got;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
ptrdiff_t
Packit Service 97d2fb
dwarf_getlocations (Dwarf_Attribute *attr, ptrdiff_t offset, Dwarf_Addr *basep,
Packit Service 97d2fb
		    Dwarf_Addr *startp, Dwarf_Addr *endp, Dwarf_Op **expr,
Packit Service 97d2fb
		    size_t *exprlen)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (! attr_ok (attr))
Packit Service 97d2fb
    return -1;
Packit Service 97d2fb
Packit Service 97d2fb
  /* 1 is an invalid offset, meaning no more locations. */
Packit Service 97d2fb
  if (offset == 1)
Packit Service 97d2fb
    return 0;
Packit Service 97d2fb
Packit Service 97d2fb
  if (offset == 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* If it has a block form, it's a single location expression.
Packit Service 97d2fb
	 Except for DW_FORM_data16, which is a 128bit constant.  */
Packit Service 97d2fb
      Dwarf_Block block;
Packit Service 97d2fb
      if (attr->form != DW_FORM_data16
Packit Service 97d2fb
	  && INTUSE(dwarf_formblock) (attr, &block) == 0)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  if (getlocation (attr->cu, &block, expr, exprlen,
Packit Service 97d2fb
			   cu_sec_idx (attr->cu)) != 0)
Packit Service 97d2fb
	    return -1;
Packit Service 97d2fb
Packit Service 97d2fb
	  /* This is the one and only location covering everything. */
Packit Service 97d2fb
	  *startp = 0;
Packit Service 97d2fb
	  *endp = -1;
Packit Service 97d2fb
	  return 1;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      if (attr->form != DW_FORM_data16)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  int error = INTUSE(dwarf_errno) ();
Packit Service 97d2fb
	  if (unlikely (error != DWARF_E_NO_BLOCK))
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      __libdw_seterrno (error);
Packit Service 97d2fb
	      return -1;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      int result = is_constant_offset (attr, expr, exprlen);
Packit Service 97d2fb
      if (result != 1)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  if (result == 0)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      /* This is the one and only location covering everything. */
Packit Service 97d2fb
	      *startp = 0;
Packit Service 97d2fb
	      *endp = -1;
Packit Service 97d2fb
	      return 1;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	  return result; /* Something bad, dwarf_errno has been set.  */
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* We must be looking at a true loclistptr, fetch the initial
Packit Service 97d2fb
	 base address and offset.  */
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
Packit Service 97d2fb
  size_t secidx = attr->cu->version < 5 ? IDX_debug_loc : IDX_debug_loclists;
Packit Service 97d2fb
  const Elf_Data *d = attr->cu->dbg->sectiondata[secidx];
Packit Service 97d2fb
Packit Service 97d2fb
  return getlocations_addr (attr, offset, basep, startp, endp,
Packit Service 97d2fb
			    (Dwarf_Word) -1, d, expr, exprlen);
Packit Service 97d2fb
}