[PATCH 5.15 135/230] powerpc/vdso: Fix incorrect CFI in gettimeofday.S

From: Greg Kroah-Hartman
Date: Mon Jul 11 2022 - 05:58:39 EST


From: Michael Ellerman <mpe@xxxxxxxxxxxxxx>

[ Upstream commit 6d65028eb67dbb7627651adfc460d64196d38bd8 ]

As reported by Alan, the CFI (Call Frame Information) in the VDSO time
routines is incorrect since commit ce7d8056e38b ("powerpc/vdso: Prepare
for switching VDSO to generic C implementation.").

DWARF has a concept called the CFA (Canonical Frame Address), which on
powerpc is calculated as an offset from the stack pointer (r1). That
means when the stack pointer is changed there must be a corresponding
CFI directive to update the calculation of the CFA.

The current code is missing those directives for the changes to r1,
which prevents gdb from being able to generate a backtrace from inside
VDSO functions, eg:

Breakpoint 1, 0x00007ffff7f804dc in __kernel_clock_gettime ()
(gdb) bt
#0 0x00007ffff7f804dc in __kernel_clock_gettime ()
#1 0x00007ffff7d8872c in clock_gettime@@GLIBC_2.17 () from /lib64/libc.so.6
#2 0x00007fffffffd960 in ?? ()
#3 0x00007ffff7d8872c in clock_gettime@@GLIBC_2.17 () from /lib64/libc.so.6
Backtrace stopped: frame did not save the PC

Alan helpfully describes some rules for correctly maintaining the CFI information:

1) Every adjustment to the current frame address reg (ie. r1) must be
described, and exactly at the instruction where r1 changes. Why?
Because stack unwinding might want to access previous frames.

2) If a function changes LR or any non-volatile register, the save
location for those regs must be given. The CFI can be at any
instruction after the saves up to the point that the reg is
changed.
(Exception: LR save should be described before a bl. not after)

3) If asychronous unwind info is needed then restores of LR and
non-volatile regs must also be described. The CFI can be at any
instruction after the reg is restored up to the point where the
save location is (potentially) trashed.

Fix the inability to backtrace by adding CFI directives describing the
changes to r1, ie. satisfying rule 1.

Also change the information for LR to point to the copy saved on the
stack, not the value in r0 that will be overwritten by the function
call.

Finally, add CFI directives describing the save/restore of r2.

With the fix gdb can correctly back trace and navigate up and down the stack:

Breakpoint 1, 0x00007ffff7f804dc in __kernel_clock_gettime ()
(gdb) bt
#0 0x00007ffff7f804dc in __kernel_clock_gettime ()
#1 0x00007ffff7d8872c in clock_gettime@@GLIBC_2.17 () from /lib64/libc.so.6
#2 0x0000000100015b60 in gettime ()
#3 0x000000010000c8bc in print_long_format ()
#4 0x000000010000d180 in print_current_files ()
#5 0x00000001000054ac in main ()
(gdb) up
#1 0x00007ffff7d8872c in clock_gettime@@GLIBC_2.17 () from /lib64/libc.so.6
(gdb)
#2 0x0000000100015b60 in gettime ()
(gdb)
#3 0x000000010000c8bc in print_long_format ()
(gdb)
#4 0x000000010000d180 in print_current_files ()
(gdb)
#5 0x00000001000054ac in main ()
(gdb)
Initial frame selected; you cannot go up.
(gdb) down
#4 0x000000010000d180 in print_current_files ()
(gdb)
#3 0x000000010000c8bc in print_long_format ()
(gdb)
#2 0x0000000100015b60 in gettime ()
(gdb)
#1 0x00007ffff7d8872c in clock_gettime@@GLIBC_2.17 () from /lib64/libc.so.6
(gdb)
#0 0x00007ffff7f804dc in __kernel_clock_gettime ()
(gdb)

Fixes: ce7d8056e38b ("powerpc/vdso: Prepare for switching VDSO to generic C implementation.")
Cc: stable@xxxxxxxxxxxxxxx # v5.11+
Reported-by: Alan Modra <amodra@xxxxxxxxx>
Signed-off-by: Michael Ellerman <mpe@xxxxxxxxxxxxxx>
Reviewed-by: Segher Boessenkool <segher@xxxxxxxxxxxxxxxxxxx>
Link: https://lore.kernel.org/r/20220502125010.1319370-1-mpe@xxxxxxxxxxxxxx
Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>
---
arch/powerpc/kernel/vdso32/gettimeofday.S | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/arch/powerpc/kernel/vdso32/gettimeofday.S b/arch/powerpc/kernel/vdso32/gettimeofday.S
index dd2099128b8f..42d40f895c1f 100644
--- a/arch/powerpc/kernel/vdso32/gettimeofday.S
+++ b/arch/powerpc/kernel/vdso32/gettimeofday.S
@@ -22,12 +22,15 @@
.macro cvdso_call funct call_time=0
.cfi_startproc
PPC_STLU r1, -PPC_MIN_STKFRM(r1)
+ .cfi_adjust_cfa_offset PPC_MIN_STKFRM
mflr r0
- .cfi_register lr, r0
PPC_STLU r1, -PPC_MIN_STKFRM(r1)
+ .cfi_adjust_cfa_offset PPC_MIN_STKFRM
PPC_STL r0, PPC_MIN_STKFRM + PPC_LR_STKOFF(r1)
+ .cfi_rel_offset lr, PPC_MIN_STKFRM + PPC_LR_STKOFF
#ifdef __powerpc64__
PPC_STL r2, PPC_MIN_STKFRM + STK_GOT(r1)
+ .cfi_rel_offset r2, PPC_MIN_STKFRM + STK_GOT
#endif
get_datapage r5
.ifeq \call_time
@@ -39,13 +42,15 @@
PPC_LL r0, PPC_MIN_STKFRM + PPC_LR_STKOFF(r1)
#ifdef __powerpc64__
PPC_LL r2, PPC_MIN_STKFRM + STK_GOT(r1)
+ .cfi_restore r2
#endif
.ifeq \call_time
cmpwi r3, 0
.endif
mtlr r0
- .cfi_restore lr
addi r1, r1, 2 * PPC_MIN_STKFRM
+ .cfi_restore lr
+ .cfi_def_cfa_offset 0
crclr so
.ifeq \call_time
beqlr+
--
2.35.1