diff options
| author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2018-01-02 08:46:35 -0500 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2018-01-02 08:46:35 -0500 |
| commit | b6a09416e83ffe4eccfb4ef1b91b3b66483fa810 (patch) | |
| tree | b30f266e85047244dcdb47d5afc134e76aec530d /arch/x86/kernel/dumpstack.c | |
| parent | db809859c8cee415293b830e67178f526d1eb2be (diff) | |
| parent | 30a7acd573899fd8b8ac39236eff6468b195ac7d (diff) | |
Merge 4.15-rc6 into char-misc-next
We want the fixes in here as well.
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'arch/x86/kernel/dumpstack.c')
| -rw-r--r-- | arch/x86/kernel/dumpstack.c | 81 |
1 files changed, 64 insertions, 17 deletions
diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c index f13b4c00a5de..5fa110699ed2 100644 --- a/arch/x86/kernel/dumpstack.c +++ b/arch/x86/kernel/dumpstack.c | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | #include <linux/nmi.h> | 18 | #include <linux/nmi.h> |
| 19 | #include <linux/sysfs.h> | 19 | #include <linux/sysfs.h> |
| 20 | 20 | ||
| 21 | #include <asm/cpu_entry_area.h> | ||
| 21 | #include <asm/stacktrace.h> | 22 | #include <asm/stacktrace.h> |
| 22 | #include <asm/unwind.h> | 23 | #include <asm/unwind.h> |
| 23 | 24 | ||
| @@ -43,6 +44,24 @@ bool in_task_stack(unsigned long *stack, struct task_struct *task, | |||
| 43 | return true; | 44 | return true; |
| 44 | } | 45 | } |
| 45 | 46 | ||
| 47 | bool in_entry_stack(unsigned long *stack, struct stack_info *info) | ||
| 48 | { | ||
| 49 | struct entry_stack *ss = cpu_entry_stack(smp_processor_id()); | ||
| 50 | |||
| 51 | void *begin = ss; | ||
| 52 | void *end = ss + 1; | ||
| 53 | |||
| 54 | if ((void *)stack < begin || (void *)stack >= end) | ||
| 55 | return false; | ||
| 56 | |||
| 57 | info->type = STACK_TYPE_ENTRY; | ||
| 58 | info->begin = begin; | ||
| 59 | info->end = end; | ||
| 60 | info->next_sp = NULL; | ||
| 61 | |||
| 62 | return true; | ||
| 63 | } | ||
| 64 | |||
| 46 | static void printk_stack_address(unsigned long address, int reliable, | 65 | static void printk_stack_address(unsigned long address, int reliable, |
| 47 | char *log_lvl) | 66 | char *log_lvl) |
| 48 | { | 67 | { |
| @@ -50,6 +69,28 @@ static void printk_stack_address(unsigned long address, int reliable, | |||
| 50 | printk("%s %s%pB\n", log_lvl, reliable ? "" : "? ", (void *)address); | 69 | printk("%s %s%pB\n", log_lvl, reliable ? "" : "? ", (void *)address); |
| 51 | } | 70 | } |
| 52 | 71 | ||
| 72 | void show_iret_regs(struct pt_regs *regs) | ||
| 73 | { | ||
| 74 | printk(KERN_DEFAULT "RIP: %04x:%pS\n", (int)regs->cs, (void *)regs->ip); | ||
| 75 | printk(KERN_DEFAULT "RSP: %04x:%016lx EFLAGS: %08lx", (int)regs->ss, | ||
| 76 | regs->sp, regs->flags); | ||
| 77 | } | ||
| 78 | |||
| 79 | static void show_regs_safe(struct stack_info *info, struct pt_regs *regs) | ||
| 80 | { | ||
| 81 | if (on_stack(info, regs, sizeof(*regs))) | ||
| 82 | __show_regs(regs, 0); | ||
| 83 | else if (on_stack(info, (void *)regs + IRET_FRAME_OFFSET, | ||
| 84 | IRET_FRAME_SIZE)) { | ||
| 85 | /* | ||
| 86 | * When an interrupt or exception occurs in entry code, the | ||
| 87 | * full pt_regs might not have been saved yet. In that case | ||
| 88 | * just print the iret frame. | ||
| 89 | */ | ||
| 90 | show_iret_regs(regs); | ||
| 91 | } | ||
| 92 | } | ||
| 93 | |||
| 53 | void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, | 94 | void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, |
| 54 | unsigned long *stack, char *log_lvl) | 95 | unsigned long *stack, char *log_lvl) |
| 55 | { | 96 | { |
| @@ -71,31 +112,35 @@ void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, | |||
| 71 | * - task stack | 112 | * - task stack |
| 72 | * - interrupt stack | 113 | * - interrupt stack |
| 73 | * - HW exception stacks (double fault, nmi, debug, mce) | 114 | * - HW exception stacks (double fault, nmi, debug, mce) |
| 115 | * - entry stack | ||
| 74 | * | 116 | * |
| 75 | * x86-32 can have up to three stacks: | 117 | * x86-32 can have up to four stacks: |
| 76 | * - task stack | 118 | * - task stack |
| 77 | * - softirq stack | 119 | * - softirq stack |
| 78 | * - hardirq stack | 120 | * - hardirq stack |
| 121 | * - entry stack | ||
| 79 | */ | 122 | */ |
| 80 | for (regs = NULL; stack; stack = PTR_ALIGN(stack_info.next_sp, sizeof(long))) { | 123 | for (regs = NULL; stack; stack = PTR_ALIGN(stack_info.next_sp, sizeof(long))) { |
| 81 | const char *stack_name; | 124 | const char *stack_name; |
| 82 | 125 | ||
| 83 | /* | 126 | if (get_stack_info(stack, task, &stack_info, &visit_mask)) { |
| 84 | * If we overflowed the task stack into a guard page, jump back | 127 | /* |
| 85 | * to the bottom of the usable stack. | 128 | * We weren't on a valid stack. It's possible that |
| 86 | */ | 129 | * we overflowed a valid stack into a guard page. |
| 87 | if (task_stack_page(task) - (void *)stack < PAGE_SIZE) | 130 | * See if the next page up is valid so that we can |
| 88 | stack = task_stack_page(task); | 131 | * generate some kind of backtrace if this happens. |
| 89 | 132 | */ | |
| 90 | if (get_stack_info(stack, task, &stack_info, &visit_mask)) | 133 | stack = (unsigned long *)PAGE_ALIGN((unsigned long)stack); |
| 91 | break; | 134 | if (get_stack_info(stack, task, &stack_info, &visit_mask)) |
| 135 | break; | ||
| 136 | } | ||
| 92 | 137 | ||
| 93 | stack_name = stack_type_name(stack_info.type); | 138 | stack_name = stack_type_name(stack_info.type); |
| 94 | if (stack_name) | 139 | if (stack_name) |
| 95 | printk("%s <%s>\n", log_lvl, stack_name); | 140 | printk("%s <%s>\n", log_lvl, stack_name); |
| 96 | 141 | ||
| 97 | if (regs && on_stack(&stack_info, regs, sizeof(*regs))) | 142 | if (regs) |
| 98 | __show_regs(regs, 0); | 143 | show_regs_safe(&stack_info, regs); |
| 99 | 144 | ||
| 100 | /* | 145 | /* |
| 101 | * Scan the stack, printing any text addresses we find. At the | 146 | * Scan the stack, printing any text addresses we find. At the |
| @@ -119,7 +164,7 @@ void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, | |||
| 119 | 164 | ||
| 120 | /* | 165 | /* |
| 121 | * Don't print regs->ip again if it was already printed | 166 | * Don't print regs->ip again if it was already printed |
| 122 | * by __show_regs() below. | 167 | * by show_regs_safe() below. |
| 123 | */ | 168 | */ |
| 124 | if (regs && stack == ®s->ip) | 169 | if (regs && stack == ®s->ip) |
| 125 | goto next; | 170 | goto next; |
| @@ -155,8 +200,8 @@ next: | |||
| 155 | 200 | ||
| 156 | /* if the frame has entry regs, print them */ | 201 | /* if the frame has entry regs, print them */ |
| 157 | regs = unwind_get_entry_regs(&state); | 202 | regs = unwind_get_entry_regs(&state); |
| 158 | if (regs && on_stack(&stack_info, regs, sizeof(*regs))) | 203 | if (regs) |
| 159 | __show_regs(regs, 0); | 204 | show_regs_safe(&stack_info, regs); |
| 160 | } | 205 | } |
| 161 | 206 | ||
| 162 | if (stack_name) | 207 | if (stack_name) |
| @@ -252,11 +297,13 @@ int __die(const char *str, struct pt_regs *regs, long err) | |||
| 252 | unsigned long sp; | 297 | unsigned long sp; |
| 253 | #endif | 298 | #endif |
| 254 | printk(KERN_DEFAULT | 299 | printk(KERN_DEFAULT |
| 255 | "%s: %04lx [#%d]%s%s%s%s\n", str, err & 0xffff, ++die_counter, | 300 | "%s: %04lx [#%d]%s%s%s%s%s\n", str, err & 0xffff, ++die_counter, |
| 256 | IS_ENABLED(CONFIG_PREEMPT) ? " PREEMPT" : "", | 301 | IS_ENABLED(CONFIG_PREEMPT) ? " PREEMPT" : "", |
| 257 | IS_ENABLED(CONFIG_SMP) ? " SMP" : "", | 302 | IS_ENABLED(CONFIG_SMP) ? " SMP" : "", |
| 258 | debug_pagealloc_enabled() ? " DEBUG_PAGEALLOC" : "", | 303 | debug_pagealloc_enabled() ? " DEBUG_PAGEALLOC" : "", |
| 259 | IS_ENABLED(CONFIG_KASAN) ? " KASAN" : ""); | 304 | IS_ENABLED(CONFIG_KASAN) ? " KASAN" : "", |
| 305 | IS_ENABLED(CONFIG_PAGE_TABLE_ISOLATION) ? | ||
| 306 | (boot_cpu_has(X86_FEATURE_PTI) ? " PTI" : " NOPTI") : ""); | ||
| 260 | 307 | ||
| 261 | if (notify_die(DIE_OOPS, str, regs, err, | 308 | if (notify_die(DIE_OOPS, str, regs, err, |
| 262 | current->thread.trap_nr, SIGSEGV) == NOTIFY_STOP) | 309 | current->thread.trap_nr, SIGSEGV) == NOTIFY_STOP) |
