[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