2023-04-13 07:40:26

by Haibo Li

[permalink] [raw]
Subject: [PATCH v2] ARM:unwind:fix unwind abort for uleb128 case

When unwind instruction is 0xb2,the subsequent instructions
are uleb128 bytes.
For now,it uses only the first uleb128 byte in code.

For vsp increments of 0x204~0x400,use one uleb128 byte like below:
0xc06a00e4 <unwind_test_work>: 0x80b27fac
Compact model index: 0
0xb2 0x7f vsp = vsp + 1024
0xac pop {r4, r5, r6, r7, r8, r14}

For vsp increments larger than 0x400,use two uleb128 bytes like below:
0xc06a00e4 <unwind_test_work>: @0xc0cc9e0c
Compact model index: 1
0xb2 0x81 0x01 vsp = vsp + 1032
0xac pop {r4, r5, r6, r7, r8, r14}
The unwind works well since the decoded uleb128 byte is also 0x81.

For vsp increments larger than 0x600,use two uleb128 bytes like below:
0xc06a00e4 <unwind_test_work>: @0xc0cc9e0c
Compact model index: 1
0xb2 0x81 0x02 vsp = vsp + 1544
0xac pop {r4, r5, r6, r7, r8, r14}
In this case,the decoded uleb128 result is 0x101(vsp=0x204+(0x101<<2)).
While the uleb128 used in code is 0x81(vsp=0x204+(0x81<<2)).
The unwind aborts at this frame since it gets incorrect vsp.

To fix this,add uleb128 decode to cover all the above case.

Signed-off-by: Haibo Li <[email protected]>
---
v2:
- As Linus Walleij and Alexandre Mergnat suggested,add comments for unwind_decode_uleb128
- As Alexandre Mergnat suggested,change variables declaration in Alphabetical order
---
arch/arm/kernel/unwind.c | 25 ++++++++++++++++++++++++-
1 file changed, 24 insertions(+), 1 deletion(-)

diff --git a/arch/arm/kernel/unwind.c b/arch/arm/kernel/unwind.c
index 53be7ea6181b..f37e55fcf81d 100644
--- a/arch/arm/kernel/unwind.c
+++ b/arch/arm/kernel/unwind.c
@@ -308,6 +308,29 @@ static int unwind_exec_pop_subset_r0_to_r3(struct unwind_ctrl_block *ctrl,
return URC_OK;
}

