diff mbox series

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

Message ID 20220815105808.17385-2-chenzhongjin@huawei.com (mailing list archive)
State New, archived
Headers show
Series x86/unwind/orc: Add 'unwind_debug' cmdline option | expand

Commit Message

Chen Zhongjin Aug. 15, 2022, 10:58 a.m. UTC
From: Josh Poimboeuf <jpoimboe@redhat.com>

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.

Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
Reviewed-by: Miroslav Benes <mbenes@suse.cz>
---
 .../admin-guide/kernel-parameters.txt         |  6 +++
 arch/x86/kernel/unwind_orc.c                  | 46 +++++++++++++++++++
 2 files changed, 52 insertions(+)

Comments

Chen Zhongjin Aug. 15, 2022, 11:04 a.m. UTC | #1
I accidentally attached this with my patch.

Please ignore this one.


Thanks,

Chen

On 2022/8/15 18:58, Chen Zhongjin wrote:
> From: Josh Poimboeuf <jpoimboe@redhat.com>
>
> 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.
>
> Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
> Reviewed-by: Miroslav Benes <mbenes@suse.cz>
> ---
>   .../admin-guide/kernel-parameters.txt         |  6 +++
>   arch/x86/kernel/unwind_orc.c                  | 46 +++++++++++++++++++
>   2 files changed, 52 insertions(+)
>
> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
> index cc3ea8febc62..85d48f6052fd 100644
> --- a/Documentation/admin-guide/kernel-parameters.txt
> +++ b/Documentation/admin-guide/kernel-parameters.txt
> @@ -6317,6 +6317,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/kernel/unwind_orc.c b/arch/x86/kernel/unwind_orc.c
> index 38185aedf7d1..c539ca39e9f4 100644
> --- a/arch/x86/kernel/unwind_orc.c
> +++ b/arch/x86/kernel/unwind_orc.c
> @@ -13,8 +13,13 @@
>   
>   #define orc_warn_current(args...)					\
>   ({									\
> +	static bool dumped_before;
>   	if (state->task == current && !state->error)			\
>   		orc_warn(args);						\
> +		if (unwind_debug && !dumped_before)			\
> +			unwind_dump(state);				\
> +		dumped_before = true;					\
> +	}								\
>   })
>   
>   extern int __start_orc_unwind_ip[];
> @@ -23,8 +28,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;
kernel test robot Aug. 15, 2022, 7:41 p.m. UTC | #2
Hi Chen,

I love your patch! Perhaps something to improve:

