aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2010-06-14 04:06:10 -0400
committerPaul Mundt <lethal@linux-sh.org>2010-06-14 04:06:10 -0400
commit57fcfdf9b2bbe8ea47771ffc16c418a20e4173c6 (patch)
tree23709004b53a40fab173437f398a87801e56da43 /arch/sh/kernel
parentda28c597996a964a195529595c37f7aacd6dad09 (diff)
sh: kprobes SMP support.
Presently kprobes support relies on several saved opcode variables for saving and restoring state, without any specific locking. This is inherently racy on SMP, and given that we already use per-CPU variables for everything else, convert these over too. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/kernel')
-rw-r--r--arch/sh/kernel/kprobes.c100
1 files changed, 50 insertions, 50 deletions
diff --git a/arch/sh/kernel/kprobes.c b/arch/sh/kernel/kprobes.c
index 4049d99f76e1..1208b09e95c3 100644
--- a/arch/sh/kernel/kprobes.c
+++ b/arch/sh/kernel/kprobes.c
@@ -20,9 +20,9 @@
20DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL; 20DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
21DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); 21DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
22 22
23static struct kprobe saved_current_opcode; 23static DEFINE_PER_CPU(struct kprobe, saved_current_opcode);
24static struct kprobe saved_next_opcode; 24static DEFINE_PER_CPU(struct kprobe, saved_next_opcode);
25static struct kprobe saved_next_opcode2; 25static DEFINE_PER_CPU(struct kprobe, saved_next_opcode2);
26 26
27#define OPCODE_JMP(x) (((x) & 0xF0FF) == 0x402b) 27#define OPCODE_JMP(x) (((x) & 0xF0FF) == 0x402b)
28#define OPCODE_JSR(x) (((x) & 0xF0FF) == 0x400b) 28#define OPCODE_JSR(x) (((x) & 0xF0FF) == 0x400b)
@@ -102,16 +102,21 @@ int __kprobes kprobe_handle_illslot(unsigned long pc)
102 102
103void __kprobes arch_remove_kprobe(struct kprobe *p) 103void __kprobes arch_remove_kprobe(struct kprobe *p)
104{ 104{
105 if (saved_next_opcode.addr != 0x0) { 105 struct kprobe *saved = &__get_cpu_var(saved_next_opcode);
106
107 if (saved->addr) {
106 arch_disarm_kprobe(p); 108 arch_disarm_kprobe(p);
107 arch_disarm_kprobe(&saved_next_opcode); 109 arch_disarm_kprobe(saved);
108 saved_next_opcode.addr = 0x0; 110
109 saved_next_opcode.opcode = 0x0; 111 saved->addr = NULL;
110 112 saved->opcode = 0;
111 if (saved_next_opcode2.addr != 0x0) { 113
112 arch_disarm_kprobe(&saved_next_opcode2); 114 saved = &__get_cpu_var(saved_next_opcode2);
113 saved_next_opcode2.addr = 0x0; 115 if (saved->addr) {
114 saved_next_opcode2.opcode = 0x0; 116 arch_disarm_kprobe(saved);
117
118 saved->addr = NULL;
119 saved->opcode = 0;
115 } 120 }
116 } 121 }
117} 122}
@@ -141,57 +146,59 @@ static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs,
141 */ 146 */
142static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs) 147static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
143{ 148{
144 kprobe_opcode_t *addr = NULL; 149 __get_cpu_var(saved_current_opcode).addr = (kprobe_opcode_t *)regs->pc;
145 saved_current_opcode.addr = (kprobe_opcode_t *) (regs->pc);
146 addr = saved_current_opcode.addr;
147 150
148 if (p != NULL) { 151 if (p != NULL) {
152 struct kprobe *op1, *op2;
153
149 arch_disarm_kprobe(p); 154 arch_disarm_kprobe(p);
150 155
156 op1 = &__get_cpu_var(saved_next_opcode);
157 op2 = &__get_cpu_var(saved_next_opcode2);
158
151 if (OPCODE_JSR(p->opcode) || OPCODE_JMP(p->opcode)) { 159 if (OPCODE_JSR(p->opcode) || OPCODE_JMP(p->opcode)) {
152 unsigned int reg_nr = ((p->opcode >> 8) & 0x000F); 160 unsigned int reg_nr = ((p->opcode >> 8) & 0x000F);
153 saved_next_opcode.addr = 161 op1->addr = (kprobe_opcode_t *) regs->regs[reg_nr];
154 (kprobe_opcode_t *) regs->regs[reg_nr];
155 } else if (OPCODE_BRA(p->opcode) || OPCODE_BSR(p->opcode)) { 162 } else if (OPCODE_BRA(p->opcode) || OPCODE_BSR(p->opcode)) {
156 unsigned long disp = (p->opcode & 0x0FFF); 163 unsigned long disp = (p->opcode & 0x0FFF);
157 saved_next_opcode.addr = 164 op1->addr =
158 (kprobe_opcode_t *) (regs->pc + 4 + disp * 2); 165 (kprobe_opcode_t *) (regs->pc + 4 + disp * 2);
159 166
160 } else if (OPCODE_BRAF(p->opcode) || OPCODE_BSRF(p->opcode)) { 167 } else if (OPCODE_BRAF(p->opcode) || OPCODE_BSRF(p->opcode)) {
161 unsigned int reg_nr = ((p->opcode >> 8) & 0x000F); 168 unsigned int reg_nr = ((p->opcode >> 8) & 0x000F);
162 saved_next_opcode.addr = 169 op1->addr =
163 (kprobe_opcode_t *) (regs->pc + 4 + 170 (kprobe_opcode_t *) (regs->pc + 4 +
164 regs->regs[reg_nr]); 171 regs->regs[reg_nr]);
165 172
166 } else if (OPCODE_RTS(p->opcode)) { 173 } else if (OPCODE_RTS(p->opcode)) {
167 saved_next_opcode.addr = (kprobe_opcode_t *) regs->pr; 174 op1->addr = (kprobe_opcode_t *) regs->pr;
168 175
169 } else if (OPCODE_BF(p->opcode) || OPCODE_BT(p->opcode)) { 176 } else if (OPCODE_BF(p->opcode) || OPCODE_BT(p->opcode)) {
170 unsigned long disp = (p->opcode & 0x00FF); 177 unsigned long disp = (p->opcode & 0x00FF);
171 /* case 1 */ 178 /* case 1 */
172 saved_next_opcode.addr = p->addr + 1; 179 op1->addr = p->addr + 1;
173 /* case 2 */ 180 /* case 2 */
174 saved_next_opcode2.addr = 181 op2->addr =
175 (kprobe_opcode_t *) (regs->pc + 4 + disp * 2); 182 (kprobe_opcode_t *) (regs->pc + 4 + disp * 2);
176 saved_next_opcode2.opcode = *(saved_next_opcode2.addr); 183 op2->opcode = *(op2->addr);
177 arch_arm_kprobe(&saved_next_opcode2); 184 arch_arm_kprobe(op2);
178 185
179 } else if (OPCODE_BF_S(p->opcode) || OPCODE_BT_S(p->opcode)) { 186 } else if (OPCODE_BF_S(p->opcode) || OPCODE_BT_S(p->opcode)) {
180 unsigned long disp = (p->opcode & 0x00FF); 187 unsigned long disp = (p->opcode & 0x00FF);
181 /* case 1 */ 188 /* case 1 */
182 saved_next_opcode.addr = p->addr + 2; 189 op1->addr = p->addr + 2;
183 /* case 2 */ 190 /* case 2 */
184 saved_next_opcode2.addr = 191 op2->addr =
185 (kprobe_opcode_t *) (regs->pc + 4 + disp * 2); 192 (kprobe_opcode_t *) (regs->pc + 4 + disp * 2);
186 saved_next_opcode2.opcode = *(saved_next_opcode2.addr); 193 op2->opcode = *(op2->addr);
187 arch_arm_kprobe(&saved_next_opcode2); 194 arch_arm_kprobe(op2);
188 195
189 } else { 196 } else {
190 saved_next_opcode.addr = p->addr + 1; 197 op1->addr = p->addr + 1;
191 } 198 }
192 199
193 saved_next_opcode.opcode = *(saved_next_opcode.addr); 200 op1->opcode = *(op1->addr);
194 arch_arm_kprobe(&saved_next_opcode); 201 arch_arm_kprobe(op1);
195 } 202 }
196} 203}
197 204
@@ -376,21 +383,23 @@ static int __kprobes post_kprobe_handler(struct pt_regs *regs)
376 cur->post_handler(cur, regs, 0); 383 cur->post_handler(cur, regs, 0);
377 } 384 }
378 385
379 if (saved_next_opcode.addr != 0x0) { 386 p = &__get_cpu_var(saved_next_opcode);
380 arch_disarm_kprobe(&saved_next_opcode); 387 if (p->addr) {
381 saved_next_opcode.addr = 0x0; 388 arch_disarm_kprobe(p);
382 saved_next_opcode.opcode = 0x0; 389 p->addr = NULL;
390 p->opcode = 0;
383 391
384 addr = saved_current_opcode.addr; 392 addr = __get_cpu_var(saved_current_opcode).addr;
385 saved_current_opcode.addr = 0x0; 393 __get_cpu_var(saved_current_opcode).addr = NULL;
386 394
387 p = get_kprobe(addr); 395 p = get_kprobe(addr);
388 arch_arm_kprobe(p); 396 arch_arm_kprobe(p);
389 397
390 if (saved_next_opcode2.addr != 0x0) { 398 p = &__get_cpu_var(saved_next_opcode2);
391 arch_disarm_kprobe(&saved_next_opcode2); 399 if (p->addr) {
392 saved_next_opcode2.addr = 0x0; 400 arch_disarm_kprobe(p);
393 saved_next_opcode2.opcode = 0x0; 401 p->addr = NULL;
402 p->opcode = 0;
394 } 403 }
395 } 404 }
396 405
@@ -572,14 +581,5 @@ static struct kprobe trampoline_p = {
572 581
573int __init arch_init_kprobes(void) 582int __init arch_init_kprobes(void)
574{ 583{
575 saved_next_opcode.addr = 0x0;
576 saved_next_opcode.opcode = 0x0;
577
578 saved_current_opcode.addr = 0x0;
579 saved_current_opcode.opcode = 0x0;
580
581 saved_next_opcode2.addr = 0x0;
582 saved_next_opcode2.opcode = 0x0;
583
584 return register_kprobe(&trampoline_p); 584 return register_kprobe(&trampoline_p);
585} 585}