diff mbox series

aarch64: Fix .cfi_window_save with pac-ret [PR94515]

Message ID 20200409142011.GG987@arm.com
State New
Headers show
Series aarch64: Fix .cfi_window_save with pac-ret [PR94515] | expand

Commit Message

Szabolcs Nagy April 9, 2020, 2:20 p.m. UTC
On aarch64 -mbranch-protection=pac-ret reuses the dwarf
opcode for window_save to mean "toggle the return address
mangle state", but in the dwarf2cfi internal logic the
state was not properly recorded so the remember/restore
logic was broken.

This can cause the unwinder not to authenticate return
addresses that were signed (or vice versa) which means
a runtime crash on a pauth enabled system.

Currently only aarch64 pac-ret uses REG_CFA_TOGGLE_RA_MANGLE.

gcc/ChangeLog:

2020-04-XX  Szabolcs Nagy  <szabolcs.nagy@arm.com>

	PR target/94515
	* dwarf2cfi.c (dwarf2out_frame_debug): Record RA
	mangle state in cur_row->window_save.

gcc/testsuite/ChangeLog:

2020-04-XX  Szabolcs Nagy  <szabolcs.nagy@arm.com>

	PR target/94515
	* g++.target/aarch64/pr94515.C: New test.
---
 gcc/dwarf2cfi.c                            |  3 ++
 gcc/testsuite/g++.target/aarch64/pr94515.C | 43 ++++++++++++++++++++++
 2 files changed, 46 insertions(+)
 create mode 100644 gcc/testsuite/g++.target/aarch64/pr94515.C

Comments

Kyrylo Tkachov April 17, 2020, 10:08 a.m. UTC | #1
Hi Szabolcs,

> -----Original Message-----
> From: Szabolcs Nagy <Szabolcs.Nagy@arm.com>
> Sent: 09 April 2020 15:20
> To: gcc-patches@gcc.gnu.org
> Cc: Richard Earnshaw <Richard.Earnshaw@arm.com>; Richard Sandiford
> <Richard.Sandiford@arm.com>; Kyrylo Tkachov <Kyrylo.Tkachov@arm.com>
> Subject: [PATCH] aarch64: Fix .cfi_window_save with pac-ret [PR94515]
> 
> On aarch64 -mbranch-protection=pac-ret reuses the dwarf
> opcode for window_save to mean "toggle the return address
> mangle state", but in the dwarf2cfi internal logic the
> state was not properly recorded so the remember/restore
> logic was broken.
> 
> This can cause the unwinder not to authenticate return
> addresses that were signed (or vice versa) which means
> a runtime crash on a pauth enabled system.
> 
> Currently only aarch64 pac-ret uses REG_CFA_TOGGLE_RA_MANGLE.

I think this is ok, but this code is in the midend so I've CC'ed Jason who, from what I gather from MAINTAINERS, is maintainer for this file.
Thanks,
Kyrill

