aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnanth N Mavinakayanahalli <ananth@in.ibm.com>2006-10-02 05:17:30 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-10-02 10:57:16 -0400
commit3a872d89baae821a0f6e2c1055d4b47650661137 (patch)
tree5ac6aa55e04960e02f25ff5079078f975957b1b3
parent782237a2418e2561a87c86a4832726931adce737 (diff)
[PATCH] Kprobes: Make kprobe modules more portable
In an effort to make kprobe modules more portable, here is a patch that: o Introduces the "symbol_name" field to struct kprobe. The symbol->address resolution now happens in the kernel in an architecture agnostic manner. 64-bit powerpc users no longer have to specify the ".symbols" o Introduces the "offset" field to struct kprobe to allow a user to specify an offset into a symbol. o The legacy mechanism of specifying the kprobe.addr is still supported. However, if both the kprobe.addr and kprobe.symbol_name are specified, probe registration fails with an -EINVAL. o The symbol resolution code uses kallsyms_lookup_name(). So CONFIG_KPROBES now depends on CONFIG_KALLSYMS o Apparantly kprobe modules were the only legitimate out-of-tree user of the kallsyms_lookup_name() EXPORT. Now that the symbol resolution happens in-kernel, remove the EXPORT as suggested by Christoph Hellwig o Modify tcp_probe.c that uses the kprobe interface so as to make it work on multiple platforms (in its earlier form, the code wouldn't work, say, on powerpc) Signed-off-by: Ananth N Mavinakayanahalli <ananth@in.ibm.com> Signed-off-by: Prasanna S Panchamukhi <prasanna@in.ibm.com> Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--arch/i386/Kconfig2
-rw-r--r--arch/ia64/Kconfig2
-rw-r--r--arch/powerpc/Kconfig2
-rw-r--r--arch/sparc64/Kconfig2
-rw-r--r--arch/x86_64/Kconfig2
-rw-r--r--include/asm-powerpc/kprobes.h15
-rw-r--r--include/linux/kprobes.h6
-rw-r--r--kernel/kallsyms.c1
-rw-r--r--kernel/kprobes.c26
-rw-r--r--net/ipv4/tcp_probe.c6
10 files changed, 56 insertions, 8 deletions
diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig
index 3fd2f256f2be..af219e51734f 100644
--- a/arch/i386/Kconfig
+++ b/arch/i386/Kconfig
@@ -1142,7 +1142,7 @@ source "arch/i386/oprofile/Kconfig"
1142 1142
1143config KPROBES 1143config KPROBES
1144 bool "Kprobes (EXPERIMENTAL)" 1144 bool "Kprobes (EXPERIMENTAL)"
1145 depends on EXPERIMENTAL && MODULES 1145 depends on KALLSYMS && EXPERIMENTAL && MODULES
1146 help 1146 help
1147 Kprobes allows you to trap at almost any kernel address and 1147 Kprobes allows you to trap at almost any kernel address and
1148 execute a callback function. register_kprobe() establishes 1148 execute a callback function. register_kprobe() establishes
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index 0b7f701d5cf7..70f7eb9fed35 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -516,7 +516,7 @@ source "arch/ia64/oprofile/Kconfig"
516 516
517config KPROBES 517config KPROBES
518 bool "Kprobes (EXPERIMENTAL)" 518 bool "Kprobes (EXPERIMENTAL)"
519 depends on EXPERIMENTAL && MODULES 519 depends on KALLSYMS && EXPERIMENTAL && MODULES
520 help 520 help
521 Kprobes allows you to trap at almost any kernel address and 521 Kprobes allows you to trap at almost any kernel address and
522 execute a callback function. register_kprobe() establishes 522 execute a callback function. register_kprobe() establishes
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index a0dd1b0ee483..032e6ab5d3c4 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -1069,7 +1069,7 @@ source "arch/powerpc/oprofile/Kconfig"
1069 1069
1070config KPROBES 1070config KPROBES
1071 bool "Kprobes (EXPERIMENTAL)" 1071 bool "Kprobes (EXPERIMENTAL)"
1072 depends on PPC64 && EXPERIMENTAL && MODULES 1072 depends on PPC64 && KALLSYMS && EXPERIMENTAL && MODULES
1073 help 1073 help
1074 Kprobes allows you to trap at almost any kernel address and 1074 Kprobes allows you to trap at almost any kernel address and
1075 execute a callback function. register_kprobe() establishes 1075 execute a callback function. register_kprobe() establishes
diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig
index 8d8ca716f7a7..b627f8dbcaad 100644
--- a/arch/sparc64/Kconfig
+++ b/arch/sparc64/Kconfig
@@ -420,7 +420,7 @@ source "arch/sparc64/oprofile/Kconfig"
420 420
421config KPROBES 421config KPROBES
422 bool "Kprobes (EXPERIMENTAL)" 422 bool "Kprobes (EXPERIMENTAL)"
423 depends on EXPERIMENTAL && MODULES 423 depends on KALLSYMS && EXPERIMENTAL && MODULES
424 help 424 help
425 Kprobes allows you to trap at almost any kernel address and 425 Kprobes allows you to trap at almost any kernel address and
426 execute a callback function. register_kprobe() establishes 426 execute a callback function. register_kprobe() establishes
diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig
index b87a19f0d584..0a5d8e659aa4 100644
--- a/arch/x86_64/Kconfig
+++ b/arch/x86_64/Kconfig
@@ -690,7 +690,7 @@ source "arch/x86_64/oprofile/Kconfig"
690 690
691config KPROBES 691config KPROBES
692 bool "Kprobes (EXPERIMENTAL)" 692 bool "Kprobes (EXPERIMENTAL)"
693 depends on EXPERIMENTAL && MODULES 693 depends on KALLSYMS && EXPERIMENTAL && MODULES
694 help 694 help
695 Kprobes allows you to trap at almost any kernel address and 695 Kprobes allows you to trap at almost any kernel address and
696 execute a callback function. register_kprobe() establishes 696 execute a callback function. register_kprobe() establishes
diff --git a/include/asm-powerpc/kprobes.h b/include/asm-powerpc/kprobes.h
index 34e1f89a5fa0..1ef54be6abfa 100644
--- a/include/asm-powerpc/kprobes.h
+++ b/include/asm-powerpc/kprobes.h
@@ -44,6 +44,21 @@ typedef unsigned int kprobe_opcode_t;
44#define IS_TDI(instr) (((instr) & 0xfc000000) == 0x08000000) 44#define IS_TDI(instr) (((instr) & 0xfc000000) == 0x08000000)
45#define IS_TWI(instr) (((instr) & 0xfc000000) == 0x0c000000) 45#define IS_TWI(instr) (((instr) & 0xfc000000) == 0x0c000000)
46 46
47/*
48 * 64bit powerpc uses function descriptors.
49 * Handle cases where:
50 * - User passes a <.symbol>
51 * - User passes a <symbol>
52 * - User passes a non-existant symbol, kallsyms_lookup_name
53 * returns 0. Don't deref the NULL pointer in that case
54 */
55#define kprobe_lookup_name(name, addr) \
56{ \
57 addr = (kprobe_opcode_t *)kallsyms_lookup_name(name); \
58 if (!(name[0] == '.') && addr) \
59 addr = *(kprobe_opcode_t **)addr; \
60}
61
47#define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)((func_descr_t *)pentry) 62#define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)((func_descr_t *)pentry)
48 63
49#define is_trap(instr) (IS_TW(instr) || IS_TD(instr) || \ 64#define is_trap(instr) (IS_TW(instr) || IS_TD(instr) || \
diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h
index 8bf6702da2a0..a5c5a0cb0d5c 100644
--- a/include/linux/kprobes.h
+++ b/include/linux/kprobes.h
@@ -77,6 +77,12 @@ struct kprobe {
77 /* location of the probe point */ 77 /* location of the probe point */
78 kprobe_opcode_t *addr; 78 kprobe_opcode_t *addr;
79 79
80 /* Allow user to indicate symbol name of the probe point */
81 char *symbol_name;
82
83 /* Offset into the symbol */
84 unsigned int offset;
85
80 /* Called before addr is executed. */ 86 /* Called before addr is executed. */
81 kprobe_pre_handler_t pre_handler; 87 kprobe_pre_handler_t pre_handler;
82 88
diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c
index ab16a5a4cfe9..342bca62c496 100644
--- a/kernel/kallsyms.c
+++ b/kernel/kallsyms.c
@@ -154,7 +154,6 @@ unsigned long kallsyms_lookup_name(const char *name)
154 } 154 }
155 return module_kallsyms_lookup_name(name); 155 return module_kallsyms_lookup_name(name);
156} 156}
157EXPORT_SYMBOL_GPL(kallsyms_lookup_name);
158 157
159/* 158/*
160 * Lookup an address 159 * Lookup an address
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index 3f57dfdc8f92..f66b8e681b4d 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -37,6 +37,7 @@
37#include <linux/slab.h> 37#include <linux/slab.h>
38#include <linux/module.h> 38#include <linux/module.h>
39#include <linux/moduleloader.h> 39#include <linux/moduleloader.h>
40#include <linux/kallsyms.h>
40#include <asm-generic/sections.h> 41#include <asm-generic/sections.h>
41#include <asm/cacheflush.h> 42#include <asm/cacheflush.h>
42#include <asm/errno.h> 43#include <asm/errno.h>
@@ -45,6 +46,16 @@
45#define KPROBE_HASH_BITS 6 46#define KPROBE_HASH_BITS 6
46#define KPROBE_TABLE_SIZE (1 << KPROBE_HASH_BITS) 47#define KPROBE_TABLE_SIZE (1 << KPROBE_HASH_BITS)
47 48
49
50/*
51 * Some oddball architectures like 64bit powerpc have function descriptors
52 * so this must be overridable.
53 */
54#ifndef kprobe_lookup_name
55#define kprobe_lookup_name(name, addr) \
56 addr = ((kprobe_opcode_t *)(kallsyms_lookup_name(name)))
57#endif
58
48static struct hlist_head kprobe_table[KPROBE_TABLE_SIZE]; 59static struct hlist_head kprobe_table[KPROBE_TABLE_SIZE];
49static struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE]; 60static struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE];
50static atomic_t kprobe_count; 61static atomic_t kprobe_count;
@@ -447,6 +458,21 @@ static int __kprobes __register_kprobe(struct kprobe *p,
447 struct kprobe *old_p; 458 struct kprobe *old_p;
448 struct module *probed_mod; 459 struct module *probed_mod;
449 460
461 /*
462 * If we have a symbol_name argument look it up,
463 * and add it to the address. That way the addr
464 * field can either be global or relative to a symbol.
465 */
466 if (p->symbol_name) {
467 if (p->addr)
468 return -EINVAL;
469 kprobe_lookup_name(p->symbol_name, p->addr);
470 }
471
472 if (!p->addr)
473 return -EINVAL;
474 p->addr = (kprobe_opcode_t *)(((char *)p->addr)+ p->offset);
475
450 if ((!kernel_text_address((unsigned long) p->addr)) || 476 if ((!kernel_text_address((unsigned long) p->addr)) ||
451 in_kprobes_functions((unsigned long) p->addr)) 477 in_kprobes_functions((unsigned long) p->addr))
452 return -EINVAL; 478 return -EINVAL;
diff --git a/net/ipv4/tcp_probe.c b/net/ipv4/tcp_probe.c
index dab37d2f65fc..4be336f17883 100644
--- a/net/ipv4/tcp_probe.c
+++ b/net/ipv4/tcp_probe.c
@@ -99,8 +99,10 @@ static int jtcp_sendmsg(struct kiocb *iocb, struct sock *sk,
99} 99}
100 100
101static struct jprobe tcp_send_probe = { 101static struct jprobe tcp_send_probe = {
102 .kp = { .addr = (kprobe_opcode_t *) &tcp_sendmsg, }, 102 .kp = {
103 .entry = (kprobe_opcode_t *) &jtcp_sendmsg, 103 .symbol_name = "tcp_sendmsg",
104 },
105 .entry = JPROBE_ENTRY(jtcp_sendmsg),
104}; 106};
105 107
106 108