[V3 22/36] [SFrame-V3] sframe: gas: translate specific CFI directives for SFRAME_FDE_TYPE_FLEX
Jan Beulich
jbeulich@suse.com
Fri Jan 16 09:13:05 GMT 2026
On 13.01.2026 12:12, Indu Bhagat via Binutils wrote:
> @@ -1636,6 +1661,132 @@ sframe_xlate_do_gnu_window_save (struct sframe_xlate_ctx *xlate_ctx,
> return SFRAME_XLATE_ERR_NOTREPRESENTED; /* Not represented. */
> }
>
> +/* Translate a DWARF sleb128 offset in the CFI escape data E to an int64_t. */
> +
> +static offsetT
> +sframe_xlate_escape_sleb128_to_int64 (const struct cfi_escape_data *e)
> +{
> + offsetT offset = 0;
> +
> + gas_assert (e->type == CFI_ESC_byte || e->type == CFI_ESC_sleb128);
> + /* Read the offset. */
> + if (e->type == CFI_ESC_byte)
> + {
> + /* The user/compiler may provide an sleb128 encoded data of a single byte
> + length (DWARF offset of DW_OP_bregN is sleb128). On a big-endian
> + host, the endianness of data itself needs to be accommodated then. To
> + keep it simple, gather the LSB, and translate it to int64. */
> + unsigned char sleb_data = e->exp.X_add_number & 0xff;
> + const unsigned char *buf_start = (const unsigned char *)&sleb_data;
> + const unsigned char *buf_end = buf_start + 1;
> + size_t read = read_sleb128_to_int64 (buf_start, buf_end, &offset);
> + gas_assert (read);
I fear asserting here isn't valid, as the user may have encoded something
bogus, or (in principle) it may be a multi-byte LEB128. The latter can't
occur right now as ...
> + }
> + else
> + /* offset must be CFI_ESC_sleb128. */
> + offset = e->exp.X_add_number;
> +
> + return offset;
> +}
> +
> +/* Handle DW_CFA_def_cfa_expression in .cfi_escape.
> +
> + As with sframe_xlate_do_cfi_escape, the intent of this function is to detect
> + only the simple-to-process but common cases. All other CFA escape
> + expressions continue to be inadmissible (no SFrame FDE emitted).
> +
> + Sets CALLER_WARN_P for skipped cases (and returns SFRAME_XLATE_OK) where the
> + caller must warn. The caller then must also set
> + SFRAME_XLATE_ERR_NOTREPRESENTED for their callers. */
> +
> +static int
> +sframe_xlate_do_escape_cfa_expr (struct sframe_xlate_ctx *xlate_ctx,
> + const struct cfi_insn_data *cfi_insn,
> + bool *caller_warn_p)
> +{
> + const struct cfi_escape_data *e = cfi_insn->u.esc;
> + const struct cfi_escape_data *e_offset = NULL;
> + int err = SFRAME_XLATE_OK;
> + unsigned int opcode1, opcode2;
> + offsetT offset;
> + unsigned int reg = SFRAME_FRE_REG_INVALID;
> + unsigned int i = 0;
> + bool x86_cfa_deref_p = false;
> +
> + /* Check roughly for an expression like so:
> + DW_CFA_def_cfa_expression (DW_OP_breg6 (rbp): -8; DW_OP_deref). */
> +#define CFI_ESC_NUM_EXP 4
> + offsetT items[CFI_ESC_NUM_EXP] = {0};
> + while (e->next)
> + {
> + e = e->next;
> + /* Bounds check, must be constant, no relocs. */
> + if (i >= CFI_ESC_NUM_EXP
> + || e->exp.X_op != O_constant
> + || e->reloc != TC_PARSE_CONS_RETURN_NONE)
> + goto warn_and_exit;
> + /* Other checks based on index i.
> + - For item[2], allow byte OR sleb128.
> + - items at index 0, 1, and 3: Must be byte. */
> + if (i == 2 && (e->type != CFI_ESC_byte && e->type != CFI_ESC_sleb128))
> + goto warn_and_exit;
> + else if (i != 2 && e->type != CFI_ESC_byte)
> + goto warn_and_exit;
> + /* Block length (items[0]) of 3 in DWARF expr. */
> + if (i == 1 && items[0] != 3)
... you constrain what you permit to it being 3 bytes total.
Jan
More information about the Binutils
mailing list