> 
> gcc/ChangeLog:
> 
> 2020-04-XX  Szabolcs Nagy  <szabolcs.nagy@arm.com>
> 
> 	PR target/94515
> 	* dwarf2cfi.c (dwarf2out_frame_debug): Record RA
> 	mangle state in cur_row->window_save.
> 
> gcc/testsuite/ChangeLog:
> 
> 2020-04-XX  Szabolcs Nagy  <szabolcs.nagy@arm.com>
> 
> 	PR target/94515
> 	* g++.target/aarch64/pr94515.C: New test.
> ---
>  gcc/dwarf2cfi.c                            |  3 ++
>  gcc/testsuite/g++.target/aarch64/pr94515.C | 43 ++++++++++++++++++++++
>  2 files changed, 46 insertions(+)
>  create mode 100644 gcc/testsuite/g++.target/aarch64/pr94515.C
> 
> diff --git a/gcc/dwarf2cfi.c b/gcc/dwarf2cfi.c
> index 229fbfacc30..22989a6c2fb 100644
> --- a/gcc/dwarf2cfi.c
> +++ b/gcc/dwarf2cfi.c
> @@ -2145,6 +2145,9 @@ dwarf2out_frame_debug (rtx_insn *insn)
>        case REG_CFA_TOGGLE_RA_MANGLE:
>  	/* This uses the same DWARF opcode as the next operation.  */
>  	dwarf2out_frame_debug_cfa_window_save (true);
> +	/* Keep track of RA mangle state by toggling the window_save bit.
> +	   This is needed so .cfi_window_save is emitted correctly.  */
> +	cur_row->window_save = !cur_row->window_save;
>  	handled_one = true;
>  	break;
> 
> diff --git a/gcc/testsuite/g++.target/aarch64/pr94515.C
> b/gcc/testsuite/g++.target/aarch64/pr94515.C
> new file mode 100644
> index 00000000000..7707c773a72
> --- /dev/null
> +++ b/gcc/testsuite/g++.target/aarch64/pr94515.C
> @@ -0,0 +1,43 @@
> +/* PR target/94515. Check .cfi_window_save with multiple return paths.  */
> +/* { dg-do run } */
> +/* { dg-additional-options "-O2 -mbranch-protection=pac-ret --save-temps" }
> */
> +
> +volatile int zero = 0;
> +
> +__attribute__((noinline, target("branch-protection=none")))
> +void unwind (void)
> +{
> +  if (zero == 0)
> +    throw 42;
> +}
> +
> +__attribute__((noinline, noipa, target("branch-protection=pac-ret")))
> +int test (int z)
> +{
> +  if (z) {
> +    asm volatile ("":::"x20","x21");
> +    unwind ();
> +    return 1;
> +  } else {
> +    unwind ();
> +    return 2;
> +  }
> +}
> +
> +__attribute__((target("branch-protection=none")))
> +int main ()
> +{
> +  try {
> +    test (zero);
> +    __builtin_abort ();
> +  } catch (...) {
> +    return 0;
> +  }
> +  __builtin_abort ();
> +}
> +
> +/* This check only works if there are two return paths in test and
> +   cfi_window_save is used for both instead of cfi_remember_state
> +   plus cfi_restore_state.  This is currently the case with -O2.  */
> +
> +/* { dg-final { scan-assembler-times {\t\.cfi_window_save\n} 4 } } */
> --
> 2.17.1
Jason Merrill April 17, 2020, 4:50 p.m. UTC | #2
On 4/17/20 6:08 AM, Kyrylo Tkachov wrote:
> Hi Szabolcs,
> 
>> -----Original Message-----
>> From: Szabolcs Nagy <Szabolcs.Nagy@arm.com>
>> Sent: 09 April 2020 15:20
>> To: gcc-patches@gcc.gnu.org
>> Cc: Richard Earnshaw <Richard.Earnshaw@arm.com>; Richard Sandiford
>> <Richard.Sandiford@arm.com>; Kyrylo Tkachov <Kyrylo.Tkachov@arm.com>
>> Subject: [PATCH] aarch64: Fix .cfi_window_save with pac-ret [PR94515]
>>
>> On aarch64 -mbranch-protection=pac-ret reuses the dwarf
>> opcode for window_save to mean "toggle the return address
>> mangle state", but in the dwarf2cfi internal logic the
>> state was not properly recorded so the remember/restore
>> logic was broken.
>>
>> This can cause the unwinder not to authenticate return
>> addresses that were signed (or vice versa) which means
>> a runtime crash on a pauth enabled system.
>>
>> Currently only aarch64 pac-ret uses REG_CFA_TOGGLE_RA_MANGLE.
> 
> I think this is ok, but this code is in the midend so I've CC'ed Jason who, from what I gather from MAINTAINERS, is maintainer for this file.
> Thanks,
> Kyrill
> 
>>
>> gcc/ChangeLog:
>>
>> 2020-04-XX  Szabolcs Nagy  <szabolcs.nagy@arm.com>
>>
>> 	PR target/94515
>> 	* dwarf2cfi.c (dwarf2out_frame_debug): Record RA
>> 	mangle state in cur_row->window_save.
>>
>> gcc/testsuite/ChangeLog:
>>
>> 2020-04-XX  Szabolcs Nagy  <szabolcs.nagy@arm.com>
>>
>> 	PR target/94515
>> 	* g++.target/aarch64/pr94515.C: New test.
>> ---
>>   gcc/dwarf2cfi.c                            |  3 ++
>>   gcc/testsuite/g++.target/aarch64/pr94515.C | 43 ++++++++++++++++++++++
>>   2 files changed, 46 insertions(+)
>>   create mode 100644 gcc/testsuite/g++.target/aarch64/pr94515.C
>>
>> diff --git a/gcc/dwarf2cfi.c b/gcc/dwarf2cfi.c
>> index 229fbfacc30..22989a6c2fb 100644
>> --- a/gcc/dwarf2cfi.c
>> +++ b/gcc/dwarf2cfi.c
>> @@ -2145,6 +2145,9 @@ dwarf2out_frame_debug (rtx_insn *insn)
>>         case REG_CFA_TOGGLE_RA_MANGLE:
>>   	/* This uses the same DWARF opcode as the next operation.  */
>>   	dwarf2out_frame_debug_cfa_window_save (true);
>> +	/* Keep track of RA mangle state by toggling the window_save bit.
>> +	   This is needed so .cfi_window_save is emitted correctly.  */
>> +	cur_row->window_save = !cur_row->window_save;

