diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/trace/trace_stack.c | 90 |
1 files changed, 73 insertions, 17 deletions
diff --git a/kernel/trace/trace_stack.c b/kernel/trace/trace_stack.c index 4d1e522e3fe8..74c5d9a3afae 100644 --- a/kernel/trace/trace_stack.c +++ b/kernel/trace/trace_stack.c | |||
@@ -16,8 +16,10 @@ | |||
16 | 16 | ||
17 | #define STACK_TRACE_ENTRIES 500 | 17 | #define STACK_TRACE_ENTRIES 500 |
18 | 18 | ||
19 | static unsigned long stack_dump_trace[STACK_TRACE_ENTRIES] = | 19 | static unsigned long stack_dump_trace[STACK_TRACE_ENTRIES+1] = |
20 | { [0 ... (STACK_TRACE_ENTRIES-1)] = ULONG_MAX }; | 20 | { [0 ... (STACK_TRACE_ENTRIES)] = ULONG_MAX }; |
21 | static unsigned stack_dump_index[STACK_TRACE_ENTRIES]; | ||
22 | |||
21 | static struct stack_trace max_stack_trace = { | 23 | static struct stack_trace max_stack_trace = { |
22 | .max_entries = STACK_TRACE_ENTRIES, | 24 | .max_entries = STACK_TRACE_ENTRIES, |
23 | .entries = stack_dump_trace, | 25 | .entries = stack_dump_trace, |
@@ -32,8 +34,9 @@ static DEFINE_PER_CPU(int, trace_active); | |||
32 | 34 | ||
33 | static inline void check_stack(void) | 35 | static inline void check_stack(void) |
34 | { | 36 | { |
35 | unsigned long this_size; | 37 | unsigned long this_size, flags; |
36 | unsigned long flags; | 38 | unsigned long *p, *top, *start; |
39 | int i; | ||
37 | 40 | ||
38 | this_size = ((unsigned long)&this_size) & (THREAD_SIZE-1); | 41 | this_size = ((unsigned long)&this_size) & (THREAD_SIZE-1); |
39 | this_size = THREAD_SIZE - this_size; | 42 | this_size = THREAD_SIZE - this_size; |
@@ -51,10 +54,42 @@ static inline void check_stack(void) | |||
51 | max_stack_size = this_size; | 54 | max_stack_size = this_size; |
52 | 55 | ||
53 | max_stack_trace.nr_entries = 0; | 56 | max_stack_trace.nr_entries = 0; |
54 | max_stack_trace.skip = 1; | 57 | max_stack_trace.skip = 3; |
55 | 58 | ||
56 | save_stack_trace(&max_stack_trace); | 59 | save_stack_trace(&max_stack_trace); |
57 | 60 | ||
61 | /* | ||
62 | * Now find where in the stack these are. | ||
63 | */ | ||
64 | i = 0; | ||
65 | start = &this_size; | ||
66 | top = (unsigned long *) | ||
67 | (((unsigned long)start & ~(THREAD_SIZE-1)) + THREAD_SIZE); | ||
68 | |||
69 | /* | ||
70 | * Loop through all the entries. One of the entries may | ||
71 | * for some reason be missed on the stack, so we may | ||
72 | * have to account for them. If they are all there, this | ||
73 | * loop will only happen once. This code only takes place | ||
74 | * on a new max, so it is far from a fast path. | ||
75 | */ | ||
76 | while (i < max_stack_trace.nr_entries) { | ||
77 | |||
78 | stack_dump_index[i] = this_size; | ||
79 | p = start; | ||
80 | |||
81 | for (; p < top && i < max_stack_trace.nr_entries; p++) { | ||
82 | if (*p == stack_dump_trace[i]) { | ||
83 | this_size = stack_dump_index[i++] = | ||
84 | (top - p) * sizeof(unsigned long); | ||
85 | /* Start the search from here */ | ||
86 | start = p + 1; | ||
87 | } | ||
88 | } | ||
89 | |||
90 | i++; | ||
91 | } | ||
92 | |||
58 | out: | 93 | out: |
59 | __raw_spin_unlock(&max_stack_lock); | 94 | __raw_spin_unlock(&max_stack_lock); |
60 | raw_local_irq_restore(flags); | 95 | raw_local_irq_restore(flags); |
@@ -145,22 +180,24 @@ static struct file_operations stack_max_size_fops = { | |||
145 | static void * | 180 | static void * |
146 | t_next(struct seq_file *m, void *v, loff_t *pos) | 181 | t_next(struct seq_file *m, void *v, loff_t *pos) |
147 | { | 182 | { |
148 | unsigned long *t = m->private; | 183 | long i = (long)m->private; |
149 | 184 | ||
150 | (*pos)++; | 185 | (*pos)++; |
151 | 186 | ||
152 | if (!t || *t == ULONG_MAX) | 187 | i++; |
188 | |||
189 | if (i >= max_stack_trace.nr_entries || | ||
190 | stack_dump_trace[i] == ULONG_MAX) | ||
153 | return NULL; | 191 | return NULL; |
154 | 192 | ||
155 | t++; | 193 | m->private = (void *)i; |
156 | m->private = t; | ||
157 | 194 | ||
158 | return t; | 195 | return &m->private; |
159 | } | 196 | } |
160 | 197 | ||
161 | static void *t_start(struct seq_file *m, loff_t *pos) | 198 | static void *t_start(struct seq_file *m, loff_t *pos) |
162 | { | 199 | { |
163 | unsigned long *t = m->private; | 200 | void *t = &m->private; |
164 | loff_t l = 0; | 201 | loff_t l = 0; |
165 | 202 | ||
166 | local_irq_disable(); | 203 | local_irq_disable(); |
@@ -178,14 +215,15 @@ static void t_stop(struct seq_file *m, void *p) | |||
178 | local_irq_enable(); | 215 | local_irq_enable(); |
179 | } | 216 | } |
180 | 217 | ||
181 | static int trace_lookup_stack(struct seq_file *m, unsigned long addr) | 218 | static int trace_lookup_stack(struct seq_file *m, long i) |
182 | { | 219 | { |
220 | unsigned long addr = stack_dump_trace[i]; | ||
183 | #ifdef CONFIG_KALLSYMS | 221 | #ifdef CONFIG_KALLSYMS |
184 | char str[KSYM_SYMBOL_LEN]; | 222 | char str[KSYM_SYMBOL_LEN]; |
185 | 223 | ||
186 | sprint_symbol(str, addr); | 224 | sprint_symbol(str, addr); |
187 | 225 | ||
188 | return seq_printf(m, "[<%p>] %s\n", (void*)addr, str); | 226 | return seq_printf(m, "%s\n", str); |
189 | #else | 227 | #else |
190 | return seq_printf(m, "%p\n", (void*)addr); | 228 | return seq_printf(m, "%p\n", (void*)addr); |
191 | #endif | 229 | #endif |
@@ -193,12 +231,30 @@ static int trace_lookup_stack(struct seq_file *m, unsigned long addr) | |||
193 | 231 | ||
194 | static int t_show(struct seq_file *m, void *v) | 232 | static int t_show(struct seq_file *m, void *v) |
195 | { | 233 | { |
196 | unsigned long *t = v; | 234 | long i = *(long *)v; |
235 | int size; | ||
236 | |||
237 | if (i < 0) { | ||
238 | seq_printf(m, " Depth Size Location" | ||
239 | " (%d entries)\n" | ||
240 | " ----- ---- --------\n", | ||
241 | max_stack_trace.nr_entries); | ||
242 | return 0; | ||
243 | } | ||
197 | 244 | ||
198 | if (!t || *t == ULONG_MAX) | 245 | if (i >= max_stack_trace.nr_entries || |
246 | stack_dump_trace[i] == ULONG_MAX) | ||
199 | return 0; | 247 | return 0; |
200 | 248 | ||
201 | trace_lookup_stack(m, *t); | 249 | if (i+1 == max_stack_trace.nr_entries || |
250 | stack_dump_trace[i+1] == ULONG_MAX) | ||
251 | size = stack_dump_index[i]; | ||
252 | else | ||
253 | size = stack_dump_index[i] - stack_dump_index[i+1]; | ||
254 | |||
255 | seq_printf(m, "%3ld) %8d %5d ", i, stack_dump_index[i], size); | ||
256 | |||
257 | trace_lookup_stack(m, i); | ||
202 | 258 | ||
203 | return 0; | 259 | return 0; |
204 | } | 260 | } |
@@ -217,7 +273,7 @@ static int stack_trace_open(struct inode *inode, struct file *file) | |||
217 | ret = seq_open(file, &stack_trace_seq_ops); | 273 | ret = seq_open(file, &stack_trace_seq_ops); |
218 | if (!ret) { | 274 | if (!ret) { |
219 | struct seq_file *m = file->private_data; | 275 | struct seq_file *m = file->private_data; |
220 | m->private = stack_dump_trace; | 276 | m->private = (void *)-1; |
221 | } | 277 | } |
222 | 278 | ||
223 | return ret; | 279 | return ret; |