diff options
Diffstat (limited to 'arch/arm64/kernel/module.c')
| -rw-r--r-- | arch/arm64/kernel/module.c | 57 | 
1 files changed, 47 insertions, 10 deletions
diff --git a/arch/arm64/kernel/module.c b/arch/arm64/kernel/module.c index 03ff15bffbb6..1cd1a4d0ed30 100644 --- a/arch/arm64/kernel/module.c +++ b/arch/arm64/kernel/module.c @@ -9,6 +9,7 @@  #include <linux/bitops.h>  #include <linux/elf.h> +#include <linux/ftrace.h>  #include <linux/gfp.h>  #include <linux/kasan.h>  #include <linux/kernel.h> @@ -470,22 +471,58 @@ overflow:  	return -ENOEXEC;  } -int module_finalize(const Elf_Ehdr *hdr, -		    const Elf_Shdr *sechdrs, -		    struct module *me) +static const Elf_Shdr *find_section(const Elf_Ehdr *hdr, +				    const Elf_Shdr *sechdrs, +				    const char *name)  {  	const Elf_Shdr *s, *se;  	const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;  	for (s = sechdrs, se = sechdrs + hdr->e_shnum; s < se; s++) { -		if (strcmp(".altinstructions", secstrs + s->sh_name) == 0) -			apply_alternatives_module((void *)s->sh_addr, s->sh_size); -#ifdef CONFIG_ARM64_MODULE_PLTS -		if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE) && -		    !strcmp(".text.ftrace_trampoline", secstrs + s->sh_name)) -			me->arch.ftrace_trampoline = (void *)s->sh_addr; -#endif +		if (strcmp(name, secstrs + s->sh_name) == 0) +			return s;  	} +	return NULL; +} + +static inline void __init_plt(struct plt_entry *plt, unsigned long addr) +{ +	*plt = get_plt_entry(addr, plt); +} + +static int module_init_ftrace_plt(const Elf_Ehdr *hdr, +				  const Elf_Shdr *sechdrs, +				  struct module *mod) +{ +#if defined(CONFIG_ARM64_MODULE_PLTS) && defined(CONFIG_DYNAMIC_FTRACE) +	const Elf_Shdr *s; +	struct plt_entry *plts; + +	s = find_section(hdr, sechdrs, ".text.ftrace_trampoline"); +	if (!s) +		return -ENOEXEC; + +	plts = (void *)s->sh_addr; + +	__init_plt(&plts[FTRACE_PLT_IDX], FTRACE_ADDR); + +	if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_REGS)) +		__init_plt(&plts[FTRACE_REGS_PLT_IDX], FTRACE_REGS_ADDR); + +	mod->arch.ftrace_trampolines = plts; +#endif  	return 0;  } + +int module_finalize(const Elf_Ehdr *hdr, +		    const Elf_Shdr *sechdrs, +		    struct module *me) +{ +	const Elf_Shdr *s; +	s = find_section(hdr, sechdrs, ".altinstructions"); +	if (s) +		apply_alternatives_module((void *)s->sh_addr, s->sh_size); + +	return module_init_ftrace_plt(hdr, sechdrs, me); +}  |