Exemple #1
0
int
_dwarf_extract_local_debug_str_string_given_offset(Dwarf_Debug dbg,
    unsigned attrform,
    Dwarf_Unsigned offset,
    char ** return_str,
    Dwarf_Error * error)
{
    if (attrform == DW_FORM_strp ||
        attrform == DW_FORM_line_strp ||
        attrform == DW_FORM_GNU_str_index ||
        attrform == DW_FORM_strx) {
        /*  The 'offset' into .debug_str or .debug_line_str is given,
            here we turn that into a pointer. */
        Dwarf_Small   *secend = 0;
        Dwarf_Small   *secbegin = 0;
        Dwarf_Small   *strbegin = 0;
        Dwarf_Unsigned secsize = 0;
        int errcode = 0;
        int res = 0;

        if(attrform == DW_FORM_line_strp) {
            res = _dwarf_load_section(dbg, &dbg->de_debug_line_str,error);
            if (res != DW_DLV_OK) {
                return res;
            }
            errcode = DW_DLE_STRP_OFFSET_BAD;
            secsize = dbg->de_debug_line_str.dss_size;
            secbegin = dbg->de_debug_line_str.dss_data;
            strbegin= dbg->de_debug_line_str.dss_data + offset;
        } else {
            res = _dwarf_load_section(dbg, &dbg->de_debug_str,error);
            if (res != DW_DLV_OK) {
                return res;
            }
            errcode = DW_DLE_STRP_OFFSET_BAD;
            secsize = dbg->de_debug_str.dss_size;
            secbegin = dbg->de_debug_str.dss_data;
            strbegin= dbg->de_debug_str.dss_data + offset;
            secend = dbg->de_debug_str.dss_data + secsize;
        }
        if (offset >= secsize) {
            /*  Badly damaged DWARF here. */
            _dwarf_error(dbg, error, errcode);
            return (DW_DLV_ERROR);
        }
        res= _dwarf_check_string_valid(dbg,secbegin,strbegin, secend,error);
        if (res != DW_DLV_OK) {
            return res;
        }

        *return_str = (char *)strbegin;
        return DW_DLV_OK;
    }
    _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_BAD);
    return (DW_DLV_ERROR);
}
Exemple #2
0
int
_dwarf_load_debug_types(Dwarf_Debug dbg, Dwarf_Error * error)
{
    int res = DW_DLV_ERROR;
    if (dbg->de_debug_types.dss_data) {
        return DW_DLV_OK;
    }
    res = _dwarf_load_section(dbg, &dbg->de_debug_abbrev,error);
    if (res != DW_DLV_OK) {
        return res;
    }
    res = _dwarf_load_section(dbg, &dbg->de_debug_types, error);
    return res;
}
Exemple #3
0
int
dwarf_get_vars(Dwarf_Debug dbg,
    Dwarf_Var ** vars,
    Dwarf_Signed * ret_var_count, Dwarf_Error * error)
{
    int res = _dwarf_load_section(dbg, &dbg->de_debug_varnames,error);
    if (res != DW_DLV_OK) {
        return res;
    }
    if (!dbg->de_debug_abbrev.dss_size) {
        return (DW_DLV_NO_ENTRY);
    }

    return _dwarf_internal_get_pubnames_like_data(dbg, 
        dbg->de_debug_varnames.dss_data, 
        dbg->de_debug_varnames.dss_size, 
        (Dwarf_Global **) vars, /* Type punning for sections 
            with identical format. */
        ret_var_count,
        error,
        DW_DLA_VAR_CONTEXT,
        DW_DLA_VAR,
        DW_DLE_DEBUG_VARNAMES_LENGTH_BAD,
        DW_DLE_DEBUG_VARNAMES_VERSION_ERROR);
}
Exemple #4
0
/* Helper routine  to avoid code duplication.
*/
static int
_dwarf_get_loclist_header_start(Dwarf_Debug dbg,
    Dwarf_Attribute attr,
    Dwarf_Unsigned * loclist_offset,
    Dwarf_Error * error)
{
    int blkres = dwarf_global_formref(attr, loclist_offset, error);
    if (blkres != DW_DLV_OK) {
        return (blkres);
    }

    if (!dbg->de_debug_loc.dss_data) {
        int secload = _dwarf_load_section(dbg, &dbg->de_debug_loc,error);
        if (secload != DW_DLV_OK) {
            return secload;
        }
        if (!dbg->de_debug_loc.dss_size) {
            return (DW_DLV_NO_ENTRY);
        }
    }
    {
        int fisres = 0;
        Dwarf_Unsigned fissoff = 0;
        Dwarf_Unsigned size = 0;
        fisres = _dwarf_get_fission_addition_die(attr->ar_die, DW_SECT_LOC,
            &fissoff, &size,error);
        if(fisres != DW_DLV_OK) {
            return fisres;
        }
        *loclist_offset += fissoff;
    }
    return DW_DLV_OK;
}
Exemple #5
0
int
dwarf_get_types(Dwarf_Debug dbg,
		Dwarf_Type ** types,
		Dwarf_Signed * ret_type_count, Dwarf_Error * error)
{
    int res;

    res =
       _dwarf_load_section(dbg,
		           dbg->de_debug_typenames_index,
			   &dbg->de_debug_typenames,
			   error);
    if (res != DW_DLV_OK) {
	return res;
    }

    return _dwarf_internal_get_pubnames_like_data(dbg, dbg->de_debug_typenames, dbg->de_debug_typenames_size, (Dwarf_Global **) types,	/* type 
																	   punning,
																	   Dwarf_Type 
																	   is never
																	   a
																	   completed 
																	   type */
						  ret_type_count,
						  error,
						  DW_DLA_TYPENAME_CONTEXT,
						  DW_DLE_DEBUG_TYPENAMES_LENGTH_BAD,
						  DW_DLE_DEBUG_TYPENAMES_VERSION_ERROR);

}
int
dwarf_get_pubtypes(Dwarf_Debug dbg,
    Dwarf_Type ** types,
    Dwarf_Signed * ret_type_count, Dwarf_Error * error)
{
    int res = _dwarf_load_section(dbg, &dbg->de_debug_pubtypes,error);
    if (res != DW_DLV_OK) {
        return res;
    }
    if (!dbg->de_debug_pubtypes.dss_size) {
        return (DW_DLV_NO_ENTRY);
    }


    return _dwarf_internal_get_pubnames_like_data(dbg,
        dbg->de_debug_pubtypes.dss_data,
        dbg->de_debug_pubtypes.dss_size,
        (Dwarf_Global **) types, /* Type punning for sections
            with identical format. */
        ret_type_count, error,
        DW_DLA_PUBTYPES_CONTEXT,
        DW_DLA_GLOBAL, /* We don't have DW_DLA_PUBTYPES,
            so use DW_DLA_GLOBAL. */
        DW_DLE_DEBUG_PUBTYPES_LENGTH_BAD,
        DW_DLE_DEBUG_PUBTYPES_VERSION_ERROR);
}
Exemple #7
0
int
dwarf_get_globals(Dwarf_Debug dbg,
    Dwarf_Global ** globals,
    Dwarf_Signed * return_count, Dwarf_Error * error)
{
    int res = _dwarf_load_section(dbg, &dbg->de_debug_pubnames,error);
    if (res != DW_DLV_OK) {
        return res = 0;
    }
    if (!dbg->de_debug_pubnames.dss_size) {
        return (DW_DLV_NO_ENTRY);
    }


    return _dwarf_internal_get_pubnames_like_data(dbg,
        dbg->de_debug_pubnames.dss_data,
        dbg->de_debug_pubnames.dss_size,
        globals,
        return_count,
        error,
        DW_DLA_GLOBAL_CONTEXT,
        DW_DLA_GLOBAL,
        DW_DLE_PUBNAMES_LENGTH_BAD,
        DW_DLE_PUBNAMES_VERSION_ERROR);

}
Exemple #8
0
int
_dwarf_get_string_from_tied(Dwarf_Debug dbg,
    Dwarf_Unsigned offset,
    char **return_str,
    Dwarf_Error*error)
{
    Dwarf_Debug tieddbg = 0;
    Dwarf_Small *secend = 0;
    Dwarf_Small *secbegin = 0;
    Dwarf_Small *strbegin = 0;
    int res = DW_DLV_ERROR;
    Dwarf_Error localerror = 0;

    /* Attach errors to dbg, not tieddbg. */
    tieddbg = dbg->de_tied_data.td_tied_object;
    if (!tieddbg) {
        _dwarf_error(dbg, error, DW_DLE_NO_TIED_FILE_AVAILABLE);
        return  DW_DLV_ERROR;
    }
    /* The 'offset' into .debug_str is set. */
    res = _dwarf_load_section(tieddbg, &tieddbg->de_debug_str,&localerror);
    if (res == DW_DLV_ERROR) {
        Dwarf_Unsigned lerrno = dwarf_errno(localerror);
        dwarf_dealloc(tieddbg,localerror,DW_DLA_ERROR);
        _dwarf_error(dbg,error,lerrno);
        return res;
    } else if (res == DW_DLV_NO_ENTRY) {
        return res;
    }
    if (offset >= tieddbg->de_debug_str.dss_size) {
        /*  Badly damaged DWARF here. */
        _dwarf_error(dbg, error,  DW_DLE_NO_TIED_STRING_AVAILABLE);
        return (DW_DLV_ERROR);
    }
    secbegin = tieddbg->de_debug_str.dss_data;
    strbegin= tieddbg->de_debug_str.dss_data + offset;
    secend = tieddbg->de_debug_str.dss_data +
        tieddbg->de_debug_str.dss_size;

    /*  Ensure the offset lies within the .debug_str */
    if (offset >= tieddbg->de_debug_str.dss_size) {
        _dwarf_error(dbg, error,  DW_DLE_NO_TIED_STRING_AVAILABLE);
        return (DW_DLV_ERROR);
    }
    res= _dwarf_check_string_valid(tieddbg,secbegin,strbegin, secend,
        &localerror);
    if (res == DW_DLV_ERROR) {
        Dwarf_Unsigned lerrno = dwarf_errno(localerror);
        dwarf_dealloc(tieddbg,localerror,DW_DLA_ERROR);
        _dwarf_error(dbg,error,lerrno);
        return res;
    } else if (res == DW_DLV_NO_ENTRY) {
        return res;
    }
    *return_str = (char *) (tieddbg->de_debug_str.dss_data + offset);
    return DW_DLV_OK;
}
Exemple #9
0
int
_dwarf_extract_string_offset_via_str_offsets(Dwarf_Debug dbg,
    Dwarf_Small *info_data_ptr,
    Dwarf_Half   attrnum,
    Dwarf_Half   attrform,
    Dwarf_CU_Context cu_context,
    Dwarf_Unsigned *str_sect_offset_out,
    Dwarf_Error *error)
{
    Dwarf_Unsigned offsettostr= 0;
    Dwarf_Unsigned offset_base = 0;
    Dwarf_Word leb_len = 0;
    Dwarf_Unsigned index_to_offset_entry = 0;
    Dwarf_Unsigned offsetintable = 0;
    Dwarf_Unsigned end_offsetintable = 0;
    Dwarf_Unsigned strofflen = 0;
    int res = 0;

    res = _dwarf_load_section(dbg, &dbg->de_debug_str_offsets,error);
    if (res != DW_DLV_OK) {
        return res;
    }
    index_to_offset_entry = (_dwarf_decode_u_leb128(info_data_ptr, &leb_len));
    /*  DW_FORM_GNU_str_index has no 'base' value.
        DW_FORM_strx has a base value
        for the offset table */
    if( attrform == DW_FORM_strx) {
        res = _dwarf_get_string_base_attr_value(dbg,cu_context,
            &offset_base,error);
        if (res != DW_DLV_OK) {
            return res;
        }
    }

    offsetintable = (index_to_offset_entry*cu_context->cc_length_size )
        + offset_base;
    {
        Dwarf_Unsigned fissoff = 0;
        Dwarf_Unsigned size = 0;
        fissoff = _dwarf_get_dwp_extra_offset(&cu_context->cc_dwp_offsets,
            DW_SECT_STR_OFFSETS, &size);
        offsetintable += fissoff;
    }
    end_offsetintable = offsetintable + cu_context->cc_length_size;
    /* The offsets table is a series of offset-size entries. */
    if ((end_offsetintable) >= dbg->de_debug_str_offsets.dss_size ) {
        _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_SIZE_BAD);
        return (DW_DLV_ERROR);
    }

    /* Now read the string offset from the offset table. */
    READ_UNALIGNED(dbg,offsettostr,Dwarf_Unsigned,
        dbg->de_debug_str_offsets.dss_data + offsetintable,
        cu_context->cc_length_size);
    *str_sect_offset_out = offsettostr;
    return DW_DLV_OK;
}
Exemple #10
0
/*
    This function returns the count of the number of
    aranges in the .debug_aranges section.  It sets
    aranges to point to a block of Dwarf_Arange's 
    describing the arange's.  It returns DW_DLV_ERROR
    on error.

    Must be identical in most aspects to
        dwarf_get_aranges_addr_offsets!

*/
int
dwarf_get_aranges(Dwarf_Debug dbg,
    Dwarf_Arange ** aranges,
    Dwarf_Signed * returned_count, Dwarf_Error * error)
{
    /* Count of total number of aranges. */
    Dwarf_Signed arange_count = 0;

    Dwarf_Arange *arange_block = 0;

    /* Used to chain Dwarf_Aranges structs. */
    Dwarf_Chain curr_chain = NULL;
    Dwarf_Chain prev_chain = NULL;
    Dwarf_Chain head_chain = NULL;
    Dwarf_Unsigned i = 0;
    int res = DW_DLV_ERROR;

    /* ***** BEGIN CODE ***** */

    if (dbg == NULL) {
        _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
        return (DW_DLV_ERROR);
    }

    res = _dwarf_load_section(dbg, &dbg->de_debug_aranges, error);
    if (res != DW_DLV_OK) {
        return res;
    }

    res = dwarf_get_aranges_list(dbg,&head_chain,&arange_count,error);
    if(res != DW_DLV_OK) {
        return res;
    }

    arange_block = (Dwarf_Arange *)
        _dwarf_get_alloc(dbg, DW_DLA_LIST, arange_count);
    if (arange_block == NULL) {
        _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
        return (DW_DLV_ERROR);
    }

    curr_chain = head_chain;
    for (i = 0; i < arange_count; i++) {
        *(arange_block + i) = curr_chain->ch_item;
        prev_chain = curr_chain;
        curr_chain = curr_chain->ch_next;
        dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN);
    }

    *aranges = arange_block;
    *returned_count = (arange_count);
    return DW_DLV_OK;
}
Exemple #11
0
/* Now that we delay loading .debug_info, we need to do the
   load in more places. So putting the load
   code in one place now instead of replicating it in multiple
   places.

*/
int
_dwarf_load_debug_info(Dwarf_Debug dbg, Dwarf_Error * error)
{
    int res = DW_DLV_ERROR;

    /* Testing de_debug_info.dss_data allows us to avoid testing
       de_debug_abbrev.dss_data. 
       One test instead of 2. .debug_info is useless
       without .debug_abbrev. */
    if (dbg->de_debug_info.dss_data) {
        return DW_DLV_OK;
    }

    res = _dwarf_load_section(dbg, &dbg->de_debug_abbrev,error);
    if (res != DW_DLV_OK) {
        return res;
    }
    res = _dwarf_load_section(dbg, &dbg->de_debug_info, error);
    return res;

}
Exemple #12
0
/* Helper routine  to avoid code duplication.
*/
static int
_dwarf_get_loclist_header_start(Dwarf_Debug dbg,
                                Dwarf_Attribute attr,
                                Dwarf_Unsigned * loclist_offset,
                                Dwarf_Error * error)
{
    int blkres = dwarf_formudata(attr, loclist_offset, error);
    if (blkres != DW_DLV_OK) {
        return (blkres);
    }

    if (!dbg->de_debug_loc.dss_data) {
        int secload = _dwarf_load_section(dbg, &dbg->de_debug_loc,error);
        if (secload != DW_DLV_OK) {
            return secload;
        }
    }
    return DW_DLV_OK;
}
Exemple #13
0
int
dwarf_get_str(Dwarf_Debug dbg,
   Dwarf_Off offset,
   char **string,
   Dwarf_Signed * returned_str_len, Dwarf_Error * error)
{
    int res = DW_DLV_ERROR;

    if (dbg == NULL) {
        _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
        return (DW_DLV_ERROR);
    }

    if (offset == dbg->de_debug_str.dss_size) {
        /*  Normal (if we've iterated thru the set of strings using
            dwarf_get_str and are at the end). */
        return DW_DLV_NO_ENTRY;
    }
    if (offset > dbg->de_debug_str.dss_size) {
        _dwarf_error(dbg, error, DW_DLE_DEBUG_STR_OFFSET_BAD);
        return (DW_DLV_ERROR);
    }

    if (string == NULL) {
        _dwarf_error(dbg, error, DW_DLE_STRING_PTR_NULL);
        return (DW_DLV_ERROR);
    }

    res = _dwarf_load_section(dbg, &dbg->de_debug_str,error);
    if (res != DW_DLV_OK) {
        return res;
    }
    if (!dbg->de_debug_str.dss_size) {
        return (DW_DLV_NO_ENTRY);
    }


    *string = (char *) dbg->de_debug_str.dss_data + offset;

    *returned_str_len = (strlen(*string));
    return DW_DLV_OK;
}
Exemple #14
0
/*ARGSUSED*/ int
dwarf_get_loclist_entry(Dwarf_Debug dbg,
    Dwarf_Unsigned offset,
    Dwarf_Addr * hipc_offset,
    Dwarf_Addr * lopc_offset,
    Dwarf_Ptr * data,
    Dwarf_Unsigned * entry_len,
    Dwarf_Unsigned * next_entry,
    Dwarf_Error * error)
{
    Dwarf_Block_c b;
    Dwarf_Addr lowpc = 0;
    Dwarf_Addr highpc = 0;
    Dwarf_Half address_size = 0;
    int res = DW_DLV_ERROR;

    if (!dbg->de_debug_loc.dss_data) {
        int secload = _dwarf_load_section(dbg, &dbg->de_debug_loc,error);
        if (secload != DW_DLV_OK) {
            return secload;
        }
    }

    /* FIXME: address_size is not necessarily the same in every frame. */
    address_size = dbg->de_pointer_size;
    res = _dwarf_read_loc_section(dbg,
        &b, &lowpc, &highpc, offset,
        address_size,error);
    if (res != DW_DLV_OK) {
        return res;
    }
    *hipc_offset = highpc;
    *lopc_offset = lowpc;
    *entry_len = b.bl_len;
    *data = b.bl_data;
    *next_entry = b.bl_len + b.bl_section_offset;
    return DW_DLV_OK;
}
Exemple #15
0
/* Contrary to pre-2005 documentation,
   The string pointer returned thru return_str must
   never have dwarf_dealloc() applied to it.
   Documentation fixed July 2005.
*/
int
dwarf_formstring(Dwarf_Attribute attr,
    char **return_str, Dwarf_Error * error)
{
    Dwarf_CU_Context cu_context = 0;
    Dwarf_Debug dbg = 0;
    Dwarf_Unsigned offset = 0;
    int res = DW_DLV_ERROR;
    Dwarf_Small *dataptr = 0;
    Dwarf_Small *infoptr = attr->ar_debug_ptr;
    res  = get_attr_dbg(&dbg,&cu_context,attr,error);
    if (res != DW_DLV_OK) {
        return res;
    }
    dataptr = cu_context->cc_is_info?
        dbg->de_debug_info.dss_data:
        dbg->de_debug_types.dss_data;
    if (attr->ar_attribute_form == DW_FORM_string) {

        void *begin = attr->ar_debug_ptr;

        if (0 == dbg->de_assume_string_in_bounds) {
            /* Check that string lies within current cu in .debug_info.
            */

            void *end = dataptr +
                cu_context->cc_debug_offset +
                cu_context->cc_length + cu_context->cc_length_size +
                cu_context->cc_extension_size;
            if (0 == _dwarf_string_valid(begin, end)) {
                _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_SIZE_BAD);
                return (DW_DLV_ERROR);
            }
        }
        *return_str = (char *) (begin);
        return DW_DLV_OK;
    }
    if (attr->ar_attribute_form == DW_FORM_GNU_strp_alt) {
        /* Unsure what this is really. FIXME */
        *return_str = (char *)"<DW_FORM_GNU_strp_alt not handled>";
        return DW_DLV_OK;
    }
    if (attr->ar_attribute_form == DW_FORM_GNU_str_index ||
        attr->ar_attribute_form == DW_FORM_strx) {
        Dwarf_Unsigned offsettostr= 0;
        res = _dwarf_extract_string_offset_via_str_offsets(dbg,
            infoptr,
            attr->ar_attribute,
            attr->ar_attribute_form,
            cu_context,
            &offsettostr,
            error);
        offset = offsettostr;
        /* FALL THRU */
    } else {
        if (attr->ar_attribute_form == DW_FORM_strp) {
            READ_UNALIGNED(dbg, offset, Dwarf_Unsigned,
                infoptr,
                cu_context->cc_length_size);
        }
    }
    if (attr->ar_attribute_form == DW_FORM_strp ||
        attr->ar_attribute_form == DW_FORM_GNU_str_index ||
        attr->ar_attribute_form == DW_FORM_strx) {
        /* The 'offset' into .debug_str is set. */
        res = _dwarf_load_section(dbg, &dbg->de_debug_str,error);
        if (res != DW_DLV_OK) {
            return res;
        }
        if (offset >= dbg->de_debug_str.dss_size) {
            /*  Badly damaged DWARF here. */
            _dwarf_error(dbg, error, DW_DLE_STRP_OFFSET_BAD);
            return (DW_DLV_ERROR);
        }
        if (0 == dbg->de_assume_string_in_bounds) {
            /* Check that string lies within its   .debug_str.  */
            void *end = dbg->de_debug_str.dss_data +
                dbg->de_debug_str.dss_size;
            void*begin = dbg->de_debug_str.dss_data + offset;
            if (0 == _dwarf_string_valid(begin, end)) {
                _dwarf_error(dbg, error, DW_DLE_STRP_OFFSET_BAD);
                return (DW_DLV_ERROR);
            }
        }

        /*  Ensure the offset lies within the .debug_str */
        if (offset >= dbg->de_debug_str.dss_size) {
            _dwarf_error(dbg, error, DW_DLE_DEBUG_STR_OFFSET_BAD);
            return (DW_DLV_ERROR);
        }

        *return_str = (char *) (dbg->de_debug_str.dss_data + offset);
        return DW_DLV_OK;
    }

    _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_BAD);
    return (DW_DLV_ERROR);
}
Exemple #16
0
/* 
    Although source files is supposed to return the
    source files in the compilation-unit, it does
    not look for any in the statement program.  In
    other words, it ignores those defined using the
    extended opcode DW_LNE_define_file.
*/
int
dwarf_srcfiles(Dwarf_Die die,
	       char ***srcfiles,
	       Dwarf_Signed * srcfilecount, Dwarf_Error * error)
{
    /* 
       This pointer is used to scan the portion of the .debug_line
       section for the current cu. */
    Dwarf_Small *line_ptr;

    /* 
       This points to the last byte of the .debug_line portion for the 
       current cu. */
    Dwarf_Small *line_ptr_end;

    /* 
       This points to the end of the statement program prologue for the 
       current cu, and serves to check that the prologue was correctly 
       decoded. */
    Dwarf_Small *check_line_ptr;

    /* 
       Pointer to a DW_AT_stmt_list attribute in case it exists in the 
       die. */
    Dwarf_Attribute stmt_list_attr;

    /* Pointer to DW_AT_comp_dir attribute in die. */
    Dwarf_Attribute comp_dir_attr;

    /* Pointer to name of compilation directory. */
    Dwarf_Small *comp_dir = 0;

    /* 
       Offset into .debug_line specified by a DW_AT_stmt_list
       attribute. */
    Dwarf_Unsigned line_offset = 0;

    /* Some of the fields of the statement program header. */
    Dwarf_Unsigned total_length = 0;
    Dwarf_Half version = 0;
    Dwarf_Unsigned prologue_length = 0;
    Dwarf_Small special_opcode_base= 0;

    /* File name excluding included directory. */
    char *file_name = 0;

    /* Name of directory that the file is in. */
    char *dir_name = 0;

    /* Name concatenating both directory and file name. */
    char *full_name = 0;

    /* 
       This is the directory index for the file. The compilation
       directory is 0, and the first included directory is 1. */
    Dwarf_Sword dir_index = 0;

    Dwarf_Small *include_directories = 0;

    Dwarf_Sword i = 0; 
    Dwarf_Sword file_count = 0; 
    Dwarf_Sword directories_count = 0;

    /* 
       This is the current opcode read from the statement program. */

    Dwarf_Word leb128_length;

    /* This is the length of an extended opcode instr.  */

    /* 
       This points to a block of char *'s, each of which points to a
       file name. */
    char **ret_files = 0;

    /* The Dwarf_Debug this die belongs to. */
    Dwarf_Debug dbg;

    /* Used to chain the file names. */
    Dwarf_Chain curr_chain, prev_chain, head_chain = NULL;
    int resattr;
    int lres;

    int local_length_size = 0;
    /*REFERENCED*/ /* Not used in this instance of the macro */
    int local_extension_size = 0;

    int res;

    /* ***** BEGIN CODE ***** */

    /* Reset error. */
    if (error != NULL)
	*error = NULL;

    CHECK_DIE(die, DW_DLV_ERROR)
	dbg = die->di_cu_context->cc_dbg;

    resattr = dwarf_attr(die, DW_AT_stmt_list, &stmt_list_attr, error);
    if (resattr != DW_DLV_OK) {
	return resattr;
    }
    
    if (dbg->de_debug_line_index == 0) {
	_dwarf_error(dbg, error, DW_DLE_DEBUG_LINE_NULL);
	return (DW_DLV_ERROR);
    }

    res =
       _dwarf_load_section(dbg,
		           dbg->de_debug_line_index,
			   &dbg->de_debug_line,
			   error);
    if (res != DW_DLV_OK) {
	return res;
    }

    lres = dwarf_formudata(stmt_list_attr, &line_offset, error);
    if (lres != DW_DLV_OK) {
	return lres;
    }
    if (line_offset >= dbg->de_debug_line_size) {
	_dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD);
	return (DW_DLV_ERROR);
    }
    line_ptr = dbg->de_debug_line + line_offset;
    dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR);

    /* 
       If die has DW_AT_comp_dir attribute, get the string that names
       the compilation directory. */
    resattr = dwarf_attr(die, DW_AT_comp_dir, &comp_dir_attr, error);
    if (resattr == DW_DLV_ERROR) {
	return resattr;
    }
    if (resattr == DW_DLV_OK) {
	int cres;
	char *cdir;

	cres = dwarf_formstring(comp_dir_attr, &cdir, error);
	if (cres == DW_DLV_ERROR) {
	    return cres;
	} else if (cres == DW_DLV_OK) {
	    comp_dir = (Dwarf_Small *) cdir;
	}
    }
    if (resattr == DW_DLV_OK) {
	dwarf_dealloc(dbg, comp_dir_attr, DW_DLA_ATTR);
    }

    /* 
       Following is a straightforward decoding of the statement
       program prologue information. */
    /* READ_AREA_LENGTH updates line_ptr for consumed bytes */
    READ_AREA_LENGTH(dbg, total_length, Dwarf_Unsigned,
		     line_ptr, local_length_size, local_extension_size);


    line_ptr_end = line_ptr + total_length;
    if (line_ptr_end > dbg->de_debug_line + dbg->de_debug_line_size) {
	_dwarf_error(dbg, error, DW_DLE_DEBUG_LINE_LENGTH_BAD);
	return (DW_DLV_ERROR);
    }

    READ_UNALIGNED(dbg, version, Dwarf_Half,
		   line_ptr, sizeof(Dwarf_Half));
    line_ptr += sizeof(Dwarf_Half);
    if (version != CURRENT_VERSION_STAMP &&
	version != CURRENT_VERSION_STAMP3) {
	_dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR);
	return (DW_DLV_ERROR);
    }

    READ_UNALIGNED(dbg, prologue_length, Dwarf_Unsigned,
		   line_ptr, local_length_size);
    line_ptr += local_length_size;
    check_line_ptr = line_ptr;

    /* Skip over minimum instruction length. */
    line_ptr = line_ptr + sizeof(Dwarf_Small);

    /* Skip over default_is_stmt. */
    line_ptr = line_ptr + sizeof(Dwarf_Small);

    /* Skip over line_base. */
    line_ptr = line_ptr + sizeof(Dwarf_Sbyte);

    /* Skip over line_ptr. */
    line_ptr = line_ptr + sizeof(Dwarf_Small);

    special_opcode_base = *(Dwarf_Small *) line_ptr;
    line_ptr = line_ptr + sizeof(Dwarf_Small);

    for (i = 1; i < special_opcode_base; i++) {
	/* Skip over opcode lengths for standard opcodes. */
	line_ptr = line_ptr + sizeof(Dwarf_Small);
    }

    directories_count = 0;
    include_directories = line_ptr;
    while ((*(char *) line_ptr) != '\0') {
	line_ptr = line_ptr + strlen((char *) line_ptr) + 1;
	directories_count++;
    }
    line_ptr++;

    file_count = 0;
    while (*(char *) line_ptr != '\0') {
	Dwarf_Unsigned utmp;

	file_name = (char *) line_ptr;
	line_ptr = line_ptr + strlen((char *) line_ptr) + 1;

	DECODE_LEB128_UWORD(line_ptr, utmp)
	    dir_index = (Dwarf_Sword) utmp;
	if (dir_index > directories_count) {
	    _dwarf_error(dbg, error, DW_DLE_DIR_INDEX_BAD);
	    return (DW_DLV_ERROR);
	}

	if (dir_index == 0)
	    dir_name = (char *) comp_dir;
	else {
	    dir_name = (char *) include_directories;
	    for (i = 1; i < dir_index; i++)
		/* FIX: this is probably very slow: redoing strlen!
		   davea 9/94 */
		dir_name = dir_name + strlen(dir_name) + 1;
	}

	/* dir_name can be NULL if there is no DW_AT_comp_dir */
	if ((*file_name) == '/' || dir_name == 0)
	    full_name = file_name;
	else {
	    full_name = (char *) _dwarf_get_alloc(dbg, DW_DLA_STRING,
						  strlen(dir_name) + 1 +
						  strlen(file_name) +
						  1);
	    if (full_name == NULL) {
		_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
		return (DW_DLV_ERROR);
	    }

	    strcpy(full_name, dir_name);
	    strcat(full_name, "/");
	    strcat(full_name, file_name);
	}

	/* Skip over time of last modification. */
	_dwarf_decode_u_leb128(line_ptr, &leb128_length);
	line_ptr = line_ptr + leb128_length;

	/* Skip over file length. */
	_dwarf_decode_u_leb128(line_ptr, &leb128_length);
	line_ptr = line_ptr + leb128_length;

	curr_chain =
	    (Dwarf_Chain) _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
	if (curr_chain == NULL) {
	    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
	    return (DW_DLV_ERROR);
	}

	curr_chain->ch_item = full_name;

	if (head_chain == NULL)
	    head_chain = prev_chain = curr_chain;
	else {
	    prev_chain->ch_next = curr_chain;
	    prev_chain = curr_chain;
	}

	file_count++;
    }
    line_ptr++;

    if (line_ptr != check_line_ptr + prologue_length) {
	_dwarf_error(dbg, error, DW_DLE_LINE_PROLOG_LENGTH_BAD);
	return (DW_DLV_ERROR);
    }

    if (file_count == 0) {
	*srcfiles = NULL;
	*srcfilecount = 0;
	return (DW_DLV_NO_ENTRY);
    }

    ret_files = (char **)
	_dwarf_get_alloc(dbg, DW_DLA_LIST, file_count);
    if (ret_files == NULL) {
	_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
	return (DW_DLV_ERROR);
    }

    curr_chain = head_chain;
    for (i = 0; i < file_count; i++) {
	*(ret_files + i) = curr_chain->ch_item;
	prev_chain = curr_chain;
	curr_chain = curr_chain->ch_next;
	dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN);
    }

    *srcfiles = ret_files;
    *srcfilecount = file_count;
    return (DW_DLV_OK);
}
Exemple #17
0
/*
    This function returns DW_DLV_OK if it succeeds
    and DW_DLV_ERR or DW_DLV_OK otherwise.
    count is set to the number of addresses in the
    .debug_aranges section. 
    For each address, the corresponding element in
    an array is set to the address itself(aranges) and
    the section offset (offsets).
    Must be identical in most aspects to
        dwarf_get_aranges!
*/
int
_dwarf_get_aranges_addr_offsets(Dwarf_Debug dbg,
    Dwarf_Addr ** addrs,
    Dwarf_Off ** offsets,
    Dwarf_Signed * count,
    Dwarf_Error * error)
{
    Dwarf_Unsigned i = 0;

    /* Used to chain Dwarf_Aranges structs. */
    Dwarf_Chain curr_chain = NULL;
    Dwarf_Chain prev_chain = NULL;
    Dwarf_Chain head_chain = NULL;

    Dwarf_Signed arange_count = 0;
    Dwarf_Addr *arange_addrs = 0;
    Dwarf_Off *arange_offsets = 0;

    int res = DW_DLV_ERROR;

    /* ***** BEGIN CODE ***** */

    if (error != NULL)
        *error = NULL;

    if (dbg == NULL) {
        _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
        return (DW_DLV_ERROR);
    }

    res = _dwarf_load_section(dbg, &dbg->de_debug_aranges,error);
    if (res != DW_DLV_OK) {
        return res;
    }

    res = dwarf_get_aranges_list(dbg,&head_chain,&arange_count,error);
    if(res != DW_DLV_OK) {
        return res;
    }

    arange_addrs = (Dwarf_Addr *)
        _dwarf_get_alloc(dbg, DW_DLA_ADDR, arange_count);
    if (arange_addrs == NULL) {
        _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
        return (DW_DLV_ERROR);
    }
    arange_offsets = (Dwarf_Off *)
        _dwarf_get_alloc(dbg, DW_DLA_ADDR, arange_count);
    if (arange_offsets == NULL) {
        _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
        return (DW_DLV_ERROR);
    }

    curr_chain = head_chain;
    for (i = 0; i < arange_count; i++) {
        Dwarf_Arange ar = curr_chain->ch_item;

        arange_addrs[i] = ar->ar_address;
        arange_offsets[i] = ar->ar_info_offset;
        prev_chain = curr_chain;
        curr_chain = curr_chain->ch_next;
        dwarf_dealloc(dbg, ar, DW_DLA_ARANGE);
        dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN);
    }
    *count = arange_count;
    *offsets = arange_offsets;
    *addrs = arange_addrs;
    return (DW_DLV_OK);
}
Exemple #18
0
int
dwarf_get_xu_index_header(Dwarf_Debug dbg,
    /* Pass in section_type "tu" or "cu" */
    const char *     section_type,
    Dwarf_Xu_Index_Header * xuptr,
    Dwarf_Unsigned * version,
    Dwarf_Unsigned * number_of_columns, /* L */
    Dwarf_Unsigned * number_of_CUs,     /* N */
    Dwarf_Unsigned * number_of_slots,   /* M */
    const char    ** section_name,
    Dwarf_Error    * error)
{
    Dwarf_Xu_Index_Header indexptr = 0;
    int res = DW_DLV_ERROR;
    struct Dwarf_Section_s *sect = 0;
    Dwarf_Unsigned local_version = 0;
    Dwarf_Unsigned num_col  = 0;
    Dwarf_Unsigned num_CUs  = 0;
    Dwarf_Unsigned num_slots  = 0;
    Dwarf_Small *data = 0;
    Dwarf_Unsigned tables_end_offset = 0;
    Dwarf_Unsigned hash_tab_offset = 0;
    Dwarf_Unsigned indexes_tab_offset = 0;
    Dwarf_Unsigned section_offsets_tab_offset = 0;
    Dwarf_Unsigned section_sizes_tab_offset = 0;
    unsigned datalen32 = LEN32BIT;

    if (!strcmp(section_type,"cu") ) {
        sect = &dbg->de_debug_cu_index;
    } else if (!strcmp(section_type,"tu") ) {
        sect = &dbg->de_debug_tu_index;
    } else {
        _dwarf_error(dbg, error, DW_DLE_XU_TYPE_ARG_ERROR);
        return DW_DLV_ERROR;
    }
    if (!sect->dss_size) {
        return DW_DLV_NO_ENTRY;
    }

    if (!sect->dss_data) {
        res = _dwarf_load_section(dbg, sect,error);
        if (res != DW_DLV_OK) {
            return res;
        }
    }

    data = sect->dss_data;

    if (sect->dss_size < (4*datalen32) ) {
        _dwarf_error(dbg, error, DW_DLE_ERRONEOUS_GDB_INDEX_SECTION);
        return (DW_DLV_ERROR);
    }
    READ_UNALIGNED(dbg,local_version, Dwarf_Unsigned,
        data,datalen32);
    data += datalen32;
    READ_UNALIGNED(dbg,num_col, Dwarf_Unsigned,
        data,datalen32);
    data += datalen32;
    READ_UNALIGNED(dbg,num_CUs, Dwarf_Unsigned,
        data,datalen32);
    data += datalen32;
    READ_UNALIGNED(dbg,num_slots, Dwarf_Unsigned,
        data,datalen32);
    data += datalen32;
    hash_tab_offset = datalen32*4;
    indexes_tab_offset = hash_tab_offset + (num_slots * HASHSIGNATURELEN);
    section_offsets_tab_offset = indexes_tab_offset +
        (num_slots *datalen32);

    section_sizes_tab_offset = section_offsets_tab_offset +
        ((num_CUs +1) *num_col* datalen32) ;
    tables_end_offset = section_sizes_tab_offset +
        ((num_CUs   ) *num_col* datalen32);

    if ( tables_end_offset > sect->dss_size) {
        /* Something is badly wrong here. */
        _dwarf_error(dbg, error, DW_DLE_ERRONEOUS_GDB_INDEX_SECTION);
        return (DW_DLV_ERROR);
    }


    indexptr = _dwarf_get_alloc(dbg,DW_DLA_XU_INDEX,1);
    if (indexptr == NULL) {
        _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
        return (DW_DLV_ERROR);
    }
    strcpy(indexptr->gx_type,section_type);
    indexptr->gx_dbg = dbg;
    indexptr->gx_section_length = sect->dss_size;
    indexptr->gx_section_data   = sect->dss_data;
    indexptr->gx_section_name   = sect->dss_name;
    indexptr->gx_version        = local_version;
    indexptr->gx_column_count_sections = num_col;
    indexptr->gx_units_in_index = num_CUs;
    indexptr->gx_slots_in_hash  = num_slots;
    indexptr->gx_hash_table_offset  =  hash_tab_offset;
    indexptr->gx_index_table_offset  = indexes_tab_offset;
    indexptr->gx_section_offsets_offset  = section_offsets_tab_offset;
    indexptr->gx_section_sizes_offset  = section_sizes_tab_offset;

    *xuptr             =     indexptr;
    *version           = indexptr->gx_version;
    *number_of_columns = indexptr->gx_column_count_sections;
    *number_of_CUs     = indexptr->gx_units_in_index;
    *number_of_slots   = indexptr->gx_slots_in_hash;
    *section_name      = indexptr->gx_section_name;
    return DW_DLV_OK;
}
/* Contrary to long standing documentation,
   The string pointer returned thru return_str must
   never have dwarf_dealloc() applied to it.
   Documentation fixed July 2005.
*/
int
dwarf_formstring(Dwarf_Attribute attr,
		 char **return_str, Dwarf_Error * error)
{
    Dwarf_CU_Context cu_context;
    Dwarf_Debug dbg;
    Dwarf_Unsigned offset;
    int res;

    if (attr == NULL) {
	_dwarf_error(NULL, error, DW_DLE_ATTR_NULL);
	return (DW_DLV_ERROR);
    }

    cu_context = attr->ar_cu_context;
    if (cu_context == NULL) {
	_dwarf_error(NULL, error, DW_DLE_ATTR_NO_CU_CONTEXT);
	return (DW_DLV_ERROR);
    }

    if (cu_context->cc_dbg == NULL) {
	_dwarf_error(NULL, error, DW_DLE_ATTR_DBG_NULL);
	return (DW_DLV_ERROR);
    }
    dbg = cu_context->cc_dbg;

    if (attr->ar_attribute_form == DW_FORM_string) {

	void *begin = attr->ar_debug_info_ptr;

	if (0 == dbg->de_assume_string_in_bounds) {
	    /* Check that string lies within current cu in .debug_info. 
	     */
	    void *end = dbg->de_debug_info +
		cu_context->cc_debug_info_offset +
		cu_context->cc_length + cu_context->cc_length_size +
		cu_context->cc_extension_size;
	    if (0 == _dwarf_string_valid(begin, end)) {
		_dwarf_error(dbg, error, DW_DLE_ATTR_FORM_SIZE_BAD);
		return (DW_DLV_ERROR);
	    }
	}
	*return_str = (char *) (begin);
	return DW_DLV_OK;
    }

    if (attr->ar_attribute_form == DW_FORM_strp) {
	READ_UNALIGNED(dbg, offset, Dwarf_Unsigned,
		       attr->ar_debug_info_ptr,
		       cu_context->cc_length_size);

	res =
	    _dwarf_load_section(dbg,
				dbg->de_debug_str_index,
				&dbg->de_debug_str, error);
	if (res != DW_DLV_OK) {
	    return res;
	}

	*return_str = (char *) (dbg->de_debug_str + offset);
	return DW_DLV_OK;
    }

    _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_BAD);
    return (DW_DLV_ERROR);
}
/*
        return DW_DLV_OK if ok. else DW_DLV_NO_ENTRY or DW_DLV_ERROR
        If err_count_out is non-NULL, this is a special 'check'
        call.
*/
int
_dwarf_internal_printlines(Dwarf_Die die, Dwarf_Error * error,
   int * err_count_out, int only_line_header)
{
    /* 
       This pointer is used to scan the portion of the .debug_line
       section for the current cu. */
    Dwarf_Small *line_ptr = 0;
    Dwarf_Small *orig_line_ptr = 0;

    /* 
       This points to the last byte of the .debug_line portion for the
       current cu. */
    Dwarf_Small *line_ptr_end = 0;

    /* 
       Pointer to a DW_AT_stmt_list attribute in case it exists in the
       die. */
    Dwarf_Attribute stmt_list_attr = 0;

    /* Pointer to DW_AT_comp_dir attribute in die. */
    Dwarf_Attribute comp_dir_attr = 0;

    /* Pointer to name of compilation directory. */
    Dwarf_Small *comp_dir = NULL;

    /* 
       Offset into .debug_line specified by a DW_AT_stmt_list
       attribute. */
    Dwarf_Unsigned line_offset = 0;

    struct Line_Table_Prefix_s prefix;


    /* These are the state machine state variables. */
    Dwarf_Addr address = 0;
    Dwarf_Word file = 1;
    Dwarf_Word line = 1;
    Dwarf_Word column = 0;
    Dwarf_Bool is_stmt = false;
    Dwarf_Bool basic_block = false;
    Dwarf_Bool end_sequence = false;
    Dwarf_Bool prologue_end = false;
    Dwarf_Bool epilogue_begin = false;
    Dwarf_Small isa = 0;


    Dwarf_Sword i=0;

    /* 
       This is the current opcode read from the statement program. */
    Dwarf_Small opcode=0;


    /* 
       These variables are used to decode leb128 numbers. Leb128_num
       holds the decoded number, and leb128_length is its length in
       bytes. */
    Dwarf_Word leb128_num=0;
    Dwarf_Word leb128_length=0;
    Dwarf_Sword advance_line=0;
    Dwarf_Half attrform = 0;
    /* 
       This is the operand of the latest fixed_advance_pc extended
       opcode. */
    Dwarf_Half fixed_advance_pc=0;

    /* In case there are wierd bytes 'after' the line table
     * prologue this lets us print something. This is a gcc
     * compiler bug and we expect the bytes count to be 12.
     */
    Dwarf_Small* bogus_bytes_ptr = 0;
    Dwarf_Unsigned bogus_bytes_count = 0;


    /* The Dwarf_Debug this die belongs to. */
    Dwarf_Debug dbg=0;
    int resattr = DW_DLV_ERROR;
    int lres =    DW_DLV_ERROR;
    int res  =    DW_DLV_ERROR;

    /* ***** BEGIN CODE ***** */

    if (error != NULL) {
        *error = NULL;
    }

    CHECK_DIE(die, DW_DLV_ERROR);
    dbg = die->di_cu_context->cc_dbg;

    res = _dwarf_load_section(dbg, &dbg->de_debug_line,error);
    if (res != DW_DLV_OK) {
        return res;
    }

    resattr = dwarf_attr(die, DW_AT_stmt_list, &stmt_list_attr, error);
    if (resattr != DW_DLV_OK) {
        return resattr;
    }


    /* The list of relevant FORMs is small. 
       DW_FORM_data4, DW_FORM_data8, DW_FORM_sec_offset 
    */
    lres = dwarf_whatform(stmt_list_attr,&attrform,error);
    if (lres != DW_DLV_OK) {
        return lres;
    }
    if (attrform != DW_FORM_data4 && attrform != DW_FORM_data8 &&
        attrform != DW_FORM_sec_offset ) {
        _dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD);
        return (DW_DLV_ERROR);
    }
    lres = dwarf_global_formref(stmt_list_attr, &line_offset, error);
    if (lres != DW_DLV_OK) {
        return lres;
    }

    if (line_offset >= dbg->de_debug_line.dss_size) {
        _dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD);
        return (DW_DLV_ERROR);
    }
    orig_line_ptr = dbg->de_debug_line.dss_data;
    line_ptr = dbg->de_debug_line.dss_data + line_offset;
    dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR);

    /* 
       If die has DW_AT_comp_dir attribute, get the string that names
       the compilation directory. */
    resattr = dwarf_attr(die, DW_AT_comp_dir, &comp_dir_attr, error);
    if (resattr == DW_DLV_ERROR) {
        return resattr;
    }
    if (resattr == DW_DLV_OK) {
        int cres = DW_DLV_ERROR;
        char *cdir = 0;

        cres = dwarf_formstring(comp_dir_attr, &cdir, error);
        if (cres == DW_DLV_ERROR) {
            return cres;
        } else if (cres == DW_DLV_OK) {
            comp_dir = (Dwarf_Small *) cdir;
        }
    }
    if (resattr == DW_DLV_OK) {
        dwarf_dealloc(dbg, comp_dir_attr, DW_DLA_ATTR);
    }

    dwarf_init_line_table_prefix(&prefix);
    {
        Dwarf_Small *line_ptr_out = 0;
        int dres = dwarf_read_line_table_prefix(dbg,
            line_ptr,dbg->de_debug_line.dss_size - line_offset,
            &line_ptr_out,
            &prefix, 
            &bogus_bytes_ptr,
            &bogus_bytes_count,
            error,
            err_count_out);
        if (dres == DW_DLV_ERROR) {
            dwarf_free_line_table_prefix(&prefix);
            return dres;
        }
        if (dres == DW_DLV_NO_ENTRY) {
            dwarf_free_line_table_prefix(&prefix);
            return dres;
        }
        line_ptr_end = prefix.pf_line_ptr_end;
        line_ptr = line_ptr_out;
    }
    if(only_line_header) {
         /* Just checking for header errors, nothing more here.*/
         dwarf_free_line_table_prefix(&prefix);
         return DW_DLV_OK;
    }


    printf("total line info length %ld bytes, "
           "line offset 0x%" DW_PR_DUx " %" DW_PR_DSd "\n",
           (long) prefix.pf_total_length,
           (Dwarf_Unsigned) line_offset, 
           (Dwarf_Signed) line_offset);
    printf("line table version %d\n",(int) prefix.pf_version);
    printf("line table length field length %d prologue length %d\n",
           (int)prefix.pf_length_field_length,
           (int)prefix.pf_prologue_length);
    printf("compilation_directory %s\n",
           comp_dir ? ((char *) comp_dir) : "");

    printf("  min instruction length %d\n",
           (int) prefix.pf_minimum_instruction_length);
    printf("  default is stmt        %d\n", (int)
           prefix.pf_default_is_stmt);
    printf("  line base              %d\n", (int)
           prefix.pf_line_base);
    printf("  line_range             %d\n", (int)
           prefix.pf_line_range);
    printf("  opcode base            %d\n", (int)
           prefix.pf_opcode_base);
    printf("  standard opcode count  %d\n", (int)
           prefix.pf_std_op_count);

    for (i = 1; i < prefix.pf_opcode_base; i++) {
        printf("  opcode[%2d] length  %d\n", (int) i,
               (int) prefix.pf_opcode_length_table[i - 1]);
    }
    printf("  include directories count %d\n", (int)
           prefix.pf_include_directories_count);

    
    for (i = 0; i < prefix.pf_include_directories_count; ++i) {
        printf("  include dir[%d] %s\n",
               (int) i, prefix.pf_include_directories[i]);
    }
    printf("  files count            %d\n", (int)
           prefix.pf_files_count);

    for (i = 0; i < prefix.pf_files_count; ++i) {
        struct Line_Table_File_Entry_s *lfile =
            prefix.pf_line_table_file_entries + i;

        Dwarf_Unsigned tlm2 = lfile->lte_last_modification_time;
        Dwarf_Unsigned di = lfile->lte_directory_index;
        Dwarf_Unsigned fl = lfile->lte_length_of_file;

        printf("  file[%d]  %s (file-number: %d) \n",
               (int) i, (char *) lfile->lte_filename,
               (int)(i+1));

        printf("    dir index %d\n", (int) di);
        {
            time_t tt = (time_t) tlm2;

            printf("    last time 0x%x %s",     /* ctime supplies
                                                   newline */
                   (unsigned) tlm2, ctime(&tt));
        }
        printf("    file length %ld 0x%lx\n",
               (long) fl, (unsigned long) fl);


    }


    {
        Dwarf_Unsigned offset = 0;
        if(bogus_bytes_count > 0) {
            Dwarf_Unsigned wcount = bogus_bytes_count;
            Dwarf_Unsigned boffset = bogus_bytes_ptr - orig_line_ptr;
            printf("*** DWARF CHECK: the line table prologue  header_length "
                " is %" DW_PR_DUu " too high, we pretend it is smaller."
                "Section offset: %" DW_PR_DUu " (0x%" DW_PR_DUx ") ***\n",
                wcount, boffset,boffset);
            *err_count_out += 1;
        }
        offset = line_ptr - orig_line_ptr;

        printf("  statement prog offset in section: %" DW_PR_DUu " 0x%" DW_PR_DUx "\n",
               offset, offset);
    }

    /* Initialize the part of the state machine dependent on the
       prefix.  */
    is_stmt = prefix.pf_default_is_stmt;


    print_line_header();
    /* Start of statement program.  */
    while (line_ptr < line_ptr_end) {
        int type = 0;

        printf(" [0x%06" DW_PR_DSx "] ", 
            (Dwarf_Signed) (line_ptr - orig_line_ptr));
        opcode = *(Dwarf_Small *) line_ptr;
        line_ptr++;
        /* 'type' is the output */
        WHAT_IS_OPCODE(type, opcode, prefix.pf_opcode_base,
                       prefix.pf_opcode_length_table, line_ptr,
                       prefix.pf_std_op_count);

        if (type == LOP_DISCARD) {
            int oc;
            int opcnt = prefix.pf_opcode_length_table[opcode];

            printf("*** DWARF CHECK: DISCARD standard opcode %d "
                "with %d operands: "
                "not understood.", opcode, opcnt);
            *err_count_out += 1;
            for (oc = 0; oc < opcnt; oc++) {
                /* 
                 * Read and discard operands we don't
                 * understand.
                 * Arbitrary choice of unsigned read.
                 * Signed read would work as well.
                 */
                Dwarf_Unsigned utmp2;

                DECODE_LEB128_UWORD(line_ptr, utmp2);
                printf(" %" DW_PR_DUu " (0x%" DW_PR_DUx ")",
                       (Dwarf_Unsigned) utmp2,
                       (Dwarf_Unsigned) utmp2);
            }

            printf("***\n");
            /* do nothing, necessary ops done */
        } else if (type == LOP_SPECIAL) {
            /* This op code is a special op in the object, no matter
               that it might fall into the standard op range in this
               compile Thatis, these are special opcodes between
               special_opcode_base and MAX_LINE_OP_CODE.  (including
               special_opcode_base and MAX_LINE_OP_CODE) */
            char special[50];
            unsigned origop = opcode;

            opcode = opcode - prefix.pf_opcode_base;
            address = address + prefix.pf_minimum_instruction_length *
                (opcode / prefix.pf_line_range);
            line =
                line + prefix.pf_line_base +
                opcode % prefix.pf_line_range;

            sprintf(special, "Specialop %3u", origop);
            print_line_detail(special,
                              opcode, address, (int) file, line, column,
                              is_stmt, basic_block, end_sequence,
                              prologue_end, epilogue_begin, isa);

            basic_block = false;

        } else if (type == LOP_STANDARD) {
            switch (opcode) {

            case DW_LNS_copy:{

                    print_line_detail("DW_LNS_copy",
                                      opcode, address, file, line,
                                      column, is_stmt, basic_block,
                                      end_sequence, prologue_end,
                                      epilogue_begin, isa);

                    basic_block = false;
                    break;
                }

            case DW_LNS_advance_pc:{
                    Dwarf_Unsigned utmp2;


                    DECODE_LEB128_UWORD(line_ptr, utmp2);
                    printf("DW_LNS_advance_pc val %" DW_PR_DSd " 0x%" DW_PR_DUx "\n",
                           (Dwarf_Signed) (Dwarf_Word) utmp2,
                           (Dwarf_Unsigned) (Dwarf_Word) utmp2);
                    leb128_num = (Dwarf_Word) utmp2;
                    address =
                        address +
                        prefix.pf_minimum_instruction_length *
                        leb128_num;
                    break;
                }

            case DW_LNS_advance_line:{
                    Dwarf_Signed stmp;


                    DECODE_LEB128_SWORD(line_ptr, stmp);
                    advance_line = (Dwarf_Sword) stmp;
                    printf("DW_LNS_advance_line val %" DW_PR_DSd " 0x%" DW_PR_DSx "\n",
                           (Dwarf_Signed) advance_line,
                           (Dwarf_Signed) advance_line);
                    line = line + advance_line;
                    break;
                }

            case DW_LNS_set_file:{
                    Dwarf_Unsigned utmp2;


                    DECODE_LEB128_UWORD(line_ptr, utmp2);
                    file = (Dwarf_Word) utmp2;
                    printf("DW_LNS_set_file  %ld\n", (long) file);
                    break;
                }

            case DW_LNS_set_column:{
                    Dwarf_Unsigned utmp2;


                    DECODE_LEB128_UWORD(line_ptr, utmp2);
                    column = (Dwarf_Word) utmp2;
                    printf("DW_LNS_set_column val %" DW_PR_DSd " 0x%" DW_PR_DSx "\n",
                           (Dwarf_Signed) column, (Dwarf_Signed) column);
                    break;
                }

            case DW_LNS_negate_stmt:{
                    is_stmt = !is_stmt;
                    printf("DW_LNS_negate_stmt\n");
                    break;
                }

            case DW_LNS_set_basic_block:{

                    printf("DW_LNS_set_basic_block\n");
                    basic_block = true;
                    break;
                }

            case DW_LNS_const_add_pc:{
                    opcode = MAX_LINE_OP_CODE - prefix.pf_opcode_base;
                    address =
                        address +
                        prefix.pf_minimum_instruction_length * (opcode /
                                                                prefix.
                                                                pf_line_range);

                    printf("DW_LNS_const_add_pc new address 0x%" DW_PR_DSx "\n",
                           (Dwarf_Signed) address);
                    break;
                }

            case DW_LNS_fixed_advance_pc:{

                    READ_UNALIGNED(dbg, fixed_advance_pc, Dwarf_Half,
                                   line_ptr, sizeof(Dwarf_Half));
                    line_ptr += sizeof(Dwarf_Half);
                    address = address + fixed_advance_pc;
                    printf("DW_LNS_fixed_advance_pc val %" DW_PR_DSd 
                       " 0x%" DW_PR_DSx " new address 0x%" DW_PR_DSx "\n",
                           (Dwarf_Signed) fixed_advance_pc,
                           (Dwarf_Signed) fixed_advance_pc,
                           (Dwarf_Signed) address);
                    break;
                }
            case DW_LNS_set_prologue_end:{

                    prologue_end = true;
                    printf("DW_LNS_set_prologue_end set true.\n");
                    break;


                }
                /* New in DWARF3 */
            case DW_LNS_set_epilogue_begin:{
                    epilogue_begin = true;
                    printf("DW_LNS_set_epilogue_begin set true.\n");
                    break;
                }

                /* New in DWARF3 */
            case DW_LNS_set_isa:{
                    Dwarf_Unsigned utmp2;

                    DECODE_LEB128_UWORD(line_ptr, utmp2);
                    isa = utmp2;
                    printf("DW_LNS_set_isa new value 0x%" DW_PR_DUx ".\n",
                           (Dwarf_Unsigned) utmp2);
                    if (isa != utmp2) {
                        /* The value of the isa did not fit in our
                           local so we record it wrong. declare an
                           error. */
                        dwarf_free_line_table_prefix(&prefix);

                        _dwarf_error(dbg, error,
                                     DW_DLE_LINE_NUM_OPERANDS_BAD);
                        return (DW_DLV_ERROR);
                    }
                    break;
                }
            }


        } else if (type == LOP_EXTENDED) {
            Dwarf_Unsigned utmp3 = 0;
            Dwarf_Word instr_length = 0;
            Dwarf_Small ext_opcode = 0;

            DECODE_LEB128_UWORD(line_ptr, utmp3);
            instr_length = (Dwarf_Word) utmp3;
            ext_opcode = *(Dwarf_Small *) line_ptr;
            line_ptr++;
            switch (ext_opcode) {

            case DW_LNE_end_sequence:{
                    end_sequence = true;

                    print_line_detail("DW_LNE_end_sequence extended",
                                      opcode, address, file, line,
                                      column, is_stmt, basic_block,
                                      end_sequence, prologue_end,
                                      epilogue_begin, isa);

                    address = 0;
                    file = 1;
                    line = 1;
                    column = 0;
                    is_stmt = prefix.pf_default_is_stmt;
                    basic_block = false;
                    end_sequence = false;
                    prologue_end = false;
                    epilogue_begin = false;


                    break;
                }

            case DW_LNE_set_address:{
                    {
                        READ_UNALIGNED(dbg, address, Dwarf_Addr,
                                       line_ptr, 
                                       die->di_cu_context->cc_address_size);

                        line_ptr += die->di_cu_context->cc_address_size;
                        printf("DW_LNE_set_address address 0x%" DW_PR_DUx "\n",
                               (Dwarf_Unsigned) address);
                    }

                    break;
                }

            case DW_LNE_define_file:{
                    Dwarf_Unsigned di = 0;
                    Dwarf_Unsigned tlm = 0;
                    Dwarf_Unsigned fl = 0;

                    Dwarf_Small *fn = (Dwarf_Small *) line_ptr;
                    line_ptr = line_ptr + strlen((char *) line_ptr) + 1;

                    di = _dwarf_decode_u_leb128(line_ptr,
                                                &leb128_length);
                    line_ptr = line_ptr + leb128_length;

                    tlm = _dwarf_decode_u_leb128(line_ptr,
                                                 &leb128_length);
                    line_ptr = line_ptr + leb128_length;

                    fl = _dwarf_decode_u_leb128(line_ptr,
                                                &leb128_length);
                    line_ptr = line_ptr + leb128_length;


                    printf("DW_LNE_define_file %s \n", fn);
                    printf("    dir index %d\n", (int) di);
                    {
                        time_t tt3 = (time_t) tlm;

                        /* ctime supplies newline */
                        printf("    last time 0x%x %s",
                               (unsigned) tlm, ctime(&tt3));
                    }
                    printf("    file length %ld 0x%lx\n",
                           (long) fl, (unsigned long) fl);

                    break;
                }

            default:{
                 /* This is an extended op code we do not know about,
                    other than we know now many bytes it is
                    (and the op code and the bytes of operand). */

                 Dwarf_Unsigned remaining_bytes = instr_length -1;
                 if(instr_length < 1 || remaining_bytes > DW_LNE_LEN_MAX) {
                      dwarf_free_line_table_prefix(&prefix);
                      _dwarf_error(dbg, error,
                                 DW_DLE_LINE_EXT_OPCODE_BAD);
                      return (DW_DLV_ERROR);
                 }
                 printf("DW_LNE extended op 0x%x ",ext_opcode);
                 printf("Bytecount: " DW_PR_DUu , instr_length);
                 if(remaining_bytes > 0) {
                     printf(" linedata: 0x");
                     while (remaining_bytes > 0) {
                        printf("%02x",(unsigned char)(*(line_ptr)));
                        line_ptr++;
                        remaining_bytes--;
                     }
                 }
                 printf("\n");
                }
                break;
            }

        }
    }

    dwarf_free_line_table_prefix(&prefix);
    return (DW_DLV_OK);
}
Exemple #21
0
/*
    This function returns DW_DLV_OK if it succeeds
    and DW_DLV_ERR or DW_DLV_OK otherwise.
    count is set to the number of addresses in the
    .debug_aranges section. 
    For each address, the corresponding element in
    an array is set to the address itself(aranges) and
    the section offset (offsets).
    Must be identical in most aspects to
	dwarf_get_aranges!
*/
int
_dwarf_get_aranges_addr_offsets(Dwarf_Debug dbg,
				Dwarf_Addr ** addrs,
				Dwarf_Off ** offsets,
				Dwarf_Signed * count,
				Dwarf_Error * error)
{
    /* Sweeps the .debug_aranges section. */
    Dwarf_Small *arange_ptr;
    Dwarf_Small *arange_start_ptr;

    /* 
       Start of arange header.  Used for rounding offset of arange_ptr
       to twice the tuple size.  Libdwarf requirement. */
    Dwarf_Small *header_ptr;

    /* Length of current set of aranges. */
    Dwarf_Unsigned length;

    /* Version of .debug_aranges header. */
    Dwarf_Half version;

    /* Offset of current set of aranges into .debug_info. */
    Dwarf_Off info_offset;

    /* Size in bytes of addresses in target. */
    Dwarf_Small address_size;

    /* Size in bytes of segment offsets in target. */
    Dwarf_Small segment_size;

    Dwarf_Small remainder;

    /* Count of total number of aranges. */
    Dwarf_Unsigned arange_count = 0;

    /* Start address of arange. */
    Dwarf_Addr range_address;

    /* Length of arange. */
    Dwarf_Unsigned range_length;

    Dwarf_Arange arange;

    Dwarf_Unsigned i;

    /* Used to chain Dwarf_Aranges structs. */
    Dwarf_Chain curr_chain, prev_chain, head_chain = NULL;

    Dwarf_Addr *arange_addrs;
    Dwarf_Off *arange_offsets;

    int res;

    /* ***** BEGIN CODE ***** */

    if (error != NULL)
	*error = NULL;

    if (dbg == NULL) {
	_dwarf_error(NULL, error, DW_DLE_DBG_NULL);
	return (DW_DLV_ERROR);
    }

    res =
        _dwarf_load_section(dbg,
			    dbg->de_debug_aranges_index,
			    &dbg->de_debug_aranges,
			    error);
    if (res != DW_DLV_OK) {
        return res;
    }

    arange_ptr = dbg->de_debug_aranges;
    do {
	int local_length_size;
	/*REFERENCED*/ /* not used in this instance of the macro */
	int local_extension_size;

	header_ptr = arange_ptr;


	/* READ_AREA_LENGTH updates arange_ptr for consumed bytes */
	READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned,
			 arange_ptr, local_length_size,
			 local_extension_size);


	READ_UNALIGNED(dbg, version, Dwarf_Half,
		       arange_ptr, sizeof(Dwarf_Half));
	arange_ptr += sizeof(Dwarf_Half);
	length = length - sizeof(Dwarf_Half);
	if (version != CURRENT_VERSION_STAMP) {
	    _dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR);
	    return (DW_DLV_ERROR);
	}

	READ_UNALIGNED(dbg, info_offset, Dwarf_Off,
		       arange_ptr, local_length_size);
	arange_ptr += local_length_size;
	length = length - local_length_size;
	if (info_offset >= dbg->de_debug_info_size) {
	    _dwarf_error(dbg, error, DW_DLE_ARANGE_OFFSET_BAD);
	    return (DW_DLV_ERROR);
	}

	address_size = *(Dwarf_Small *) arange_ptr;
	arange_ptr = arange_ptr + sizeof(Dwarf_Small);
	length = length - sizeof(Dwarf_Small);

	segment_size = *(Dwarf_Small *) arange_ptr;
	arange_ptr = arange_ptr + sizeof(Dwarf_Small);
	length = length - sizeof(Dwarf_Small);
	if (segment_size != 0) {
	    _dwarf_error(dbg, error, DW_DLE_SEGMENT_SIZE_BAD);
	    return (DW_DLV_ERROR);
	}

	/* Round arange_ptr offset to next multiple of address_size. */
	remainder = (Dwarf_Unsigned) (arange_ptr - header_ptr) %
	    (2 * address_size);
	if (remainder != 0) {
	    arange_ptr = arange_ptr + (2 * address_size) - remainder;
	    length = length - ((2 * address_size) - remainder);
	}

	do {
	    arange_start_ptr = arange_ptr;
	    READ_UNALIGNED(dbg, range_address, Dwarf_Addr,
			   arange_ptr, dbg->de_pointer_size);
	    arange_ptr += dbg->de_pointer_size;
	    length = length - dbg->de_pointer_size;

	    READ_UNALIGNED(dbg, range_length, Dwarf_Unsigned,
			   arange_ptr, local_length_size);
	    arange_ptr += local_length_size;
	    length = length - local_length_size;

	    if (range_address != 0 || range_length != 0) {

		arange = (Dwarf_Arange)
		    _dwarf_get_alloc(dbg, DW_DLA_ARANGE, 1);
		if (arange == NULL) {
		    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
		    return (DW_DLV_ERROR);
		}

		arange->ar_address = range_address;
		arange->ar_length = range_length;
		arange->ar_info_offset =
		    arange_start_ptr - dbg->de_debug_aranges;
		arange->ar_dbg = dbg;
		arange_count++;

		curr_chain = (Dwarf_Chain)
		    _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
		if (curr_chain == NULL) {
		    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
		    return (DW_DLV_ERROR);
		}

		curr_chain->ch_item = arange;
		if (head_chain == NULL)
		    head_chain = prev_chain = curr_chain;
		else {
		    prev_chain->ch_next = curr_chain;
		    prev_chain = curr_chain;
		}
	    }
	} while (range_address != 0 || range_length != 0);

	if (length != 0) {
	    _dwarf_error(dbg, error, DW_DLE_ARANGE_LENGTH_BAD);
	    return (DW_DLV_ERROR);
	}

    } while (arange_ptr <
	     dbg->de_debug_aranges + dbg->de_debug_aranges_size);

    if (arange_ptr !=
	dbg->de_debug_aranges + dbg->de_debug_aranges_size) {
	_dwarf_error(dbg, error, DW_DLE_ARANGE_DECODE_ERROR);
	return (DW_DLV_ERROR);
    }

    arange_addrs = (Dwarf_Addr *)
	_dwarf_get_alloc(dbg, DW_DLA_ADDR, arange_count);
    if (arange_addrs == NULL) {
	_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
	return (DW_DLV_ERROR);
    }
    arange_offsets = (Dwarf_Off *)
	_dwarf_get_alloc(dbg, DW_DLA_ADDR, arange_count);
    if (arange_offsets == NULL) {
	_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
	return (DW_DLV_ERROR);
    }

    curr_chain = head_chain;
    for (i = 0; i < arange_count; i++) {
	Dwarf_Arange ar = curr_chain->ch_item;

	arange_addrs[i] = ar->ar_address;
	arange_offsets[i] = ar->ar_info_offset;
	prev_chain = curr_chain;
	curr_chain = curr_chain->ch_next;
	dwarf_dealloc(dbg, ar, DW_DLA_ARANGE);
	dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN);
    }
    *count = arange_count;
    *offsets = arange_offsets;
    *addrs = arange_addrs;
    return (DW_DLV_OK);
}
Exemple #22
0
/*  return DW_DLV_OK if ok. else DW_DLV_NO_ENTRY or DW_DLV_ERROR
    If err_count_out is non-NULL, this is a special 'check'
    call.  */