It looks like passing 'true' to dwarf2out_frame_debug_cfa_window_save 
prevents that function from messing with the window_safe flag.  Does 
changing the argument to 'false' get the behavior you want?

>>   	handled_one = true;
>>   	break;
>>
>> diff --git a/gcc/testsuite/g++.target/aarch64/pr94515.C
>> b/gcc/testsuite/g++.target/aarch64/pr94515.C
>> new file mode 100644
>> index 00000000000..7707c773a72
>> --- /dev/null
>> +++ b/gcc/testsuite/g++.target/aarch64/pr94515.C
>> @@ -0,0 +1,43 @@
>> +/* PR target/94515. Check .cfi_window_save with multiple return paths.  */
>> +/* { dg-do run } */
>> +/* { dg-additional-options "-O2 -mbranch-protection=pac-ret --save-temps" }
>> */
>> +
>> +volatile int zero = 0;
>> +
>> +__attribute__((noinline, target("branch-protection=none")))
>> +void unwind (void)
>> +{
>> +  if (zero == 0)
>> +    throw 42;
>> +}
>> +
>> +__attribute__((noinline, noipa, target("branch-protection=pac-ret")))
>> +int test (int z)
>> +{
>> +  if (z) {
>> +    asm volatile ("":::"x20","x21");
>> +    unwind ();
>> +    return 1;
>> +  } else {
>> +    unwind ();
>> +    return 2;
>> +  }
>> +}
>> +
>> +__attribute__((target("branch-protection=none")))
>> +int main ()
>> +{
>> +  try {
>> +    test (zero);
>> +    __builtin_abort ();
>> +  } catch (...) {
>> +    return 0;
>> +  }
>> +  __builtin_abort ();
>> +}
>> +
>> +/* This check only works if there are two return paths in test and
>> +   cfi_window_save is used for both instead of cfi_remember_state
>> +   plus cfi_restore_state.  This is currently the case with -O2.  */
>> +
>> +/* { dg-final { scan-assembler-times {\t\.cfi_window_save\n} 4 } } */
>> --
>> 2.17.1
>
Szabolcs Nagy April 17, 2020, 5:55 p.m. UTC | #3
The 04/17/2020 12:50, Jason Merrill wrote:
> On 4/17/20 6:08 AM, Kyrylo Tkachov wrote:
> > Hi Szabolcs,
> > 
> > > -----Original Message-----
> > > From: Szabolcs Nagy <Szabolcs.Nagy@arm.com>
> > > Sent: 09 April 2020 15:20
> > > To: gcc-patches@gcc.gnu.org
> > > Cc: Richard Earnshaw <Richard.Earnshaw@arm.com>; Richard Sandiford
> > > <Richard.Sandiford@arm.com>; Kyrylo Tkachov <Kyrylo.Tkachov@arm.com>
> > > Subject: [PATCH] aarch64: Fix .cfi_window_save with pac-ret [PR94515]
> > > 
> > > On aarch64 -mbranch-protection=pac-ret reuses the dwarf
> > > opcode for window_save to mean "toggle the return address
> > > mangle state", but in the dwarf2cfi internal logic the
> > > state was not properly recorded so the remember/restore
> > > logic was broken.
> > > 
> > > This can cause the unwinder not to authenticate return
> > > addresses that were signed (or vice versa) which means
> > > a runtime crash on a pauth enabled system.
> > > 
> > > Currently only aarch64 pac-ret uses REG_CFA_TOGGLE_RA_MANGLE.
> > 
> > I think this is ok, but this code is in the midend so I've CC'ed Jason who, from what I gather from MAINTAINERS, is maintainer for this file.
> > Thanks,
> > Kyrill
> > 
> > > 
> > > gcc/ChangeLog:
> > > 
> > > 2020-04-XX  Szabolcs Nagy  <szabolcs.nagy@arm.com>
> > > 
> > > 	PR target/94515
> > > 	* dwarf2cfi.c (dwarf2out_frame_debug): Record RA
> > > 	mangle state in cur_row->window_save.
> > > 
> > > gcc/testsuite/ChangeLog:
> > > 
> > > 2020-04-XX  Szabolcs Nagy  <szabolcs.nagy@arm.com>
> > > 
> > > 	PR target/94515
> > > 	* g++.target/aarch64/pr94515.C: New test.
> > > ---
> > >   gcc/dwarf2cfi.c                            |  3 ++
> > >   gcc/testsuite/g++.target/aarch64/pr94515.C | 43 ++++++++++++++++++++++
> > >   2 files changed, 46 insertions(+)
> > >   create mode 100644 gcc/testsuite/g++.target/aarch64/pr94515.C
> > > 
> > > diff --git a/gcc/dwarf2cfi.c b/gcc/dwarf2cfi.c
> > > index 229fbfacc30..22989a6c2fb 100644
> > > --- a/gcc/dwarf2cfi.c
> > > +++ b/gcc/dwarf2cfi.c
> > > @@ -2145,6 +2145,9 @@ dwarf2out_frame_debug (rtx_insn *insn)
> > >         case REG_CFA_TOGGLE_RA_MANGLE:
> > >   	/* This uses the same DWARF opcode as the next operation.  */
> > >   	dwarf2out_frame_debug_cfa_window_save (true);
> > > +	/* Keep track of RA mangle state by toggling the window_save bit.
> > > +	   This is needed so .cfi_window_save is emitted correctly.  */
> > > +	cur_row->window_save = !cur_row->window_save;
> 
> It looks like passing 'true' to dwarf2out_frame_debug_cfa_window_save
> prevents that function from messing with the window_safe flag.  Does
> changing the argument to 'false' get the behavior you want?

