/* Gather the fde print logic here so the control logic determining what FDE to print is clearer. */ int print_one_fde(Dwarf_Debug dbg, Dwarf_Fde fde, Dwarf_Unsigned fde_index, Dwarf_Cie * cie_data, Dwarf_Signed cie_element_count, Dwarf_Half address_size, int is_eh, struct dwconf_s *config_data) { Dwarf_Addr j = 0; Dwarf_Addr low_pc = 0; Dwarf_Unsigned func_length = 0; Dwarf_Ptr fde_bytes = NULL; Dwarf_Unsigned fde_bytes_length = 0; Dwarf_Off cie_offset = 0; Dwarf_Signed cie_index = 0; Dwarf_Off fde_offset = 0; Dwarf_Signed eh_table_offset = 0; int fres = 0; int offres = 0; string temps = 0; Dwarf_Error err = 0; int printed_intro_addr = 0; fres = dwarf_get_fde_range(fde, &low_pc, &func_length, &fde_bytes, &fde_bytes_length, &cie_offset, &cie_index, &fde_offset, &err); if (fres == DW_DLV_ERROR) { print_error(dbg, "dwarf_get_fde_range", fres, err); } if (fres == DW_DLV_NO_ENTRY) { return DW_DLV_NO_ENTRY; } if (cu_name_flag && fde_offset_for_cu_low != DW_DLV_BADOFFSET && (fde_offset < fde_offset_for_cu_low || fde_offset > fde_offset_for_cu_high)) { return DW_DLV_NO_ENTRY; } /* eh_table_offset is IRIX ONLY. */ fres = dwarf_get_fde_exception_info(fde, &eh_table_offset, &err); if (fres == DW_DLV_ERROR) { print_error(dbg, "dwarf_get_fde_exception_info", fres, err); } temps = get_fde_proc_name(dbg, low_pc); printf ("<%3lld><%#llx:%#llx><%s><fde offset 0x%llx length: 0x%llx>", cie_index, low_pc, (low_pc + func_length), temps ? temps : "", fde_offset, fde_bytes_length); if (!is_eh) { /* IRIX uses eh_table_offset. */ if (eh_table_offset == DW_DLX_NO_EH_OFFSET) { printf("<eh offset %s>\n", "none"); } else if (eh_table_offset == DW_DLX_EH_OFFSET_UNAVAILABLE) { printf("<eh offset %s>\n", "unknown"); } else { printf("<eh offset 0x%llx>\n", eh_table_offset); } } else { int ares = 0; Dwarf_Small *data = 0; Dwarf_Unsigned len = 0; ares = dwarf_get_fde_augmentation_data(fde, &data, &len, &err); if (ares == DW_DLV_NO_ENTRY) { /* do nothing. */ } else if (ares == DW_DLV_OK) { int k2; printf("<eh aug data len 0x%llx", (long long) len); for (k2 = 0; k2 < len; ++k2) { if (k2 == 0) { printf(" bytes 0x"); } printf("%02x ", (unsigned char) data[k2]); } printf(">"); } /* else DW_DLV_ERROR, do nothing */ printf("\n"); } /* call dwarf_get_fde_info_for_reg() to get whole matrix */ for (j = low_pc; j < low_pc + func_length; j++) { Dwarf_Half k; if (config_data->cf_interface_number == 3) { Dwarf_Signed reg = 0; Dwarf_Signed offset_relevant = 0; Dwarf_Small value_type = 0; Dwarf_Signed offset_or_block_len = 0; Dwarf_Signed offset = 0; Dwarf_Ptr block_ptr = 0; Dwarf_Addr row_pc = 0; int fires = dwarf_get_fde_info_for_cfa_reg3(fde, j, &value_type, &offset_relevant, ®, &offset_or_block_len, &block_ptr, &row_pc, &err); offset = offset_or_block_len; if (fires == DW_DLV_ERROR) { print_error(dbg, "dwarf_get_fde_info_for_reg", fires, err); } if (fires == DW_DLV_NO_ENTRY) { continue; } if (row_pc != j) { /* duplicate row */ continue; } if (!printed_intro_addr) { printf(" %08llx:\t", j); printed_intro_addr = 1; } print_one_frame_reg_col(dbg, config_data->cf_cfa_reg, value_type, reg, config_data, offset_relevant, offset, block_ptr); } for (k = 0; k < config_data->cf_table_entry_count; k++) { Dwarf_Signed reg = 0; Dwarf_Signed offset_relevant = 0; int fires = 0; Dwarf_Small value_type = 0; Dwarf_Ptr block_ptr = 0; Dwarf_Signed offset_or_block_len = 0; Dwarf_Signed offset = 0; Dwarf_Addr row_pc = 0; if (config_data->cf_interface_number == 3) { fires = dwarf_get_fde_info_for_reg3(fde, k, j, &value_type, &offset_relevant, ®, &offset_or_block_len, &block_ptr, &row_pc, &err); offset = offset_or_block_len; } else { /* ASSERT: config_data->cf_interface_number == 2 */ value_type = DW_EXPR_OFFSET; fires = dwarf_get_fde_info_for_reg(fde, k, j, &offset_relevant, ®, &offset, &row_pc, &err); } if (fires == DW_DLV_ERROR) { printf("\n"); print_error(dbg, "dwarf_get_fde_info_for_reg", fires, err); } if (fires == DW_DLV_NO_ENTRY) { continue; } if (row_pc != j) { /* duplicate row */ break; } if (!printed_intro_addr) { printf(" %08llx:\t", j); printed_intro_addr = 1; } print_one_frame_reg_col(dbg,k, value_type, reg, config_data, offset_relevant, offset, block_ptr); } if (printed_intro_addr) { printf("\n"); printed_intro_addr = 0; } } if (verbose > 1) { Dwarf_Off fde_off; Dwarf_Off cie_off; /* get the fde instructions and print them in raw form, just like cie instructions */ Dwarf_Ptr instrs; Dwarf_Unsigned ilen; int res; res = dwarf_get_fde_instr_bytes(fde, &instrs, &ilen, &err); offres = dwarf_fde_section_offset(dbg, fde, &fde_off, &cie_off, &err); if (offres == DW_DLV_OK) { printf("\tfde sec. offset %llu 0x%llx" " cie offset for fde: %llu 0x%llx\n", (unsigned long long) fde_off, (unsigned long long) fde_off, (unsigned long long) cie_off, (unsigned long long) cie_off); } if (res == DW_DLV_OK) { int cires = 0; Dwarf_Unsigned cie_length = 0; Dwarf_Small version = 0; string augmenter; Dwarf_Unsigned code_alignment_factor = 0; Dwarf_Signed data_alignment_factor = 0; Dwarf_Half return_address_register_rule = 0; Dwarf_Ptr initial_instructions = 0; Dwarf_Unsigned initial_instructions_length = 0; if (cie_index >= cie_element_count) { printf("Bad cie index %lld with fde index %lld! " "(table entry max %lld)\n", (long long) cie_index, (long long) fde_index, (long long) cie_element_count); exit(1); } cires = dwarf_get_cie_info(cie_data[cie_index], &cie_length, &version, &augmenter, &code_alignment_factor, &data_alignment_factor, &return_address_register_rule, &initial_instructions, &initial_instructions_length, &err); if (cires == DW_DLV_ERROR) { printf ("Bad cie index %lld with fde index %lld!\n", (long long) cie_index, (long long) fde_index); print_error(dbg, "dwarf_get_cie_info", cires, err); } if (cires == DW_DLV_NO_ENTRY) { ; /* ? */ } else { print_frame_inst_bytes(dbg, instrs, (Dwarf_Signed) ilen, data_alignment_factor, (int) code_alignment_factor, address_size, config_data); } } else if (res == DW_DLV_NO_ENTRY) { printf ("Impossible: no instr bytes for fde index %d?\n", (int) fde_index); } else { /* DW_DLV_ERROR */ printf ("Error: on gettinginstr bytes for fde index %d?\n", (int) fde_index); print_error(dbg, "dwarf_get_fde_instr_bytes", res, err); } } return DW_DLV_OK; }
static void _dwarf_cie_fde_test(Dwarf_Debug dbg, int eh, void (*_frame_test)(Dwarf_Debug, Dwarf_Fde, Dwarf_Addr, Dwarf_Unsigned, Dwarf_Unsigned)) { Dwarf_Cie *cielist, cie; Dwarf_Fde *fdelist, fde; Dwarf_Frame_Op *oplist; Dwarf_Signed ciecnt, fdecnt; Dwarf_Addr low_pc, high_pc; Dwarf_Unsigned func_len, fde_byte_len, fde_inst_len, bytes_in_cie; Dwarf_Unsigned cie_caf, cie_daf, cie_inst_len; Dwarf_Signed cie_index, opcnt; Dwarf_Off cie_offset, fde_offset; Dwarf_Ptr fde_bytes, fde_inst, cie_initinst; Dwarf_Half cie_ra; Dwarf_Small cie_version; Dwarf_Error de; const char *cfa_str; char *cie_augmenter; int i, j, r_fde_at_pc; if (eh) { if (dwarf_get_fde_list_eh(dbg, &cielist, &ciecnt, &fdelist, &fdecnt, &de) != DW_DLV_OK) { tet_printf("dwarf_get_fde_list_eh failed: %s\n", dwarf_errmsg(de)); result = TET_FAIL; goto done; } } else { if (dwarf_get_fde_list(dbg, &cielist, &ciecnt, &fdelist, &fdecnt, &de) != DW_DLV_OK) { tet_printf("dwarf_get_fde_list failed: %s\n", dwarf_errmsg(de)); result = TET_FAIL; goto done; } } TS_CHECK_INT(ciecnt); TS_CHECK_INT(fdecnt); /* * Test dwarf_get_fde_at_pc using hard-coded PC values. */ tet_infoline("attempt to get fde at 0x08082a30"); r_fde_at_pc = dwarf_get_fde_at_pc(fdelist, 0x08082a30, &fde, &low_pc, &high_pc, &de); TS_CHECK_INT(r_fde_at_pc); if (r_fde_at_pc == DW_DLV_OK) { TS_CHECK_UINT(low_pc); TS_CHECK_UINT(high_pc); } tet_infoline("attempt to get fde at 0x08083087"); r_fde_at_pc = dwarf_get_fde_at_pc(fdelist, 0x08083087, &fde, &low_pc, &high_pc, &de); TS_CHECK_INT(r_fde_at_pc); if (r_fde_at_pc == DW_DLV_OK) { TS_CHECK_UINT(low_pc); TS_CHECK_UINT(high_pc); } tet_infoline("attempt to get fde at 0x080481f0"); r_fde_at_pc = dwarf_get_fde_at_pc(fdelist, 0x080481f0, &fde, &low_pc, &high_pc, &de); TS_CHECK_INT(r_fde_at_pc); if (r_fde_at_pc == DW_DLV_OK) { TS_CHECK_UINT(low_pc); TS_CHECK_UINT(high_pc); } tet_infoline("attempt to get fde at 0x08048564"); r_fde_at_pc = dwarf_get_fde_at_pc(fdelist, 0x08048564, &fde, &low_pc, &high_pc, &de); TS_CHECK_INT(r_fde_at_pc); if (r_fde_at_pc == DW_DLV_OK) { TS_CHECK_UINT(low_pc); TS_CHECK_UINT(high_pc); } tet_infoline("attempt to get fde at 0x00401280"); r_fde_at_pc = dwarf_get_fde_at_pc(fdelist, 0x00401280, &fde, &low_pc, &high_pc, &de); TS_CHECK_INT(r_fde_at_pc); if (r_fde_at_pc == DW_DLV_OK) { TS_CHECK_UINT(low_pc); TS_CHECK_UINT(high_pc); } tet_infoline("attempt to get fde at 0x004012b1"); r_fde_at_pc = dwarf_get_fde_at_pc(fdelist, 0x004012b1, &fde, &low_pc, &high_pc, &de); TS_CHECK_INT(r_fde_at_pc); if (r_fde_at_pc == DW_DLV_OK) { TS_CHECK_UINT(low_pc); TS_CHECK_UINT(high_pc); } /* * Test each FDE contained in the FDE list. */ for (i = 0; i < fdecnt; i++) { if (dwarf_get_fde_n(fdelist, i, &fde, &de) != DW_DLV_OK) { tet_printf("dwarf_get_fde_n(%d) failed: %s\n", i, dwarf_errmsg(de)); result = TET_FAIL; continue; } if (dwarf_get_fde_range(fde, &low_pc, &func_len, &fde_bytes, &fde_byte_len, &cie_offset, &cie_index, &fde_offset, &de) == DW_DLV_ERROR) { tet_printf("dwarf_get_fde_range(%d) failed: %s\n", i, dwarf_errmsg(de)); result = TET_FAIL; continue; } TS_CHECK_UINT(low_pc); TS_CHECK_UINT(func_len); TS_CHECK_UINT(fde_byte_len); if (fde_byte_len > 0) TS_CHECK_BLOCK(fde_bytes, fde_byte_len); TS_CHECK_INT(cie_offset); TS_CHECK_INT(cie_index); TS_CHECK_INT(fde_offset); if (dwarf_get_cie_of_fde(fde, &cie, &de) != DW_DLV_OK) { tet_printf("dwarf_get_cie_of_fde(%d) failed: %s\n", i, dwarf_errmsg(de)); result = TET_FAIL; continue; } if (dwarf_get_cie_index(cie, &cie_index, &de) != DW_DLV_OK) { tet_printf("dwarf_get_cie_index(%d) failed: %s\n", i, dwarf_errmsg(de)); result = TET_FAIL; continue; } TS_CHECK_INT(cie_index); if (dwarf_get_cie_info(cie, &bytes_in_cie, &cie_version, &cie_augmenter, &cie_caf, &cie_daf, &cie_ra, &cie_initinst, &cie_inst_len, &de) != DW_DLV_OK) { tet_printf("dwarf_get_cie_info(%d) failed: %s\n", i, dwarf_errmsg(de)); result = TET_FAIL; continue; } TS_CHECK_UINT(bytes_in_cie); TS_CHECK_UINT(cie_version); TS_CHECK_STRING(cie_augmenter); TS_CHECK_UINT(cie_caf); TS_CHECK_UINT(cie_daf); TS_CHECK_UINT(cie_ra); TS_CHECK_UINT(cie_inst_len); if (cie_inst_len > 0) TS_CHECK_BLOCK(cie_initinst, cie_inst_len); if (dwarf_get_fde_instr_bytes(fde, &fde_inst, &fde_inst_len, &de) != DW_DLV_OK) { tet_printf("dwarf_get_fde_instr_bytes(%d) failed: %s\n", i, dwarf_errmsg(de)); result = TET_FAIL; continue; } TS_CHECK_UINT(fde_inst_len); if (fde_inst_len > 0) { TS_CHECK_BLOCK(fde_inst, fde_inst_len); if (dwarf_expand_frame_instructions(cie, fde_inst, fde_inst_len, &oplist, &opcnt, &de) != DW_DLV_OK) { tet_printf("dwarf_expand_frame_instructions(%d)" " failed: %s\n", i, dwarf_errmsg(de)); result = TET_FAIL; continue; } TS_CHECK_INT(opcnt); for (j = 0; j < opcnt; j++) { TS_CHECK_UINT(oplist[j].fp_base_op); if (oplist[j].fp_base_op != 0) { if (dwarf_get_CFA_name( oplist[j].fp_base_op << 6, &cfa_str) != DW_DLV_OK) { tet_printf("dwarf_get_CFA_name" " failed\n"); continue; } TS_CHECK_STRING(cfa_str); } TS_CHECK_UINT(oplist[j].fp_extended_op); if (oplist[j].fp_extended_op != 0) { if (dwarf_get_CFA_name( oplist[j].fp_extended_op, &cfa_str) != DW_DLV_OK) { tet_printf("dwarf_get_CFA_name" " failed\n"); continue; } TS_CHECK_STRING(cfa_str); } TS_CHECK_UINT(oplist[j].fp_register); TS_CHECK_INT(oplist[j].fp_offset); TS_CHECK_INT(oplist[j].fp_instr_offset); } } _frame_test(dbg, fde, low_pc, func_len, cie_caf); } done: return; }