_Unwind_Reason_Code lsda_scan(lsda_t* lsda, _Unwind_Action actions, uintptr_t* lp) { (void)actions; const uint8_t* p = lsda->call_site_table; while(p < lsda->action_table) { uintptr_t start = read_encoded_ptr(&p, lsda->call_site_encoding); uintptr_t length = read_encoded_ptr(&p, lsda->call_site_encoding); uintptr_t landing_pad = read_encoded_ptr(&p, lsda->call_site_encoding); // Pony ignores the action index, since it uses only cleanup landing pads. read_uleb128(&p); if((start <= lsda->ip_offset) && (lsda->ip_offset < (start + length))) { // No landing pad. if(landing_pad == 0) return _URC_CONTINUE_UNWIND; // Pony doesn't read the type index or look up types. We treat cleanup // landing pads the same as any other landing pad. *lp = lsda->landing_pads + landing_pad; return _URC_HANDLER_FOUND; } } return _URC_CONTINUE_UNWIND; }
static uintptr_t read_with_encoding(const uint8_t** data, uintptr_t def) { uintptr_t start = (uintptr_t)(*data); const uint8_t* p = *data; uint8_t encoding = *p++; *data = p; if(encoding == DW_EH_PE_omit) return def; uintptr_t result = read_encoded_ptr(data, encoding); // Relative offset. switch(encoding & 0x70) { case DW_EH_PE_absptr: break; case DW_EH_PE_pcrel: result += start; break; case DW_EH_PE_textrel: case DW_EH_PE_datarel: case DW_EH_PE_funcrel: case DW_EH_PE_aligned: default: abort(); break; } // apply indirection if(encoding & DW_EH_PE_indirect) result = *((uintptr_t*)result); return result; }
int dwarf_create_fde_from_after_start(Dwarf_Debug dbg, struct cie_fde_prefix_s *prefix, Dwarf_Small * frame_ptr, int use_gnu_cie_calc, Dwarf_Cie cie_ptr_in, Dwarf_Fde * fde_ptr_out, Dwarf_Error * error) { Dwarf_Fde new_fde = 0; Dwarf_Cie cieptr = cie_ptr_in; Dwarf_Small *saved_frame_ptr = 0; Dwarf_Small *initloc = frame_ptr; Dwarf_Signed offset_into_exception_tables /* must be min dwarf_sfixed in size */ = (Dwarf_Signed) DW_DLX_NO_EH_OFFSET; Dwarf_Small *fde_aug_data = 0; Dwarf_Unsigned fde_aug_data_len = 0; Dwarf_Addr cie_base_offset = prefix->cf_cie_id; Dwarf_Addr initial_location = 0; /* must be min de_pointer_size bytes in size */ Dwarf_Addr address_range = 0; /* must be min de_pointer_size bytes in size */ enum Dwarf_augmentation_type augt = cieptr->ci_augmentation_type; if (augt == aug_gcc_eh_z) { /* If z augmentation this is eh_frame, and initial_location and address_range in the FDE are read according to the CIE augmentation string instructions. */ { Dwarf_Small *fp_updated = 0; int res = res = read_encoded_ptr(dbg, frame_ptr, cieptr-> ci_gnu_fde_begin_encoding, &initial_location, &fp_updated); if (res != DW_DLV_OK) { _dwarf_error(dbg, error, DW_DLE_FRAME_AUGMENTATION_UNKNOWN); return DW_DLV_ERROR; } frame_ptr = fp_updated; res = read_encoded_ptr(dbg, frame_ptr, cieptr->ci_gnu_fde_begin_encoding, &address_range, &fp_updated); if (res != DW_DLV_OK) { _dwarf_error(dbg, error, DW_DLE_FRAME_AUGMENTATION_UNKNOWN); return DW_DLV_ERROR; } frame_ptr = fp_updated; } { Dwarf_Unsigned adlen = 0; DECODE_LEB128_UWORD(frame_ptr, adlen); fde_aug_data_len = adlen; fde_aug_data = frame_ptr; frame_ptr += adlen; } } else { READ_UNALIGNED(dbg, initial_location, Dwarf_Addr, frame_ptr, dbg->de_pointer_size); frame_ptr += dbg->de_pointer_size; READ_UNALIGNED(dbg, address_range, Dwarf_Addr, frame_ptr, dbg->de_pointer_size); frame_ptr += dbg->de_pointer_size; } switch (augt) { case aug_irix_mti_v1: case aug_empty_string: break; case aug_irix_exception_table:{ Dwarf_Unsigned lreg = 0; Dwarf_Word length_of_augmented_fields = 0; DECODE_LEB128_UWORD(frame_ptr, lreg); length_of_augmented_fields = (Dwarf_Word) lreg; saved_frame_ptr = frame_ptr; /* The first word is an offset into exception tables. Defined as a 32bit offset even for CC -64. */ READ_UNALIGNED(dbg, offset_into_exception_tables, Dwarf_Addr, frame_ptr, sizeof(Dwarf_sfixed)); SIGN_EXTEND(offset_into_exception_tables, sizeof(Dwarf_sfixed)); frame_ptr = saved_frame_ptr + length_of_augmented_fields; } break; case aug_eh:{ Dwarf_Unsigned eh_table_value = 0; if (!use_gnu_cie_calc) { /* This should be impossible. */ _dwarf_error(dbg, error, DW_DLE_FRAME_AUGMENTATION_UNKNOWN); return DW_DLV_ERROR; } /* gnu eh fde case. we do not need to do anything */ /*REFERENCED*/ /* Not used in this instance of the macro */ READ_UNALIGNED(dbg, eh_table_value, Dwarf_Unsigned, frame_ptr, dbg->de_pointer_size); frame_ptr += dbg->de_pointer_size; } break; case aug_gcc_eh_z:{ /* The Augmentation Data Length is here, followed by the Augmentation Data bytes themselves. */ } break; } /* End switch on augmentation type */ new_fde = (Dwarf_Fde) _dwarf_get_alloc(dbg, DW_DLA_FDE, 1); if (new_fde == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } new_fde->fd_length = prefix->cf_length; new_fde->fd_length_size = prefix->cf_local_length_size; new_fde->fd_extension_size = prefix->cf_local_extension_size; new_fde->fd_cie_offset = cie_base_offset; new_fde->fd_cie_index = cieptr->ci_index; new_fde->fd_cie = cieptr; new_fde->fd_initial_location = initial_location; new_fde->fd_initial_loc_pos = initloc; new_fde->fd_address_range = address_range; new_fde->fd_fde_start = prefix->cf_start_addr; new_fde->fd_fde_instr_start = frame_ptr; new_fde->fd_dbg = dbg; new_fde->fd_offset_into_exception_tables = offset_into_exception_tables; new_fde->fd_section_ptr = prefix->cf_section_ptr; new_fde->fd_section_index = prefix->cf_section_index; new_fde->fd_section_length = prefix->cf_section_length; new_fde->fd_gnu_eh_augmentation_bytes = fde_aug_data; new_fde->fd_gnu_eh_augmentation_len = fde_aug_data_len; *fde_ptr_out = new_fde; return DW_DLV_OK; }
static int gnu_aug_encodings(Dwarf_Debug dbg, char *augmentation, Dwarf_Small * aug_data, Dwarf_Unsigned aug_data_len, unsigned char *pers_hand_enc_out, unsigned char *lsda_enc_out, unsigned char *fde_begin_enc_out, Dwarf_Addr * gnu_pers_addr_out) { char *nc = 0; Dwarf_Small *cur_aug_p = aug_data; Dwarf_Small *end_aug_p = aug_data + aug_data_len; for (nc = augmentation; *nc; ++nc) { char c = *nc; switch (c) { case 'z': continue; case 'L': if (cur_aug_p > end_aug_p) { return DW_DLV_ERROR; } *lsda_enc_out = *(unsigned char *) cur_aug_p; ++cur_aug_p; break; case 'R': if (cur_aug_p >= end_aug_p) { return DW_DLV_ERROR; } *fde_begin_enc_out = *(unsigned char *) cur_aug_p; ++cur_aug_p; break; case 'P':{ int res = 0; Dwarf_Small *updated_aug_p = 0; unsigned char encoding = 0; if (cur_aug_p >= end_aug_p) { return DW_DLV_ERROR; } encoding = *(unsigned char *) cur_aug_p; *pers_hand_enc_out = encoding; ++cur_aug_p; if (cur_aug_p > end_aug_p) { return DW_DLV_ERROR; } res = read_encoded_ptr(dbg, cur_aug_p, encoding, gnu_pers_addr_out, &updated_aug_p); if (res != DW_DLV_OK) { return res; } cur_aug_p = updated_aug_p; if (cur_aug_p > end_aug_p) { return DW_DLV_ERROR; } } break; default: return DW_DLV_ERROR; } } return DW_DLV_OK; }