* [PATCH 1/3] ftrace: Add module to ftrace_make_call() parameters
2018-02-23 16:58 [PATCH 0/3] ARM: Implement MODULE_PLT support in FTRACE Alexander Sverdlin
@ 2018-02-23 16:58 ` Alexander Sverdlin
2018-02-25 11:53 ` kbuild test robot
2018-02-25 14:57 ` kbuild test robot
2018-02-23 16:58 ` [PATCH 2/3] ARM: PLT: Move struct plt_entries definition to header Alexander Sverdlin
2018-02-23 16:58 ` [PATCH 3/3] ftrace: Add MODULE_PLTS support Alexander Sverdlin
2 siblings, 2 replies; 6+ messages in thread
From: Alexander Sverdlin @ 2018-02-23 16:58 UTC (permalink / raw)
To: Steven Rostedt, Ingo Molnar, linux-arm-kernel, linux-kernel
Cc: Alexander Sverdlin, Russell King, Catalin Marinas, Will Deacon,
Steven Miao, Tony Luck, Fenghua Yu, James Hogan, Michal Simek,
Ralf Baechle, Benjamin Herrenschmidt, Paul Mackerras,
Michael Ellerman, Martin Schwidefsky, Heiko Carstens,
Yoshinori Sato, Rich Felker, David S. Miller, Chris Metcalf,
Thomas Gleixner, H. Peter Anvin, x86, adi-buildroot-devel,
linux-ia64, linux-metag, linux-mips, linuxppc-dev, linux-s390,
linux-sh, sparclinux
ARM support for modules' PLTs will require a module pointer in
ftrace_make_call() exactly as ftrace_make_nop() has it. Change the function
signature without functional change for now.
Signed-off-by: Alexander Sverdlin <alexander.sverdlin@nokia.com>
---
arch/arm/kernel/ftrace.c | 3 ++-
arch/arm64/kernel/ftrace.c | 3 ++-
arch/blackfin/kernel/ftrace.c | 3 ++-
arch/ia64/kernel/ftrace.c | 3 ++-
arch/metag/kernel/ftrace.c | 3 ++-
arch/microblaze/kernel/ftrace.c | 3 ++-
arch/mips/kernel/ftrace.c | 3 ++-
arch/powerpc/kernel/trace/ftrace.c | 3 ++-
arch/s390/kernel/ftrace.c | 3 ++-
arch/sh/kernel/ftrace.c | 3 ++-
arch/sparc/kernel/ftrace.c | 3 ++-
arch/tile/kernel/ftrace.c | 3 ++-
arch/x86/kernel/ftrace.c | 3 ++-
include/linux/ftrace.h | 4 +++-
kernel/trace/ftrace.c | 6 +++---
15 files changed, 32 insertions(+), 17 deletions(-)
diff --git a/arch/arm/kernel/ftrace.c b/arch/arm/kernel/ftrace.c
index 5617932..be20adc 100644
--- a/arch/arm/kernel/ftrace.c
+++ b/arch/arm/kernel/ftrace.c
@@ -162,7 +162,8 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
return ret;
}
-int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+int ftrace_make_call(struct module *mod, struct dyn_ftrace *rec,
+ unsigned long addr)
{
unsigned long new, old;
unsigned long ip = rec->ip;
diff --git a/arch/arm64/kernel/ftrace.c b/arch/arm64/kernel/ftrace.c
index 50986e3..e3a95d3 100644
--- a/arch/arm64/kernel/ftrace.c
+++ b/arch/arm64/kernel/ftrace.c
@@ -68,7 +68,8 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
/*
* Turn on the call to ftrace_caller() in instrumented function
*/
-int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+int ftrace_make_call(struct module *mod, struct dyn_ftrace *rec,
+ unsigned long addr)
{
unsigned long pc = rec->ip;
u32 old, new;
diff --git a/arch/blackfin/kernel/ftrace.c b/arch/blackfin/kernel/ftrace.c
index 8dad758..61ffc99 100644
--- a/arch/blackfin/kernel/ftrace.c
+++ b/arch/blackfin/kernel/ftrace.c
@@ -45,7 +45,8 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
return ftrace_modify_code(rec->ip, mnop, sizeof(mnop));
}
-int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+int ftrace_make_call(struct module *mod, struct dyn_ftrace *rec,
+ unsigned long addr)
{
/* Restore the mcount call site */
unsigned char call[8];
diff --git a/arch/ia64/kernel/ftrace.c b/arch/ia64/kernel/ftrace.c
index cee411e..658a011 100644
--- a/arch/ia64/kernel/ftrace.c
+++ b/arch/ia64/kernel/ftrace.c
@@ -169,7 +169,8 @@ int ftrace_make_nop(struct module *mod,
return ftrace_modify_code(rec->ip, NULL, new, 0);
}
-int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+int ftrace_make_call(struct module *mod, struct dyn_ftrace *rec,
+ unsigned long addr)
{
unsigned long ip = rec->ip;
unsigned char *old, *new;
diff --git a/arch/metag/kernel/ftrace.c b/arch/metag/kernel/ftrace.c
index f7b23d3..635652a 100644
--- a/arch/metag/kernel/ftrace.c
+++ b/arch/metag/kernel/ftrace.c
@@ -104,7 +104,8 @@ int ftrace_make_nop(struct module *mod,
return ftrace_modify_code(ip, old, new);
}
-int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+int ftrace_make_call(struct module *mod, struct dyn_ftrace *rec,
+ unsigned long addr)
{
unsigned char *new, *old;
unsigned long ip = rec->ip;
diff --git a/arch/microblaze/kernel/ftrace.c b/arch/microblaze/kernel/ftrace.c
index d57563c..01b314a 100644
--- a/arch/microblaze/kernel/ftrace.c
+++ b/arch/microblaze/kernel/ftrace.c
@@ -161,7 +161,8 @@ int ftrace_make_nop(struct module *mod,
}
/* I believe that first is called ftrace_make_nop before this function */
-int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+int ftrace_make_call(struct module *mod, struct dyn_ftrace *rec,
+ unsigned long addr)
{
int ret;
pr_debug("%s: addr:0x%x, rec->ip: 0x%x, imm:0x%x\n",
diff --git a/arch/mips/kernel/ftrace.c b/arch/mips/kernel/ftrace.c
index 7f3dfdb..9dcec19 100644
--- a/arch/mips/kernel/ftrace.c
+++ b/arch/mips/kernel/ftrace.c
@@ -200,7 +200,8 @@ int ftrace_make_nop(struct module *mod,
#endif
}
-int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+int ftrace_make_call(struct module *mod, struct dyn_ftrace *rec,
+ unsigned long addr)
{
unsigned int new;
unsigned long ip = rec->ip;
diff --git a/arch/powerpc/kernel/trace/ftrace.c b/arch/powerpc/kernel/trace/ftrace.c
index 4741fe1..b198433 100644
--- a/arch/powerpc/kernel/trace/ftrace.c
+++ b/arch/powerpc/kernel/trace/ftrace.c
@@ -437,7 +437,8 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
#endif /* CONFIG_PPC64 */
#endif /* CONFIG_MODULES */
-int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+int ftrace_make_call(struct module *mod, struct dyn_ftrace *rec,
+ unsigned long addr)
{
unsigned long ip = rec->ip;
unsigned int old, new;
diff --git a/arch/s390/kernel/ftrace.c b/arch/s390/kernel/ftrace.c
index dc76d81..1691d53 100644
--- a/arch/s390/kernel/ftrace.c
+++ b/arch/s390/kernel/ftrace.c
@@ -136,7 +136,8 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
return 0;
}
-int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+int ftrace_make_call(struct module *mod, struct dyn_ftrace *rec,
+ unsigned long addr)
{
struct ftrace_insn orig, new, old;
diff --git a/arch/sh/kernel/ftrace.c b/arch/sh/kernel/ftrace.c
index 96dd9f7..2d3cacd 100644
--- a/arch/sh/kernel/ftrace.c
+++ b/arch/sh/kernel/ftrace.c
@@ -242,7 +242,8 @@ int ftrace_make_nop(struct module *mod,
return ftrace_modify_code(rec->ip, old, new);
}
-int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+int ftrace_make_call(struct module *mod, struct dyn_ftrace *rec,
+ unsigned long addr)
{
unsigned char *new, *old;
unsigned long ip = rec->ip;
diff --git a/arch/sparc/kernel/ftrace.c b/arch/sparc/kernel/ftrace.c
index 915dda4..36117b5 100644
--- a/arch/sparc/kernel/ftrace.c
+++ b/arch/sparc/kernel/ftrace.c
@@ -63,7 +63,8 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, unsigned long ad
return ftrace_modify_code(ip, old, new);
}
-int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+int ftrace_make_call(struct module *mod, struct dyn_ftrace *rec,
+ unsigned long addr)
{
unsigned long ip = rec->ip;
u32 old, new;
diff --git a/arch/tile/kernel/ftrace.c b/arch/tile/kernel/ftrace.c
index b827a41..749e50f 100644
--- a/arch/tile/kernel/ftrace.c
+++ b/arch/tile/kernel/ftrace.c
@@ -136,7 +136,8 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
return ret;
}
-int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+int ftrace_make_call(struct module *mod, struct dyn_ftrace *rec,
+ unsigned long addr)
{
unsigned long new, old;
unsigned long ip = rec->ip;
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c
index 01ebcb6..389f15c 100644
--- a/arch/x86/kernel/ftrace.c
+++ b/arch/x86/kernel/ftrace.c
@@ -162,7 +162,8 @@ int ftrace_make_nop(struct module *mod,
return -EINVAL;
}
-int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+int ftrace_make_call(struct module *mod, struct dyn_ftrace *rec,
+ unsigned long addr)
{
unsigned const char *new, *old;
unsigned long ip = rec->ip;
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 9c3c9a3..1e8c421 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -536,6 +536,7 @@ extern int ftrace_make_nop(struct module *mod,
/**
* ftrace_make_call - convert a nop call site into a call to addr
+ * @mod: module structure if called by module load initialization
* @rec: the mcount call site record
* @addr: the address that the call site should call
*
@@ -554,7 +555,8 @@ extern int ftrace_make_nop(struct module *mod,
* -EPERM on error writing to the location
* Any other value will be considered a failure.
*/
-extern int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr);
+extern int ftrace_make_call(struct module *mod, struct dyn_ftrace *rec,
+ unsigned long addr);
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
/**
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index eac9ce2..d32f2f5 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -2421,7 +2421,7 @@ unsigned long ftrace_get_addr_curr(struct dyn_ftrace *rec)
}
static int
-__ftrace_replace_code(struct dyn_ftrace *rec, int enable)
+__ftrace_replace_code(struct module *mod, struct dyn_ftrace *rec, int enable)
{
unsigned long ftrace_old_addr;
unsigned long ftrace_addr;
@@ -2442,7 +2442,7 @@ __ftrace_replace_code(struct dyn_ftrace *rec, int enable)
case FTRACE_UPDATE_MAKE_CALL:
ftrace_bug_type = FTRACE_BUG_CALL;
- return ftrace_make_call(rec, ftrace_addr);
+ return ftrace_make_call(mod, rec, ftrace_addr);
case FTRACE_UPDATE_MAKE_NOP:
ftrace_bug_type = FTRACE_BUG_NOP;
@@ -2470,7 +2470,7 @@ void __weak ftrace_replace_code(int enable)
if (rec->flags & FTRACE_FL_DISABLED)
continue;
- failed = __ftrace_replace_code(rec, enable);
+ failed = __ftrace_replace_code(NULL, rec, enable);
if (failed) {
ftrace_bug(failed, rec);
/* Stop processing */
--
2.4.6
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 2/3] ARM: PLT: Move struct plt_entries definition to header
2018-02-23 16:58 [PATCH 0/3] ARM: Implement MODULE_PLT support in FTRACE Alexander Sverdlin
2018-02-23 16:58 ` [PATCH 1/3] ftrace: Add module to ftrace_make_call() parameters Alexander Sverdlin
@ 2018-02-23 16:58 ` Alexander Sverdlin
2018-02-23 16:58 ` [PATCH 3/3] ftrace: Add MODULE_PLTS support Alexander Sverdlin
2 siblings, 0 replies; 6+ messages in thread
From: Alexander Sverdlin @ 2018-02-23 16:58 UTC (permalink / raw)
To: Steven Rostedt, Ingo Molnar, linux-arm-kernel, linux-kernel
Cc: Alexander Sverdlin, Russell King, Catalin Marinas, Will Deacon,
Steven Miao, Tony Luck, Fenghua Yu, James Hogan, Michal Simek,
Ralf Baechle, Benjamin Herrenschmidt, Paul Mackerras,
Michael Ellerman, Martin Schwidefsky, Heiko Carstens,
Yoshinori Sato, Rich Felker, David S. Miller, Chris Metcalf,
Thomas Gleixner, H. Peter Anvin, x86, adi-buildroot-devel,
linux-ia64, linux-metag, linux-mips, linuxppc-dev, linux-s390,
linux-sh, sparclinux
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 89ad059..6996405 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 3d0c2e4..f272711 100644
--- a/arch/arm/kernel/module-plts.c
+++ b/arch/arm/kernel/module-plts.c
@@ -14,10 +14,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))
@@ -26,11 +22,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 related [flat|nested] 6+ messages in thread* [PATCH 3/3] ftrace: Add MODULE_PLTS support
2018-02-23 16:58 [PATCH 0/3] ARM: Implement MODULE_PLT support in FTRACE Alexander Sverdlin
2018-02-23 16:58 ` [PATCH 1/3] ftrace: Add module to ftrace_make_call() parameters Alexander Sverdlin
2018-02-23 16:58 ` [PATCH 2/3] ARM: PLT: Move struct plt_entries definition to header Alexander Sverdlin
@ 2018-02-23 16:58 ` Alexander Sverdlin
2 siblings, 0 replies; 6+ messages in thread
From: Alexander Sverdlin @ 2018-02-23 16:58 UTC (permalink / raw)
To: Steven Rostedt, Ingo Molnar, linux-arm-kernel, linux-kernel
Cc: Alexander Sverdlin, Russell King, Catalin Marinas, Will Deacon,
Steven Miao, Tony Luck, Fenghua Yu, James Hogan, Michal Simek,
Ralf Baechle, Benjamin Herrenschmidt, Paul Mackerras,
Michael Ellerman, Martin Schwidefsky, Heiko Carstens,
Yoshinori Sato, Rich Felker, David S. Miller, Chris Metcalf,
Thomas Gleixner, H. Peter Anvin, x86, adi-buildroot-devel,
linux-ia64, linux-metag, linux-mips, linuxppc-dev, linux-s390,
linux-sh, sparclinux
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/module.h | 1 +
arch/arm/kernel/ftrace.c | 70 ++++++++++++++++++++++++++++++++++++-------
arch/arm/kernel/module-plts.c | 53 ++++++++++++++++++++++++--------
3 files changed, 101 insertions(+), 23 deletions(-)
diff --git a/arch/arm/include/asm/module.h b/arch/arm/include/asm/module.h
index 6996405..e3d7a51 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 be20adc..0a0da25 100644
--- a/arch/arm/kernel/ftrace.c
+++ b/arch/arm/kernel/ftrace.c
@@ -98,6 +98,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);
}
@@ -167,10 +180,27 @@ int ftrace_make_call(struct module *mod, struct dyn_ftrace *rec,
{
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) {
+ /*
+ * mod is only supplied during module loading, later we have to
+ * search for it
+ */
+ if (!mod)
+ mod = __module_address(ip);
+
+ 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);
}
@@ -200,20 +230,40 @@ int ftrace_make_nop(struct module *mod,
unsigned long new;
int ret;
- old = ftrace_call_replace(ip, adjust_address(rec, addr));
- new = ftrace_nop_replace(rec);
- ret = ftrace_modify_code(ip, old, new, true);
-
-#ifdef CONFIG_OLD_MCOUNT
- if (ret == -EINVAL && addr == MCOUNT_ADDR) {
- rec->arch.old_mcount = true;
+ for (;;) {
+ unsigned long aaddr = adjust_address(rec, addr);
+
+ old = ftrace_call_replace(ip, aaddr);
+
+#ifdef CONFIG_ARM_MODULE_PLTS
+ if (!old) {
+ /*
+ * mod is only supplied during module loading, later we
+ * have to search for it
+ */
+ if (!mod)
+ mod = __module_address(ip);
+
+ if (mod) {
+ aaddr = get_module_plt(mod, ip, aaddr);
+ old = ftrace_call_replace(ip, aaddr);
+ }
+ }
+#endif
- old = ftrace_call_replace(ip, adjust_address(rec, addr));
new = ftrace_nop_replace(rec);
ret = ftrace_modify_code(ip, old, new, true);
- }
+
+#ifdef CONFIG_OLD_MCOUNT
+ if (ret == -EINVAL && !rec->arch.old_mcount) {
+ rec->arch.old_mcount = true;
+ continue;
+ }
#endif
+ break;
+ }
+
return ret;
}
diff --git a/arch/arm/kernel/module-plts.c b/arch/arm/kernel/module-plts.c
index f272711..a216256 100644
--- a/arch/arm/kernel/module-plts.c
+++ b/arch/arm/kernel/module-plts.c
@@ -7,6 +7,7 @@
*/
#include <linux/elf.h>
+#include <linux/ftrace.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sort.h>
@@ -22,6 +23,15 @@
(PLT_ENT_STRIDE - 8))
#endif
+static u32 fixed_plts[] = {
+ FTRACE_ADDR,
+ MCOUNT_ADDR,
+#ifdef CONFIG_OLD_MCOUNT
+ (unsigned long)ftrace_caller_old,
+ (unsigned long)mcount,
+#endif
+};
+
static bool in_init(const struct module *mod, unsigned long loc)
{
return loc - (u32)mod->init_layout.base < mod->init_layout.size;
@@ -31,26 +41,43 @@ 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;
+ int idx;
+ struct plt_entries *plt;
+
+ /* Pre-allocate entries in the first plt */
+ if (!pltsec->plt_count) {
+ plt = (struct plt_entries *)pltsec->plt->sh_addr;
+ for (idx = 0; idx < ARRAY_SIZE(plt->ldr); ++idx)
+ plt->ldr[idx] = PLT_ENT_LDR;
+ memcpy(plt->lit, fixed_plts, sizeof(fixed_plts));
+ pltsec->plt_count = ARRAY_SIZE(fixed_plts);
+ /*
+ * cache the address,
+ * ELF header is available only during module load
+ */
+ pltsec->plt_ent = plt;
+ }
+ plt = pltsec->plt_ent;
- struct plt_entries *plt = (struct plt_entries *)pltsec->plt->sh_addr;
- int idx = 0;
+ idx = ARRAY_SIZE(fixed_plts);
+ while (idx)
+ if (plt->lit[--idx] == val)
+ return (u32)&plt->ldr[idx];
/*
* Look for an existing entry pointing to 'val'. Given that the
* relocations are sorted, this will be the last entry we allocated.
* (if one exists).
*/
- if (pltsec->plt_count > 0) {
- plt += (pltsec->plt_count - 1) / PLT_ENT_COUNT;
- idx = (pltsec->plt_count - 1) % PLT_ENT_COUNT;
+ plt += (pltsec->plt_count - 1) / PLT_ENT_COUNT;
+ idx = (pltsec->plt_count - 1) % PLT_ENT_COUNT;
- if (plt->lit[idx] == val)
- return (u32)&plt->ldr[idx];
+ if (plt->lit[idx] == val)
+ return (u32)&plt->ldr[idx];
- idx = (idx + 1) % PLT_ENT_COUNT;
- if (!idx)
- plt++;
- }
+ idx = (idx + 1) % PLT_ENT_COUNT;
+ if (!idx)
+ plt++;
pltsec->plt_count++;
BUG_ON(pltsec->plt_count * PLT_ENT_SIZE > pltsec->plt->sh_size);
@@ -182,8 +209,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;
--
2.4.6
^ permalink raw reply related [flat|nested] 6+ messages in thread