Dwarf_Die *
dwarf_cu_die (Dwarf_CU *cu, Dwarf_Die *result, Dwarf_Half *versionp,
              Dwarf_Off *abbrev_offsetp, uint8_t *address_sizep,
              uint8_t *offset_sizep, uint64_t *type_signaturep,
              Dwarf_Off *type_offsetp)
{
    if (cu == NULL)
        return NULL;

    *result = CUDIE (cu);

    if (versionp != NULL)
        *versionp = cu->version;
    if (abbrev_offsetp != NULL)
        *abbrev_offsetp = cu->orig_abbrev_offset;
    if (address_sizep != NULL)
        *address_sizep = cu->address_size;
    if (offset_sizep != NULL)
        *offset_sizep = cu->offset_size;
    if (type_signaturep != NULL)
        *type_signaturep = cu->type_sig8;
    if (type_offsetp != NULL)
        *type_offsetp = cu->type_offset;

    return result;
}
int
dwarf_entry_breakpoints (Dwarf_Die *die, Dwarf_Addr **bkpts)
{
  int nbkpts = 0;
  *bkpts = NULL;

  /* Fetch the CU's line records to look for this DIE's addresses.  */
  Dwarf_Die cudie = CUDIE (die->cu);
  Dwarf_Lines *lines;
  size_t nlines;
  if (INTUSE(dwarf_getsrclines) (&cudie, &lines, &nlines) < 0)
    {
      int error = INTUSE (dwarf_errno) ();
      if (error == 0)		/* CU has no DW_AT_stmt_list.  */
	return entrypc_bkpt (die, bkpts, &nbkpts);
      __libdw_seterrno (error);
      return -1;
    }

  /* Search each contiguous address range for DWARF prologue_end markers.  */

  Dwarf_Addr base;
  Dwarf_Addr begin;
  Dwarf_Addr end;
  ptrdiff_t offset = INTUSE(dwarf_ranges) (die, 0, &base, &begin, &end);
  if (offset < 0)
    return -1;

  /* Most often there is a single contiguous PC range for the DIE.  */
  if (offset == 1)
    return search_range (begin, end, true, true, lines, nlines, bkpts, &nbkpts)
        ?: entrypc_bkpt (die, bkpts, &nbkpts);

  Dwarf_Addr lowpc = (Dwarf_Addr) -1l;
  Dwarf_Addr highpc = (Dwarf_Addr) -1l;
  while (offset > 0)
    {
      /* We have an address range entry.  */
      if (search_range (begin, end, true, false,
                        lines, nlines, bkpts, &nbkpts) < 0)
	return -1;

      if (begin < lowpc)
	{
	  lowpc = begin;
	  highpc = end;
	}

      offset = INTUSE(dwarf_ranges) (die, offset, &base, &begin, &end);
    }

  /* If we didn't find any proper DWARF markers, then look in the
     lowest-addressed range for an ad hoc marker.  Failing that,
     fall back to just using the entrypc value.  */
  return (nbkpts
	  ?: (lowpc == (Dwarf_Addr) -1l ? 0
	      : search_range (lowpc, highpc, false, true,
	                      lines, nlines, bkpts, &nbkpts))
	  ?: entrypc_bkpt (die, bkpts, &nbkpts));
}
int
dwarf_getlocation_implicit_value (Dwarf_Attribute *attr, const Dwarf_Op *op,
				  Dwarf_Block *return_block)
{
  if (attr == NULL)
    return -1;

  struct loc_block_s fake = { .addr = (void *) op };
  struct loc_block_s **found = tfind (&fake, &attr->cu->locs, loc_compare);
  if (unlikely (found == NULL))
    {
      __libdw_seterrno (DWARF_E_NO_BLOCK);
      return -1;
    }

  return_block->length = (*found)->length;
  return_block->data = (*found)->data;
  return 0;
}

/* DW_AT_data_member_location can be a constant as well as a loclistptr.
   Only data[48] indicate a loclistptr.  */
static int
check_constant_offset (Dwarf_Attribute *attr,
		       Dwarf_Op **llbuf, size_t *listlen)
{
  if (attr->code != DW_AT_data_member_location)
    return 1;

  switch (attr->form)
    {
      /* Punt for any non-constant form.  */
    default:
      return 1;

    case DW_FORM_data1:
    case DW_FORM_data2:
    case DW_FORM_data4:
    case DW_FORM_data8:
    case DW_FORM_sdata:
    case DW_FORM_udata:
      break;
    }

  /* Check whether we already cached this location.  */
  struct loc_s fake = { .addr = attr->valp };
  struct loc_s **found = tfind (&fake, &attr->cu->locs, loc_compare);

  if (found == NULL)
    {
      Dwarf_Word offset;
      if (INTUSE(dwarf_formudata) (attr, &offset) != 0)
	return -1;

      Dwarf_Op *result = libdw_alloc (attr->cu->dbg,
				      Dwarf_Op, sizeof (Dwarf_Op), 1);

      result->atom = DW_OP_plus_uconst;
      result->number = offset;
      result->number2 = 0;
      result->offset = 0;

      /* Insert a record in the search tree so we can find it again later.  */
      struct loc_s *newp = libdw_alloc (attr->cu->dbg,
					struct loc_s, sizeof (struct loc_s),
					1);
      newp->addr = attr->valp;
      newp->loc = result;
      newp->nloc = 1;

      found = tsearch (newp, &attr->cu->locs, loc_compare);
    }

  assert ((*found)->nloc == 1);

  if (llbuf != NULL)
    {
      *llbuf = (*found)->loc;
      *listlen = 1;
    }

  return 0;
}