we want the state = !state toggling.
it might make more sense to do that in
dwarf2out_frame_debug_cfa_window_save(true)
or to inline that entire logic into the two
places where it is used (instead of
dispatching with a bool argument).

for the bug fix i'd like a minimal change
(so it can be backported), doing the fix in
dwarf2out_frame_debug_cfa_window_save
is fine with me, would you prefer that?

> 
> > >   	handled_one = true;
> > >   	break;
> > > 
> > > diff --git a/gcc/testsuite/g++.target/aarch64/pr94515.C
> > > b/gcc/testsuite/g++.target/aarch64/pr94515.C
> > > new file mode 100644
> > > index 00000000000..7707c773a72
> > > --- /dev/null
> > > +++ b/gcc/testsuite/g++.target/aarch64/pr94515.C
> > > @@ -0,0 +1,43 @@
> > > +/* PR target/94515. Check .cfi_window_save with multiple return paths.  */
> > > +/* { dg-do run } */
> > > +/* { dg-additional-options "-O2 -mbranch-protection=pac-ret --save-temps" }
> > > */
> > > +
> > > +volatile int zero = 0;
> > > +
> > > +__attribute__((noinline, target("branch-protection=none")))
> > > +void unwind (void)
> > > +{
> > > +  if (zero == 0)
> > > +    throw 42;
> > > +}
> > > +
> > > +__attribute__((noinline, noipa, target("branch-protection=pac-ret")))
> > > +int test (int z)
> > > +{
> > > +  if (z) {
> > > +    asm volatile ("":::"x20","x21");
> > > +    unwind ();
> > > +    return 1;
> > > +  } else {
> > > +    unwind ();
> > > +    return 2;
> > > +  }
> > > +}
> > > +
> > > +__attribute__((target("branch-protection=none")))
> > > +int main ()
> > > +{
> > > +  try {
> > > +    test (zero);
> > > +    __builtin_abort ();
> > > +  } catch (...) {
> > > +    return 0;
> > > +  }
> > > +  __builtin_abort ();
> > > +}
> > > +
> > > +/* This check only works if there are two return paths in test and
> > > +   cfi_window_save is used for both instead of cfi_remember_state
> > > +   plus cfi_restore_state.  This is currently the case with -O2.  */
> > > +
> > > +/* { dg-final { scan-assembler-times {\t\.cfi_window_save\n} 4 } } */
> > > --
> > > 2.17.1
> > 
> 

