Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86/unwind/orc: Add 'unwind_debug' cmdline option

Sometimes the one-line ORC unwinder warnings aren't very helpful. Add a
new 'unwind_debug' cmdline option which will dump the full stack
contents of the current task when an error condition is encountered.

Reviewed-by: Miroslav Benes <mbenes@suse.cz>
Link: https://lore.kernel.org/r/6afb9e48a05fd2046bfad47e69b061b43dfd0e0e.1681331449.git.jpoimboe@kernel.org
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>

authored by

Josh Poimboeuf and committed by
Josh Poimboeuf
89da5a69 dc1d0553

+54 -1
+6
Documentation/admin-guide/kernel-parameters.txt
··· 6563 6563 unknown_nmi_panic 6564 6564 [X86] Cause panic on unknown NMI. 6565 6565 6566 + unwind_debug [X86-64] 6567 + Enable unwinder debug output. This can be 6568 + useful for debugging certain unwinder error 6569 + conditions, including corrupt stacks and 6570 + bad/missing unwinder metadata. 6571 + 6566 6572 usbcore.authorized_default= 6567 6573 [USB] Default USB device authorization: 6568 6574 (default -1 = authorized except for wireless USB,
+48 -1
arch/x86/kernel/unwind_orc.c
··· 13 13 14 14 #define orc_warn_current(args...) \ 15 15 ({ \ 16 - if (state->task == current && !state->error) \ 16 + static bool dumped_before; \ 17 + if (state->task == current && !state->error) { \ 17 18 orc_warn(args); \ 19 + if (unwind_debug && !dumped_before) { \ 20 + dumped_before = true; \ 21 + unwind_dump(state); \ 22 + } \ 23 + } \ 18 24 }) 19 25 20 26 extern int __start_orc_unwind_ip[]; ··· 29 23 extern struct orc_entry __stop_orc_unwind[]; 30 24 31 25 static bool orc_init __ro_after_init; 26 + static bool unwind_debug __ro_after_init; 32 27 static unsigned int lookup_num_blocks __ro_after_init; 28 + 29 + static int __init unwind_debug_cmdline(char *str) 30 + { 31 + unwind_debug = true; 32 + 33 + return 0; 34 + } 35 + early_param("unwind_debug", unwind_debug_cmdline); 36 + 37 + static void unwind_dump(struct unwind_state *state) 38 + { 39 + static bool dumped_before; 40 + unsigned long word, *sp; 41 + struct stack_info stack_info = {0}; 42 + unsigned long visit_mask = 0; 43 + 44 + if (dumped_before) 45 + return; 46 + 47 + dumped_before = true; 48 + 49 + printk_deferred("unwind stack type:%d next_sp:%p mask:0x%lx graph_idx:%d\n", 50 + state->stack_info.type, state->stack_info.next_sp, 51 + state->stack_mask, state->graph_idx); 52 + 53 + for (sp = __builtin_frame_address(0); sp; 54 + sp = PTR_ALIGN(stack_info.next_sp, sizeof(long))) { 55 + if (get_stack_info(sp, state->task, &stack_info, &visit_mask)) 56 + break; 57 + 58 + for (; sp < stack_info.end; sp++) { 59 + 60 + word = READ_ONCE_NOCHECK(*sp); 61 + 62 + printk_deferred("%0*lx: %0*lx (%pB)\n", BITS_PER_LONG/4, 63 + (unsigned long)sp, BITS_PER_LONG/4, 64 + word, (void *)word); 65 + } 66 + } 67 + } 33 68 34 69 static inline unsigned long orc_ip(const int *ip) 35 70 {