[PATCH] gas: sframe: partially process DWARF expressions in CFI_escape
Jan Beulich
jbeulich@suse.com
Wed Jan 29 07:06:33 GMT 2025
On 28.01.2025 19:09, Indu Bhagat wrote:
> On 1/28/25 7:31 AM, Jan Beulich wrote:
>> On 28.01.2025 16:24, Indu Bhagat wrote:
>>> On 1/28/25 12:03 AM, Jan Beulich wrote:
>>>> On 28.01.2025 01:57, Indu Bhagat wrote:
>>>>> + 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?
>>>
>>> IIUC, the first operand of both of these opcodes (DW_CFA_expression,
>>> DW_CFA_val_expression) will be a register. Hence, cfi_parse_reg ()
>>> behaviour is being cross-checked against.
>>>
>>> This function only aims to process some "simple DWARF expressions", and
>>> if they are benign (OK to skip), we do not warn (nor error out with
>>> SFRAME_XLATE_ERR_NOTREPRESENTED). E.g. for,
>>>
>>> DW_CFA_expression: r1 (rdx) (DW_OP_breg7 (rsp): 136)
>>> DW_CFA_expression: r0 (rax) (DW_OP_breg7 (rsp): 144)
>>
>> Yet .cfi_escape accepts all sorts of expressions. It's okay to tell the
>> user that for SFrame this isn't supported. But it's not okay to hide
>> this information behind an internal error (that the failed assertion
>> will result in).
>
> FWIW, cfi_parse_reg () will issue an as_bad () already. I can change
> the assert to if () and continue to warn and return
> SFRAME_XLATE_ERR_NOTREPRESENTED.
Yes please.
>>>>> + 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_*?
>>>
>>> The function intends to process only some DWARF expressions (basically
>>> some commonly-occurring, but safe to skip from SFrame perspective).
>>> Going into a loop may be necessary for opcodes other than
>>> DW_CFA_expression or DW_CFA_val_expression, but at the moment, since we
>>> prefer to cater to only the simple expressions, parsing the complete
>>> expression is not required.
>>
>> No, wait. Simple expressions or not isn't the point here. The point is
>> that with a single .cfi_escape you can specify any number of things,
>> i.e. also multiple operations involving multiple expressions. There's
>> no limit to the number of operands to .cfi_escape afaics - it could
>> literally be hundreds.
>>
>
> (Sorry I am still missing the point)
>
> Yes, potentially large number of operands may follow a .cfi_escape. And
> for all of those, we will hit the "default:" case of the thw switch and
> warn and bail out (like we are doing currently on master).
>
> The only "safe to skip" cases are possible when the first opcode is
> DW_CFA_expression or DW_CFA_val_expression (for now).
Even when others follow? You look at only the first two elements of the
chain starting from cfi_insn->u.esc. That chain, as said, can in principle
be hundreds of elements long, and can - aiui - contain any sequence of
DW_CFA_* (including their operands).
Jan
More information about the Binutils
mailing list