ranges: add initial kprobes demo
This adds a small demo of sectoin ranges matching the style
used in the Linux kernel for kprobes. The only use case we give
and test here is being able to annotate routines as part of
the kprobe section, or not. We test a __kprobes routine, and
then also test another routine without the __kprobes annotation.
To support section ranges properly I noticed we needed to also
extend ranges.h with a proper:
SECTION_RANGE_BEGIN()
SECTION_RANGE_END()
These are used for the DEFINE_SECTION_RANGE(), which is used
to require the user to specify the specific section the custom
section range being defined belongs to.
The next required set of tests would be to test sub-sections...
Its not clear what examples there are for these yet though.
At least I have not seen them in
Results:
Initializing x86 bare metal world
Number of init entries: 8
Initializing kasan ...
Early init for Kasan...
Completed initializing kasan !
Initializing memory ...
Completed initializing memory !
Initializing kprobes ...
== OK: test_kprobe_0001 within range!
== OK: test_kprobe_0002 not in range as expected!
Completed initializing kprobes !
Initializing pci ...
PCI fixup size: 1
Demo: Using LINKTABLE_FOR_EACH
foo_fixup
Demo: Using LINKTABLE_RUN_ALL
foo_fixup
Completed initializing pci !
Initializing beta ...
Completed initializing beta !
Initializing alpha ...
Completed initializing alpha !
Initializing acme ...
Completed initializing acme !
Booting bare metal
Calling start_kernel()...
Running setup_arch for kasan ...
Calling setup_arch work for Kasan...
Signed-off-by: Luis R. Rodriguez <mcgrof@kernel.org>
diff --git a/Makefile b/Makefile
index 5970bd7..d69aa28 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,6 @@
CFLAGS += -O2 -g
CFLAGS += -std=gnu99 -Wall -Werror
+CFLAGS += -DCONFIG_KPROBES
INCLUDES = -I include/ -I arch/x86/include/
CFLAGS += $(INCLUDES)
@@ -42,6 +43,7 @@
memory.o \
kasan.o\
arch/x86/kernel/init.o \
+ kprobes.o \
pci.o \
pci-quirks.o \
beta.o \
diff --git a/include/linux/ranges.h b/include/linux/ranges.h
index d79690f..dd51d45 100644
--- a/include/linux/ranges.h
+++ b/include/linux/ranges.h
@@ -9,6 +9,34 @@
addr < (unsigned long) LINUX_SECTION_END(name))
#define DECLARE_SECTION_RANGE(name) \
- DECLARE_LINUX_SECTION_RO(char, name)
+ DECLARE_LINUX_SECTION_RO(char, name)
+
+#define SECTION_RANGE_BEGIN(name, __section) \
+ const __typeof__(name[0]) \
+ __attribute__((used, \
+ weak, \
+ __aligned__(LINUX_SECTION_ALIGNMENT(name)),\
+ section(SECTION_TBL(__section, name, ))))
+
+#define SECTION_RANGE_END(name, __section) \
+ const __typeof__(name[0]) \
+ __attribute__((used, \
+ __aligned__(LINUX_SECTION_ALIGNMENT(name)),\
+ section(SECTION_TBL(__section, name, ~))))
+
+#define DEFINE_SECTION_RANGE(name, section) \
+ DECLARE_LINUX_SECTION_RO(char, name); \
+ SECTION_RANGE_BEGIN(name, section) VMLINUX_SYMBOL(name)[0] = {};\
+ LTO_REFERENCE_INITCALL(name); \
+ SECTION_RANGE_END(name, section) VMLINUX_SYMBOL(name##__end)[0] = {};\
+ LTO_REFERENCE_INITCALL(name##__end);
+
+/*
+ * We use the special "any" order, as section ranges need not care
+ * about that.
+ */
+#define SECTION_RANGE_ORDER any
+#define __LINUX_SECTION(section, name) \
+ __attribute__((__section__(SECTION_TBL(section, name, SECTION_RANGE_ORDER))))
#endif /* _LINUX_RANGES_H */
diff --git a/kprobes.c b/kprobes.c
new file mode 100644
index 0000000..3d4b024
--- /dev/null
+++ b/kprobes.c
@@ -0,0 +1,46 @@
+#include <linux/tables.h>
+#include <asm/x86_init_fn.h>
+#include <linux/ranges.h>
+#include <linux/kprobes.h>
+
+DEFINE_SECTION_RANGE(kprobes, SECTION_TEXT);
+
+void __kprobes test_kprobe_0001(void)
+{
+ pr_info("test_kprobe\n");
+}
+
+void test_kprobe_0002(void)
+{
+ pr_info("test_kprobe\n");
+}
+
+void test_kprobe_addr(const char *test, unsigned long addr, bool should_match)
+{
+ if (SECTION_ADDR_IN_RANGE(kprobes, addr))
+ if (should_match)
+ pr_info("== OK: %s within range!\n", test);
+ else
+ pr_info("== FAIL: %s should not be in range...\n",
+ test);
+ else
+ if (should_match)
+ pr_info("== FAIL: %s should be in range...\n", test);
+ else
+ pr_info("== OK: %s not in range as expected!\n", test);
+}
+
+void early_init_kprobes(void)
+{
+ unsigned long addr;
+
+ addr = (unsigned long) &test_kprobe_0001;
+
+ test_kprobe_addr("test_kprobe_0001", addr, true);
+
+ addr = (unsigned long) &test_kprobe_0002;
+
+ test_kprobe_addr("test_kprobe_0002", addr, false);
+}
+
+X86_INIT_EARLY_ALL(kprobes, NULL, NULL, early_init_kprobes, NULL, NULL);