Hi Lianbo

Ive reviewed and tested the patch on my setup, but I wasnt able to reproduce the issue on my side. All relevant tests and scenarios passed as expected.

Since you mentioned that the problem occurs in your environment, it might be related to differences in configuration, kernel version, or other environment-specific factors. Could you share more details about your setup (kernel version, config, workloads, etc.) so we can investigate further?

Also, could you send me your crash dump and the corresponding vmlinux? I can try debugging it on my side to see what might be causing the issue.

Im happy to help dig deeper once we have the environment specifics.

Thanks

Li Pengfei

 

发件人: lijiang <lijiang@redhat.com>
发送时间: 202624 17:09
收件人: devel@lists.crash-utility.osci.io
抄送: 李鹏飞 <lipengfei28@xiaomi.com>
主题: [External Mail]Re: [PATCH] arm64: Fix broken/incomplete gdb backtrace and unify output format

 

[外部邮件] 此邮件来源于小米公司外部,请谨慎处理。若对邮件安全性存疑,请将邮件转发给misec@xiaomi.com进行反馈

Hi, Pengfei

 

I did the test with your patch, and got an incorrect back trace, Can you also help double check?

 

crash> gdb bt
#0    0xffffc8c40b0d9b14 in crash_setup_regs (newregs=newregs@entry=0xffff80008862b638, oldregs=oldregs@entry=0x0) at ./arch/arm64/include/asm/kexec.h:45
#1    0xffffc8c40b0d9dc4 in __crash_kexec (regs=regs@entry=0x0) at kernel/crash_core.c:119
#2    0xffffc8c40aed6a44 in vpanic (fmt=fmt@entry=0xffffc8c40c527558 "sysrq triggered crash\n", args=<error reading variable: Cannot access memory at address 0x0>) at kernel/panic.c:369
#3    0xffffc8c40aed6cd0 in panic (fmt=fmt@entry=0xffffc8c40c527558 "sysrq triggered crash\n") at kernel/panic.c:484
#4    0xffffc8c40b82a594 in sysrq_handle_crash (key=<optimized out>) at drivers/tty/sysrq.c:154
#5    0xffffc8c40b82aee0 in __handle_sysrq (key=99 'c', check_mask=false) at drivers/tty/sysrq.c:613
#6    0xffffc8c40b82b6b0 in write_sysrq_trigger (file=<optimized out>, buf=<optimized out>, count=2, ppos=<optimized out>) at drivers/tty/sysrq.c:1183
#7    0xffffc8c40b46bcec in pde_write (pde=0xffff0000c7fa6a80, file=<optimized out>, buf=<optimized out>, count=<optimized out>, ppos=<optimized out>) at fs/proc/inode.c:330
#8                          proc_reg_write (file=<optimized out>, buf=<optimized out>, count=<optimized out>, ppos=<optimized out>) at fs/proc/inode.c:342
#9    0xffffc8c40b3ad52c in vfs_write (file=file@entry=0xffff0000c86aff00, buf=buf@entry=0xaaab1a0c37f0 <error: Cannot access memory at address 0xaaab1a0c37f0>, count=count@entry=2, pos=pos@entry=0xffff80008862ba20) at fs/read_write.c:681
#10  0xffffc8c40b3ad9a4 in ksys_write (fd=<optimized out>, buf=0xaaab1a0c37f0 <error: Cannot access memory at address 0xaaab1a0c37f0>, count=2) at fs/read_write.c:736
#11  0xffffc8c40b3ada6c in __do_sys_write (fd=<optimized out>, buf=<optimized out>, count=<optimized out>) at fs/read_write.c:748
#12                        __se_sys_write (fd=<optimized out>, buf=<optimized out>, count=<optimized out>) at fs/read_write.c:745
#13                        __arm64_sys_write (regs=<optimized out>) at fs/read_write.c:745
#14  0xffffc8c40af0cc7c in __invoke_syscall (regs=0xffff80008862beb0, syscall_fn=<optimized out>) at arch/arm64/kernel/syscall.c:35
#15                        invoke_syscall (regs=regs@entry=0xffff80008862beb0, scno=<optimized out>, sc_nr=sc_nr@entry=463, syscall_table=<optimized out>) at arch/arm64/kernel/syscall.c:49
#16  0xffffc8c40af0cd88 in el0_svc_common (sc_nr=463, syscall_table=<optimized out>, regs=0xffff80008862beb0, scno=<optimized out>) at arch/arm64/kernel/syscall.c:132
#17                        do_el0_svc (regs=regs@entry=0xffff80008862beb0) at arch/arm64/kernel/syscall.c:151
#18  0xffffc8c40beb9e2c in el0_svc (regs=0xffff80008862beb0) at arch/arm64/kernel/entry-common.c:879
#19  0xffffc8c40beba2b0 in el0t_64_sync_handler (regs=<optimized out>) at arch/arm64/kernel/entry-common.c:898
#20  0xffffc8c40aed1684 in el0t_64_sync () at arch/arm64/kernel/entry.S:596
#21                         machine_kexec (kimage=<unavailable>) at arch/arm64/kernel/machine_kexec.c:194
#22   0xffffc8c40b0d9dd8 in __crash_kexec (regs=regs@entry=0x0) at kernel/crash_core.c:122
#23   0xffffc8c40aed6a44 in vpanic (fmt=fmt@entry=0xffffc8c40c527558 "sysrq triggered crash\n", args=<error reading variable: Cannot access memory at address 0x0>) at kernel/panic.c:369
#24   0xffffc8c40aed6cd0 in panic (fmt=fmt@entry=0xffffc8c40c527558 "sysrq triggered crash\n") at kernel/panic.c:484
#25   0xffffc8c40b82a594 in sysrq_handle_crash (key=<optimized out>) at drivers/tty/sysrq.c:154
#26   0xffffc8c40b82aee0 in __handle_sysrq (key=99 'c', check_mask=<unavailable>) at drivers/tty/sysrq.c:613
#27   0xffffc8c40b82b6b0 in write_sysrq_trigger (file=<optimized out>, buf=<optimized out>, count=2, ppos=<optimized out>) at drivers/tty/sysrq.c:1183
#28   0xffffc8c40b46bcec in pde_write (pde=0xffff0000c7fa6a80, file=<optimized out>, buf=<optimized out>, count=<optimized out>, ppos=<optimized out>) at fs/proc/inode.c:330
#29                         proc_reg_write (file=<optimized out>, buf=<optimized out>, count=<optimized out>, ppos=<optimized out>) at fs/proc/inode.c:342
#30   0xffffc8c40b3ad52c in vfs_write (file=file@entry=0xffff0000c86aff00, buf=buf@entry=0xaaab1a0c37f0 <error: Cannot access memory at address 0xaaab1a0c37f0>, count=count@entry=2, pos=pos@entry=0xffff80008862ba20) at fs/read_write.c:681
#31  0xffffc8c40b3ad9a4 in ksys_write (fd=<optimized out>, buf=0xaaab1a0c37f0 <error: Cannot access memory at address 0xaaab1a0c37f0>, count=2) at fs/read_write.c:736
#32  0xffffc8c40b3ada6c in __do_sys_write (fd=<optimized out>, buf=<optimized out>, count=<optimized out>) at fs/read_write.c:748
#33                        __se_sys_write (fd=<optimized out>, buf=<optimized out>, count=<optimized out>) at fs/read_write.c:745
#34                        __arm64_sys_write (regs=<optimized out>) at fs/read_write.c:745
#35  0xffffc8c40af0cc7c in __invoke_syscall (regs=0xffff80008862beb0, syscall_fn=<optimized out>) at arch/arm64/kernel/syscall.c:35
#36                        invoke_syscall (regs=regs@entry=0xffff80008862beb0, scno=<optimized out>, sc_nr=sc_nr@entry=463, syscall_table=<optimized out>) at arch/arm64/kernel/syscall.c:49
#37  0xffffc8c40af0cd88 in el0_svc_common (sc_nr=463, syscall_table=<optimized out>, regs=0xffff80008862beb0, scno=<optimized out>) at arch/arm64/kernel/syscall.c:132
#38                        do_el0_svc (regs=regs@entry=0xffff80008862beb0) at arch/arm64/kernel/syscall.c:151
#39  0xffffc8c40beb9e2c in el0_svc (regs=0xffff80008862beb0) at arch/arm64/kernel/entry-common.c:879
#40  0xffffc8c40beba2b0 in el0t_64_sync_handler (regs=<optimized out>) at arch/arm64/kernel/entry-common.c:898
#41  0xffffc8c40aed1684 in el0t_64_sync () at arch/arm64/kernel/entry.S:596

 

 

