lkml.org 
[lkml]   [2022]   [Jul]   [15]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
From
Date
SubjectRe: [PATCH v4 05/18] arm64: stacktrace: Factor out common unwind()
Hi Kalesh,


On Fri, Jul 15, 2022 at 7:11 AM Kalesh Singh <kaleshsingh@google.com> wrote:
>
> Move unwind() to stacktrace/common.h, and as a result
> the kernel unwind_next() to asm/stacktrace.h. This allow
> reusing unwind() in the implementation of the nVHE HYP
> stack unwinder, later in the series.
>
> Signed-off-by: Kalesh Singh <kaleshsingh@google.com>
> ---

Reviewed-by: Fuad Tabba <tabba@google.com>

Thanks,
/fuad


> arch/arm64/include/asm/stacktrace.h | 51 ++++++++++++++++
> arch/arm64/include/asm/stacktrace/common.h | 19 ++++++
> arch/arm64/kernel/stacktrace.c | 67 ----------------------
> 3 files changed, 70 insertions(+), 67 deletions(-)
>
> diff --git a/arch/arm64/include/asm/stacktrace.h b/arch/arm64/include/asm/stacktrace.h
> index a4f8b84fb459..4fa07f0f913d 100644
> --- a/arch/arm64/include/asm/stacktrace.h
> +++ b/arch/arm64/include/asm/stacktrace.h
> @@ -11,6 +11,7 @@
> #include <linux/llist.h>
>
> #include <asm/memory.h>
> +#include <asm/pointer_auth.h>
> #include <asm/ptrace.h>
> #include <asm/sdei.h>
>
> @@ -78,4 +79,54 @@ static inline bool on_accessible_stack(const struct task_struct *tsk,
>
> return false;
> }
> +
> +/*
> + * Unwind from one frame record (A) to the next frame record (B).
> + *
> + * We terminate early if the location of B indicates a malformed chain of frame
> + * records (e.g. a cycle), determined based on the location and fp value of A
> + * and the location (but not the fp value) of B.
> + */
> +static inline int notrace unwind_next(struct unwind_state *state)
> +{
> + struct task_struct *tsk = state->task;
> + unsigned long fp = state->fp;
> + struct stack_info info;
> + int err;
> +
> + /* Final frame; nothing to unwind */
> + if (fp == (unsigned long)task_pt_regs(tsk)->stackframe)
> + return -ENOENT;
> +
> + err = unwind_next_common(state, &info, NULL);
> + if (err)
> + return err;
> +
> + state->pc = ptrauth_strip_insn_pac(state->pc);
> +
> +#ifdef CONFIG_FUNCTION_GRAPH_TRACER
> + if (tsk->ret_stack &&
> + (state->pc == (unsigned long)return_to_handler)) {
> + unsigned long orig_pc;
> + /*
> + * This is a case where function graph tracer has
> + * modified a return address (LR) in a stack frame
> + * to hook a function return.
> + * So replace it to an original value.
> + */
> + orig_pc = ftrace_graph_ret_addr(tsk, NULL, state->pc,
> + (void *)state->fp);
> + if (WARN_ON_ONCE(state->pc == orig_pc))
> + return -EINVAL;
> + state->pc = orig_pc;
> + }
> +#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
> +#ifdef CONFIG_KRETPROBES
> + if (is_kretprobe_trampoline(state->pc))
> + state->pc = kretprobe_find_ret_addr(tsk, (void *)state->fp, &state->kr_cur);
> +#endif
> +
> + return 0;
> +}
> +NOKPROBE_SYMBOL(unwind_next);
> #endif /* __ASM_STACKTRACE_H */
> diff --git a/arch/arm64/include/asm/stacktrace/common.h b/arch/arm64/include/asm/stacktrace/common.h
> index 5f5d74a286f3..f86efe71479d 100644
> --- a/arch/arm64/include/asm/stacktrace/common.h
> +++ b/arch/arm64/include/asm/stacktrace/common.h
> @@ -9,6 +9,7 @@
>
> #include <linux/bitmap.h>
> #include <linux/bitops.h>
> +#include <linux/kprobes.h>
> #include <linux/types.h>
>
> enum stack_type {
> @@ -69,6 +70,8 @@ static inline bool on_accessible_stack(const struct task_struct *tsk,
> unsigned long sp, unsigned long size,
> struct stack_info *info);
>
> +static inline int unwind_next(struct unwind_state *state);
> +
> static inline bool on_stack(unsigned long sp, unsigned long size,
> unsigned long low, unsigned long high,
> enum stack_type type, struct stack_info *info)
> @@ -192,4 +195,20 @@ static inline int unwind_next_common(struct unwind_state *state,
>
> return 0;
> }
> +
> +static inline void notrace unwind(struct unwind_state *state,
> + stack_trace_consume_fn consume_entry,
> + void *cookie)
> +{
> + while (1) {
> + int ret;
> +
> + if (!consume_entry(cookie, state->pc))
> + break;
> + ret = unwind_next(state);
> + if (ret < 0)
> + break;
> + }
> +}
> +NOKPROBE_SYMBOL(unwind);
> #endif /* __ASM_STACKTRACE_COMMON_H */
> diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c
> index eef3cf6bf2d7..9fa60ee48499 100644
> --- a/arch/arm64/kernel/stacktrace.c
> +++ b/arch/arm64/kernel/stacktrace.c
> @@ -7,14 +7,12 @@
> #include <linux/kernel.h>
> #include <linux/export.h>
> #include <linux/ftrace.h>
> -#include <linux/kprobes.h>
> #include <linux/sched.h>
> #include <linux/sched/debug.h>
> #include <linux/sched/task_stack.h>
> #include <linux/stacktrace.h>
>
> #include <asm/irq.h>
> -#include <asm/pointer_auth.h>
> #include <asm/stack_pointer.h>
> #include <asm/stacktrace.h>
>
> @@ -69,71 +67,6 @@ static inline void unwind_init_from_task(struct unwind_state *state,
> state->pc = thread_saved_pc(task);
> }
>
> -/*
> - * Unwind from one frame record (A) to the next frame record (B).
> - *
> - * We terminate early if the location of B indicates a malformed chain of frame
> - * records (e.g. a cycle), determined based on the location and fp value of A
> - * and the location (but not the fp value) of B.
> - */
> -static int notrace unwind_next(struct unwind_state *state)
> -{
> - struct task_struct *tsk = state->task;
> - unsigned long fp = state->fp;
> - struct stack_info info;
> - int err;
> -
> - /* Final frame; nothing to unwind */
> - if (fp == (unsigned long)task_pt_regs(tsk)->stackframe)
> - return -ENOENT;
> -
> - err = unwind_next_common(state, &info, NULL);
> - if (err)
> - return err;
> -
> - state->pc = ptrauth_strip_insn_pac(state->pc);
> -
> -#ifdef CONFIG_FUNCTION_GRAPH_TRACER
> - if (tsk->ret_stack &&
> - (state->pc == (unsigned long)return_to_handler)) {
> - unsigned long orig_pc;
> - /*
> - * This is a case where function graph tracer has
> - * modified a return address (LR) in a stack frame
> - * to hook a function return.
> - * So replace it to an original value.
> - */
> - orig_pc = ftrace_graph_ret_addr(tsk, NULL, state->pc,
> - (void *)state->fp);
> - if (WARN_ON_ONCE(state->pc == orig_pc))
> - return -EINVAL;
> - state->pc = orig_pc;
> - }
> -#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
> -#ifdef CONFIG_KRETPROBES
> - if (is_kretprobe_trampoline(state->pc))
> - state->pc = kretprobe_find_ret_addr(tsk, (void *)state->fp, &state->kr_cur);
> -#endif
> -
> - return 0;
> -}
> -NOKPROBE_SYMBOL(unwind_next);
> -
> -static void notrace unwind(struct unwind_state *state,
> - stack_trace_consume_fn consume_entry, void *cookie)
> -{
> - while (1) {
> - int ret;
> -
> - if (!consume_entry(cookie, state->pc))
> - break;
> - ret = unwind_next(state);
> - if (ret < 0)
> - break;
> - }
> -}
> -NOKPROBE_SYMBOL(unwind);
> -
> static bool dump_backtrace_entry(void *arg, unsigned long where)
> {
> char *loglvl = arg;
> --
> 2.37.0.170.g444d1eabd0-goog
>

\
 
 \ /
  Last update: 2022-07-15 16:00    [W:0.751 / U:0.320 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site