/* This function takes an Dwarf_Arange, and returns the offset of the first die in the compilation-unit that the arange belongs to. Returns DW_DLV_ERROR on error. */ int dwarf_get_cu_die_offset(Dwarf_Arange arange, Dwarf_Off * returned_offset, Dwarf_Error * error) { Dwarf_Debug dbg; Dwarf_Off offset; if (arange == NULL) { _dwarf_error(NULL, error, DW_DLE_ARANGE_NULL); return (DW_DLV_ERROR); } dbg = arange->ar_dbg; offset = arange->ar_info_offset; if(!dbg->de_debug_info) { int res = _dwarf_load_debug_info(dbg,error); if(res != DW_DLV_OK) { return res; } } *returned_offset = offset + _dwarf_length_of_cu_header(dbg, offset); return DW_DLV_OK; }
/* This function takes a Dwarf_Arange, and returns true if it is not NULL. It also stores the start address of the range in *start, the length of the range in *length, and the offset of the first die in the compilation-unit in *cu_die_offset. It returns false on error. If cu_die_offset returned ensures .debug_info loaded so the cu_die_offset is meaningful. */ int dwarf_get_arange_info(Dwarf_Arange arange, Dwarf_Addr * start, Dwarf_Unsigned * length, Dwarf_Off * cu_die_offset, Dwarf_Error * error) { if (arange == NULL) { _dwarf_error(NULL, error, DW_DLE_ARANGE_NULL); return (DW_DLV_ERROR); } if (start != NULL) *start = arange->ar_address; if (length != NULL) *length = arange->ar_length; if (cu_die_offset != NULL) { Dwarf_Debug dbg = arange->ar_dbg; Dwarf_Off offset = arange->ar_info_offset; /* This applies to debug_info only, not to debug_types. */ if (!dbg->de_debug_info.dss_data) { int res = _dwarf_load_debug_info(dbg, error); if (res != DW_DLV_OK) { return res; } } *cu_die_offset = offset + _dwarf_length_of_cu_header(dbg, offset,true); } return (DW_DLV_OK); }
/* This function takes an Dwarf_Arange, and returns the offset of the first die in the compilation-unit that the arange belongs to. Returns DW_DLV_ERROR on error. For an arange, the cu_die can only be from debug_info, not debug_types, it seems. */ int dwarf_get_cu_die_offset(Dwarf_Arange arange, Dwarf_Off * returned_offset, Dwarf_Error * error) { Dwarf_Debug dbg = 0; Dwarf_Off offset = 0; if (arange == NULL) { _dwarf_error(NULL, error, DW_DLE_ARANGE_NULL); return (DW_DLV_ERROR); } dbg = arange->ar_dbg; offset = arange->ar_info_offset; /* This applies to debug_info only, not to debug_types. */ if (!dbg->de_debug_info.dss_data) { int res = _dwarf_load_debug_info(dbg, error); if (res != DW_DLV_OK) { return res; } } *returned_offset = offset + _dwarf_length_of_cu_header(dbg, offset, true); return DW_DLV_OK; }
/* This function takes an Dwarf_Arange, and returns the offset of the CU header in the compilation-unit that the arange belongs to. Returns DW_DLV_ERROR on error. Ensures .debug_info loaded so the cu_offset is meaningful. */ int dwarf_get_arange_cu_header_offset(Dwarf_Arange arange, Dwarf_Off * cu_header_offset_returned, Dwarf_Error * error) { Dwarf_Debug dbg = 0; if (arange == NULL) { _dwarf_error(NULL, error, DW_DLE_ARANGE_NULL); return (DW_DLV_ERROR); } dbg = arange->ar_dbg; /* This applies to debug_info only, not to debug_types. */ /* Like dwarf_get_arange_info this ensures debug_info loaded: the cu_header is in debug_info and will be used else we would not call dwarf_get_arange_cu_header_offset. */ if (!dbg->de_debug_info.dss_data) { int res = _dwarf_load_debug_info(dbg, error); if (res != DW_DLV_OK) { return res; } } *cu_header_offset_returned = arange->ar_info_offset; return DW_DLV_OK; }
int dwarf_get_abbrev(Dwarf_Debug dbg, Dwarf_Unsigned offset, Dwarf_Abbrev * returned_abbrev, Dwarf_Unsigned * length, Dwarf_Unsigned * abbr_count, Dwarf_Error * error) { Dwarf_Small *abbrev_ptr; Dwarf_Small *abbrev_section_end; Dwarf_Half attr; Dwarf_Half attr_form; Dwarf_Abbrev ret_abbrev; Dwarf_Unsigned labbr_count = 0; Dwarf_Unsigned utmp; if (dbg == NULL) { _dwarf_error(NULL, error, DW_DLE_DBG_NULL); return (DW_DLV_ERROR); } if (dbg->de_debug_abbrev == 0) { /* Loads abbrev section (and .debug_info as we do those together). */ int res = _dwarf_load_debug_info(dbg, error); if (res != DW_DLV_OK) { return res; } } if (offset >= dbg->de_debug_abbrev_size) { return (DW_DLV_NO_ENTRY); } ret_abbrev = (Dwarf_Abbrev) _dwarf_get_alloc(dbg, DW_DLA_ABBREV, 1); if (ret_abbrev == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } ret_abbrev->ab_dbg = dbg; if (returned_abbrev == 0 || abbr_count == 0) { dwarf_dealloc(dbg, ret_abbrev, DW_DLA_ABBREV); _dwarf_error(dbg, error, DW_DLE_DWARF_ABBREV_NULL); return (DW_DLV_ERROR); } *abbr_count = 0; if (length != NULL) *length = 1; abbrev_ptr = dbg->de_debug_abbrev + offset; abbrev_section_end = dbg->de_debug_abbrev + dbg->de_debug_abbrev_size; DECODE_LEB128_UWORD(abbrev_ptr, utmp); ret_abbrev->ab_code = (Dwarf_Word) utmp; if (ret_abbrev->ab_code == 0) { *returned_abbrev = ret_abbrev; *abbr_count = 0; if (length) { *length = 1; } return (DW_DLV_OK); } DECODE_LEB128_UWORD(abbrev_ptr, utmp); ret_abbrev->ab_tag = utmp; ret_abbrev->ab_has_child = *(abbrev_ptr++); ret_abbrev->ab_abbrev_ptr = abbrev_ptr; do { Dwarf_Unsigned utmp2; DECODE_LEB128_UWORD(abbrev_ptr, utmp2) attr = (Dwarf_Half) utmp2; DECODE_LEB128_UWORD(abbrev_ptr, utmp2) attr_form = (Dwarf_Half) utmp2; if (attr != 0) (labbr_count)++; } while (abbrev_ptr < abbrev_section_end && (attr != 0 || attr_form != 0)); if (abbrev_ptr > abbrev_section_end) { dwarf_dealloc(dbg, ret_abbrev, DW_DLA_ABBREV); _dwarf_error(dbg, error, DW_DLE_ABBREV_DECODE_ERROR); return (DW_DLV_ERROR); } if (length != NULL) *length = abbrev_ptr - dbg->de_debug_abbrev - offset; *returned_abbrev = ret_abbrev; *abbr_count = labbr_count; return (DW_DLV_OK); }
static int dwarf_next_cu_header_internal(Dwarf_Debug dbg, Dwarf_Bool is_info, Dwarf_Unsigned * cu_header_length, Dwarf_Half * version_stamp, Dwarf_Unsigned * abbrev_offset, Dwarf_Half * address_size, Dwarf_Half * offset_size, Dwarf_Half * extension_size, Dwarf_Sig8 * signature, Dwarf_Unsigned *typeoffset, Dwarf_Unsigned * next_cu_offset, Dwarf_Error * error) { /* Offset for current and new CU. */ Dwarf_Unsigned new_offset = 0; /* CU Context for current CU. */ Dwarf_CU_Context cu_context = 0; Dwarf_Debug_InfoTypes dis = 0; Dwarf_Unsigned section_size = 0; /* ***** BEGIN CODE ***** */ if (dbg == NULL) { _dwarf_error(NULL, error, DW_DLE_DBG_NULL); return (DW_DLV_ERROR); } dis = is_info? &dbg->de_info_reading: &dbg->de_types_reading; /* Get offset into .debug_info of next CU. If dbg has no context, this has to be the first one. */ if (dis->de_cu_context == NULL) { new_offset = 0; Dwarf_Small *dataptr = is_info? dbg->de_debug_info.dss_data: dbg->de_debug_types.dss_data; if (!dataptr) { Dwarf_Error err2= 0; int res = is_info?_dwarf_load_debug_info(dbg, &err2): _dwarf_load_debug_types(dbg,&err2); if (res != DW_DLV_OK) { if(reloc_incomplete(err2)) { /* We will assume all is ok, though it is not. Relocation errors need not be fatal. */ char msg_buf[200]; snprintf(msg_buf,sizeof(msg_buf), "Relocations did not complete successfully, but we are " " ignoring error: %s",dwarf_errmsg(err2)); dwarf_insert_harmless_error(dbg,msg_buf); res = DW_DLV_OK; } else { if( error) { *error = err2; } return res; } } } } else { new_offset = dis->de_cu_context->cc_debug_offset + dis->de_cu_context->cc_length + dis->de_cu_context->cc_length_size + dis->de_cu_context->cc_extension_size; } /* Check that there is room in .debug_info beyond the new offset for at least a new cu header. If not, return 0 to indicate end of debug_info section, and reset de_cu_debug_info_offset to enable looping back through the cu's. */ section_size = is_info? dbg->de_debug_info.dss_size: dbg->de_debug_types.dss_size; if ((new_offset + _dwarf_length_of_cu_header_simple(dbg,is_info)) >= section_size) { dis->de_cu_context = NULL; return (DW_DLV_NO_ENTRY); } /* Check if this CU has been read before. */ cu_context = _dwarf_find_CU_Context(dbg, new_offset,is_info); /* If not, make CU Context for it. */ if (cu_context == NULL) { cu_context = _dwarf_make_CU_Context(dbg, new_offset,is_info, error); if (cu_context == NULL) { /* Error if CU Context could not be made. Since _dwarf_make_CU_Context has already registered an error we do not do that here: we let the lower error pass thru. */ return (DW_DLV_ERROR); } } dis->de_cu_context = cu_context; if (cu_header_length != NULL) { *cu_header_length = cu_context->cc_length; } if (version_stamp != NULL) { *version_stamp = cu_context->cc_version_stamp; } if (abbrev_offset != NULL) { *abbrev_offset = cu_context->cc_abbrev_offset; } if (address_size != NULL) { *address_size = cu_context->cc_address_size; } if (offset_size != NULL) { *offset_size = cu_context->cc_length_size; } if (extension_size != NULL) { *extension_size = cu_context->cc_extension_size; } if(!is_info) { if(signature) { *signature = cu_context->cc_signature; } if(typeoffset) { *typeoffset = cu_context->cc_typeoffset; } } new_offset = new_offset + cu_context->cc_length + cu_context->cc_length_size + cu_context->cc_extension_size; *next_cu_offset = new_offset; return (DW_DLV_OK); }
int dwarf_offdie_b(Dwarf_Debug dbg, Dwarf_Off offset, Dwarf_Bool is_info, Dwarf_Die * new_die, Dwarf_Error * error) { Dwarf_CU_Context cu_context = 0; Dwarf_Off new_cu_offset = 0; Dwarf_Die die = 0; Dwarf_Byte_Ptr info_ptr = 0; Dwarf_Unsigned abbrev_code = 0; Dwarf_Unsigned utmp = 0; Dwarf_Debug_InfoTypes dis = 0; if (dbg == NULL) { _dwarf_error(NULL, error, DW_DLE_DBG_NULL); return (DW_DLV_ERROR); } dis = is_info? &dbg->de_info_reading: &dbg->de_types_reading; cu_context = _dwarf_find_CU_Context(dbg, offset,is_info); if (cu_context == NULL) cu_context = _dwarf_find_offdie_CU_Context(dbg, offset,is_info); if (cu_context == NULL) { Dwarf_Unsigned section_size = is_info? dbg->de_debug_info.dss_size: dbg->de_debug_types.dss_size; int res = is_info?_dwarf_load_debug_info(dbg, error): _dwarf_load_debug_types(dbg,error); if (res != DW_DLV_OK) { return res; } if (dis->de_offdie_cu_context_end != NULL) { Dwarf_CU_Context lcu_context = dis->de_offdie_cu_context_end; new_cu_offset = lcu_context->cc_debug_offset + lcu_context->cc_length + lcu_context->cc_length_size + lcu_context->cc_extension_size; } do { if ((new_cu_offset + _dwarf_length_of_cu_header_simple(dbg,is_info)) >= section_size) { _dwarf_error(dbg, error, DW_DLE_OFFSET_BAD); return (DW_DLV_ERROR); } cu_context = _dwarf_make_CU_Context(dbg, new_cu_offset,is_info, error); if (cu_context == NULL) { /* Error if CU Context could not be made. Since _dwarf_make_CU_Context has already registered an error we do not do that here: we let the lower error pass thru. */ return (DW_DLV_ERROR); } if (dis->de_offdie_cu_context == NULL) { dis->de_offdie_cu_context = cu_context; dis->de_offdie_cu_context_end = cu_context; } else { dis->de_offdie_cu_context_end->cc_next = cu_context; dis->de_offdie_cu_context_end = cu_context; } new_cu_offset = new_cu_offset + cu_context->cc_length + cu_context->cc_length_size; } while (offset >= new_cu_offset); } die = (Dwarf_Die) _dwarf_get_alloc(dbg, DW_DLA_DIE, 1); if (die == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } die->di_cu_context = cu_context; die->di_is_info = is_info; { Dwarf_Small *dataptr = is_info? dbg->de_debug_info.dss_data: dbg->de_debug_types.dss_data; info_ptr = dataptr + offset; } die->di_debug_ptr = info_ptr; DECODE_LEB128_UWORD(info_ptr, utmp); abbrev_code = utmp; if (abbrev_code == 0) { /* we are at a null DIE (or there is a bug). */ *new_die = 0; dwarf_dealloc(dbg, die, DW_DLA_DIE); return DW_DLV_NO_ENTRY; } die->di_abbrev_code = abbrev_code; die->di_abbrev_list = _dwarf_get_abbrev_for_code(cu_context, abbrev_code); if (die->di_abbrev_list == NULL) { dwarf_dealloc(dbg, die, DW_DLA_DIE); _dwarf_error(dbg, error, DW_DLE_DIE_ABBREV_LIST_NULL); return (DW_DLV_ERROR); } *new_die = die; return (DW_DLV_OK); }
/* Give back the pubnames entry (or any other like section) name, symbol DIE offset, and the cu-DIE offset. Various errors are possible. The string pointer returned thru ret_name is not dwarf_get_alloc()ed, so no dwarf_dealloc() DW_DLA_STRING should be applied to it. */ int dwarf_global_name_offsets(Dwarf_Global global, char **ret_name, Dwarf_Off * die_offset, Dwarf_Off * cu_die_offset, Dwarf_Error * error) { Dwarf_Global_Context con = 0; Dwarf_Debug dbg = 0; Dwarf_Off off = 0; if (global == NULL) { _dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL); return (DW_DLV_ERROR); } con = global->gl_context; if (con == NULL) { _dwarf_error(NULL, error, DW_DLE_GLOBAL_CONTEXT_NULL); return (DW_DLV_ERROR); } off = con->pu_offset_of_cu_header; /* The offset had better not be too close to the end. If it is, _dwarf_length_of_cu_header() will step off the end and therefore must not be used. 10 is a meaningless heuristic, but no CU header is that small so it is safe. An erroneous offset is due to a bug in the tool chain. A bug like this has been seen on IRIX with MIPSpro 7.3.1.3 and an executable > 2GB in size and with 2 million pubnames entries. */ #define MIN_CU_HDR_SIZE 10 dbg = con->pu_dbg; if (dbg == NULL) { _dwarf_error(NULL, error, DW_DLE_DBG_NULL); return (DW_DLV_ERROR); } /* Cannot refer to debug_types */ if (dbg->de_debug_info.dss_size && ((off + MIN_CU_HDR_SIZE) >= dbg->de_debug_info.dss_size)) { _dwarf_error(NULL, error, DW_DLE_OFFSET_BAD); return (DW_DLV_ERROR); } #undef MIN_CU_HDR_SIZE if (die_offset != NULL) { *die_offset = global->gl_named_die_offset_within_cu + off; } *ret_name = (char *) global->gl_name; if (cu_die_offset != NULL) { /* Globals cannot refer to debug_types */ int cres = 0; Dwarf_Unsigned headerlen = 0; int res = _dwarf_load_debug_info(dbg, error); if (res != DW_DLV_OK) { return res; } /* The offset had better not be too close to the end. If it is, _dwarf_length_of_cu_header() will step off the end and therefore must not be used. 10 is a meaningless heuristic, but no CU header is that small so it is safe. */ /* Globals cannot refer to debug_types */ if ((off + 10) >= dbg->de_debug_info.dss_size) { _dwarf_error(NULL, error, DW_DLE_OFFSET_BAD); return (DW_DLV_ERROR); } cres = _dwarf_length_of_cu_header(dbg, off,true, &headerlen,error); if(cres != DW_DLV_OK) { return cres; } *cu_die_offset = off + headerlen; } return DW_DLV_OK; }
/* Sweeps the complete section. */ int _dwarf_internal_get_pubnames_like_data(Dwarf_Debug dbg, Dwarf_Small * section_data_ptr, Dwarf_Unsigned section_length, Dwarf_Global ** globals, Dwarf_Signed * return_count, Dwarf_Error * error, int context_code, int global_code, int length_err_num, int version_err_num) { Dwarf_Small *pubnames_like_ptr = 0; Dwarf_Small *section_end_ptr = section_data_ptr +section_length; /* Points to the context for the current set of global names, and contains information to identify the compilation-unit that the set refers to. */ Dwarf_Global_Context pubnames_context = 0; Dwarf_Half version = 0; /* Offset from the start of compilation-unit for the current global. */ Dwarf_Off die_offset_in_cu = 0; Dwarf_Unsigned global_count = 0; /* Points to the current global read. */ Dwarf_Global global = 0; /* Used to chain the Dwarf_Global_s structs for creating contiguous list of pointers to the structs. */ Dwarf_Chain curr_chain = 0; Dwarf_Chain prev_chain = 0; Dwarf_Chain head_chain = 0; /* Points to contiguous block of Dwarf_Global's to be returned. */ Dwarf_Global *ret_globals = 0; /* Temporary counter. */ Dwarf_Unsigned i = 0; if (dbg == NULL) { _dwarf_error(NULL, error, DW_DLE_DBG_NULL); return (DW_DLV_ERROR); } /* We will eventually need the .debug_info data. Load it now. */ if (!dbg->de_debug_info.dss_data) { int res = _dwarf_load_debug_info(dbg, error); if (res != DW_DLV_OK) { return res; } } if (section_data_ptr == NULL) { return (DW_DLV_NO_ENTRY); } pubnames_like_ptr = section_data_ptr; do { Dwarf_Unsigned length = 0; int local_extension_size = 0; int local_length_size = 0; /* Some compilers emit padding at the end of each cu's area. pubnames_ptr_past_end_cu records the true area end for the pubnames(like) content of a cu. Essentially the length in the header and the 0 terminator of the data are redundant information. The dwarf2/3 spec does not mention what to do if the length is past the 0 terminator. So we take any bytes left after the 0 as padding and ignore them. */ Dwarf_Small *pubnames_ptr_past_end_cu = 0; pubnames_context = (Dwarf_Global_Context) _dwarf_get_alloc(dbg, context_code, 1); if (pubnames_context == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } /* READ_AREA_LENGTH updates pubnames_like_ptr for consumed bytes. */ READ_AREA_LENGTH_CK(dbg, length, Dwarf_Unsigned, pubnames_like_ptr, local_length_size, local_extension_size,error,section_length,section_end_ptr); pubnames_context->pu_length_size = local_length_size; pubnames_context->pu_extension_size = local_extension_size; pubnames_context->pu_dbg = dbg; pubnames_ptr_past_end_cu = pubnames_like_ptr + length; READ_UNALIGNED_CK(dbg, version, Dwarf_Half, pubnames_like_ptr, DWARF_HALF_SIZE, error,section_end_ptr); pubnames_like_ptr += DWARF_HALF_SIZE; /* ASSERT: DW_PUBNAMES_VERSION2 == DW_PUBTYPES_VERSION2 */ if (version != DW_PUBNAMES_VERSION2) { _dwarf_error(dbg, error, version_err_num); return (DW_DLV_ERROR); } /* Offset of CU header in debug section. */ READ_UNALIGNED_CK(dbg, pubnames_context->pu_offset_of_cu_header, Dwarf_Off, pubnames_like_ptr, pubnames_context->pu_length_size, error,section_end_ptr); pubnames_like_ptr += pubnames_context->pu_length_size; FIX_UP_OFFSET_IRIX_BUG(dbg, pubnames_context->pu_offset_of_cu_header, "pubnames cu header offset"); READ_UNALIGNED_CK(dbg, pubnames_context->pu_info_length, Dwarf_Unsigned, pubnames_like_ptr, pubnames_context->pu_length_size, error,section_end_ptr); pubnames_like_ptr += pubnames_context->pu_length_size; if (pubnames_like_ptr > (section_data_ptr + section_length)) { _dwarf_error(dbg, error, length_err_num); return (DW_DLV_ERROR); } /* Read initial offset (of DIE within CU) of a pubname, final entry is not a pair, just a zero offset. */ READ_UNALIGNED_CK(dbg, die_offset_in_cu, Dwarf_Off, pubnames_like_ptr, pubnames_context->pu_length_size, error,section_end_ptr); pubnames_like_ptr += pubnames_context->pu_length_size; FIX_UP_OFFSET_IRIX_BUG(dbg, die_offset_in_cu, "offset of die in cu"); /* Loop thru pairs. DIE off with CU followed by string. */ while (die_offset_in_cu != 0) { int res; /* Already read offset, pubnames_like_ptr now points to the string. */ global = (Dwarf_Global) _dwarf_get_alloc(dbg, global_code, 1); if (global == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } global_count++; global->gl_context = pubnames_context; global->gl_named_die_offset_within_cu = die_offset_in_cu; global->gl_name = pubnames_like_ptr; res = _dwarf_check_string_valid(dbg,section_data_ptr, pubnames_like_ptr,section_end_ptr, DW_DLE_STRING_OFF_END_PUBNAMES_LIKE,error); if (res != DW_DLV_OK) { return res; } pubnames_like_ptr = pubnames_like_ptr + strlen((char *) pubnames_like_ptr) + 1; /* Finish off current entry chain */ 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); } /* Put current global on singly_linked list. */ curr_chain->ch_item = (Dwarf_Global) global; if (head_chain == NULL) head_chain = prev_chain = curr_chain; else { prev_chain->ch_next = curr_chain; prev_chain = curr_chain; } /* Fead offset for the *next* entry */ READ_UNALIGNED_CK(dbg, die_offset_in_cu, Dwarf_Off, pubnames_like_ptr, pubnames_context->pu_length_size, error,section_end_ptr); pubnames_like_ptr += pubnames_context->pu_length_size; FIX_UP_OFFSET_IRIX_BUG(dbg, die_offset_in_cu, "offset of next die in cu"); if (pubnames_like_ptr > (section_data_ptr + section_length)) { _dwarf_error(dbg, error, length_err_num); return (DW_DLV_ERROR); } } /* ASSERT: die_offset_in_cu == 0 */ if (pubnames_like_ptr > pubnames_ptr_past_end_cu) { /* This is some kind of error. This simply cannot happen. The encoding is wrong or the length in the header for this cu's contribution is wrong. */ _dwarf_error(dbg, error, length_err_num); return (DW_DLV_ERROR); } /* If there is some kind of padding at the end of the section, as emitted by some compilers, skip over that padding and simply ignore the bytes thus passed-over. With most compilers, pubnames_like_ptr == pubnames_ptr_past_end_cu at this point */ pubnames_like_ptr = pubnames_ptr_past_end_cu; } while (pubnames_like_ptr < (section_data_ptr + section_length)); /* Points to contiguous block of Dwarf_Global's. */ ret_globals = (Dwarf_Global *) _dwarf_get_alloc(dbg, DW_DLA_LIST, global_count); if (ret_globals == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } /* Store pointers to Dwarf_Global_s structs in contiguous block, and deallocate the chain. */ curr_chain = head_chain; for (i = 0; i < global_count; i++) { *(ret_globals + i) = curr_chain->ch_item; prev_chain = curr_chain; curr_chain = curr_chain->ch_next; dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN); } *globals = ret_globals; *return_count = (Dwarf_Signed) global_count; return DW_DLV_OK; }
/* Given a die offset, this returns a pointer to a DIE thru *new_die. It is up to the caller to do a dwarf_dealloc(dbg,*new_die,DW_DLE_DIE); */ int dwarf_offdie(Dwarf_Debug dbg, Dwarf_Off offset, Dwarf_Die * new_die, Dwarf_Error * error) { Dwarf_CU_Context cu_context; Dwarf_Off new_cu_offset = 0; Dwarf_Die die; Dwarf_Byte_Ptr info_ptr; Dwarf_Half abbrev_code; Dwarf_Unsigned utmp; if (dbg == NULL) { _dwarf_error(NULL, error, DW_DLE_DBG_NULL); return (DW_DLV_ERROR); } cu_context = _dwarf_find_CU_Context(dbg, offset); if (cu_context == NULL) cu_context = _dwarf_find_offdie_CU_Context(dbg, offset); if (cu_context == NULL) { int res = _dwarf_load_debug_info(dbg, error); if (res != DW_DLV_OK) { return res; } if (dbg->de_cu_context_list_end != NULL) new_cu_offset = dbg->de_cu_context_list_end->cc_debug_info_offset + dbg->de_cu_context_list_end->cc_length + dbg->de_cu_context_list_end->cc_length_size + dbg->de_cu_context_list_end->cc_extension_size; do { if ((new_cu_offset + _dwarf_length_of_cu_header_simple(dbg)) >= dbg->de_debug_info_size) { _dwarf_error(dbg, error, DW_DLE_OFFSET_BAD); return (DW_DLV_ERROR); } cu_context = _dwarf_make_CU_Context(dbg, new_cu_offset, error); if (cu_context == NULL) { /* Error if CU Context could not be made. Since _dwarf_make_CU_Context has already registered an error we do not do that here: we let the lower error pass thru. */ return (DW_DLV_ERROR); } if (dbg->de_offdie_cu_context == NULL) { dbg->de_offdie_cu_context = cu_context; dbg->de_offdie_cu_context_end = cu_context; } else { dbg->de_offdie_cu_context_end->cc_next = cu_context; dbg->de_offdie_cu_context_end = cu_context; } new_cu_offset = new_cu_offset + cu_context->cc_length + cu_context->cc_length_size; } while (offset >= new_cu_offset); } die = (Dwarf_Die) _dwarf_get_alloc(dbg, DW_DLA_DIE, 1); if (die == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } die->di_cu_context = cu_context; info_ptr = dbg->de_debug_info + offset; die->di_debug_info_ptr = info_ptr; DECODE_LEB128_UWORD(info_ptr, utmp) abbrev_code = (Dwarf_Half) utmp; if (abbrev_code == 0) { /* we are at a null DIE (or there is a bug). */ *new_die = 0; return DW_DLV_NO_ENTRY; } die->di_abbrev_list = _dwarf_get_abbrev_for_code(cu_context, abbrev_code); if (die->di_abbrev_list == NULL) { _dwarf_error(dbg, error, DW_DLE_DIE_ABBREV_LIST_NULL); return (DW_DLV_ERROR); } *new_die = die; return (DW_DLV_OK); }
/* Returns offset of next compilation-unit thru next_cu_offset pointer. It basically sequentially moves from one cu to the next. The current cu is recorded internally by libdwarf. */ int dwarf_next_cu_header(Dwarf_Debug dbg, Dwarf_Unsigned * cu_header_length, Dwarf_Half * version_stamp, Dwarf_Unsigned * abbrev_offset, Dwarf_Half * address_size, Dwarf_Unsigned * next_cu_offset, Dwarf_Error * error) { /* Offset for current and new CU. */ Dwarf_Unsigned new_offset; /* CU Context for current CU. */ Dwarf_CU_Context cu_context; /* ***** BEGIN CODE ***** */ if (dbg == NULL) { _dwarf_error(NULL, error, DW_DLE_DBG_NULL); return (DW_DLV_ERROR); } /* Get offset into .debug_info of next CU. If dbg has no context, this has to be the first one. */ if (dbg->de_cu_context == NULL) { new_offset = 0; if (!dbg->de_debug_info) { int res = _dwarf_load_debug_info(dbg, error); if (res != DW_DLV_OK) { return res; } } } else { new_offset = dbg->de_cu_context->cc_debug_info_offset + dbg->de_cu_context->cc_length + dbg->de_cu_context->cc_length_size + dbg->de_cu_context->cc_extension_size; } /* Check that there is room in .debug_info beyond the new offset for at least a new cu header. If not, return 0 to indicate end of debug_info section, and reset de_cu_debug_info_offset to enable looping back through the cu's. */ if ((new_offset + _dwarf_length_of_cu_header_simple(dbg)) >= dbg->de_debug_info_size) { dbg->de_cu_context = NULL; return (DW_DLV_NO_ENTRY); } /* Check if this CU has been read before. */ cu_context = _dwarf_find_CU_Context(dbg, new_offset); /* If not, make CU Context for it. */ if (cu_context == NULL) { cu_context = _dwarf_make_CU_Context(dbg, new_offset, error); if (cu_context == NULL) { /* Error if CU Context could not be made. Since _dwarf_make_CU_Context has already registered an error we do not do that here: we let the lower error pass thru. */ return (DW_DLV_ERROR); } } dbg->de_cu_context = cu_context; if (cu_header_length != NULL) *cu_header_length = cu_context->cc_length; if (version_stamp != NULL) *version_stamp = cu_context->cc_version_stamp; if (abbrev_offset != NULL) *abbrev_offset = cu_context->cc_abbrev_offset; if (address_size != NULL) *address_size = cu_context->cc_address_size; new_offset = new_offset + cu_context->cc_length + cu_context->cc_length_size + cu_context->cc_extension_size; *next_cu_offset = new_offset; return (DW_DLV_OK); }