I can get the correct back trace without the patch:

crash> gdb bt
#0  0xffffc8c40b0d9b14 in crash_setup_regs (newregs=newregs@entry=0xffff80008862b638, oldregs=oldregs@entry=0x0) at ./arch/arm64/include/asm/kexec.h:45
#1  0xffffc8c40b0d9dc4 in __crash_kexec (regs=regs@entry=0x0) at kernel/crash_core.c:119
#2  0xffffc8c40aed6a44 in vpanic (fmt=fmt@entry=0xffffc8c40c527558 "sysrq triggered crash\n", args=<error reading variable: Cannot access memory at address 0x0>) at kernel/panic.c:369
#3  0xffffc8c40aed6cd0 in panic (fmt=fmt@entry=0xffffc8c40c527558 "sysrq triggered crash\n") at kernel/panic.c:484
#4  0xffffc8c40b82a594 in sysrq_handle_crash (key=<optimized out>) at drivers/tty/sysrq.c:154
#5  0xffffc8c40b82aee0 in __handle_sysrq (key=99 'c', check_mask=false) at drivers/tty/sysrq.c:613
#6  0xffffc8c40b82b6b0 in write_sysrq_trigger (file=<optimized out>, buf=<optimized out>, count=2, ppos=<optimized out>) at drivers/tty/sysrq.c:1183
#7  0xffffc8c40b46bcec in pde_write (pde=0xffff0000c7fa6a80, file=<optimized out>, buf=<optimized out>, count=<optimized out>, ppos=<optimized out>) at fs/proc/inode.c:330
#8  proc_reg_write (file=<optimized out>, buf=<optimized out>, count=<optimized out>, ppos=<optimized out>) at fs/proc/inode.c:342
#9  0xffffc8c40b3ad52c in vfs_write (file=file@entry=0xffff0000c86aff00, buf=buf@entry=0xaaab1a0c37f0 <error: Cannot access memory at address 0xaaab1a0c37f0>, count=count@entry=2, pos=pos@entry=0xffff80008862ba20) at fs/read_write.c:681
#10 0xffffc8c40b3ad9a4 in ksys_write (fd=<optimized out>, buf=0xaaab1a0c37f0 <error: Cannot access memory at address 0xaaab1a0c37f0>, count=2) at fs/read_write.c:736
#11 0xffffc8c40b3ada6c in __do_sys_write (fd=<optimized out>, buf=<optimized out>, count=<optimized out>) at fs/read_write.c:748
#12 __se_sys_write (fd=<optimized out>, buf=<optimized out>, count=<optimized out>) at fs/read_write.c:745
#13 __arm64_sys_write (regs=<optimized out>) at fs/read_write.c:745
#14 0xffffc8c40af0cc7c in __invoke_syscall (regs=0xffff80008862beb0, syscall_fn=<optimized out>) at arch/arm64/kernel/syscall.c:35
#15 invoke_syscall (regs=regs@entry=0xffff80008862beb0, scno=<optimized out>, sc_nr=sc_nr@entry=463, syscall_table=<optimized out>) at arch/arm64/kernel/syscall.c:49
#16 0xffffc8c40af0cd88 in el0_svc_common (sc_nr=463, syscall_table=<optimized out>, regs=0xffff80008862beb0, scno=<optimized out>) at arch/arm64/kernel/syscall.c:132
#17 do_el0_svc (regs=regs@entry=0xffff80008862beb0) at arch/arm64/kernel/syscall.c:151
#18 0xffffc8c40beb9e2c in el0_svc (regs=0xffff80008862beb0) at arch/arm64/kernel/entry-common.c:879
#19 0xffffc8c40beba2b0 in el0t_64_sync_handler (regs=<optimized out>) at arch/arm64/kernel/entry-common.c:898
#20 0xffffc8c40aed1684 in el0t_64_sync () at arch/arm64/kernel/entry.S:596

 

