* [PATCH v6 0/2] ARM: Implement MODULE_PLT support in FTRACE
@ 2020-02-17 14:09 Alexander X Sverdlin
2020-02-17 14:09 ` [PATCH v6 1/2] ARM: PLT: Move struct plt_entries definition to header Alexander X Sverdlin
` (2 more replies)
0 siblings, 3 replies; 5+ messages in thread
From: Alexander X Sverdlin @ 2020-02-17 14:09 UTC (permalink / raw)
To: linux-arm-kernel
Cc: Alexander Sverdlin, linux-kernel, Russell King, Steven Rostedt,
Ingo Molnar, Ard Biesheuvel
From: Alexander Sverdlin <alexander.sverdlin@nokia.com>
FTRACE's function tracer currently doesn't always work on ARM with
MODULE_PLT option enabled. If the module is loaded too far, FTRACE's
code modifier cannot cope with introduced veneers and turns the
function tracer off globally.
ARM64 already has a solution for the problem, refer to the following
patches:
arm64: ftrace: emit ftrace-mod.o contents through code
arm64: module-plts: factor out PLT generation code for ftrace
arm64: ftrace: fix !CONFIG_ARM64_MODULE_PLTS kernels
arm64: ftrace: fix building without CONFIG_MODULES
arm64: ftrace: add support for far branches to dynamic ftrace
arm64: ftrace: don't validate branch via PLT in ftrace_make_nop()
But the presented ARM variant has just a half of the footprint in terms of
the changed LoCs. It also retains the code validation-before-modification
instead of switching it off.
Changelog:
v6:
* rebased
v5:
* BUILD_BUG_ON() ensures fixed_plts[] always fits one PLT block
* use "for" loop instead of "while"
* scripts/recordmcount is filtering reloc types
v4:
* Fixed build without CONFIG_FUNCTION_TRACER
* Reorganized pre-allocated PLTs handling in get_module_plt(),
now compiler eliminates the whole FTRACE-related handling code
if ARRAY_SIZE(fixed_plts) == 0
v3:
* Only extend struct dyn_arch_ftrace when ARM_MODULE_PLTS is enabled
v2:
* As suggested by Steven Rostedt, refrain from tree-wide API modification,
save module pointer in struct dyn_arch_ftrace instead (PowerPC way)
Alexander Sverdlin (2):
ARM: PLT: Move struct plt_entries definition to header
ARM: ftrace: Add MODULE_PLTS support
arch/arm/include/asm/ftrace.h | 3 +++
arch/arm/include/asm/module.h | 10 +++++++++
arch/arm/kernel/ftrace.c | 46 ++++++++++++++++++++++++++++++++++++++--
arch/arm/kernel/module-plts.c | 49 +++++++++++++++++++++++++++++++++----------
4 files changed, 95 insertions(+), 13 deletions(-)
--
2.4.6
^ permalink raw reply [flat|nested] 5+ messages in thread* [PATCH v6 1/2] ARM: PLT: Move struct plt_entries definition to header 2020-02-17 14:09 [PATCH v6 0/2] ARM: Implement MODULE_PLT support in FTRACE Alexander X Sverdlin @ 2020-02-17 14:09 ` Alexander X Sverdlin 2020-02-17 14:09 ` [PATCH v6 2/2] ARM: ftrace: Add MODULE_PLTS support Alexander X Sverdlin 2021-01-27 4:48 ` [PATCH v6 0/2] ARM: Implement MODULE_PLT support in FTRACE Florian Fainelli 2 siblings, 0 replies; 5+ messages in thread From: Alexander X Sverdlin @ 2020-02-17 14:09 UTC (permalink / raw) To: linux-arm-kernel Cc: Alexander Sverdlin, linux-kernel, Russell King, Steven Rostedt, Ingo Molnar, Ard Biesheuvel From: Alexander Sverdlin <alexander.sverdlin@nokia.com> No functional change, later it will be re-used in several files. Signed-off-by: Alexander Sverdlin <alexander.sverdlin@nokia.com> --- arch/arm/include/asm/module.h | 9 +++++++++ arch/arm/kernel/module-plts.c | 9 --------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/arm/include/asm/module.h b/arch/arm/include/asm/module.h index 182163b..78e4c16 100644 --- a/arch/arm/include/asm/module.h +++ b/arch/arm/include/asm/module.h @@ -19,6 +19,15 @@ enum { }; #endif +#define PLT_ENT_STRIDE L1_CACHE_BYTES +#define PLT_ENT_COUNT (PLT_ENT_STRIDE / sizeof(u32)) +#define PLT_ENT_SIZE (sizeof(struct plt_entries) / PLT_ENT_COUNT) + +struct plt_entries { + u32 ldr[PLT_ENT_COUNT]; + u32 lit[PLT_ENT_COUNT]; +}; + struct mod_plt_sec { struct elf32_shdr *plt; int plt_count; diff --git a/arch/arm/kernel/module-plts.c b/arch/arm/kernel/module-plts.c index 6e626ab..d330e9e 100644 --- a/arch/arm/kernel/module-plts.c +++ b/arch/arm/kernel/module-plts.c @@ -12,10 +12,6 @@ #include <asm/cache.h> #include <asm/opcodes.h> -#define PLT_ENT_STRIDE L1_CACHE_BYTES -#define PLT_ENT_COUNT (PLT_ENT_STRIDE / sizeof(u32)) -#define PLT_ENT_SIZE (sizeof(struct plt_entries) / PLT_ENT_COUNT) - #ifdef CONFIG_THUMB2_KERNEL #define PLT_ENT_LDR __opcode_to_mem_thumb32(0xf8dff000 | \ (PLT_ENT_STRIDE - 4)) @@ -24,11 +20,6 @@ (PLT_ENT_STRIDE - 8)) #endif -struct plt_entries { - u32 ldr[PLT_ENT_COUNT]; - u32 lit[PLT_ENT_COUNT]; -}; - static bool in_init(const struct module *mod, unsigned long loc) { return loc - (u32)mod->init_layout.base < mod->init_layout.size; -- 2.4.6 ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v6 2/2] ARM: ftrace: Add MODULE_PLTS support 2020-02-17 14:09 [PATCH v6 0/2] ARM: Implement MODULE_PLT support in FTRACE Alexander X Sverdlin 2020-02-17 14:09 ` [PATCH v6 1/2] ARM: PLT: Move struct plt_entries definition to header Alexander X Sverdlin @ 2020-02-17 14:09 ` Alexander X Sverdlin 2021-01-27 4:48 ` [PATCH v6 0/2] ARM: Implement MODULE_PLT support in FTRACE Florian Fainelli 2 siblings, 0 replies; 5+ messages in thread From: Alexander X Sverdlin @ 2020-02-17 14:09 UTC (permalink / raw) To: linux-arm-kernel Cc: Alexander Sverdlin, linux-kernel, Russell King, Steven Rostedt, Ingo Molnar, Ard Biesheuvel From: Alexander Sverdlin <alexander.sverdlin@nokia.com> Teach ftrace_make_call() and ftrace_make_nop() about PLTs. Teach PLT code about FTRACE and all its callbacks. Otherwise the following might happen: ------------[ cut here ]------------ WARNING: CPU: 14 PID: 2265 at .../arch/arm/kernel/insn.c:14 __arm_gen_branch+0x83/0x8c() ... Hardware name: LSI Axxia AXM55XX [<c0314a49>] (unwind_backtrace) from [<c03115e9>] (show_stack+0x11/0x14) [<c03115e9>] (show_stack) from [<c0519f51>] (dump_stack+0x81/0xa8) [<c0519f51>] (dump_stack) from [<c032185d>] (warn_slowpath_common+0x69/0x90) [<c032185d>] (warn_slowpath_common) from [<c03218f3>] (warn_slowpath_null+0x17/0x1c) [<c03218f3>] (warn_slowpath_null) from [<c03143cf>] (__arm_gen_branch+0x83/0x8c) [<c03143cf>] (__arm_gen_branch) from [<c0314337>] (ftrace_make_nop+0xf/0x24) [<c0314337>] (ftrace_make_nop) from [<c038ebcb>] (ftrace_process_locs+0x27b/0x3e8) [<c038ebcb>] (ftrace_process_locs) from [<c0378d79>] (load_module+0x11e9/0x1a44) [<c0378d79>] (load_module) from [<c037974d>] (SyS_finit_module+0x59/0x84) [<c037974d>] (SyS_finit_module) from [<c030e981>] (ret_fast_syscall+0x1/0x18) ---[ end trace e1b64ced7a89adcc ]--- ------------[ cut here ]------------ WARNING: CPU: 14 PID: 2265 at .../kernel/trace/ftrace.c:1979 ftrace_bug+0x1b1/0x234() ... Hardware name: LSI Axxia AXM55XX [<c0314a49>] (unwind_backtrace) from [<c03115e9>] (show_stack+0x11/0x14) [<c03115e9>] (show_stack) from [<c0519f51>] (dump_stack+0x81/0xa8) [<c0519f51>] (dump_stack) from [<c032185d>] (warn_slowpath_common+0x69/0x90) [<c032185d>] (warn_slowpath_common) from [<c03218f3>] (warn_slowpath_null+0x17/0x1c) [<c03218f3>] (warn_slowpath_null) from [<c038e87d>] (ftrace_bug+0x1b1/0x234) [<c038e87d>] (ftrace_bug) from [<c038ebd5>] (ftrace_process_locs+0x285/0x3e8) [<c038ebd5>] (ftrace_process_locs) from [<c0378d79>] (load_module+0x11e9/0x1a44) [<c0378d79>] (load_module) from [<c037974d>] (SyS_finit_module+0x59/0x84) [<c037974d>] (SyS_finit_module) from [<c030e981>] (ret_fast_syscall+0x1/0x18) ---[ end trace e1b64ced7a89adcd ]--- ftrace failed to modify [<e9ef7006>] 0xe9ef7006 actual: 02:f0:3b:fa ftrace record flags: 0 (0) expected tramp: c0314265 Signed-off-by: Alexander Sverdlin <alexander.sverdlin@nokia.com> --- arch/arm/include/asm/ftrace.h | 3 +++ arch/arm/include/asm/module.h | 1 + arch/arm/kernel/ftrace.c | 46 +++++++++++++++++++++++++++++++++++++++++-- arch/arm/kernel/module-plts.c | 44 +++++++++++++++++++++++++++++++++++++---- 4 files changed, 88 insertions(+), 6 deletions(-) diff --git a/arch/arm/include/asm/ftrace.h b/arch/arm/include/asm/ftrace.h index 48ec1d0..a4dbac0 100644 --- a/arch/arm/include/asm/ftrace.h +++ b/arch/arm/include/asm/ftrace.h @@ -15,6 +15,9 @@ extern void __gnu_mcount_nc(void); #ifdef CONFIG_DYNAMIC_FTRACE struct dyn_arch_ftrace { +#ifdef CONFIG_ARM_MODULE_PLTS + struct module *mod; +#endif }; static inline unsigned long ftrace_call_adjust(unsigned long addr) diff --git a/arch/arm/include/asm/module.h b/arch/arm/include/asm/module.h index 78e4c16..961fedb 100644 --- a/arch/arm/include/asm/module.h +++ b/arch/arm/include/asm/module.h @@ -30,6 +30,7 @@ struct plt_entries { struct mod_plt_sec { struct elf32_shdr *plt; + struct plt_entries *plt_ent; int plt_count; }; diff --git a/arch/arm/kernel/ftrace.c b/arch/arm/kernel/ftrace.c index 10499d4..75830e5 100644 --- a/arch/arm/kernel/ftrace.c +++ b/arch/arm/kernel/ftrace.c @@ -70,6 +70,19 @@ int ftrace_arch_code_modify_post_process(void) static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr) { + s32 offset = addr - pc; + s32 blim = 0xfe000008; + s32 flim = 0x02000004; + + if (IS_ENABLED(CONFIG_THUMB2_KERNEL)) { + blim = 0xff000004; + flim = 0x01000002; + } + + if (IS_ENABLED(CONFIG_ARM_MODULE_PLTS) && + (offset < blim || offset > flim)) + return 0; + return arm_gen_branch_link(pc, addr); } @@ -123,10 +136,22 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) { unsigned long new, old; unsigned long ip = rec->ip; + unsigned long aaddr = adjust_address(rec, addr); old = ftrace_nop_replace(rec); - new = ftrace_call_replace(ip, adjust_address(rec, addr)); + new = ftrace_call_replace(ip, aaddr); + +#ifdef CONFIG_ARM_MODULE_PLTS + if (!new) { + struct module *mod = rec->arch.mod; + + if (mod) { + aaddr = get_module_plt(mod, ip, aaddr); + new = ftrace_call_replace(ip, aaddr); + } + } +#endif return ftrace_modify_code(rec->ip, old, new, true); } @@ -151,12 +176,29 @@ int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, unsigned long addr) { + unsigned long aaddr = adjust_address(rec, addr); unsigned long ip = rec->ip; unsigned long old; unsigned long new; int ret; - old = ftrace_call_replace(ip, adjust_address(rec, addr)); +#ifdef CONFIG_ARM_MODULE_PLTS + /* mod is only supplied during module loading */ + if (!mod) + mod = rec->arch.mod; + else + rec->arch.mod = mod; +#endif + + old = ftrace_call_replace(ip, aaddr); + +#ifdef CONFIG_ARM_MODULE_PLTS + if (!old && mod) { + aaddr = get_module_plt(mod, ip, aaddr); + old = ftrace_call_replace(ip, aaddr); + } +#endif + new = ftrace_nop_replace(rec); ret = ftrace_modify_code(ip, old, new, true); diff --git a/arch/arm/kernel/module-plts.c b/arch/arm/kernel/module-plts.c index d330e9e..a0524ad 100644 --- a/arch/arm/kernel/module-plts.c +++ b/arch/arm/kernel/module-plts.c @@ -4,6 +4,7 @@ */ #include <linux/elf.h> +#include <linux/ftrace.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/sort.h> @@ -20,19 +21,52 @@ (PLT_ENT_STRIDE - 8)) #endif +static const u32 fixed_plts[] = { +#ifdef CONFIG_FUNCTION_TRACER + FTRACE_ADDR, + MCOUNT_ADDR, +#endif +}; + static bool in_init(const struct module *mod, unsigned long loc) { return loc - (u32)mod->init_layout.base < mod->init_layout.size; } +static void prealloc_fixed(struct mod_plt_sec *pltsec, struct plt_entries *plt) +{ + int i; + + if (!ARRAY_SIZE(fixed_plts) || pltsec->plt_count) + return; + pltsec->plt_count = ARRAY_SIZE(fixed_plts); + + for (i = 0; i < ARRAY_SIZE(plt->ldr); ++i) + plt->ldr[i] = PLT_ENT_LDR; + + BUILD_BUG_ON(sizeof(fixed_plts) > sizeof(plt->lit)); + memcpy(plt->lit, fixed_plts, sizeof(fixed_plts)); +} + u32 get_module_plt(struct module *mod, unsigned long loc, Elf32_Addr val) { struct mod_plt_sec *pltsec = !in_init(mod, loc) ? &mod->arch.core : &mod->arch.init; + struct plt_entries *plt; + int idx; + + /* cache the address, ELF header is available only during module load */ + if (!pltsec->plt_ent) + pltsec->plt_ent = (struct plt_entries *)pltsec->plt->sh_addr; + plt = pltsec->plt_ent; - struct plt_entries *plt = (struct plt_entries *)pltsec->plt->sh_addr; - int idx = 0; + prealloc_fixed(pltsec, plt); + + for (idx = 0; idx < ARRAY_SIZE(fixed_plts); ++idx) + if (plt->lit[idx] == val) + return (u32)&plt->ldr[idx]; + idx = 0; /* * Look for an existing entry pointing to 'val'. Given that the * relocations are sorted, this will be the last entry we allocated. @@ -180,8 +214,8 @@ static unsigned int count_plts(const Elf32_Sym *syms, Elf32_Addr base, int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, char *secstrings, struct module *mod) { - unsigned long core_plts = 0; - unsigned long init_plts = 0; + unsigned long core_plts = ARRAY_SIZE(fixed_plts); + unsigned long init_plts = ARRAY_SIZE(fixed_plts); Elf32_Shdr *s, *sechdrs_end = sechdrs + ehdr->e_shnum; Elf32_Sym *syms = NULL; @@ -236,6 +270,7 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, mod->arch.core.plt->sh_size = round_up(core_plts * PLT_ENT_SIZE, sizeof(struct plt_entries)); mod->arch.core.plt_count = 0; + mod->arch.core.plt_ent = NULL; mod->arch.init.plt->sh_type = SHT_NOBITS; mod->arch.init.plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC; @@ -243,6 +278,7 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, mod->arch.init.plt->sh_size = round_up(init_plts * PLT_ENT_SIZE, sizeof(struct plt_entries)); mod->arch.init.plt_count = 0; + mod->arch.init.plt_ent = NULL; pr_debug("%s: plt=%x, init.plt=%x\n", __func__, mod->arch.core.plt->sh_size, mod->arch.init.plt->sh_size); -- 2.4.6 ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v6 0/2] ARM: Implement MODULE_PLT support in FTRACE 2020-02-17 14:09 [PATCH v6 0/2] ARM: Implement MODULE_PLT support in FTRACE Alexander X Sverdlin 2020-02-17 14:09 ` [PATCH v6 1/2] ARM: PLT: Move struct plt_entries definition to header Alexander X Sverdlin 2020-02-17 14:09 ` [PATCH v6 2/2] ARM: ftrace: Add MODULE_PLTS support Alexander X Sverdlin @ 2021-01-27 4:48 ` Florian Fainelli 2021-01-27 10:43 ` Alexander Sverdlin 2 siblings, 1 reply; 5+ messages in thread From: Florian Fainelli @ 2021-01-27 4:48 UTC (permalink / raw) To: Alexander X Sverdlin, linux-arm-kernel Cc: Ard Biesheuvel, linux-kernel, Steven Rostedt, Russell King, Ingo Molnar Hi Alexander, On 2/17/2020 6:09 AM, Alexander X Sverdlin wrote: > From: Alexander Sverdlin <alexander.sverdlin@nokia.com> > > FTRACE's function tracer currently doesn't always work on ARM with > MODULE_PLT option enabled. If the module is loaded too far, FTRACE's > code modifier cannot cope with introduced veneers and turns the > function tracer off globally. > > ARM64 already has a solution for the problem, refer to the following > patches: > > arm64: ftrace: emit ftrace-mod.o contents through code > arm64: module-plts: factor out PLT generation code for ftrace > arm64: ftrace: fix !CONFIG_ARM64_MODULE_PLTS kernels > arm64: ftrace: fix building without CONFIG_MODULES > arm64: ftrace: add support for far branches to dynamic ftrace > arm64: ftrace: don't validate branch via PLT in ftrace_make_nop() > > But the presented ARM variant has just a half of the footprint in terms of > the changed LoCs. It also retains the code validation-before-modification > instead of switching it off. We have been using those patches and I was wondering what happened after this version since they did not show up upstream nor in Russell's patch tracker? Would you be willing to resubmit them? Thanks! -- Florian ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v6 0/2] ARM: Implement MODULE_PLT support in FTRACE 2021-01-27 4:48 ` [PATCH v6 0/2] ARM: Implement MODULE_PLT support in FTRACE Florian Fainelli @ 2021-01-27 10:43 ` Alexander Sverdlin 0 siblings, 0 replies; 5+ messages in thread From: Alexander Sverdlin @ 2021-01-27 10:43 UTC (permalink / raw) To: Florian Fainelli, linux-arm-kernel Cc: Ard Biesheuvel, linux-kernel, Steven Rostedt, Russell King, Ingo Molnar Hello Florian, On 27/01/2021 05:48, Florian Fainelli wrote: >> FTRACE's function tracer currently doesn't always work on ARM with >> MODULE_PLT option enabled. If the module is loaded too far, FTRACE's >> code modifier cannot cope with introduced veneers and turns the >> function tracer off globally. >> >> ARM64 already has a solution for the problem, refer to the following >> patches: >> >> arm64: ftrace: emit ftrace-mod.o contents through code >> arm64: module-plts: factor out PLT generation code for ftrace >> arm64: ftrace: fix !CONFIG_ARM64_MODULE_PLTS kernels >> arm64: ftrace: fix building without CONFIG_MODULES >> arm64: ftrace: add support for far branches to dynamic ftrace >> arm64: ftrace: don't validate branch via PLT in ftrace_make_nop() >> >> But the presented ARM variant has just a half of the footprint in terms of >> the changed LoCs. It also retains the code validation-before-modification >> instead of switching it off. > We have been using those patches and I was wondering what happened after > this version since they did not show up upstream nor in Russell's patch > tracker? Would you be willing to resubmit them? it's a pity, but nobody ever showed any interest to take them to fix real problem in FTRACE. A grain of salt would be to remind, that no-one also replied that the series helped him or a Tested-by: tag. This would probably wake more interest from maintainers side. Of course I can re-send them because I personally re-base them regularly. -- Best regards, Alexander Sverdlin. ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2021-01-27 10:47 UTC | newest] Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2020-02-17 14:09 [PATCH v6 0/2] ARM: Implement MODULE_PLT support in FTRACE Alexander X Sverdlin 2020-02-17 14:09 ` [PATCH v6 1/2] ARM: PLT: Move struct plt_entries definition to header Alexander X Sverdlin 2020-02-17 14:09 ` [PATCH v6 2/2] ARM: ftrace: Add MODULE_PLTS support Alexander X Sverdlin 2021-01-27 4:48 ` [PATCH v6 0/2] ARM: Implement MODULE_PLT support in FTRACE Florian Fainelli 2021-01-27 10:43 ` Alexander Sverdlin
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®