/* Given a form, and a pointer to the bytes encoding a value of that form, val_ptr, this function returns the length, in bytes, of a value of that form. When using this function, check for a return of 0 a recursive DW_FORM_INDIRECT value. */ int _dwarf_get_size_of_val(Dwarf_Debug dbg, Dwarf_Unsigned form, Dwarf_Half cu_version, Dwarf_Half address_size, Dwarf_Small * val_ptr, int v_length_size, Dwarf_Unsigned *size_out, Dwarf_Error*error) { Dwarf_Unsigned length = 0; Dwarf_Word leb128_length = 0; Dwarf_Unsigned form_indirect = 0; Dwarf_Unsigned ret_value = 0; switch (form) { /* When we encounter a FORM here that we know about but forgot to enter here, we had better not just continue. Usually means we forgot to update this function when implementing form handling of a new FORM. Disaster results from using a bogus value, so generate error. */ default: _dwarf_error(dbg,error,DW_DLE_DEBUG_FORM_HANDLING_INCOMPLETE); return DW_DLV_ERROR; case 0: return 0; case DW_FORM_GNU_ref_alt: case DW_FORM_GNU_strp_alt: case DW_FORM_strp_sup: *size_out = v_length_size; return DW_DLV_OK; case DW_FORM_addr: if (address_size) { *size_out = address_size; } else { /* This should never happen, address_size should be set. */ *size_out = dbg->de_pointer_size; } return DW_DLV_OK; case DW_FORM_ref_sig8: *size_out = 8; /* sizeof Dwarf_Sig8 */ return DW_DLV_OK; /* DWARF2 was wrong on the size of the attribute for DW_FORM_ref_addr. We assume compilers are using the corrected DWARF3 text (for 32bit pointer target objects pointer and offsets are the same size anyway). It is clear (as of 2014) that for 64bit folks used the V2 spec in the way V2 was written, so the ref_addr has to account for that.*/ case DW_FORM_ref_addr: if (cu_version == DW_CU_VERSION2) { *size_out = address_size; } else { *size_out = v_length_size; } return DW_DLV_OK; case DW_FORM_block1: *size_out = *(Dwarf_Small *) val_ptr + 1; return DW_DLV_OK; case DW_FORM_block2: READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned, val_ptr, sizeof(Dwarf_Half)); *size_out = ret_value + sizeof(Dwarf_Half); return DW_DLV_OK; case DW_FORM_block4: READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned, val_ptr, sizeof(Dwarf_ufixed)); *size_out = ret_value + sizeof(Dwarf_ufixed); return DW_DLV_OK; case DW_FORM_data1: *size_out = 1; return DW_DLV_OK; case DW_FORM_data2: *size_out = 2; return DW_DLV_OK; case DW_FORM_data4: *size_out = 4; return DW_DLV_OK; case DW_FORM_data8: *size_out = 8; return DW_DLV_OK; case DW_FORM_string: *size_out = strlen((char *) val_ptr) + 1; return DW_DLV_OK; case DW_FORM_block: case DW_FORM_exprloc: length = _dwarf_decode_u_leb128(val_ptr, &leb128_length); *size_out = length + leb128_length; return DW_DLV_OK; case DW_FORM_flag_present: *size_out = 0; return DW_DLV_OK; case DW_FORM_flag: *size_out = 1; return DW_DLV_OK; case DW_FORM_sec_offset: /* If 32bit dwarf, is 4. Else is 64bit dwarf and is 8. */ *size_out = v_length_size; return DW_DLV_OK; case DW_FORM_ref_udata: /* Discard the decoded value, we just want the length of the value. */ _dwarf_decode_u_leb128(val_ptr, &leb128_length); *size_out = leb128_length; return DW_DLV_OK; case DW_FORM_indirect: { Dwarf_Word indir_len = 0; int res = 0; Dwarf_Unsigned real_form_len = 0; form_indirect = _dwarf_decode_u_leb128(val_ptr, &indir_len); if (form_indirect == DW_FORM_indirect) { /* We are in big trouble: The true form of DW_FORM_indirect is DW_FORM_indirect? Nonsense. Should never happen. */ _dwarf_error(dbg,error,DW_DLE_NESTED_FORM_INDIRECT_ERROR); return DW_DLV_ERROR; } res = _dwarf_get_size_of_val(dbg, form_indirect, cu_version, address_size, val_ptr + indir_len, v_length_size, &real_form_len, error); if(res != DW_DLV_OK) { return res; } *size_out = indir_len + real_form_len; return DW_DLV_OK; } case DW_FORM_ref1: *size_out = 1; return DW_DLV_OK; case DW_FORM_ref2: *size_out = 2; return DW_DLV_OK; case DW_FORM_ref4: *size_out = 4; return DW_DLV_OK; case DW_FORM_ref8: *size_out = 8; return DW_DLV_OK; case DW_FORM_sdata: /* Discard the decoded value, we just want the length of the value. */ _dwarf_decode_s_leb128(val_ptr, &leb128_length); *size_out = (leb128_length); return DW_DLV_OK; case DW_FORM_addrx: case DW_FORM_GNU_addr_index: case DW_FORM_strx: case DW_FORM_GNU_str_index: _dwarf_decode_u_leb128(val_ptr, &leb128_length); *size_out = leb128_length; return DW_DLV_OK; case DW_FORM_strp: *size_out = v_length_size; return DW_DLV_OK; case DW_FORM_udata: /* Discard the decoded value, we just want the length of the value. */ _dwarf_decode_u_leb128(val_ptr, &leb128_length); *size_out = leb128_length; return DW_DLV_OK; } }
/* Given a form, and a pointer to the bytes encoding a value of that form, val_ptr, this function returns the length, in bytes, of a value of that form. When using this function, check for a return of 0 a recursive DW_FORM_INDIRECT value. */ Dwarf_Unsigned _dwarf_get_size_of_val(Dwarf_Debug dbg, Dwarf_Unsigned form, Dwarf_Half address_size, Dwarf_Small * val_ptr, int v_length_size) { Dwarf_Unsigned length = 0; Dwarf_Word leb128_length = 0; Dwarf_Unsigned form_indirect = 0; Dwarf_Unsigned ret_value = 0; switch (form) { default: /* Handles form = 0. */ return (form); case DW_FORM_addr: return (dbg->de_pointer_size); /* DWARF2 was wrong on the size of the attribute for DW_FORM_ref_addr. We assume compilers are using the corrected DWARF3 text (for 32bit pointer target objects pointer and offsets are the same size anyway). */ case DW_FORM_ref_addr: return (v_length_size); case DW_FORM_block1: return (*(Dwarf_Small *) val_ptr + 1); case DW_FORM_block2: READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned, val_ptr, sizeof(Dwarf_Half)); return (ret_value + sizeof(Dwarf_Half)); case DW_FORM_block4: READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned, val_ptr, sizeof(Dwarf_ufixed)); return (ret_value + sizeof(Dwarf_ufixed)); case DW_FORM_data1: return (1); case DW_FORM_data2: return (2); case DW_FORM_data4: return (4); case DW_FORM_data8: return (8); case DW_FORM_string: return (strlen((char *) val_ptr) + 1); case DW_FORM_block: length = _dwarf_decode_u_leb128(val_ptr, &leb128_length); return (length + leb128_length); case DW_FORM_flag: return (1); case DW_FORM_ref_udata: _dwarf_decode_u_leb128(val_ptr, &leb128_length); return (leb128_length); case DW_FORM_indirect: { Dwarf_Word indir_len = 0; form_indirect = _dwarf_decode_u_leb128(val_ptr, &indir_len); if (form_indirect == DW_FORM_indirect) { return (0); /* We are in big trouble: The true form of DW_FORM_indirect is DW_FORM_indirect? Nonsense. Should never happen. */ } return (indir_len + _dwarf_get_size_of_val(dbg, form_indirect, address_size, val_ptr + indir_len, v_length_size)); } case DW_FORM_ref1: return (1); case DW_FORM_ref2: return (2); case DW_FORM_ref4: return (4); case DW_FORM_ref8: return (8); case DW_FORM_sdata: _dwarf_decode_s_leb128(val_ptr, &leb128_length); return (leb128_length); case DW_FORM_strp: return (v_length_size); case DW_FORM_udata: _dwarf_decode_u_leb128(val_ptr, &leb128_length); return (leb128_length); } }
/* This function does two slightly different things depending on the input flag want_AT_sibling. If this flag is true, it checks if the input die has a DW_AT_sibling attribute. If it does it returns a pointer to the start of the sibling die in the .debug_info section. Otherwise it behaves the same as the want_AT_sibling false case. If the want_AT_sibling flag is false, it returns a pointer to the immediately adjacent die in the .debug_info section. Die_info_end points to the end of the .debug_info portion for the cu the die belongs to. It is used to check that the search for the next die does not cross the end of the current cu. Cu_info_start points to the start of the .debug_info portion for the current cu, and is used to add to the offset for DW_AT_sibling attributes. Finally, has_die_child is a pointer to a Dwarf_Bool that is set true if the present die has children, false otherwise. However, in case want_AT_child is true and the die has a DW_AT_sibling attribute *has_die_child is set false to indicate that the children are being skipped. die_info_end points to the last byte+1 of the cu. */ static Dwarf_Byte_Ptr _dwarf_next_die_info_ptr(Dwarf_Byte_Ptr die_info_ptr, Dwarf_CU_Context cu_context, Dwarf_Byte_Ptr die_info_end, Dwarf_Byte_Ptr cu_info_start, Dwarf_Bool want_AT_sibling, Dwarf_Bool * has_die_child) { Dwarf_Byte_Ptr info_ptr = 0; Dwarf_Byte_Ptr abbrev_ptr = 0; Dwarf_Word abbrev_code = 0; Dwarf_Abbrev_List abbrev_list; Dwarf_Half attr = 0; Dwarf_Half attr_form = 0; Dwarf_Unsigned offset = 0; Dwarf_Word leb128_length = 0; Dwarf_Unsigned utmp = 0; Dwarf_Debug dbg = 0; info_ptr = die_info_ptr; DECODE_LEB128_UWORD(info_ptr, utmp); abbrev_code = (Dwarf_Word) utmp; if (abbrev_code == 0) { return NULL; } abbrev_list = _dwarf_get_abbrev_for_code(cu_context, abbrev_code); if (abbrev_list == NULL) { return (NULL); } dbg = cu_context->cc_dbg; *has_die_child = abbrev_list->ab_has_child; abbrev_ptr = abbrev_list->ab_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_form == DW_FORM_indirect) { Dwarf_Unsigned utmp6; /* DECODE_LEB128_UWORD updates info_ptr */ DECODE_LEB128_UWORD(info_ptr, utmp6); attr_form = (Dwarf_Half) utmp6; } if (want_AT_sibling && attr == DW_AT_sibling) { switch (attr_form) { case DW_FORM_ref1: offset = *(Dwarf_Small *) info_ptr; break; case DW_FORM_ref2: /* READ_UNALIGNED does not update info_ptr */ READ_UNALIGNED(dbg, offset, Dwarf_Unsigned, info_ptr, sizeof(Dwarf_Half)); break; case DW_FORM_ref4: READ_UNALIGNED(dbg, offset, Dwarf_Unsigned, info_ptr, sizeof(Dwarf_ufixed)); break; case DW_FORM_ref8: READ_UNALIGNED(dbg, offset, Dwarf_Unsigned, info_ptr, sizeof(Dwarf_Unsigned)); break; case DW_FORM_ref_udata: offset = _dwarf_decode_u_leb128(info_ptr, &leb128_length); break; case DW_FORM_ref_addr: /* Very unusual. The FORM is intended to refer to a different CU, but a different CU cannot be a sibling, can it? We could ignore this and treat as if no DW_AT_sibling present. Or derive the offset from it and if it is in the same CU use it directly. The offset here is *supposed* to be a global offset, so adding cu_info_start is wrong to any offset we find here unless cu_info_start is zero! Lets pretend there is no DW_AT_sibling attribute. */ goto no_sibling_attr; default: return (NULL); } /* Reset *has_die_child to indicate children skipped. */ *has_die_child = false; /* A value beyond die_info_end indicates an error. Exactly at die_info_end means 1-past-cu-end and simply means we are at the end, do not return NULL. Higher level code will detect that we are at the end. */ if (cu_info_start + offset > die_info_end) { /* Error case, bad DWARF. */ return (NULL); } /* At or before end-of-cu */ return (cu_info_start + offset); } no_sibling_attr: if (attr_form != 0) { info_ptr += _dwarf_get_size_of_val(cu_context->cc_dbg, attr_form, cu_context->cc_address_size, info_ptr, cu_context->cc_length_size); /* It is ok for info_ptr == die_info_end, as we will test later before using a too-large info_ptr */ if (info_ptr > die_info_end) { /* More than one-past-end indicates a bug somewhere, likely bad dwarf generation. */ return (NULL); } } } while (attr != 0 || attr_form != 0); return (info_ptr); }
/* Given a form, and a pointer to the bytes encoding a value of that form, val_ptr, this function returns the length, in bytes, of a value of that form. When using this function, check for a return of 0 a recursive DW_FORM_INDIRECT value. */ Dwarf_Unsigned _dwarf_get_size_of_val(Dwarf_Debug dbg, Dwarf_Unsigned form, Dwarf_Small * val_ptr, int v_length_size) { Dwarf_Unsigned length = 0; Dwarf_Word leb128_length = 0; Dwarf_Unsigned form_indirect = 0; Dwarf_Unsigned ret_value = 0; switch (form) { default: /* Handles form = 0. */ return (form); case DW_FORM_addr: return (dbg->de_pointer_size); case DW_FORM_ref_addr: return (v_length_size); case DW_FORM_block1: return (*(Dwarf_Small *) val_ptr + 1); case DW_FORM_block2: READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned, val_ptr, sizeof(Dwarf_Half)); return (ret_value + sizeof(Dwarf_Half)); case DW_FORM_block4: READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned, val_ptr, sizeof(Dwarf_ufixed)); return (ret_value + sizeof(Dwarf_ufixed)); case DW_FORM_data1: return (1); case DW_FORM_data2: return (2); case DW_FORM_data4: return (4); case DW_FORM_data8: return (8); case DW_FORM_string: return (strlen((char *) val_ptr) + 1); case DW_FORM_block: length = _dwarf_decode_u_leb128(val_ptr, &leb128_length); return (length + leb128_length); case DW_FORM_flag: return (1); case DW_FORM_ref_udata: _dwarf_decode_u_leb128(val_ptr, &leb128_length); return (leb128_length); case DW_FORM_indirect: { Dwarf_Word indir_len = 0; form_indirect = _dwarf_decode_u_leb128(val_ptr, &indir_len); if (form_indirect == DW_FORM_indirect) { return (0); /* We are in big trouble: The true form of DW_FORM_indirect is DW_FORM_indirect? Nonsense. Should never happen. */ } return (indir_len + _dwarf_get_size_of_val(dbg, form_indirect, val_ptr + indir_len, v_length_size)); } case DW_FORM_ref1: return (1); case DW_FORM_ref2: return (2); case DW_FORM_ref4: return (4); case DW_FORM_ref8: return (8); case DW_FORM_sdata: _dwarf_decode_s_leb128(val_ptr, &leb128_length); return (leb128_length); case DW_FORM_strp: return (v_length_size); case DW_FORM_udata: _dwarf_decode_u_leb128(val_ptr, &leb128_length); return (leb128_length); } }
/* This function does two slightly different things depending on the input flag want_AT_sibling. If this flag is true, it checks if the input die has a DW_AT_sibling attribute. If it does it returns a pointer to the start of the sibling die in the .debug_info section. Otherwise it behaves the same as the want_AT_sibling false case. If the want_AT_sibling flag is false, it returns a pointer to the immediately adjacent die in the .debug_info section. Die_info_end points to the end of the .debug_info portion for the cu the die belongs to. It is used to check that the search for the next die does not cross the end of the current cu. Cu_info_start points to the start of the .debug_info portion for the current cu, and is used to add to the offset for DW_AT_sibling attributes. Finally, has_die_child is a pointer to a Dwarf_Bool that is set true if the present die has children, false otherwise. However, in case want_AT_child is true and the die has a DW_AT_sibling attribute *has_die_child is set false to indicate that the children are being skipped. */ static Dwarf_Byte_Ptr _dwarf_next_die_info_ptr(Dwarf_Byte_Ptr die_info_ptr, Dwarf_CU_Context cu_context, Dwarf_Byte_Ptr die_info_end, Dwarf_Byte_Ptr cu_info_start, Dwarf_Bool want_AT_sibling, Dwarf_Bool * has_die_child) { Dwarf_Byte_Ptr info_ptr; Dwarf_Byte_Ptr abbrev_ptr; Dwarf_Word abbrev_code; Dwarf_Abbrev_List abbrev_list; Dwarf_Half attr; Dwarf_Half attr_form; Dwarf_Unsigned offset; Dwarf_Word leb128_length; Dwarf_Unsigned utmp; Dwarf_Debug dbg; info_ptr = die_info_ptr; DECODE_LEB128_UWORD(info_ptr, utmp) abbrev_code = (Dwarf_Word) utmp; if (abbrev_code == 0) { return NULL; } abbrev_list = _dwarf_get_abbrev_for_code(cu_context, abbrev_code); if (abbrev_list == NULL) { return (NULL); } dbg = cu_context->cc_dbg; *has_die_child = abbrev_list->ab_has_child; abbrev_ptr = abbrev_list->ab_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_form == DW_FORM_indirect) { Dwarf_Unsigned utmp6; /* READ_UNALIGNED does update info_ptr */ DECODE_LEB128_UWORD(info_ptr, utmp6) attr_form = (Dwarf_Half) utmp6; } if (want_AT_sibling && attr == DW_AT_sibling) { switch (attr_form) { case DW_FORM_ref1: offset = *(Dwarf_Small *) info_ptr; break; case DW_FORM_ref2: READ_UNALIGNED(dbg, offset, Dwarf_Unsigned, info_ptr, sizeof(Dwarf_Half)); break; case DW_FORM_ref4: READ_UNALIGNED(dbg, offset, Dwarf_Unsigned, info_ptr, sizeof(Dwarf_ufixed)); break; case DW_FORM_ref8: READ_UNALIGNED(dbg, offset, Dwarf_Unsigned, info_ptr, sizeof(Dwarf_Unsigned)); break; case DW_FORM_ref_udata: offset = _dwarf_decode_u_leb128(info_ptr, &leb128_length); break; default: return (NULL); } /* Reset *has_die_child to indicate children skipped. */ *has_die_child = false; if (cu_info_start + offset > die_info_end) { return (NULL); } else { return (cu_info_start + offset); } } if (attr_form != 0) { info_ptr += _dwarf_get_size_of_val(cu_context->cc_dbg, attr_form, info_ptr, cu_context-> cc_length_size); if (info_ptr > die_info_end) { return (NULL); } } } while (attr != 0 || attr_form != 0); return (info_ptr); }