Commit 1df0f0ff7e56f6dcb1351b9490d55ebf91ff4bd8

Authored by Atsushi Nemoto
Committed by Ralf Baechle
1 parent eae6c0da9d

[MIPS] lockdep: Add STACKTRACE_SUPPORT and enable LOCKDEP_SUPPORT

Implement stacktrace interface by using unwind_stack() and enable lockdep
support in Kconfig.

Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

Showing 6 changed files with 168 additions and 34 deletions Side-by-side Diff

... ... @@ -1841,6 +1841,14 @@
1841 1841 bool
1842 1842 default y
1843 1843  
  1844 +config LOCKDEP_SUPPORT
  1845 + bool
  1846 + default y
  1847 +
  1848 +config STACKTRACE_SUPPORT
  1849 + bool
  1850 + default y
  1851 +
1844 1852 source "init/Kconfig"
1845 1853  
1846 1854 menu "Bus options (PCI, PCMCIA, EISA, ISA, TC)"
arch/mips/kernel/Makefile
... ... @@ -11,6 +11,7 @@
11 11 binfmt_irix-objs := irixelf.o irixinv.o irixioctl.o irixsig.o \
12 12 irix5sys.o sysirix.o
13 13  
  14 +obj-$(CONFIG_STACKTRACE) += stacktrace.o
14 15 obj-$(CONFIG_MODULES) += mips_ksyms.o module.o
15 16  
16 17 obj-$(CONFIG_APM) += apm.o
arch/mips/kernel/process.c
... ... @@ -40,6 +40,7 @@
40 40 #include <asm/elf.h>
41 41 #include <asm/isadep.h>
42 42 #include <asm/inst.h>
  43 +#include <asm/stacktrace.h>
43 44 #ifdef CONFIG_MIPS_MT_SMTC
44 45 #include <asm/mipsmtregs.h>
45 46 extern void smtc_idle_loop_hook(void);
arch/mips/kernel/stacktrace.c
  1 +/*
  2 + * arch/mips/kernel/stacktrace.c
  3 + *
  4 + * Stack trace management functions
  5 + *
  6 + * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
  7 + */
  8 +#include <linux/sched.h>
  9 +#include <linux/stacktrace.h>
  10 +#include <asm/stacktrace.h>
  11 +
  12 +/*
  13 + * Save stack-backtrace addresses into a stack_trace buffer:
  14 + */
  15 +static void save_raw_context_stack(struct stack_trace *trace,
  16 + unsigned int skip, unsigned long reg29)
  17 +{
  18 + unsigned long *sp = (unsigned long *)reg29;
  19 + unsigned long addr;
  20 +
  21 + while (!kstack_end(sp)) {
  22 + addr = *sp++;
  23 + if (__kernel_text_address(addr)) {
  24 + if (!skip)
  25 + trace->entries[trace->nr_entries++] = addr;
  26 + else
  27 + skip--;
  28 + if (trace->nr_entries >= trace->max_entries)
  29 + break;
  30 + }
  31 + }
  32 +}
  33 +
  34 +static struct pt_regs * save_context_stack(struct stack_trace *trace,
  35 + unsigned int skip, struct task_struct *task, struct pt_regs *regs)
  36 +{
  37 + unsigned long sp = regs->regs[29];
  38 +#ifdef CONFIG_KALLSYMS
  39 + unsigned long ra = regs->regs[31];
  40 + unsigned long pc = regs->cp0_epc;
  41 + extern void ret_from_irq(void);
  42 +
  43 + if (raw_show_trace || !__kernel_text_address(pc)) {
  44 + save_raw_context_stack(trace, skip, sp);
  45 + return NULL;
  46 + }
  47 + do {
  48 + if (!skip)
  49 + trace->entries[trace->nr_entries++] = pc;
  50 + else
  51 + skip--;
  52 + if (trace->nr_entries >= trace->max_entries)
  53 + break;
  54 + /*
  55 + * If we reached the bottom of interrupt context,
  56 + * return saved pt_regs.
  57 + */
  58 + if (pc == (unsigned long)ret_from_irq) {
  59 + unsigned long stack_page =
  60 + (unsigned long)task_stack_page(task);
  61 + if (!stack_page ||
  62 + sp < stack_page ||
  63 + sp > stack_page + THREAD_SIZE - 32)
  64 + break;
  65 + return (struct pt_regs *)sp;
  66 + }
  67 + pc = unwind_stack(task, &sp, pc, ra);
  68 + ra = 0;
  69 + } while (pc);
  70 +#else
  71 + save_raw_context_stack(sp);
  72 +#endif
  73 +
  74 + return NULL;
  75 +}
  76 +
  77 +/*
  78 + * Save stack-backtrace addresses into a stack_trace buffer.
  79 + * If all_contexts is set, all contexts (hardirq, softirq and process)
  80 + * are saved. If not set then only the current context is saved.
  81 + */
  82 +void save_stack_trace(struct stack_trace *trace,
  83 + struct task_struct *task, int all_contexts,
  84 + unsigned int skip)
  85 +{
  86 + struct pt_regs dummyregs;
  87 + struct pt_regs *regs = &dummyregs;
  88 +
  89 + WARN_ON(trace->nr_entries || !trace->max_entries);
  90 +
  91 + if (task && task != current) {
  92 + regs->regs[29] = task->thread.reg29;
  93 + regs->regs[31] = 0;
  94 + regs->cp0_epc = task->thread.reg31;
  95 + } else {
  96 + if (!task)
  97 + task = current;
  98 + prepare_frametrace(regs);
  99 + }
  100 +
  101 + while (1) {
  102 + regs = save_context_stack(trace, skip, task, regs);
  103 + if (!all_contexts || !regs ||
  104 + trace->nr_entries >= trace->max_entries)
  105 + break;
  106 + trace->entries[trace->nr_entries++] = ULONG_MAX;
  107 + if (trace->nr_entries >= trace->max_entries)
  108 + break;
  109 + skip = 0;
  110 + }
  111 +}