--
Jason Merrill April 17, 2020, 7:26 p.m. UTC | #4
On 4/17/20 1:55 PM, Szabolcs Nagy wrote:
> The 04/17/2020 12:50, Jason Merrill wrote:
>> On 4/17/20 6:08 AM, Kyrylo Tkachov wrote:
>>> Hi Szabolcs,
>>>
>>>> -----Original Message-----
>>>> From: Szabolcs Nagy <Szabolcs.Nagy@arm.com>
>>>> Sent: 09 April 2020 15:20
>>>> To: gcc-patches@gcc.gnu.org
>>>> Cc: Richard Earnshaw <Richard.Earnshaw@arm.com>; Richard Sandiford
>>>> <Richard.Sandiford@arm.com>; Kyrylo Tkachov <Kyrylo.Tkachov@arm.com>
>>>> Subject: [PATCH] aarch64: Fix .cfi_window_save with pac-ret [PR94515]
>>>>
>>>> On aarch64 -mbranch-protection=pac-ret reuses the dwarf
>>>> opcode for window_save to mean "toggle the return address
>>>> mangle state", but in the dwarf2cfi internal logic the
>>>> state was not properly recorded so the remember/restore
>>>> logic was broken.
>>>>
>>>> This can cause the unwinder not to authenticate return
>>>> addresses that were signed (or vice versa) which means
>>>> a runtime crash on a pauth enabled system.
>>>>
>>>> Currently only aarch64 pac-ret uses REG_CFA_TOGGLE_RA_MANGLE.
>>>
>>> I think this is ok, but this code is in the midend so I've CC'ed Jason who, from what I gather from MAINTAINERS, is maintainer for this file.
>>> Thanks,
>>> Kyrill
>>>
>>>>
>>>> gcc/ChangeLog:
>>>>
>>>> 2020-04-XX  Szabolcs Nagy  <szabolcs.nagy@arm.com>
>>>>
>>>> 	PR target/94515
>>>> 	* dwarf2cfi.c (dwarf2out_frame_debug): Record RA
>>>> 	mangle state in cur_row->window_save.
>>>>
>>>> gcc/testsuite/ChangeLog:
>>>>
>>>> 2020-04-XX  Szabolcs Nagy  <szabolcs.nagy@arm.com>
>>>>
>>>> 	PR target/94515
>>>> 	* g++.target/aarch64/pr94515.C: New test.
>>>> ---
>>>>    gcc/dwarf2cfi.c                            |  3 ++
>>>>    gcc/testsuite/g++.target/aarch64/pr94515.C | 43 ++++++++++++++++++++++
>>>>    2 files changed, 46 insertions(+)
>>>>    create mode 100644 gcc/testsuite/g++.target/aarch64/pr94515.C
>>>>
>>>> diff --git a/gcc/dwarf2cfi.c b/gcc/dwarf2cfi.c
>>>> index 229fbfacc30..22989a6c2fb 100644
>>>> --- a/gcc/dwarf2cfi.c
>>>> +++ b/gcc/dwarf2cfi.c
>>>> @@ -2145,6 +2145,9 @@ dwarf2out_frame_debug (rtx_insn *insn)
>>>>          case REG_CFA_TOGGLE_RA_MANGLE:
>>>>    	/* This uses the same DWARF opcode as the next operation.  */
>>>>    	dwarf2out_frame_debug_cfa_window_save (true);
>>>> +	/* Keep track of RA mangle state by toggling the window_save bit.
>>>> +	   This is needed so .cfi_window_save is emitted correctly.  */
>>>> +	cur_row->window_save = !cur_row->window_save;
>>
>> It looks like passing 'true' to dwarf2out_frame_debug_cfa_window_save
>> prevents that function from messing with the window_safe flag.  Does
>> changing the argument to 'false' get the behavior you want?
> 
> we want the state = !state toggling.
> it might make more sense to do that in
> dwarf2out_frame_debug_cfa_window_save(true)
> or to inline that entire logic into the two
> places where it is used (instead of
> dispatching with a bool argument).

