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

um: Add support for CONFIG_STACKTRACE

Add stacktrace support for User Mode Linux

Signed-off-by: Daniel Walter <dwalter@google.com>
Signed-off-by: Richard Weinberger <richard@nod.at>

authored by

Daniel Walter and committed by
Richard Weinberger
970e51fe 2a236122

+144 -55
+2 -1
arch/um/Kconfig.common
··· 39 39 40 40 config STACKTRACE_SUPPORT 41 41 bool 42 - default n 42 + default y 43 + select STACKTRACE 43 44 44 45 config GENERIC_CALIBRATE_DELAY 45 46 bool
+42
arch/um/include/asm/stacktrace.h
··· 1 + #ifndef _ASM_UML_STACKTRACE_H 2 + #define _ASM_UML_STACKTRACE_H 3 + 4 + #include <linux/uaccess.h> 5 + #include <linux/ptrace.h> 6 + 7 + struct stack_frame { 8 + struct stack_frame *next_frame; 9 + unsigned long return_address; 10 + }; 11 + 12 + struct stacktrace_ops { 13 + void (*address)(void *data, unsigned long address, int reliable); 14 + }; 15 + 16 + #ifdef CONFIG_FRAME_POINTER 17 + static inline unsigned long 18 + get_frame_pointer(struct task_struct *task, struct pt_regs *segv_regs) 19 + { 20 + if (!task || task == current) 21 + return segv_regs ? PT_REGS_BP(segv_regs) : current_bp(); 22 + return KSTK_EBP(task); 23 + } 24 + #else 25 + static inline unsigned long 26 + get_frame_pointer(struct task_struct *task, struct pt_regs *segv_regs) 27 + { 28 + return 0; 29 + } 30 + #endif 31 + 32 + static inline unsigned long 33 + *get_stack_pointer(struct task_struct *task, struct pt_regs *segv_regs) 34 + { 35 + if (!task || task == current) 36 + return segv_regs ? (unsigned long *)PT_REGS_SP(segv_regs) : current_sp(); 37 + return (unsigned long *)KSTK_ESP(task); 38 + } 39 + 40 + void dump_trace(struct task_struct *tsk, const struct stacktrace_ops *ops, void *data); 41 + 42 + #endif /* _ASM_UML_STACKTRACE_H */
+1
arch/um/kernel/Makefile
··· 19 19 obj-$(CONFIG_GPROF) += gprof_syms.o 20 20 obj-$(CONFIG_GCOV) += gmon_syms.o 21 21 obj-$(CONFIG_EARLY_PRINTK) += early_printk.o 22 + obj-$(CONFIG_STACKTRACE) += stacktrace.o 22 23 23 24 USER_OBJS := config.o 24 25
+80
arch/um/kernel/stacktrace.c
··· 1 + /* 2 + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 3 + * Copyright (C) 2013 Richard Weinberger <richard@nod.at> 4 + * Copyright (C) 2014 Google Inc., Author: Daniel Walter <dwalter@google.com> 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License version 2 as 8 + * published by the Free Software Foundation. 9 + */ 10 + 11 + #include <linux/kallsyms.h> 12 + #include <linux/kernel.h> 13 + #include <linux/sched.h> 14 + #include <linux/stacktrace.h> 15 + #include <linux/module.h> 16 + #include <linux/uaccess.h> 17 + #include <asm/stacktrace.h> 18 + 19 + void dump_trace(struct task_struct *tsk, 20 + const struct stacktrace_ops *ops, 21 + void *data) 22 + { 23 + int reliable = 0; 24 + unsigned long *sp, bp, addr; 25 + struct pt_regs *segv_regs = tsk->thread.segv_regs; 26 + struct stack_frame *frame; 27 + 28 + bp = get_frame_pointer(tsk, segv_regs); 29 + sp = get_stack_pointer(tsk, segv_regs); 30 + 31 + frame = (struct stack_frame *)bp; 32 + while (((long) sp & (THREAD_SIZE-1)) != 0) { 33 + addr = *sp; 34 + if (__kernel_text_address(addr)) { 35 + reliable = 0; 36 + if ((unsigned long) sp == bp + sizeof(long)) { 37 + frame = frame ? frame->next_frame : NULL; 38 + bp = (unsigned long)frame; 39 + reliable = 1; 40 + } 41 + ops->address(data, addr, reliable); 42 + } 43 + sp++; 44 + } 45 + } 46 + 47 + static void save_addr(void *data, unsigned long address, int reliable) 48 + { 49 + struct stack_trace *trace = data; 50 + 51 + if (!reliable) 52 + return; 53 + if (trace->nr_entries >= trace->max_entries) 54 + return; 55 + 56 + trace->entries[trace->nr_entries++] = address; 57 + } 58 + 59 + static const struct stacktrace_ops dump_ops = { 60 + .address = save_addr 61 + }; 62 + 63 + static void __save_stack_trace(struct task_struct *tsk, struct stack_trace *trace) 64 + { 65 + dump_trace(tsk, &dump_ops, trace); 66 + if (trace->nr_entries < trace->max_entries) 67 + trace->entries[trace->nr_entries++] = ULONG_MAX; 68 + } 69 + 70 + void save_stack_trace(struct stack_trace *trace) 71 + { 72 + __save_stack_trace(current, trace); 73 + } 74 + EXPORT_SYMBOL_GPL(save_stack_trace); 75 + 76 + void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) 77 + { 78 + __save_stack_trace(tsk, trace); 79 + } 80 + EXPORT_SYMBOL_GPL(save_stack_trace_tsk);
+19 -54
arch/um/kernel/sysrq.c
··· 12 12 #include <linux/module.h> 13 13 #include <linux/sched.h> 14 14 #include <asm/sysrq.h> 15 + #include <asm/stacktrace.h> 15 16 #include <os.h> 16 17 17 - struct stack_frame { 18 - struct stack_frame *next_frame; 19 - unsigned long return_address; 18 + static void _print_addr(void *data, unsigned long address, int reliable) 19 + { 20 + pr_info(" [<%08lx>]", address); 21 + pr_cont(" %s", reliable ? "" : "? "); 22 + print_symbol("%s", address); 23 + pr_cont("\n"); 24 + } 25 + 26 + static const struct stacktrace_ops stackops = { 27 + .address = _print_addr 20 28 }; 21 - 22 - static void do_stack_trace(unsigned long *sp, unsigned long bp) 23 - { 24 - int reliable; 25 - unsigned long addr; 26 - struct stack_frame *frame = (struct stack_frame *)bp; 27 - 28 - printk(KERN_INFO "Call Trace:\n"); 29 - while (((long) sp & (THREAD_SIZE-1)) != 0) { 30 - addr = *sp; 31 - if (__kernel_text_address(addr)) { 32 - reliable = 0; 33 - if ((unsigned long) sp == bp + sizeof(long)) { 34 - frame = frame ? frame->next_frame : NULL; 35 - bp = (unsigned long)frame; 36 - reliable = 1; 37 - } 38 - 39 - printk(KERN_INFO " [<%08lx>]", addr); 40 - printk(KERN_CONT " %s", reliable ? "" : "? "); 41 - print_symbol(KERN_CONT "%s", addr); 42 - printk(KERN_CONT "\n"); 43 - } 44 - sp++; 45 - } 46 - printk(KERN_INFO "\n"); 47 - } 48 - 49 - static unsigned long get_frame_pointer(struct task_struct *task, 50 - struct pt_regs *segv_regs) 51 - { 52 - if (!task || task == current) 53 - return segv_regs ? PT_REGS_BP(segv_regs) : current_bp(); 54 - else 55 - return KSTK_EBP(task); 56 - } 57 - 58 - static unsigned long *get_stack_pointer(struct task_struct *task, 59 - struct pt_regs *segv_regs) 60 - { 61 - if (!task || task == current) 62 - return segv_regs ? (unsigned long *)PT_REGS_SP(segv_regs) : current_sp(); 63 - else 64 - return (unsigned long *)KSTK_ESP(task); 65 - } 66 29 67 30 void show_stack(struct task_struct *task, unsigned long *stack) 68 31 { ··· 34 71 int i; 35 72 36 73 if (!segv_regs && os_is_signal_stack()) { 37 - printk(KERN_ERR "Received SIGSEGV in SIGSEGV handler," 74 + pr_err("Received SIGSEGV in SIGSEGV handler," 38 75 " aborting stack trace!\n"); 39 76 return; 40 77 } ··· 46 83 if (!stack) 47 84 sp = get_stack_pointer(task, segv_regs); 48 85 49 - printk(KERN_INFO "Stack:\n"); 86 + pr_info("Stack:\n"); 50 87 stack = sp; 51 88 for (i = 0; i < 3 * STACKSLOTS_PER_LINE; i++) { 52 89 if (kstack_end(stack)) 53 90 break; 54 91 if (i && ((i % STACKSLOTS_PER_LINE) == 0)) 55 - printk(KERN_CONT "\n"); 56 - printk(KERN_CONT " %08lx", *stack++); 92 + pr_cont("\n"); 93 + pr_cont(" %08lx", *stack++); 57 94 } 58 - printk(KERN_CONT "\n"); 95 + pr_cont("\n"); 59 96 60 - do_stack_trace(sp, bp); 97 + pr_info("Call Trace:\n"); 98 + dump_trace(current, &stackops, NULL); 99 + pr_info("\n"); 61 100 }