Anyway, I haven't checked the patch carefully, just tried to test it and found this error.

 

In addition, I would suggest splitting this patch into smaller patches, and each patch should only do one thing(keep its functionality independent), which will help us to review it easily.

 

Thanks

Lianbo

 

On Fri, Jan 30, 2026 at 5:21PM <devel-request@lists.crash-utility.osci.io> wrote:

Date: Mon, 26 Jan 2026 11:43:42 -0000
From: lipengfei28@xiaomi.com
Subject: [Crash-utility] [PATCH] arm64: Fix broken/incomplete gdb
        backtrace and unify output format
To: devel@lists.crash-utility.osci.io
Message-ID: <20260126114342.13119.56270@lists.crash-utility.osci.io>
Content-Type: text/plain; charset="utf-8"

>From 4d832a33ebd80bd109cc5a47f98c6b35fdcbd956 Mon Sep 17 00:00:00 2001
From: lipengfei28 <lipengfei28@xiaomi.com>
Date: Fri, 23 Jan 2026 16:24:07 +0800
Subject: [PATCH]  arm64: Fix broken/incomplete gdb backtrace and unify output
 format

 This patch fixes multiple issues with 'gdb bt' on ARM64, where the backtrace
 would be interrupted, contain garbage threads, or display fragmented output.

 1. Fix Out-of-Bounds Read in Exception Frame Handling:
    In `arm64_print_exception_frame`, the code previously used `memcpy` to copy
    `sizeof(struct arm64_pt_regs)` bytes from a `struct arm64_stackframe *` source.
    Since `stackframe` is significantly smaller than `pt_regs`, this caused an
    out-of-bounds read, populating the GDB thread registers with stack garbage
    (often resulting in invalid addresses like -3/0xff...fd).
    This is fixed by manually copying only the valid registers (PC, SP, FP, etc.)
    and properly initializing the bitmap.

 2. Bridge the Gap Between IRQ and Process Stacks:
    Previously, GDB unwinding would stop at `call_on_irq_stack` because it could
    not automatically unwind through the assembly trampoline back to the process
    stack.
    Modified `arm64_switch_stack` (and the overflow variant) to "peek" one frame
    ahead (reading the saved FP/PC of the caller) before registering the new
    GDB substack. This effectively bridges the discontinuity, allowing GDB to
    show frames like `do_interrupt_handler` that were previously missing.

 3. Unify and Format GDB Output:
    Modified `gdb_interface.c` to:
    - Strip "Thread <id>" headers to present a continuous backtrace similar to
      the native `crash bt`.
    - Renumber stack frames sequentially (e.g., #0 to #30) instead of resetting
      at each stack switch.
    - Add indentation/alignment for frames where GDB omits the address (e.g.,
      inline functions) to improve readability.

 4. Prevent Invalid Thread Creation:
    Added checks to ensure a GDB substack is only created if the Program Counter
    (PC) is non-zero, preventing the display of "corrupt" or empty threads.

    Tested on: Android 6.x ARM64

Signed-off-by: lipengfei28 <lipengfei28@xiaomi.com>
---
 arm64.c         | 117 +++++++++++++++++++++++++++++++++++++------
 gdb_interface.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 229 insertions(+), 18 deletions(-)

diff --git a/arm64.c b/arm64.c
index c125655..f842739 100644
--- a/arm64.c
+++ b/arm64.c
@@ -3026,6 +3026,9 @@ static char *arm64_exception_functions[] = {
         "do_el0_irq_bp_hardening",
         "do_sp_pc_abort",
         "handle_bad_stack",
+        "el1h_64_sync",
+        "el1h_64_irq",
+        "el1h_64_error",
         NULL
 };

@@ -3123,6 +3126,11 @@ arm64_print_stackframe_entry(struct bt_info *bt, int level, struct arm64_stackfr

        fprintf(ofp, "\n");

+       if (STREQ(name, "el1h_64_irq") || STREQ(name, "el1h_64_sync"))
+               if (arm64_is_kernel_exception_frame(bt, frame->sp)) {
+                       arm64_print_exception_frame(bt, frame->sp, KERNEL_MODE, ofp);
+               }
+
        if (bt->flags & BT_LINE_NUMBERS) {
                get_line_number(branch_pc, buf, FALSE);
                if (strlen(buf))
@@ -3775,11 +3783,12 @@ arm64_back_trace_cmd(struct bt_info *bt)
                        REG_SEQ(arm64_pt_regs, pc));
                SET_BIT(extra_stacks_regs[extra_stacks_idx]->bitmap,
                        REG_SEQ(arm64_pt_regs, sp));
-               if (!bt->machdep ||
+               if (extra_stacks_regs[extra_stacks_idx]->ur.pc &&
+                   (!bt->machdep ||
                     (extra_stacks_regs[extra_stacks_idx]->ur.sp !=
                      ((struct user_regs_bitmap_struct *)(bt->machdep))->ur.sp &&
                      extra_stacks_regs[extra_stacks_idx]->ur.pc !=
-                     ((struct user_regs_bitmap_struct *)(bt->machdep))->ur.pc)) {
+                     ((struct user_regs_bitmap_struct *)(bt->machdep))->ur.pc))) {
                        gdb_add_substack (extra_stacks_idx++);
                }
        }
@@ -3925,11 +3934,12 @@ arm64_back_trace_cmd_v2(struct bt_info *bt)
                        REG_SEQ(arm64_pt_regs, pc));
                SET_BIT(extra_stacks_regs[extra_stacks_idx]->bitmap,
                        REG_SEQ(arm64_pt_regs, sp));