int
internal_function
__libdw_intern_expression (Dwarf *dbg, bool other_byte_order,
			   unsigned int address_size, unsigned int ref_size,
			   void **cache, const Dwarf_Block *block,
			   bool cfap, bool valuep,
			   Dwarf_Op **llbuf, size_t *listlen, int sec_index)
{
  /* Empty location expressions don't have any ops to intern.  */
  if (block->length == 0)
    {
      *listlen = 0;
      return 0;
    }

  /* Check whether we already looked at this list.  */
  struct loc_s fake = { .addr = block->data };
  struct loc_s **found = tfind (&fake, cache, loc_compare);
  if (found != NULL)
    {
      /* We already saw it.  */
      *llbuf = (*found)->loc;
      *listlen = (*found)->nloc;

      if (valuep)
	{
	  assert (*listlen > 1);
	  assert ((*llbuf)[*listlen - 1].atom == DW_OP_stack_value);
	}

      return 0;
    }

  const unsigned char *data = block->data;
  const unsigned char *const end_data = data + block->length;

  const struct { bool other_byte_order; } bo = { other_byte_order };

  struct loclist *loclist = NULL;
  unsigned int n = 0;

  /* Stack allocate at most this many locs.  */
#define MAX_STACK_LOCS 256
  struct loclist stack_locs[MAX_STACK_LOCS];
#define NEW_LOC() ({ struct loclist *ll;			\
		     ll = (likely (n < MAX_STACK_LOCS)		\
			   ? &stack_locs[n]			\
			   : malloc (sizeof (struct loclist)));	\
		     if (unlikely (ll == NULL))			\
		       goto nomem;				\
		     n++;					\
		     ll->next = loclist;			\
		     loclist = ll;				\
		     ll; })

  if (cfap)
    {
      /* Synthesize the operation to push the CFA before the expression.  */
      struct loclist *newloc = NEW_LOC ();
      newloc->atom = DW_OP_call_frame_cfa;
      newloc->number = 0;
      newloc->number2 = 0;
      newloc->offset = -1;
    }

  /* Decode the opcodes.  It is possible in some situations to have a
     block of size zero.  */
  while (data < end_data)
    {
      struct loclist *newloc;
      newloc = NEW_LOC ();
      newloc->number = 0;
      newloc->number2 = 0;
      newloc->offset = data - block->data;

      switch ((newloc->atom = *data++))
	{
	case DW_OP_addr:
	  /* Address, depends on address size of CU.  */
	  if (dbg == NULL)
	    {
	      // XXX relocation?
	      if (address_size == 4)
		{
		  if (unlikely (data + 4 > end_data))
		    goto invalid;
		  else
		    newloc->number = read_4ubyte_unaligned_inc (&bo, data);
		}
	      else
		{
		  if (unlikely (data + 8 > end_data))
		    goto invalid;
		  else
		    newloc->number = read_8ubyte_unaligned_inc (&bo, data);
		}
	    }
	  else if (__libdw_read_address_inc (dbg, sec_index, &data,
					     address_size, &newloc->number))
	    goto invalid;
	  break;

	case DW_OP_call_ref:
	  /* DW_FORM_ref_addr, depends on offset size of CU.  */
	  if (dbg == NULL || __libdw_read_offset_inc (dbg, sec_index, &data,
						      ref_size,
						      &newloc->number,
						      IDX_debug_info, 0))
	    goto invalid;
	  break;

	case DW_OP_deref:
	case DW_OP_dup:
	case DW_OP_drop:
	case DW_OP_over:
	case DW_OP_swap:
	case DW_OP_rot:
	case DW_OP_xderef:
	case DW_OP_abs:
	case DW_OP_and:
	case DW_OP_div:
	case DW_OP_minus:
	case DW_OP_mod:
	case DW_OP_mul:
	case DW_OP_neg:
	case DW_OP_not:
	case DW_OP_or:
	case DW_OP_plus:
	case DW_OP_shl:
	case DW_OP_shr:
	case DW_OP_shra:
	case DW_OP_xor:
	case DW_OP_eq:
	case DW_OP_ge:
	case DW_OP_gt:
	case DW_OP_le:
	case DW_OP_lt:
	case DW_OP_ne:
	case DW_OP_lit0 ... DW_OP_lit31:
	case DW_OP_reg0 ... DW_OP_reg31:
	case DW_OP_nop:
	case DW_OP_push_object_address:
	case DW_OP_call_frame_cfa:
	case DW_OP_form_tls_address:
	case DW_OP_GNU_push_tls_address:
	case DW_OP_stack_value:
	  /* No operand.  */
	  break;

	case DW_OP_const1u:
	case DW_OP_pick:
	case DW_OP_deref_size:
	case DW_OP_xderef_size:
	  if (unlikely (data >= end_data))
	    {
	    invalid:
	      __libdw_seterrno (DWARF_E_INVALID_DWARF);
	    returnmem:
	      /* Free any dynamicly allocated loclists, if any.  */
	      while (n > MAX_STACK_LOCS)
		{
		  struct loclist *loc = loclist;
		  loclist = loc->next;
		  free (loc);
		  n--;
		}
	      return -1;
	    }

	  newloc->number = *data++;
	  break;

	case DW_OP_const1s:
	  if (unlikely (data >= end_data))
	    goto invalid;

	  newloc->number = *((int8_t *) data);
	  ++data;
	  break;

	case DW_OP_const2u:
	  if (unlikely (data + 2 > end_data))
	    goto invalid;

	  newloc->number = read_2ubyte_unaligned_inc (&bo, data);
	  break;

	case DW_OP_const2s:
	case DW_OP_skip:
	case DW_OP_bra:
	case DW_OP_call2:
	  if (unlikely (data + 2 > end_data))
	    goto invalid;

	  newloc->number = read_2sbyte_unaligned_inc (&bo, data);
	  break;

	case DW_OP_const4u:
	  if (unlikely (data + 4 > end_data))
	    goto invalid;

	  newloc->number = read_4ubyte_unaligned_inc (&bo, data);
	  break;

	case DW_OP_const4s:
	case DW_OP_call4:
	case DW_OP_GNU_parameter_ref:
	  if (unlikely (data + 4 > end_data))
	    goto invalid;

	  newloc->number = read_4sbyte_unaligned_inc (&bo, data);
	  break;

	case DW_OP_const8u:
	  if (unlikely (data + 8 > end_data))
	    goto invalid;

	  newloc->number = read_8ubyte_unaligned_inc (&bo, data);
	  break;

	case DW_OP_const8s:
	  if (unlikely (data + 8 > end_data))
	    goto invalid;

	  newloc->number = read_8sbyte_unaligned_inc (&bo, data);
	  break;

	case DW_OP_constu:
	case DW_OP_plus_uconst:
	case DW_OP_regx:
	case DW_OP_piece:
	case DW_OP_GNU_convert:
	case DW_OP_GNU_reinterpret:
	  get_uleb128 (newloc->number, data, end_data);
	  break;

	case DW_OP_consts:
	case DW_OP_breg0 ... DW_OP_breg31:
	case DW_OP_fbreg:
	  get_sleb128 (newloc->number, data, end_data);
	  break;

	case DW_OP_bregx:
	  get_uleb128 (newloc->number, data, end_data);
	  if (unlikely (data >= end_data))
	    goto invalid;
	  get_sleb128 (newloc->number2, data, end_data);
	  break;

	case DW_OP_bit_piece:
	case DW_OP_GNU_regval_type:
	  get_uleb128 (newloc->number, data, end_data);
	  if (unlikely (data >= end_data))
	    goto invalid;
	  get_uleb128 (newloc->number2, data, end_data);
	  break;

	case DW_OP_implicit_value:
	case DW_OP_GNU_entry_value:
	  /* This cannot be used in a CFI expression.  */
	  if (unlikely (dbg == NULL))
	    goto invalid;

	  /* start of block inc. len.  */
	  newloc->number2 = (Dwarf_Word) (uintptr_t) data;
	  get_uleb128 (newloc->number, data, end_data); /* Block length.  */
	  if (unlikely ((Dwarf_Word) (end_data - data) < newloc->number))
	    goto invalid;
	  data += newloc->number;		/* Skip the block.  */
	  break;

	case DW_OP_GNU_implicit_pointer:
	  /* DW_FORM_ref_addr, depends on offset size of CU.  */
	  if (dbg == NULL || __libdw_read_offset_inc (dbg, sec_index, &data,
						      ref_size,
						      &newloc->number,
						      IDX_debug_info, 0))
	    goto invalid;
	  if (unlikely (data >= end_data))
	    goto invalid;
	  get_uleb128 (newloc->number2, data, end_data); /* Byte offset.  */
	  break;

	case DW_OP_GNU_deref_type:
	  if (unlikely (data + 1 >= end_data))
	    goto invalid;
	  newloc->number = *data++;
	  get_uleb128 (newloc->number2, data, end_data);
	  break;

	case DW_OP_GNU_const_type:
	  {
	    size_t size;
	    get_uleb128 (newloc->number, data, end_data);
	    if (unlikely (data >= end_data))
	      goto invalid;

	    /* start of block inc. len.  */
	    newloc->number2 = (Dwarf_Word) (uintptr_t) data;
	    size = *data++;
	    if (unlikely ((Dwarf_Word) (end_data - data) < size))
	      goto invalid;
	    data += size;		/* Skip the block.  */
	  }
	  break;

	default:
	  goto invalid;
	}
    }

  if (unlikely (n == 0))
    {
      /* This is not allowed.
	 It would mean an empty location expression, which we handled
	 already as a special case above.  */
      goto invalid;
    }

  if (valuep)
    {
      struct loclist *newloc = NEW_LOC ();
      newloc->atom = DW_OP_stack_value;
      newloc->number = 0;
      newloc->number2 = 0;
      newloc->offset = data - block->data;
    }

  /* Allocate the array.  */
  Dwarf_Op *result;
  if (dbg != NULL)
    result = libdw_alloc (dbg, Dwarf_Op, sizeof (Dwarf_Op), n);
  else
    {
      result = malloc (sizeof *result * n);
      if (result == NULL)
	{
	nomem:
	  __libdw_seterrno (DWARF_E_NOMEM);
	  goto returnmem;
	}
    }

  /* Store the result.  */
  *llbuf = result;
  *listlen = n;

  do
    {
      /* We populate the array from the back since the list is backwards.  */
      --n;
      result[n].atom = loclist->atom;
      result[n].number = loclist->number;
      result[n].number2 = loclist->number2;
      result[n].offset = loclist->offset;

      if (result[n].atom == DW_OP_implicit_value)
	store_implicit_value (dbg, cache, &result[n]);

      struct loclist *loc = loclist;
      loclist = loclist->next;
      if (unlikely (n + 1 > MAX_STACK_LOCS))
	free (loc);
    }
  while (n > 0);

  /* Insert a record in the search tree so that we can find it again later.  */
  struct loc_s *newp;
  if (dbg != NULL)
    newp = libdw_alloc (dbg, struct loc_s, sizeof (struct loc_s), 1);
  else
    {
      newp = malloc (sizeof *newp);
      if (newp == NULL)
	{
	  free (result);
	  goto nomem;
	}
    }

  newp->addr = block->data;
  newp->loc = result;
  newp->nloc = *listlen;
  (void) tsearch (newp, cache, loc_compare);

  /* We did it.  */
  return 0;
}

