diff options
-rw-r--r-- | arch/x86/kernel/stacktrace.c | 51 | ||||
-rw-r--r-- | include/linux/stacktrace.h | 2 | ||||
-rw-r--r-- | kernel/trace/trace.c | 7 |
3 files changed, 33 insertions, 27 deletions
diff --git a/arch/x86/kernel/stacktrace.c b/arch/x86/kernel/stacktrace.c index b15153060417..10786af95545 100644 --- a/arch/x86/kernel/stacktrace.c +++ b/arch/x86/kernel/stacktrace.c | |||
@@ -89,7 +89,7 @@ EXPORT_SYMBOL_GPL(save_stack_trace_tsk); | |||
89 | 89 | ||
90 | struct stack_frame { | 90 | struct stack_frame { |
91 | const void __user *next_fp; | 91 | const void __user *next_fp; |
92 | unsigned long return_address; | 92 | unsigned long ret_addr; |
93 | }; | 93 | }; |
94 | 94 | ||
95 | static int copy_stack_frame(const void __user *fp, struct stack_frame *frame) | 95 | static int copy_stack_frame(const void __user *fp, struct stack_frame *frame) |
@@ -108,33 +108,40 @@ static int copy_stack_frame(const void __user *fp, struct stack_frame *frame) | |||
108 | return ret; | 108 | return ret; |
109 | } | 109 | } |
110 | 110 | ||
111 | static inline void __save_stack_trace_user(struct stack_trace *trace) | ||
112 | { | ||
113 | const struct pt_regs *regs = task_pt_regs(current); | ||
114 | const void __user *fp = (const void __user *)regs->bp; | ||
115 | |||
116 | if (trace->nr_entries < trace->max_entries) | ||
117 | trace->entries[trace->nr_entries++] = regs->ip; | ||
118 | |||
119 | while (trace->nr_entries < trace->max_entries) { | ||
120 | struct stack_frame frame; | ||
121 | |||
122 | frame.next_fp = NULL; | ||
123 | frame.ret_addr = 0; | ||
124 | if (!copy_stack_frame(fp, &frame)) | ||
125 | break; | ||
126 | if ((unsigned long)fp < regs->sp) | ||
127 | break; | ||
128 | if (frame.ret_addr) { | ||
129 | trace->entries[trace->nr_entries++] = | ||
130 | frame.ret_addr; | ||
131 | } | ||
132 | if (fp == frame.next_fp) | ||
133 | break; | ||
134 | fp = frame.next_fp; | ||
135 | } | ||
136 | } | ||
137 | |||
111 | void save_stack_trace_user(struct stack_trace *trace) | 138 | void save_stack_trace_user(struct stack_trace *trace) |
112 | { | 139 | { |
113 | /* | 140 | /* |
114 | * Trace user stack if we are not a kernel thread | 141 | * Trace user stack if we are not a kernel thread |
115 | */ | 142 | */ |
116 | if (current->mm) { | 143 | if (current->mm) { |
117 | const struct pt_regs *regs = task_pt_regs(current); | 144 | __save_stack_trace_user(trace); |
118 | const void __user *fp = (const void __user *)regs->bp; | ||
119 | |||
120 | if (trace->nr_entries < trace->max_entries) | ||
121 | trace->entries[trace->nr_entries++] = regs->ip; | ||
122 | |||
123 | while (trace->nr_entries < trace->max_entries) { | ||
124 | struct stack_frame frame; | ||
125 | frame.next_fp = NULL; | ||
126 | frame.return_address = 0; | ||
127 | if (!copy_stack_frame(fp, &frame)) | ||
128 | break; | ||
129 | if ((unsigned long)fp < regs->sp) | ||
130 | break; | ||
131 | if (frame.return_address) | ||
132 | trace->entries[trace->nr_entries++] = | ||
133 | frame.return_address; | ||
134 | if (fp == frame.next_fp) | ||
135 | break; | ||
136 | fp = frame.next_fp; | ||
137 | } | ||
138 | } | 145 | } |
139 | if (trace->nr_entries < trace->max_entries) | 146 | if (trace->nr_entries < trace->max_entries) |
140 | trace->entries[trace->nr_entries++] = ULONG_MAX; | 147 | trace->entries[trace->nr_entries++] = ULONG_MAX; |
diff --git a/include/linux/stacktrace.h b/include/linux/stacktrace.h index 68de51468f5d..fd42d6851109 100644 --- a/include/linux/stacktrace.h +++ b/include/linux/stacktrace.h | |||
@@ -25,7 +25,7 @@ extern void save_stack_trace_user(struct stack_trace *trace); | |||
25 | #else | 25 | #else |
26 | # define save_stack_trace(trace) do { } while (0) | 26 | # define save_stack_trace(trace) do { } while (0) |
27 | # define save_stack_trace_tsk(tsk, trace) do { } while (0) | 27 | # define save_stack_trace_tsk(tsk, trace) do { } while (0) |
28 | # define save_stack_trace_user(trace) do { } while (0) | 28 | # define save_stack_trace_user(trace) do { } while (0) |
29 | # define print_stack_trace(trace, spaces) do { } while (0) | 29 | # define print_stack_trace(trace, spaces) do { } while (0) |
30 | #endif | 30 | #endif |
31 | 31 | ||
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 62776b71b1c5..dedf35f36971 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
@@ -948,9 +948,9 @@ static void ftrace_trace_userstack(struct trace_array *tr, | |||
948 | struct trace_array_cpu *data, | 948 | struct trace_array_cpu *data, |
949 | unsigned long flags, int pc) | 949 | unsigned long flags, int pc) |
950 | { | 950 | { |
951 | struct ring_buffer_event *event; | ||
951 | struct userstack_entry *entry; | 952 | struct userstack_entry *entry; |
952 | struct stack_trace trace; | 953 | struct stack_trace trace; |
953 | struct ring_buffer_event *event; | ||
954 | unsigned long irq_flags; | 954 | unsigned long irq_flags; |
955 | 955 | ||
956 | if (!(trace_flags & TRACE_ITER_USERSTACKTRACE)) | 956 | if (!(trace_flags & TRACE_ITER_USERSTACKTRACE)) |
@@ -1471,8 +1471,7 @@ static inline int seq_print_user_ip(struct trace_seq *s, struct mm_struct *mm, | |||
1471 | if (file) { | 1471 | if (file) { |
1472 | ret = trace_seq_path(s, &file->f_path); | 1472 | ret = trace_seq_path(s, &file->f_path); |
1473 | if (ret) | 1473 | if (ret) |
1474 | ret = trace_seq_printf(s, "[+0x%lx]", | 1474 | ret = trace_seq_printf(s, "[+0x%lx]", ip - vmstart); |
1475 | ip - vmstart); | ||
1476 | } | 1475 | } |
1477 | if (ret && ((sym_flags & TRACE_ITER_SYM_ADDR) || !file)) | 1476 | if (ret && ((sym_flags & TRACE_ITER_SYM_ADDR) || !file)) |
1478 | ret = trace_seq_printf(s, " <" IP_FMT ">", ip); | 1477 | ret = trace_seq_printf(s, " <" IP_FMT ">", ip); |
@@ -1485,7 +1484,7 @@ seq_print_userip_objs(const struct userstack_entry *entry, struct trace_seq *s, | |||
1485 | { | 1484 | { |
1486 | struct mm_struct *mm = NULL; | 1485 | struct mm_struct *mm = NULL; |
1487 | int ret = 1; | 1486 | int ret = 1; |
1488 | unsigned i; | 1487 | unsigned int i; |
1489 | 1488 | ||
1490 | if (trace_flags & TRACE_ITER_SYM_USEROBJ) { | 1489 | if (trace_flags & TRACE_ITER_SYM_USEROBJ) { |
1491 | struct task_struct *task; | 1490 | struct task_struct *task; |