I think that inlining and dropping the parameter would be cleaner.

> for the bug fix i'd like a minimal change
> (so it can be backported), doing the fix in
> dwarf2out_frame_debug_cfa_window_save
> is fine with me, would you prefer that?

No, thanks.  If you want to commit your patch as is for backporting and 
then do the inlining in a separate commit, that works  for me.

>>>>    	handled_one = true;
>>>>    	break;
>>>>
>>>> diff --git a/gcc/testsuite/g++.target/aarch64/pr94515.C
>>>> b/gcc/testsuite/g++.target/aarch64/pr94515.C
>>>> new file mode 100644
>>>> index 00000000000..7707c773a72
>>>> --- /dev/null
>>>> +++ b/gcc/testsuite/g++.target/aarch64/pr94515.C
>>>> @@ -0,0 +1,43 @@
>>>> +/* PR target/94515. Check .cfi_window_save with multiple return paths.  */
>>>> +/* { dg-do run } */
>>>> +/* { dg-additional-options "-O2 -mbranch-protection=pac-ret --save-temps" }
>>>> */
>>>> +
>>>> +volatile int zero = 0;
>>>> +
>>>> +__attribute__((noinline, target("branch-protection=none")))
>>>> +void unwind (void)
>>>> +{
>>>> +  if (zero == 0)
>>>> +    throw 42;
>>>> +}
>>>> +
>>>> +__attribute__((noinline, noipa, target("branch-protection=pac-ret")))
>>>> +int test (int z)
>>>> +{
>>>> +  if (z) {
>>>> +    asm volatile ("":::"x20","x21");
>>>> +    unwind ();
>>>> +    return 1;
>>>> +  } else {
>>>> +    unwind ();
>>>> +    return 2;
>>>> +  }
>>>> +}
>>>> +
>>>> +__attribute__((target("branch-protection=none")))
>>>> +int main ()
>>>> +{
>>>> +  try {
>>>> +    test (zero);
>>>> +    __builtin_abort ();
>>>> +  } catch (...) {
>>>> +    return 0;
>>>> +  }
>>>> +  __builtin_abort ();
>>>> +}
>>>> +
>>>> +/* This check only works if there are two return paths in test and
>>>> +   cfi_window_save is used for both instead of cfi_remember_state
>>>> +   plus cfi_restore_state.  This is currently the case with -O2.  */
>>>> +
>>>> +/* { dg-final { scan-assembler-times {\t\.cfi_window_save\n} 4 } } */
>>>> --
>>>> 2.17.1
>>>
>>
>
Szabolcs Nagy April 21, 2020, 2:31 p.m. UTC | #5
The 04/17/2020 15:26, Jason Merrill wrote:
> On 4/17/20 1:55 PM, Szabolcs Nagy wrote:
> > The 04/17/2020 12:50, Jason Merrill wrote:
> > > On 4/17/20 6:08 AM, Kyrylo Tkachov wrote:
> > > > Hi Szabolcs,
> > > > 
> > > > > -----Original Message-----
> > > > > From: Szabolcs Nagy <Szabolcs.Nagy@arm.com>
> > > > > Sent: 09 April 2020 15:20
> > > > > To: gcc-patches@gcc.gnu.org
> > > > > Cc: Richard Earnshaw <Richard.Earnshaw@arm.com>; Richard Sandiford
> > > > > <Richard.Sandiford@arm.com>; Kyrylo Tkachov <Kyrylo.Tkachov@arm.com>
> > > > > Subject: [PATCH] aarch64: Fix .cfi_window_save with pac-ret [PR94515]
> > > > > 
> > > > > On aarch64 -mbranch-protection=pac-ret reuses the dwarf
> > > > > opcode for window_save to mean "toggle the return address
> > > > > mangle state", but in the dwarf2cfi internal logic the
> > > > > state was not properly recorded so the remember/restore
> > > > > logic was broken.
> > > > > 
> > > > > This can cause the unwinder not to authenticate return
> > > > > addresses that were signed (or vice versa) which means
> > > > > a runtime crash on a pauth enabled system.
> > > > > 
> > > > > Currently only aarch64 pac-ret uses REG_CFA_TOGGLE_RA_MANGLE.
> > > > 
> > > > I think this is ok, but this code is in the midend so I've CC'ed Jason who, from what I gather from MAINTAINERS, is maintainer for this file.
> > > > Thanks,
> > > > Kyrill
> > > > 
> > > > > 
> > > > > gcc/ChangeLog:
> > > > > 
> > > > > 2020-04-XX  Szabolcs Nagy  <szabolcs.nagy@arm.com>
> > > > > 
> > > > > 	PR target/94515
> > > > > 	* dwarf2cfi.c (dwarf2out_frame_debug): Record RA
> > > > > 	mangle state in cur_row->window_save.
> > > > > 
> > > > > gcc/testsuite/ChangeLog:
> > > > > 
> > > > > 2020-04-XX  Szabolcs Nagy  <szabolcs.nagy@arm.com>
> > > > > 
> > > > > 	PR target/94515
> > > > > 	* g++.target/aarch64/pr94515.C: New test.
> > > > > ---
> > > > >    gcc/dwarf2cfi.c                            |  3 ++
> > > > >    gcc/testsuite/g++.target/aarch64/pr94515.C | 43 ++++++++++++++++++++++
> > > > >    2 files changed, 46 insertions(+)
> > > > >    create mode 100644 gcc/testsuite/g++.target/aarch64/pr94515.C
> > > > > 
> > > > > diff --git a/gcc/dwarf2cfi.c b/gcc/dwarf2cfi.c
> > > > > index 229fbfacc30..22989a6c2fb 100644
> > > > > --- a/gcc/dwarf2cfi.c
> > > > > +++ b/gcc/dwarf2cfi.c
> > > > > @@ -2145,6 +2145,9 @@ dwarf2out_frame_debug (rtx_insn *insn)
> > > > >          case REG_CFA_TOGGLE_RA_MANGLE:
> > > > >    	/* This uses the same DWARF opcode as the next operation.  */
> > > > >    	dwarf2out_frame_debug_cfa_window_save (true);
> > > > > +	/* Keep track of RA mangle state by toggling the window_save bit.
> > > > > +	   This is needed so .cfi_window_save is emitted correctly.  */
> > > > > +	cur_row->window_save = !cur_row->window_save;
> > > 
> > > It looks like passing 'true' to dwarf2out_frame_debug_cfa_window_save
> > > prevents that function from messing with the window_safe flag.  Does
> > > changing the argument to 'false' get the behavior you want?
> > 
> > we want the state = !state toggling.
> > it might make more sense to do that in
> > dwarf2out_frame_debug_cfa_window_save(true)
> > or to inline that entire logic into the two
> > places where it is used (instead of
> > dispatching with a bool argument).
> 
> I think that inlining and dropping the parameter would be cleaner.
> 
> > for the bug fix i'd like a minimal change
> > (so it can be backported), doing the fix in
> > dwarf2out_frame_debug_cfa_window_save
> > is fine with me, would you prefer that?
> 
> No, thanks.  If you want to commit your patch as is for backporting and then
> do the inlining in a separate commit, that works  for me.

