Exemple #1
0
/*  Given a form, and a pointer to the bytes encoding
    a value of that form, val_ptr, this function returns
    the length, in bytes, of a value of that form.
    When using this function, check for a return of 0
    a recursive DW_FORM_INDIRECT value.  */
int
_dwarf_get_size_of_val(Dwarf_Debug dbg,
    Dwarf_Unsigned form,
    Dwarf_Half cu_version,
    Dwarf_Half address_size,
    Dwarf_Small * val_ptr,
    int v_length_size,
    Dwarf_Unsigned *size_out,
    Dwarf_Error*error)
{
    Dwarf_Unsigned length = 0;
    Dwarf_Word leb128_length = 0;
    Dwarf_Unsigned form_indirect = 0;
    Dwarf_Unsigned ret_value = 0;

    switch (form) {

    /*  When we encounter a FORM here that
        we know about but forgot to enter here,
        we had better not just continue.
        Usually means we forgot to update this function
        when implementing form handling of a new FORM.
        Disaster results from using a bogus value,
        so generate error. */
    default:
        _dwarf_error(dbg,error,DW_DLE_DEBUG_FORM_HANDLING_INCOMPLETE);
        return DW_DLV_ERROR;


    case 0:  return 0;
    case DW_FORM_GNU_ref_alt:
    case DW_FORM_GNU_strp_alt:
    case DW_FORM_strp_sup:
        *size_out = v_length_size;
        return DW_DLV_OK;

    case DW_FORM_addr:
        if (address_size) {
            *size_out = address_size;
        } else {
            /* This should never happen, address_size should be set. */
            *size_out = dbg->de_pointer_size;
        }
        return DW_DLV_OK;
    case DW_FORM_ref_sig8:
        *size_out = 8;
        /* sizeof Dwarf_Sig8 */
        return DW_DLV_OK;

    /*  DWARF2 was wrong on the size of the attribute for
        DW_FORM_ref_addr.  We assume compilers are using the
        corrected DWARF3 text (for 32bit pointer target objects pointer and
        offsets are the same size anyway).
        It is clear (as of 2014) that for 64bit folks used
        the V2 spec in the way V2 was
        written, so the ref_addr has to account for that.*/
    case DW_FORM_ref_addr:
        if (cu_version == DW_CU_VERSION2) {
            *size_out = address_size;
        } else {
            *size_out = v_length_size;
        }
        return DW_DLV_OK;

    case DW_FORM_block1:
        *size_out =  *(Dwarf_Small *) val_ptr + 1;
        return DW_DLV_OK;

    case DW_FORM_block2:
        READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
            val_ptr, sizeof(Dwarf_Half));
        *size_out = ret_value + sizeof(Dwarf_Half);
        return DW_DLV_OK;

    case DW_FORM_block4:
        READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
            val_ptr, sizeof(Dwarf_ufixed));
        *size_out = ret_value + sizeof(Dwarf_ufixed);
        return DW_DLV_OK;

    case DW_FORM_data1:
        *size_out = 1;
        return DW_DLV_OK;

    case DW_FORM_data2:
        *size_out = 2;
        return DW_DLV_OK;

    case DW_FORM_data4:
        *size_out = 4;
        return DW_DLV_OK;

    case DW_FORM_data8:
        *size_out = 8;
        return DW_DLV_OK;

    case DW_FORM_string:
        *size_out = strlen((char *) val_ptr) + 1;
        return DW_DLV_OK;

    case DW_FORM_block:
    case DW_FORM_exprloc:
        length = _dwarf_decode_u_leb128(val_ptr, &leb128_length);
        *size_out = length + leb128_length;
        return DW_DLV_OK;

    case DW_FORM_flag_present:
        *size_out = 0;
        return DW_DLV_OK;

    case DW_FORM_flag:
        *size_out = 1;
        return DW_DLV_OK;

    case DW_FORM_sec_offset:
        /* If 32bit dwarf, is 4. Else is 64bit dwarf and is 8. */
        *size_out = v_length_size;
        return DW_DLV_OK;

    case DW_FORM_ref_udata:
        /*  Discard the decoded value, we just want the length
            of the value. */
        _dwarf_decode_u_leb128(val_ptr, &leb128_length);
        *size_out = leb128_length;
        return DW_DLV_OK;

    case DW_FORM_indirect:
        {
            Dwarf_Word indir_len = 0;
            int res = 0;
            Dwarf_Unsigned real_form_len = 0;

            form_indirect = _dwarf_decode_u_leb128(val_ptr, &indir_len);
            if (form_indirect == DW_FORM_indirect) {
                /* We are in big trouble: The true form
                    of DW_FORM_indirect is
                    DW_FORM_indirect? Nonsense. Should
                    never happen. */
                _dwarf_error(dbg,error,DW_DLE_NESTED_FORM_INDIRECT_ERROR);
                return DW_DLV_ERROR;
            }
            res = _dwarf_get_size_of_val(dbg,
                form_indirect,
                cu_version,
                address_size,
                val_ptr + indir_len,
                v_length_size,
                &real_form_len,
                error);
            if(res != DW_DLV_OK) {
                return res;
            }
            *size_out = indir_len + real_form_len;
            return DW_DLV_OK;
        }

    case DW_FORM_ref1:
        *size_out = 1;
        return DW_DLV_OK;

    case DW_FORM_ref2:
        *size_out = 2;
        return DW_DLV_OK;

    case DW_FORM_ref4:
        *size_out = 4;
        return DW_DLV_OK;

    case DW_FORM_ref8:
        *size_out = 8;
        return DW_DLV_OK;

    case DW_FORM_sdata:
        /*  Discard the decoded value, we just want the length
            of the value. */
        _dwarf_decode_s_leb128(val_ptr, &leb128_length);
        *size_out = (leb128_length);
        return DW_DLV_OK;


    case DW_FORM_addrx:
    case DW_FORM_GNU_addr_index:
    case DW_FORM_strx:
    case DW_FORM_GNU_str_index:
        _dwarf_decode_u_leb128(val_ptr, &leb128_length);
        *size_out = leb128_length;
        return DW_DLV_OK;

    case DW_FORM_strp:
        *size_out = v_length_size;
        return DW_DLV_OK;

    case DW_FORM_udata:
        /*  Discard the decoded value, we just want the length
            of the value. */
        _dwarf_decode_u_leb128(val_ptr, &leb128_length);
        *size_out = leb128_length;
        return DW_DLV_OK;
    }
}
Exemple #2
0
/*
    Given a form, and a pointer to the bytes encoding 
    a value of that form, val_ptr, this function returns
    the length, in bytes, of a value of that form.
    When using this function, check for a return of 0
    a recursive DW_FORM_INDIRECT value.
*/
Dwarf_Unsigned
_dwarf_get_size_of_val(Dwarf_Debug dbg,
    Dwarf_Unsigned form,
    Dwarf_Half address_size,
    Dwarf_Small * val_ptr, int v_length_size)
{
    Dwarf_Unsigned length = 0;
    Dwarf_Word leb128_length = 0;
    Dwarf_Unsigned form_indirect = 0;
    Dwarf_Unsigned ret_value = 0;

    switch (form) {

    default:                    /* Handles form = 0. */
        return (form);

    case DW_FORM_addr:
        return (dbg->de_pointer_size);

    /* DWARF2 was wrong on the size of the attribute for
       DW_FORM_ref_addr.  We assume compilers are using the 
       corrected DWARF3 text (for 32bit pointer target objects pointer and
       offsets are the same size anyway). */
    case DW_FORM_ref_addr:
        return (v_length_size);

    case DW_FORM_block1:
        return (*(Dwarf_Small *) val_ptr + 1);

    case DW_FORM_block2:
        READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
                       val_ptr, sizeof(Dwarf_Half));
        return (ret_value + sizeof(Dwarf_Half));

    case DW_FORM_block4:
        READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
                       val_ptr, sizeof(Dwarf_ufixed));
        return (ret_value + sizeof(Dwarf_ufixed));


    case DW_FORM_data1:
        return (1);

    case DW_FORM_data2:
        return (2);

    case DW_FORM_data4:
        return (4);

    case DW_FORM_data8:
        return (8);

    case DW_FORM_string:
        return (strlen((char *) val_ptr) + 1);

    case DW_FORM_block:
        length = _dwarf_decode_u_leb128(val_ptr, &leb128_length);
        return (length + leb128_length);

    case DW_FORM_flag:
        return (1);

    case DW_FORM_ref_udata:
        _dwarf_decode_u_leb128(val_ptr, &leb128_length);
        return (leb128_length);

    case DW_FORM_indirect:
        {
            Dwarf_Word indir_len = 0;

            form_indirect = _dwarf_decode_u_leb128(val_ptr, &indir_len);
            if (form_indirect == DW_FORM_indirect) {
                return (0);     /* We are in big trouble: The true form 
                                   of DW_FORM_indirect is
                                   DW_FORM_indirect? Nonsense. Should
                                   never happen. */
            }
            return (indir_len + _dwarf_get_size_of_val(dbg,
                   form_indirect,
                   address_size,
                   val_ptr + indir_len,
                   v_length_size));
        }

    case DW_FORM_ref1:
        return (1);

    case DW_FORM_ref2:
        return (2);

    case DW_FORM_ref4:
        return (4);

    case DW_FORM_ref8:
        return (8);

    case DW_FORM_sdata:
        _dwarf_decode_s_leb128(val_ptr, &leb128_length);
        return (leb128_length);

    case DW_FORM_strp:
        return (v_length_size);

    case DW_FORM_udata:
        _dwarf_decode_u_leb128(val_ptr, &leb128_length);
        return (leb128_length);
    }
}
Exemple #3
0
/*  This function does two slightly different things
    depending on the input flag want_AT_sibling.  If
    this flag is true, it checks if the input die has
    a DW_AT_sibling attribute.  If it does it returns
    a pointer to the start of the sibling die in the
    .debug_info section.  Otherwise it behaves the 
    same as the want_AT_sibling false case.

    If the want_AT_sibling flag is false, it returns
    a pointer to the immediately adjacent die in the 
    .debug_info section.

    Die_info_end points to the end of the .debug_info 
    portion for the cu the die belongs to.  It is used 
    to check that the search for the next die does not 
    cross the end of the current cu.  Cu_info_start points 
    to the start of the .debug_info portion for the 
    current cu, and is used to add to the offset for 
    DW_AT_sibling attributes.  Finally, has_die_child 
    is a pointer to a Dwarf_Bool that is set true if 
    the present die has children, false otherwise.  
    However, in case want_AT_child is true and the die 
    has a DW_AT_sibling attribute *has_die_child is set 
    false to indicate that the children are being skipped.

    die_info_end  points to the last byte+1 of the cu.  */
