1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31#include <linux/kprobes.h>
32#include <linux/spinlock.h>
33#include <linux/hash.h>
34#include <linux/init.h>
35#include <linux/module.h>
36#include <asm/cacheflush.h>
37#include <asm/errno.h>
38#include <asm/kdebug.h>
39
40#define KPROBE_HASH_BITS 6
41#define KPROBE_TABLE_SIZE (1 << KPROBE_HASH_BITS)
42
43static struct hlist_head kprobe_table[KPROBE_TABLE_SIZE];
44
45unsigned int kprobe_cpu = NR_CPUS;
46static DEFINE_SPINLOCK(kprobe_lock);
47
48
49void lock_kprobes(void)
50{
51 spin_lock(&kprobe_lock);
52 kprobe_cpu = smp_processor_id();
53}
54
55void unlock_kprobes(void)
56{
57 kprobe_cpu = NR_CPUS;
58 spin_unlock(&kprobe_lock);
59}
60
61
62struct kprobe *get_kprobe(void *addr)
63{
64 struct hlist_head *head;
65 struct hlist_node *node;
66
67 head = &kprobe_table[hash_ptr(addr, KPROBE_HASH_BITS)];
68 hlist_for_each(node, head) {
69 struct kprobe *p = hlist_entry(node, struct kprobe, hlist);
70 if (p->addr == addr)
71 return p;
72 }
73 return NULL;
74}
75
76int register_kprobe(struct kprobe *p)
77{
78 int ret = 0;
79 unsigned long flags = 0;
80
81 if ((ret = arch_prepare_kprobe(p)) != 0) {
82 goto out;
83 }
84 spin_lock_irqsave(&kprobe_lock, flags);
85 INIT_HLIST_NODE(&p->hlist);
86 if (get_kprobe(p->addr)) {
87 ret = -EEXIST;
88 goto out;
89 }
90 arch_copy_kprobe(p);
91
92 hlist_add_head(&p->hlist,
93 &kprobe_table[hash_ptr(p->addr, KPROBE_HASH_BITS)]);
94
95 p->opcode = *p->addr;
96 *p->addr = BREAKPOINT_INSTRUCTION;
97 flush_icache_range((unsigned long) p->addr,
98 (unsigned long) p->addr + sizeof(kprobe_opcode_t));
99 out:
100 spin_unlock_irqrestore(&kprobe_lock, flags);
101 if (ret == -EEXIST)
102 arch_remove_kprobe(p);
103 return ret;
104}
105
106void unregister_kprobe(struct kprobe *p)
107{
108 unsigned long flags;
109 arch_remove_kprobe(p);
110 spin_lock_irqsave(&kprobe_lock, flags);
111 *p->addr = p->opcode;
112 hlist_del(&p->hlist);
113 flush_icache_range((unsigned long) p->addr,
114 (unsigned long) p->addr + sizeof(kprobe_opcode_t));
115 spin_unlock_irqrestore(&kprobe_lock, flags);
116}
117
118static struct notifier_block kprobe_exceptions_nb = {
119 .notifier_call = kprobe_exceptions_notify,
120 .priority = 0x7fffffff
121};
122
123int register_jprobe(struct jprobe *jp)
124{
125
126 jp->kp.pre_handler = setjmp_pre_handler;
127 jp->kp.break_handler = longjmp_break_handler;
128
129 return register_kprobe(&jp->kp);
130}
131
132void unregister_jprobe(struct jprobe *jp)
133{
134 unregister_kprobe(&jp->kp);
135}
136
137static int __init init_kprobes(void)
138{
139 int i, err = 0;
140
141
142
143 for (i = 0; i < KPROBE_TABLE_SIZE; i++)
144 INIT_HLIST_HEAD(&kprobe_table[i]);
145
146 err = register_die_notifier(&kprobe_exceptions_nb);
147 return err;
148}
149
150__initcall(init_kprobes);
151
152EXPORT_SYMBOL_GPL(register_kprobe);
153EXPORT_SYMBOL_GPL(unregister_kprobe);
154EXPORT_SYMBOL_GPL(register_jprobe);
155EXPORT_SYMBOL_GPL(unregister_jprobe);
156EXPORT_SYMBOL_GPL(jprobe_return);
157