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; }
/* Used by rqs (an IRIX application). Not needed except for that one application. Should be moved to its own source file since it is so rarely needed. Returns DW_DLV_OK if returns the arrays. Returns DW_DLV_NO_ENTRY if no section. ?? (How do I tell?) Returns DW_DLV_ERROR if there is an error. Uses DW_FRAME_CFA_COL because IRIX is only DWARF2 and that is what IRIX compilers and compatible compilers support on IRIX. */ int _dwarf_frame_address_offsets(Dwarf_Debug dbg, Dwarf_Addr ** addrlist, Dwarf_Off ** offsetlist, Dwarf_Signed * returncount, Dwarf_Error * err) { int retval = DW_DLV_OK; int res = DW_DLV_ERROR; Dwarf_Cie *cie_data = 0; Dwarf_Signed cie_count = 0; Dwarf_Fde *fde_data = 0; Dwarf_Signed fde_count = 0; Dwarf_Signed i = 0; Dwarf_Unsigned u = 0; Dwarf_Frame_Op *frame_inst = 0; Dwarf_Fde fdep = 0; Dwarf_Cie ciep = 0; Dwarf_Chain curr_chain = 0; Dwarf_Chain head_chain = 0; Dwarf_Chain prev_chain = 0; Dwarf_Arange arange = 0; Dwarf_Unsigned arange_count = 0; Dwarf_Addr *arange_addrs = 0; Dwarf_Off *arange_offsets = 0; res = dwarf_get_fde_list(dbg, &cie_data, &cie_count, &fde_data, &fde_count, err); if (res != DW_DLV_OK) { return res; } res = _dwarf_load_section(dbg, &dbg->de_debug_frame, err); if (res != DW_DLV_OK) { return res; } if (!dbg->de_debug_frame.dss_size) { return (DW_DLV_NO_ENTRY); } for (i = 0; i < cie_count; i++) { Dwarf_Off instoff = 0; Dwarf_Signed initial_instructions_length = 0; Dwarf_Small *instr_end = 0; Dwarf_Sword icount = 0; int j = 0; int dw_err; ciep = cie_data[i]; instoff = ciep->ci_cie_instr_start - dbg->de_debug_frame.dss_data; initial_instructions_length = ciep->ci_length + ciep->ci_length_size + ciep->ci_extension_size - (ciep->ci_cie_instr_start - ciep->ci_cie_start); instr_end = ciep->ci_cie_instr_start + initial_instructions_length; res = _dwarf_exec_frame_instr( /* make_instr */ true, &frame_inst, /* search_pc= */ false, /* search_pc_val= */ 0, /* location */ 0, ciep->ci_cie_instr_start, instr_end, /* Dwarf_frame= */ 0, /* cie= */ 0, dbg, DW_FRAME_CFA_COL, &icount, &dw_err); if (res == DW_DLV_ERROR) { _dwarf_error(dbg, err, dw_err); return (res); } else if (res == DW_DLV_NO_ENTRY) { continue; } for (j = 0; j < icount; ++j) { Dwarf_Frame_Op *finst = frame_inst + j; if (finst->fp_base_op == 0 && finst->fp_extended_op == 1) { /* is DW_CFA_set_loc */ Dwarf_Addr add = (Dwarf_Addr) finst->fp_offset; Dwarf_Off off = finst->fp_instr_offset + instoff; arange = (Dwarf_Arange) _dwarf_get_alloc(dbg, DW_DLA_ARANGE, 1); if (arange == NULL) { _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } arange->ar_address = add; arange->ar_info_offset = off; arange_count++; curr_chain = (Dwarf_Chain) _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); if (curr_chain == NULL) { _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } curr_chain->ch_item = arange; if (head_chain == NULL) head_chain = prev_chain = curr_chain; else { prev_chain->ch_next = curr_chain; prev_chain = curr_chain; } } } dwarf_dealloc(dbg, frame_inst, DW_DLA_FRAME_BLOCK); } for (i = 0; i < fde_count; i++) { Dwarf_Small *instr_end = 0; Dwarf_Sword icount = 0; Dwarf_Signed instructions_length = 0; Dwarf_Off instoff = 0; Dwarf_Off off = 0; Dwarf_Addr addr = 0; int j = 0; int dw_err; fdep = fde_data[i]; off = fdep->fd_initial_loc_pos - dbg->de_debug_frame.dss_data; addr = fdep->fd_initial_location; arange = (Dwarf_Arange) _dwarf_get_alloc(dbg, DW_DLA_ARANGE, 1); if (arange == NULL) { _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } arange->ar_address = addr; arange->ar_info_offset = off; arange_count++; curr_chain = (Dwarf_Chain) _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); if (curr_chain == NULL) { _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } curr_chain->ch_item = arange; if (head_chain == NULL) head_chain = prev_chain = curr_chain; else { prev_chain->ch_next = curr_chain; prev_chain = curr_chain; } instoff = fdep->fd_fde_instr_start - dbg->de_debug_frame.dss_data; instructions_length = fdep->fd_length + fdep->fd_length_size + fdep->fd_extension_size - (fdep->fd_fde_instr_start - fdep->fd_fde_start); instr_end = fdep->fd_fde_instr_start + instructions_length; res = _dwarf_exec_frame_instr( /* make_instr */ true, &frame_inst, /* search_pc= */ false, /* search_pc_val= */ 0, /* location */ 0, fdep->fd_fde_instr_start, instr_end, /* Dwarf_frame= */ 0, /* cie= */ 0, dbg, DW_FRAME_CFA_COL, &icount, &dw_err); if (res == DW_DLV_ERROR) { _dwarf_error(dbg, err, dw_err); return (res); } else if (res == DW_DLV_NO_ENTRY) { continue; } for (j = 0; j < icount; ++j) { Dwarf_Frame_Op *finst2 = frame_inst + j; if (finst2->fp_base_op == 0 && finst2->fp_extended_op == 1) { /* is DW_CFA_set_loc */ Dwarf_Addr add = (Dwarf_Addr) finst2->fp_offset; Dwarf_Off off2 = finst2->fp_instr_offset + instoff; arange = (Dwarf_Arange) _dwarf_get_alloc(dbg, DW_DLA_ARANGE, 1); if (arange == NULL) { _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } arange->ar_address = add; arange->ar_info_offset = off2; arange_count++; curr_chain = (Dwarf_Chain) _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); if (curr_chain == NULL) { _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } curr_chain->ch_item = arange; if (head_chain == NULL) head_chain = prev_chain = curr_chain; else { prev_chain->ch_next = curr_chain; prev_chain = curr_chain; } } } dwarf_dealloc(dbg, frame_inst, DW_DLA_FRAME_BLOCK); } dwarf_dealloc(dbg, fde_data, DW_DLA_LIST); dwarf_dealloc(dbg, cie_data, DW_DLA_LIST); arange_addrs = (Dwarf_Addr *) _dwarf_get_alloc(dbg, DW_DLA_ADDR, arange_count); if (arange_addrs == NULL) { _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } arange_offsets = (Dwarf_Off *) _dwarf_get_alloc(dbg, DW_DLA_ADDR, arange_count); if (arange_offsets == NULL) { _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } curr_chain = head_chain; for (u = 0; u < arange_count; u++) { Dwarf_Arange ar = curr_chain->ch_item; arange_addrs[u] = ar->ar_address; arange_offsets[u] = ar->ar_info_offset; prev_chain = curr_chain; curr_chain = curr_chain->ch_next; dwarf_dealloc(dbg, ar, DW_DLA_ARANGE); dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN); } *returncount = arange_count; *offsetlist = arange_offsets; *addrlist = arange_addrs; return retval; }