[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