static int
_dwarf_internal_printlines(Dwarf_Die die,
    Dwarf_Error * error,
    int * err_count_out,
    int only_line_header)
{
    /*  This pointer is used to scan the portion of the .debug_line
        section for the current cu. */
    Dwarf_Small *line_ptr = 0;
    Dwarf_Small *orig_line_ptr = 0;

    /*  Pointer to a DW_AT_stmt_list attribute in case it exists in the
        die. */
    Dwarf_Attribute stmt_list_attr = 0;

    /*  Pointer to DW_AT_comp_dir attribute in die. */
    Dwarf_Attribute comp_dir_attr = 0;

    /*  Pointer to name of compilation directory. */
    Dwarf_Small *comp_dir = NULL;

    /*  Offset into .debug_line specified by a DW_AT_stmt_list
        attribute. */
    Dwarf_Unsigned line_offset = 0;

    Dwarf_Sword i=0;
    Dwarf_Word u=0;

    /*  These variables are used to decode leb128 numbers. Leb128_num
        holds the decoded number, and leb128_length is its length in
        bytes. */
    Dwarf_Half attrform = 0;

    /*  In case there are wierd bytes 'after' the line table
        prologue this lets us print something. This is a gcc
        compiler bug and we expect the bytes count to be 12.  */
    Dwarf_Small* bogus_bytes_ptr = 0;
    Dwarf_Unsigned bogus_bytes_count = 0;
    Dwarf_Half address_size = 0;
    Dwarf_Unsigned fission_offset = 0;


    /* The Dwarf_Debug this die belongs to. */
    Dwarf_Debug dbg=0;
    Dwarf_CU_Context cu_context = 0;
    Dwarf_Line_Context line_context = 0;
    int resattr = DW_DLV_ERROR;
    int lres =    DW_DLV_ERROR;
    int res  =    DW_DLV_ERROR;
    Dwarf_Small *line_ptr_actuals  = 0;
    Dwarf_Small *line_ptr_end = 0;
    Dwarf_Small *section_start = 0;

    /* ***** BEGIN CODE ***** */

    if (error != NULL) {
        *error = NULL;
    }

    CHECK_DIE(die, DW_DLV_ERROR);
    cu_context = die->di_cu_context;
    dbg = cu_context->cc_dbg;

    res = _dwarf_load_section(dbg, &dbg->de_debug_line,error);
    if (res != DW_DLV_OK) {
        return res;
    }
    if (!dbg->de_debug_line.dss_size) {
        return (DW_DLV_NO_ENTRY);
    }

    address_size = _dwarf_get_address_size(dbg, die);
    resattr = dwarf_attr(die, DW_AT_stmt_list, &stmt_list_attr, error);
    if (resattr != DW_DLV_OK) {
        return resattr;
    }


    /*  The list of relevant FORMs is small.
        DW_FORM_data4, DW_FORM_data8, DW_FORM_sec_offset
    */
    lres = dwarf_whatform(stmt_list_attr,&attrform,error);
    if (lres != DW_DLV_OK) {
        return lres;
    }
    if (attrform != DW_FORM_data4 && attrform != DW_FORM_data8 &&
        attrform != DW_FORM_sec_offset ) {
        _dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD);
        return (DW_DLV_ERROR);
    }
    lres = dwarf_global_formref(stmt_list_attr, &line_offset, error);
    if (lres != DW_DLV_OK) {
        return lres;
    }

    if (line_offset >= dbg->de_debug_line.dss_size) {
        _dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD);
        return (DW_DLV_ERROR);
    }
    section_start =  dbg->de_debug_line.dss_data;
    {
        Dwarf_Unsigned fission_size = 0;
        int resfis = _dwarf_get_fission_addition_die(die, DW_SECT_LINE,
            &fission_offset,&fission_size,error);
        if(resfis != DW_DLV_OK) {
            return resfis;
        }
    }

    orig_line_ptr = section_start + line_offset + fission_offset;
    line_ptr = orig_line_ptr;
    dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR);

    /*  If die has DW_AT_comp_dir attribute, get the string that names
        the compilation directory. */
    resattr = dwarf_attr(die, DW_AT_comp_dir, &comp_dir_attr, error);
    if (resattr == DW_DLV_ERROR) {
        return resattr;
    }
    if (resattr == DW_DLV_OK) {
        int cres = DW_DLV_ERROR;
        char *cdir = 0;

        cres = dwarf_formstring(comp_dir_attr, &cdir, error);
        if (cres == DW_DLV_ERROR) {
            return cres;
        } else if (cres == DW_DLV_OK) {
            comp_dir = (Dwarf_Small *) cdir;
        }
    }
    if (resattr == DW_DLV_OK) {
        dwarf_dealloc(dbg, comp_dir_attr, DW_DLA_ATTR);
    }
    line_context = (Dwarf_Line_Context)
        _dwarf_get_alloc(dbg, DW_DLA_LINE_CONTEXT, 1);
    if (line_context == NULL) {
        _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
        return (DW_DLV_ERROR);
    }
    {
        Dwarf_Small *newlinep = 0;
        int dres = _dwarf_read_line_table_header(dbg,
            cu_context,
            section_start,
            line_ptr,
            dbg->de_debug_line.dss_size,
            &newlinep,
            line_context,
            &bogus_bytes_ptr,
            &bogus_bytes_count,
            error,
            err_count_out);
        if (dres == DW_DLV_ERROR) {
            dwarf_srclines_dealloc_b(line_context);
            return dres;
        }
        if (dres == DW_DLV_NO_ENTRY) {
            dwarf_srclines_dealloc_b(line_context);
            return dres;
        }
        line_ptr_end = line_context->lc_line_ptr_end;
        line_ptr = newlinep;
        if (line_context->lc_actuals_table_offset > 0) {
            line_ptr_actuals = line_context->lc_line_prologue_start +
                line_context->lc_actuals_table_offset;
        }
    }
    line_context->lc_compilation_directory = comp_dir;
    if (only_line_header) {
        /* Just checking for header errors, nothing more here.*/
        dwarf_srclines_dealloc_b(line_context);
        return DW_DLV_OK;
    }

    dwarf_printf(dbg,
        "total line info length %ld bytes,"
        " line offset 0x%" DW_PR_XZEROS DW_PR_DUx
        " %" DW_PR_DUu "\n",
        (long) line_context->lc_total_length,
        line_context->lc_section_offset,
        line_context->lc_section_offset);
    if (line_context->lc_version_number <= DW_LINE_VERSION5) {
        dwarf_printf(dbg,
            "line table version %d\n",(int) line_context->lc_version_number);
    } else {
        dwarf_printf(dbg,
            "line table version 0x%x\n",(int) line_context->lc_version_number);
    }
    dwarf_printf(dbg,
        "line table length field length %d prologue length %d\n",
        (int)line_context->lc_length_field_length,
        (int)line_context->lc_prologue_length);
    dwarf_printf(dbg,
        "compilation_directory %s\n",
        comp_dir ? ((char *) comp_dir) : "");

    dwarf_printf(dbg,
        "  min instruction length %d\n",
        (int) line_context->lc_minimum_instruction_length);
    if (line_context->lc_version_number == EXPERIMENTAL_LINE_TABLES_VERSION) {
        dwarf_printf(dbg, "  actuals table offset "
            "0x%" DW_PR_XZEROS DW_PR_DUx
            " logicals table offset "
            "0x%" DW_PR_XZEROS DW_PR_DUx "\n",
            line_context->lc_actuals_table_offset,
            line_context->lc_logicals_table_offset);
    }
    if (line_context->lc_version_number == DW_LINE_VERSION5) {
        dwarf_printf(dbg,
            "  segment selector size %d\n",
            (int) line_context->lc_segment_selector_size);
        dwarf_printf(dbg,
            "  address    size       %d\n",
            (int) line_context->lc_address_size);
    }
    dwarf_printf(dbg,
        "  default is stmt        %d\n",(int)line_context->lc_default_is_stmt);
    dwarf_printf(dbg,
        "  line base              %d\n",(int)line_context->lc_line_base);
    dwarf_printf(dbg,
        "  line_range             %d\n",(int)line_context->lc_line_range);
    dwarf_printf(dbg,
        "  opcode base            %d\n",(int)line_context->lc_opcode_base);
    dwarf_printf(dbg,
        "  standard opcode count  %d\n",(int)line_context->lc_std_op_count);

    for (i = 1; i < line_context->lc_opcode_base; i++) {
        dwarf_printf(dbg,
            "  opcode[%2d] length  %d\n", (int) i,
            (int) line_context->lc_opcode_length_table[i - 1]);
    }
    dwarf_printf(dbg,
        "  include directories count %d\n",
        (int) line_context->lc_include_directories_count);
    for (u = 0; u < line_context->lc_include_directories_count; ++u) {
        dwarf_printf(dbg,
            "  include dir[%u] %s\n",
            (int) u, line_context->lc_include_directories[u]);
    }
    dwarf_printf(dbg,
        "  files count            %d\n",
        (int) line_context->lc_file_entry_count);

    if (line_context->lc_file_entry_count) {
        Dwarf_File_Entry fe = line_context->lc_file_entries;
        Dwarf_File_Entry fe2 = fe;
        unsigned fiu = 0;

        for (fiu = 0 ; fe2 ; fe2 = fe->fi_next,++fiu ) {
            Dwarf_Unsigned tlm2 = 0;
            Dwarf_Unsigned di = 0;
            Dwarf_Unsigned fl = 0;

            fe = fe2;
            tlm2 = fe->fi_time_last_mod;
            di = fe->fi_dir_index;
            fl = fe->fi_file_length;

            dwarf_printf(dbg,
                "  file[%u]  %s (file-number: %u) \n",
                (unsigned) fiu, (char *) fe->fi_file_name,
                (unsigned)(fiu+1));
            dwarf_printf(dbg,
                "    dir index %d\n", (int) di);
            {
                time_t tt = (time_t) tlm2;

                /* ctime supplies newline */
                dwarf_printf(dbg,
                    "    last time 0x%x %s",
                    (unsigned) tlm2, ctime(&tt));
                }
            dwarf_printf(dbg,
                "    file length %ld 0x%lx\n",
                (long) fl, (unsigned long) fl);
        }
    }

    if (line_context->lc_version_number == EXPERIMENTAL_LINE_TABLES_VERSION) {
        /*  Print the subprograms list. */
        Dwarf_Unsigned count = line_context->lc_subprogs_count;
        Dwarf_Unsigned exu = 0;
        Dwarf_Subprog_Entry sub = line_context->lc_subprogs;
        dwarf_printf(dbg,"  subprograms count"
            " %" DW_PR_DUu "\n",count);
        if (count > 0) {
            dwarf_printf(dbg,"    indx  file   line   name\n");
        }
        for (exu = 0 ; exu < count ; exu++,sub++) {
            dwarf_printf(dbg,"    [%2" DW_PR_DUu "] %4" DW_PR_DUu
                "    %4" DW_PR_DUu " %s\n",
                exu+1,
                sub->ds_decl_file,
                sub->ds_decl_line,
                sub->ds_subprog_name);
        }
    }
    {
        Dwarf_Unsigned offset = 0;
        if (bogus_bytes_count > 0) {
            Dwarf_Unsigned wcount = bogus_bytes_count;
            Dwarf_Unsigned boffset = bogus_bytes_ptr - section_start;
            dwarf_printf(dbg,
                "*** DWARF CHECK: the line table prologue  header_length "
                " is %" DW_PR_DUu " too high, we pretend it is smaller."
                "Section offset: 0x%" DW_PR_XZEROS DW_PR_DUx
                " (%" DW_PR_DUu ") ***\n",
                wcount, boffset,boffset);
            *err_count_out += 1;
        }
        offset = line_ptr - section_start;
        dwarf_printf(dbg,
            "  statement prog offset in section: 0x%"
            DW_PR_XZEROS DW_PR_DUx " (%" DW_PR_DUu ")\n",
            offset, offset);
    }

    {
        Dwarf_Bool doaddrs = false;
        Dwarf_Bool dolines = true;

        _dwarf_print_line_context_record(dbg,line_context);
        if (!line_ptr_actuals) {
            /* Normal single level line table. */

            Dwarf_Bool is_single_table = true;
            Dwarf_Bool is_actuals_table = false;
            print_line_header(dbg, is_single_table, is_actuals_table);
            res = read_line_table_program(dbg,
                line_ptr, line_ptr_end, orig_line_ptr,
                section_start,
                line_context,
                address_size, doaddrs, dolines,
                is_single_table,
                is_actuals_table,
                error,
                err_count_out);
            if (res != DW_DLV_OK) {
                dwarf_srclines_dealloc_b(line_context);
                return res;
            }
        } else {
            Dwarf_Bool is_single_table = false;
            Dwarf_Bool is_actuals_table = false;
            if (line_context->lc_version_number !=
                EXPERIMENTAL_LINE_TABLES_VERSION) {
                dwarf_srclines_dealloc_b(line_context);
                _dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR);
                return (DW_DLV_ERROR);
            }
            /* Read Logicals */
            print_line_header(dbg, is_single_table, is_actuals_table);
            res = read_line_table_program(dbg,
                line_ptr, line_ptr_actuals, orig_line_ptr,
                section_start,
                line_context,
                address_size, doaddrs, dolines,
                is_single_table,
                is_actuals_table,
                error,err_count_out);
            if (res != DW_DLV_OK) {
                dwarf_srclines_dealloc_b(line_context);
                return res;
            }
            if (line_context->lc_actuals_table_offset > 0) {
                is_actuals_table = true;
                /* Read Actuals */

                print_line_header(dbg, is_single_table, is_actuals_table);
                res = read_line_table_program(dbg,
                    line_ptr_actuals, line_ptr_end, orig_line_ptr,
                    section_start,
                    line_context,
                    address_size, doaddrs, dolines,
                    is_single_table,
                    is_actuals_table,
                    error,
                    err_count_out);
                if (res != DW_DLV_OK) {
                    dwarf_srclines_dealloc_b(line_context);
                    return res;
                }
            }
        }
    }
    dwarf_srclines_dealloc_b(line_context);
    return DW_DLV_OK;
}
Exemple #23
0
/* Contrary to long standing documentation,
   The string pointer returned thru return_str must
   never have dwarf_dealloc() applied to it.
   Documentation fixed July 2005.
*/
int
dwarf_formstring(Dwarf_Attribute attr,
    char **return_str, Dwarf_Error * error)
{
    Dwarf_CU_Context cu_context = 0;
    Dwarf_Debug dbg = 0;
    Dwarf_Unsigned offset = 0;
    int res = DW_DLV_ERROR;

    res  = get_attr_dbg(&dbg,&cu_context,attr,error);
    if (res != DW_DLV_OK) { 
        return res;
    } 
    if (attr->ar_attribute_form == DW_FORM_string) {

        void *begin = attr->ar_debug_ptr;

        if (0 == dbg->de_assume_string_in_bounds) {
            /* Check that string lies within current cu in .debug_info. 
            */
            void *end = dbg->de_debug_info.dss_data +
                cu_context->cc_debug_offset +
                cu_context->cc_length + cu_context->cc_length_size +
                cu_context->cc_extension_size;
            if (0 == _dwarf_string_valid(begin, end)) {
                _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_SIZE_BAD);
                return (DW_DLV_ERROR);
            }
        }
        *return_str = (char *) (begin);
        return DW_DLV_OK;
    }

    if (attr->ar_attribute_form == DW_FORM_strp) {
        READ_UNALIGNED(dbg, offset, Dwarf_Unsigned,
            attr->ar_debug_ptr,
            cu_context->cc_length_size);

        res = _dwarf_load_section(dbg, &dbg->de_debug_str,error);
        if (res != DW_DLV_OK) {
            return res;
        }
        if (0 == dbg->de_assume_string_in_bounds) {
            /* Check that string lies within current cu in .debug_info. 
            */
            void *end = dbg->de_debug_str.dss_data + 
                dbg->de_debug_str.dss_size;
            void*begin = dbg->de_debug_str.dss_data + offset;
            if (0 == _dwarf_string_valid(begin, end)) {
                _dwarf_error(dbg, error, DW_DLE_STRP_OFFSET_BAD);
                return (DW_DLV_ERROR);
            }
        }

        /*  Ensure the offset lies within the .debug_str */
        if (offset >= dbg->de_debug_str.dss_size) {
            _dwarf_error(dbg, error, DW_DLE_DEBUG_STR_OFFSET_BAD);
            return (DW_DLV_ERROR);
        }

        *return_str = (char *) (dbg->de_debug_str.dss_data + offset);
        return DW_DLV_OK;
    }

    _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_BAD);
    return (DW_DLV_ERROR);
}
Exemple #24
0
int dwarf_get_ranges_a(Dwarf_Debug dbg,
    Dwarf_Off rangesoffset,
    Dwarf_Die die,
    Dwarf_Ranges ** rangesbuf,
    Dwarf_Signed * listlen,
    Dwarf_Unsigned * bytecount,
    Dwarf_Error * error)
{
    Dwarf_Small *rangeptr = 0;
    Dwarf_Small *beginrangeptr = 0;
    Dwarf_Small *section_end = 0;
    unsigned entry_count = 0;
    struct ranges_entry *base = 0;
    struct ranges_entry *last = 0;
    struct ranges_entry *curre = 0;
    Dwarf_Ranges * ranges_data_out = 0;
    unsigned copyindex = 0;
    Dwarf_Half address_size = 0;
    int res = DW_DLV_ERROR;
    Dwarf_Unsigned rangebase = 0;
    Dwarf_Debug localdbg = dbg;
    Dwarf_Error localerror = 0;

    if (die &&localdbg->de_tied_data.td_tied_object) {
        /*  ASSERT: localdbg->de_debug_ranges is missing: DW_DLV_NO_ENTRY.
            So lets not look in dbg. */
        Dwarf_CU_Context context = 0;
        int restied = 0;

        context = die->di_cu_context;
        restied = _dwarf_get_ranges_base_attr_from_tied(localdbg,
            context,
            &rangebase,
            error);
        if (restied == DW_DLV_ERROR ) {
            if(!error) {
                return restied;
            }
            dwarf_dealloc(localdbg,*error,DW_DLA_ERROR);
            *error = 0;
            /* Nothing else to do. Look in original dbg. */
        } else if (restied == DW_DLV_NO_ENTRY ) {
            /* Nothing else to do. Look in original dbg. */
        } else {
            /*  Ranges are never in a split dwarf object.
                In the base object
                instead. Use the tied_object */
            localdbg = dbg->de_tied_data.td_tied_object;
        }
    }


    res = _dwarf_load_section(localdbg, &localdbg->de_debug_ranges,&localerror);
    if (res == DW_DLV_ERROR) {
        _dwarf_error_mv_s_to_t(localdbg,&localerror,dbg,error);
        return res;
    } else if (res == DW_DLV_NO_ENTRY) {
        return res;
    }

    if ((rangesoffset +rangebase) >= localdbg->de_debug_ranges.dss_size) {
        _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OFFSET_BAD);
        return (DW_DLV_ERROR);

    }
    address_size = _dwarf_get_address_size(localdbg, die);
    section_end = localdbg->de_debug_ranges.dss_data +
        localdbg->de_debug_ranges.dss_size;
    rangeptr = localdbg->de_debug_ranges.dss_data + rangesoffset+rangebase;
    beginrangeptr = rangeptr;

    for (;;) {
        struct ranges_entry * re = 0;

        if (rangeptr == section_end) {
            break;
        }
        if (rangeptr  > section_end) {
            free_allocated_ranges(base);
            _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OFFSET_BAD);
            return (DW_DLV_ERROR);
            break;
        }
        re = calloc(sizeof(struct ranges_entry),1);
        if (!re) {
            free_allocated_ranges(base);
            _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OUT_OF_MEM);
            return (DW_DLV_ERROR);
        }
        if ((rangeptr + (2*address_size)) > section_end) {
            free(re);
            free_allocated_ranges(base);
            _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OFFSET_BAD);
            return (DW_DLV_ERROR);
        }
        entry_count++;
        res = read_unaligned_addr_check(localdbg,&re->cur.dwr_addr1,
            rangeptr, address_size,error,section_end);
        if (res != DW_DLV_OK) {
            free(re);
            free_allocated_ranges(base);
            return res;
        }
        rangeptr +=  address_size;
        res = read_unaligned_addr_check(localdbg,&re->cur.dwr_addr2,
            rangeptr, address_size,error,section_end);
        if (res != DW_DLV_OK) {
            free(re);
            free_allocated_ranges(base);
            return res;
        }
        rangeptr +=  address_size;
        if (!base) {
            base = re;
            last = re;
        } else {
            last->next = re;
            last = re;
        }
        if (re->cur.dwr_addr1 == 0 && re->cur.dwr_addr2 == 0) {
            re->cur.dwr_type =  DW_RANGES_END;
            break;
        } else if (re->cur.dwr_addr1 == MAX_ADDR) {
            re->cur.dwr_type =  DW_RANGES_ADDRESS_SELECTION;
        } else {
            re->cur.dwr_type =  DW_RANGES_ENTRY;
        }
    }

    /* We return ranges on dbg, so use that to allocate. */
    ranges_data_out =   (Dwarf_Ranges *)
        _dwarf_get_alloc(dbg,DW_DLA_RANGES,entry_count);
    if (!ranges_data_out) {
        /* Error, apply to original, not local dbg. */
        free_allocated_ranges(base);
        _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OUT_OF_MEM);
        return (DW_DLV_ERROR);
    }
    curre = base;
    *rangesbuf = ranges_data_out;
    *listlen = entry_count;
    for (copyindex = 0; curre && (copyindex < entry_count);
        ++copyindex,++ranges_data_out) {

        *ranges_data_out = curre->cur;
        curre = curre->next;
    }
    /* ASSERT: curre == NULL */
    free_allocated_ranges(base);
    base = 0;
    /* Callers will often not care about the bytes used. */
    if (bytecount) {
        *bytecount = rangeptr - beginrangeptr;
    }
    return DW_DLV_OK;
}
Exemple #25
0
int
dwarf_get_macro_details(Dwarf_Debug dbg,
                        Dwarf_Off macro_offset,
                        Dwarf_Unsigned maximum_count,
                        Dwarf_Signed * entry_count,
                        Dwarf_Macro_Details ** details,
                        Dwarf_Error * error)
{
    Dwarf_Small *macro_base = 0;
    Dwarf_Small *macro_end = 0;
    Dwarf_Small *pnext = 0;
    Dwarf_Unsigned endloc = 0;
    unsigned char uc = 0;
    unsigned long depth = 0;
    /* By section 6.3.2 Dwarf3 draft 8/9,
    the base file should appear as
    DW_MACINFO_start_file. See
    http://gcc.gnu.org/ml/gcc-bugs/2005-02/msg03442.html
    on "[Bug debug/20253] New: [3.4/4.0 regression]:
    Macro debug info broken due to lexer change" for how
    gcc is broken in some versions. We no longer use
    depth as a stopping point, it's not needed as a
    stopping point anyway.  */
    int res = 0;
    /* count space used by strings */
    unsigned long str_space = 0;
    int done = 0;
    unsigned long space_needed = 0;
    unsigned long string_offset = 0;
    Dwarf_Small *return_data = 0;
    Dwarf_Small *pdata = 0;
    unsigned long final_count = 0;
    Dwarf_Signed fileindex = -1;
    Dwarf_Small *latest_str_loc = 0;
    struct macro_stack_s msdata;

    unsigned long count = 0;
    unsigned long max_count = (unsigned long) maximum_count;

    _dwarf_reset_index_macro_stack(&msdata);
    if (dbg == NULL) {
        _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
        free_macro_stack(dbg,&msdata);
        return (DW_DLV_ERROR);
    }

    res = _dwarf_load_section(dbg, &dbg->de_debug_macinfo,error);
    if (res != DW_DLV_OK) {
        free_macro_stack(dbg,&msdata);
        return res;
    }
    if (!dbg->de_debug_abbrev.dss_size) {
        free_macro_stack(dbg,&msdata);
        return (DW_DLV_NO_ENTRY);
    }

    macro_base = dbg->de_debug_macinfo.dss_data;
    if (macro_base == NULL) {
        free_macro_stack(dbg,&msdata);
        return (DW_DLV_NO_ENTRY);
    }
    if (macro_offset >= dbg->de_debug_macinfo.dss_size) {
        free_macro_stack(dbg,&msdata);
        return (DW_DLV_NO_ENTRY);
    }
    macro_end = macro_base + dbg->de_debug_macinfo.dss_size;
    /*   FIXME debugfission is NOT handled here.  */

    pnext = macro_base + macro_offset;
    if (maximum_count == 0) {
        max_count = ULONG_MAX;
    }


    /* how many entries and how much space will they take? */

    endloc = (pnext - macro_base);
    if (endloc >= dbg->de_debug_macinfo.dss_size) {
        if (endloc == dbg->de_debug_macinfo.dss_size) {
            /* normal: found last entry */
            free_macro_stack(dbg,&msdata);
            return DW_DLV_NO_ENTRY;
        }
        _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_LENGTH_BAD);
        free_macro_stack(dbg,&msdata);
        return (DW_DLV_ERROR);
    }
    for (count = 0; !done && count < max_count; ++count) {
        unsigned long slen = 0;

        /* Set but not used */
        UNUSEDARG Dwarf_Unsigned utemp = 0;

        uc = *pnext;
        ++pnext;                /* get past the type code */
        switch (uc) {
        case DW_MACINFO_define:
        case DW_MACINFO_undef:
        /* line, string */
        case DW_MACINFO_vendor_ext:
            /* number, string */
            DECODE_LEB128_UWORD_CK(pnext,utemp,dbg,error,
                                   macro_end);
            if (((Dwarf_Unsigned)(pnext - macro_base)) >=
                    dbg->de_debug_macinfo.dss_size) {
                free_macro_stack(dbg,&msdata);
                _dwarf_error(dbg, error,
                             DW_DLE_DEBUG_MACRO_INCONSISTENT);
                return (DW_DLV_ERROR);
            }
            res = _dwarf_check_string_valid(dbg,
                                            macro_base,pnext,macro_end,error);
            if (res != DW_DLV_OK) {
                return res;
            }
            slen = strlen((char *) pnext) + 1;
            pnext += slen;
            if (((Dwarf_Unsigned)(pnext - macro_base)) >=
                    dbg->de_debug_macinfo.dss_size) {
                free_macro_stack(dbg,&msdata);
                _dwarf_error(dbg, error,
                             DW_DLE_DEBUG_MACRO_INCONSISTENT);
                return (DW_DLV_ERROR);
            }
            str_space += slen;
            break;
        case DW_MACINFO_start_file:
            /* line, file index */
            DECODE_LEB128_UWORD_CK(pnext,utemp,dbg,error,
                                   macro_end);
            if (((Dwarf_Unsigned)(pnext - macro_base)) >=
                    dbg->de_debug_macinfo.dss_size) {
                free_macro_stack(dbg,&msdata);
                _dwarf_error(dbg, error,
                             DW_DLE_DEBUG_MACRO_INCONSISTENT);
                return (DW_DLV_ERROR);
            }
            DECODE_LEB128_UWORD_CK(pnext,utemp,dbg,error,
                                   macro_end);
            if (((Dwarf_Unsigned)(pnext - macro_base)) >=
                    dbg->de_debug_macinfo.dss_size) {
                free_macro_stack(dbg,&msdata);
                _dwarf_error(dbg, error,
                             DW_DLE_DEBUG_MACRO_INCONSISTENT);
                return (DW_DLV_ERROR);
            }
            ++depth;
            break;

        case DW_MACINFO_end_file:
            if (--depth == 0) {
                /*  done = 1; no, do not stop here, at least one gcc had
                    the wrong depth settings in the gcc 3.4 timeframe. */
            }
            /* no string or number here */
            break;
        case 0:
            /* end of cu's entries */
            done = 1;
            break;
        default:
            free_macro_stack(dbg,&msdata);
            _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_INCONSISTENT);
            return (DW_DLV_ERROR);
            /* bogus macinfo! */
        }

        endloc = (pnext - macro_base);
        if (endloc == dbg->de_debug_macinfo.dss_size) {
            done = 1;
        } else if (endloc > dbg->de_debug_macinfo.dss_size) {
            _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_LENGTH_BAD);
            free_macro_stack(dbg,&msdata);
            return (DW_DLV_ERROR);
        }
    }
    if (count == 0) {
        free_macro_stack(dbg,&msdata);
        _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_INTERNAL_ERR);
        return (DW_DLV_ERROR);
    }

    /*  We have 'count' array entries to allocate and str_space bytes of
        string space to provide for. */

    string_offset = count * sizeof(Dwarf_Macro_Details);

    /* extra 2 not really needed */
    space_needed = string_offset + str_space + 2;
    return_data = pdata =
                      (Dwarf_Small *)_dwarf_get_alloc(dbg, DW_DLA_STRING, space_needed);
    latest_str_loc = pdata + string_offset;
    if (pdata == 0) {
        free_macro_stack(dbg,&msdata);
        _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_MALLOC_SPACE);
        return (DW_DLV_ERROR);
    }
    pnext = macro_base + macro_offset;

    done = 0;

    /* A series ends with a type code of 0. */

    for (final_count = 0; !done && final_count < count; ++final_count) {
        unsigned long slen = 0;
        Dwarf_Unsigned v1 = 0;
        Dwarf_Macro_Details *pdmd = (Dwarf_Macro_Details *) (pdata +
                                    (final_count * sizeof (Dwarf_Macro_Details)));

        endloc = (pnext - macro_base);
        if (endloc > dbg->de_debug_macinfo.dss_size) {
            free_macro_stack(dbg,&msdata);
            _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_LENGTH_BAD);
            return (DW_DLV_ERROR);
        }
        uc = *pnext;
        pdmd->dmd_offset = (pnext - macro_base);
        pdmd->dmd_type = uc;
        pdmd->dmd_fileindex = fileindex;
        pdmd->dmd_lineno = 0;
        pdmd->dmd_macro = 0;
        ++pnext;                /* get past the type code */
        switch (uc) {
        case DW_MACINFO_define:
        case DW_MACINFO_undef:
        /* line, string */
        case DW_MACINFO_vendor_ext:
            /* number, string */
            DECODE_LEB128_UWORD_CK(pnext,v1,dbg,error,
                                   macro_end);
            pdmd->dmd_lineno = v1;

            if (((Dwarf_Unsigned)(pnext - macro_base)) >=
                    dbg->de_debug_macinfo.dss_size) {
                free_macro_stack(dbg,&msdata);
                dwarf_dealloc(dbg, return_data, DW_DLA_STRING);
                _dwarf_error(dbg, error,
                             DW_DLE_DEBUG_MACRO_INCONSISTENT);
                return (DW_DLV_ERROR);
            }
            res = _dwarf_check_string_valid(dbg,
                                            macro_base,pnext,macro_end,error);
            if (res != DW_DLV_OK) {
                return res;
            }
            slen = strlen((char *) pnext) + 1;
            strcpy((char *) latest_str_loc, (char *) pnext);
            pdmd->dmd_macro = (char *) latest_str_loc;
            latest_str_loc += slen;
            pnext += slen;
            if (((Dwarf_Unsigned)(pnext - macro_base)) >=
                    dbg->de_debug_macinfo.dss_size) {
                free_macro_stack(dbg,&msdata);
                dwarf_dealloc(dbg, return_data, DW_DLA_STRING);
                _dwarf_error(dbg, error,
                             DW_DLE_DEBUG_MACRO_INCONSISTENT);
                return (DW_DLV_ERROR);
            }
            break;
        case DW_MACINFO_start_file:
            /* Line, file index */
            DECODE_LEB128_UWORD_CK(pnext,v1,dbg,error,
                                   macro_end);
            pdmd->dmd_lineno = v1;
            if (((Dwarf_Unsigned)(pnext - macro_base)) >=
                    dbg->de_debug_macinfo.dss_size) {
                free_macro_stack(dbg,&msdata);
                dwarf_dealloc(dbg, return_data, DW_DLA_STRING);
                _dwarf_error(dbg, error,
                             DW_DLE_DEBUG_MACRO_INCONSISTENT);
                return (DW_DLV_ERROR);
            }
            DECODE_LEB128_UWORD_CK(pnext,v1,dbg,error,
                                   macro_end);
            pdmd->dmd_fileindex = v1;
            (void) _dwarf_macro_stack_push_index(dbg, fileindex,
                                                 &msdata);
            /*  We ignore the error, we just let fileindex ** be -1 when
                we pop this one. */
            fileindex = v1;
            if (((Dwarf_Unsigned)(pnext - macro_base)) >=
                    dbg->de_debug_macinfo.dss_size) {
                free_macro_stack(dbg,&msdata);
                dwarf_dealloc(dbg, return_data, DW_DLA_STRING);
                _dwarf_error(dbg, error,
                             DW_DLE_DEBUG_MACRO_INCONSISTENT);
                return (DW_DLV_ERROR);
            }
            break;

        case DW_MACINFO_end_file:
            fileindex = _dwarf_macro_stack_pop_index(&msdata);
            break;              /* no string or number here */
        case 0:
            /* Type code of 0 means the end of cu's entries. */
            done = 1;
            break;
        default:
            /* Bogus macinfo! */
            dwarf_dealloc(dbg, return_data, DW_DLA_STRING);
            free_macro_stack(dbg,&msdata);
            _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_INCONSISTENT);
            return (DW_DLV_ERROR);
        }
    }
    *entry_count = count;
    *details = (Dwarf_Macro_Details *) return_data;
    free_macro_stack(dbg,&msdata);
    return DW_DLV_OK;
}
Exemple #26
0
int dwarf_get_ranges_a(Dwarf_Debug dbg,
    Dwarf_Off rangesoffset,
    Dwarf_Die die,
    Dwarf_Ranges ** rangesbuf,
    Dwarf_Signed * listlen,
    Dwarf_Unsigned * bytecount,
    Dwarf_Error * error)
{
    Dwarf_Small *rangeptr = 0;
    Dwarf_Small *beginrangeptr = 0;
    Dwarf_Small *section_end = 0;
    unsigned entry_count = 0;
    struct ranges_entry *base = 0;
    struct ranges_entry *last = 0;
    struct ranges_entry *curre = 0;
    Dwarf_Ranges * ranges_data_out = 0;
    unsigned copyindex = 0;
    Dwarf_Half address_size = 0;
    int res = DW_DLV_ERROR;

    res = _dwarf_load_section(dbg, &dbg->de_debug_ranges,error);
    if (res != DW_DLV_OK) {
        return res;
    }

    if(rangesoffset >= dbg->de_debug_ranges.dss_size) {
        _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OFFSET_BAD);
        return (DW_DLV_ERROR);

    }
    address_size = _dwarf_get_address_size(dbg, die);
    section_end = dbg->de_debug_ranges.dss_data + 
        dbg->de_debug_ranges.dss_size;
    rangeptr = dbg->de_debug_ranges.dss_data + rangesoffset;
    beginrangeptr = rangeptr;

    for(;;) {
        struct ranges_entry * re = calloc(sizeof(struct ranges_entry),1);
        if(!re) {
            _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OUT_OF_MEM);
            return (DW_DLV_ERROR);
        }
        if(rangeptr  >= section_end) {
            return (DW_DLV_NO_ENTRY);
        }
        if((rangeptr + (2*address_size)) > section_end) {
            _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OFFSET_BAD);
            return (DW_DLV_ERROR);
        }
        entry_count++;
        READ_UNALIGNED(dbg,re->cur.dwr_addr1,
            Dwarf_Addr, rangeptr,
            address_size);
        rangeptr +=  address_size;
        READ_UNALIGNED(dbg,re->cur.dwr_addr2 ,
            Dwarf_Addr, rangeptr,
            address_size);
        rangeptr +=  address_size;
        if(!base) {
            base = re;
            last = re;
        } else {
            last->next = re;
            last = re;
        }
        if(re->cur.dwr_addr1 == 0 && re->cur.dwr_addr2 == 0) {
            re->cur.dwr_type =  DW_RANGES_END;
            break;
        } else if ( re->cur.dwr_addr1 == MAX_ADDR) {
            re->cur.dwr_type =  DW_RANGES_ADDRESS_SELECTION;
        } else {
            re->cur.dwr_type =  DW_RANGES_ENTRY;
        }
    }

    ranges_data_out =   (Dwarf_Ranges *)
    _dwarf_get_alloc(dbg,DW_DLA_RANGES,entry_count);
    if(!ranges_data_out) {
        _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OUT_OF_MEM);
        return (DW_DLV_ERROR);
    }
    curre = base;
    *rangesbuf = ranges_data_out;
    *listlen = entry_count;
    for( copyindex = 0; curre && (copyindex < entry_count); 
        ++copyindex,++ranges_data_out) {

        struct ranges_entry *r = curre;
        *ranges_data_out = curre->cur;
        curre = curre->next;
        free(r);
    }
    /* Callers will often not care about the bytes used. */
    if(bytecount) {
        *bytecount = rangeptr - beginrangeptr;
    }
    return DW_DLV_OK; 
}
Exemple #27
0
/*
	return DW_DLV_OK if ok. else DW_DLV_NO_ENTRY or DW_DLV_ERROR
*/
int
_dwarf_internal_srclines(Dwarf_Die die,
			 Dwarf_Line ** linebuf,
			 Dwarf_Signed * count,
			 Dwarf_Bool doaddrs,
			 Dwarf_Bool dolines, Dwarf_Error * error)
{
    /* 
       This pointer is used to scan the portion of the .debug_line
       section for the current cu. */
    Dwarf_Small *line_ptr;

    /* 
       This points to the last byte of the .debug_line portion for the 
       current cu. */
    Dwarf_Small *line_ptr_end;

    /* 
       This points to the end of the statement program prologue for the 
       current cu, and serves to check that the prologue was correctly 
       decoded. */
    Dwarf_Small *check_line_ptr;

    /* 
       Pointer to a DW_AT_stmt_list attribute in case it exists in the 
       die. */
    Dwarf_Attribute stmt_list_attr;

    /* Pointer to DW_AT_comp_dir attribute in die. */
    Dwarf_Attribute comp_dir_attr;

    /* Pointer to name of compilation directory. */
    Dwarf_Small *comp_dir = NULL;

    /* 
       Offset into .debug_line specified by a DW_AT_stmt_list
       attribute. */
    Dwarf_Unsigned line_offset;

    /* These are the fields of the statement program header. */
    Dwarf_Unsigned total_length;
    Dwarf_Half version;
    Dwarf_Unsigned prologue_length;
    Dwarf_Small minimum_instruction_length;
    Dwarf_Small default_is_stmt;
    Dwarf_Sbyte line_base;
    Dwarf_Small line_range;
    Dwarf_Small special_opcode_base;

    Dwarf_Small *opcode_length;
    Dwarf_Small *include_directories;
    Dwarf_File_Entry file_entries;

    /* These are the state machine state variables. */
    Dwarf_Addr address;
    Dwarf_Word file;
    Dwarf_Word line;
    Dwarf_Word column;
    Dwarf_Bool is_stmt;
    Dwarf_Bool basic_block;
    Dwarf_Bool end_sequence;

    /* 
       These pointers are used to build the list of files names by
       this cu.  cur_file_entry points to the file name being added,
       and prev_file_entry to the previous one. */
    Dwarf_File_Entry cur_file_entry, prev_file_entry;

    Dwarf_Sword i, file_entry_count, include_directories_count;

    /* 
       This is the current opcode read from the statement program. */
    Dwarf_Small opcode;

    /* 
       Pointer to a Dwarf_Line_Context_s structure that contains the
       context such as file names and include directories for the set
       of lines being generated. */
    Dwarf_Line_Context line_context;

    /* 
       This is a pointer to the current line being added to the line
       matrix. */
    Dwarf_Line curr_line;

    /* 
       These variables are used to decode leb128 numbers. Leb128_num
       holds the decoded number, and leb128_length is its length in
       bytes. */
    Dwarf_Word leb128_num;
    Dwarf_Word leb128_length;
    Dwarf_Sword advance_line;

    /* 
       This is the operand of the latest fixed_advance_pc extended
       opcode. */
    Dwarf_Half fixed_advance_pc;

    /* 
       Counts the number of lines in the line matrix. */
    Dwarf_Sword line_count = 0;

    /* This is the length of an extended opcode instr.  */
    Dwarf_Word instr_length;
    Dwarf_Small ext_opcode;

    /* 
       Used to chain together pointers to line table entries that are
       later used to create a block of Dwarf_Line entries. */
    Dwarf_Chain chain_line, head_chain = NULL, curr_chain;

    /* 
       This points to a block of Dwarf_Lines, a pointer to which is
       returned in linebuf. */
    Dwarf_Line *block_line;

    /* The Dwarf_Debug this die belongs to. */
    Dwarf_Debug dbg;
    int resattr;
    int lres;
    int local_length_size = 0;
    /*REFERENCED*/ /* Not used in this instance of the macro */
    int local_extension_size = 0;

    int res;

    /* ***** BEGIN CODE ***** */

    if (error != NULL)
	*error = NULL;

    CHECK_DIE(die, DW_DLV_ERROR)
	dbg = die->di_cu_context->cc_dbg;

    res =
       _dwarf_load_section(dbg,
		           dbg->de_debug_line_index,
			   &dbg->de_debug_line,
			   error);
    if (res != DW_DLV_OK) {
	return res;
    }

    resattr = dwarf_attr(die, DW_AT_stmt_list, &stmt_list_attr, error);
    if (resattr != DW_DLV_OK) {
	return resattr;
    }



    lres = dwarf_formudata(stmt_list_attr, &line_offset, error);
    if (lres != DW_DLV_OK) {
	return lres;
    }

    if (line_offset >= dbg->de_debug_line_size) {
	_dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD);
	return (DW_DLV_ERROR);
    }
    line_ptr = dbg->de_debug_line + line_offset;
    dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR);

    /* 
       If die has DW_AT_comp_dir attribute, get the string that names
       the compilation directory. */
    resattr = dwarf_attr(die, DW_AT_comp_dir, &comp_dir_attr, error);
    if (resattr == DW_DLV_ERROR) {
	return resattr;
    }
    if (resattr == DW_DLV_OK) {
	int cres;
	char *cdir;

	cres = dwarf_formstring(comp_dir_attr, &cdir, error);
	if (cres == DW_DLV_ERROR) {
	    return cres;
	} else if (cres == DW_DLV_OK) {
	    comp_dir = (Dwarf_Small *) cdir;
	}
    }
    if (resattr == DW_DLV_OK) {
	dwarf_dealloc(dbg, comp_dir_attr, DW_DLA_ATTR);
    }

    /* 
       Following is a straightforward decoding of the statement
       program prologue information. */
    /* READ_AREA_LENGTH updates line_ptr for consumed bytes */
    READ_AREA_LENGTH(dbg, total_length, Dwarf_Unsigned,
		     line_ptr, local_length_size, local_extension_size);

    line_ptr_end = line_ptr + total_length;
    if (line_ptr_end > dbg->de_debug_line + dbg->de_debug_line_size) {
	_dwarf_error(dbg, error, DW_DLE_DEBUG_LINE_LENGTH_BAD);
	return (DW_DLV_ERROR);
    }

    READ_UNALIGNED(dbg, version, Dwarf_Half,
		   line_ptr, sizeof(Dwarf_Half));
    line_ptr += sizeof(Dwarf_Half);
    if (version != CURRENT_VERSION_STAMP &&
	version != CURRENT_VERSION_STAMP3) {
	_dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR);
	return (DW_DLV_ERROR);
    }

    READ_UNALIGNED(dbg, prologue_length, Dwarf_Unsigned,
		   line_ptr, local_length_size);
    line_ptr += local_length_size;
    check_line_ptr = line_ptr;

    minimum_instruction_length = *(Dwarf_Small *) line_ptr;
    line_ptr = line_ptr + sizeof(Dwarf_Small);

    default_is_stmt = *(Dwarf_Small *) line_ptr;
    line_ptr = line_ptr + sizeof(Dwarf_Small);

    line_base = *(Dwarf_Sbyte *) line_ptr;
    line_ptr = line_ptr + sizeof(Dwarf_Sbyte);

    line_range = *(Dwarf_Small *) line_ptr;
    line_ptr = line_ptr + sizeof(Dwarf_Small);

    special_opcode_base = *(Dwarf_Small *) line_ptr;
    line_ptr = line_ptr + sizeof(Dwarf_Small);

    opcode_length = (Dwarf_Small *)
	alloca(sizeof(Dwarf_Small) * special_opcode_base);
    for (i = 1; i < special_opcode_base; i++) {
	opcode_length[i] = *(Dwarf_Small *) line_ptr;
	line_ptr = line_ptr + sizeof(Dwarf_Small);
    }

    include_directories_count = 0;
    include_directories = line_ptr;
    while ((*(char *) line_ptr) != '\0') {
	line_ptr = line_ptr + strlen((char *) line_ptr) + 1;
	include_directories_count++;
    }
    line_ptr++;

    file_entry_count = 0;
    file_entries = prev_file_entry = NULL;
    while (*(char *) line_ptr != '\0') {

	cur_file_entry = (Dwarf_File_Entry)
	    _dwarf_get_alloc(dbg, DW_DLA_FILE_ENTRY, 1);
	if (cur_file_entry == NULL) {
	    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
	    return (DW_DLV_ERROR);
	}

	cur_file_entry->fi_file_name = (Dwarf_Small *) line_ptr;
	line_ptr = line_ptr + strlen((char *) line_ptr) + 1;

	cur_file_entry->fi_dir_index =
	    (Dwarf_Sword) _dwarf_decode_u_leb128(line_ptr,
						 &leb128_length);
	line_ptr = line_ptr + leb128_length;

	cur_file_entry->fi_time_last_mod =
	    _dwarf_decode_u_leb128(line_ptr, &leb128_length);
	line_ptr = line_ptr + leb128_length;

	cur_file_entry->fi_file_length =
	    _dwarf_decode_u_leb128(line_ptr, &leb128_length);
	line_ptr = line_ptr + leb128_length;

	if (file_entries == NULL)
	    file_entries = cur_file_entry;
	else
	    prev_file_entry->fi_next = cur_file_entry;
	prev_file_entry = cur_file_entry;

	file_entry_count++;
    }
    line_ptr++;

    if (line_ptr != check_line_ptr + prologue_length) {
	_dwarf_error(dbg, error, DW_DLE_LINE_PROLOG_LENGTH_BAD);
	return (DW_DLV_ERROR);
    }

    /* Set up context structure for this set of lines. */
    line_context = (Dwarf_Line_Context)
	_dwarf_get_alloc(dbg, DW_DLA_LINE_CONTEXT, 1);
    if (line_context == NULL) {
	_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
	return (DW_DLV_ERROR);
    }

    /* Initialize the state machine.  */
    address = 0;
    file = 1;
    line = 1;
    column = 0;
    is_stmt = default_is_stmt;
    basic_block = false;
    end_sequence = false;

    /* Start of statement program.  */
    while (line_ptr < line_ptr_end) {
	int type;

	opcode = *(Dwarf_Small *) line_ptr;
	line_ptr++;


	/* 'type' is the output */
	WHAT_IS_OPCODE(type, opcode, special_opcode_base,
		       opcode_length, line_ptr);



	if (type == LOP_DISCARD) {
	    /* do nothing, necessary ops done */
	} else if (type == LOP_SPECIAL) {
	    /* This op code is a special op in the object, no matter
	       that it might fall into the standard op range in this
	       compile Thatis, these are special opcodes between
	       special_opcode_base and MAX_LINE_OP_CODE.  (including
	       special_opcode_base and MAX_LINE_OP_CODE) */

	    opcode = opcode - special_opcode_base;
	    address = address + minimum_instruction_length *
		(opcode / line_range);
	    line = line + line_base + opcode % line_range;

	    if (dolines) {
		curr_line =
		    (Dwarf_Line) _dwarf_get_alloc(dbg, DW_DLA_LINE, 1);
		if (curr_line == NULL) {
		    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
		    return (DW_DLV_ERROR);
		}

		curr_line->li_address = address;
		curr_line->li_addr_line.li_l_data.li_file =
		    (Dwarf_Sword) file;
		curr_line->li_addr_line.li_l_data.li_line =
		    (Dwarf_Sword) line;
		curr_line->li_addr_line.li_l_data.li_column =
		    (Dwarf_Half) column;
		curr_line->li_addr_line.li_l_data.li_is_stmt = is_stmt;
		curr_line->li_addr_line.li_l_data.li_basic_block =
		    basic_block;
		curr_line->li_addr_line.li_l_data.li_end_sequence =
		    end_sequence;
		curr_line->li_context = line_context;
		line_count++;

		chain_line = (Dwarf_Chain)
		    _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
		if (chain_line == NULL) {
		    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
		    return (DW_DLV_ERROR);
		}
		chain_line->ch_item = curr_line;

		if (head_chain == NULL)
		    head_chain = curr_chain = chain_line;
		else {
		    curr_chain->ch_next = chain_line;
		    curr_chain = chain_line;
		}
	    }

	    basic_block = false;
	} else if (type == LOP_STANDARD) {
	    switch (opcode) {

	    case DW_LNS_copy:{
		    if (opcode_length[DW_LNS_copy] != 0) {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_NUM_OPERANDS_BAD);
			return (DW_DLV_ERROR);
		    }

		    if (dolines) {

			curr_line =
			    (Dwarf_Line) _dwarf_get_alloc(dbg,
							  DW_DLA_LINE,
							  1);
			if (curr_line == NULL) {
			    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
			    return (DW_DLV_ERROR);
			}

			curr_line->li_address = address;
			curr_line->li_addr_line.li_l_data.li_file =
			    (Dwarf_Sword) file;
			curr_line->li_addr_line.li_l_data.li_line =
			    (Dwarf_Sword) line;
			curr_line->li_addr_line.li_l_data.li_column =
			    (Dwarf_Half) column;
			curr_line->li_addr_line.li_l_data.li_is_stmt =
			    is_stmt;
			curr_line->li_addr_line.li_l_data.
			    li_basic_block = basic_block;
			curr_line->li_addr_line.li_l_data.
			    li_end_sequence = end_sequence;
			curr_line->li_context = line_context;
			line_count++;

			chain_line = (Dwarf_Chain)
			    _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
			if (chain_line == NULL) {
			    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
			    return (DW_DLV_ERROR);
			}
			chain_line->ch_item = curr_line;
			if (head_chain == NULL)
			    head_chain = curr_chain = chain_line;
			else {
			    curr_chain->ch_next = chain_line;
			    curr_chain = chain_line;
			}
		    }

		    basic_block = false;
		    break;
		}

	    case DW_LNS_advance_pc:{
		    Dwarf_Unsigned utmp2;

		    if (opcode_length[DW_LNS_advance_pc] != 1) {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_NUM_OPERANDS_BAD);
			return (DW_DLV_ERROR);
		    }

		    DECODE_LEB128_UWORD(line_ptr, utmp2)
			leb128_num = (Dwarf_Word) utmp2;
		    address =
			address +
			minimum_instruction_length * leb128_num;
		    break;
		}

	    case DW_LNS_advance_line:{
		    Dwarf_Signed stmp;

		    if (opcode_length[DW_LNS_advance_line] != 1) {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_NUM_OPERANDS_BAD);
			return (DW_DLV_ERROR);
		    }

		    DECODE_LEB128_SWORD(line_ptr, stmp)
			advance_line = (Dwarf_Sword) stmp;
		    line = line + advance_line;
		    break;
		}

	    case DW_LNS_set_file:{
		    Dwarf_Unsigned utmp2;

		    if (opcode_length[DW_LNS_set_file] != 1) {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_NUM_OPERANDS_BAD);
			return (DW_DLV_ERROR);
		    }

		    DECODE_LEB128_UWORD(line_ptr, utmp2)
			file = (Dwarf_Word) utmp2;
		    break;
		}

	    case DW_LNS_set_column:{
		    Dwarf_Unsigned utmp2;

		    if (opcode_length[DW_LNS_set_column] != 1) {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_NUM_OPERANDS_BAD);
			return (DW_DLV_ERROR);
		    }

		    DECODE_LEB128_UWORD(line_ptr, utmp2)
			column = (Dwarf_Word) utmp2;
		    break;
		}

	    case DW_LNS_negate_stmt:{
		    if (opcode_length[DW_LNS_negate_stmt] != 0) {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_NUM_OPERANDS_BAD);
			return (DW_DLV_ERROR);
		    }

		    is_stmt = !is_stmt;
		    break;
		}

	    case DW_LNS_set_basic_block:{
		    if (opcode_length[DW_LNS_set_basic_block] != 0) {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_NUM_OPERANDS_BAD);
			return (DW_DLV_ERROR);
		    }

		    basic_block = true;
		    break;
		}

	    case DW_LNS_const_add_pc:{
		    opcode = MAX_LINE_OP_CODE - special_opcode_base;
		    address = address + minimum_instruction_length *
			(opcode / line_range);

		    break;
		}

	    case DW_LNS_fixed_advance_pc:{
		    if (opcode_length[DW_LNS_fixed_advance_pc] != 1) {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_NUM_OPERANDS_BAD);
			return (DW_DLV_ERROR);
		    }

		    READ_UNALIGNED(dbg, fixed_advance_pc, Dwarf_Half,
				   line_ptr, sizeof(Dwarf_Half));
		    line_ptr += sizeof(Dwarf_Half);
		    address = address + fixed_advance_pc;
		    break;
		}
	    }

	} else if (type == LOP_EXTENDED) {
	    Dwarf_Unsigned utmp3;

	    DECODE_LEB128_UWORD(line_ptr, utmp3)
		instr_length = (Dwarf_Word) utmp3;
	    /* Dwarf_Small is a ubyte and the extended opcode
	       is a ubyte, though not stated as clearly in
	       the 2.0.0 spec as one might hope.
	    */
	    ext_opcode = *(Dwarf_Small *) line_ptr;
	    line_ptr++;
	    switch (ext_opcode) {

	    case DW_LNE_end_sequence:{
		    end_sequence = true;

		    if (dolines) {
			curr_line = (Dwarf_Line)
			    _dwarf_get_alloc(dbg, DW_DLA_LINE, 1);
			if (curr_line == NULL) {
			    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
			    return (DW_DLV_ERROR);
			}

			curr_line->li_address = address;
			curr_line->li_addr_line.li_l_data.li_file =
			    (Dwarf_Sword) file;
			curr_line->li_addr_line.li_l_data.li_line =
			    (Dwarf_Sword) line;
			curr_line->li_addr_line.li_l_data.li_column =
			    (Dwarf_Half) column;
			curr_line->li_addr_line.li_l_data.li_is_stmt =
			    default_is_stmt;
			curr_line->li_addr_line.li_l_data.
			    li_basic_block = basic_block;
			curr_line->li_addr_line.li_l_data.
			    li_end_sequence = end_sequence;
			curr_line->li_context = line_context;
			line_count++;

			chain_line = (Dwarf_Chain)
			    _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
			if (chain_line == NULL) {
			    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
			    return (DW_DLV_ERROR);
			}
			chain_line->ch_item = curr_line;

			if (head_chain == NULL)
			    head_chain = curr_chain = chain_line;
			else {
			    curr_chain->ch_next = chain_line;
			    curr_chain = chain_line;
			}
		    }

		    address = 0;
		    file = 1;
		    line = 1;
		    column = 0;
		    is_stmt = default_is_stmt;
		    basic_block = false;
		    end_sequence = false;

		    break;
		}

	    case DW_LNE_set_address:{
		    if (instr_length - 1 == dbg->de_pointer_size) {
			READ_UNALIGNED(dbg, address, Dwarf_Addr,
				       line_ptr, dbg->de_pointer_size);
			if (doaddrs) {
			    curr_line =
				(Dwarf_Line) _dwarf_get_alloc(dbg,
							      DW_DLA_LINE,
							      1);
			    if (curr_line == NULL) {
				_dwarf_error(dbg, error,
					     DW_DLE_ALLOC_FAIL);
				return (DW_DLV_ERROR);
			    }

			    curr_line->li_address = address;
			    curr_line->li_addr_line.li_offset =
				line_ptr - dbg->de_debug_line;

			    line_count++;

			    chain_line = (Dwarf_Chain)
				_dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
			    if (chain_line == NULL) {
				_dwarf_error(dbg, error,
					     DW_DLE_ALLOC_FAIL);
				return (DW_DLV_ERROR);
			    }
			    chain_line->ch_item = curr_line;

			    if (head_chain == NULL)
				head_chain = curr_chain = chain_line;
			    else {
				curr_chain->ch_next = chain_line;
				curr_chain = chain_line;
			    }
			}

			line_ptr += dbg->de_pointer_size;
		    } else {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_SET_ADDR_ERROR);
			return (DW_DLV_ERROR);
		    }

		    break;
		}

	    case DW_LNE_define_file:{

		    if (dolines) {
			cur_file_entry = (Dwarf_File_Entry)
			    _dwarf_get_alloc(dbg, DW_DLA_FILE_ENTRY, 1);
			if (cur_file_entry == NULL) {
			    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
			    return (DW_DLV_ERROR);
			}

			cur_file_entry->fi_file_name =
			    (Dwarf_Small *) line_ptr;
			line_ptr =
			    line_ptr + strlen((char *) line_ptr) + 1;

			cur_file_entry->fi_dir_index =
			    (Dwarf_Sword)
			    _dwarf_decode_u_leb128(line_ptr,
						   &leb128_length);
			line_ptr = line_ptr + leb128_length;

			cur_file_entry->fi_time_last_mod =
			    _dwarf_decode_u_leb128(line_ptr,
						   &leb128_length);
			line_ptr = line_ptr + leb128_length;

			cur_file_entry->fi_file_length =
			    _dwarf_decode_u_leb128(line_ptr,
						   &leb128_length);
			line_ptr = line_ptr + leb128_length;

			if (file_entries == NULL)
			    file_entries = cur_file_entry;
			else
			    prev_file_entry->fi_next = cur_file_entry;
			prev_file_entry = cur_file_entry;

			file_entry_count++;
		    }
		    break;
		}

	    default:{
		    _dwarf_error(dbg, error,
				 DW_DLE_LINE_EXT_OPCODE_BAD);
		    return (DW_DLV_ERROR);
		}
	    }

	}
    }

    block_line = (Dwarf_Line *)
	_dwarf_get_alloc(dbg, DW_DLA_LIST, line_count);
    if (block_line == NULL) {
	_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
	return (DW_DLV_ERROR);
    }

    curr_chain = head_chain;
    for (i = 0; i < line_count; i++) {
	*(block_line + i) = curr_chain->ch_item;
	head_chain = curr_chain;
	curr_chain = curr_chain->ch_next;
	dwarf_dealloc(dbg, head_chain, DW_DLA_CHAIN);
    }

    line_context->lc_file_entries = file_entries;
    line_context->lc_file_entry_count = file_entry_count;
    line_context->lc_include_directories = include_directories;
    line_context->lc_include_directories_count =
	include_directories_count;
    line_context->lc_line_count = line_count;
    line_context->lc_compilation_directory = comp_dir;
    line_context->lc_version_number = version;	
    line_context->lc_dbg = dbg;
    *count = line_count;

    *linebuf = block_line;
    return (DW_DLV_OK);
}
Exemple #28
0
int
_dwarf_extract_string_offset_via_str_offsets(Dwarf_Debug dbg,
    Dwarf_Small *info_data_ptr,
    UNUSEDARG Dwarf_Half   attrnum,
    Dwarf_Half   attrform,
    Dwarf_CU_Context cu_context,
    Dwarf_Unsigned *str_sect_offset_out,
    Dwarf_Error *error)
{
    Dwarf_Unsigned offsettostr= 0;
    Dwarf_Unsigned offset_base = 0;
    Dwarf_Word leb_len = 0;
    Dwarf_Unsigned index_to_offset_entry = 0;
    Dwarf_Unsigned offsetintable = 0;
    Dwarf_Unsigned end_offsetintable = 0;
    int res = 0;

    res = _dwarf_load_section(dbg, &dbg->de_debug_str_offsets,error);
    if (res != DW_DLV_OK) {
        return res;
    }
    index_to_offset_entry = (_dwarf_decode_u_leb128(info_data_ptr, &leb_len));
    /*  DW_FORM_GNU_str_index has no 'base' value.
        DW_FORM_strx has a base value
        for the offset table */
    if( attrform == DW_FORM_strx) {
        res = _dwarf_get_string_base_attr_value(dbg,cu_context,
            &offset_base,error);
        if (res != DW_DLV_OK) {
            /*  DW_DLV_NO_ENTRY could be acceptable when
                a producer knows that the base offset will be zero.
                Hence DW_AT_str_offsets_base missing.
                DWARF5 draft as of September 2015 allows the attribute
                to be missing (it's up to the compilation tools to
                make sure that has the correct effect).
            */
            return res;
        }
    }

    offsetintable = (index_to_offset_entry*cu_context->cc_length_size )
        + offset_base;
    {
        Dwarf_Unsigned fissoff = 0;
        Dwarf_Unsigned size = 0;
        fissoff = _dwarf_get_dwp_extra_offset(&cu_context->cc_dwp_offsets,
            DW_SECT_STR_OFFSETS, &size);
        offsetintable += fissoff;
    }
    end_offsetintable = offsetintable + cu_context->cc_length_size;
    /*  The offsets table is a series of offset-size entries.
        The == case in the test applies when we are at the last table
        entry, so == is not an error, hence only test >
    */
    if (end_offsetintable > dbg->de_debug_str_offsets.dss_size ) {
        _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_SIZE_BAD);
        return (DW_DLV_ERROR);
    }

    /* Now read the string offset from the offset table. */
    READ_UNALIGNED(dbg,offsettostr,Dwarf_Unsigned,
        dbg->de_debug_str_offsets.dss_data + offsetintable,
        cu_context->cc_length_size);
    *str_sect_offset_out = offsettostr;
    return DW_DLV_OK;
}
Exemple #29
0
/*
    This function returns the count of the number of
    aranges in the .debug_aranges section.  It sets
    aranges to point to a block of Dwarf_Arange's 
    describing the arange's.  It returns DW_DLV_ERROR
    on error.

    Must be identical in most aspects to
	dwarf_get_aranges_addr_offsets!
*/
int
dwarf_get_aranges(Dwarf_Debug dbg,
		  Dwarf_Arange ** aranges,
		  Dwarf_Signed * returned_count, Dwarf_Error * error)
{
    /* Sweeps the .debug_aranges section. */
    Dwarf_Small *arange_ptr;

    /* 
       Start of arange header.  Used for rounding offset of arange_ptr
       to twice the tuple size.  Libdwarf requirement. */
    Dwarf_Small *header_ptr;


    /* Version of .debug_aranges header. */
    Dwarf_Half version;

    /* Offset of current set of aranges into .debug_info. */
    Dwarf_Off info_offset;

    /* Size in bytes of addresses in target. */
    Dwarf_Small address_size;

    /* Size in bytes of segment offsets in target. */
    Dwarf_Small segment_size;

    Dwarf_Small remainder;

    /* Count of total number of aranges. */
    Dwarf_Unsigned arange_count = 0;

    /* Start address of arange. */
    Dwarf_Addr range_address;

    /* Length of arange. */
    Dwarf_Unsigned range_length;

    Dwarf_Arange arange, *arange_block;

    Dwarf_Unsigned i;

    /* Used to chain Dwarf_Aranges structs. */
    Dwarf_Chain curr_chain, prev_chain, head_chain = NULL;

    int res;

    /* ***** BEGIN CODE ***** */

    if (dbg == NULL) {
	_dwarf_error(NULL, error, DW_DLE_DBG_NULL);
	return (DW_DLV_ERROR);
    }

    res =
        _dwarf_load_section(dbg,
			    dbg->de_debug_aranges_index,
			    &dbg->de_debug_aranges,
			    error);
    if (res != DW_DLV_OK) {
        return res;
    }

    arange_ptr = dbg->de_debug_aranges;
    do {
        /* Length of current set of aranges. */
        Dwarf_Unsigned length;
	Dwarf_Small *arange_ptr_past_end = 0;

	int local_length_size;
	/*REFERENCED*/ /* Not used in this instance of the macro */
	int local_extension_size;

	header_ptr = arange_ptr;

	/* READ_AREA_LENGTH updates arange_ptr for consumed bytes */
	READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned,
			 arange_ptr, local_length_size,
			 local_extension_size);
	arange_ptr_past_end = arange_ptr + length;


	READ_UNALIGNED(dbg, version, Dwarf_Half,
		       arange_ptr, sizeof(Dwarf_Half));
	arange_ptr += sizeof(Dwarf_Half);
	length = length - sizeof(Dwarf_Half);
	if (version != CURRENT_VERSION_STAMP) {
	    _dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR);
	    return (DW_DLV_ERROR);
	}

	READ_UNALIGNED(dbg, info_offset, Dwarf_Off,
		       arange_ptr, local_length_size);
	arange_ptr += local_length_size;
	length = length - local_length_size;
	if (info_offset >= dbg->de_debug_info_size) {
	    _dwarf_error(dbg, error, DW_DLE_ARANGE_OFFSET_BAD);
	    return (DW_DLV_ERROR);
	}

	address_size = *(Dwarf_Small *) arange_ptr;
	if (address_size != dbg->de_pointer_size) {
	    /* Internal error of some kind */
	    _dwarf_error(dbg, error, DW_DLE_BADBITC);
	    return (DW_DLV_ERROR);
	}
	arange_ptr = arange_ptr + sizeof(Dwarf_Small);
	length = length - sizeof(Dwarf_Small);

	segment_size = *(Dwarf_Small *) arange_ptr;
	arange_ptr = arange_ptr + sizeof(Dwarf_Small);
	length = length - sizeof(Dwarf_Small);
	if (segment_size != 0) {
	    _dwarf_error(dbg, error, DW_DLE_SEGMENT_SIZE_BAD);
	    return (DW_DLV_ERROR);
	}

	/* Round arange_ptr offset to next multiple of address_size. */
	remainder = (Dwarf_Unsigned) (arange_ptr - header_ptr) %
	    (2 * address_size);
	if (remainder != 0) {
	    arange_ptr = arange_ptr + (2 * address_size) - remainder;
	    length = length - ((2 * address_size) - remainder);
	}

	do {
	    READ_UNALIGNED(dbg, range_address, Dwarf_Addr,
			   arange_ptr, address_size);
	    arange_ptr += address_size;
	    length = length - address_size;

	    READ_UNALIGNED(dbg, range_length, Dwarf_Unsigned,
			   arange_ptr, address_size);
	    arange_ptr += address_size;
	    length = length - address_size;

	    if (range_address != 0 || range_length != 0) {

		arange = (Dwarf_Arange)
		    _dwarf_get_alloc(dbg, DW_DLA_ARANGE, 1);
		if (arange == NULL) {
		    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
		    return (DW_DLV_ERROR);
		}

		arange->ar_address = range_address;
		arange->ar_length = range_length;
		arange->ar_info_offset = info_offset;
		arange->ar_dbg = dbg;
		arange_count++;

		curr_chain = (Dwarf_Chain)
		    _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
		if (curr_chain == NULL) {
		    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
		    return (DW_DLV_ERROR);
		}

		curr_chain->ch_item = arange;
		if (head_chain == NULL)
		    head_chain = prev_chain = curr_chain;
		else {
		    prev_chain->ch_next = curr_chain;
		    prev_chain = curr_chain;
		}
	    }
	} while (range_address != 0 || range_length != 0);

	/* A compiler could emit some padding bytes here.
	   dwarf2/3 (dwarf3 draft8 sec 7.20) does not clearly make
	   extra padding bytes illegal. */
	if(arange_ptr_past_end < arange_ptr) {
	    _dwarf_error(dbg, error, DW_DLE_ARANGE_LENGTH_BAD);
	    return (DW_DLV_ERROR);
	}
	/* For most compilers, arange_ptr == arange_ptr_past_end
	   at this point. But not if there were padding bytes */
	arange_ptr = arange_ptr_past_end;

    } while (arange_ptr <
	     dbg->de_debug_aranges + dbg->de_debug_aranges_size);

    if (arange_ptr !=
	dbg->de_debug_aranges + dbg->de_debug_aranges_size) {
	_dwarf_error(dbg, error, DW_DLE_ARANGE_DECODE_ERROR);
	return (DW_DLV_ERROR);
    }

    arange_block = (Dwarf_Arange *)
	_dwarf_get_alloc(dbg, DW_DLA_LIST, arange_count);
    if (arange_block == NULL) {
	_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
	return (DW_DLV_ERROR);
    }

    curr_chain = head_chain;
    for (i = 0; i < arange_count; i++) {
	*(arange_block + i) = curr_chain->ch_item;
	prev_chain = curr_chain;
	curr_chain = curr_chain->ch_next;
	dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN);
    }

    *aranges = arange_block;
    *returned_count = (arange_count);
    return DW_DLV_OK;
}
Exemple #30
0
/*
	return DW_DLV_OK if ok. else DW_DLV_NO_ENTRY or DW_DLV_ERROR
*/
int
_dwarf_internal_printlines(Dwarf_Die die, Dwarf_Error * error)
{
    /* 
       This pointer is used to scan the portion of the .debug_line
       section for the current cu. */
    Dwarf_Small *line_ptr;
    Dwarf_Small *orig_line_ptr;

    /* 
       This points to the last byte of the .debug_line portion for the 
       current cu. */
    Dwarf_Small *line_ptr_end;

    /* 
       This points to the end of the statement program prologue for the 
       current cu, and serves to check that the prologue was correctly 
       decoded. */
    Dwarf_Small *check_line_ptr;

    /* 
       Pointer to a DW_AT_stmt_list attribute in case it exists in the 
       die. */
    Dwarf_Attribute stmt_list_attr;

    /* Pointer to DW_AT_comp_dir attribute in die. */
    Dwarf_Attribute comp_dir_attr;

    /* Pointer to name of compilation directory. */
    Dwarf_Small *comp_dir = NULL;

    /* 
       Offset into .debug_line specified by a DW_AT_stmt_list
       attribute. */
    Dwarf_Unsigned line_offset;

    /* These are the fields of the statement program header. */
    Dwarf_Unsigned total_length;
    Dwarf_Half version;
    Dwarf_Unsigned prologue_length;
    Dwarf_Small minimum_instruction_length;
    Dwarf_Small default_is_stmt;
    Dwarf_Sbyte line_base;
    Dwarf_Small line_range;
    Dwarf_Small opcode_base;

    Dwarf_Small *opcode_length;

    /* These are the state machine state variables. */
    Dwarf_Addr address;
    Dwarf_Word file;
    Dwarf_Word line;
    Dwarf_Word column;
    Dwarf_Bool is_stmt;
    Dwarf_Bool basic_block;
    Dwarf_Bool end_sequence;

    Dwarf_Sword i, file_entry_count, include_directories_count;

    /* 
       This is the current opcode read from the statement program. */
    Dwarf_Small opcode;

    /* 
       Pointer to a Dwarf_Line_Context_s structure that contains the
       context such as file names and include directories for the set
       of lines being generated. */
    Dwarf_Line_Context line_context;


    /* 
       These variables are used to decode leb128 numbers. Leb128_num
       holds the decoded number, and leb128_length is its length in
       bytes. */
    Dwarf_Word leb128_num;
    Dwarf_Word leb128_length;
    Dwarf_Sword advance_line;

    /* 
       This is the operand of the latest fixed_advance_pc extended
       opcode. */
    Dwarf_Half fixed_advance_pc;

    /* This is the length of an extended opcode instr.  */
    Dwarf_Word instr_length;
    Dwarf_Small ext_opcode;
    int local_length_size;
    /*REFERENCED*/ /* Not used in this instance of the macro */
    int local_extension_size;

    /* The Dwarf_Debug this die belongs to. */
    Dwarf_Debug dbg;
    int resattr;
    int lres;

    int res;

    /* ***** BEGIN CODE ***** */

    if (error != NULL)
	*error = NULL;

    CHECK_DIE(die, DW_DLV_ERROR)
	dbg = die->di_cu_context->cc_dbg;

    res =
       _dwarf_load_section(dbg,
		           dbg->de_debug_line_index,
			   &dbg->de_debug_line,
		           error);
    if (res != DW_DLV_OK) {
	return res;
    }

    resattr = dwarf_attr(die, DW_AT_stmt_list, &stmt_list_attr, error);
    if (resattr != DW_DLV_OK) {
	return resattr;
    }



    lres = dwarf_formudata(stmt_list_attr, &line_offset, error);
    if (lres != DW_DLV_OK) {
	return lres;
    }

    if (line_offset >= dbg->de_debug_line_size) {
	_dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD);
	return (DW_DLV_ERROR);
    }
    orig_line_ptr = dbg->de_debug_line;
    line_ptr = dbg->de_debug_line + line_offset;
    dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR);

    /* 
       If die has DW_AT_comp_dir attribute, get the string that names
       the compilation directory. */
    resattr = dwarf_attr(die, DW_AT_comp_dir, &comp_dir_attr, error);
    if (resattr == DW_DLV_ERROR) {
	return resattr;
    }
    if (resattr == DW_DLV_OK) {
	int cres;
	char *cdir;

	cres = dwarf_formstring(comp_dir_attr, &cdir, error);
	if (cres == DW_DLV_ERROR) {
	    return cres;
	} else if (cres == DW_DLV_OK) {
	    comp_dir = (Dwarf_Small *) cdir;
	}
    }
    if (resattr == DW_DLV_OK) {
	dwarf_dealloc(dbg, comp_dir_attr, DW_DLA_ATTR);
    }

    /* 
       Following is a straightforward decoding of the statement
       program prologue information. */

    /* READ_AREA_LENGTH updates line_ptr for consumed bytes */
    READ_AREA_LENGTH(dbg, total_length, Dwarf_Unsigned,
		     line_ptr, local_length_size, local_extension_size);



    line_ptr_end = line_ptr + total_length;
    if (line_ptr_end > dbg->de_debug_line + dbg->de_debug_line_size) {
	_dwarf_error(dbg, error, DW_DLE_DEBUG_LINE_LENGTH_BAD);
	return (DW_DLV_ERROR);
    }

    printf("total line info length %ld bytes, "
	   "line offset 0x%llx %lld\n",
	   (long) total_length,
	   (long long) line_offset, (long long) line_offset);
    printf("compilation_directory %s\n",
	   comp_dir ? ((char *) comp_dir) : "");
    READ_UNALIGNED(dbg, version, Dwarf_Half,
		   line_ptr, sizeof(Dwarf_Half));
    line_ptr += sizeof(Dwarf_Half);
    if (version != CURRENT_VERSION_STAMP) {
	_dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR);
	return (DW_DLV_ERROR);
    }

    READ_UNALIGNED(dbg, prologue_length, Dwarf_Unsigned,
		   line_ptr, local_length_size);
    line_ptr += local_length_size;
    check_line_ptr = line_ptr;

    minimum_instruction_length = *(Dwarf_Small *) line_ptr;
    line_ptr = line_ptr + sizeof(Dwarf_Small);

    default_is_stmt = *(Dwarf_Small *) line_ptr;
    line_ptr = line_ptr + sizeof(Dwarf_Small);

    line_base = *(Dwarf_Sbyte *) line_ptr;
    line_ptr = line_ptr + sizeof(Dwarf_Sbyte);

    line_range = *(Dwarf_Small *) line_ptr;
    line_ptr = line_ptr + sizeof(Dwarf_Small);

    opcode_base = *(Dwarf_Small *) line_ptr;
    line_ptr = line_ptr + sizeof(Dwarf_Small);
    printf("  min instruction length %d\n",
	   (int) minimum_instruction_length);
    printf("  default is stmt        %d\n", (int) default_is_stmt);
    printf("  line base              %d\n", (int) line_base);
    printf("  line_range             %d\n", (int) line_range);

    opcode_length = (Dwarf_Small *)
	alloca(sizeof(Dwarf_Small) * opcode_base);

    for (i = 1; i < opcode_base; i++) {
	opcode_length[i] = *(Dwarf_Small *) line_ptr;
	printf("  opcode[%d] length %d\n", (int) i,
	       (int) opcode_length[i]);
	line_ptr = line_ptr + sizeof(Dwarf_Small);
    }

    include_directories_count = 0;
    while ((*(char *) line_ptr) != '\0') {
	printf("  include dir[%d] %s\n",
	       (int) include_directories_count, line_ptr);
	line_ptr = line_ptr + strlen((char *) line_ptr) + 1;
	include_directories_count++;
    }
    line_ptr++;

    file_entry_count = 0;
    while (*(char *) line_ptr != '\0') {

	Dwarf_Unsigned tlm2;
	Dwarf_Unsigned di;
	Dwarf_Unsigned fl;

	printf("  file[%d]  %s\n",
	       (int) file_entry_count, (char *) line_ptr);

	line_ptr = line_ptr + strlen((char *) line_ptr) + 1;

	di = _dwarf_decode_u_leb128(line_ptr, &leb128_length);
	line_ptr = line_ptr + leb128_length;

	tlm2 = _dwarf_decode_u_leb128(line_ptr, &leb128_length);
	line_ptr = line_ptr + leb128_length;

	fl = _dwarf_decode_u_leb128(line_ptr, &leb128_length);
	line_ptr = line_ptr + leb128_length;

	printf("    dir index %d\n", (int) di);
	{
	    time_t tt = (time_t) tlm2;

	    printf("    last time 0x%x %s",	/* ctime supplies
						   newline */
		   (unsigned) tlm2, ctime(&tt));
	}
	printf("    file length %ld 0x%lx\n",
	       (long) fl, (unsigned long) fl);


	file_entry_count++;
    }
    line_ptr++;

    if (line_ptr != check_line_ptr + prologue_length) {
	_dwarf_error(dbg, error, DW_DLE_LINE_PROLOG_LENGTH_BAD);
	return (DW_DLV_ERROR);
    }

    /* Set up context structure for this set of lines. */
    line_context = (Dwarf_Line_Context)
	_dwarf_get_alloc(dbg, DW_DLA_LINE_CONTEXT, 1);
    if (line_context == NULL) {
	_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
	return (DW_DLV_ERROR);
    }

    printf("  statement prog offset in section: %lld 0x%llx\n",
	   (long long) (line_ptr - orig_line_ptr),
	   (long long) (line_ptr - orig_line_ptr));

    /* Initialize the state machine.  */
    address = 0;
    file = 1;
    line = 1;
    column = 0;
    is_stmt = default_is_stmt;
    basic_block = false;
    end_sequence = false;

    print_line_header();
    /* Start of statement program.  */
    while (line_ptr < line_ptr_end) {
	int type;

	printf(" [0x%06llx] ", (long long) (line_ptr - orig_line_ptr));
	opcode = *(Dwarf_Small *) line_ptr;
	line_ptr++;
	/* 'type' is the output */
	WHAT_IS_OPCODE(type, opcode, opcode_base,
		       opcode_length, line_ptr);



	if (type == LOP_DISCARD) {
	    /* do nothing, necessary ops done */
	} else if (type == LOP_SPECIAL) {
	    /* This op code is a special op in the object, no matter
	       that it might fall into the standard op range in this
	       compile Thatis, these are special opcodes between
	       special_opcode_base and MAX_LINE_OP_CODE.  (including
	       special_opcode_base and MAX_LINE_OP_CODE) */
	    char special[50];
	    unsigned origop = opcode;

	    opcode = opcode - opcode_base;
	    address = address + minimum_instruction_length *
		(opcode / line_range);
	    line = line + line_base + opcode % line_range;

	    sprintf(special, "Specialop %3u", origop);
	    print_line_detail(special,
			      opcode, address, (int) file, line, column,
			      is_stmt, basic_block, end_sequence);

	    basic_block = false;

	} else if (type == LOP_STANDARD) {
	    switch (opcode) {

	    case DW_LNS_copy:{
		    if (opcode_length[DW_LNS_copy] != 0) {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_NUM_OPERANDS_BAD);
			return (DW_DLV_ERROR);
		    }

		    print_line_detail("DW_LNS_copy",
				      opcode, address, file, line,
				      column, is_stmt, basic_block,
				      end_sequence);

		    basic_block = false;
		    break;
		}

	    case DW_LNS_advance_pc:{
		    Dwarf_Unsigned utmp2;

		    if (opcode_length[DW_LNS_advance_pc] != 1) {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_NUM_OPERANDS_BAD);
			return (DW_DLV_ERROR);
		    }

		    DECODE_LEB128_UWORD(line_ptr, utmp2)
			printf("DW_LNS_advance_pc val %lld 0x%llx\n",
			       (long long) (Dwarf_Word) utmp2,
			       (long long) (Dwarf_Word) utmp2);
		    leb128_num = (Dwarf_Word) utmp2;
		    address =
			address +
			minimum_instruction_length * leb128_num;
		    break;
		}

	    case DW_LNS_advance_line:{
		    Dwarf_Signed stmp;

		    if (opcode_length[DW_LNS_advance_line] != 1) {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_NUM_OPERANDS_BAD);
			return (DW_DLV_ERROR);
		    }

		    DECODE_LEB128_SWORD(line_ptr, stmp)
			advance_line = (Dwarf_Sword) stmp;
		    printf("DW_LNS_advance_line val %lld 0x%llx\n",
			   (long long) advance_line,
			   (long long) advance_line);
		    line = line + advance_line;
		    break;
		}

	    case DW_LNS_set_file:{
		    Dwarf_Unsigned utmp2;

		    if (opcode_length[DW_LNS_set_file] != 1) {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_NUM_OPERANDS_BAD);
			return (DW_DLV_ERROR);
		    }

		    DECODE_LEB128_UWORD(line_ptr, utmp2)
			file = (Dwarf_Word) utmp2;
		    printf("DW_LNS_set_file  %ld\n", (long) file);
		    break;
		}

	    case DW_LNS_set_column:{
		    Dwarf_Unsigned utmp2;

		    if (opcode_length[DW_LNS_set_column] != 1) {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_NUM_OPERANDS_BAD);
			return (DW_DLV_ERROR);
		    }

		    DECODE_LEB128_UWORD(line_ptr, utmp2)
			column = (Dwarf_Word) utmp2;
		    printf("DW_LNS_set_column val %lld 0x%llx\n",
			   (long long) column, (long long) column);
		    break;
		}

	    case DW_LNS_negate_stmt:{
		    if (opcode_length[DW_LNS_negate_stmt] != 0) {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_NUM_OPERANDS_BAD);
			return (DW_DLV_ERROR);
		    }

		    is_stmt = !is_stmt;
		    printf("DW_LNS_negate_stmt\n");
		    break;
		}

	    case DW_LNS_set_basic_block:{
		    if (opcode_length[DW_LNS_set_basic_block] != 0) {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_NUM_OPERANDS_BAD);
			return (DW_DLV_ERROR);
		    }

		    printf("DW_LNS_set_basic_block\n");
		    basic_block = true;
		    break;
		}

	    case DW_LNS_const_add_pc:{
		    opcode = MAX_LINE_OP_CODE - opcode_base;
		    address = address + minimum_instruction_length *
			(opcode / line_range);

		    printf("DW_LNS_const_add_pc new address 0x%llx\n",
			   (long long) address);
		    break;
		}

	    case DW_LNS_fixed_advance_pc:{
		    if (opcode_length[DW_LNS_fixed_advance_pc] != 1) {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_NUM_OPERANDS_BAD);
			return (DW_DLV_ERROR);
		    }

		    READ_UNALIGNED(dbg, fixed_advance_pc, Dwarf_Half,
				   line_ptr, sizeof(Dwarf_Half));
		    line_ptr += sizeof(Dwarf_Half);
		    address = address + fixed_advance_pc;
		    printf("DW_LNS_fixed_advance_pc val %lld 0x%llx"
			   " new address 0x%llx\n",
			   (long long) fixed_advance_pc,
			   (long long) fixed_advance_pc,
			   (long long) address);
		    break;
		}
	    }

	} else if (type == LOP_EXTENDED) {
	    Dwarf_Unsigned utmp3;

	    DECODE_LEB128_UWORD(line_ptr, utmp3)
		instr_length = (Dwarf_Word) utmp3;
	    ext_opcode = *(Dwarf_Small *) line_ptr;
	    line_ptr++;
	    switch (ext_opcode) {

	    case DW_LNE_end_sequence:{
		    end_sequence = true;

		    print_line_detail("DW_LNE_end_sequence extended",
				      opcode, address, file, line,
				      column, is_stmt, basic_block,
				      end_sequence);

		    address = 0;
		    file = 1;
		    line = 1;
		    column = 0;
		    is_stmt = default_is_stmt;
		    basic_block = false;
		    end_sequence = false;

		    break;
		}

	    case DW_LNE_set_address:{
		    if (instr_length - 1 == dbg->de_pointer_size) {
			READ_UNALIGNED(dbg, address, Dwarf_Addr,
				       line_ptr, dbg->de_pointer_size);

			line_ptr += dbg->de_pointer_size;
			printf("DW_LNE_set_address address 0x%llx\n",
			       (long long) address);
		    } else {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_SET_ADDR_ERROR);
			return (DW_DLV_ERROR);
		    }

		    break;
		}

	    case DW_LNE_define_file:{


		    Dwarf_Small *fn;
		    Dwarf_Signed di;
		    Dwarf_Signed tlm;
		    Dwarf_Unsigned fl;

		    fn = (Dwarf_Small *) line_ptr;
		    line_ptr = line_ptr + strlen((char *) line_ptr) + 1;

		    di = _dwarf_decode_u_leb128(line_ptr,
						&leb128_length);
		    line_ptr = line_ptr + leb128_length;

		    tlm =
			_dwarf_decode_u_leb128(line_ptr,
					       &leb128_length);
		    line_ptr = line_ptr + leb128_length;

		    fl = _dwarf_decode_u_leb128(line_ptr,
						&leb128_length);
		    line_ptr = line_ptr + leb128_length;


		    printf("DW_LNE_define_file %s \n", fn);
		    printf("    dir index %d\n", (int) di);
		    {
			time_t tt3 = (time_t) tlm;

			/* ctime supplies newline */
			printf("    last time 0x%x %s",
			       (unsigned) tlm, ctime(&tt3));
		    }
		    printf("    file length %ld 0x%lx\n",
			   (long) fl, (unsigned long) fl);

		    break;
		}

	    default:{
		    _dwarf_error(dbg, error,
				 DW_DLE_LINE_EXT_OPCODE_BAD);
		    return (DW_DLV_ERROR);
		}
	    }

	}
    }

    return (DW_DLV_OK);
}