i spoted failing execution tests that expected to pass,
it turns out change_cfi_row() needs something like

-  if (!old_row->window_save && new_row->window_save)
+  if (old_row->window_save != new_row->window_save)

to generate .cfi_window_save that correctly tracks the
toggled state on aarch64, but i assume sparc wants
something else, i added Eric to CC he might know what's
right for the old&&!new case on sparc, any help is
welcome, the logic was added in

commit dfe1fe91dbc7f068bb3efcee40237caacc0c53ae

i can imagine adding a new bool flag in dw_cfi_row
for aarch64 or making the logic target specific
(depending on if the target uses REG_CFA_WINDOW_SAVE
or REG_CFA_TOGGLE_RA_MANGLE for cfi_window_save)

i added a test to the bug report that fails with
my original patch, but works if change_cfi_row is
updated.
Eric Botcazou April 21, 2020, 3:41 p.m. UTC | #6
> i spoted failing execution tests that expected to pass,
> it turns out change_cfi_row() needs something like
> 
> -  if (!old_row->window_save && new_row->window_save)
> +  if (old_row->window_save != new_row->window_save)
> 
> to generate .cfi_window_save that correctly tracks the
> toggled state on aarch64, but i assume sparc wants
> something else, i added Eric to CC he might know what's
> right for the old&&!new case on sparc, any help is
> welcome, the logic was added in
> 
> commit dfe1fe91dbc7f068bb3efcee40237caacc0c53ae