-               if (!bt->machdep ||
+               if (extra_stacks_regs[extra_stacks_idx]->ur.pc &&
+                   (!bt->machdep ||
                     (extra_stacks_regs[extra_stacks_idx]->ur.sp !=
                      ((struct user_regs_bitmap_struct *)(bt->machdep))->ur.sp &&
                      extra_stacks_regs[extra_stacks_idx]->ur.pc !=
-                     ((struct user_regs_bitmap_struct *)(bt->machdep))->ur.pc)) {
+                     ((struct user_regs_bitmap_struct *)(bt->machdep))->ur.pc))) {
                        gdb_add_substack (extra_stacks_idx++);
                }               
        }
@@ -4263,8 +4273,40 @@ arm64_switch_stack(struct bt_info *bt, struct arm64_stackframe *frame, FILE *ofp
        if (frame->fp == 0)
                return USER_MODE;

-       if (!(machdep->flags & UNW_4_14))
+       if (!(machdep->flags & UNW_4_14)) {
                arm64_print_exception_frame(bt, frame->sp, KERNEL_MODE, ofp);
+       } else {
+               if (!extra_stacks_regs[extra_stacks_idx]) {
+                       extra_stacks_regs[extra_stacks_idx] = (struct user_regs_bitmap_struct *)
+                               malloc(sizeof(struct user_regs_bitmap_struct));
+               }
+               memset(extra_stacks_regs[extra_stacks_idx], 0, sizeof(struct user_regs_bitmap_struct));
+               struct user_regs_bitmap_struct *ur_ptr = extra_stacks_regs[extra_stacks_idx];
+
+               ulong next_fp = GET_STACK_ULONG(frame->fp);
+               ulong next_pc = GET_STACK_ULONG(frame->fp + 8);
+               ulong next_sp = frame->fp + 16;
+
+               if (is_kernel_text(next_pc | ms->CONFIG_ARM64_KERNELPACMASK))
+                       next_pc |= ms->CONFIG_ARM64_KERNELPACMASK;
+
+               ur_ptr->ur.pc = next_pc;
+               ur_ptr->ur.sp = next_sp;
+               ur_ptr->ur.regs[29] = next_fp;
+
+               SET_BIT(ur_ptr->bitmap, REG_SEQ(arm64_pt_regs, pc));
+               SET_BIT(ur_ptr->bitmap, REG_SEQ(arm64_pt_regs, sp));
+               SET_BIT(ur_ptr->bitmap, REG_SEQ(arm64_pt_regs, regs[0]) + 29);
+
+               if (ur_ptr->ur.pc &&
+                   (!bt->machdep ||
+                    (ur_ptr->ur.sp !=
+                     ((struct user_regs_bitmap_struct *)(bt->machdep))->ur.sp &&
+                     ur_ptr->ur.pc !=
+                     ((struct user_regs_bitmap_struct *)(bt->machdep))->ur.pc))) {
+                       gdb_add_substack (extra_stacks_idx++);
+               }
+       }

        return KERNEL_MODE;
 }