[auto build test WARNING on tip/x86/core]
[also build test WARNING on soc/for-next clk/clk-next linus/master v6.0-rc1 next-20220815]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Chen-Zhongjin/x86-unwind-orc-Add-unwind_debug-cmdline-option/20220815-190328
base:   https://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git a1a5482a2c6e38a3ebed32e571625c56a8cc41a6
config: x86_64-randconfig-a003-20220815 (https://download.01.org/0day-ci/archive/20220816/202208160326.pFZMVgFP-lkp@intel.com/config)
compiler: gcc-11 (Debian 11.3.0-5) 11.3.0
reproduce (this is a W=1 build):
        # https://github.com/intel-lab-lkp/linux/commit/3295e738f5b51f1f1f223bf52a8ecee2ab93fbca
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Chen-Zhongjin/x86-unwind-orc-Add-unwind_debug-cmdline-option/20220815-190328
        git checkout 3295e738f5b51f1f1f223bf52a8ecee2ab93fbca
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        make W=1 O=build_dir ARCH=x86_64 SHELL=/bin/bash arch/x86/kernel/

If you fix the issue, kindly add following tag where applicable
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   arch/x86/kernel/unwind_orc.c:17:9: error: expected identifier or '(' before 'if'
      17 |         if (state->task == current && !state->error)                    \
         |         ^~
   In file included from include/asm-generic/bug.h:7,
                    from arch/x86/include/asm/bug.h:87,
                    from include/linux/bug.h:5,
                    from include/linux/jump_label.h:257,
                    from include/linux/static_key.h:1,
                    from arch/x86/include/asm/nospec-branch.h:6,
                    from arch/x86/include/asm/paravirt_types.h:40,
                    from arch/x86/include/asm/ptrace.h:97,
                    from arch/x86/include/asm/math_emu.h:5,
                    from arch/x86/include/asm/processor.h:13,
                    from arch/x86/include/asm/timex.h:5,
                    from include/linux/timex.h:67,
                    from include/linux/time32.h:13,
                    from include/linux/time.h:60,
                    from include/linux/stat.h:19,
                    from include/linux/module.h:13,
                    from arch/x86/kernel/unwind_orc.c:3:
   include/linux/once_lite.h:34:10: error: expected identifier or '(' before ')' token
      34 |         })
         |          ^
   include/linux/once_lite.h:11:9: note: in expansion of macro 'DO_ONCE_LITE_IF'
      11 |         DO_ONCE_LITE_IF(true, func, ##__VA_ARGS__)
         |         ^~~~~~~~~~~~~~~
   include/linux/printk.h:605:9: note: in expansion of macro 'DO_ONCE_LITE'
     605 |         DO_ONCE_LITE(printk_deferred, fmt, ##__VA_ARGS__)
         |         ^~~~~~~~~~~~
   arch/x86/kernel/unwind_orc.c:12:9: note: in expansion of macro 'printk_deferred_once'
      12 |         printk_deferred_once(KERN_WARNING "WARNING: " fmt, ##__VA_ARGS__)
         |         ^~~~~~~~~~~~~~~~~~~~
   arch/x86/kernel/unwind_orc.c:18:17: note: in expansion of macro 'orc_warn'
      18 |                 orc_warn(args);                                         \
         |                 ^~~~~~~~
   arch/x86/kernel/unwind_orc.c:19:17: error: expected identifier or '(' before 'if'
      19 |                 if (unwind_debug && !dumped_before)                     \
         |                 ^~
>> arch/x86/kernel/unwind_orc.c:21:17: warning: data definition has no type or storage class
      21 |                 dumped_before = true;                                   \
         |                 ^~~~~~~~~~~~~
   arch/x86/kernel/unwind_orc.c:21:17: error: type defaults to 'int' in declaration of 'dumped_before' [-Werror=implicit-int]
   arch/x86/kernel/unwind_orc.c:22:9: error: expected identifier or '(' before '}' token
      22 |         }                                                               \
         |         ^
   arch/x86/kernel/unwind_orc.c:23:1: error: expected identifier or '(' before '}' token
      23 | })
         | ^
   arch/x86/kernel/unwind_orc.c:23:2: error: expected identifier or '(' before ')' token
      23 | })
         |  ^
   arch/x86/kernel/unwind_orc.c: In function 'orc_find':
   arch/x86/kernel/unwind_orc.c:219:35: error: '__start_orc_unwind_ip' undeclared (first use in this function); did you mean '__start_orc_unwind'?
     219 |                 return __orc_find(__start_orc_unwind_ip + start,
         |                                   ^~~~~~~~~~~~~~~~~~~~~
         |                                   __start_orc_unwind
   arch/x86/kernel/unwind_orc.c:219:35: note: each undeclared identifier is reported only once for each function it appears in
   arch/x86/kernel/unwind_orc.c: At top level:
   arch/x86/kernel/unwind_orc.c:239:32: error: '__start_orc_unwind_ip' undeclared here (not in a function); did you mean '__start_orc_unwind'?
     239 | static int *cur_orc_ip_table = __start_orc_unwind_ip;
         |                                ^~~~~~~~~~~~~~~~~~~~~
         |                                __start_orc_unwind
   arch/x86/kernel/unwind_orc.c: In function 'unwind_next_frame':
   arch/x86/kernel/unwind_orc.c:534:18: error: expected ')' before 'break'
     534 |                 }
         |                  ^
         |                  )
     535 |                 break;
         |                 ~~~~~
