int
dwarf_formblock (Dwarf_Attribute *attr, Dwarf_Block *return_block)
{
  if (attr == NULL)
    return -1;

  const unsigned char *datap = attr->valp;
  const unsigned char *endp = attr->cu->endp;

  switch (attr->form)
    {
    case DW_FORM_block1:
      if (unlikely (endp - datap < 1))
	goto invalid;
      return_block->length = *(uint8_t *) attr->valp;
      return_block->data = attr->valp + 1;
      break;

    case DW_FORM_block2:
      if (unlikely (endp - datap < 2))
	goto invalid;
      return_block->length = read_2ubyte_unaligned (attr->cu->dbg, attr->valp);
      return_block->data = attr->valp + 2;
      break;

    case DW_FORM_block4:
      if (unlikely (endp - datap < 4))
	goto invalid;
      return_block->length = read_4ubyte_unaligned (attr->cu->dbg, attr->valp);
      return_block->data = attr->valp + 4;
      break;

    case DW_FORM_block:
    case DW_FORM_exprloc:
      if (unlikely (endp - datap < 1))
	goto invalid;
      get_uleb128 (return_block->length, datap, endp);
      return_block->data = (unsigned char *) datap;
      break;

    default:
      __libdw_seterrno (DWARF_E_NO_BLOCK);
      return -1;
    }

  if (unlikely (return_block->length > (size_t) (endp - return_block->data)))
    {
      /* Block does not fit.  */
    invalid:
      __libdw_seterrno (DWARF_E_INVALID_DWARF);
      return -1;
    }

  return 0;
}
static int
get_offsets (Dwarf *dbg)
{
  size_t allocated = 0;
  size_t cnt = 0;
  struct pubnames_s *mem = NULL;
  const size_t entsize = sizeof (struct pubnames_s);
  unsigned char *const startp = dbg->sectiondata[IDX_debug_pubnames]->d_buf;
  unsigned char *readp = startp;
  unsigned char *endp = readp + dbg->sectiondata[IDX_debug_pubnames]->d_size;

  while (readp + 14 < endp)
    {
      /* If necessary, allocate more entries.  */
      if (cnt >= allocated)
	{
	  allocated = MAX (10, 2 * allocated);
	  struct pubnames_s *newmem
	    = (struct pubnames_s *) realloc (mem, allocated * entsize);
	  if (newmem == NULL)
	    {
	      __libdw_seterrno (DWARF_E_NOMEM);
	    err_return:
	      free (mem);
	      return -1;
	    }

	  mem = newmem;
	}

      /* Read the set header.  */
      int len_bytes = 4;
      Dwarf_Off len = read_4ubyte_unaligned_inc (dbg, readp);
      if (len == DWARF3_LENGTH_64_BIT)
	{
	  len = read_8ubyte_unaligned_inc (dbg, readp);
	  len_bytes = 8;
	}
      else if (unlikely (len >= DWARF3_LENGTH_MIN_ESCAPE_CODE
			 && len <= DWARF3_LENGTH_MAX_ESCAPE_CODE))
	{
	invalid_dwarf:
	  __libdw_seterrno (DWARF_E_INVALID_DWARF);
	  goto err_return;
	}

      /* Now we know the offset of the first offset/name pair.  */
      mem[cnt].set_start = readp + 2 + 2 * len_bytes - startp;
      mem[cnt].address_len = len_bytes;
      if (mem[cnt].set_start >= dbg->sectiondata[IDX_debug_pubnames]->d_size)
	/* Something wrong, the first entry is beyond the end of
	   the section.  */
	break;

      /* Read the version.  It better be two for now.  */
      uint16_t version = read_2ubyte_unaligned (dbg, readp);
      if (unlikely (version != 2))
	{
	  __libdw_seterrno (DWARF_E_INVALID_VERSION);
	  goto err_return;
	}

      /* Get the CU offset.  */
      if (len_bytes == 4)
	mem[cnt].cu_offset = read_4ubyte_unaligned (dbg, readp + 2);
      else
	mem[cnt].cu_offset = read_8ubyte_unaligned (dbg, readp + 2);

      /* Determine the size of the CU header.  */
      if (unlikely (dbg->sectiondata[IDX_debug_info] == NULL
		    || dbg->sectiondata[IDX_debug_info]->d_buf == NULL
		    || (mem[cnt].cu_offset + 3
			>= dbg->sectiondata[IDX_debug_info]->d_size)))
	goto invalid_dwarf;

      unsigned char *infop
	= ((unsigned char *) dbg->sectiondata[IDX_debug_info]->d_buf
	   + mem[cnt].cu_offset);
      if (read_4ubyte_unaligned_noncvt (infop) == DWARF3_LENGTH_64_BIT)
	mem[cnt].cu_header_size = 23;
      else
	mem[cnt].cu_header_size = 11;

      ++cnt;

      /* Advance to the next set.  */
      readp += len;
    }

  if (mem == NULL)
    {
      __libdw_seterrno (DWARF_E_NO_ENTRY);
      return -1;
    }

  dbg->pubnames_sets = (struct pubnames_s *) realloc (mem, cnt * entsize);
  dbg->pubnames_nsets = cnt;

  return 0;
}
int
dwarf_formudata (Dwarf_Attribute *attr, Dwarf_Word *return_uval)
{
  if (attr == NULL)
    return -1;

  const unsigned char *datap = attr->valp;
  const unsigned char *endp = attr->cu->endp;

  switch (attr->form)
    {
    case DW_FORM_data1:
      if (datap + 1 > endp)
	{
	invalid:
	  __libdw_seterrno (DWARF_E_INVALID_DWARF);
	  return -1;
	}
      *return_uval = *attr->valp;
      break;

    case DW_FORM_data2:
      if (datap + 2 > endp)
	goto invalid;
      *return_uval = read_2ubyte_unaligned (attr->cu->dbg, attr->valp);
      break;

    case DW_FORM_data4:
    case DW_FORM_data8:
    case DW_FORM_sec_offset:
      /* Before DWARF4 data4 and data8 are pure constants unless the
	 attribute also allows offsets (*ptr classes), since DWARF4
	 they are always just constants (start_scope is special though,
	 since it only could express a rangelist since DWARF4).  */
      if (attr->form == DW_FORM_sec_offset
	  || (attr->cu->version < 4 && attr->code != DW_AT_start_scope))
	{
	  switch (attr->code)
	    {
	    case DW_AT_data_member_location:
	    case DW_AT_frame_base:
	    case DW_AT_location:
	    case DW_AT_return_addr:
	    case DW_AT_segment:
	    case DW_AT_static_link:
	    case DW_AT_string_length:
	    case DW_AT_use_location:
	    case DW_AT_vtable_elem_location:
	      /* loclistptr */
	      if (__libdw_formptr (attr, IDX_debug_loc,
				   DWARF_E_NO_LOCLIST, NULL,
				   return_uval) == NULL)
		return -1;
	      break;

	    case DW_AT_macro_info:
	      /* macptr into .debug_macinfo */
	      if (__libdw_formptr (attr, IDX_debug_macinfo,
				   DWARF_E_NO_ENTRY, NULL,
				   return_uval) == NULL)
		return -1;
	      break;

	    case DW_AT_GNU_macros:
	      /* macptr into .debug_macro */
	      if (__libdw_formptr (attr, IDX_debug_macro,
				   DWARF_E_NO_ENTRY, NULL,
				   return_uval) == NULL)
		return -1;
	      break;

	    case DW_AT_ranges:
	    case DW_AT_start_scope:
	      /* rangelistptr */
	      if (__libdw_formptr (attr, IDX_debug_ranges,
				   DWARF_E_NO_DEBUG_RANGES, NULL,
				   return_uval) == NULL)
		return -1;
	      break;

	    case DW_AT_stmt_list:
	      /* lineptr */
	      if (__libdw_formptr (attr, IDX_debug_line,
				   DWARF_E_NO_DEBUG_LINE, NULL,
				   return_uval) == NULL)
		return -1;
	      break;

	    default:
	      /* sec_offset can only be used by one of the above attrs.  */
	      if (attr->form == DW_FORM_sec_offset)
		{
		  __libdw_seterrno (DWARF_E_INVALID_DWARF);
		  return -1;
		}

	      /* Not one of the special attributes, just a constant.  */
	      if (__libdw_read_address (attr->cu->dbg, cu_sec_idx (attr->cu),
					attr->valp,
					attr->form == DW_FORM_data4 ? 4 : 8,
					return_uval))
		return -1;
	      break;
	    }
	}
      else
	{
	  /* We are dealing with a constant data4 or data8.  */
	  if (__libdw_read_address (attr->cu->dbg, cu_sec_idx (attr->cu),
				    attr->valp,
				    attr->form == DW_FORM_data4 ? 4 : 8,
				    return_uval))
	    return -1;
	}
      break;

    case DW_FORM_sdata:
      if (datap + 1 > endp)
	goto invalid;
      get_sleb128 (*return_uval, datap, endp);
      break;

    case DW_FORM_udata:
      if (datap + 1 > endp)
	goto invalid;
      get_uleb128 (*return_uval, datap, endp);
      break;

    default:
      __libdw_seterrno (DWARF_E_NO_CONSTANT);
      return -1;
    }

  return 0;
}
Exemple #4
0
int
internal_function
__libdw_formref (Dwarf_Attribute *attr, Dwarf_Off *return_offset)
{
  const unsigned char *datap = attr->valp;
  const unsigned char *endp = attr->cu->endp;

  if (attr->valp == NULL)
    {
      __libdw_seterrno (DWARF_E_INVALID_REFERENCE);
      return -1;
    }

  switch (attr->form)
    {
    case DW_FORM_ref1:
      if (datap + 1 > endp)
	{
	invalid:
	  __libdw_seterrno (DWARF_E_INVALID_DWARF);
	  return -1;
	}
      *return_offset = *attr->valp;
      break;

    case DW_FORM_ref2:
      if (datap + 2 > endp)
	goto invalid;
      *return_offset = read_2ubyte_unaligned (attr->cu->dbg, attr->valp);
      break;

    case DW_FORM_ref4:
      if (datap + 4 > endp)
	goto invalid;
      *return_offset = read_4ubyte_unaligned (attr->cu->dbg, attr->valp);
      break;

    case DW_FORM_ref8:
      if (datap + 8 > endp)
	goto invalid;
      *return_offset = read_8ubyte_unaligned (attr->cu->dbg, attr->valp);
      break;

    case DW_FORM_ref_udata:
      if (datap + 1 > endp)
	goto invalid;
      get_uleb128 (*return_offset, datap, endp);
      break;

    case DW_FORM_ref_addr:
    case DW_FORM_ref_sig8:
    case DW_FORM_GNU_ref_alt:
      /* These aren't handled by dwarf_formref, only by dwarf_formref_die.  */
      __libdw_seterrno (DWARF_E_INVALID_REFERENCE);
      return -1;

    default:
      __libdw_seterrno (DWARF_E_NO_REFERENCE);
      return -1;
    }

  return 0;
}
Exemple #5
0
size_t
internal_function
__libdw_form_val_compute_len (Dwarf *dbg, struct Dwarf_CU *cu,
			      unsigned int form, const unsigned char *valp)
{
  const unsigned char *saved;
  Dwarf_Word u128;
  size_t result;

  /* NB: This doesn't cover constant form lengths, which are
     already handled by the inlined __libdw_form_val_len.  */
  switch (form)
    {
    case DW_FORM_addr:
      result = cu->address_size;
      break;

    case DW_FORM_ref_addr:
      result = cu->version == 2 ? cu->address_size : cu->offset_size;
      break;

    case DW_FORM_strp:
    case DW_FORM_sec_offset:
    case DW_FORM_GNU_ref_alt:
    case DW_FORM_GNU_strp_alt:
      result = cu->offset_size;
      break;

    case DW_FORM_block1:
      result = *valp + 1;
      break;

    case DW_FORM_block2:
      result = read_2ubyte_unaligned (dbg, valp) + 2;
      break;

    case DW_FORM_block4:
      result = read_4ubyte_unaligned (dbg, valp) + 4;
      break;

    case DW_FORM_block:
    case DW_FORM_exprloc:
      saved = valp;
      get_uleb128 (u128, valp);
      result = u128 + (valp - saved);
      break;

    case DW_FORM_string:
      result = strlen ((char *) valp) + 1;
      break;

    case DW_FORM_sdata:
    case DW_FORM_udata:
    case DW_FORM_ref_udata:
      saved = valp;
      get_uleb128 (u128, valp);
      result = valp - saved;
      break;

    case DW_FORM_indirect:
      saved = valp;
      get_uleb128 (u128, valp);
      // XXX Is this really correct?
      result = __libdw_form_val_len (dbg, cu, u128, valp);
      if (result != (size_t) -1)
	result += valp - saved;
      break;

    default:
      __libdw_seterrno (DWARF_E_INVALID_DWARF);
      result = (size_t) -1l;
      break;
    }

  return result;
}