/* 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. */ 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 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; }
/* Give back the pubnames entry (or any other like section) name, symbol DIE offset, and the cu-DIE offset. */ 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; Dwarf_Off off; 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; if (die_offset != NULL) { *die_offset = global->gl_named_die_offset_within_cu + off; } if (cu_die_offset != NULL) { *cu_die_offset = off + _dwarf_length_of_cu_header(global->gl_context->pu_dbg, off); } *ret_name = (char *)global->gl_name; return DW_DLV_OK; }
/* ARGSUSED */ int dwarf_get_cu_die_offset_given_cu_header_offset(Dwarf_Debug dbg, Dwarf_Off in_cu_header_offset, Dwarf_Off * out_cu_die_offset, UNUSEDARG Dwarf_Error * err) { Dwarf_Off headerlen = 0; int cres = 0; cres = _dwarf_length_of_cu_header(dbg, in_cu_header_offset,true, &headerlen,err); if (cres != DW_DLV_OK) { return cres; } *out_cu_die_offset = in_cu_header_offset + headerlen; return DW_DLV_OK; }
/* This is the new form, October 2011. On calling with 'die' NULL, we cannot tell if this is debug_info or debug_types, so we must be informed!. */ int dwarf_siblingof_b(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Bool is_info, Dwarf_Die * caller_ret_die, Dwarf_Error * error) { Dwarf_Die ret_die = 0; Dwarf_Byte_Ptr die_info_ptr = 0; Dwarf_Byte_Ptr cu_info_start = 0; /* die_info_end points 1-past end of die (once set) */ Dwarf_Byte_Ptr die_info_end = 0; Dwarf_Word abbrev_code = 0; Dwarf_Unsigned utmp = 0; /* Since die may be NULL, we rely on the input argument. */ Dwarf_Debug_InfoTypes dis = is_info? &dbg->de_info_reading: &dbg->de_types_reading; Dwarf_Small *dataptr = is_info? dbg->de_debug_info.dss_data: dbg->de_debug_types.dss_data; if (dbg == NULL) { _dwarf_error(NULL, error, DW_DLE_DBG_NULL); return (DW_DLV_ERROR); } if (die == NULL) { /* Find root die of cu */ /* die_info_end is untouched here, need not be set in this branch. */ Dwarf_Off off2; Dwarf_CU_Context context=0; /* If we've not loaded debug_info, de_cu_context will be NULL, so no need to laod */ context = dis->de_cu_context; if (context == NULL) { _dwarf_error(dbg, error, DW_DLE_DBG_NO_CU_CONTEXT); return (DW_DLV_ERROR); } off2 = context->cc_debug_offset; cu_info_start = dataptr + off2; die_info_ptr = cu_info_start + _dwarf_length_of_cu_header(dbg, off2,is_info); die_info_end = cu_info_start + context->cc_length + context->cc_length_size + context->cc_extension_size; } else { /* Find sibling die. */ Dwarf_Bool has_child = false; Dwarf_Sword child_depth = 0; Dwarf_CU_Context context=0; /* We cannot have a legal die unless debug_info was loaded, so no need to load debug_info here. */ CHECK_DIE(die, DW_DLV_ERROR); die_info_ptr = die->di_debug_ptr; if (*die_info_ptr == 0) { return (DW_DLV_NO_ENTRY); } context = die->di_cu_context; cu_info_start = dataptr+ context->cc_debug_offset; die_info_end = cu_info_start + context->cc_length + context->cc_length_size + context->cc_extension_size; if ((*die_info_ptr) == 0) { return (DW_DLV_NO_ENTRY); } child_depth = 0; do { die_info_ptr = _dwarf_next_die_info_ptr(die_info_ptr, die->di_cu_context, die_info_end, cu_info_start, true, &has_child); if (die_info_ptr == NULL) { _dwarf_error(dbg, error, DW_DLE_NEXT_DIE_PTR_NULL); return (DW_DLV_ERROR); } /* die_info_end is one past end. Do not read it! A test for ``!= die_info_end'' would work as well, but perhaps < reads more like the meaning. */ if(die_info_ptr < die_info_end) { if ((*die_info_ptr) == 0 && has_child) { die_info_ptr++; has_child = false; } } /* die_info_ptr can be one-past-end. */ if ((die_info_ptr == die_info_end) || ((*die_info_ptr) == 0)) { for (; child_depth > 0 && *die_info_ptr == 0; child_depth--, die_info_ptr++); } else { child_depth = has_child ? child_depth + 1 : child_depth; } } while (child_depth != 0); } /* die_info_ptr > die_info_end is really a bug (possibly in dwarf generation)(but we are past end, no more DIEs here), whereas die_info_ptr == die_info_end means 'one past end, no more DIEs here'. */ if (die_info_ptr >= die_info_end) { return (DW_DLV_NO_ENTRY); } if ((*die_info_ptr) == 0) { return (DW_DLV_NO_ENTRY); } ret_die = (Dwarf_Die) _dwarf_get_alloc(dbg, DW_DLA_DIE, 1); if (ret_die == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } ret_die->di_is_info = is_info; ret_die->di_debug_ptr = die_info_ptr; ret_die->di_cu_context = die == NULL ? dis->de_cu_context : die->di_cu_context; DECODE_LEB128_UWORD(die_info_ptr, utmp); if (die_info_ptr > die_info_end) { /* We managed to go past the end of the CU!. Something is badly wrong. */ dwarf_dealloc(dbg, ret_die, DW_DLA_DIE); _dwarf_error(dbg, error, DW_DLE_ABBREV_DECODE_ERROR); return (DW_DLV_ERROR); } abbrev_code = (Dwarf_Word) utmp; if (abbrev_code == 0) { /* Zero means a null DIE */ dwarf_dealloc(dbg, ret_die, DW_DLA_DIE); return (DW_DLV_NO_ENTRY); } ret_die->di_abbrev_code = abbrev_code; ret_die->di_abbrev_list = _dwarf_get_abbrev_for_code(ret_die->di_cu_context, abbrev_code); if (ret_die->di_abbrev_list == NULL ) { dwarf_dealloc(dbg, ret_die, DW_DLA_DIE); _dwarf_error(dbg, error, DW_DLE_DIE_ABBREV_LIST_NULL); return (DW_DLV_ERROR); } if (die == NULL && !is_cu_tag(ret_die->di_abbrev_list->ab_tag)) { dwarf_dealloc(dbg, ret_die, DW_DLA_DIE); _dwarf_error(dbg, error, DW_DLE_FIRST_DIE_NOT_CU); return (DW_DLV_ERROR); } *caller_ret_die = ret_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; }
/* Given a Dwarf_Debug dbg, and a Dwarf_Die die, it returns a Dwarf_Die for the sibling of die. In case die is NULL, it returns (thru ptr) a Dwarf_Die for the first die in the current cu in dbg. Returns DW_DLV_ERROR on error. It is assumed that every sibling chain including those with only one element is terminated with a NULL die, except a chain with only a NULL die. The algorithm moves from one die to the adjacent one. It returns when the depth of children it sees equals the number of sibling chain terminations. A single count, child_depth is used to track the depth of children and sibling terminations encountered. Child_depth is incremented when a die has the Has-Child flag set unless the child happens to be a NULL die. Child_depth is decremented when a die has Has-Child false, and the adjacent die is NULL. Algorithm returns when child_depth is 0. **NOTE: Do not modify input die, since it is used at the end. */ int dwarf_siblingof(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Die * caller_ret_die, Dwarf_Error * error) { Dwarf_Die ret_die; Dwarf_Byte_Ptr die_info_ptr; Dwarf_Byte_Ptr cu_info_start = 0; Dwarf_Byte_Ptr die_info_end = 0; Dwarf_Half abbrev_code; Dwarf_Unsigned utmp; if (dbg == NULL) { _dwarf_error(NULL, error, DW_DLE_DBG_NULL); return (DW_DLV_ERROR); } if (die == NULL) { /* Find root die of cu */ /* die_info_end is untouched here, need not be set in this branch. */ Dwarf_Off off2; /* If we've not loaded debug_info, de_cu_context will be NULL, so no need to laod */ if (dbg->de_cu_context == NULL) { _dwarf_error(dbg, error, DW_DLE_DBG_NO_CU_CONTEXT); return (DW_DLV_ERROR); } off2 = dbg->de_cu_context->cc_debug_info_offset; die_info_ptr = dbg->de_debug_info + off2 + _dwarf_length_of_cu_header(dbg, off2); } else { /* Find sibling die. */ Dwarf_Bool has_child; Dwarf_Sword child_depth; /* We cannot have a legal die unless debug_info was loaded, so no need to load debug_info here. */ CHECK_DIE(die, DW_DLV_ERROR) die_info_ptr = die->di_debug_info_ptr; if (*die_info_ptr == 0) { return (DW_DLV_NO_ENTRY); } cu_info_start = dbg->de_debug_info + die->di_cu_context->cc_debug_info_offset; die_info_end = cu_info_start + die->di_cu_context->cc_length + die->di_cu_context->cc_length_size + die->di_cu_context->cc_extension_size; if ((*die_info_ptr) == 0) { return (DW_DLV_NO_ENTRY); } child_depth = 0; do { die_info_ptr = _dwarf_next_die_info_ptr(die_info_ptr, die->di_cu_context, die_info_end, cu_info_start, true, &has_child); if (die_info_ptr == NULL) { _dwarf_error(dbg, error, DW_DLE_NEXT_DIE_PTR_NULL); return (DW_DLV_ERROR); } if ((*die_info_ptr) == 0 && has_child) { die_info_ptr++; has_child = false; } if ((*die_info_ptr) == 0) for (; child_depth > 0 && *die_info_ptr == 0; child_depth--, die_info_ptr++); else child_depth = has_child ? child_depth + 1 : child_depth; } while (child_depth != 0); } if (die != NULL && die_info_ptr >= die_info_end) { return (DW_DLV_NO_ENTRY); } if ((*die_info_ptr) == 0) { return (DW_DLV_NO_ENTRY); } ret_die = (Dwarf_Die) _dwarf_get_alloc(dbg, DW_DLA_DIE, 1); if (ret_die == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } ret_die->di_debug_info_ptr = die_info_ptr; ret_die->di_cu_context = die == NULL ? dbg->de_cu_context : die->di_cu_context; DECODE_LEB128_UWORD(die_info_ptr, utmp) abbrev_code = (Dwarf_Half) utmp; if (abbrev_code == 0) { /* Zero means a null DIE */ return (DW_DLV_NO_ENTRY); } ret_die->di_abbrev_list = _dwarf_get_abbrev_for_code(ret_die->di_cu_context, abbrev_code); if (ret_die->di_abbrev_list == NULL || (die == NULL && ret_die->di_abbrev_list-> ab_tag != DW_TAG_compile_unit)) { _dwarf_error(dbg, error, DW_DLE_FIRST_DIE_NOT_CU); return (DW_DLV_ERROR); } *caller_ret_die = ret_die; return (DW_DLV_OK); }