s390/unwind: recover kretprobe modified return address in stacktrace
Based on commit cd9bc2c925
("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>
This commit is contained in:
Родитель
09bc20c8fb
Коммит
d81675b60d
|
@ -4,6 +4,8 @@
|
|||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/ftrace.h>
|
||||
#include <linux/kprobes.h>
|
||||
#include <linux/llist.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/stacktrace.h>
|
||||
|
||||
|
@ -36,10 +38,21 @@ struct unwind_state {
|
|||
struct pt_regs *regs;
|
||||
unsigned long sp, ip;
|
||||
int graph_idx;
|
||||
struct llist_node *kr_cur;
|
||||
bool reliable;
|
||||
bool error;
|
||||
};
|
||||
|
||||
/* Recover the return address modified by kretprobe and ftrace_graph. */
|
||||
static inline unsigned long unwind_recover_ret_addr(struct unwind_state *state,
|
||||
unsigned long ip)
|
||||
{
|
||||
ip = ftrace_graph_ret_addr(state->task, &state->graph_idx, ip, NULL);
|
||||
if (is_kretprobe_trampoline(ip))
|
||||
ip = kretprobe_find_ret_addr(state->task, (void *)state->sp, &state->kr_cur);
|
||||
return ip;
|
||||
}
|
||||
|
||||
void __unwind_start(struct unwind_state *state, struct task_struct *task,
|
||||
struct pt_regs *regs, unsigned long first_frame);
|
||||
bool unwind_next_frame(struct unwind_state *state);
|
||||
|
|
|
@ -103,13 +103,11 @@ bool unwind_next_frame(struct unwind_state *state)
|
|||
if (sp & 0x7)
|
||||
goto out_err;
|
||||
|
||||
ip = ftrace_graph_ret_addr(state->task, &state->graph_idx, ip, (void *) sp);
|
||||
|
||||
/* Update unwind state */
|
||||
state->sp = sp;
|
||||
state->ip = ip;
|
||||
state->regs = regs;
|
||||
state->reliable = reliable;
|
||||
state->ip = unwind_recover_ret_addr(state, ip);
|
||||
return true;
|
||||
|
||||
out_err:
|
||||
|
@ -161,12 +159,10 @@ void __unwind_start(struct unwind_state *state, struct task_struct *task,
|
|||
ip = READ_ONCE_NOCHECK(sf->gprs[8]);
|
||||
}
|
||||
|
||||
ip = ftrace_graph_ret_addr(state->task, &state->graph_idx, ip, NULL);
|
||||
|
||||
/* Update unwind state */
|
||||
state->sp = sp;
|
||||
state->ip = ip;
|
||||
state->reliable = true;
|
||||
state->ip = unwind_recover_ret_addr(state, ip);
|
||||
|
||||
if (!first_frame)
|
||||
return;
|
||||
|
|
Загрузка…
Ссылка в новой задаче