[RFC 19/28] [SFrame-V3] sframe: gas: translate specific CFI directives for SFRAME_FDE_TYPE_FLEX_TOPMOST_FRAME

Jan Beulich jbeulich@suse.com
Fri Dec 19 08:12:10 GMT 2025


On 09.12.2025 10:07, Indu Bhagat via Binutils wrote:
> @@ -1574,6 +1614,98 @@ sframe_xlate_do_gnu_window_save (struct sframe_xlate_ctx *xlate_ctx,
>    return SFRAME_XLATE_ERR_NOTREPRESENTED;  /* Not represented.  */
>  }
>  
> +/* 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;
> +  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
> +     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;
> +      if ((i == 1 && (items[0] != 3)) /* Block length of 3 in DWARF expr.  */
> +	  /* We do not care for the exact values of items[2], items[3], and
> +	     items[4], so an explicit check for O_constant isnt necessary
> +	     either.  */
> +	  || i >= CFI_ESC_NUM_EXP
> +	  || (i < 2
> +	      && (e->exp.X_op != O_constant
> +		  || e->type != CFI_ESC_byte
> +		  || e->reloc != TC_PARSE_CONS_RETURN_NONE)))
> +	goto warn_and_exit;
> +      items[i] = e->exp.X_add_number;
> +      i++;
> +    }
> +
> +  if (i <= CFI_ESC_NUM_EXP - 1)
> +    goto warn_and_exit;
> +
> +  opcode1 = items[1];
> +  opcode2 = items[3];
> +  /* DW_OP_breg6 is rbp.  FIXME - this stub can be enhanced to handle more
> +     regs.  */
> +  if (sframe_get_abi_arch () == SFRAME_ABI_AMD64_ENDIAN_LITTLE
> +     && opcode1 == DW_OP_breg6 && opcode2 == DW_OP_deref)
> +    {
> +      x86_cfa_deref_p = true;
> +      reg = SFRAME_CFA_FP_REG;
> +    }
> +
> +  /* Read the offset.  */
> +  const unsigned char *buf_start = (const unsigned char *)&items[2];
> +  const unsigned char *buf_end = buf_start + sizeof (offsetT) - 1;
> +  size_t read = read_sleb128_to_int64 (buf_start, buf_end, &offset);
> +  gas_assert (read);
> +#undef CFI_ESC_NUM_EXP

Now that I finally understood where the already-encoded sleb128 is coming from
(as per the 20/28 sub-thread), I'd like to clarify here that more checking will
need adding: You also need to check items[0] to be DW_CFA_def_cfa_expression,
and I think you also want to do the checking in order (i.e. check items[3] only
after having checked items[2], to eliminate the risk of mistaking an item).

And then, as already alluded to by Jens, I think you also want to permit other
than CFI_ESC_byte in items[2] (in which case the ugly sleb128 decoding won't
be needed). Whether in the CFI_ESC_byte case allowing only 1-byte sleb128 is
going to be sufficient for a wide range of real-world uses I don't know.

Jan


More information about the Binutils mailing list