Skip to content

Commit d81675b

Browse files
author
Vasily Gorbik
committed
s390/unwind: recover kretprobe modified return address in stacktrace
Based on commit cd9bc2c ("arm64: Recover kretprobe modified return address in stacktrace"). """ Since the kretprobe replaces the function return address with the __kretprobe_trampoline on the stack, stack unwinder shows it instead of the correct return address. This checks whether the next return address is the __kretprobe_trampoline(), and if so, try to find the correct return address from the kretprobe instance list. """ Original patch series: https://lore.kernel.org/all/163163030719.489837.2236069935502195491.stgit@devnote2/ Reviewed-by: Tobias Huschle <huschle@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
1 parent 09bc20c commit d81675b

2 files changed

Lines changed: 15 additions & 6 deletions

File tree

arch/s390/include/asm/unwind.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
#include <linux/sched.h>
66
#include <linux/ftrace.h>
7+
#include <linux/kprobes.h>
8+
#include <linux/llist.h>
79
#include <asm/ptrace.h>
810
#include <asm/stacktrace.h>
911

@@ -36,10 +38,21 @@ struct unwind_state {
3638
struct pt_regs *regs;
3739
unsigned long sp, ip;
3840
int graph_idx;
41+
struct llist_node *kr_cur;
3942
bool reliable;
4043
bool error;
4144
};
4245

46+
/* Recover the return address modified by kretprobe and ftrace_graph. */
47+
static inline unsigned long unwind_recover_ret_addr(struct unwind_state *state,
48+
unsigned long ip)
49+
{
50+
ip = ftrace_graph_ret_addr(state->task, &state->graph_idx, ip, NULL);
51+
if (is_kretprobe_trampoline(ip))
52+
ip = kretprobe_find_ret_addr(state->task, (void *)state->sp, &state->kr_cur);
53+
return ip;
54+
}
55+
4356
void __unwind_start(struct unwind_state *state, struct task_struct *task,
4457
struct pt_regs *regs, unsigned long first_frame);
4558
bool unwind_next_frame(struct unwind_state *state);

arch/s390/kernel/unwind_bc.c

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -103,13 +103,11 @@ bool unwind_next_frame(struct unwind_state *state)
103103
if (sp & 0x7)
104104
goto out_err;
105105

106-
ip = ftrace_graph_ret_addr(state->task, &state->graph_idx, ip, (void *) sp);
107-
108106
/* Update unwind state */
109107
state->sp = sp;
110-
state->ip = ip;
111108
state->regs = regs;
112109
state->reliable = reliable;
110+
state->ip = unwind_recover_ret_addr(state, ip);
113111
return true;
114112

115113
out_err:
@@ -161,12 +159,10 @@ void __unwind_start(struct unwind_state *state, struct task_struct *task,
161159
ip = READ_ONCE_NOCHECK(sf->gprs[8]);
162160
}
163161

164-
ip = ftrace_graph_ret_addr(state->task, &state->graph_idx, ip, NULL);
165-
166162
/* Update unwind state */
167163
state->sp = sp;
168-
state->ip = ip;
169164
state->reliable = true;
165+
state->ip = unwind_recover_ret_addr(state, ip);
170166

171167
if (!first_frame)
172168
return;

0 commit comments

Comments
 (0)