Yes, you cannot really "toggle" a register window on SPARC.

> i can imagine adding a new bool flag in dw_cfi_row
> for aarch64 or making the logic target specific
> (depending on if the target uses REG_CFA_WINDOW_SAVE
> or REG_CFA_TOGGLE_RA_MANGLE for cfi_window_save)

Yes, please do not hijack again the SPARC logic here.
diff mbox series

Patch

diff --git a/gcc/dwarf2cfi.c b/gcc/dwarf2cfi.c
index 229fbfacc30..22989a6c2fb 100644
--- a/gcc/dwarf2cfi.c
+++ b/gcc/dwarf2cfi.c
@@ -2145,6 +2145,9 @@  dwarf2out_frame_debug (rtx_insn *insn)
       case REG_CFA_TOGGLE_RA_MANGLE:
 	/* This uses the same DWARF opcode as the next operation.  */
 	dwarf2out_frame_debug_cfa_window_save (true);
+	/* Keep track of RA mangle state by toggling the window_save bit.
+	   This is needed so .cfi_window_save is emitted correctly.  */
+	cur_row->window_save = !cur_row->window_save;
 	handled_one = true;
 	break;
 
diff --git a/gcc/testsuite/g++.target/aarch64/pr94515.C b/gcc/testsuite/g++.target/aarch64/pr94515.C
new file mode 100644
index 00000000000..7707c773a72
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/pr94515.C
@@ -0,0 +1,43 @@ 
+/* PR target/94515. Check .cfi_window_save with multiple return paths.  */
+/* { dg-do run } */
+/* { dg-additional-options "-O2 -mbranch-protection=pac-ret --save-temps" } */
+
+volatile int zero = 0;
+
+__attribute__((noinline, target("branch-protection=none")))
+void unwind (void)
+{
+  if (zero == 0)
+    throw 42;
+}
+
+__attribute__((noinline, noipa, target("branch-protection=pac-ret")))
+int test (int z)
+{
+  if (z) {
+    asm volatile ("":::"x20","x21");
+    unwind ();
+    return 1;
+  } else {
+    unwind ();
+    return 2;
+  }
+}
+
+__attribute__((target("branch-protection=none")))
+int main ()
+{
+  try {
+    test (zero);
+    __builtin_abort ();
+  } catch (...) {
+    return 0;
+  }
+  __builtin_abort ();
+}
+
+/* This check only works if there are two return paths in test and
+   cfi_window_save is used for both instead of cfi_remember_state
+   plus cfi_restore_state.  This is currently the case with -O2.  */
+
+/* { dg-final { scan-assembler-times {\t\.cfi_window_save\n} 4 } } */