+static unsigned long unwind_decode_uleb128(struct unwind_ctrl_block *ctrl)
+{
+ unsigned long bytes = 0;
+ unsigned long insn;
+ unsigned long result = 0;
+
+ /* unwind_get_byte() will advance ctrl one instruction at a time,
+ * we loop until we get an instruction byte where bit 7 is not set.
+ * Note:It decodes max 4 bytes to output 28bits data.
+ * 28bits data(0xfffffff) covers vsp increments of 1073742336.
+ * It is sufficent for unwinding stack.
+ */
+ do {
+ insn = unwind_get_byte(ctrl);
+ result |= (insn & 0x7f) << (bytes * 7);
+ bytes++;
+ if (bytes == sizeof(result))
+ break;
+ } while (!!(insn & 0x80));
+
+ return result;
+}
+
/*
* Execute the current unwind instruction.
*/
@@ -361,7 +384,7 @@ static int unwind_exec_insn(struct unwind_ctrl_block *ctrl)
if (ret)
goto error;
} else if (insn == 0xb2) {
- unsigned long uleb128 = unwind_get_byte(ctrl);
+ unsigned long uleb128 = unwind_decode_uleb128(ctrl);

ctrl->vrs[SP] += 0x204 + (uleb128 << 2);
} else {
--
2.25.1


2023-04-13 07:42:29

by Linus Walleij

[permalink] [raw]
Subject: Re: [PATCH v2] ARM:unwind:fix unwind abort for uleb128 case

On Thu, Apr 13, 2023 at 9:34 AM Haibo Li <[email protected]> wrote:

> When unwind instruction is 0xb2,the subsequent instructions
> are uleb128 bytes.
> For now,it uses only the first uleb128 byte in code.
>
> For vsp increments of 0x204~0x400,use one uleb128 byte like below:
> 0xc06a00e4 <unwind_test_work>: 0x80b27fac
> Compact model index: 0
> 0xb2 0x7f vsp = vsp + 1024
> 0xac pop {r4, r5, r6, r7, r8, r14}
>
> For vsp increments larger than 0x400,use two uleb128 bytes like below:
> 0xc06a00e4 <unwind_test_work>: @0xc0cc9e0c
> Compact model index: 1
> 0xb2 0x81 0x01 vsp = vsp + 1032
> 0xac pop {r4, r5, r6, r7, r8, r14}
> The unwind works well since the decoded uleb128 byte is also 0x81.
>
> For vsp increments larger than 0x600,use two uleb128 bytes like below:
> 0xc06a00e4 <unwind_test_work>: @0xc0cc9e0c
> Compact model index: 1
> 0xb2 0x81 0x02 vsp = vsp + 1544
> 0xac pop {r4, r5, r6, r7, r8, r14}
> In this case,the decoded uleb128 result is 0x101(vsp=0x204+(0x101<<2)).
> While the uleb128 used in code is 0x81(vsp=0x204+(0x81<<2)).
> The unwind aborts at this frame since it gets incorrect vsp.
>
> To fix this,add uleb128 decode to cover all the above case.
>
> Signed-off-by: Haibo Li <[email protected]>

Thanks Haibo,
Reviewed-by: Linus Walleij <[email protected]>

Please put this into Russell's patch tracker once you feel it is finished!
https://www.arm.linux.org.uk/developer/patches/

Yours,
Linus Walleij

2023-04-13 13:11:05

by Alexandre Mergnat

[permalink] [raw]
Subject: Re: [PATCH v2] ARM:unwind:fix unwind abort for uleb128 case

On 13/04/2023 09:39, Linus Walleij wrote:
> On Thu, Apr 13, 2023 at 9:34 AM Haibo Li<[email protected]> wrote:
>
>> When unwind instruction is 0xb2,the subsequent instructions
>> are uleb128 bytes.
>> For now,it uses only the first uleb128 byte in code.
>>
>> For vsp increments of 0x204~0x400,use one uleb128 byte like below:
>> 0xc06a00e4 <unwind_test_work>: 0x80b27fac
>> Compact model index: 0
>> 0xb2 0x7f vsp = vsp + 1024
>> 0xac pop {r4, r5, r6, r7, r8, r14}
>>
>> For vsp increments larger than 0x400,use two uleb128 bytes like below:
>> 0xc06a00e4 <unwind_test_work>: @0xc0cc9e0c
>> Compact model index: 1
>> 0xb2 0x81 0x01 vsp = vsp + 1032
>> 0xac pop {r4, r5, r6, r7, r8, r14}
>> The unwind works well since the decoded uleb128 byte is also 0x81.
>>
>> For vsp increments larger than 0x600,use two uleb128 bytes like below:
>> 0xc06a00e4 <unwind_test_work>: @0xc0cc9e0c
>> Compact model index: 1
>> 0xb2 0x81 0x02 vsp = vsp + 1544
>> 0xac pop {r4, r5, r6, r7, r8, r14}
>> In this case,the decoded uleb128 result is 0x101(vsp=0x204+(0x101<<2)).
>> While the uleb128 used in code is 0x81(vsp=0x204+(0x81<<2)).
>> The unwind aborts at this frame since it gets incorrect vsp.
>>
>> To fix this,add uleb128 decode to cover all the above case.
>>
>> Signed-off-by: Haibo Li<[email protected]>
> Thanks Haibo,
> Reviewed-by: Linus Walleij<[email protected]>

Reviewed-by: Alexandre Mergnat <[email protected]>


Regards,
Alexandre

Subject: Re: [PATCH v2] ARM:unwind:fix unwind abort for uleb128 case

Il 13/04/23 09:34, Haibo Li ha scritto:
> When unwind instruction is 0xb2,the subsequent instructions
> are uleb128 bytes.
> For now,it uses only the first uleb128 byte in code.
>
> For vsp increments of 0x204~0x400,use one uleb128 byte like below:
> 0xc06a00e4 <unwind_test_work>: 0x80b27fac
> Compact model index: 0
> 0xb2 0x7f vsp = vsp + 1024
> 0xac pop {r4, r5, r6, r7, r8, r14}
>
> For vsp increments larger than 0x400,use two uleb128 bytes like below:
> 0xc06a00e4 <unwind_test_work>: @0xc0cc9e0c
> Compact model index: 1
> 0xb2 0x81 0x01 vsp = vsp + 1032
> 0xac pop {r4, r5, r6, r7, r8, r14}
> The unwind works well since the decoded uleb128 byte is also 0x81.
>
> For vsp increments larger than 0x600,use two uleb128 bytes like below:
> 0xc06a00e4 <unwind_test_work>: @0xc0cc9e0c
> Compact model index: 1
> 0xb2 0x81 0x02 vsp = vsp + 1544
> 0xac pop {r4, r5, r6, r7, r8, r14}
> In this case,the decoded uleb128 result is 0x101(vsp=0x204+(0x101<<2)).
> While the uleb128 used in code is 0x81(vsp=0x204+(0x81<<2)).
> The unwind aborts at this frame since it gets incorrect vsp.
>
> To fix this,add uleb128 decode to cover all the above case.
>
> Signed-off-by: Haibo Li <[email protected]>
> ---
> v2:
> - As Linus Walleij and Alexandre Mergnat suggested,add comments for unwind_decode_uleb128
> - As Alexandre Mergnat suggested,change variables declaration in Alphabetical order
> ---
> arch/arm/kernel/unwind.c | 25 ++++++++++++++++++++++++-
> 1 file changed, 24 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm/kernel/unwind.c b/arch/arm/kernel/unwind.c
> index 53be7ea6181b..f37e55fcf81d 100644
> --- a/arch/arm/kernel/unwind.c
> +++ b/arch/arm/kernel/unwind.c
> @@ -308,6 +308,29 @@ static int unwind_exec_pop_subset_r0_to_r3(struct unwind_ctrl_block *ctrl,
> return URC_OK;
> }
>
> +static unsigned long unwind_decode_uleb128(struct unwind_ctrl_block *ctrl)
> +{
> + unsigned long bytes = 0;
> + unsigned long insn;
> + unsigned long result = 0;
> +
> + /* unwind_get_byte() will advance ctrl one instruction at a time,
> + * we loop until we get an instruction byte where bit 7 is not set.
> + * Note:It decodes max 4 bytes to output 28bits data.
> + * 28bits data(0xfffffff) covers vsp increments of 1073742336.
> + * It is sufficent for unwinding stack.
> + */

/*
* unwind_get_byte() will advance `ctrl` one instruction at a time, so
* loop until we get an instruction byte where bit 7 is not set.
*
* Note: This decodes a maximum of 4 bytes to output 28 bits data where
* max is 0xfffffff: that will cover a vsp increment of 1073742336, hence
* it is sufficient for unwinding the stack.
*/

> + do {
> + insn = unwind_get_byte(ctrl);
> + result |= (insn & 0x7f) << (bytes * 7);
> + bytes++;

also, I would do ...

} while (!!(insn & 0x80) && bytes != sizeof(result));

...compressing the code and not creating any human readability concern.

after which, you can get my

Reviewed-by: AngeloGioacchino Del Regno <[email protected]>


2023-04-14 05:58:14

by Haibo Li

[permalink] [raw]
Subject: Re: [PATCH v2] ARM:unwind:fix unwind abort for uleb128 case

> Il 13/04/23 09:34, Haibo Li ha scritto:

> > When unwind instruction is 0xb2,the subsequent instructions are

> > uleb128 bytes.

> > For now,it uses only the first uleb128 byte in code.

> >

> > For vsp increments of 0x204~0x400,use one uleb128 byte like below:

> > 0xc06a00e4 <unwind_test_work>: 0x80b27fac

> > Compact model index: 0

> > 0xb2 0x7f vsp = vsp + 1024

> > 0xac pop {r4, r5, r6, r7, r8, r14}

> >

> > For vsp increments larger than 0x400,use two uleb128 bytes like below:

> > 0xc06a00e4 <unwind_test_work>: @0xc0cc9e0c

> > Compact model index: 1

> > 0xb2 0x81 0x01 vsp = vsp + 1032

> > 0xac pop {r4, r5, r6, r7, r8, r14}

> > The unwind works well since the decoded uleb128 byte is also 0x81.

> >

> > For vsp increments larger than 0x600,use two uleb128 bytes like below:

> > 0xc06a00e4 <unwind_test_work>: @0xc0cc9e0c

> > Compact model index: 1

> > 0xb2 0x81 0x02 vsp = vsp + 1544

> > 0xac pop {r4, r5, r6, r7, r8, r14}

> > In this case,the decoded uleb128 result is 0x101(vsp=0x204+(0x101<<2)).

> > While the uleb128 used in code is 0x81(vsp=0x204+(0x81<<2)).

> > The unwind aborts at this frame since it gets incorrect vsp.

> >

> > To fix this,add uleb128 decode to cover all the above case.

> >

> > Signed-off-by: Haibo Li <[email protected]>

> > ---

> > v2:

> > - As Linus Walleij and Alexandre Mergnat suggested,add comments for

> > unwind_decode_uleb128

> > - As Alexandre Mergnat suggested,change variables declaration in

> > Alphabetical order

> > ---

> > arch/arm/kernel/unwind.c | 25 ++++++++++++++++++++++++-

> > 1 file changed, 24 insertions(+), 1 deletion(-)

> >

> > diff --git a/arch/arm/kernel/unwind.c b/arch/arm/kernel/unwind.c index

> > 53be7ea6181b..f37e55fcf81d 100644

> > --- a/arch/arm/kernel/unwind.c

> > +++ b/arch/arm/kernel/unwind.c

> > @@ -308,6 +308,29 @@ static int

> unwind_exec_pop_subset_r0_to_r3(struct unwind_ctrl_block *ctrl,

> > return URC_OK;

> > }

> >

> > +static unsigned long unwind_decode_uleb128(struct unwind_ctrl_block

> > +*ctrl) {

> > + unsigned long bytes = 0;

> > + unsigned long insn;

> > + unsigned long result = 0;

> > +

> > + /* unwind_get_byte() will advance ctrl one instruction at a time,

> > + * we loop until we get an instruction byte where bit 7 is not set.

> > + * Note:It decodes max 4 bytes to output 28bits data.

> > + * 28bits data(0xfffffff) covers vsp increments of 1073742336.

> > + * It is sufficent for unwinding stack.

> > + */

>

> /*

> * unwind_get_byte() will advance `ctrl` one instruction at a time, so

> * loop until we get an instruction byte where bit 7 is not set.

> *

> * Note: This decodes a maximum of 4 bytes to output 28 bits data where

> * max is 0xfffffff: that will cover a vsp increment of 1073742336, hence

> * it is sufficient for unwinding the stack.

> */

Looks much better.Thanks.

>

> > + do {

> > + insn = unwind_get_byte(ctrl);

> > + result |= (insn & 0x7f) << (bytes * 7);

> > + bytes++;

>

> also, I would do ...

>

> } while (!!(insn & 0x80) && bytes != sizeof(result));

>

> ...compressing the code and not creating any human readability concern.

>

> after which, you can get my

>

> Reviewed-by: AngeloGioacchino Del Regno

> <[email protected]>

get it.I will make a new patch.