Commit 89da5a69 authored by Josh Poimboeuf's avatar Josh Poimboeuf Committed by Josh Poimboeuf
Browse files

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: default avatarMiroslav Benes <mbenes@suse.cz>
Link: https://lore.kernel.org/r/6afb9e48a05fd2046bfad47e69b061b43dfd0e0e.1681331449.git.jpoimboe@kernel.org


Signed-off-by: default avatarJosh Poimboeuf <jpoimboe@kernel.org>
parent dc1d0553
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -6563,6 +6563,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,
+48 −1
Original line number Diff line number Diff line
@@ -13,8 +13,14 @@

#define orc_warn_current(args...)					\
({									\
	if (state->task == current && !state->error)			\
	static bool dumped_before;					\
	if (state->task == current && !state->error) {			\
		orc_warn(args);						\
		if (unwind_debug && !dumped_before) {			\
			dumped_before = true;				\
			unwind_dump(state);				\
		}							\
	}								\
})

extern int __start_orc_unwind_ip[];
@@ -23,8 +29,49 @@ extern struct orc_entry __start_orc_unwind[];
extern struct orc_entry __stop_orc_unwind[];

static bool orc_init __ro_after_init;
static bool unwind_debug __ro_after_init;
static unsigned int lookup_num_blocks __ro_after_init;

static int __init unwind_debug_cmdline(char *str)
{
	unwind_debug = true;

	return 0;
}
early_param("unwind_debug", unwind_debug_cmdline);

static void unwind_dump(struct unwind_state *state)
{
	static bool dumped_before;
	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 = __builtin_frame_address(0); 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);
		}
	}
}

static inline unsigned long orc_ip(const int *ip)
{
	return (unsigned long)ip + *ip;