Projects
openEuler:Mainline
crash
_service:tar_scm:0001-add-SDEI-stack-resolution...
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File _service:tar_scm:0001-add-SDEI-stack-resolution.patch of Package crash
From e43071b6ceaa4fe20c65befe1b5685b68dc9f33f Mon Sep 17 00:00:00 2001 From: Jialong Chen <chenjialong@huawei.com> Date: Wed, 5 Jun 2019 21:25:34 +0800 Subject: [PATCH] crash: add SDEI stack resolution reason: The kernel adds NMI dog detection, and the NMI interrupt stack uses a separate SDEI stack. When the NMI dog is called, the kernel stack will switch to the sdei stack. If the crash reads the stack data, the stack data cannot be parsed normally. normal call trace as follows: PID: 55429 TASK: ffff802772e3ae80 CPU: 19 COMMAND: "insmod" #0 [ffff00000d4e3c70] __crash_kexec at ffff0000081b4ac0 #1 [ffff00000d4e3e00] panic at ffff0000080ebd0c #2 [ffff00000d4e3ee0] nmi_panic at ffff0000080eb864 #3 [ffff00000d4e3f00] watchdog_hardlockup_check at ffff0000081ecd6c #4 [ffff00000d4e3f40] sdei_watchdog_callback at ffff0000080a411c #5 [ffff00000d4e3f60] sdei_event_handler at ffff0000087971ec #6 [ffff00000d4e3f90] __sdei_handler at ffff000008995964 #7 [ffff00000d4e3ff0] __sdei_asm_handler at ffff0000080862dc --- <IRQ stack> --- #8 [ffff0000ccad3b70] __delay at ffff000008973658 #9 [ffff0000ccad3ba0] __const_udelay at ffff0000089735e8 #10 [ffff0000ccad3bb0] init_module at ffff0000009c6038 [test] #11 [ffff0000ccad3bd0] do_one_initcall at ffff000008084ae0 #12 [ffff0000ccad3c60] do_init_module at ffff0000081b1418 #13 [ffff0000ccad3c90] load_module at ffff0000081afc54 #14 [ffff0000ccad3d80] __se_sys_finit_module at ffff0000081b0134 #15 [ffff0000ccad3e40] __arm64_sys_finit_module at ffff0000081b01a0 #16 [ffff0000ccad3e60] el0_svc_common at ffff000008097b44 #17 [ffff0000ccad3ea0] el0_svc_handler at ffff000008097c34 #18 [ffff0000ccad3ff0] el0_svc at ffff000008084144 Signed-off-by: Jialong Chen <chenjialong@huawei.com> --- arm64.c | 213 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- defs.h | 3 + 2 files changed, 212 insertions(+), 4 deletions(-) diff --git a/arm64.c b/arm64.c index c3e26a3..d293e6c 100644 --- a/arm64.c +++ b/arm64.c @@ -93,6 +93,11 @@ static void arm64_calc_VA_BITS(void); static int arm64_is_uvaddr(ulong, struct task_context *); static void arm64_calc_KERNELPACMASK(void); +static int arm64_in_sdei_normal_stack(int cpu, ulong stkptr); +static void arm64_set_sdei_normal_stack(struct bt_info *bt); +static void arm64_sdei_stack_init(void); +static int arm64_in_kdump_text_on_sdei_stack(struct bt_info *bt); + struct kernel_range { unsigned long modules_vaddr, modules_end; unsigned long vmalloc_start_addr, vmalloc_end; @@ -520,6 +525,7 @@ arm64_init(int when) arm64_irq_stack_init(); arm64_overflow_stack_init(); arm64_stackframe_init(); + arm64_sdei_stack_init(); break; case POST_INIT: @@ -2174,6 +2180,70 @@ arm64_irq_stack_init(void) } } +/* + * Gather IRQ stack values. + */ +static void +arm64_sdei_stack_init(void) +{ + int i; + struct syment *sp; + struct gnu_request request, *req; + struct machine_specific *ms = machdep->machspec; + ulong p, sz; + req = &request; + + if (symbol_exists("sdei_stack_normal_ptr") && + (sp = per_cpu_symbol_search("sdei_stack_normal_ptr")) && + get_symbol_type("sdei_stack_normal_ptr", NULL, req)) { + /* v4.14 and later with CONFIG_VMAP_STACK enabled */ + if (CRASHDEBUG(1)) { + fprintf(fp, "sdei_stack_normal_ptr: \n"); + fprintf(fp, " type: %x, %s\n", + (int)req->typecode, + (req->typecode == TYPE_CODE_PTR) ? + "TYPE_CODE_PTR" : "other"); + fprintf(fp, " target_typecode: %x, %s\n", + (int)req->target_typecode, + req->target_typecode == TYPE_CODE_INT ? + "TYPE_CODE_INT" : "other"); + fprintf(fp, " target_length: %ld\n", + req->target_length); + fprintf(fp, " length: %ld\n", req->length); + } + + if (!(ms->sdei_stacks = (ulong *)malloc((size_t)(kt->cpus * sizeof(ulong))))) + error(FATAL, "cannot malloc irq_stack addresses\n"); + + /* + * Determining the IRQ_STACK_SIZE is tricky, but for now + * 4.14 kernel has: + * + * #define IRQ_STACK_SIZE THREAD_SIZE + * + * and finding a solid usage of THREAD_SIZE is hard, but: + * + * union thread_union { + * ... + * unsigned long stack[THREAD_SIZE/sizeof(long)]; + * }; + */ + if (MEMBER_EXISTS("thread_union", "stack")) { + if ((sz = MEMBER_SIZE("thread_union", "stack")) > 0) + ms->sdei_stack_size = sz; + } else + ms->sdei_stack_size = ARM64_IRQ_STACK_SIZE; + + machdep->flags |= IRQ_STACKS; + + for (i = 0; i < kt->cpus; i++) { + p = kt->__per_cpu_offset[i] + sp->value; + readmem(p, KVADDR, &(ms->sdei_stacks[i]), sizeof(ulong), + "SDEI stack pointer", RETURN_ON_ERROR); + } + } +} + /* * Gather Overflow stack values. * @@ -2736,7 +2806,7 @@ arm64_unwind_frame(struct bt_info *bt, struct arm64_stackframe *frame) { unsigned long high, low, fp; unsigned long stack_mask; - unsigned long irq_stack_ptr, orig_sp; + unsigned long irq_stack_ptr, orig_sp, sdei_stack_ptr; struct arm64_pt_regs *ptregs; struct machine_specific *ms = machdep->machspec; @@ -2765,7 +2835,8 @@ arm64_unwind_frame(struct bt_info *bt, struct arm64_stackframe *frame) if (((bt->flags & BT_IRQSTACK) && !arm64_on_irq_stack(bt->tc->processor, frame->fp)) || ((bt->flags & BT_OVERFLOW_STACK) && - !arm64_on_overflow_stack(bt->tc->processor, frame->fp))) { + !arm64_on_overflow_stack(bt->tc->processor, frame->fp)) && + !arm64_in_sdei_normal_stack(bt->tc->processor, frame->fp)) { if (arm64_on_process_stack(bt, frame->fp)) { arm64_set_process_stack(bt); @@ -2805,6 +2876,7 @@ arm64_unwind_frame(struct bt_info *bt, struct arm64_stackframe *frame) * orig_sp = IRQ_STACK_TO_TASK_STACK(irq_stack_ptr); (pt_regs pointer on process stack) */ irq_stack_ptr = ms->irq_stacks[bt->tc->processor] + ms->irq_stack_size - 16; + sdei_stack_ptr = ms->sdei_stacks[bt->tc->processor] + ms->sdei_stack_size - 16; if (frame->sp == irq_stack_ptr) { orig_sp = GET_STACK_ULONG(irq_stack_ptr - 8); @@ -2825,6 +2897,25 @@ arm64_unwind_frame(struct bt_info *bt, struct arm64_stackframe *frame) frame->fp, INSTACK(frame->fp, bt) ? "" : " (?)"); return FALSE; } + } else if (frame->sp == sdei_stack_ptr) { + orig_sp = GET_STACK_ULONG(sdei_stack_ptr - 8); + arm64_set_process_stack(bt); + if (INSTACK(orig_sp, bt) && (INSTACK(frame->fp, bt) || (frame->fp == 0))) { + ptregs = (struct arm64_pt_regs *)&bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(orig_sp))]; + frame->sp = orig_sp; + frame->pc = ptregs->pc; + bt->bptr = fp; + if (CRASHDEBUG(1)) + error(INFO, + "arm64_unwind_frame: switch stacks: fp: %lx sp: %lx pc: %lx\n", + frame->fp, frame->sp, frame->pc); + } else { + error(WARNING, + "arm64_unwind_frame: on IRQ stack: oriq_sp: %lx%s fp: %lx%s\n", + orig_sp, INSTACK(orig_sp, bt) ? "" : " (?)", + frame->fp, INSTACK(frame->fp, bt) ? "" : " (?)"); + return FALSE; + } } return TRUE; @@ -3164,6 +3255,10 @@ arm64_back_trace_cmd(struct bt_info *bt) arm64_set_irq_stack(bt); bt->flags |= BT_IRQSTACK; } + if (arm64_in_sdei_normal_stack(bt->tc->processor, bt->bptr)) { + arm64_set_sdei_normal_stack(bt); + bt->flags |= BT_IRQSTACK; + } stackframe.fp = GET_STACK_ULONG(bt->bptr - 8); stackframe.pc = GET_STACK_ULONG(bt->bptr); stackframe.sp = bt->bptr + 8; @@ -3173,6 +3268,10 @@ arm64_back_trace_cmd(struct bt_info *bt) arm64_set_irq_stack(bt); bt->flags |= BT_IRQSTACK; } + if (arm64_in_sdei_normal_stack(bt->tc->processor, bt->bptr)) { + arm64_set_sdei_normal_stack(bt); + bt->flags |= BT_IRQSTACK; + } stackframe.fp = GET_STACK_ULONG(bt->hp->esp - 8); stackframe.pc = bt->hp->eip ? bt->hp->eip : GET_STACK_ULONG(bt->hp->esp); @@ -3186,6 +3285,10 @@ arm64_back_trace_cmd(struct bt_info *bt) arm64_set_overflow_stack(bt); bt->flags |= BT_OVERFLOW_STACK; } + if (arm64_in_sdei_normal_stack(bt->tc->processor, bt->bptr)) { + arm64_set_sdei_normal_stack(bt); + bt->flags |= BT_IRQSTACK; + } stackframe.sp = bt->stkptr; stackframe.pc = bt->instptr; stackframe.fp = bt->frameptr; @@ -3249,7 +3352,8 @@ arm64_back_trace_cmd(struct bt_info *bt) } if ((bt->flags & BT_IRQSTACK) && - !arm64_on_irq_stack(bt->tc->processor, stackframe.fp)) { + !arm64_on_irq_stack(bt->tc->processor, stackframe.fp) && + !arm64_in_sdei_normal_stack(bt->tc->processor, stackframe.fp)) { bt->flags &= ~BT_IRQSTACK; if (arm64_switch_stack(bt, &stackframe, ofp) == USER_MODE) break; @@ -3537,6 +3641,81 @@ arm64_in_kdump_text(struct bt_info *bt, struct arm64_stackframe *frame) return FALSE; } +static int +arm64_in_kdump_text_on_sdei_stack(struct bt_info *bt) +{ + int cpu; + ulong stackbase; + char *stackbuf; + ulong *ptr, *start, *base; + struct machine_specific *ms; + + if ((machdep->flags & (IRQ_STACKS|KDUMP_ENABLED)) != (IRQ_STACKS|KDUMP_ENABLED)) + return FALSE; + + ms = machdep->machspec; + if (!ms->sdei_stacks) + return FALSE; + cpu = bt->tc->processor; + stackbase = ms->sdei_stacks[cpu]; + stackbuf = GETBUF(ms->sdei_stack_size); + + if (!readmem(stackbase, KVADDR, stackbuf, + ms->sdei_stack_size, "IRQ stack contents", RETURN_ON_ERROR)) { + error(INFO, "read of IRQ stack at %lx failed\n", stackbase); + FREEBUF(stackbuf); + return FALSE; + } + + base = (ulong *)stackbuf; + start = (ulong *)(stackbuf + ms->sdei_stack_size); + + for (ptr = start - 8; ptr >= base; ptr--) { + if (bt->flags & BT_OPT_BACK_TRACE) { + if ((*ptr > ms->crash_kexec_start) && + (*ptr < ms->crash_kexec_end) && + INSTACK(*(ptr - 1), bt)) { + bt->bptr = ((ulong)(ptr - 1) - (ulong)base) + stackbase; + if (CRASHDEBUG(1)) + fprintf(fp, "%lx: %lx (crash_kexec on IRQ stack)\n", + bt->bptr, *ptr); + FREEBUF(stackbuf); + return TRUE; + } + if ((*ptr > ms->crash_save_cpu_start) && + (*ptr < ms->crash_save_cpu_end) && + INSTACK(*(ptr - 1), bt)) { + bt->bptr = ((ulong)(ptr - 1) - (ulong)base) + stackbase; + if (CRASHDEBUG(1)) + fprintf(fp, "%lx: %lx (crash_save_cpu on IRQ stack)\n", + bt->bptr, *ptr); + FREEBUF(stackbuf); + return TRUE; + } + } else { + if ((*ptr > ms->crash_kexec_start) && (*ptr < ms->crash_kexec_end)) { + bt->bptr = ((ulong)ptr - (ulong)base) + stackbase; + if (CRASHDEBUG(1)) + fprintf(fp, "%lx: %lx (crash_kexec on IRQ stack)\n", + bt->bptr, *ptr); + FREEBUF(stackbuf); + return TRUE; + } + if ((*ptr > ms->crash_save_cpu_start) && (*ptr < ms->crash_save_cpu_end)) { + bt->bptr = ((ulong)ptr - (ulong)base) + stackbase; + if (CRASHDEBUG(1)) + fprintf(fp, "%lx: %lx (crash_save_cpu on IRQ stack)\n", + bt->bptr, *ptr); + FREEBUF(stackbuf); + return TRUE; + } + } + } + + FREEBUF(stackbuf); + return FALSE; +} + static int arm64_in_kdump_text_on_irq_stack(struct bt_info *bt) { @@ -3727,7 +3906,8 @@ try_kernel: } if (arm64_in_kdump_text(bt, frame) || - arm64_in_kdump_text_on_irq_stack(bt)) { + arm64_in_kdump_text_on_irq_stack(bt) || + arm64_in_kdump_text_on_sdei_stack(bt)) { bt->flags |= BT_KDUMP_ADJUST; if (skip && is_idle_thread(bt->task)) bt->flags |= BT_SKIP_IDLE; @@ -4488,6 +4668,31 @@ arm64_on_overflow_stack(int cpu, ulong stkptr) ms->overflow_stacks, ms->overflow_stack_size); } +static int +arm64_in_sdei_normal_stack(int cpu, ulong stkptr) +{ + struct machine_specific *ms = machdep->machspec; + + if (!ms->sdei_stack_size || (cpu >= kt->cpus)) + return FALSE; + + if ((stkptr > ms->sdei_stacks[cpu]) && + (stkptr < (ms->sdei_stacks[cpu] + ms->sdei_stack_size))) + return TRUE; + + return FALSE; +} + +static void +arm64_set_sdei_normal_stack(struct bt_info *bt) +{ + struct machine_specific *ms = machdep->machspec; + + bt->stackbase = ms->sdei_stacks[bt->tc->processor]; + bt->stacktop = bt->stackbase + ms->sdei_stack_size; + alter_stackbuf(bt); +} + static void arm64_set_irq_stack(struct bt_info *bt) { diff --git a/defs.h b/defs.h index afdcf6c..4885d55 100644 --- a/defs.h +++ b/defs.h @@ -3376,6 +3376,9 @@ struct machine_specific { ulong irq_stack_size; ulong *irq_stacks; char *irq_stackbuf; + ulong sdei_stack_size; + ulong *sdei_stacks; + char *sdei_stackbuf; ulong __irqentry_text_start; ulong __irqentry_text_end; ulong overflow_stack_size; -- 2.27.0
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.
浙ICP备2022010568号-2