@@ -4300,8 +4342,40 @@ arm64_switch_stack_from_overflow(struct bt_info *bt, struct arm64_stackframe *fr
        if (frame->fp == 0)
                return USER_MODE;

-       if (!(machdep->flags & UNW_4_14))
+       if (!(machdep->flags & UNW_4_14)) {
                arm64_print_exception_frame(bt, frame->sp, KERNEL_MODE, ofp);
+       } else {
+               if (!extra_stacks_regs[extra_stacks_idx]) {
+                       extra_stacks_regs[extra_stacks_idx] = (struct user_regs_bitmap_struct *)
+                               malloc(sizeof(struct user_regs_bitmap_struct));
+               }
+               memset(extra_stacks_regs[extra_stacks_idx], 0, sizeof(struct user_regs_bitmap_struct));
+               struct user_regs_bitmap_struct *ur_ptr = extra_stacks_regs[extra_stacks_idx];
+
+               ulong next_fp = GET_STACK_ULONG(frame->fp);
+               ulong next_pc = GET_STACK_ULONG(frame->fp + 8);
+               ulong next_sp = frame->fp + 16;
+
+               if (is_kernel_text(next_pc | ms->CONFIG_ARM64_KERNELPACMASK))
+                       next_pc |= ms->CONFIG_ARM64_KERNELPACMASK;
+
+               ur_ptr->ur.pc = next_pc;
+               ur_ptr->ur.sp = next_sp;
+               ur_ptr->ur.regs[29] = next_fp;
+
+               SET_BIT(ur_ptr->bitmap, REG_SEQ(arm64_pt_regs, pc));
+               SET_BIT(ur_ptr->bitmap, REG_SEQ(arm64_pt_regs, sp));
+               SET_BIT(ur_ptr->bitmap, REG_SEQ(arm64_pt_regs, regs[0]) + 29);
+
+               if (ur_ptr->ur.pc &&
+                   (!bt->machdep ||
+                    (ur_ptr->ur.sp !=
+                     ((struct user_regs_bitmap_struct *)(bt->machdep))->ur.sp &&
+                     ur_ptr->ur.pc !=
+                     ((struct user_regs_bitmap_struct *)(bt->machdep))->ur.pc))) {
+                       gdb_add_substack (extra_stacks_idx++);
+               }
+       }

        return KERNEL_MODE;
 }
