typedef struct sframe_decoder_ctx sframe_decoder_ctx;
typedef struct sframe_encoder_ctx sframe_encoder_ctx;
-#define MAX_NUM_STACK_OFFSETS 3
+#define MAX_NUM_STACK_OFFSETS 6
#define MAX_OFFSET_BYTES \
((SFRAME_FRE_OFFSET_4B * 2 * MAX_NUM_STACK_OFFSETS))
extern void
dump_sframe (const sframe_decoder_ctx *decoder, uint64_t addr);
+/* Get IDX'th offset as unsigned data from FRE. Set errp as applicable. */
+extern uint32_t
+sframe_get_fre_udata (const sframe_frame_row_entry *fre, int idx, int *errp);
+
/* Get the base reg id from the FRE info. Sets errp if fails. */
extern uint8_t
sframe_fre_get_base_reg_id (const sframe_frame_row_entry *fre, int *errp);
/* Get the CFA offset from the FRE. If the offset is invalid, sets errp. */
extern int32_t
sframe_fre_get_cfa_offset (const sframe_decoder_ctx *dtcx,
- const sframe_frame_row_entry *fre, int *errp);
+ const sframe_frame_row_entry *fre,
+ uint32_t fde_type,
+ int *errp);
/* Get the FP offset from the FRE. If the offset is invalid, sets errp.
LSB set to one, which is only valid in the topmost frame. */
extern int32_t
sframe_fre_get_fp_offset (const sframe_decoder_ctx *dctx,
- const sframe_frame_row_entry *fre, int *errp);
+ const sframe_frame_row_entry *fre,
+ uint32_t fde_type,
+ int *errp);
/* Get the RA offset from the FRE. If the offset is invalid, sets errp.
LSB set to one, which is only valid in the topmost frame. */
extern int32_t
sframe_fre_get_ra_offset (const sframe_decoder_ctx *dctx,
- const sframe_frame_row_entry *fre, int *errp);
+ const sframe_frame_row_entry *fre,
+ uint32_t fde_type,
+ int *errp);
/* Get whether the RA is mangled. */
sframe_fde_create_func_info;
sframe_calc_fre_type;
sframe_fre_get_base_reg_id;
+ sframe_get_fre_udata;
sframe_fre_get_cfa_offset;
sframe_fre_get_fp_offset;
sframe_fre_get_ra_offset;
assert no error for base reg id and RA undefined. */
base_reg_id = sframe_fre_get_base_reg_id (&fre, &err[0]);
ra_undefined_p = sframe_fre_get_ra_undefined_p (sfd_ctx, &fre, &err[0]);
- cfa_offset = sframe_fre_get_cfa_offset (sfd_ctx, &fre, &err[0]);
- fp_offset = sframe_fre_get_fp_offset (sfd_ctx, &fre, &err[1]);
- ra_offset = sframe_fre_get_ra_offset (sfd_ctx, &fre, &err[2]);
+ cfa_offset = sframe_fre_get_cfa_offset (sfd_ctx, &fre,
+ SFRAME_FDE_TYPE_DEFAULT,
+ &err[0]);
+ fp_offset = sframe_fre_get_fp_offset (sfd_ctx, &fre,
+ SFRAME_FDE_TYPE_DEFAULT, &err[1]);
+ ra_offset = sframe_fre_get_ra_offset (sfd_ctx, &fre,
+ SFRAME_FDE_TYPE_DEFAULT, &err[2]);
/* Dump VMA. */
printf ("\n");
}
}
+/* Get IDX'th offset as unsigned data from FRE. Set errp as applicable. */
+
+uint32_t
+sframe_get_fre_udata (const sframe_frame_row_entry *fre, int idx, int *errp)
+{
+ uint8_t offset_cnt, offset_size;
+
+ if (fre == NULL || !sframe_fre_sanity_check_p (fre))
+ return sframe_set_errno (errp, SFRAME_ERR_FRE_INVAL);
+
+ offset_cnt = sframe_fre_get_offset_count (fre->fre_info);
+ offset_size = sframe_fre_get_offset_size (fre->fre_info);
+
+ if (offset_cnt < idx + 1)
+ return sframe_set_errno (errp, SFRAME_ERR_FREOFFSET_NOPRESENT);
+
+ if (errp)
+ *errp = 0; /* Offset Valid. */
+
+ if (offset_size == SFRAME_FRE_OFFSET_1B)
+ {
+ uint8_t *offsets = (uint8_t *)fre->fre_offsets;
+ return offsets[idx];
+ }
+ else if (offset_size == SFRAME_FRE_OFFSET_2B)
+ {
+ uint16_t *offsets = (uint16_t *)fre->fre_offsets;
+ return offsets[idx];
+ }
+ else
+ {
+ uint32_t *offsets = (uint32_t *)fre->fre_offsets;
+ return offsets[idx];
+ }
+}
+
/* Free the decoder context. */
void
int32_t
sframe_fre_get_cfa_offset (const sframe_decoder_ctx *dctx,
- const sframe_frame_row_entry *fre, int *errp)
+ const sframe_frame_row_entry *fre,
+ uint32_t fde_type,
+ int *errp)
{
int err;
- int32_t offset = sframe_get_fre_offset (fre, SFRAME_FRE_CFA_OFFSET_IDX, &err);
+ bool flex_p = (fde_type == SFRAME_FDE_TYPE_FLEX);
+ uint32_t idx = flex_p ? 1 : 0;
+ int32_t offset = sframe_get_fre_offset (fre, idx, &err);
/* For s390x undo adjustment of CFA offset (to enable 8-bit offsets). */
- if (!err && sframe_decoder_get_abi_arch (dctx) == SFRAME_ABI_S390X_ENDIAN_BIG)
+ if (!err
+ && sframe_decoder_get_abi_arch (dctx) == SFRAME_ABI_S390X_ENDIAN_BIG)
offset = SFRAME_V2_S390X_CFA_OFFSET_DECODE (offset);
if (errp)
return offset;
}
-/* Get the FP offset from the FRE. If the offset is invalid, sets errp.
-
- For s390x the offset may be an encoded register number, indicated by
- LSB set to one, which is only valid in the topmost frame. */
+/* Get the FP offset from the FRE. If the offset is invalid, sets errp. */
int32_t
sframe_fre_get_fp_offset (const sframe_decoder_ctx *dctx,
- const sframe_frame_row_entry *fre, int *errp)
-{
- uint32_t fp_offset_idx = 0;
- int8_t fp_offset = sframe_decoder_get_fixed_fp_offset (dctx);
- /* If the FP offset is not being tracked, return the fixed FP offset
- from the SFrame header. */
- if (fp_offset != SFRAME_CFA_FIXED_FP_INVALID
+ const sframe_frame_row_entry *fre,
+ uint32_t fde_type,
+ int *errp)
+{
+ int fp_err = 0;
+ int8_t fixed_fp_offset = sframe_decoder_get_fixed_fp_offset (dctx);
+ bool flex_p = (fde_type == SFRAME_FDE_TYPE_FLEX);
+
+ /* Initialize fp_offset_idx for default FDEs. In some ABIs, the stack offset
+ to recover RA (using the CFA) from is fixed (like AMD64). In such cases,
+ the stack offset to recover FP will appear at the second index. */
+ uint32_t fp_offset_idx = ((sframe_decoder_get_fixed_ra_offset (dctx)
+ != SFRAME_CFA_FIXED_RA_INVALID)
+ ? SFRAME_FRE_RA_OFFSET_IDX
+ : SFRAME_FRE_FP_OFFSET_IDX);
+ if (flex_p)
+ {
+ uint32_t flex_ra_reg_data
+ = sframe_get_fre_udata (fre, SFRAME_FRE_RA_OFFSET_IDX * 2, errp);
+ /* In presence of RA padding SFRAME_FRE_RA_OFFSET_INVALID (instead of RA
+ offsets), adjust the expected index of the FP offset. */
+ if (errp && *errp == 0
+ && flex_ra_reg_data == SFRAME_FRE_RA_OFFSET_INVALID)
+ fp_offset_idx = SFRAME_FRE_FP_OFFSET_IDX * 2;
+ else
+ fp_offset_idx = SFRAME_FRE_FP_OFFSET_IDX * 2 + 1;
+ }
+
+ /* NB: This errp must be retained if returning fp_offset. */
+ int32_t fp_offset = sframe_get_fre_offset (fre, fp_offset_idx, &fp_err);
+
+ /* If the FP offset is not being tracked, return the fixed FP offset from the
+ SFrame header:
+ - For default FDEs (!flex_p)
+ - For flex FDEs, if there were no FP offsets found. */
+ if ((!flex_p || (flex_p && fp_err))
+ && fixed_fp_offset != SFRAME_CFA_FIXED_FP_INVALID
&& !sframe_get_fre_ra_undefined_p (fre->fre_info))
{
if (errp)
*errp = 0;
- return fp_offset;
+ return fixed_fp_offset;
}
- /* In some ABIs, the stack offset to recover RA (using the CFA) from is
- fixed (like AMD64). In such cases, the stack offset to recover FP will
- appear at the second index. */
- fp_offset_idx = ((sframe_decoder_get_fixed_ra_offset (dctx)
- != SFRAME_CFA_FIXED_RA_INVALID)
- ? SFRAME_FRE_RA_OFFSET_IDX
- : SFRAME_FRE_FP_OFFSET_IDX);
- return sframe_get_fre_offset (fre, fp_offset_idx, errp);
+ if (errp)
+ *errp = fp_err;
+ return fp_offset;
}
-/* Get the RA offset from the FRE. If the offset is invalid, sets errp.
-
- For s390x an RA offset value of SFRAME_FRE_RA_OFFSET_INVALID indicates
- that the RA is not saved, which is only valid in the topmost frame.
- For s390x the offset may be an encoded register number, indicated by
- LSB set to one, which is only valid in the topmost frame. */
+/* Get the RA offset from the FRE. If the offset is invalid, sets errp. */
int32_t
sframe_fre_get_ra_offset (const sframe_decoder_ctx *dctx,
- const sframe_frame_row_entry *fre, int *errp)
-{
- int8_t ra_offset = sframe_decoder_get_fixed_ra_offset (dctx);
- /* If the RA offset was not being tracked, return the fixed RA offset
- from the SFrame header. */
- if (ra_offset != SFRAME_CFA_FIXED_RA_INVALID
+ const sframe_frame_row_entry *fre,
+ uint32_t fde_type,
+ int *errp)
+{
+ int ra_err = 0;
+ int8_t fixed_ra_offset = sframe_decoder_get_fixed_ra_offset (dctx);
+ bool flex_p = (fde_type == SFRAME_FDE_TYPE_FLEX);
+
+ uint32_t ra_offset_idx = (flex_p
+ ? SFRAME_FRE_RA_OFFSET_IDX * 2 + 1
+ : SFRAME_FRE_RA_OFFSET_IDX);
+ /* NB: This errp must be retained if returning ra_offset. */
+ int32_t ra_offset = sframe_get_fre_offset (fre, ra_offset_idx, &ra_err);
+
+ /* For ABIs where RA offset is not being tracked, return the fixed RA offset
+ specified in the the SFrame header, when:
+ - for default FDEs (!flex_p)
+ - for flex FDEs, if RA offset is solely padding or not present. */
+ if ((!flex_p || (flex_p && ra_err))
+ && fixed_ra_offset != SFRAME_CFA_FIXED_RA_INVALID
&& !sframe_get_fre_ra_undefined_p (fre->fre_info))
{
if (errp)
*errp = 0;
- return ra_offset;
+ return fixed_ra_offset;
}
- /* Otherwise, get the RA offset from the FRE. */
- return sframe_get_fre_offset (fre, SFRAME_FRE_RA_OFFSET_IDX, errp);
+ /* Otherwise, return the RA offset from the FRE. The corresponding errp was
+ set earlier. */
+ if (errp)
+ *errp = ra_err;
+ return ra_offset;
}
/* Get whether the RA is mangled. */
char *sframe_buf;
size_t sf_size;
int err = 0;
+ uint32_t dfde = SFRAME_FDE_TYPE_DEFAULT;
encode = sframe_encode (SFRAME_VERSION,
SFRAME_F_FDE_FUNC_START_PCREL,
/* Find the third FRE in first FDE. */
lookup_pc = func1_start_vaddr + 0x15 - sframe_vaddr;
err = sframe_find_fre (dctx, lookup_pc, &frep);
- TEST ((err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x3),
+ TEST ((err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, dfde, &err) == 0x3),
"findfre-1%c: Find third FRE", suffix);
/* Find an FRE for PC at the end of range covered by FRE. */
lookup_pc = func1_start_vaddr + 0x9 - sframe_vaddr;
err = sframe_find_fre (dctx, lookup_pc, &frep);
- TEST ((err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x2),
+ TEST ((err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, dfde, &err) == 0x2),
"findfre-1%c: Find FRE for last PC covered by FRE", suffix);
/* Find the last FRE in first FDE. */
lookup_pc = func1_start_vaddr + 0x39 - sframe_vaddr;
err = sframe_find_fre (dctx, lookup_pc, &frep);
- TEST ((err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x8),
+ TEST ((err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, dfde, &err) == 0x8),
"findfre-1%c: Find last FRE", suffix);
/* Find the second FRE in second FDE. */
lookup_pc = func2_start_vaddr + 0x11 - sframe_vaddr;
err = sframe_find_fre (dctx, lookup_pc, &frep);
- TEST ((err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x12),
+ TEST ((err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, dfde, &err) == 0x12),
"findfre-1%c: Find second FRE", suffix);
/* Find the first FRE in second FDE. */
lookup_pc = func2_start_vaddr + 0x0 - sframe_vaddr;
err = sframe_find_fre (dctx, lookup_pc, &frep);
- TEST ((err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x10),
+ TEST ((err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, dfde, &err) == 0x10),
"findfre-1%c: Find first FRE", suffix);
/* Find FRE for PC out of range. Expect error code. */
char *sframe_buf;
size_t sf_size;
int err = 0;
+ uint32_t dfde = SFRAME_FDE_TYPE_DEFAULT;
encode = sframe_encode (SFRAME_VERSION,
SFRAME_F_FDE_FUNC_START_PCREL,
/* Find an FRE for PC in FDE1. */
lookup_pc = func1_start_vaddr + 0x9 - sframe_vaddr;
err = sframe_find_fre (dctx, lookup_pc, &frep);
- TEST ((err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x2),
+ TEST ((err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, dfde, &err) == 0x2),
"findfunc-1%c: Find FRE in FDE1", suffix);
/* Find an FRE for PC in FDE2. */
lookup_pc = func2_start_vaddr + 0x11 - sframe_vaddr;
err = sframe_find_fre (dctx, lookup_pc, &frep);
- TEST ((err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x12),
+ TEST ((err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, dfde, &err) == 0x12),
"findfunc-1%c: Find FRE in FDE2", suffix);
/* Find an FRE for PC in FDE3. */
lookup_pc = func3_start_vaddr + 0x10 - sframe_vaddr;
err = sframe_find_fre (dctx, lookup_pc, &frep);
- TEST ((err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x18),
+ TEST ((err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, dfde, &err) == 0x18),
"findfunc-1%c: Find FRE in FDE3", suffix);
sframe_encoder_free (&encode);
size_t sf_size;
int err = 0;
uint32_t fde_cnt = 0;
+ uint32_t dfde = SFRAME_FDE_TYPE_DEFAULT;
ectx = sframe_encode (SFRAME_VERSION, SFRAME_F_FDE_FUNC_START_PCREL,
SFRAME_ABI_AMD64_ENDIAN_LITTLE,
/* Find the first FRE in PLT1. */
err = sframe_find_fre (dctx, (plt_vaddr + 0x0 - sframe_vaddr), &frep);
- TEST ((err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x1),
+ TEST ((err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, dfde, &err) == 0x1),
"plt-findfre-1%c: Find first FRE in PLT1", suffix);
/* Find the second FRE. */
err = sframe_find_fre (dctx, (plt_vaddr + 0x6 - sframe_vaddr), &frep);
- TEST ((err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x2),
+ TEST ((err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, dfde, &err) == 0x2),
"plt-findfre-1%c: Find second FRE in PLT1", suffix);
/* Find the last FRE. */
err = sframe_find_fre (dctx, (plt_vaddr + 0xc - sframe_vaddr), &frep);
- TEST ((err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x3),
+ TEST ((err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, dfde, &err) == 0x3),
"plt-findfre-1%c: Find last FRE in PLT1", suffix);
/* Find the first FRE in PLT4. */
err = sframe_find_fre (dctx, (plt_vaddr + 16*3 + 0x0 - sframe_vaddr), &frep);
- TEST ((err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x1),
+ TEST ((err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, dfde, &err) == 0x1),
"plt-findfre-1%c: Find first FRE in PLT4", suffix);
/* Find the second FRE in PLT4. */
err = sframe_find_fre (dctx, (plt_vaddr + 16*3 + 0x6 - sframe_vaddr), &frep);
- TEST ((err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x2),
+ TEST ((err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, dfde, &err) == 0x2),
"plt-findfre-1%c: Find second FRE in PLT4", suffix);
/* Find the last FRE in PLT4. */
err = sframe_find_fre (dctx, (plt_vaddr + 16*3 + 0xc - sframe_vaddr), &frep);
- TEST ((err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x3),
+ TEST ((err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, dfde, &err) == 0x3),
"plt-findfre-1%c: Find last FRE in PLT4", suffix);
/* Find no FRE for out of range PLT6. */
int err = 0;
unsigned int fde_cnt = 0;
int i;
+ uint32_t dfde = SFRAME_FDE_TYPE_DEFAULT;
ectx = sframe_encode (SFRAME_VERSION, SFRAME_F_FDE_FUNC_START_PCREL,
SFRAME_ABI_S390X_ENDIAN_BIG,
/* Find the only FRE in PLT0 at offset 0. */
err = sframe_find_fre (dctx, (plt_vaddr + 0 - sframe_vaddr), &frep);
- TEST (err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 160 + PLT0_CFA_OFFSET_MAGIC,
+ TEST (err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, dfde, &err) == 160 + PLT0_CFA_OFFSET_MAGIC,
"plt-findfre-2%c: Find only FRE in PLT0 at offset 0", suffix);
/* Find the only FRE in PLT0 at offset PLT_SIZE-1. */
err = sframe_find_fre (dctx, (plt_vaddr + (PLT_SIZE-1) - sframe_vaddr), &frep);
- TEST (err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 160 + PLT0_CFA_OFFSET_MAGIC,
+ TEST (err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, dfde, &err) == 160 + PLT0_CFA_OFFSET_MAGIC,
"plt-findfre-2%c: Find only FRE in PLT0 at offset PLT_SIZE-1", suffix);
/* Find the only FRE in PLT1-5 at offset 0 and PLT_SIZE-1. */
{
/* Find the only FRE in PLTN at offset 0. */
err = sframe_find_fre (dctx, (plt_vaddr + i * PLT_SIZE + 0 - sframe_vaddr), &frep);
- TEST (err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 160 + PLTN_CFA_OFFSET_MAGIC,
+ TEST (err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, dfde, &err) == 160 + PLTN_CFA_OFFSET_MAGIC,
"plt-findfre-2%c: Find only FRE in PLT%d at offset 0", suffix, i);
/* Find the only FRE in PLTN at offset 31. */
err = sframe_find_fre (dctx, (plt_vaddr + i * PLT_SIZE + (PLT_SIZE-1) - sframe_vaddr), &frep);
- TEST (err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 160 + PLTN_CFA_OFFSET_MAGIC,
+ TEST (err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, dfde, &err) == 160 + PLTN_CFA_OFFSET_MAGIC,
"plt-findfre-2%c: Find only FRE in PLT%d at offset PLT_SIZE-1", suffix, i);
}