Re: [PATCH] riscv: eliminate unreliable __builtin_frame_address(1)

From: Jessica Clarke
Date: Mon Jan 17 2022 - 12:33:47 EST


On 17 Jan 2022, at 15:44, Changbin Du <changbin.du@xxxxxxxxx> wrote:
>
> I tried different pieces of code which uses __builtin_frame_address(1)
> (with both gcc version 7.5.0 and 10.3.0) to verify whether it works as
> expected on riscv64. The result is negative.
>
> What the compiler had generated is as below:
> 31 fp = (unsigned long)__builtin_frame_address(1);
> 0xffffffff80006024 <+200>: ld s1,0(s0)
>
> It takes '0(s0)' as the address of frame 1 (caller), but the actual address
> should be '-16(s0)'.
>
> | ... | <-+
> +-----------------+ |
> | return address | |
> | previous fp | |
> | saved registers | |
> | local variables | |
> $fp --> | ... | |
> +-----------------+ |
> | return address | |
> | previous fp --------+
> | saved registers |
> $sp --> | local variables |
> +-----------------+
>
> This leads the kernel can not dump the full stack trace on riscv.
>
> [ 7.222126][ T1] Call Trace:
> [ 7.222804][ T1] [<ffffffff80006058>] dump_backtrace+0x2c/0x3a
>
> This problem is not exposed on most riscv builds just because the '0(s0)'
> occasionally is the address frame 2 (caller's caller), if only ra and fp
> are stored in frame 1 (caller).
>
> | ... | <-+
> +-----------------+ |
> | return address | |
> $fp --> | previous fp | |
> +-----------------+ |
> | return address | |
> | previous fp --------+
> | saved registers |
> $sp --> | local variables |
> +-----------------+
>
> This could be a *bug* of gcc that should be fixed. But as noted in gcc
> manual "Calling this function with a nonzero argument can have
> unpredictable effects, including crashing the calling program.", let's
> remove the '__builtin_frame_address(1)' in backtrace code.

Yes, this is a bug, that is always wrong. LLVM gets this right.

https://godbolt.org/z/MrhsoPPM6

Jess