Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0 2 : : /* 3 : : * Provide a default dump_stack() function for architectures 4 : : * which don't implement their own. 5 : : */ 6 : : 7 : : #include <linux/kernel.h> 8 : : #include <linux/export.h> 9 : : #include <linux/sched.h> 10 : : #include <linux/sched/debug.h> 11 : : #include <linux/smp.h> 12 : : #include <linux/atomic.h> 13 : : #include <linux/kexec.h> 14 : : #include <linux/utsname.h> 15 : : 16 : : static char dump_stack_arch_desc_str[128]; 17 : : 18 : : /** 19 : : * dump_stack_set_arch_desc - set arch-specific str to show with task dumps 20 : : * @fmt: printf-style format string 21 : : * @...: arguments for the format string 22 : : * 23 : : * The configured string will be printed right after utsname during task 24 : : * dumps. Usually used to add arch-specific system identifiers. If an 25 : : * arch wants to make use of such an ID string, it should initialize this 26 : : * as soon as possible during boot. 27 : : */ 28 : 3 : void __init dump_stack_set_arch_desc(const char *fmt, ...) 29 : : { 30 : : va_list args; 31 : : 32 : 3 : va_start(args, fmt); 33 : 3 : vsnprintf(dump_stack_arch_desc_str, sizeof(dump_stack_arch_desc_str), 34 : : fmt, args); 35 : 3 : va_end(args); 36 : 3 : } 37 : : 38 : : /** 39 : : * dump_stack_print_info - print generic debug info for dump_stack() 40 : : * @log_lvl: log level 41 : : * 42 : : * Arch-specific dump_stack() implementations can use this function to 43 : : * print out the same debug information as the generic dump_stack(). 44 : : */ 45 : 1 : void dump_stack_print_info(const char *log_lvl) 46 : : { 47 : 1 : printk("%sCPU: %d PID: %d Comm: %.20s %s%s %s %.*s\n", 48 : 1 : log_lvl, raw_smp_processor_id(), current->pid, current->comm, 49 : : kexec_crash_loaded() ? "Kdump: loaded " : "", 50 : : print_tainted(), 51 : : init_utsname()->release, 52 : 1 : (int)strcspn(init_utsname()->version, " "), 53 : : init_utsname()->version); 54 : : 55 : 1 : if (dump_stack_arch_desc_str[0] != '\0') 56 : 1 : printk("%sHardware name: %s\n", 57 : : log_lvl, dump_stack_arch_desc_str); 58 : : 59 : 1 : print_worker_info(log_lvl, current); 60 : 1 : } 61 : : 62 : : /** 63 : : * show_regs_print_info - print generic debug info for show_regs() 64 : : * @log_lvl: log level 65 : : * 66 : : * show_regs() implementations can use this function to print out generic 67 : : * debug information. 68 : : */ 69 : 0 : void show_regs_print_info(const char *log_lvl) 70 : : { 71 : 0 : dump_stack_print_info(log_lvl); 72 : 0 : } 73 : : 74 : 1 : static void __dump_stack(void) 75 : : { 76 : 1 : dump_stack_print_info(KERN_DEFAULT); 77 : 1 : show_stack(NULL, NULL); 78 : 1 : } 79 : : 80 : : /** 81 : : * dump_stack - dump the current task information and its stack trace 82 : : * 83 : : * Architectures can override this implementation by implementing its own. 84 : : */ 85 : : #ifdef CONFIG_SMP 86 : : static atomic_t dump_lock = ATOMIC_INIT(-1); 87 : : 88 : 1 : asmlinkage __visible void dump_stack(void) 89 : : { 90 : : unsigned long flags; 91 : : int was_locked; 92 : : int old; 93 : : int cpu; 94 : : 95 : : /* 96 : : * Permit this cpu to perform nested stack dumps while serialising 97 : : * against other CPUs 98 : : */ 99 : : retry: 100 : 1 : local_irq_save(flags); 101 : 1 : cpu = smp_processor_id(); 102 : 1 : old = atomic_cmpxchg(&dump_lock, -1, cpu); 103 : 1 : if (old == -1) { 104 : : was_locked = 0; 105 : 0 : } else if (old == cpu) { 106 : : was_locked = 1; 107 : : } else { 108 : 0 : local_irq_restore(flags); 109 : : /* 110 : : * Wait for the lock to release before jumping to 111 : : * atomic_cmpxchg() in order to mitigate the thundering herd 112 : : * problem. 113 : : */ 114 : 0 : do { cpu_relax(); } while (atomic_read(&dump_lock) != -1); 115 : : goto retry; 116 : : } 117 : : 118 : 1 : __dump_stack(); 119 : : 120 : 1 : if (!was_locked) 121 : : atomic_set(&dump_lock, -1); 122 : : 123 : 1 : local_irq_restore(flags); 124 : 1 : } 125 : : #else 126 : : asmlinkage __visible void dump_stack(void) 127 : : { 128 : : __dump_stack(); 129 : : } 130 : : #endif 131 : : EXPORT_SYMBOL(dump_stack);