Hi lianbo,
On Wed, Dec 4, 2024 at 9:03 PM lijiang <lijiang(a)redhat.com> wrote:
On Mon, Nov 11, 2024 at 2:54 PM <devel-request(a)lists.crash-utility.osci.io> wrote:
>
> Date: Mon, 11 Nov 2024 16:24:25 +1300
> From: Tao Liu <ltao(a)redhat.com>
> Subject: [Crash-utility] Re: [PATCH] gdb bt: multiple stacks support
> (x86_64)
> To: Alexey Makhalov <alexey.makhalov(a)broadcom.com>
> Cc: devel(a)lists.crash-utility.osci.io
> Message-ID:
> <CAO7dBbWO84Uhw=i6yFOJT-gbQ=CQ6QTzj-g+tQG9+B4TK-Kw-Q(a)mail.gmail.com>
> Content-Type: text/plain; charset="UTF-8"
>
> Hi Alexey,
>
> Thanks a lot for your improvement! This is a feature which I planned
> to support for the next crash release, and you have provided a good
> start for it.
>
> I have tried your patch over the weekend, and currently I'm working on
> an improvement, and will send it upstream later.
Do you mean you will post an improved patchset based on the current patch to support this
feature on X86 64/aarch64/ppc64 arches? Should we ignore the current patch from Alex(no
need to review this one)?
Please check this out [1]. I think Alexy's and mine are not formal,
but RFC patchsets. There are flaws as I commented in [2], so need to
get improved before the formal patchset. But at least you can give it
a try as a preview...
[1]:
https://github.com/liutgnu/crash-dev/commits/multi-stack-v2/
[2]:
https://www.mail-archive.com/devel@lists.crash-utility.osci.io/msg01209.html
Thanks
Lianbo
>
>
> On Sat, Nov 9, 2024 at 2:12 PM Alexey Makhalov
> <alexey.makhalov(a)broadcom.com> wrote:
> >
> > gdb target analyzes only one task at a time and it backtraces
> > only straight C stack until end of the stack. If stacks were concatenated
> > during exceptions or interrupts, gdb bt will show only the topmost one.
> >
> > Introduce multiple stacks support in gdb target, which can be observed
> > as a different threads from gdb perspective.
> > 'gdb info threads' - to see list of in-kenrel stacks to given task.
> > 'gdb thread <Id>' - to switch.
> > 'gdb bt' - to show it.
>
> I like the idea, this is really nice!
>
> >
> > Implmentation is machine specific. In x86_64, I use cmd_bt() to add
> > additional gdb threads (gdb_add_substack(stack_id) call). Once added,
> > gdb will may call machdep->get_current_task_reg() with corresonding
> > stack_id (sid: new argument).
> > Note: crash 'bt' command must be called for addition threads to appear.
> >
> I guess this is not very user-friendly, I'm trying to improve that.
>
> > No threads/stacks support for arm64 and ppc64, x86_64 only.
> >
> > Example of #GP fault in the kernel caught by SCTP task..
> >
> > crash> bt
> > PID: 94228 TASK: ffff96a6766a8000 CPU: 31 COMMAND: "SCTP"
> > #0 [ffffbb67437e7220] panic at ffffffff99b4f60b
> > #1 [ffffbb67437e72c0] die_addr at ffffffff99033650
> > #2 [ffffbb67437e72f0] exc_general_protection at ffffffff99b9194b
> > #3 [ffffbb67437e7390] asm_exc_general_protection at ffffffff99c00b47
> > [exception RIP: crypto_aead_encrypt+9]
> > RIP: ffffffff995ce269 RSP: ffffbb67437e7440 RFLAGS: 00010246
> > RAX: 0fdd59d2b3d89ecb RBX: 0000000000000000 RCX: 0000000000000c90
> > RDX: ffff96a368508110 RSI: 0000000000000000 RDI: ffff96a348352060
> > RBP: ffffbb67437e7650 R8: 0000000000000001 R9: ffff96a3685080c8
> > R10: ffff96a348351c78 R11: 00000000d5a09e53 R12: 0000000000000008
> > R13: ffff96a348352010 R14: ffff96a348352000 R15: 0000000000000001
> > ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018
> > #4 [ffffbb67437e7440] echainiv_encrypt at ffffffffc0ae82c2 [echainiv]
> > #5 [ffffbb67437e7658] crypto_aead_encrypt at ffffffff995ce27c
> > #6 [ffffbb67437e7668] esp_output_tail at ffffffffc0add3fc [esp4]
> > #7 [ffffbb67437e76f8] esp_output at ffffffffc0addedf [esp4]
> > #8 [ffffbb67437e7760] xfrm_output_resume at ffffffff99a9186a
> > #9 [ffffbb67437e77e0] xfrm_output at ffffffff99a91fba
> > #10 [ffffbb67437e7810] __xfrm4_output at ffffffff99a7b0e6
> > #11 [ffffbb67437e7820] xfrm4_output at ffffffff99a7b172
> > #12 [ffffbb67437e7890] ip_local_out at ffffffff99a000ef
> > #13 [ffffbb67437e78b8] __ip_queue_xmit at ffffffff99a0028e
> > #14 [ffffbb67437e7918] sctp_v4_xmit at ffffffffc0afe0f8 [sctp]
> > #15 [ffffbb67437e79f0] sctp_packet_singleton at ffffffffc0b0bc47 [sctp]
> > #16 [ffffbb67437e7a60] sctp_outq_flush at ffffffffc0b0c636 [sctp]
> > #17 [ffffbb67437e7b08] sctp_outq_uncork at ffffffffc0b0d85c [sctp]
> > #18 [ffffbb67437e7b18] sctp_do_sm at ffffffffc0afbaa6 [sctp]
> > #19 [ffffbb67437e7d08] __sctp_connect at ffffffffc0b17893 [sctp]
> > #20 [ffffbb67437e7d78] __sctp_setsockopt_connectx at ffffffffc0b17a6d [sctp]
> > #21 [ffffbb67437e7da8] sctp_getsockopt at ffffffffc0b1c892 [sctp]
> > #22 [ffffbb67437e7eb8] sock_common_getsockopt at ffffffff9993c6e7
> > #23 [ffffbb67437e7ec8] __sys_getsockopt at ffffffff9993afac
> > #24 [ffffbb67437e7f18] __x64_sys_getsockopt at ffffffff9993b0bf
> > #25 [ffffbb67437e7f28] x64_sys_call at ffffffff99004ca5
> > #26 [ffffbb67437e7f38] do_syscall_64 at ffffffff99b90e34
> > #27 [ffffbb67437e7f50] entry_SYSCALL_64_after_hwframe at ffffffff99c00126
> > RIP: 00007f12c63028ea RSP: 00007f10e41d9b28 RFLAGS: 00000206
> > RAX: ffffffffffffffda RBX: 0000000000000050 RCX: 00007f12c63028ea
> > RDX: 000000000000006f RSI: 0000000000000084 RDI: 0000000000000050
> > RBP: 00007f10a00009b0 R8: 00007f10e41d9b3c R9: 00007f10ac000a5c
> > R10: 00007f10e41d9b40 R11: 0000000000000206 R12: 00007f10e41db120
> > R13: 0000000000000050 R14: 0000000000000010 R15: 000000000289e070
> > ORIG_RAX: 0000000000000037 CS: 0033 SS: 002b
> >
> > crash> gdb bt
> > #0 0xffffffff998eaadf in __inb (port=100) at
./arch/x86/include/asm/shared/io.h:22
> > #1 i8042_read_status () at drivers/input/serio/i8042-acpipnpio.h:54
> > #2 i8042_panic_blink (state=<optimized out>) at
drivers/input/serio/i8042.c:1137
> > #3 0xffffffff99b4f60b in panic (fmt=fmt@entry=0xffffffff9a42c4cb "Fatal
exception") at kernel/panic.c:460
> > #4 0xffffffff99b49b84 in oops_end (flags=<optimized out>,
flags@entry=582, regs=<optimized out>, regs@entry=0xffffbb67437e7398,
signr=<optimized out>) at arch/x86/kernel/dumpstack.c:382
> > #5 0xffffffff99033650 in die_addr (str=str@entry=0xffffbb67437e7304
"general protection fault, probably for non-canonical address
0xfdd59d2b3d89edb", regs=regs@entry=0xffffbb67437e7398, err=err@entry=0,
gp_addr=<optimized out>) at arch/x86/kernel/dumpstack.c:462
> > #6 0xffffffff99b9194b in __exc_general_protection (error_code=0,
regs=0xffffbb67437e7398) at arch/x86/kernel/traps.c:784
> > #7 exc_general_protection (regs=0xffffbb67437e7398, error_code=0) at
arch/x86/kernel/traps.c:729
> > #8 0xffffffff99c00b47 in asm_exc_general_protection () at
./arch/x86/include/asm/idtentry.h:564
> >
> > crash> gdb info threads
> > Id Target Id Frame
> > * 1 94228 SCTP (stack 0) 0xffffffff998eaadf in __inb (port=100) at
./arch/x86/include/asm/shared/io.h:22
> > 2 94228 SCTP (stack 1) crypto_aead_encrypt
(req=req@entry=0xffff96a348352060) at crypto/aead.c:86
>
> The stack(0,1) doesn't make sense for users, I prefer to set marks for
> each threads, as the follows:
>
> crash> info threads
> Detaching from process 18613
> Id Target Id Frame
> * 1 18336 insmod crash_setup_regs (oldregs=<optimized
> out>, newregs=<optimized out>) at ./arch/x86/include/asm/kexec.h:134
> 2 18336 insmod "eframe" 0xffffffffa008300e in ?? ()
>
> So the user will know what kind of stack the thread is...
>
> Anyway, please wait a while and let's work this out together.
>
> Thanks,
> Tao Liu
>
> >
> > crash> gdb thread 2
> > [Switching to thread 2 (94228 SCTP (stack 1))]
> > #0 crypto_aead_encrypt (req=req@entry=0xffff96a348352060) at crypto/aead.c:86
> > 86 crypto/aead.c: No such file or directory.
> >
> > crash> gdb bt
> > #0 crypto_aead_encrypt (req=req@entry=0xffff96a348352060) at crypto/aead.c:86
> > #1 0xffffffffc0ae82c2 in echainiv_encrypt (req=0xffff96a348352010) at
crypto/echainiv.c:82
> > #2 0xffffffff995ce27c in crypto_aead_encrypt (req=0xffff96a348352060) at
crypto/aead.c:94
> > #3 0xffffffffc0add3fc in esp_output_tail ()
> > #4 0xffffffffc0addedf in esp_output ()
> > #5 0xffffffff99a9186a in xfrm_output_one (err=0, skb=0xffff96a3c852b300) at
net/xfrm/xfrm_output.c:553
> > #6 xfrm_output_resume (sk=sk@entry=0xffff96a348368000,
skb=skb@entry=0xffff96a3c852b300, err=<optimized out>, err@entry=1) at
net/xfrm/xfrm_output.c:588
> > #7 0xffffffff99a91fba in xfrm_output2 (skb=0xffff96a3c852b300,
sk=0xffff96a348368000, net=0xffff96a365582580) at net/xfrm/xfrm_output.c:615
> > #8 xfrm_output (sk=0xffff96a348368000, skb=0xffff96a3c852b300) at
net/xfrm/xfrm_output.c:765
> > #9 0xffffffff99a7b0e6 in __xfrm4_output (net=<optimized out>,
sk=<optimized out>, skb=<optimized out>) at net/ipv4/xfrm4_output.c:28
> > #10 0xffffffff99a7b172 in NF_HOOK_COND (pf=2 '\002', hook=4,
okfn=0xffffffff99a7b0c0 <__xfrm4_output>, cond=<optimized out>,
out=0xffff96a496ff2000, in=0x0, skb=0xffff96a3c852b300, sk=0xffff96a348368000,
net=0xffff96a365582580) at ./include/linux/netfilter.h:291
> > #11 xfrm4_output (net=0xffff96a365582580, sk=0xffff96a348368000,
skb=0xffff96a3c852b300) at net/ipv4/xfrm4_output.c:33
> > #12 0xffffffff99a000ef in dst_output (skb=0xffff96a368508110, sk=0x0,
net=0xffff96a348352060) at ./include/net/dst.h:444
> > #13 ip_local_out (net=0xffff96a348352060, sk=0x0, skb=0xffff96a368508110) at
net/ipv4/ip_output.c:126
> > #14 0xffffffff99a0028e in __ip_queue_xmit (sk=sk@entry=0xffff96a348368000,
skb=skb@entry=0xffff96a3c852b300, fl=fl@entry=0xffff96a348351830, tos=tos@entry=186
'\272') at net/ipv4/ip_output.c:532
> > #15 0xffffffffc0afe0f8 in sctp_v4_xmit (skb=0xffff96a3c852b300,
t=0xffff96a348351800) at net/sctp/protocol.c:1071
> > #16 0xffffffffc0b1f553 in sctp_packet_transmit
(packet=packet@entry=0xffffbb67437e79f8, gfp=gfp@entry=3264) at net/sctp/output.c:653
> > #17 0xffffffffc0b0bc47 in sctp_packet_singleton (transport=<optimized
out>, chunk=chunk@entry=0xffff96a34c96f500, gfp=3264) at net/sctp/outqueue.c:783
> > #18 0xffffffffc0b0c636 in sctp_outq_flush_ctrl (ctx=0xffffbb67437e7aa0) at
net/sctp/outqueue.c:914
> > #19 sctp_outq_flush (q=0xffff96a3483585b8, rtx_timeout=rtx_timeout@entry=0,
gfp=<optimized out>) at net/sctp/outqueue.c:1212
> > #20 0xffffffffc0b0d85c in sctp_outq_uncork (q=q@entry=0xffff96a3483585b8,
gfp=gfp@entry=3264) at net/sctp/outqueue.c:764
> > #21 0xffffffffc0afbaa6 in sctp_cmd_interpreter (state=<optimized out>,
status=<optimized out>, gfp=<optimized out>, commands=0xffffbb67437e7b68,
event_arg=<optimized out>, asoc=0xffff96a348358000, ep=<optimized out>,
subtype=..., event_type=<optimized out>) at net/sctp/sm_sideeffect.c:1819
> > #22 sctp_side_effects (gfp=<optimized out>, commands=0xffffbb67437e7b68,
status=<optimized out>, event_arg=<optimized out>, asoc=<synthetic
pointer>, ep=<optimized out>, state=<optimized out>, subtype=...,
event_type=<optimized out>) at net/sctp/sm_sideeffect.c:1199
> > #23 sctp_do_sm (net=<optimized out>,
event_type=event_type@entry=SCTP_EVENT_T_PRIMITIVE, subtype=..., subtype@entry=...,
state=<optimized out>, ep=<optimized out>, asoc=<optimized out>,
event_arg=<optimized out>, gfp=<optimized out>) at
net/sctp/sm_sideeffect.c:1170
> > #24 0xffffffffc0b1e2f0 in sctp_primitive_ASSOCIATE (net=<optimized out>,
asoc=asoc@entry=0xffff96a348358000, arg=arg@entry=0x0) at net/sctp/primitive.c:73
> > #25 0xffffffffc0b17893 in __sctp_connect (sk=sk@entry=0xffff96a348368000,
kaddrs=kaddrs@entry=0xffff96a342085030, addrs_size=addrs_size@entry=16, flags=2050,
assoc_id=assoc_id@entry=0xffffbb67437e7df4) at ./include/net/net_namespace.h:369
> > #26 0xffffffffc0b17a6d in __sctp_setsockopt_connectx
(sk=sk@entry=0xffff96a348368000, kaddrs=kaddrs@entry=0xffff96a342085030, addrs_size=16,
assoc_id=assoc_id@entry=0xffffbb67437e7df4) at net/sctp/socket.c:1334
> > #27 0xffffffffc0b1c892 in sctp_getsockopt_connectx3 (optlen=0x7f10e41d9b3c,
optval=0x7f10e41d9b40 <error: Cannot access memory at address 0x7f10e41d9b40>,
len=16, sk=0xffff96a348368000) at net/sctp/socket.c:1419
> > #28 sctp_getsockopt (sk=0xffff96a348368000, level=<optimized out>,
optname=<optimized out>, optval=0x7f10e41d9b40 <error: Cannot access memory at
address 0x7f10e41d9b40>, optlen=<optimized out>) at net/sctp/socket.c:8124
> > #29 0xffffffff9993c6e7 in sock_common_getsockopt (sock=<optimized out>,
level=0, optname=1750106384, optval=0xc90 <error: Cannot access memory at address
0xc90>, optlen=0x1) at net/core/sock.c:3652
> > #30 0xffffffff9993afac in __sys_getsockopt (fd=<optimized out>,
level=132, optname=111, optval=0x7f10e41d9b40 <error: Cannot access memory at address
0x7f10e41d9b40>, optlen=<optimized out>) at net/socket.c:2327
> > #31 0xffffffff9993b0bf in __do_sys_getsockopt (optlen=<optimized out>,
optval=<optimized out>, optname=<optimized out>, level=<optimized out>,
fd=<optimized out>) at net/socket.c:2342
> > #32 __se_sys_getsockopt (optlen=<optimized out>, optval=<optimized
out>, optname=<optimized out>, level=<optimized out>, fd=<optimized
out>) at net/socket.c:2339
> > #33 __x64_sys_getsockopt (regs=<optimized out>) at net/socket.c:2339
> > #34 0xffffffff99004ca5 in x64_sys_call (regs=regs@entry=0xffffbb67437e7f58,
nr=<optimized out>) at ./arch/x86/include/generated/asm/syscalls_64.h:56
> > #35 0xffffffff99b90e34 in do_syscall_x64 (nr=<optimized out>,
regs=0xffffbb67437e7f58) at arch/x86/entry/common.c:51
> > #36 do_syscall_64 (regs=0xffffbb67437e7f58, nr=<optimized out>) at
arch/x86/entry/common.c:81
> > #37 0xffffffff99c00126 in entry_SYSCALL_64 () at arch/x86/entry/entry_64.S:121
> >
> > Now we can use GDB to see the root cause.
> >
> > Signed-off-by: Alexey Makhalov <alexey.makhalov(a)broadcom.com>
> > ---
> > arm64.c | 2 +-
> > crash_target.c | 25 ++++++++++++++++++----
> > defs.h | 3 ++-
> > gdb_interface.c | 6 +++---
> > ppc64.c | 2 +-
> > x86_64.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++--
> > 6 files changed, 81 insertions(+), 12 deletions(-)
> >
> > diff --git a/arm64.c b/arm64.c
> > index 608b19d..62f91d8 100644
> > --- a/arm64.c
> > +++ b/arm64.c
> > @@ -204,7 +204,7 @@ out:
> >
> > static int
> > arm64_get_current_task_reg(int regno, const char *name,
> > - int size, void *value)
> > + int size, void *value, int unused)
> > {
> > struct bt_info bt_info, bt_setup;
> > struct task_context *tc;
> > diff --git a/crash_target.c b/crash_target.c
> > index 1080976..8b17ef8 100644
> > --- a/crash_target.c
> > +++ b/crash_target.c
> > @@ -27,8 +27,9 @@ void crash_target_init (void);
> >
> > extern "C" int gdb_readmem_callback(unsigned long, void *, int,
int);
> > extern "C" int crash_get_current_task_reg (int regno, const char
*regname,
> > - int regsize, void *val);
> > + int regsize, void *val, int sid);
> > extern "C" int gdb_change_thread_context (void);
> > +extern "C" int gdb_add_substack (int sid);
> > extern "C" void crash_get_current_task_info(unsigned long *pid, char
**comm);
> >
> > /* The crash target. */
> > @@ -64,9 +65,10 @@ public:
> > unsigned long pid;
> > char *comm;
> > crash_get_current_task_info(&pid, &comm);
> > - return string_printf ("%ld %s", pid, comm);
> > + if (thread_count(this) == 1)
> > + return string_printf ("%ld %s", pid, comm);
> > + return string_printf ("%ld %s (stack %ld)", pid, comm,
ptid.tid());
> > }
> > -
> > };
> >
> > static void supply_registers(struct regcache *regcache, int regno)
> > @@ -79,7 +81,7 @@ static void supply_registers(struct regcache *regcache, int
regno)
> > if (regsize > sizeof (regval))
> > error (_("fatal error: buffer size is not enough to fit register
value"));
> >
> > - if (crash_get_current_task_reg (regno, regname, regsize, (void
*)®val))
> > + if (crash_get_current_task_reg (regno, regname, regsize, (void *)®val,
inferior_thread()->ptid.tid()))
> > regcache->raw_supply (regno, regval);
> > else
> > regcache->raw_supply (regno, NULL);
> > @@ -144,7 +146,22 @@ crash_target_init (void)
> > extern "C" int
> > gdb_change_thread_context (void)
> > {
> > + for (thread_info *tp : current_inferior()->threads_safe())
> > + if (tp->ptid.tid_p())
> > + delete_thread (tp);
> > target_fetch_registers(get_current_regcache(), -1);
> > reinit_frame_cache();
> > return TRUE;
> > }
> > +
> > +/* Add a thread for each additional stack. Use stack ID as a thread ID */
> > +extern "C" int
> > +gdb_add_substack (int sid)
> > +{
> > + ptid_t ptid = ptid_t(CRASH_INFERIOR_PID, 0, sid);
> > +
> > + thread_info *tp = find_thread_ptid (current_inferior(), ptid);
> > + if (tp == nullptr)
> > + add_thread_silent (current_inferior()->process_target(), ptid);
> > + return TRUE;
> > +}
> > diff --git a/defs.h b/defs.h
> > index b93a7a6..bb2bc20 100644
> > --- a/defs.h
> > +++ b/defs.h
> > @@ -1081,7 +1081,7 @@ struct machdep_table {
> > void (*get_irq_affinity)(int);
> > void (*show_interrupts)(int, ulong *);
> > int (*is_page_ptr)(ulong, physaddr_t *);
> > - int (*get_current_task_reg)(int, const char *, int, void *);
> > + int (*get_current_task_reg)(int, const char *, int, void *, int);
> > int (*is_cpu_prstatus_valid)(int cpu);
> > };
> >
> > @@ -8301,5 +8301,6 @@ enum ppc64_regnum {
> >
> > /* crash_target.c */
> > extern int gdb_change_thread_context (void);
> > +extern int gdb_add_substack (int sid);
> >
> > #endif /* !GDB_COMMON */
> > diff --git a/gdb_interface.c b/gdb_interface.c
> > index 315711e..c138c94 100644
> > --- a/gdb_interface.c
> > +++ b/gdb_interface.c
> > @@ -1074,12 +1074,12 @@ unsigned long crash_get_kaslr_offset(void)
> >
> > /* Callbacks for crash_target */
> > int crash_get_current_task_reg (int regno, const char *regname,
> > - int regsize, void *value);
> > + int regsize, void *value, int sid);
> > int crash_get_current_task_reg (int regno, const char *regname,
> > - int regsize, void *value)
> > + int regsize, void *value, int sid)
> > {
> > if (!machdep->get_current_task_reg)
> > return FALSE;
> > - return machdep->get_current_task_reg(regno, regname, regsize,
value);
> > + return machdep->get_current_task_reg(regno, regname, regsize, value,
sid);
> > }
> >
> > diff --git a/ppc64.c b/ppc64.c
> > index 782107b..1cf06e3 100644
> > --- a/ppc64.c
> > +++ b/ppc64.c
> > @@ -2512,7 +2512,7 @@ ppc64_print_eframe(char *efrm_str, struct ppc64_pt_regs
*regs,
> >
> > static int
> > ppc64_get_current_task_reg(int regno, const char *name, int size,
> > - void *value)
> > + void *value, int unused)
> > {
> > struct bt_info bt_info, bt_setup;
> > struct task_context *tc;
> > diff --git a/x86_64.c b/x86_64.c
> > index e7f8fe2..2e7cde4 100644
> > --- a/x86_64.c
> > +++ b/x86_64.c
> > @@ -126,7 +126,7 @@ static int x86_64_get_framesize(struct bt_info *, ulong,
ulong, char *);
> > static void x86_64_framesize_debug(struct bt_info *);
> > static void x86_64_get_active_set(void);
> > static int x86_64_get_kvaddr_ranges(struct vaddr_range *);
> > -static int x86_64_get_current_task_reg(int, const char *, int, void *);
> > +static int x86_64_get_current_task_reg(int, const char *, int, void *, int);
> > static int x86_64_verify_paddr(uint64_t);
> > static void GART_init(void);
> > static void x86_64_exception_stacks_init(void);
> > @@ -143,6 +143,14 @@ struct machine_specific x86_64_machine_specific = { 0 };
> > static const char *exception_functions_orig[];
> > static const char *exception_functions_5_8[];
> >
> > +/*
> > + * Additional stacks entry registers for gdb target.
> > + * See 'gdb info threads'
> > + */
> > +#define MAX_STACKS_NUM 5
> > +ulong stack_idx;
> > +ulong stacks_regs[MAX_STACKS_NUM][SS_REGNUM + 1];
> > +
> > /* Use this hardwired version -- sometimes the
> > * debuginfo doesn't pick this up even though
> > * it exists in the kernel; it shouldn't change.
> > @@ -3551,6 +3559,7 @@ x86_64_low_budget_back_trace_cmd(struct bt_info *bt_in)
> > irq_eframe = 0;
> > last_process_stack_eframe = 0;
> > bt->call_target = NULL;
> > + stack_idx = 0;
> > rsp = bt->stkptr;
> > ms = machdep->machspec;
> >
> > @@ -4159,6 +4168,7 @@ x86_64_dwarf_back_trace_cmd(struct bt_info *bt_in)
> > last_process_stack_eframe = 0;
> > bt->call_target = NULL;
> > bt->bptr = 0;
> > + stack_idx = 0;
> > rsp = bt->stkptr;
> > if (!rsp) {
> > error(INFO, "cannot determine starting stack
pointer\n");
> > @@ -4799,6 +4809,36 @@ x86_64_exception_frame(ulong flags, ulong kvaddr, char
*local,
> > } else if (machdep->flags & ORC)
> > bt->bptr = rbp;
> >
> > +
> > + /*
> > + * Preserve registers set for each additional in-kernel stack
> > + * up to MAX_STACKS_NUM.
> > + */
> > + if (!(cs & 3) && verified && stack_idx <
MAX_STACKS_NUM) {
> > + stacks_regs[stack_idx][RAX_REGNUM] = rax;
> > + stacks_regs[stack_idx][RBX_REGNUM] = rbx;
> > + stacks_regs[stack_idx][RCX_REGNUM] = rcx;
> > + stacks_regs[stack_idx][RDX_REGNUM] = rdx;
> > + stacks_regs[stack_idx][RSI_REGNUM] = rsi;
> > + stacks_regs[stack_idx][RDI_REGNUM] = rdi;
> > + stacks_regs[stack_idx][RBP_REGNUM] = rbp;
> > + stacks_regs[stack_idx][RSP_REGNUM] = rsp;
> > + stacks_regs[stack_idx][R8_REGNUM] = r8;
> > + stacks_regs[stack_idx][R9_REGNUM] = r9;
> > + stacks_regs[stack_idx][R10_REGNUM] = r10;
> > + stacks_regs[stack_idx][R11_REGNUM] = r11;
> > + stacks_regs[stack_idx][R12_REGNUM] = r12;
> > + stacks_regs[stack_idx][R13_REGNUM] = r13;
> > + stacks_regs[stack_idx][R14_REGNUM] = r14;
> > + stacks_regs[stack_idx][R15_REGNUM] = r15;
> > + stacks_regs[stack_idx][RIP_REGNUM] = rip;
> > + stacks_regs[stack_idx][EFLAGS_REGNUM] = rflags;
> > + stacks_regs[stack_idx][CS_REGNUM] = cs;
> > + stacks_regs[stack_idx][SS_REGNUM] = ss;
> > + /* Skip stack 0 (main stack), start with index 1 */
> > + gdb_add_substack (stack_idx + 1);
> > + stack_idx++;
> > + }
> > if (kvaddr)
> > FREEBUF(pt_regs_buf);
> >
> > @@ -9236,7 +9276,7 @@ x86_64_get_kvaddr_ranges(struct vaddr_range *vrp)
> >
> > static int
> > x86_64_get_current_task_reg(int regno, const char *name,
> > - int size, void *value)
> > + int size, void *value, int sid)
> > {
> > struct bt_info bt_info, bt_setup;
> > struct task_context *tc;
> > @@ -9256,6 +9296,17 @@ x86_64_get_current_task_reg(int regno, const char *name,
> > if (!tc)
> > return FALSE;
> >
> > + /* Non zero stack ID, use saved regs */
> > + if (sid && sid <= MAX_STACKS_NUM) {
> > + switch (regno) {
> > + case RAX_REGNUM ... SS_REGNUM:
> > + memcpy(value, &stacks_regs[sid - 1][regno], size
> 8 ? 8 : size);
> > + return TRUE;
> > + default:
> > + return FALSE;
> > + }
> > + }
> > +
> > /*
> > * Task is active, grab CPU's registers
> > */
> > --
> > 2.43.5