static int
getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block,
	     Dwarf_Op **llbuf, size_t *listlen, int sec_index)
{
  /* Empty location expressions don't have any ops to intern.
     Note that synthetic empty_cu doesn't have an associated DWARF dbg.  */
  if (block->length == 0)
    {
      *listlen = 0;
      return 0;
    }

  return __libdw_intern_expression (cu->dbg, cu->dbg->other_byte_order,
				    cu->address_size, (cu->version == 2
						       ? cu->address_size
						       : cu->offset_size),
				    &cu->locs, block,
				    false, false,
				    llbuf, listlen, sec_index);
}

int
dwarf_getlocation (Dwarf_Attribute *attr, Dwarf_Op **llbuf, size_t *listlen)
{
  if (! attr_ok (attr))
    return -1;

  int result = check_constant_offset (attr, llbuf, listlen);
  if (result != 1)
    return result;

  /* If it has a block form, it's a single location expression.  */
  Dwarf_Block block;
  if (INTUSE(dwarf_formblock) (attr, &block) != 0)
    return -1;

  return getlocation (attr->cu, &block, llbuf, listlen, cu_sec_idx (attr->cu));
}

static int
attr_base_address (Dwarf_Attribute *attr, Dwarf_Addr *basep)
{
  /* Fetch the CU's base address.  */
  Dwarf_Die cudie = CUDIE (attr->cu);

  /* Find the base address of the compilation unit.  It will
     normally be specified by DW_AT_low_pc.  In DWARF-3 draft 4,
     the base address could be overridden by DW_AT_entry_pc.  It's
     been removed, but GCC emits DW_AT_entry_pc and not DW_AT_lowpc
     for compilation units with discontinuous ranges.  */
  Dwarf_Attribute attr_mem;
  if (unlikely (INTUSE(dwarf_lowpc) (&cudie, basep) != 0)
      && INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (&cudie,
						     DW_AT_entry_pc,
						     &attr_mem),
				 basep) != 0)
    {
      if (INTUSE(dwarf_errno) () != 0)
	return -1;

      /* The compiler provided no base address when it should
	 have.  Buggy GCC does this when it used absolute
	 addresses in the location list and no DW_AT_ranges.  */
      *basep = 0;
    }
  return 0;
}
static int
getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block,
	     Dwarf_Op **llbuf, size_t *listlen)
{
  Dwarf *dbg = cu->dbg;

  /* Check whether we already looked at this list.  */
  struct loc_s fake = { .addr = block->data };
  struct loc_s **found = tfind (&fake, &cu->locs, loc_compare);
  if (found != NULL)
    {
      /* We already saw it.  */
      *llbuf = (*found)->loc;
      *listlen = (*found)->nloc;

      return 0;
    }

  const unsigned char *data = block->data;
  const unsigned char *const end_data = data + block->length;

  struct loclist *loclist = NULL;
  unsigned int n = 0;
  /* Decode the opcodes.  It is possible in some situations to have a
     block of size zero.  */
  while (data < end_data)
    {
      struct loclist *newloc;
      newloc = (struct loclist *) alloca (sizeof (struct loclist));
      newloc->number = 0;
      newloc->number2 = 0;
      newloc->offset = data - block->data;
      newloc->next = loclist;
      loclist = newloc;
      ++n;

      switch ((newloc->atom = *data++))
	{
	case DW_OP_addr:
	  /* Address, depends on address size of CU.  */
	  if (cu->address_size == 4)
	    {
	      if (unlikely (data + 4 > end_data))
		{
		invalid:
		  __libdw_seterrno (DWARF_E_INVALID_DWARF);
		  return -1;
		}

	      newloc->number = read_4ubyte_unaligned_inc (dbg, data);
	    }
	  else
	    {
	      if (unlikely (data + 8 > end_data))
		goto invalid;

	      newloc->number = read_8ubyte_unaligned_inc (dbg, data);
	    }
	  break;

	case DW_OP_deref:
	case DW_OP_dup:
	case DW_OP_drop:
	case DW_OP_over:
	case DW_OP_swap:
	case DW_OP_rot:
	case DW_OP_xderef:
	case DW_OP_abs:
	case DW_OP_and:
	case DW_OP_div:
	case DW_OP_minus:
	case DW_OP_mod:
	case DW_OP_mul:
	case DW_OP_neg:
	case DW_OP_not:
	case DW_OP_or:
	case DW_OP_plus:
	case DW_OP_shl:
	case DW_OP_shr:
	case DW_OP_shra:
	case DW_OP_xor:
	case DW_OP_eq:
	case DW_OP_ge:
	case DW_OP_gt:
	case DW_OP_le:
	case DW_OP_lt:
	case DW_OP_ne:
	case DW_OP_lit0 ... DW_OP_lit31:
	case DW_OP_reg0 ... DW_OP_reg31:
	case DW_OP_nop:
	case DW_OP_push_object_address:
	case DW_OP_call_ref:
	  /* No operand.  */
	  break;

	case DW_OP_const1u:
	case DW_OP_pick:
	case DW_OP_deref_size:
	case DW_OP_xderef_size:
	  if (unlikely (data >= end_data))
	    goto invalid;

	  newloc->number = *data++;
	  break;

	case DW_OP_const1s:
	  if (unlikely (data >= end_data))
	    goto invalid;

	  newloc->number = *((int8_t *) data);
	  ++data;
	  break;

	case DW_OP_const2u:
	  if (unlikely (data + 2 > end_data))
	    goto invalid;

	  newloc->number = read_2ubyte_unaligned_inc (dbg, data);
	  break;

	case DW_OP_const2s:
	case DW_OP_skip:
	case DW_OP_bra:
	case DW_OP_call2:
	  if (unlikely (data + 2 > end_data))
	    goto invalid;

	  newloc->number = read_2sbyte_unaligned_inc (dbg, data);
	  break;

	case DW_OP_const4u:
	  if (unlikely (data + 4 > end_data))
	    goto invalid;

	  newloc->number = read_4ubyte_unaligned_inc (dbg, data);
	  break;

	case DW_OP_const4s:
	case DW_OP_call4:
	  if (unlikely (data + 4 > end_data))
	    goto invalid;

	  newloc->number = read_4sbyte_unaligned_inc (dbg, data);
	  break;

	case DW_OP_const8u:
	  if (unlikely (data + 8 > end_data))
	    goto invalid;

	  newloc->number = read_8ubyte_unaligned_inc (dbg, data);
	  break;

	case DW_OP_const8s:
	  if (unlikely (data + 8 > end_data))
	    goto invalid;

	  newloc->number = read_8sbyte_unaligned_inc (dbg, data);
	  break;

	case DW_OP_constu:
	case DW_OP_plus_uconst:
	case DW_OP_regx:
	case DW_OP_piece:
	  /* XXX Check size.  */
	  get_uleb128 (newloc->number, data);
	  break;

	case DW_OP_consts:
	case DW_OP_breg0 ... DW_OP_breg31:
	case DW_OP_fbreg:
	  /* XXX Check size.  */
	  get_sleb128 (newloc->number, data);
	  break;

	case DW_OP_bregx:
	  /* XXX Check size.  */
	  get_uleb128 (newloc->number, data);
	  get_sleb128 (newloc->number2, data);
	  break;

	default:
	  goto invalid;
	}
    }

  if (unlikely (n == 0))
    {
      /* This is not allowed.

	 XXX Is it?  */
      goto invalid;
    }

  /* Allocate the array.  */
  Dwarf_Op *result = libdw_alloc (dbg, Dwarf_Op, sizeof (Dwarf_Op), n);

  /* Store the result.  */
  *llbuf = result;
  *listlen = n;

  do
    {
      /* We populate the array from the back since the list is
         backwards.  */
      --n;
      result[n].atom = loclist->atom;
      result[n].number = loclist->number;
      result[n].number2 = loclist->number2;
      result[n].offset = loclist->offset;

      loclist = loclist->next;
    }
  while (n > 0);

  /* Insert a record in the search tree so that we can find it again
     later.  */
  struct loc_s *newp = libdw_alloc (dbg, struct loc_s, sizeof (struct loc_s),
				    1);
  newp->addr = block->data;
  newp->loc = result;
  newp->nloc = *listlen;
  (void) tsearch (newp, &cu->locs, loc_compare);

  /* We did it.  */
  return 0;
}

int
dwarf_getlocation (attr, llbuf, listlen)
     Dwarf_Attribute *attr;
     Dwarf_Op **llbuf;
     size_t *listlen;
{
  if (! attr_ok (attr))
    return -1;

  /* If it has a block form, it's a single location expression.  */
  Dwarf_Block block;
  if (INTUSE(dwarf_formblock) (attr, &block) != 0)
    return -1;

  return getlocation (attr->cu, &block, llbuf, listlen);
}

int
dwarf_getlocation_addr (attr, address, llbufs, listlens, maxlocs)
     Dwarf_Attribute *attr;
     Dwarf_Addr address;
     Dwarf_Op **llbufs;
     size_t *listlens;
     size_t maxlocs;
{
  if (! attr_ok (attr))
    return -1;

  if (llbufs == NULL)
    maxlocs = SIZE_MAX;

  /* If it has a block form, it's a single location expression.  */
  Dwarf_Block block;
  if (INTUSE(dwarf_formblock) (attr, &block) == 0)
    {
      if (maxlocs == 0)
	return 0;
      if (llbufs != NULL &&
	  getlocation (attr->cu, &block, &llbufs[0], &listlens[0]) != 0)
	return -1;
      return listlens[0] == 0 ? 0 : 1;
    }

  int error = INTUSE(dwarf_errno) ();
  if (unlikely (error != DWARF_E_NO_BLOCK))
    {
      __libdw_seterrno (error);
      return -1;
    }

  /* Must have the form data4 or data8 which act as an offset.  */
  Dwarf_Word offset;
  if (unlikely (INTUSE(dwarf_formudata) (attr, &offset) != 0))
    return -1;

  const Elf_Data *d = attr->cu->dbg->sectiondata[IDX_debug_loc];
  if (unlikely (d == NULL))
    {
      __libdw_seterrno (DWARF_E_NO_LOCLIST);
      return -1;
    }

  Dwarf_Addr base = (Dwarf_Addr) -1;
  unsigned char *readp = d->d_buf + offset;
  size_t got = 0;
  while (got < maxlocs)
    {
      if ((unsigned char *) d->d_buf + d->d_size - readp
	  < attr->cu->address_size * 2)
	{
	invalid:
	  __libdw_seterrno (DWARF_E_INVALID_DWARF);
	  return -1;
	}

      Dwarf_Addr begin;
      Dwarf_Addr end;
      if (attr->cu->address_size == 8)
	{
	  begin = read_8ubyte_unaligned_inc (attr->cu->dbg, readp);
	  end = read_8ubyte_unaligned_inc (attr->cu->dbg, readp);

	  if (begin == (Elf64_Addr) -1l) /* Base address entry.  */
	    {
	      base = end;
	      if (unlikely (base == (Dwarf_Addr) -1))
		goto invalid;
	      continue;
	    }
	}
      else
	{
	  begin = read_4ubyte_unaligned_inc (attr->cu->dbg, readp);
	  end = read_4ubyte_unaligned_inc (attr->cu->dbg, readp);

	  if (begin == (Elf32_Addr) -1) /* Base address entry.  */
	    {
	      base = end;
	      continue;
	    }
	}

      if (begin == 0 && end == 0) /* End of list entry.  */
	break;

      if ((unsigned char *) d->d_buf + d->d_size - readp < 2)
	goto invalid;

      /* We have a location expression.  */
      block.length = read_2ubyte_unaligned_inc (attr->cu->dbg, readp);
      block.data = readp;
      if ((unsigned char *) d->d_buf + d->d_size - readp
	  < (ptrdiff_t) block.length)
	goto invalid;
      readp += block.length;

      if (base == (Dwarf_Addr) -1)
	{
	  /* Fetch the CU's base address.  */
	  Dwarf_Die cudie = CUDIE (attr->cu);

	  /* Find the base address of the compilation unit.  It will
	     normally be specified by DW_AT_low_pc.  In DWARF-3 draft 4,
	     the base address could be overridden by DW_AT_entry_pc.  It's
	     been removed, but GCC emits DW_AT_entry_pc and not DW_AT_lowpc
	     for compilation units with discontinuous ranges.  */
	  Dwarf_Attribute attr_mem;
	  if (unlikely (INTUSE(dwarf_lowpc) (&cudie, &base) != 0)
	      && INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (&cudie,
							     DW_AT_entry_pc,
							     &attr_mem),
					 &base) != 0)
	    {
	      if (INTUSE(dwarf_errno) () != 0)
		return -1;

	      /* The compiler provided no base address when it should
		 have.  Buggy GCC does this when it used absolute
		 addresses in the location list and no DW_AT_ranges.  */
	      base = 0;
	    }
	}

      if (address >= base + begin && address < base + end)
	{
	  /* This one matches the address.  */
	  if (llbufs != NULL
	      && unlikely (getlocation (attr->cu, &block,
					&llbufs[got], &listlens[got]) != 0))
	    return -1;
	  ++got;
	}
    }

  return got;
}
Beispiel #5
0
/* Find the containing CU's files.  */
static int
getfiles (Dwarf_Die *die, Dwarf_Files **files)
{
  return INTUSE(dwarf_getsrcfiles) (&CUDIE (die->cu), files, NULL);
}
Beispiel #6
0
ptrdiff_t
dwarf_ranges (Dwarf_Die *die, ptrdiff_t offset, Dwarf_Addr *basep,
	      Dwarf_Addr *startp, Dwarf_Addr *endp)
{
  if (die == NULL)
    return -1;

  if (offset == 0
      /* Usually there is a single contiguous range.  */
      && INTUSE(dwarf_highpc) (die, endp) == 0
      && INTUSE(dwarf_lowpc) (die, startp) == 0)
    /* A offset into .debug_ranges will never be 1, it must be at least a
       multiple of 4.  So we can return 1 as a special case value to mark
       there are no ranges to look for on the next call.  */
    return 1;

  if (offset == 1)
    return 0;

  /* We have to look for a noncontiguous range.  */

  const Elf_Data *d = die->cu->dbg->sectiondata[IDX_debug_ranges];
  if (d == NULL && offset != 0)
    {
      __libdw_seterrno (DWARF_E_NO_DEBUG_RANGES);
      return -1;
    }

  unsigned char *readp;
  unsigned char *readendp;
  if (offset == 0)
    {
      Dwarf_Attribute attr_mem;
      Dwarf_Attribute *attr = INTUSE(dwarf_attr) (die, DW_AT_ranges,
						  &attr_mem);
      if (attr == NULL)
	/* No PC attributes in this DIE at all, so an empty range list.  */
	return 0;

      Dwarf_Word start_offset;
      if ((readp = __libdw_formptr (attr, IDX_debug_ranges,
				    DWARF_E_NO_DEBUG_RANGES,
				    &readendp, &start_offset)) == NULL)
	return -1;

      offset = start_offset;
      assert ((Dwarf_Word) offset == start_offset);

      /* Fetch the CU's base address.  */
      Dwarf_Die cudie = CUDIE (attr->cu);

      /* Find the base address of the compilation unit.  It will
	 normally be specified by DW_AT_low_pc.  In DWARF-3 draft 4,
	 the base address could be overridden by DW_AT_entry_pc.  It's
	 been removed, but GCC emits DW_AT_entry_pc and not DW_AT_lowpc
	 for compilation units with discontinuous ranges.  */
      if (unlikely (INTUSE(dwarf_lowpc) (&cudie, basep) != 0)
	  && INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (&cudie,
							 DW_AT_entry_pc,
							 &attr_mem),
				     basep) != 0)
	*basep = (Dwarf_Addr) -1;
    }
  else
    {
      if (__libdw_offset_in_section (die->cu->dbg,
				     IDX_debug_ranges, offset, 1))
	return -1l;

      readp = d->d_buf + offset;
      readendp = d->d_buf + d->d_size;
    }

 next:
  if (readendp - readp < die->cu->address_size * 2)
    goto invalid;

  Dwarf_Addr begin;
  Dwarf_Addr end;

  switch (__libdw_read_begin_end_pair_inc (die->cu->dbg, IDX_debug_ranges,
					   &readp, die->cu->address_size,
					   &begin, &end, basep))
    {
    case 0:
      break;
    case 1:
      goto next;
    case 2:
      return 0;
    default:
      return -1l;
    }

  /* We have an address range entry.  Check that we have a base.  */
  if (*basep == (Dwarf_Addr) -1)
    {
      if (INTUSE(dwarf_errno) () == 0)
	{
	invalid:
	  __libdw_seterrno (DWARF_E_INVALID_DWARF);
	}
      return -1;
    }

  *startp = *basep + begin;
  *endp = *basep + end;
  return readp - (unsigned char *) d->d_buf;
}
static int
array_size (Dwarf_Die *die, Dwarf_Word *size,
	    Dwarf_Attribute *attr_mem, Dwarf_Die *type_mem)
{
  Dwarf_Word eltsize;
  if (INTUSE(dwarf_aggregate_size) (get_type (die, attr_mem, type_mem),
				    &eltsize) != 0)
      return -1;

  /* An array can have DW_TAG_subrange_type or DW_TAG_enumeration_type
     children instead that give the size of each dimension.  */

  Dwarf_Die child;
  if (INTUSE(dwarf_child) (die, &child) != 0)
    return -1;

  bool any = false;
  Dwarf_Word total = 0;
  do
    {
      Dwarf_Word count;
      switch (INTUSE(dwarf_tag) (&child))
	{
	case DW_TAG_subrange_type:
	  /* This has either DW_AT_count or DW_AT_upper_bound.  */
	  if (INTUSE(dwarf_attr_integrate) (&child, DW_AT_count,
					    attr_mem) != NULL)
	    {
	      if (INTUSE(dwarf_formudata) (attr_mem, &count) != 0)
		return -1;
	    }
	  else
	    {
	      Dwarf_Sword upper;
	      Dwarf_Sword lower;
	      if (INTUSE(dwarf_formsdata) (INTUSE(dwarf_attr_integrate)
					   (&child, DW_AT_upper_bound,
					    attr_mem), &upper) != 0)
		return -1;

	      /* Having DW_AT_lower_bound is optional.  */
	      if (INTUSE(dwarf_attr_integrate) (&child, DW_AT_lower_bound,
						attr_mem) != NULL)
		{
		  if (INTUSE(dwarf_formsdata) (attr_mem, &lower) != 0)
		    return -1;
		}
	      else
		{
		  /* Determine default lower bound from language,
		     as per "4.12 Subrange Type Entries".  */
		  Dwarf_Die cu = CUDIE (die->cu);
		  switch (INTUSE(dwarf_srclang) (&cu))
		    {
		    case DW_LANG_C:
		    case DW_LANG_C89:
		    case DW_LANG_C99:
		    case DW_LANG_C_plus_plus:
		    case DW_LANG_ObjC:
		    case DW_LANG_ObjC_plus_plus:
		    case DW_LANG_Java:
		    case DW_LANG_D:
		    case DW_LANG_UPC:
		      lower = 0;
		      break;

		    case DW_LANG_Ada83:
		    case DW_LANG_Ada95:
		    case DW_LANG_Cobol74:
		    case DW_LANG_Cobol85:
		    case DW_LANG_Fortran77:
		    case DW_LANG_Fortran90:
		    case DW_LANG_Fortran95:
		    case DW_LANG_Pascal83:
		    case DW_LANG_Modula2:
		    case DW_LANG_PL1:
		      lower = 1;
		      break;

		    default:
		      return -1;
		    }
		}
	      if (unlikely (lower > upper))
		return -1;
	      count = upper - lower + 1;
	    }
	  break;

	case DW_TAG_enumeration_type:
	  /* We have to find the DW_TAG_enumerator child with the
	     highest value to know the array's element count.  */
	  count = 0;
	  Dwarf_Die enum_child;
	  int has_children = INTUSE(dwarf_child) (die, &enum_child);
	  if (has_children < 0)
	    return -1;
	  if (has_children > 0)
	    do
	      if (INTUSE(dwarf_tag) (&enum_child) == DW_TAG_enumerator)
		{
		  Dwarf_Word value;
		  if (INTUSE(dwarf_formudata) (INTUSE(dwarf_attr_integrate)
					       (&enum_child, DW_AT_const_value,
						attr_mem), &value) != 0)
		    return -1;
		  if (value >= count)
		    count = value + 1;
		}
	    while (INTUSE(dwarf_siblingof) (&enum_child, &enum_child) > 0);
	  break;

	default:
	  continue;
	}

      /* This is a subrange_type or enumeration_type and we've set COUNT.
	 Now determine the stride for this array dimension.  */
      Dwarf_Word stride = eltsize;
      if (INTUSE(dwarf_attr_integrate) (&child, DW_AT_byte_stride,
					attr_mem) != NULL)
	{
	  if (INTUSE(dwarf_formudata) (attr_mem, &stride) != 0)
	    return -1;
	}
      else if (INTUSE(dwarf_attr_integrate) (&child, DW_AT_bit_stride,
					     attr_mem) != NULL)
	{
	  if (INTUSE(dwarf_formudata) (attr_mem, &stride) != 0)
	    return -1;
	  if (stride % 8) 	/* XXX maybe compute in bits? */
	    return -1;
	  stride /= 8;
	}

      any = true;
      total += stride * count;
    }
  while (INTUSE(dwarf_siblingof) (&child, &child) == 0);

  if (!any)
    return -1;

  *size = total;
  return 0;
}