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); }
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; }
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); }
/* 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; }
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); }
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); }
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; }
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; }
/* 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; }
/* 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; }
/* 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; }
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; }
/*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; }
/* 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); }
/* 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); }
/* 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); }
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); }
/* 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); }
/* 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; }
/* 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); }
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; }
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; }
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; }
/* 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); }
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; }
/* 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; }
/* 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); }