On Wed, Feb 03, 2021 at 09:46:55AM -0800, Ivan Babrou wrote: > > Can you pretty please not line-wrap console output? It's unreadable. > > GMail doesn't make it easy, I'll send a link to a pastebin next time. > Let me know if you'd like me to regenerate the decoded stack. > > > > edfd9b7838ba5e47f19ad8466d0565aba5c59bf0 is the first bad commit > > > commit edfd9b7838ba5e47f19ad8466d0565aba5c59bf0 > > > > Not sure what tree you're on, but that's not the upstream commit. > > I mentioned that it's a rebased core-static_call-2020-10-12 tag and > added a link to the upstream hash right below. > > > > Author: Steven Rostedt (VMware) <rostedt@xxxxxxxxxxx> > > > Date: Tue Aug 18 15:57:52 2020 +0200 > > > > > > tracepoint: Optimize using static_call() > > > > > > > There's a known issue with that patch, can you try: > > > > http://lkml.kernel.org/r/20210202220121.435051654@xxxxxxxxxxx > > I've tried it on top of core-static_call-2020-10-12 tag rebased on top > of v5.9 (to make it reproducible), and the patch did not help. Do I > need to apply the whole series or something else? Can you recreate with this patch, and add "unwind_debug" to the cmdline? It will spit out a bunch of stack data. From: Josh Poimboeuf <jpoimboe@xxxxxxxxxx> Subject: [PATCH] Subject: [PATCH] x86/unwind: Add 'unwind_debug' cmdline option Sometimes the one-line ORC unwinder warnings aren't very helpful. Take the existing frame pointer unwind_dump() and make it useful for all unwinders. I don't want to be too aggressive about enabling the dumps, so for now they're only enabled with the use of a new 'unwind_debug' cmdline option. When enabled, it will dump the full contents of the stack when an error condition is encountered, or when dump_stack() is called. Signed-off-by: Josh Poimboeuf <jpoimboe@xxxxxxxxxx> --- .../admin-guide/kernel-parameters.txt | 6 +++ arch/x86/include/asm/unwind.h | 3 ++ arch/x86/kernel/dumpstack.c | 39 ++++++++++++++ arch/x86/kernel/unwind_frame.c | 51 +++---------------- arch/x86/kernel/unwind_orc.c | 5 +- 5 files changed, 58 insertions(+), 46 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 3d6604a949f8..d29689aa62a2 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -5521,6 +5521,12 @@ unknown_nmi_panic [X86] Cause panic on unknown NMI. + unwind_debug [X86-64] + Enable unwinder debug output. This can be + useful for debugging certain unwinder error + conditions, including corrupt stacks and + bad/missing unwinder metadata. + usbcore.authorized_default= [USB] Default USB device authorization: (default -1 = authorized except for wireless USB, diff --git a/arch/x86/include/asm/unwind.h b/arch/x86/include/asm/unwind.h index 70fc159ebe69..5101d7ef7912 100644 --- a/arch/x86/include/asm/unwind.h +++ b/arch/x86/include/asm/unwind.h @@ -123,4 +123,7 @@ static inline bool task_on_another_cpu(struct task_struct *task) #endif } +extern bool unwind_debug __ro_after_init; +void unwind_dump(struct unwind_state *state); + #endif /* _ASM_X86_UNWIND_H */ diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c index 299c20f0a38b..febfd5b7f62a 100644 --- a/arch/x86/kernel/dumpstack.c +++ b/arch/x86/kernel/dumpstack.c @@ -29,6 +29,42 @@ static int die_counter; static struct pt_regs exec_summary_regs; +bool unwind_debug __ro_after_init; +static int __init unwind_debug_cmdline(char *str) +{ + unwind_debug = true; + return 0; +} +early_param("unwind_debug", unwind_debug_cmdline); + +void unwind_dump(struct unwind_state *state) +{ + unsigned long word, *sp; + struct stack_info stack_info = {0}; + unsigned long visit_mask = 0; + + printk_deferred("unwinder dump: stack type:%d next_sp:%p mask:0x%lx graph_idx:%d\n", + state->stack_info.type, state->stack_info.next_sp, + state->stack_mask, state->graph_idx); + + sp = state->task == current ? __builtin_frame_address(0) + : (void *)state->task->thread.sp; + + for (; sp; sp = PTR_ALIGN(stack_info.next_sp, sizeof(long))) { + if (get_stack_info(sp, state->task, &stack_info, &visit_mask)) + break; + + for (; sp < stack_info.end; sp++) { + + word = READ_ONCE_NOCHECK(*sp); + + printk_deferred("%0*lx: %0*lx (%pB)\n", BITS_PER_LONG/4, + (unsigned long)sp, BITS_PER_LONG/4, + word, (void *)word); + } + } +} + bool noinstr in_task_stack(unsigned long *stack, struct task_struct *task, struct stack_info *info) { @@ -301,6 +337,9 @@ static void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, if (stack_name) printk("%s </%s>\n", log_lvl, stack_name); } + + if (unwind_debug) + unwind_dump(&state); } void show_stack(struct task_struct *task, unsigned long *sp, diff --git a/arch/x86/kernel/unwind_frame.c b/arch/x86/kernel/unwind_frame.c index d7c44b257f7f..6bcdf6ecad65 100644 --- a/arch/x86/kernel/unwind_frame.c +++ b/arch/x86/kernel/unwind_frame.c @@ -28,48 +28,6 @@ unsigned long *unwind_get_return_address_ptr(struct unwind_state *state) return state->regs ? &state->regs->ip : state->bp + 1; } -static void unwind_dump(struct unwind_state *state) -{ - static bool dumped_before = false; - bool prev_zero, zero = false; - unsigned long word, *sp; - struct stack_info stack_info = {0}; - unsigned long visit_mask = 0; - - if (dumped_before) - return; - - dumped_before = true; - - printk_deferred("unwind stack type:%d next_sp:%p mask:0x%lx graph_idx:%d\n", - state->stack_info.type, state->stack_info.next_sp, - state->stack_mask, state->graph_idx); - - for (sp = PTR_ALIGN(state->orig_sp, sizeof(long)); sp; - sp = PTR_ALIGN(stack_info.next_sp, sizeof(long))) { - if (get_stack_info(sp, state->task, &stack_info, &visit_mask)) - break; - - for (; sp < stack_info.end; sp++) { - - word = READ_ONCE_NOCHECK(*sp); - - prev_zero = zero; - zero = word == 0; - - if (zero) { - if (!prev_zero) - printk_deferred("%p: %0*x ...\n", - sp, BITS_PER_LONG/4, 0); - continue; - } - - printk_deferred("%p: %0*lx (%pB)\n", - sp, BITS_PER_LONG/4, word, (void *)word); - } - } -} - static bool in_entry_code(unsigned long ip) { char *addr = (char *)ip; @@ -244,7 +202,6 @@ static bool update_stack_state(struct unwind_state *state, addr, addr_p); } - /* Save the original stack pointer for unwind_dump(): */ if (!state->orig_sp) state->orig_sp = frame; @@ -346,13 +303,17 @@ bool unwind_next_frame(struct unwind_state *state) "WARNING: kernel stack regs at %p in %s:%d has bad 'bp' value %p\n", state->regs, state->task->comm, state->task->pid, next_bp); - unwind_dump(state); + + if (unwind_debug) + unwind_dump(state); } else { printk_deferred_once(KERN_WARNING "WARNING: kernel stack frame pointer at %p in %s:%d has bad value %p\n", state->bp, state->task->comm, state->task->pid, next_bp); - unwind_dump(state); + + if (unwind_debug) + unwind_dump(state); } the_end: state->stack_info.type = STACK_TYPE_UNKNOWN; diff --git a/arch/x86/kernel/unwind_orc.c b/arch/x86/kernel/unwind_orc.c index 73f800100066..38265eac41dd 100644 --- a/arch/x86/kernel/unwind_orc.c +++ b/arch/x86/kernel/unwind_orc.c @@ -13,8 +13,11 @@ #define orc_warn_current(args...) \ ({ \ - if (state->task == current) \ + if (state->task == current) { \ orc_warn(args); \ + if (unwind_debug) \ + unwind_dump(state); \ + } \ }) extern int __start_orc_unwind_ip[]; -- 2.29.2