>> arch/x86/kernel/unwind_orc.c:16:21: warning: unused variable 'dumped_before' [-Wunused-variable]
      16 |         static bool dumped_before;
         |                     ^~~~~~~~~~~~~
   arch/x86/kernel/unwind_orc.c:531:25: note: in expansion of macro 'orc_warn_current'
     531 |                         orc_warn_current("missing R10 value at %pB\n",
         |                         ^~~~~~~~~~~~~~~~
   arch/x86/kernel/unwind_orc.c:767:1: error: expected declaration or statement at end of input
     767 | EXPORT_SYMBOL_GPL(__unwind_start);
         | ^~~~~~~~~~~~~~~~~
   arch/x86/kernel/unwind_orc.c:767:1: error: expected declaration or statement at end of input
   arch/x86/kernel/unwind_orc.c:767:1: error: expected declaration or statement at end of input
   arch/x86/kernel/unwind_orc.c:533:25: error: label 'err' used but not defined
     533 |                         goto err;
         |                         ^~~~
   arch/x86/kernel/unwind_orc.c:506:17: error: label 'the_end' used but not defined
     506 |                 goto the_end;
         |                 ^~~~
>> arch/x86/kernel/unwind_orc.c:468:14: warning: variable 'indirect' set but not used [-Wunused-but-set-variable]
     468 |         bool indirect = false;
         |              ^~~~~~~~
>> arch/x86/kernel/unwind_orc.c:466:25: warning: unused variable 'prev_type' [-Wunused-variable]
     466 |         enum stack_type prev_type = state->stack_info.type;
         |                         ^~~~~~~~~
>> arch/x86/kernel/unwind_orc.c:465:59: warning: unused variable 'prev_sp' [-Wunused-variable]
     465 |         unsigned long ip_p, sp, tmp, orig_ip = state->ip, prev_sp = state->sp;
         |                                                           ^~~~~~~
>> arch/x86/kernel/unwind_orc.c:465:38: warning: unused variable 'orig_ip' [-Wunused-variable]
     465 |         unsigned long ip_p, sp, tmp, orig_ip = state->ip, prev_sp = state->sp;
         |                                      ^~~~~~~
>> arch/x86/kernel/unwind_orc.c:465:33: warning: unused variable 'tmp' [-Wunused-variable]
     465 |         unsigned long ip_p, sp, tmp, orig_ip = state->ip, prev_sp = state->sp;
         |                                 ^~~
>> arch/x86/kernel/unwind_orc.c:465:23: warning: unused variable 'ip_p' [-Wunused-variable]
     465 |         unsigned long ip_p, sp, tmp, orig_ip = state->ip, prev_sp = state->sp;
         |                       ^~~~
   arch/x86/kernel/unwind_orc.c:768: error: control reaches end of non-void function [-Werror=return-type]
   At top level:
>> arch/x86/kernel/unwind_orc.c:16:21: warning: 'dumped_before' defined but not used [-Wunused-variable]
      16 |         static bool dumped_before;
         |                     ^~~~~~~~~~~~~
   arch/x86/kernel/unwind_orc.c:531:25: note: in expansion of macro 'orc_warn_current'
     531 |                         orc_warn_current("missing R10 value at %pB\n",
         |                         ^~~~~~~~~~~~~~~~
   arch/x86/kernel/unwind_orc.c:421:13: warning: 'deref_stack_iret_regs' defined but not used [-Wunused-function]
     421 | static bool deref_stack_iret_regs(struct unwind_state *state, unsigned long addr,
         |             ^~~~~~~~~~~~~~~~~~~~~
   arch/x86/kernel/unwind_orc.c:405:13: warning: 'deref_stack_regs' defined but not used [-Wunused-function]
     405 | static bool deref_stack_regs(struct unwind_state *state, unsigned long addr,
         |             ^~~~~~~~~~~~~~~~
   arch/x86/kernel/unwind_orc.c:395:13: warning: 'deref_stack_reg' defined but not used [-Wunused-function]
     395 | static bool deref_stack_reg(struct unwind_state *state, unsigned long addr,
         |             ^~~~~~~~~~~~~~~
   arch/x86/kernel/unwind_orc.c:42:13: warning: 'unwind_dump' defined but not used [-Wunused-function]
      42 | static void unwind_dump(struct unwind_state *state)
         |             ^~~~~~~~~~~
   cc1: some warnings being treated as errors


vim +21 arch/x86/kernel/unwind_orc.c

    10	
    11	#define orc_warn(fmt, ...) \
    12		printk_deferred_once(KERN_WARNING "WARNING: " fmt, ##__VA_ARGS__)
    13	
    14	#define orc_warn_current(args...)					\
    15	({									\
  > 16		static bool dumped_before;
    17		if (state->task == current && !state->error)			\
    18			orc_warn(args);						\
    19			if (unwind_debug && !dumped_before)			\
    20				unwind_dump(state);				\
  > 21			dumped_before = true;					\
    22		}								\
    23	})
    24
kernel test robot Aug. 15, 2022, 11:44 p.m. UTC | #3
Hi Chen,

I love your patch! Yet something to improve:

[auto build test ERROR on tip/x86/core]
[also build test ERROR on soc/for-next clk/clk-next linus/master v6.0-rc1 next-20220815]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Chen-Zhongjin/x86-unwind-orc-Add-unwind_debug-cmdline-option/20220815-190328
base:   https://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git a1a5482a2c6e38a3ebed32e571625c56a8cc41a6
config: x86_64-randconfig-a003-20220815 (https://download.01.org/0day-ci/archive/20220816/202208160719.jJFohEBB-lkp@intel.com/config)
compiler: gcc-11 (Debian 11.3.0-5) 11.3.0
reproduce (this is a W=1 build):
        # https://github.com/intel-lab-lkp/linux/commit/3295e738f5b51f1f1f223bf52a8ecee2ab93fbca
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Chen-Zhongjin/x86-unwind-orc-Add-unwind_debug-cmdline-option/20220815-190328
        git checkout 3295e738f5b51f1f1f223bf52a8ecee2ab93fbca
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        make W=1 O=build_dir ARCH=x86_64 SHELL=/bin/bash

If you fix the issue, kindly add following tag where applicable
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

>> arch/x86/kernel/unwind_orc.c:17:9: error: expected identifier or '(' before 'if'
      17 |         if (state->task == current && !state->error)                    \
         |         ^~
   In file included from include/asm-generic/bug.h:7,
                    from arch/x86/include/asm/bug.h:87,
                    from include/linux/bug.h:5,
                    from include/linux/jump_label.h:257,
                    from include/linux/static_key.h:1,
                    from arch/x86/include/asm/nospec-branch.h:6,
                    from arch/x86/include/asm/paravirt_types.h:40,
                    from arch/x86/include/asm/ptrace.h:97,
                    from arch/x86/include/asm/math_emu.h:5,
                    from arch/x86/include/asm/processor.h:13,
                    from arch/x86/include/asm/timex.h:5,
                    from include/linux/timex.h:67,
                    from include/linux/time32.h:13,
                    from include/linux/time.h:60,
                    from include/linux/stat.h:19,
                    from include/linux/module.h:13,
                    from arch/x86/kernel/unwind_orc.c:3:
>> include/linux/once_lite.h:34:10: error: expected identifier or '(' before ')' token
      34 |         })
         |          ^
   include/linux/once_lite.h:11:9: note: in expansion of macro 'DO_ONCE_LITE_IF'
      11 |         DO_ONCE_LITE_IF(true, func, ##__VA_ARGS__)
         |         ^~~~~~~~~~~~~~~
   include/linux/printk.h:605:9: note: in expansion of macro 'DO_ONCE_LITE'
     605 |         DO_ONCE_LITE(printk_deferred, fmt, ##__VA_ARGS__)
         |         ^~~~~~~~~~~~
   arch/x86/kernel/unwind_orc.c:12:9: note: in expansion of macro 'printk_deferred_once'
      12 |         printk_deferred_once(KERN_WARNING "WARNING: " fmt, ##__VA_ARGS__)
         |         ^~~~~~~~~~~~~~~~~~~~
   arch/x86/kernel/unwind_orc.c:18:17: note: in expansion of macro 'orc_warn'
      18 |                 orc_warn(args);                                         \
         |                 ^~~~~~~~
   arch/x86/kernel/unwind_orc.c:19:17: error: expected identifier or '(' before 'if'
      19 |                 if (unwind_debug && !dumped_before)                     \
         |                 ^~
   arch/x86/kernel/unwind_orc.c:21:17: warning: data definition has no type or storage class
      21 |                 dumped_before = true;                                   \
         |                 ^~~~~~~~~~~~~
>> arch/x86/kernel/unwind_orc.c:21:17: error: type defaults to 'int' in declaration of 'dumped_before' [-Werror=implicit-int]
>> arch/x86/kernel/unwind_orc.c:22:9: error: expected identifier or '(' before '}' token
      22 |         }                                                               \
         |         ^
   arch/x86/kernel/unwind_orc.c:23:1: error: expected identifier or '(' before '}' token
      23 | })
         | ^
>> arch/x86/kernel/unwind_orc.c:23:2: error: expected identifier or '(' before ')' token
      23 | })
         |  ^
   arch/x86/kernel/unwind_orc.c: In function 'orc_find':
>> arch/x86/kernel/unwind_orc.c:219:35: error: '__start_orc_unwind_ip' undeclared (first use in this function); did you mean '__start_orc_unwind'?
     219 |                 return __orc_find(__start_orc_unwind_ip + start,
         |                                   ^~~~~~~~~~~~~~~~~~~~~
         |                                   __start_orc_unwind
   arch/x86/kernel/unwind_orc.c:219:35: note: each undeclared identifier is reported only once for each function it appears in
   arch/x86/kernel/unwind_orc.c: At top level:
>> arch/x86/kernel/unwind_orc.c:239:32: error: '__start_orc_unwind_ip' undeclared here (not in a function); did you mean '__start_orc_unwind'?
     239 | static int *cur_orc_ip_table = __start_orc_unwind_ip;
         |                                ^~~~~~~~~~~~~~~~~~~~~
         |                                __start_orc_unwind
   arch/x86/kernel/unwind_orc.c: In function 'unwind_next_frame':
>> arch/x86/kernel/unwind_orc.c:534:18: error: expected ')' before 'break'
     534 |                 }
         |                  ^
         |                  )
     535 |                 break;
         |                 ~~~~~
   arch/x86/kernel/unwind_orc.c:16:21: warning: unused variable 'dumped_before' [-Wunused-variable]
      16 |         static bool dumped_before;
         |                     ^~~~~~~~~~~~~
   arch/x86/kernel/unwind_orc.c:531:25: note: in expansion of macro 'orc_warn_current'
     531 |                         orc_warn_current("missing R10 value at %pB\n",
         |                         ^~~~~~~~~~~~~~~~
>> arch/x86/kernel/unwind_orc.c:767:1: error: expected declaration or statement at end of input
     767 | EXPORT_SYMBOL_GPL(__unwind_start);
         | ^~~~~~~~~~~~~~~~~
>> arch/x86/kernel/unwind_orc.c:767:1: error: expected declaration or statement at end of input
>> arch/x86/kernel/unwind_orc.c:767:1: error: expected declaration or statement at end of input
>> arch/x86/kernel/unwind_orc.c:533:25: error: label 'err' used but not defined
     533 |                         goto err;
         |                         ^~~~
>> arch/x86/kernel/unwind_orc.c:506:17: error: label 'the_end' used but not defined
     506 |                 goto the_end;
         |                 ^~~~
   arch/x86/kernel/unwind_orc.c:468:14: warning: variable 'indirect' set but not used [-Wunused-but-set-variable]
     468 |         bool indirect = false;
         |              ^~~~~~~~
   arch/x86/kernel/unwind_orc.c:466:25: warning: unused variable 'prev_type' [-Wunused-variable]
     466 |         enum stack_type prev_type = state->stack_info.type;
         |                         ^~~~~~~~~
   arch/x86/kernel/unwind_orc.c:465:59: warning: unused variable 'prev_sp' [-Wunused-variable]
     465 |         unsigned long ip_p, sp, tmp, orig_ip = state->ip, prev_sp = state->sp;
         |                                                           ^~~~~~~
   arch/x86/kernel/unwind_orc.c:465:38: warning: unused variable 'orig_ip' [-Wunused-variable]
     465 |         unsigned long ip_p, sp, tmp, orig_ip = state->ip, prev_sp = state->sp;
         |                                      ^~~~~~~
   arch/x86/kernel/unwind_orc.c:465:33: warning: unused variable 'tmp' [-Wunused-variable]
     465 |         unsigned long ip_p, sp, tmp, orig_ip = state->ip, prev_sp = state->sp;
         |                                 ^~~
   arch/x86/kernel/unwind_orc.c:465:23: warning: unused variable 'ip_p' [-Wunused-variable]
     465 |         unsigned long ip_p, sp, tmp, orig_ip = state->ip, prev_sp = state->sp;
         |                       ^~~~
   arch/x86/kernel/unwind_orc.c:768: error: control reaches end of non-void function [-Werror=return-type]
   At top level:
   arch/x86/kernel/unwind_orc.c:16:21: warning: 'dumped_before' defined but not used [-Wunused-variable]
      16 |         static bool dumped_before;
         |                     ^~~~~~~~~~~~~
   arch/x86/kernel/unwind_orc.c:531:25: note: in expansion of macro 'orc_warn_current'
     531 |                         orc_warn_current("missing R10 value at %pB\n",
         |                         ^~~~~~~~~~~~~~~~
   arch/x86/kernel/unwind_orc.c:421:13: warning: 'deref_stack_iret_regs' defined but not used [-Wunused-function]
     421 | static bool deref_stack_iret_regs(struct unwind_state *state, unsigned long addr,
         |             ^~~~~~~~~~~~~~~~~~~~~
   arch/x86/kernel/unwind_orc.c:405:13: warning: 'deref_stack_regs' defined but not used [-Wunused-function]
     405 | static bool deref_stack_regs(struct unwind_state *state, unsigned long addr,
         |             ^~~~~~~~~~~~~~~~
   arch/x86/kernel/unwind_orc.c:395:13: warning: 'deref_stack_reg' defined but not used [-Wunused-function]
     395 | static bool deref_stack_reg(struct unwind_state *state, unsigned long addr,
         |             ^~~~~~~~~~~~~~~
   arch/x86/kernel/unwind_orc.c:42:13: warning: 'unwind_dump' defined but not used [-Wunused-function]
      42 | static void unwind_dump(struct unwind_state *state)
         |             ^~~~~~~~~~~
   cc1: some warnings being treated as errors


vim +17 arch/x86/kernel/unwind_orc.c

ee9f8fce996408 Josh Poimboeuf 2017-07-24  10  
ee9f8fce996408 Josh Poimboeuf 2017-07-24  11  #define orc_warn(fmt, ...) \
b08418b5483125 Josh Poimboeuf 2020-04-25  12  	printk_deferred_once(KERN_WARNING "WARNING: " fmt, ##__VA_ARGS__)
b08418b5483125 Josh Poimboeuf 2020-04-25  13  
b08418b5483125 Josh Poimboeuf 2020-04-25  14  #define orc_warn_current(args...)					\
b08418b5483125 Josh Poimboeuf 2020-04-25  15  ({									\
3295e738f5b51f Josh Poimboeuf 2022-08-15 @16  	static bool dumped_before;
b59cc97674c947 Josh Poimboeuf 2021-02-05 @17  	if (state->task == current && !state->error)			\
b08418b5483125 Josh Poimboeuf 2020-04-25 @18  		orc_warn(args);						\
3295e738f5b51f Josh Poimboeuf 2022-08-15 @19  		if (unwind_debug && !dumped_before)			\
3295e738f5b51f Josh Poimboeuf 2022-08-15  20  			unwind_dump(state);				\
3295e738f5b51f Josh Poimboeuf 2022-08-15 @21  		dumped_before = true;					\
3295e738f5b51f Josh Poimboeuf 2022-08-15 @22  	}								\
b08418b5483125 Josh Poimboeuf 2020-04-25 @23  })
ee9f8fce996408 Josh Poimboeuf 2017-07-24  24
diff mbox series

Patch

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index cc3ea8febc62..85d48f6052fd 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -6317,6 +6317,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/kernel/unwind_orc.c b/arch/x86/kernel/unwind_orc.c
index 38185aedf7d1..c539ca39e9f4 100644
--- a/arch/x86/kernel/unwind_orc.c
+++ b/arch/x86/kernel/unwind_orc.c
@@ -13,8 +13,13 @@ 
 
 #define orc_warn_current(args...)					\
 ({									\
+	static bool dumped_before;
 	if (state->task == current && !state->error)			\
 		orc_warn(args);						\
+		if (unwind_debug && !dumped_before)			\
+			unwind_dump(state);				\
+		dumped_before = true;					\
+	}								\
 })
 
 extern int __start_orc_unwind_ip[];
@@ -23,8 +28,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;