[V3 22/36] [SFrame-V3] sframe: gas: translate specific CFI directives for SFRAME_FDE_TYPE_FLEX

Indu Bhagat indu.bhagat@oracle.com
Tue Jan 20 21:18:46 GMT 2026


On 1/16/26 1:13 AM, Jan Beulich wrote:
> 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 ...
> 

Since the code is attempting to read one byte ATM, I'd expect the assert 
to never fail (read_sleb128_to_int64 will return 0 when start >= end). 
I realize now though that this isnt necessarily fulfilling any purpose 
other than documentation around expectations of the current code.

I am afraid I dont understand what you are suggesting.

>> +    }
>> +  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