@@ -93,6 +93,7 @@ config PPC
select OF_EARLY_FLATTREE
select OF_RESERVED_MEM
select HAVE_FTRACE_MCOUNT_RECORD
+ select HAVE_C_RECORDMCOUNT
select HAVE_DYNAMIC_FTRACE
select HAVE_DYNAMIC_FTRACE_WITH_REGS if PPC64 && CPU_LITTLE_ENDIAN
select HAVE_FUNCTION_TRACER
@@ -121,6 +121,7 @@ config S390
select HAVE_ARCH_TRACEHOOK
select HAVE_ARCH_TRANSPARENT_HUGEPAGE
select HAVE_BPF_JIT if PACK_STACK && HAVE_MARCH_Z196_FEATURES
+ select HAVE_C_RECORDMCOUNT
select HAVE_CMPXCHG_DOUBLE
select HAVE_CMPXCHG_LOCAL
select HAVE_DEBUG_KMEMLEAK
@@ -1,3 +1,16 @@
obj-$(CONFIG_LIVEPATCH) += livepatch.o
livepatch-objs := core.o
+
+always := $(hostprogs-y) ftrace-test.o
+
+# dependencies on generated files need to be listed explicitly
+$(obj)/core.o: $(obj)/livepatch-ftrace.h
+
+quiet_cmd_livepatch-rmcount = RMCOUNT $@
+ cmd_livepatch-rmcount = $(objtree)/scripts/recordmcount -p $< > $@
+
+$(obj)/livepatch-ftrace.h: $(obj)/ftrace-test.o $(objtree)/scripts/recordmcount
+ $(call if_changed,livepatch-rmcount)
+
+targets += livepatch-ftrace.h
@@ -30,6 +30,8 @@
#include <linux/livepatch.h>
#include <asm/cacheflush.h>
+#include "livepatch-ftrace.h"
+
/**
* struct klp_ops - structure for tracking registered ftrace ops structs
*
@@ -312,8 +314,10 @@ static void klp_disable_func(struct klp_func *func)
return;
if (list_is_singular(&ops->func_stack)) {
+ unsigned long ftrace_loc = func->old_addr + KLP_FTRACE_LOCATION;
+
WARN_ON(unregister_ftrace_function(&ops->fops));
- WARN_ON(ftrace_set_filter_ip(&ops->fops, func->old_addr, 1, 0));
+ WARN_ON(ftrace_set_filter_ip(&ops->fops, ftrace_loc, 1, 0));
list_del_rcu(&func->stack_node);
list_del(&ops->node);
@@ -338,6 +342,8 @@ static int klp_enable_func(struct klp_func *func)
ops = klp_find_ops(func->old_addr);
if (!ops) {
+ unsigned long ftrace_loc = func->old_addr + KLP_FTRACE_LOCATION;
+
ops = kzalloc(sizeof(*ops), GFP_KERNEL);
if (!ops)
return -ENOMEM;
@@ -352,7 +358,7 @@ static int klp_enable_func(struct klp_func *func)
INIT_LIST_HEAD(&ops->func_stack);
list_add_rcu(&func->stack_node, &ops->func_stack);
- ret = ftrace_set_filter_ip(&ops->fops, func->old_addr, 0, 0);
+ ret = ftrace_set_filter_ip(&ops->fops, ftrace_loc, 0, 0);
if (ret) {
pr_err("failed to set ftrace filter for function '%s' (%d)\n",
func->old_name, ret);
@@ -363,7 +369,7 @@ static int klp_enable_func(struct klp_func *func)
if (ret) {
pr_err("failed to register ftrace handler for function '%s' (%d)\n",
func->old_name, ret);
- ftrace_set_filter_ip(&ops->fops, func->old_addr, 1, 0);
+ ftrace_set_filter_ip(&ops->fops, ftrace_loc, 1, 0);
goto err;
}
new file mode 100644
@@ -0,0 +1,6 @@
+/* Sample code to figure out mcount location offset */
+
+int test(int a)
+{
+ return ++a;
+}
@@ -53,6 +53,7 @@ static struct stat sb; /* Remember .st_size, etc. */
static jmp_buf jmpenv; /* setjmp/longjmp per-file error escape */
static const char *altmcount; /* alternate mcount symbol name */
static int warn_on_notrace_sect; /* warn when section has mcount not being recorded */
+static int print_mcount_offset; /* print offset of the first mcount location */
static void *file_map; /* pointer of the mapped file */
static void *file_end; /* pointer to the end of the mapped file */
static int file_updated; /* flag to state file was changed */
@@ -539,11 +540,14 @@ main(int argc, char *argv[])
int c;
int i;
- while ((c = getopt(argc, argv, "w")) >= 0) {
+ while ((c = getopt(argc, argv, "wp")) >= 0) {
switch (c) {
case 'w':
warn_on_notrace_sect = 1;
break;
+ case 'p':
+ print_mcount_offset = 1;
+ break;
default:
fprintf(stderr, "usage: recordmcount [-w] file.o...\n");
return 0;
@@ -47,6 +47,7 @@
#undef fn_ELF_R_SYM
#undef fn_ELF_R_INFO
#undef uint_t
+#undef uint_t_format
#undef _w
#undef _align
#undef _size
@@ -81,6 +82,7 @@
# define fn_ELF_R_SYM fn_ELF64_R_SYM
# define fn_ELF_R_INFO fn_ELF64_R_INFO
# define uint_t uint64_t
+# define uint_t_format "%lu"
# define _w w8
# define _align 7u
# define _size 8
@@ -114,6 +116,7 @@
# define fn_ELF_R_SYM fn_ELF32_R_SYM
# define fn_ELF_R_INFO fn_ELF32_R_INFO
# define uint_t uint32_t
+# define uint_t_format "%u"
# define _w w
# define _align 3u
# define _size 4
@@ -338,7 +341,14 @@ static uint_t *sift_rel_mcount(uint_t *mlocp,
} else
*mlocp++ = addend;
+ if (print_mcount_offset) {
+ printf("#define KLP_FTRACE_LOCATION " uint_t_format "\n",
+ addend);
+ succeed_file();
+ }
+
mrelp = (Elf_Rel *)(rel_entsize + (void *)mrelp);
+
}
relp = (Elf_Rel const *)(rel_entsize + (void *)relp);
}
@@ -458,7 +468,8 @@ __has_rel_mcount(Elf_Shdr const *const relhdr, /* is SHT_REL or SHT_RELA */
Elf_Shdr const *const txthdr = &shdr0[w(relhdr->sh_info)];
char const *const txtname = &shstrtab[w(txthdr->sh_name)];
- if (strcmp("__mcount_loc", txtname) == 0) {
+ /* Allow to print the mcount offset for an already modified file. */
+ if (strcmp("__mcount_loc", txtname) == 0 && !print_mcount_offset) {
fprintf(stderr, "warning: __mcount_loc already exists: %s\n",
fname);
succeed_file();
@@ -546,7 +557,9 @@ do_func(Elf_Ehdr *const ehdr, char const *const fname, unsigned const reltype)
nop_mcount(relhdr, ehdr, txtname);
}
}
- if (mloc0 != mlocp) {
+
+ /* The file is not modified when the offset is just printed. */
+ if (mloc0 != mlocp && !print_mcount_offset) {
append_func(ehdr, shstr, mloc0, mlocp, mrel0, mrelp,
rel_entsize, symsec_sh_link);
}