aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/sframe.h4
-rw-r--r--libsframe/doc/sframe-spec.texi6
-rw-r--r--libsframe/sframe.c78
3 files changed, 62 insertions, 26 deletions
diff --git a/include/sframe.h b/include/sframe.h
index c3dbb3a..cdf275f 100644
--- a/include/sframe.h
+++ b/include/sframe.h
@@ -117,8 +117,8 @@ extern "C"
/* Unwinders perform a (PC >= FRE_START_ADDR) to look up a matching FRE. */
#define SFRAME_FDE_TYPE_PCINC 0
-/* Unwinders perform a (PC & FRE_START_ADDR_AS_MASK >= FRE_START_ADDR_AS_MASK)
- to look up a matching FRE. */
+/* Unwinders perform a (PC % REP_BLOCK_SIZE >= FRE_START_ADDR) to look up a
+ matching FRE. */
#define SFRAME_FDE_TYPE_PCMASK 1
typedef struct sframe_preamble
diff --git a/libsframe/doc/sframe-spec.texi b/libsframe/doc/sframe-spec.texi
index 5155410..a37a6f9 100644
--- a/libsframe/doc/sframe-spec.texi
+++ b/libsframe/doc/sframe-spec.texi
@@ -451,8 +451,10 @@ entries and trampolines.
@item SFRAME_FDE_TYPE_PCMASK
@tab 1 @tab Unwinders perform a @*
-(PC & FRE_START_ADDR_AS_MASK >= FRE_START_ADDR_AS_MASK)
-to look up a matching FRE.
+(PC % REP_BLOCK_SIZE @*
+ >= FRE_START_ADDR)
+to look up a matching FRE. REP_BLOCK_SIZE is the size in bytes of the
+repeating block of program instructions.
@end multitable
diff --git a/libsframe/sframe.c b/libsframe/sframe.c
index 2914243..fd966cf 100644
--- a/libsframe/sframe.c
+++ b/libsframe/sframe.c
@@ -362,6 +362,53 @@ sframe_decoder_get_funcdesc_at_index (sframe_decoder_ctx *ctx,
return fdep;
}
+/* 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. */
+
+static bool
+sframe_fre_check_range_p (sframe_func_desc_entry *fdep,
+ int32_t start_ip_offset, int32_t end_ip_offset,
+ int32_t pc)
+{
+ int32_t start_ip, end_ip;
+ int32_t func_start_addr;
+ uint32_t rep_block_size;
+ uint32_t fde_type;
+ int32_t masked_pc;
+ bool mask_p;
+ bool ret;
+
+ ret = false;
+ /* FIXME - the rep_block_size should be encoded in the format somehow. For
+ AMD64, each pltN entry stub in .plt is 16 bytes. */
+ rep_block_size = 16;
+
+ if (!fdep)
+ return ret;
+
+ func_start_addr = fdep->sfde_func_start_address;
+ fde_type = sframe_get_fde_type (fdep);
+ mask_p = (fde_type == SFRAME_FDE_TYPE_PCMASK);
+
+ if (!mask_p)
+ {
+ start_ip = start_ip_offset + func_start_addr;
+ end_ip = end_ip_offset + func_start_addr;
+ ret = ((start_ip <= pc) && (end_ip >= pc));
+ }
+ else
+ {
+ /* For FDEs for repetitive pattern of insns, we need to return the FRE
+ where pc % rep_block_size is between start_ip_offset and
+ end_ip_offset. */
+ masked_pc = pc % rep_block_size;
+ ret = ((start_ip_offset <= masked_pc) && (end_ip_offset >= masked_pc));
+ }
+
+ return ret;
+}
+
static int
flip_fre (char *fp, uint32_t fre_type, size_t *fre_size)
{
@@ -1056,19 +1103,14 @@ sframe_find_fre (sframe_decoder_ctx *ctx, int32_t pc,
{
sframe_frame_row_entry cur_fre;
sframe_func_desc_entry *fdep;
- uint32_t fre_type, fde_type;
- uint32_t end_ip_offset, i;
- int32_t start_ip, end_ip;
+ uint32_t fre_type, fde_type, i;
+ int32_t start_ip_offset;
int32_t func_start_addr;
+ int32_t end_ip_offset;
const char *fres;
size_t size = 0;
int err = 0;
- /* For regular FDEs (i.e. fde_type SFRAME_FDE_TYPE_PCINC),
- where the start address in the FRE is an offset from start pc,
- use a bitmask with all bits set so that none of the address bits are
- ignored. In this case, we need to return the FRE where
- (PC >= FRE_START_ADDR) */
- uint64_t bitmask = 0xffffffff;
+ bool mask_p;
if ((ctx == NULL) || (frep == NULL))
return sframe_set_errno (&err, SFRAME_ERR_INVAL);
@@ -1080,14 +1122,7 @@ sframe_find_fre (sframe_decoder_ctx *ctx, int32_t pc,
fre_type = sframe_get_fre_type (fdep);
fde_type = sframe_get_fde_type (fdep);
-
- /* For FDEs for repetitive pattern of insns, we need to return the FRE
- such that (PC & FRE_START_ADDR_AS_MASK >= FRE_START_ADDR_AS_MASK).
- so, update the bitmask to the start address. */
- /* FIXME - the bitmask should be picked per ABI or encoded in the format
- somehow. For AMD64, the pltN entry stub is 16 bytes. */
- if (fde_type == SFRAME_FDE_TYPE_PCMASK)
- bitmask = 0xf;
+ mask_p = (fde_type == SFRAME_FDE_TYPE_PCMASK);
fres = ctx->sfd_fres + fdep->sfde_func_start_fre_off;
func_start_addr = fdep->sfde_func_start_address;
@@ -1098,15 +1133,14 @@ sframe_find_fre (sframe_decoder_ctx *ctx, int32_t pc,
if (err)
return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
- start_ip = func_start_addr + cur_fre.fre_start_addr;
+ start_ip_offset = cur_fre.fre_start_addr;
end_ip_offset = sframe_fre_get_end_ip_offset (fdep, i, fres + size);
- end_ip = func_start_addr + end_ip_offset;
- if ((start_ip & bitmask) > (pc & bitmask))
+ /* First FRE's start_ip must be more than pc for regular SFrame FDEs. */
+ if (i == 0 && !mask_p && (start_ip_offset + func_start_addr) > pc)
return sframe_set_errno (&err, SFRAME_ERR_FRE_INVAL);
- if (((start_ip & bitmask) <= (pc & bitmask))
- && (end_ip & bitmask) >= (pc & bitmask))
+ if (sframe_fre_check_range_p (fdep, start_ip_offset, end_ip_offset, pc))
{
sframe_frame_row_entry_copy (frep, &cur_fre);
return 0;