static Dwarf_Byte_Ptr
_dwarf_next_die_info_ptr(Dwarf_Byte_Ptr die_info_ptr,
    Dwarf_CU_Context cu_context,
    Dwarf_Byte_Ptr die_info_end,
    Dwarf_Byte_Ptr cu_info_start,
    Dwarf_Bool want_AT_sibling,
    Dwarf_Bool * has_die_child)
{
    Dwarf_Byte_Ptr info_ptr = 0;
    Dwarf_Byte_Ptr abbrev_ptr = 0;
    Dwarf_Word abbrev_code = 0;
    Dwarf_Abbrev_List abbrev_list;
    Dwarf_Half attr = 0;
    Dwarf_Half attr_form = 0;
    Dwarf_Unsigned offset = 0;
    Dwarf_Word leb128_length = 0;
    Dwarf_Unsigned utmp = 0;
    Dwarf_Debug dbg = 0;

    info_ptr = die_info_ptr;
    DECODE_LEB128_UWORD(info_ptr, utmp);
    abbrev_code = (Dwarf_Word) utmp;
    if (abbrev_code == 0) {
        return NULL;
    }


    abbrev_list = _dwarf_get_abbrev_for_code(cu_context, abbrev_code);
    if (abbrev_list == NULL) {
        return (NULL);
    }
    dbg = cu_context->cc_dbg;

    *has_die_child = abbrev_list->ab_has_child;

    abbrev_ptr = abbrev_list->ab_abbrev_ptr;
    do {
        Dwarf_Unsigned utmp2;

        DECODE_LEB128_UWORD(abbrev_ptr, utmp2);
        attr = (Dwarf_Half) utmp2;
        DECODE_LEB128_UWORD(abbrev_ptr, utmp2);
        attr_form = (Dwarf_Half) utmp2;
        if (attr_form == DW_FORM_indirect) {
            Dwarf_Unsigned utmp6;

            /* DECODE_LEB128_UWORD updates info_ptr */
            DECODE_LEB128_UWORD(info_ptr, utmp6);
            attr_form = (Dwarf_Half) utmp6;

        }

        if (want_AT_sibling && attr == DW_AT_sibling) {
            switch (attr_form) {
            case DW_FORM_ref1:
                offset = *(Dwarf_Small *) info_ptr;
                break;
            case DW_FORM_ref2:
                /* READ_UNALIGNED does not update info_ptr */
                READ_UNALIGNED(dbg, offset, Dwarf_Unsigned,
                    info_ptr, sizeof(Dwarf_Half));
                break;
            case DW_FORM_ref4:
                READ_UNALIGNED(dbg, offset, Dwarf_Unsigned,
                    info_ptr, sizeof(Dwarf_ufixed));
                break;
            case DW_FORM_ref8:
                READ_UNALIGNED(dbg, offset, Dwarf_Unsigned,
                    info_ptr, sizeof(Dwarf_Unsigned));
                break;
            case DW_FORM_ref_udata:
                offset =
                    _dwarf_decode_u_leb128(info_ptr, &leb128_length);
                break;
            case DW_FORM_ref_addr:
                /*  Very unusual.  The FORM is intended to refer to
                    a different CU, but a different CU cannot
                    be a sibling, can it? 
                    We could ignore this and treat as if no DW_AT_sibling
                    present.   Or derive the offset from it and if
                    it is in the same CU use it directly. 
                    The offset here is *supposed* to be a global offset,
                    so adding cu_info_start is wrong  to any offset
                    we find here unless cu_info_start
                    is zero! Lets pretend there is no DW_AT_sibling
                    attribute.  */
                goto no_sibling_attr;
            default:
                return (NULL);
            }

            /*  Reset *has_die_child to indicate children skipped.  */
            *has_die_child = false;

            /*  A value beyond die_info_end indicates an error. Exactly
                at die_info_end means 1-past-cu-end and simply means we
                are at the end, do not return NULL. Higher level code
                will detect that we are at the end. */
            if (cu_info_start + offset > die_info_end) {
                /* Error case, bad DWARF. */
                return (NULL);
            }
            /* At or before end-of-cu */
            return (cu_info_start + offset);
        }

        no_sibling_attr:
        if (attr_form != 0) {
            info_ptr += _dwarf_get_size_of_val(cu_context->cc_dbg,
                attr_form, 
                cu_context->cc_address_size,
                info_ptr,
                cu_context->cc_length_size);
            /*  It is ok for info_ptr == die_info_end, as we will test
                later before using a too-large info_ptr */
            if (info_ptr > die_info_end) {
                /*  More than one-past-end indicates a bug somewhere,
                    likely bad dwarf generation. */
                return (NULL);
            }
        }
    } while (attr != 0 || attr_form != 0);
    return (info_ptr);
}
Exemple #4
0
/*
    Given a form, and a pointer to the bytes encoding 
    a value of that form, val_ptr, this function returns
    the length, in bytes, of a value of that form.
    When using this function, check for a return of 0
    a recursive DW_FORM_INDIRECT value.
*/
Dwarf_Unsigned
_dwarf_get_size_of_val(Dwarf_Debug dbg,
		       Dwarf_Unsigned form,
		       Dwarf_Small * val_ptr, int v_length_size)
{
    Dwarf_Unsigned length = 0;
    Dwarf_Word leb128_length = 0;
    Dwarf_Unsigned form_indirect = 0;
    Dwarf_Unsigned ret_value = 0;

    switch (form) {

    default:			/* Handles form = 0. */
	return (form);

    case DW_FORM_addr:
	return (dbg->de_pointer_size);

    case DW_FORM_ref_addr:
	return (v_length_size);

    case DW_FORM_block1:
	return (*(Dwarf_Small *) val_ptr + 1);

    case DW_FORM_block2:
	READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
		       val_ptr, sizeof(Dwarf_Half));
	return (ret_value + sizeof(Dwarf_Half));

    case DW_FORM_block4:
	READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
		       val_ptr, sizeof(Dwarf_ufixed));
	return (ret_value + sizeof(Dwarf_ufixed));


    case DW_FORM_data1:
	return (1);

    case DW_FORM_data2:
	return (2);

    case DW_FORM_data4:
	return (4);

    case DW_FORM_data8:
	return (8);

    case DW_FORM_string:
	return (strlen((char *) val_ptr) + 1);

    case DW_FORM_block:
	length = _dwarf_decode_u_leb128(val_ptr, &leb128_length);
	return (length + leb128_length);

    case DW_FORM_flag:
	return (1);

    case DW_FORM_ref_udata:
	_dwarf_decode_u_leb128(val_ptr, &leb128_length);
	return (leb128_length);

    case DW_FORM_indirect:
	{
	    Dwarf_Word indir_len = 0;

	    form_indirect = _dwarf_decode_u_leb128(val_ptr, &indir_len);
	    if (form_indirect == DW_FORM_indirect) {
		return (0);	/* We are in big trouble: The true form 
				   of DW_FORM_indirect is
				   DW_FORM_indirect? Nonsense. Should
				   never happen. */
	    }
	    return (indir_len + _dwarf_get_size_of_val(dbg,
						       form_indirect,
						       val_ptr +
						       indir_len,
						       v_length_size));
	}

    case DW_FORM_ref1:
	return (1);

    case DW_FORM_ref2:
	return (2);

    case DW_FORM_ref4:
	return (4);

    case DW_FORM_ref8:
	return (8);

    case DW_FORM_sdata:
	_dwarf_decode_s_leb128(val_ptr, &leb128_length);
	return (leb128_length);

    case DW_FORM_strp:
	return (v_length_size);

    case DW_FORM_udata:
	_dwarf_decode_u_leb128(val_ptr, &leb128_length);
	return (leb128_length);
    }
}
Exemple #5
0
/* 
    This function does two slightly different things
    depending on the input flag want_AT_sibling.  If
    this flag is true, it checks if the input die has
    a DW_AT_sibling attribute.  If it does it returns
    a pointer to the start of the sibling die in the
    .debug_info section.  Otherwise it behaves the 
    same as the want_AT_sibling false case.

    If the want_AT_sibling flag is false, it returns
    a pointer to the immediately adjacent die in the 
    .debug_info section.

    Die_info_end points to the end of the .debug_info 
    portion for the cu the die belongs to.  It is used 
    to check that the search for the next die does not 
    cross the end of the current cu.  Cu_info_start points 
    to the start of the .debug_info portion for the 
    current cu, and is used to add to the offset for 
    DW_AT_sibling attributes.  Finally, has_die_child 
    is a pointer to a Dwarf_Bool that is set true if 
    the present die has children, false otherwise.  
    However, in case want_AT_child is true and the die 
    has a DW_AT_sibling attribute *has_die_child is set 
    false to indicate that the children are being skipped.
*/
static Dwarf_Byte_Ptr
_dwarf_next_die_info_ptr(Dwarf_Byte_Ptr die_info_ptr,
			 Dwarf_CU_Context cu_context,
			 Dwarf_Byte_Ptr die_info_end,
			 Dwarf_Byte_Ptr cu_info_start,
			 Dwarf_Bool want_AT_sibling,
			 Dwarf_Bool * has_die_child)
{
    Dwarf_Byte_Ptr info_ptr;
    Dwarf_Byte_Ptr abbrev_ptr;
    Dwarf_Word abbrev_code;
    Dwarf_Abbrev_List abbrev_list;
    Dwarf_Half attr;
    Dwarf_Half attr_form;
    Dwarf_Unsigned offset;
    Dwarf_Word leb128_length;
    Dwarf_Unsigned utmp;
    Dwarf_Debug dbg;

    info_ptr = die_info_ptr;
    DECODE_LEB128_UWORD(info_ptr, utmp)
	abbrev_code = (Dwarf_Word) utmp;
    if (abbrev_code == 0) {
	return NULL;
    }

    abbrev_list = _dwarf_get_abbrev_for_code(cu_context, abbrev_code);
    if (abbrev_list == NULL) {
	return (NULL);
    }
    dbg = cu_context->cc_dbg;

    *has_die_child = abbrev_list->ab_has_child;

    abbrev_ptr = abbrev_list->ab_abbrev_ptr;
    do {
	Dwarf_Unsigned utmp2;

	DECODE_LEB128_UWORD(abbrev_ptr, utmp2)
	    attr = (Dwarf_Half) utmp2;
	DECODE_LEB128_UWORD(abbrev_ptr, utmp2)
	    attr_form = (Dwarf_Half) utmp2;
	if (attr_form == DW_FORM_indirect) {
	    Dwarf_Unsigned utmp6;

	    /* READ_UNALIGNED does update info_ptr */
	    DECODE_LEB128_UWORD(info_ptr, utmp6)
		attr_form = (Dwarf_Half) utmp6;

	}

	if (want_AT_sibling && attr == DW_AT_sibling) {
	    switch (attr_form) {
	    case DW_FORM_ref1:
		offset = *(Dwarf_Small *) info_ptr;
		break;
	    case DW_FORM_ref2:
		READ_UNALIGNED(dbg, offset, Dwarf_Unsigned,
			       info_ptr, sizeof(Dwarf_Half));
		break;
	    case DW_FORM_ref4:
		READ_UNALIGNED(dbg, offset, Dwarf_Unsigned,
			       info_ptr, sizeof(Dwarf_ufixed));
		break;
	    case DW_FORM_ref8:
		READ_UNALIGNED(dbg, offset, Dwarf_Unsigned,
			       info_ptr, sizeof(Dwarf_Unsigned));
		break;
	    case DW_FORM_ref_udata:
		offset =
		    _dwarf_decode_u_leb128(info_ptr, &leb128_length);
		break;
	    default:
		return (NULL);
	    }

	    /* Reset *has_die_child to indicate children skipped.  */
	    *has_die_child = false;

	    if (cu_info_start + offset > die_info_end) {
		return (NULL);
	    } else {
		return (cu_info_start + offset);
	    }
	}

	if (attr_form != 0) {
	    info_ptr += _dwarf_get_size_of_val(cu_context->cc_dbg,
					       attr_form, info_ptr,
					       cu_context->
					       cc_length_size);
	    if (info_ptr > die_info_end) {
		return (NULL);
	    }
	}
    } while (attr != 0 || attr_form != 0);

    return (info_ptr);
}