Messages in this thread Patch in this message | | | Date | Sat, 23 Feb 2008 13:51:47 +0100 | From | Vegard Nossum <> | Subject | [PATCH] stacktrace: add reliability information to saved stack traces |
| |
Hi again,
This patch is different (probably better?), but touches all users and all architectures implementing stacktrace saving. If you want it, it's here... :-)
Kind regards, Vegard Nossum
From 98d928d337dca6326773d43da90a268e5ff0c098 Mon Sep 17 00:00:00 2001 From: Vegard Nossum <vegardno@ifi.uio.no> Date: Sat, 23 Feb 2008 13:42:56 +0100 Subject: [PATCH] stacktrace: add reliability information to saved stack traces
This will make print_stack_trace() behave more like dump_stack() by saving "unreliable" trace entries and displaying them as such by prepending a question mark in front of the function name.
NOTE: This patch has been compile- and run-tested on x86 platform (which is the only platform supporting unreliable trace entries). No testing has been carried out for the other platforms. End of note.
Signed-off-by: Vegard Nossum <vegardno@ifi.uio.no> --- arch/arm/kernel/stacktrace.c | 2 +- arch/avr32/kernel/stacktrace.c | 2 +- arch/mips/kernel/stacktrace.c | 8 ++++-- arch/s390/kernel/stacktrace.c | 11 +++++---- arch/sh/kernel/stacktrace.c | 6 +++- arch/sparc64/kernel/stacktrace.c | 2 +- arch/x86/kernel/stacktrace.c | 27 +++++++++++---------- include/linux/latencytop.h | 3 ++ include/linux/stacktrace.h | 46 +++++++++++++++++++++++++++++++++++-- kernel/latencytop.c | 6 +--- kernel/lockdep.c | 17 +++++++------ kernel/stacktrace.c | 12 +++++---- lib/fault-inject.c | 7 +---- 13 files changed, 98 insertions(+), 51 deletions(-)
diff --git a/arch/arm/kernel/stacktrace.c b/arch/arm/kernel/stacktrace.c index ae31deb..a354f2d 100644 --- a/arch/arm/kernel/stacktrace.c +++ b/arch/arm/kernel/stacktrace.c @@ -49,7 +49,7 @@ static int save_trace(struct stackframe *frame, void *d) return 0; }
- trace->entries[trace->nr_entries++] = frame->lr; + trace->entries.addr[trace->nr_entries++] = frame->lr;
return trace->nr_entries >= trace->max_entries; } diff --git a/arch/avr32/kernel/stacktrace.c b/arch/avr32/kernel/stacktrace.c index 9a68190..db799ed 100644 --- a/arch/avr32/kernel/stacktrace.c +++ b/arch/avr32/kernel/stacktrace.c @@ -38,7 +38,7 @@ void save_stack_trace(struct stack_trace *trace) if (skip) { skip--; } else { - trace->entries[trace->nr_entries++] = frame->lr; + trace->entries.addr[trace->nr_entries++] = frame->lr; if (trace->nr_entries >= trace->max_entries) break; } diff --git a/arch/mips/kernel/stacktrace.c b/arch/mips/kernel/stacktrace.c index ebd9db8..6f303b3 100644 --- a/arch/mips/kernel/stacktrace.c +++ b/arch/mips/kernel/stacktrace.c @@ -23,8 +23,10 @@ static void save_raw_context_stack(struct stack_trace *trace, if (__kernel_text_address(addr)) { if (trace->skip > 0) trace->skip--; - else - trace->entries[trace->nr_entries++] = addr; + else { + trace->entries.addr[trace->nr_entries++] + = addr; + } if (trace->nr_entries >= trace->max_entries) break; } @@ -50,7 +52,7 @@ static void save_context_stack(struct stack_trace *trace, struct pt_regs *regs) if (trace->skip > 0) trace->skip--; else - trace->entries[trace->nr_entries++] = pc; + trace->entries.addr[trace->nr_entries++] = pc; if (trace->nr_entries >= trace->max_entries) break; pc = unwind_stack(current, &sp, pc, &ra); diff --git a/arch/s390/kernel/stacktrace.c b/arch/s390/kernel/stacktrace.c index 85e46a5..bd62af7 100644 --- a/arch/s390/kernel/stacktrace.c +++ b/arch/s390/kernel/stacktrace.c @@ -28,9 +28,10 @@ static unsigned long save_context_stack(struct stack_trace *trace, sf = (struct stack_frame *)sp; while(1) { addr = sf->gprs[8] & PSW_ADDR_INSN; - if (!trace->skip) - trace->entries[trace->nr_entries++] = addr; - else + if (!trace->skip) { + trace->entries.addr[trace->nr_entries++] + = addr; + } else trace->skip--; if (trace->nr_entries >= trace->max_entries) return sp; @@ -50,7 +51,7 @@ static unsigned long save_context_stack(struct stack_trace *trace, addr = regs->psw.addr & PSW_ADDR_INSN; if (savesched || !in_sched_functions(addr)) { if (!trace->skip) - trace->entries[trace->nr_entries++] = addr; + trace->entries.addr[trace->nr_entries++] = addr; else trace->skip--; } @@ -91,5 +92,5 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) high = (unsigned long) task_pt_regs(tsk); save_context_stack(trace, sp, low, high, 0); if (trace->nr_entries < trace->max_entries) - trace->entries[trace->nr_entries++] = ULONG_MAX; + trace->entries.addr[trace->nr_entries++] = ULONG_MAX; } diff --git a/arch/sh/kernel/stacktrace.c b/arch/sh/kernel/stacktrace.c index d41e561..7d6ff92 100644 --- a/arch/sh/kernel/stacktrace.c +++ b/arch/sh/kernel/stacktrace.c @@ -27,8 +27,10 @@ void save_stack_trace(struct stack_trace *trace) if (__kernel_text_address(addr)) { if (trace->skip > 0) trace->skip--; - else - trace->entries[trace->nr_entries++] = addr; + else { + trace->entries.addr[trace->nr_entries++] + = addr; + } if (trace->nr_entries >= trace->max_entries) break; } diff --git a/arch/sparc64/kernel/stacktrace.c b/arch/sparc64/kernel/stacktrace.c index 47f92a5..95daaac 100644 --- a/arch/sparc64/kernel/stacktrace.c +++ b/arch/sparc64/kernel/stacktrace.c @@ -28,7 +28,7 @@ void save_stack_trace(struct stack_trace *trace) if (trace->skip > 0) trace->skip--; else - trace->entries[trace->nr_entries++] = rw->ins[7]; + trace->entries.addr[trace->nr_entries++] = rw->ins[7];
fp = rw->ins[6] + STACK_BIAS; } while (trace->nr_entries < trace->max_entries); diff --git a/arch/x86/kernel/stacktrace.c b/arch/x86/kernel/stacktrace.c index 02f0f61..d1bacaa 100644 --- a/arch/x86/kernel/stacktrace.c +++ b/arch/x86/kernel/stacktrace.c @@ -25,26 +25,27 @@ static int save_stack_stack(void *data, char *name) static void save_stack_address(void *data, unsigned long addr, int reliable) { struct stack_trace *trace = data; + if (trace->skip > 0) { trace->skip--; return; } - if (trace->nr_entries < trace->max_entries) - trace->entries[trace->nr_entries++] = addr; + + if (trace->nr_entries == trace->max_entries) + return; + + trace->entries.addr[trace->nr_entries] = addr; + trace->entries.reliable[trace->nr_entries] = reliable; + trace->nr_entries++; }
static void save_stack_address_nosched(void *data, unsigned long addr, int reliable) { - struct stack_trace *trace = (struct stack_trace *)data; if (in_sched_functions(addr)) return; - if (trace->skip > 0) { - trace->skip--; - return; - } - if (trace->nr_entries < trace->max_entries) - trace->entries[trace->nr_entries++] = addr; + + save_stack_address(data, addr, reliable); }
static const struct stacktrace_ops save_stack_ops = { @@ -66,14 +67,14 @@ static const struct stacktrace_ops save_stack_ops_nosched = { */ void save_stack_trace(struct stack_trace *trace) { + trace->has_reliable = true; dump_trace(current, NULL, NULL, 0, &save_stack_ops, trace); - if (trace->nr_entries < trace->max_entries) - trace->entries[trace->nr_entries++] = ULONG_MAX; + save_stack_address(trace, ULONG_MAX, 1); }
void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) { + trace->has_reliable = true; dump_trace(tsk, NULL, NULL, 0, &save_stack_ops_nosched, trace); - if (trace->nr_entries < trace->max_entries) - trace->entries[trace->nr_entries++] = ULONG_MAX; + save_stack_address(trace, ULONG_MAX, 1); } diff --git a/include/linux/latencytop.h b/include/linux/latencytop.h index 901c2d6..4abb8f1 100644 --- a/include/linux/latencytop.h +++ b/include/linux/latencytop.h @@ -9,6 +9,8 @@ #ifndef _INCLUDE_GUARD_LATENCYTOP_H_ #define _INCLUDE_GUARD_LATENCYTOP_H_
+#include <linux/types.h> + #ifdef CONFIG_LATENCYTOP
#define LT_SAVECOUNT 32 @@ -16,6 +18,7 @@
struct latency_record { unsigned long backtrace[LT_BACKTRACEDEPTH]; + bool backtrace_reliable[LT_BACKTRACEDEPTH]; unsigned int count; unsigned long time; unsigned long max; diff --git a/include/linux/stacktrace.h b/include/linux/stacktrace.h index 5da9794..f5e5e9b 100644 --- a/include/linux/stacktrace.h +++ b/include/linux/stacktrace.h @@ -1,19 +1,59 @@ #ifndef __LINUX_STACKTRACE_H #define __LINUX_STACKTRACE_H
+#include <linux/types.h> + #ifdef CONFIG_STACKTRACE + +/* + * These two are separate arrays in order to pack entries as tightly + * as possible. + */ +struct stack_trace_entries { + unsigned long *addr; + bool *reliable; +}; + +#define DEFINE_STACK_TRACE_ENTRIES(entries_addr, entries_reliable) \ + { \ + .addr = (entries_addr), \ + .reliable = (entries_reliable), \ + } + struct stack_trace { - unsigned int nr_entries, max_entries; - unsigned long *entries; - int skip; /* input argument: How many entries to skip */ + unsigned int nr_entries; + unsigned int max_entries; + struct stack_trace_entries entries; + /* input argument: How many entries to skip */ + int skip; + /* + * Indicate whether the stack-trace dumper has information about the + * reliability of entries. (This varies between architectures.) + */ + bool has_reliable; };
+/* + * Common entry point for stack-trace initialisation. + */ +static inline void init_stack_trace(struct stack_trace *trace, + unsigned int n, int skip, unsigned long *addr, bool *reliable) +{ + trace->nr_entries = 0; + trace->max_entries = n; + trace->entries.addr = addr; + trace->entries.reliable = reliable; + trace->skip = skip; + trace->has_reliable = 0; +} + extern void save_stack_trace(struct stack_trace *trace); extern void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace);
extern void print_stack_trace(struct stack_trace *trace, int spaces); #else +# define init_stack_trace(trace, n, skip, addr, rel) do { } while (0) # define save_stack_trace(trace) do { } while (0) # define save_stack_trace_tsk(tsk, trace) do { } while (0) # define print_stack_trace(trace, spaces) do { } while (0) diff --git a/kernel/latencytop.c b/kernel/latencytop.c index b4e3c85..01f620a 100644 --- a/kernel/latencytop.c +++ b/kernel/latencytop.c @@ -102,10 +102,8 @@ static inline void store_stacktrace(struct task_struct *tsk, struct latency_reco { struct stack_trace trace;
- memset(&trace, 0, sizeof(trace)); - trace.max_entries = LT_BACKTRACEDEPTH; - trace.entries = &lat->backtrace[0]; - trace.skip = 0; + init_stack_trace(&trace, LT_BACKTRACEDEPTH, 0, + lat->backtrace, lat->backtrace_reliable); save_stack_trace_tsk(tsk, &trace); }
diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 3574379..43cd90b 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c @@ -332,16 +332,15 @@ static int verbose(struct lock_class *class) * addresses. Protected by the graph_lock. */ unsigned long nr_stack_trace_entries; -static unsigned long stack_trace[MAX_STACK_TRACE_ENTRIES]; +static unsigned long stack_trace_addr[MAX_STACK_TRACE_ENTRIES]; +static bool stack_trace_reliable[MAX_STACK_TRACE_ENTRIES];
static int save_trace(struct stack_trace *trace) { - trace->nr_entries = 0; - trace->max_entries = MAX_STACK_TRACE_ENTRIES - nr_stack_trace_entries; - trace->entries = stack_trace + nr_stack_trace_entries; - - trace->skip = 3; - + init_stack_trace(trace, + MAX_STACK_TRACE_ENTRIES - nr_stack_trace_entries, 3, + stack_trace_addr + nr_stack_trace_entries, + stack_trace_reliable + nr_stack_trace_entries); save_stack_trace(trace);
trace->max_entries = trace->nr_entries; @@ -376,9 +375,11 @@ unsigned int max_recursion_depth; */ static int lockdep_init_error; static unsigned long lockdep_init_trace_data[20]; +static bool lockdep_init_trace_reliable[20]; static struct stack_trace lockdep_init_trace = { .max_entries = ARRAY_SIZE(lockdep_init_trace_data), - .entries = lockdep_init_trace_data, + .entries = DEFINE_STACK_TRACE_ENTRIES(lockdep_init_trace_data, + lockdep_init_trace_reliable), };
/* diff --git a/kernel/stacktrace.c b/kernel/stacktrace.c index b71816e..e14b0c9 100644 --- a/kernel/stacktrace.c +++ b/kernel/stacktrace.c @@ -11,14 +11,16 @@
void print_stack_trace(struct stack_trace *trace, int spaces) { - int i, j; + struct stack_trace_entries *e; + int i;
+ e = &trace->entries; for (i = 0; i < trace->nr_entries; i++) { - unsigned long ip = trace->entries[i]; + printk("%*.s [<%p>] ", spaces, "", (void *) e->addr[i]);
- for (j = 0; j < spaces + 1; j++) - printk(" "); - print_ip_sym(ip); + if (trace->has_reliable) + printk("%s ", !e->reliable[i] ? "?" : " "); + print_symbol("%s\n", e->addr[i]); } }
diff --git a/lib/fault-inject.c b/lib/fault-inject.c index a50a311..0918819 100644 --- a/lib/fault-inject.c +++ b/lib/fault-inject.c @@ -62,17 +62,14 @@ static bool fail_stacktrace(struct fault_attr *attr) struct stack_trace trace; int depth = attr->stacktrace_depth; unsigned long entries[MAX_STACK_TRACE_DEPTH]; + bool entries_reliable[MAX_STACK_TRACE_DEPTH]; int n; bool found = (attr->require_start == 0 && attr->require_end == ULONG_MAX);
if (depth == 0) return found;
- trace.nr_entries = 0; - trace.entries = entries; - trace.max_entries = depth; - trace.skip = 1; - + init_stack_trace(&trace, depth, 1, entries, entries_reliable); save_stack_trace(&trace); for (n = 0; n < trace.nr_entries; n++) { if (attr->reject_start <= entries[n] && -- 1.5.3.8
| |