int dwarf_child(Dwarf_Die die, Dwarf_Die * caller_ret_die, Dwarf_Error * error) { Dwarf_Byte_Ptr die_info_ptr = 0; /* die_info_end points one-past-end of die area. */ Dwarf_Byte_Ptr die_info_end = 0; Dwarf_Die ret_die = 0; Dwarf_Bool has_die_child = 0; Dwarf_Debug dbg; Dwarf_Word abbrev_code = 0; Dwarf_Unsigned utmp = 0; Dwarf_Small *dataptr = 0; Dwarf_Debug_InfoTypes dis = 0; CHECK_DIE(die, DW_DLV_ERROR); dbg = die->di_cu_context->cc_dbg; dis = die->di_is_info? &dbg->de_info_reading: &dbg->de_types_reading; die_info_ptr = die->di_debug_ptr; dataptr = die->di_is_info? dbg->de_debug_info.dss_data: dbg->de_debug_types.dss_data; /* We are saving a DIE pointer here, but the pointer will not be presumed live later, when it is tested. */ dis->de_last_die = die; dis->de_last_di_ptr = die_info_ptr; /* NULL die has no child. */ if ((*die_info_ptr) == 0) return (DW_DLV_NO_ENTRY); die_info_end = dataptr + die->di_cu_context->cc_debug_offset + die->di_cu_context->cc_length + die->di_cu_context->cc_length_size + die->di_cu_context->cc_extension_size; die_info_ptr = _dwarf_next_die_info_ptr(die_info_ptr, die->di_cu_context, die_info_end, NULL, false, &has_die_child); if (die_info_ptr == NULL) { _dwarf_error(dbg, error, DW_DLE_NEXT_DIE_PTR_NULL); return (DW_DLV_ERROR); } dis->de_last_di_ptr = die_info_ptr; if (!has_die_child) { /* Look for end of sibling chain. */ while ( dis->de_last_di_ptr < die_info_end) { if (*dis->de_last_di_ptr) { break; } ++dis->de_last_di_ptr; } 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_ptr = die_info_ptr; ret_die->di_cu_context = die->di_cu_context; ret_die->di_is_info = die->di_is_info; DECODE_LEB128_UWORD(die_info_ptr, utmp); abbrev_code = (Dwarf_Word) utmp; dis->de_last_di_ptr = die_info_ptr; if (abbrev_code == 0) { /* Look for end of sibling chain */ while ( dis->de_last_di_ptr < die_info_end) { if (*dis->de_last_di_ptr) { break; } ++dis->de_last_di_ptr; } /* We have arrived at a null DIE, at the end of a CU or the end of a list of siblings. */ *caller_ret_die = 0; 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(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_BAD); return (DW_DLV_ERROR); } *caller_ret_die = ret_die; return (DW_DLV_OK); }
int dwarf_child(Dwarf_Die die, Dwarf_Die * caller_ret_die, Dwarf_Error * error) { Dwarf_Byte_Ptr die_info_ptr; Dwarf_Byte_Ptr die_info_end; Dwarf_Die ret_die; Dwarf_Bool has_die_child; Dwarf_Debug dbg; Dwarf_Half abbrev_code; Dwarf_Unsigned utmp; CHECK_DIE(die, DW_DLV_ERROR) dbg = die->di_cu_context->cc_dbg; die_info_ptr = die->di_debug_info_ptr; /* NULL die has no child. */ if ((*die_info_ptr) == 0) return (DW_DLV_NO_ENTRY); die_info_end = dbg->de_debug_info + die->di_cu_context->cc_debug_info_offset + die->di_cu_context->cc_length + die->di_cu_context->cc_length_size + die->di_cu_context->cc_extension_size; die_info_ptr = _dwarf_next_die_info_ptr(die_info_ptr, die->di_cu_context, die_info_end, NULL, false, &has_die_child); if (die_info_ptr == NULL) { _dwarf_error(dbg, error, DW_DLE_NEXT_DIE_PTR_NULL); return (DW_DLV_ERROR); } if (!has_die_child) 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->di_cu_context; DECODE_LEB128_UWORD(die_info_ptr, utmp) abbrev_code = (Dwarf_Half) utmp; if (abbrev_code == 0) { /* We have arrived at a null DIE, at the end of a CU or the end of a list of siblings. */ *caller_ret_die = 0; return DW_DLV_NO_ENTRY; } ret_die->di_abbrev_list = _dwarf_get_abbrev_for_code(die->di_cu_context, abbrev_code); if (ret_die->di_abbrev_list == NULL) { _dwarf_error(dbg, error, DW_DLE_DIE_BAD); return (DW_DLV_ERROR); } *caller_ret_die = ret_die; 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); }
/* 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); }