[PATCH] gas: sframe: partially process DWARF expressions in CFI_escape
Jan Beulich
jbeulich@suse.com
Tue Jan 28 08:03:17 GMT 2025
On 28.01.2025 01:57, Indu Bhagat wrote:
> --- a/gas/gen-sframe.c
> +++ b/gas/gen-sframe.c
> @@ -1310,6 +1310,77 @@ sframe_xlate_do_gnu_window_save (struct sframe_xlate_ctx *xlate_ctx,
> return SFRAME_XLATE_ERR_NOTREPRESENTED; /* Not represented. */
> }
>
> +/* Translate CFI_escape into SFrame context.
> +
> + .cfi_escape CFI directive allows the user to add arbitrary bytes to the
> + unwind info. DWARF expressions commonly follow after CFI_escape (fake CFI)
> + DWARF opcode. One might also use CFI_escape to add OS-specific CFI opcodes
> + even.
> +
> + In SFrame stack trace format, complex unwind info cannot be represented. In
> + such cases, SFrame FDE generation is skipped and the user is warned. Recall,
> + however, that SFrame stack trace information is meant to convey information
> + about SP, FP and RA only. Hence, some DWARF expressions, are indeed safe to
> + skip.
> +
> + This function partially processes some DWARF expresssions and returns
> + SFRAME_XLATE_OK if OK to skip. */
> +
> +static int
> +sframe_xlate_do_expr (struct sframe_xlate_ctx *xlate_ctx,
> + struct cfi_insn_data *cfi_insn)
Both pointer-to-const?
> +{
> + int op;
> + struct cfi_escape_data *e;
Again.
> + unsigned int reg = 0;
> + int err = SFRAME_XLATE_OK;
> + struct sframe_row_entry *cur_fre = NULL;
And yet gain.
Some of the variables may also better go into the more narrow scope, ...
> + e = cfi_insn->u.esc;
> +
> + if (e)
... or you may want to invert the condition here:
if (!e)
return ...;
reducing indentation for the bulk of the function (helping readability).
> + {
> + op = e->exp.X_add_number;
You're truncating the value here, and ...
> + switch (op)
> + {
> + /* Of all the possible opcodes expected here, it is safe to
> + ignore DW_CFA_expression and DW_CFA_val_expression, provided they
> + do not impact the SP / FP register. */
> + case DW_CFA_expression:
> + case DW_CFA_val_expression:
> + /* Both DW_CFA_expression and DW_CFA_val_expression instructions take
> + two operands: an unsigned LEB128 value representing a register
> + number, and a DW_FORM_block value representing a DWARF expression.
> + For the current purpose, we simply need to know the register
> + number. */
> + e = e->next;
> + /* Keep in sync with the behaviour of cfi_parse_reg (). */
> + gas_assert (e->exp.X_op == O_register || e->exp.X_op == O_constant);
... you're asserting on user input here. Afaics neither is in any way
enforced by dot_cfi_escape() / do_parse_cons_expression(). As to the
comment - how does cfi_parse_reg() come into play for .cfi_escape?
> + reg = e->exp.X_add_number;
> + /* Get the scratchpad FRE. */
> + cur_fre = xlate_ctx->cur_fre;
> + if (reg == SFRAME_CFA_SP_REG || reg == SFRAME_CFA_FP_REG
> + || reg == cur_fre->cfa_base_reg)
> + {
> + as_warn (_("skipping SFrame FDE; .cfi_escape with reg (%#x)"), reg);
> + err = SFRAME_XLATE_ERR_NOTREPRESENTED;
> + }
> + break;
> + /* FIXME - Also add processing for DW_CFA_GNU_args_size in future? */
> + default:
> + /* In all other cases (e.g., DW_CFA_def_cfa_expression or other
> + OS-specific CFI opcodes), skip inspecting the DWARF expression.
> + This may impact the asynchronicity due to loss of coverage.
> + Continue to warn the user and bail out. */
> + as_warn (_("skipping SFrame FDE; .cfi_escape with op (%#x)"), op);
> + err = SFRAME_XLATE_ERR_NOTREPRESENTED;
> + break;
> + }
> + }
Doesn't all of this need to go in a loop, as a single .cfi_escape might
specify multiple successive DW_CFA_*?
Jan
More information about the Binutils
mailing list