@@ -4556,16 +4630,27 @@ arm64_print_exception_frame(struct bt_info *bt, ulong pt_regs, int mode, FILE *o
                        }
                        memset(extra_stacks_regs[extra_stacks_idx], 0,
                                sizeof(struct user_regs_bitmap_struct));
-                       memcpy(&extra_stacks_regs[extra_stacks_idx]->ur, regs,
-                               sizeof(struct arm64_pt_regs));
-                       for (int i = 0; i < sizeof(struct arm64_pt_regs)/sizeof(long); i++)
-                               SET_BIT(extra_stacks_regs[extra_stacks_idx]->bitmap, i);
-                       if (!bt->machdep ||
-                            (extra_stacks_regs[extra_stacks_idx]->ur.sp !=
-                             ((struct user_regs_bitmap_struct *)(bt->machdep))->ur.sp &&
-                             extra_stacks_regs[extra_stacks_idx]->ur.pc !=
-                             ((struct user_regs_bitmap_struct *)(bt->machdep))->ur.pc)) {
-                               gdb_add_substack (extra_stacks_idx++);
+                       {
+                               struct user_regs_bitmap_struct *ur_ptr = extra_stacks_regs[extra_stacks_idx];
+                               int i;
+
+                               ur_ptr->ur.pc = regs->pc;
+                               ur_ptr->ur.sp = regs->sp;
+                               ur_ptr->ur.pstate = regs->pstate;
+                               for (i = 0; i < 31; i++)
+                                       ur_ptr->ur.regs[i] = regs->regs[i];
+
+                               for (i = 0; i < 34; i++)
+                                       SET_BIT(ur_ptr->bitmap, i);
+
+                               if (ur_ptr->ur.pc &&
+                                   (!bt->machdep ||
+                                    (ur_ptr->ur.sp !=
+                                     ((struct user_regs_bitmap_struct *)(bt->machdep))->ur.sp &&
+                                     ur_ptr->ur.pc !=
+                                     ((struct user_regs_bitmap_struct *)(bt->machdep))->ur.pc))) {
+                                       gdb_add_substack (extra_stacks_idx++);
+                               }
                        }                       
                }
        }
