aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/stacktrace.c51
-rw-r--r--include/linux/stacktrace.h2
-rw-r--r--kernel/trace/trace.c7
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
90struct stack_frame { 90struct 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
95static int copy_stack_frame(const void __user *fp, struct stack_frame *frame) 95static 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
111static 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
111void save_stack_trace_user(struct stack_trace *trace) 138void 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;