applied:
https://github.com/crash-utility/crash/commit/fa4ba91e0383343112478decce4...
On Thu, May 7, 2026 at 11:45 AM Tao Liu <ltao(a)redhat.com> wrote:
Sorry for the late reply, for v3, ack.
Thanks,
Tao Liu
On Thu, May 7, 2026 at 12:31 AM 李鹏飞 <ljdlns1987(a)gmail.com> wrote:
>
> Hi Tao,
>
> Just a gentle follow-up on this patch.
>
> Is there anything else needed, or can it be picked up?
>
> Thanks,
> Pengfei
>
> Li Pengfei <ljdlns1987(a)gmail.com> 于2026年4月1日周三 10:32写道:
>>
>> From: lipengfei28 <lipengfei28(a)xiaomi.com>
>>
>> Hi Tao,
>>
>> Thanks for your review.
>>
>> This v3 addresses your comment:
>> - remove redundant extra_stacks_regs[] allocation in
>> arm64_switch_stack_from_overflow()
>> - move variable declarations to block start for C89 style
>> - add braces to outer if for readability
>>
>> Thanks,
>> Pengfei
>>
>> ---
>>
>> On ARM64, crash's gdb bt relies on feeding a register snapshot (PC/SP/FP,
>> etc.) into gdb and letting gdb unwind from there. Before this change, the
>> register snapshot handling across exception frames / stack switching could be
>> broken in several ways, leading to truncated backtraces, garbage substacks, or
>> invalid addresses (e.g. -3 / 0xff...fd) showing up in gdb output.
>>
>> Fixes included in this patch:
>>
>> Fix out-of-bounds read when populating gdb registers from an exception frame
>> In arm64_print_exception_frame() the previous code copied
>> sizeof(struct arm64_pt_regs) bytes from a smaller stackframe-derived
>> buffer, which could read past valid data and poison the gdb registers.
>> Replace this with explicit field/register assignment and initialize the
>> bitmap accordingly.
>>
>> Improve unwinding across IRQ/overflow stack transitions on newer kernels
>> When switching stacks (IRQ / overflow), gdb may stop at the trampoline (e.g.
>> call_on_irq_stack) because the discontinuity prevents it from recovering
>> the caller frame automatically. For UNW_4_14+, "peek" one frame ahead
by
>> reading the saved FP/PC from the current frame, and register that as the
>> next gdb substack, so gdb can continue unwinding on the process stack.
>>
>> Avoid creating invalid/empty substacks
>> Only add a gdb substack when the recovered PC is non-zero, preventing bogus
>> threads from being created.
>>
>> This patch only changes ARM64 unwinding/register setup logic. It does not try
>> to reformat or merge gdb output.
>>
>> Tested on: Android Linux 6.x, arm64
>>
>> Changes in v2:
>> - Fix duplicate definition of arm64_gdb_add_next_frame_substack()
>> - Fix indentation issues in arm64_print_exception_frame()
>> - Minor cleanups based on Tao's review
>>
>> Changes in v3:
>> - Remove redundant extra_stacks_regs[] allocation in
>> arm64_switch_stack_from_overflow(), as arm64_gdb_add_next_frame_substack()
>> already handles its own allocation internally
>>
>> Signed-off-by: lipengfei28 <lipengfei28(a)xiaomi.com>
>> ---
>> arm64.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++---------
>> 1 file changed, 87 insertions(+), 17 deletions(-)
>>
>> diff --git a/arm64.c b/arm64.c
>> index c125655..d177092 100644
>> --- a/arm64.c
>> +++ b/arm64.c
>> @@ -228,7 +228,7 @@ arm64_get_current_task_reg(int regno, const char *name,
>> return FALSE;
>>
>> if (sid && sid <= extra_stacks_idx) {
>> - ur_bitmap = extra_stacks_regs[extra_stacks_idx - 1];
>> + ur_bitmap = extra_stacks_regs[sid - 1];
>> goto get_sub;
>> }
>>
>> @@ -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,13 @@ 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->task != tt->panic_task) &&
>> + (!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 +3935,13 @@ 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->task != tt->panic_task) &&
>> + (!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++);
>> }
>> }
>> @@ -4232,6 +4244,46 @@ arm64_in_kdump_text_on_irq_stack(struct bt_info *bt)
>> return FALSE;
>> }
>>
>> +static void
>> +arm64_gdb_add_next_frame_substack(struct bt_info *bt, const struct
arm64_stackframe *frame)
>> +{
>> + struct machine_specific *ms = machdep->machspec;
>> + struct user_regs_bitmap_struct *ur_ptr;
>> + ulong next_fp, next_pc, next_sp;
>> +
>> + 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));
>> + ur_ptr = extra_stacks_regs[extra_stacks_idx];
>> +
>> + next_fp = GET_STACK_ULONG(frame->fp);
>> + next_pc = GET_STACK_ULONG(frame->fp + 8);
>> + 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++);
>> + }
>> +}
>> +
>> static int
>> arm64_switch_stack(struct bt_info *bt, struct arm64_stackframe *frame, FILE
*ofp)
>> {
>> @@ -4263,8 +4315,11 @@ 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 {
>> + arm64_gdb_add_next_frame_substack(bt, frame);
>> + }
>>
>> return KERNEL_MODE;
>> }
>> @@ -4300,8 +4355,11 @@ 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 {
>> + arm64_gdb_add_next_frame_substack(bt, frame);
>> + }
>>
>> return KERNEL_MODE;
>> }
>> @@ -4549,6 +4607,9 @@ arm64_print_exception_frame(struct bt_info *bt, ulong
pt_regs, int mode, FILE *o
>> (ulong)regs->orig_x0,
(ulong)regs->syscallno);
>> fprintf(ofp, " PSTATE: %08lx\n",
(ulong)regs->pstate);
>> } else if (!(bt->flags & BT_EFRAME_SEARCH)) {
>> + struct user_regs_bitmap_struct *ur_ptr;
>> + int i;
>> +
>> if (!extra_stacks_regs[extra_stacks_idx]) {
>> extra_stacks_regs[extra_stacks_idx] =
>> (struct user_regs_bitmap_struct *)
>> @@ -4556,17 +4617,26 @@ 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 !=
>> +
>> + ur_ptr = extra_stacks_regs[extra_stacks_idx];
>> +
>> + 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 &&
>> - extra_stacks_regs[extra_stacks_idx]->ur.pc !=
>> - ((struct user_regs_bitmap_struct
*)(bt->machdep))->ur.pc)) {
>> - gdb_add_substack (extra_stacks_idx++);
>> - }
>> + ur_ptr->ur.pc !=
>> + ((struct user_regs_bitmap_struct
*)(bt->machdep))->ur.pc))) {
>> + gdb_add_substack(extra_stacks_idx++);
>> + }
>> }
>> }
>>
>> --
>> 2.34.1
>>