With SFRAME_UNWINDER, read in the .sframe section at boot. This provides unwind data as an alternative/supplement to frame pointer-based unwinding.
Signed-off-by: Dylan Hatch <[email protected]> --- arch/arm64/kernel/setup.c | 2 ++ include/linux/sframe.h | 14 ++++++++++++++ kernel/unwind/sframe.c | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+) diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 23c05dc7a8f2..4a633bc7aefb 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -32,6 +32,7 @@ #include <linux/sched/task.h> #include <linux/scs.h> #include <linux/mm.h> +#include <linux/sframe.h> #include <asm/acpi.h> #include <asm/fixmap.h> @@ -375,6 +376,7 @@ void __init __no_sanitize_address setup_arch(char **cmdline_p) "This indicates a broken bootloader or old kernel\n", boot_args[1], boot_args[2], boot_args[3]); } + init_sframe_table(); } static inline bool cpu_can_disable(unsigned int cpu) diff --git a/include/linux/sframe.h b/include/linux/sframe.h index 673b9edfc921..905775c3fde2 100644 --- a/include/linux/sframe.h +++ b/include/linux/sframe.h @@ -109,4 +109,18 @@ static inline int sframe_find_user(unsigned long ip, struct unwind_frame *frame) #endif /* CONFIG_HAVE_UNWIND_USER_SFRAME */ +#ifdef CONFIG_SFRAME_UNWINDER + +void __init init_sframe_table(void); +void sframe_module_init(struct module *mod, void *sframe, size_t sframe_size, + void *text, size_t text_size); + +extern int sframe_find_kernel(unsigned long ip, struct unwind_frame *frame); + +#else + +static inline void __init init_sframe_table(void) {} + +#endif /* CONFIG_SFRAME_UNWINDER */ + #endif /* _LINUX_SFRAME_H */ diff --git a/kernel/unwind/sframe.c b/kernel/unwind/sframe.c index cad4384dfb4f..321d0615aec7 100644 --- a/kernel/unwind/sframe.c +++ b/kernel/unwind/sframe.c @@ -13,10 +13,23 @@ #include <linux/string_helpers.h> #include <linux/sframe.h> #include <asm/unwind_sframe.h> +#ifdef CONFIG_SFRAME_UNWINDER +#include <linux/kallsyms.h> +#endif #include "sframe.h" #include "sframe_debug.h" +#ifdef CONFIG_SFRAME_UNWINDER + +extern char __start_sframe_header[]; +extern char __stop_sframe_header[]; + +static bool sframe_init __ro_after_init; +static struct sframe_section kernel_sfsec __ro_after_init; + +#endif /* CONFIG_SFRAME_UNWINDER */ + struct sframe_fde_internal { unsigned long func_addr; u32 func_size; @@ -930,3 +943,29 @@ void sframe_free_mm(struct mm_struct *mm) } #endif /* CONFIG_HAVE_UNWIND_USER_SFRAME */ + +#ifdef CONFIG_SFRAME_UNWINDER + +int sframe_find_kernel(unsigned long ip, struct unwind_frame *frame) +{ + if (!frame || !sframe_init) + return -EINVAL; + + return __sframe_find(&kernel_sfsec, ip, frame); +} + +void __init init_sframe_table(void) +{ + kernel_sfsec.sec_type = SFRAME_KERNEL; + kernel_sfsec.sframe_start = (unsigned long)__start_sframe_header; + kernel_sfsec.sframe_end = (unsigned long)__stop_sframe_header; + kernel_sfsec.text_start = (unsigned long)_stext; + kernel_sfsec.text_end = (unsigned long)_etext; + + if (WARN_ON(sframe_read_header(&kernel_sfsec))) + return; + + sframe_init = true; +} + +#endif /* CONFIG_SFRAME_UNWINDER */ -- 2.53.0.1213.gd9a14994de-goog