arch/mips/kernel/traps.c
... ... @@ -41,6 +41,7 @@
41 41 #include <asm/mmu_context.h>
42 42 #include <asm/watch.h>
43 43 #include <asm/types.h>
  44 +#include <asm/stacktrace.h>
44 45  
45 46 extern asmlinkage void handle_int(void);
46 47 extern asmlinkage void handle_tlbm(void);
47 48  
48 49  
... ... @@ -92,17 +93,15 @@
92 93 }
93 94  
94 95 #ifdef CONFIG_KALLSYMS
95   -static int raw_show_trace;
  96 +int raw_show_trace;
96 97 static int __init set_raw_show_trace(char *str)
97 98 {
98 99 raw_show_trace = 1;
99 100 return 1;
100 101 }
101 102 __setup("raw_show_trace", set_raw_show_trace);
  103 +#endif
102 104  
103   -extern unsigned long unwind_stack(struct task_struct *task, unsigned long *sp,
104   - unsigned long pc, unsigned long ra);
105   -
106 105 static void show_backtrace(struct task_struct *task, struct pt_regs *regs)
107 106 {
108 107 unsigned long sp = regs->regs[29];
... ... @@ -121,9 +120,6 @@
121 120 } while (pc);
122 121 printk("\n");
123 122 }
124   -#else
125   -#define show_backtrace(task, r) show_raw_backtrace((r)->regs[29]);
126   -#endif
127 123  
128 124 /*
129 125 * This routine abuses get_user()/put_user() to reference pointers
... ... @@ -158,28 +154,6 @@
158 154 show_backtrace(task, regs);
159 155 }
160 156  
161   -static __always_inline void prepare_frametrace(struct pt_regs *regs)
162   -{
163   - __asm__ __volatile__(
164   - ".set push\n\t"
165   - ".set noat\n\t"
166   -#ifdef CONFIG_64BIT
167   - "1: dla $1, 1b\n\t"
168   - "sd $1, %0\n\t"
169   - "sd $29, %1\n\t"
170   - "sd $31, %2\n\t"
171   -#else
172   - "1: la $1, 1b\n\t"
173   - "sw $1, %0\n\t"
174   - "sw $29, %1\n\t"
175   - "sw $31, %2\n\t"
176   -#endif
177   - ".set pop\n\t"
178   - : "=m" (regs->cp0_epc),
179   - "=m" (regs->regs[29]), "=m" (regs->regs[31])
180   - : : "memory");
181   -}
182   -
183 157 void show_stack(struct task_struct *task, unsigned long *sp)
184 158 {
185 159 struct pt_regs regs;
... ... @@ -206,11 +180,6 @@
206 180 {
207 181 struct pt_regs regs;
208 182  
209   - /*
210   - * Remove any garbage that may be in regs (specially func
211   - * addresses) to avoid show_raw_backtrace() to report them
212   - */
213   - memset(&regs, 0, sizeof(regs));
214 183 prepare_frametrace(&regs);
215 184 show_backtrace(current, &regs);
216 185 }
include/asm-mips/stacktrace.h
  1 +#ifndef _ASM_STACKTRACE_H
  2 +#define _ASM_STACKTRACE_H
  3 +
  4 +#include <asm/ptrace.h>
  5 +
  6 +#ifdef CONFIG_KALLSYMS
  7 +extern int raw_show_trace;
  8 +extern unsigned long unwind_stack(struct task_struct *task, unsigned long *sp,
  9 + unsigned long pc, unsigned long ra);
  10 +#else
  11 +#define raw_show_trace 1
  12 +#define unwind_stack(task, sp, pc, ra) 0
  13 +#endif
  14 +
  15 +static __always_inline void prepare_frametrace(struct pt_regs *regs)
  16 +{
  17 +#ifndef CONFIG_KALLSYMS
  18 + /*
  19 + * Remove any garbage that may be in regs (specially func
  20 + * addresses) to avoid show_raw_backtrace() to report them
  21 + */
  22 + memset(regs, 0, sizeof(*regs));
  23 +#endif
  24 + __asm__ __volatile__(
  25 + ".set push\n\t"
  26 + ".set noat\n\t"
  27 +#ifdef CONFIG_64BIT
  28 + "1: dla $1, 1b\n\t"
  29 + "sd $1, %0\n\t"
  30 + "sd $29, %1\n\t"
  31 + "sd $31, %2\n\t"
  32 +#else
  33 + "1: la $1, 1b\n\t"
  34 + "sw $1, %0\n\t"
  35 + "sw $29, %1\n\t"
  36 + "sw $31, %2\n\t"
  37 +#endif
  38 + ".set pop\n\t"
  39 + : "=m" (regs->cp0_epc),
  40 + "=m" (regs->regs[29]), "=m" (regs->regs[31])
  41 + : : "memory");
  42 +}
  43 +
  44 +#endif /* _ASM_STACKTRACE_H */