diff --git a/gdb_interface.c b/gdb_interface.c
index 9f76f85..d14144e 100644
--- a/gdb_interface.c
+++ b/gdb_interface.c
@@ -16,6 +16,7 @@
  */

 #include "defs.h"
+#include <ctype.h>

 #if !defined(GDB_10_2) && !defined(GDB_16_2)
 static void exit_after_gdb_info(void);
@@ -779,22 +780,53 @@ strip_redirection(char *buf)
 /*
  *  Command for passing strings directly to gdb.
  */
+static void format_and_print_gdb_bt(FILE *input_fp);
+
 void
 cmd_gdb(void)
 {
        char buf[BUFSIZE];
         char **argv;
+       int i;

        argv = STREQ(args[0], "gdb") ? &args[1] : &args[0];

         if (*argv == NULL)
                 cmd_usage(pc->curcmd, SYNOPSIS);

+       if (STREQ(*argv, "bt")) {
+               FILE *tmp_fp;
+
+               if ((tmp_fp = tmpfile()) == NULL) {
+                       error(FATAL, "cannot create temporary file for GDB output\n");
+               }
+
+               strcpy(buf, "thread apply all bt");
+               /* Append any arguments that were passed to 'bt' */
+               /* args[0] is "gdb", args[1] is "bt", so options start at index 2 */
+               for (i = 2; i < argcnt; i++) {
+                       strcat(buf, " ");
+                       strcat(buf, args[i]);
+               }
+
+               if (!gdb_pass_through(buf, tmp_fp, GNU_RETURN_ON_ERROR)) {
+                       fclose(tmp_fp);
+                       error(INFO, "gdb request failed: %s\n", buf);
+                       return;
+               }
+
+               rewind(tmp_fp);
+               format_and_print_gdb_bt(tmp_fp);
+
+               fclose(tmp_fp);
+               return;
+       }
+
         if (STREQ(*argv, "set") && argv[1]) {
                 /*
                  *  Intercept set commands in case something has to be done
-                *  here or elsewhere.
-                 */
+                *  here or elsewhere.
+                */
                 if (STREQ(argv[1], "gdb")) {
                         cmd_set();
                         return;
@@ -821,6 +853,100 @@ cmd_gdb(void)
        }
 }

+#define MAX_BT_LINES 1024
+#define MAX_THREAD_BLOCKS 64
+
+/*
+ * Helper function to parse 'thread apply all bt' output, reverse the
+ * thread blocks, and print the result.
+ */
+static void format_and_print_gdb_bt(FILE *input_fp)
+{
+    char *lines[MAX_BT_LINES];
+    int line_count = 0;
+    int thread_starts[MAX_THREAD_BLOCKS];
+    int thread_count = 0;
+    char line_buffer[BUFSIZE];
+    int i, j;
+    int global_frame_cnt = 0;
+
+    // Read all lines into memory
+    while (fgets(line_buffer, BUFSIZE, input_fp) && line_count < MAX_BT_LINES) {
+        if (strstr(line_buffer, "Thread ") == line_buffer) {
+            if (thread_count < MAX_THREAD_BLOCKS) {
+                thread_starts[thread_count++] = line_count;
+            }
+        }
+        lines[line_count] = strdup(line_buffer);
+        if (!lines[line_count]) {
+            error(FATAL, "strdup failed while reading gdb output\n");
+        }
+        line_count++;
+    }
+
+    if (thread_count == 0) { // If no threads, just print everything as is.
+        for (i = 0; i < line_count; i++) {
+            fputs(lines[i], fp);
+        }
+    } else {
+        // Iterate threads in reverse order to fix the display order
+        for (i = thread_count - 1; i >= 0; i--) {
+            int start_line = thread_starts[i];
+            int end_line = (i == thread_count - 1) ? line_count : thread_starts[i+1];
+
+            // Print thread frames, stripping header and renumbering
+            for (j = start_line; j < end_line; j++) {
+                char *line = lines[j];
+                // Skip "Thread " line
+                if (strncmp(line, "Thread ", 7) == 0) continue;
+                // Skip "Backtrace stopped" or similar noise if desired,
+                // but usually GDB prints "Backtrace stopped" at the very end.
+                // We'll keep it for info unless it's in the middle of our merge.
+                // Actually, duplicate frames or stops might appear.
+                // For now, simple renumbering.
+
+                char *ptr = line;
+                while (*ptr == ' ' || *ptr == '\t') ptr++;
+
+                if (*ptr == '#') {
+                    // Frame line: #0  0x...
+                    char *rest = ptr + 1;
+                    while (isdigit(*rest)) rest++; // Skip old number
+
+                    // Parse content to check for address
+                    char *p = rest;
+                    while (*p == ' ' || *p == '\t') p++;
+
+                    int has_addr = (strncmp(p, "0x", 2) == 0);
+
+                    // Print number
+                    fprintf(fp, "#%-3d", global_frame_cnt++);
+
+                    // Align if address is missing
+                    if (!has_addr) {
+                        // Align function name with frames that have addresses
+                        // 64-bit: 0x... (18 chars) + " in " (4 chars) = 22 chars
+                        // 32-bit: 0x... (10 chars) + " in " (4 chars) = 14 chars
+                        int width = (machdep->bits == 64) ? 22 : 14;
+                        for (int k = 0; k < width; k++) fputc(' ', fp);
+                    }
+
+                    fputs(rest, fp);
+                } else {
+                    // Other lines (e.g. variable info, code)
+                    fputs(line, fp);
+                }
+            }
+        }
+    }
+
+    // Cleanup
+    for (i = 0; i < line_count; i++) {
+        free(lines[i]);
+    }
+}
+
+
 /*
  *  The gdb target_xfer_memory() has a hook installed to re-route
  *  all memory accesses back here; reads of 1 or 4 bytes come primarily
--
2.34.1

#/******本邮件及其附件含有小米公司的保密信息,仅限于发送给上面地址中列出的个人或群组。禁止任何其他人以任何形式使用(包括但不限于全部或部分地泄露、复制、或散发)本邮件中的信息。如果您错收了本邮件,请您立即电话或邮件通知发件人并删除本邮件! This e-mail and its attachments contain confidential information from XIAOMI, which is intended only for the person or entity whose address is listed above. Any use of the information contained herein in any way (including, but not limited to, total or partial disclosure, reproduction, or dissemination) by persons other than the intended recipient(s) is prohibited. If you receive this e-mail in error, please notify the sender by phone or email immediately and delete it!******/#