gas: scfi: bugfixes for SCFI state propagation

There are two state propagation functions in SCFI machinery - forward
and backward flow.  The patch addresses two issues:
  - In forward_flow_scfi_state (), the state being compared in forward flow
    must be that at the exit of a prev bb and that at the entry of the
    next bb.  The variable holding the state to be compared was
    previously (erroneously) stale.
  - In cmp_scfi_state (), the assumption that two different control
    flows, leading to the same basic block, cannot have a mismatched
    notion of CFA base register, is not true.  Remove the assertion and
    instead return err if mismatch.

Fixing these issues helps correctly synthesize CFI, when previously
SCFI was erroring out for an otherwise valid input asm.

gas/
	* scfi.c (cmp_scfi_state): Remove assertion and return mismatch
	in return value as applicable.
	(forward_flow_scfi_state): Update state object to be the same as
	the exit state of the prev bb before comparing.

gas/testsuite/
	* gas/scfi/x86_64/scfi-x86-64.exp: Add new test.
	* gas/scfi/x86_64/scfi-cfg-5.d: New test.
	* gas/scfi/x86_64/scfi-cfg-5.l: New test.
	* gas/scfi/x86_64/scfi-cfg-5.s: New test.
This commit is contained in:
Indu Bhagat
2024-04-10 13:46:37 -07:00
parent a1c6a60cc5
commit f1c5d46cae
5 changed files with 87 additions and 8 deletions

View File

@@ -155,7 +155,7 @@ cmp_scfi_state (scfi_stateS *state1, scfi_stateS *state2)
int ret;
if (!state1 || !state2)
ret = 1;
return 1;
/* Skip comparing the scratch[] value of registers. The user visible
unwind information is derived from the regs[] from the SCFI state. */
@@ -164,10 +164,12 @@ cmp_scfi_state (scfi_stateS *state1, scfi_stateS *state2)
/* For user functions which perform dynamic stack allocation, after switching
t REG_FP based CFA tracking, it is perfectly possible to have stack usage
in some control flows. However, double-checking that all control flows
have the same idea of CFA tracking before this wont hurt. */
gas_assert (state1->regs[REG_CFA].base == state2->regs[REG_CFA].base);
if (state1->regs[REG_CFA].base == REG_SP)
in some control flows. Further, the different control flows may even not
have the same idea of CFA tracking (likely later necessitating generation
of .cfi_remember_state / .cfi_restore_state pair). */
ret |= state1->regs[REG_CFA].base != state2->regs[REG_CFA].base;
if (!ret && state1->regs[REG_CFA].base == REG_SP)
ret |= state1->stack_size != state2->stack_size;
ret |= state1->traceable_p != state2->traceable_p;
@@ -911,11 +913,11 @@ gen_scfi_ops (ginsnS *ginsn, scfi_stateS *state)
return ret;
}
/* Recursively perform forward flow of the (unwind information) SCFI state
/* Recursively perform forward flow of the (unwind information) SCFI STATE
starting at basic block GBB.
The forward flow process propagates the SCFI state at exit of a basic block
to the successor basic block.
The core of forward flow process takes the SCFI state at the entry of a bb
and updates it incrementally as per the semantics of each ginsn in the bb.
Returns error code, if any. */
@@ -961,6 +963,8 @@ forward_flow_scfi_state (gcfgS *gcfg, gbbS *gbb, scfi_stateS *state)
bb_for_each_edge(gbb, gedge)
{
gbb = gedge->dst_bb;
/* Ensure that the state is the one from the exit of the prev bb. */
memcpy (state, prev_bb->exit_state, sizeof (scfi_stateS));
if (gbb->visited)
{
ret = cmp_scfi_state (gbb->entry_state, state);

View File

@@ -0,0 +1,39 @@
#as: --scfi=experimental -W
#as:
#objdump: -Wf
#name: Synthesize CFI in presence of control flow 5
#...
Contents of the .eh_frame section:
00000000 0+0014 0+0000 CIE
Version: 1
Augmentation: "zR"
Code alignment factor: 1
Data alignment factor: -8
Return address column: 16
Augmentation data: 1b
DW_CFA_def_cfa: r7 \(rsp\) ofs 8
DW_CFA_offset: r16 \(rip\) at cfa-8
DW_CFA_nop
DW_CFA_nop
0+0018 0+002c 0000001c FDE cie=00000000 pc=0+0000..0+0017
DW_CFA_advance_loc: 1 to 0+0001
DW_CFA_def_cfa_offset: 16
DW_CFA_offset: r6 \(rbp\) at cfa-16
DW_CFA_advance_loc: 3 to 0+0004
DW_CFA_def_cfa_register: r6 \(rbp\)
DW_CFA_advance_loc: 5 to 0+0009
DW_CFA_remember_state
DW_CFA_advance_loc: 6 to 0+000f
DW_CFA_def_cfa_register: r7 \(rsp\)
DW_CFA_restore: r6 \(rbp\)
DW_CFA_def_cfa_offset: 8
DW_CFA_advance_loc: 1 to 0+0010
DW_CFA_restore_state
DW_CFA_advance_loc: 6 to 0+0016
DW_CFA_def_cfa_register: r7 \(rsp\)
DW_CFA_restore: r6 \(rbp\)
DW_CFA_def_cfa_offset: 8
#pass

View File

@@ -0,0 +1,2 @@
.*Assembler messages:
.*5: Warning: SCFI ignores most user-specified CFI directives

View File

@@ -0,0 +1,32 @@
.text
.globl foo
.type foo, @function
foo:
.cfi_startproc
push %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
mov %rsp, %rbp
.cfi_def_cfa_register %rbp
cmpl $-1, %eax
jne .L1
.L2:
.cfi_remember_state
call bar
pop %rbp
.cfi_def_cfa_register %rsp
.cfi_restore %rbp
.cfi_def_cfa_offset 8
ret
.L1:
.cfi_restore_state
testq %rax, %rax
je .L2
pop %rbp
.cfi_def_cfa_register %rsp
.cfi_restore %rbp
.cfi_def_cfa_offset 8
ret
.cfi_endproc
.size foo,.-foo

View File

@@ -82,6 +82,8 @@ if { ([istarget "x86_64-*-*"] && ![istarget "x86_64-*-linux*-gnux32"]) } then {
run_list_test "scfi-cfg-3" "--scfi=experimental --warn"
run_dump_test "scfi-cfg-4"
run_list_test "scfi-cfg-4" "--scfi=experimental --warn"
run_dump_test "scfi-cfg-5"
run_list_test "scfi-cfg-5" "--scfi=experimental --warn"
run_dump_test "scfi-asm-marker-1"
run_list_test "scfi-asm-marker-1" "--scfi=experimental --warn"
run_dump_test "scfi-asm-marker-2"