[lldb-dev] [Bug 52165] New: lldb incorrectly unwinds from signal handlers on AArch64 Linux

2021-10-13 Thread via lldb-dev
https://bugs.llvm.org/show_bug.cgi?id=52165

Bug ID: 52165
   Summary: lldb incorrectly unwinds from signal handlers on
AArch64 Linux
   Product: lldb
   Version: unspecified
  Hardware: PC
OS: Linux
Status: NEW
  Severity: enhancement
  Priority: P
 Component: All Bugs
  Assignee: lldb-dev@lists.llvm.org
  Reporter: david.spick...@linaro.org
CC: jdevliegh...@apple.com, llvm-b...@lists.llvm.org

TestHandleAbort.py fails on AArch64 Ubuntu Focal because we're using frame
information from the stack when trying to unwind from __kernel_rt_sigreturn. We
should be using register values from the signal context instead.

The explanation:

This is the backtrace when the signal is first raised:
(lldb) bt
* thread #1, name = 'a.out', stop reason = signal SIGABRT
  * frame #0: 0xf7bda138 libc.so.6`raise + 224
frame #1: 0xf7bc6d68 libc.so.6`abort + 272
frame #2: 0x00400704 a.out`abort_caller at main.c:12:5
frame #3: 0x0040074c a.out`main at main.c:23:5
frame #4: 0xf7bc7090 libc.so.6`__libc_start_main + 232
frame #5: 0x00400614 a.out`_start + 52

We expect to get something like this, plus the signal handler when we hit a
breakpoint in the signal handler. What we actually get is:

(lldb) bt
* thread #1, name = 'a.out', stop reason = breakpoint 1.1
  * frame #0: 0x004006ec a.out`handler(sig=6) at main.c:7:5
frame #1: 0xf7ffc5b8 [vdso]`__kernel_rt_sigreturn
frame #2: 0xeef8

If we examine the frame info in __kernel_rt_sigreturn:
(lldb) memory read -s 8 -f x -c 2 $fp
0xeec0: 0xeed0 0xeef8

We have a vaguely valid looking FP and a clearly invalid LR.

(lldb) memory region 0xeef8
[0xfffdf000-0x0001) rw- [stack]

The FP does actually point to something that *looks* ok (whether by design or
accident).

(lldb) memory read -s 8 -f x -c 2 0xeed0
0xeed0: 0xf000 0xf7bc6d68
(lldb) image lookup -a 0xf7bc6d68
  Address: libc.so.6[0x00023d68] (libc.so.6.PT_LOAD[0]..text + 424)
  Summary: libc.so.6`abort + 272

We expect to get abort but we're missing some "raise" entry beacause of that
invalid LR.

Looking at kernel source they have not added cfi info to sgireturn:
https://github.com/torvalds/linux/blob/659caaf65dc9c7150aa3e80225ec6e66b25ab3ce/arch/arm64/kernel/vdso/sigreturn.S

And gdb/libunwind would be ignoring it anyway as what they do is assume that
the stack pointer in the sigreturn frame points to a signal context and you get
the register from there. See: https://reviews.llvm.org/D90898

We can see the pc we'd want by manually reading that memory:
(lldb) memory read -s 8 -f x $sp+304 $sp+304+512
0xdda0: 0x 0x
<...>
0xdea0: 0xeed0 0xf7bda138
<...>

LLDB needs to have a specific unwind plan for this situation. The closest thing
at the moment is a comment in lldb/source/Target/RegisterContextUnwind.cpp.

// section, so prefer that if available. On other platforms we may need to
// provide a platform-specific UnwindPlan which encodes the details of how to
// unwind out of sigtramp.

So we do have a point in time where we can do that.

Why did this work on bionic? I'm not sure it ever did. I'm not sure that the
frame pointer of __kernel_rt_sigreturn is ever supposed to be valid. What I
think happened on Bionic is that it happened to point to a set of info that
points back into libc's raise.

But it's just memory re-use rather than a deliberate action to put that data
there. I can't prove this 100% but it seems odd that it would be broken between
libc releases, when the kernel stays the same. If anyone was going to setup
this information it would be the kernel.

Further to that, the frame addresses that we get on bionic look a bit off.

* thread #1, name = 'a.out', stop reason = breakpoint 1.1
  * frame #0: 0x004006ac a.out`handler(sig=6) at main.c:7:5
frame #1: 0xf7ffc5b8 [vdso]`__kernel_rt_sigreturn
frame #2: 0xf7c38484 libc.so.6`__GI_raise at nptl-signals.h:68
frame #3: 0xf7c38480 libc.so.6`__GI_raise(sig=6) at raise.c:40
frame #4: 0xf7c398d4 libc.so.6`__GI_abort at abort.c:79
frame #5: 0x004006c8 a.out`abort_caller at main.c:12:5
<...>

(lldb) d -n __GI_raise
libc.so.6`:
<...>
0xf7c38480 <+56>:  bl 0xf7c88f90; __GI_memcpy
0xf7c38484 <+60>:  movx3, x0

I would expect to see some instruction after an svc. Not after a call to a
normal function.

GDB's backtrace shows a different source location for raise.

(gdb) bt
#0  handler (sig=6) at
/home/david.spickett/llvm-project/lldb/test/API/functionalities/signal/handle-abrt/main.c:7
#1  
#2  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/l

[lldb-dev] [Bug 52165] lldb incorrectly unwinds from signal handlers on AArch64 Linux

2021-10-13 Thread via lldb-dev
https://bugs.llvm.org/show_bug.cgi?id=52165

David Spickett  changed:

   What|Removed |Added

   Assignee|lldb-dev@lists.llvm.org |david.spick...@linaro.org
 Status|NEW |CONFIRMED

-- 
You are receiving this mail because:
You are the assignee for the bug.___
lldb-dev mailing list
lldb-dev@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev