diff options
Diffstat (limited to 'sysdeps/generic/sframe-read.c')
-rw-r--r-- | sysdeps/generic/sframe-read.c | 128 |
1 files changed, 99 insertions, 29 deletions
diff --git a/sysdeps/generic/sframe-read.c b/sysdeps/generic/sframe-read.c index d536575..a6ebc42 100644 --- a/sysdeps/generic/sframe-read.c +++ b/sysdeps/generic/sframe-read.c @@ -75,11 +75,10 @@ sframe_get_fde_type (sframe_func_desc_entry *fdep) static bool sframe_header_sanity_check_p (sframe_header *hp) { - uint8_t all_flags = SFRAME_F_FDE_SORTED | SFRAME_F_FRAME_POINTER; /* Check preamble is valid. */ if ((hp->sfh_preamble.sfp_magic != SFRAME_MAGIC) || (hp->sfh_preamble.sfp_version != SFRAME_VERSION_2) - || ((hp->sfh_preamble.sfp_flags | all_flags) != all_flags)) + || (hp->sfh_preamble.sfp_flags & ~SFRAME_V2_F_ALL_FLAGS)) return false; /* Check offsets are valid. */ @@ -171,25 +170,103 @@ sframe_fre_entry_size (sframe_frame_row_entry *frep, size_t addr_size) + sframe_fre_offset_bytes_size (fre_info)); } -/* Check whether for the given FDEP, the SFrame Frame Row Entry identified via - the START_IP_OFFSET and the END_IP_OFFSET, provides the stack trace - information for the PC. */ +/* Get SFrame header from the given decoder context DCTX. */ + +static inline sframe_header * +sframe_decoder_get_header (sframe_decoder_ctx *dctx) +{ + sframe_header *hp = NULL; + if (dctx != NULL) + hp = &dctx->sfd_header; + return hp; +} + +/* Get the offset of the sfde_func_start_address field (from the start of the + on-disk layout of the SFrame section) of the FDE at FUNC_IDX in the decoder + context DCTX. */ + +static uint32_t +sframe_decoder_get_offsetof_fde_start_addr (sframe_decoder_ctx *dctx, + uint32_t func_idx, + _Unwind_Reason_Code *errp) +{ + sframe_header *dhp; + + dhp = sframe_decoder_get_header (dctx); + if (dhp == NULL) + { + if (errp != NULL) + *errp = _URC_END_OF_STACK; + return 0; + } + + if (func_idx >= dhp->sfh_num_fdes) + { + if (errp != NULL) + *errp = _URC_END_OF_STACK; + return 0; + } + else if (errp != NULL) + *errp = _URC_NO_REASON; + + return (sframe_get_hdr_size (dhp) + + func_idx * sizeof (sframe_func_desc_entry) + + offsetof (sframe_func_desc_entry, sfde_func_start_address)); +} + + +/* Get the offset of the start PC of the SFrame FDE at FUNC_IDX from + the start of the SFrame section. If the flag + SFRAME_F_FDE_FUNC_START_PCREL is set, sfde_func_start_address is + the offset of the start PC of the function from the field itself. + + If FUNC_IDX is not a valid index in the given decoder object, returns 0. */ + +static int32_t +sframe_decoder_get_secrel_func_start_addr (sframe_decoder_ctx *dctx, + uint32_t func_idx) +{ + int32_t func_start_addr; + _Unwind_Reason_Code err = 0; + int32_t offsetof_fde_in_sec = 0; + + /* Check if we have SFRAME_F_FDE_FUNC_START_PCREL. */ + sframe_header *sh = &dctx->sfd_header; + if ((sh->sfh_preamble.sfp_flags & SFRAME_F_FDE_FUNC_START_PCREL)) + { + offsetof_fde_in_sec = + sframe_decoder_get_offsetof_fde_start_addr (dctx, func_idx, &err); + /* If func_idx is not a valid index, return 0. */ + if (err == _URC_END_OF_STACK) + return 0; + } + + func_start_addr = dctx->sfd_funcdesc[func_idx].sfde_func_start_address; + + return func_start_addr + offsetof_fde_in_sec; +} + +/* Check if the SFrame Frame Row Entry identified via the + START_IP_OFFSET and the END_IP_OFFSET (for SFrame FDE at + FUNC_IDX). */ static bool -sframe_fre_check_range_p (sframe_func_desc_entry *fdep, +sframe_fre_check_range_p (sframe_decoder_ctx *dctx, uint32_t func_idx, uint32_t start_ip_offset, uint32_t end_ip_offset, int32_t pc) { + sframe_func_desc_entry *fdep; int32_t func_start_addr; uint8_t rep_block_size; uint32_t fde_type; uint32_t pc_offset; bool mask_p; + fdep = &dctx->sfd_funcdesc[func_idx]; if (fdep == NULL) return false; - func_start_addr = fdep->sfde_func_start_address; + func_start_addr = sframe_decoder_get_secrel_func_start_addr (dctx, func_idx); fde_type = sframe_get_fde_type (fdep); mask_p = (fde_type == SFRAME_FDE_TYPE_PCMASK); rep_block_size = fdep->sfde_func_rep_size; @@ -207,19 +284,6 @@ sframe_fre_check_range_p (sframe_func_desc_entry *fdep, return (start_ip_offset <= pc_offset) && (end_ip_offset >= pc_offset); } -/* The SFrame Decoder. */ - -/* Get SFrame header from the given decoder context DCTX. */ - -static inline sframe_header * -sframe_decoder_get_header (sframe_decoder_ctx *dctx) -{ - sframe_header *hp = NULL; - if (dctx != NULL) - hp = &dctx->sfd_header; - return hp; -} - /* Get IDX'th offset from FRE. Set ERRP as applicable. */ static int32_t @@ -298,7 +362,7 @@ sframe_decode_fre_start_address (const char *fre_buf, static sframe_func_desc_entry * sframe_get_funcdesc_with_addr_internal (sframe_decoder_ctx *ctx, int32_t addr, - int *errp) + int *errp, uint32_t *func_idx) { sframe_header *dhp; sframe_func_desc_entry *fdp; @@ -319,19 +383,23 @@ sframe_get_funcdesc_with_addr_internal (sframe_decoder_ctx *ctx, int32_t addr, /* Do the binary search. */ fdp = (sframe_func_desc_entry *) ctx->sfd_funcdesc; low = 0; - high = dhp->sfh_num_fdes; + high = dhp->sfh_num_fdes - 1; while (low <= high) { int mid = low + (high - low) / 2; /* Given sfde_func_start_address <= addr, addr - sfde_func_start_address must be positive. */ - if (fdp[mid].sfde_func_start_address <= addr - && ((uint32_t)(addr - fdp[mid].sfde_func_start_address) + if (sframe_decoder_get_secrel_func_start_addr (ctx, mid) <= addr + && ((uint32_t)(addr - sframe_decoder_get_secrel_func_start_addr (ctx, + mid)) < fdp[mid].sfde_func_size)) - return fdp + mid; + { + *func_idx = mid; + return fdp + mid; + } - if (fdp[mid].sfde_func_start_address < addr) + if (sframe_decoder_get_secrel_func_start_addr (ctx, mid) < addr) low = mid + 1; else high = mid - 1; @@ -510,6 +578,7 @@ __sframe_find_fre (sframe_decoder_ctx *ctx, int32_t pc, sframe_frame_row_entry *frep) { sframe_func_desc_entry *fdep; + uint32_t func_idx; uint32_t fre_type, i; uint32_t start_ip_offset; int32_t func_start_addr; @@ -522,14 +591,14 @@ __sframe_find_fre (sframe_decoder_ctx *ctx, int32_t pc, return _URC_END_OF_STACK; /* Find the FDE which contains the PC, then scan its fre entries. */ - fdep = sframe_get_funcdesc_with_addr_internal (ctx, pc, &err); + fdep = sframe_get_funcdesc_with_addr_internal (ctx, pc, &err, &func_idx); if (fdep == NULL || ctx->sfd_fres == NULL) return _URC_END_OF_STACK; fre_type = sframe_get_fre_type (fdep); fres = ctx->sfd_fres + fdep->sfde_func_start_fre_off; - func_start_addr = fdep->sfde_func_start_address; + func_start_addr = sframe_decoder_get_secrel_func_start_addr (ctx, func_idx); for (i = 0; i < fdep->sfde_func_num_fres; i++) { @@ -553,7 +622,8 @@ __sframe_find_fre (sframe_decoder_ctx *ctx, int32_t pc, if (start_ip_offset > (uint32_t) (pc - func_start_addr)) return _URC_END_OF_STACK; - if (sframe_fre_check_range_p (fdep, start_ip_offset, end_ip_offset, pc)) + if (sframe_fre_check_range_p (ctx, func_idx, start_ip_offset, + end_ip_offset, pc)) { /* Decode last FRE bits: offsets size. */ frep->fre_offsets = fres + addr_size + sizeof (frep->fre_info); |