diff options
author | Ananth N Mavinakayanahalli <ananth@in.ibm.com> | 2005-11-07 04:00:08 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-11-07 10:53:45 -0500 |
commit | 9a0e3a86837ac7542e601c18346102c9d9e65fa5 (patch) | |
tree | 0e58782bfe2be7c1dd82e254df9d4d0fea6781bd /arch/i386 | |
parent | e65845235c8120be63001fc1a4ac00c819194bbe (diff) |
[PATCH] Kprobes: Track kprobe on a per_cpu basis - i386 changes
I386 changes to track kprobe execution on a per-cpu basis. We now track the
kprobe state machine independently on each cpu, using an arch specific kprobe
control block.
Signed-off-by: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Signed-off-by: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/i386')
-rw-r--r-- | arch/i386/kernel/kprobes.c | 126 |
1 files changed, 69 insertions, 57 deletions
diff --git a/arch/i386/kernel/kprobes.c b/arch/i386/kernel/kprobes.c index fd35039859e6..99565a66915d 100644 --- a/arch/i386/kernel/kprobes.c +++ b/arch/i386/kernel/kprobes.c | |||
@@ -37,16 +37,11 @@ | |||
37 | #include <asm/kdebug.h> | 37 | #include <asm/kdebug.h> |
38 | #include <asm/desc.h> | 38 | #include <asm/desc.h> |
39 | 39 | ||
40 | static struct kprobe *current_kprobe; | ||
41 | static unsigned long kprobe_status, kprobe_old_eflags, kprobe_saved_eflags; | ||
42 | static struct kprobe *kprobe_prev; | ||
43 | static unsigned long kprobe_status_prev, kprobe_old_eflags_prev, kprobe_saved_eflags_prev; | ||
44 | static struct pt_regs jprobe_saved_regs; | ||
45 | static long *jprobe_saved_esp; | ||
46 | /* copy of the kernel stack at the probe fire time */ | ||
47 | static kprobe_opcode_t jprobes_stack[MAX_STACK_SIZE]; | ||
48 | void jprobe_return_end(void); | 40 | void jprobe_return_end(void); |
49 | 41 | ||
42 | DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL; | ||
43 | DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); | ||
44 | |||
50 | /* | 45 | /* |
51 | * returns non-zero if opcode modifies the interrupt flag. | 46 | * returns non-zero if opcode modifies the interrupt flag. |
52 | */ | 47 | */ |
@@ -91,29 +86,30 @@ void __kprobes arch_remove_kprobe(struct kprobe *p) | |||
91 | { | 86 | { |
92 | } | 87 | } |
93 | 88 | ||
94 | static inline void save_previous_kprobe(void) | 89 | static inline void save_previous_kprobe(struct kprobe_ctlblk *kcb) |
95 | { | 90 | { |
96 | kprobe_prev = current_kprobe; | 91 | kcb->prev_kprobe.kp = kprobe_running(); |
97 | kprobe_status_prev = kprobe_status; | 92 | kcb->prev_kprobe.status = kcb->kprobe_status; |
98 | kprobe_old_eflags_prev = kprobe_old_eflags; | 93 | kcb->prev_kprobe.old_eflags = kcb->kprobe_old_eflags; |
99 | kprobe_saved_eflags_prev = kprobe_saved_eflags; | 94 | kcb->prev_kprobe.saved_eflags = kcb->kprobe_saved_eflags; |
100 | } | 95 | } |
101 | 96 | ||
102 | static inline void restore_previous_kprobe(void) | 97 | static inline void restore_previous_kprobe(struct kprobe_ctlblk *kcb) |
103 | { | 98 | { |
104 | current_kprobe = kprobe_prev; | 99 | __get_cpu_var(current_kprobe) = kcb->prev_kprobe.kp; |
105 | kprobe_status = kprobe_status_prev; | 100 | kcb->kprobe_status = kcb->prev_kprobe.status; |
106 | kprobe_old_eflags = kprobe_old_eflags_prev; | 101 | kcb->kprobe_old_eflags = kcb->prev_kprobe.old_eflags; |
107 | kprobe_saved_eflags = kprobe_saved_eflags_prev; | 102 | kcb->kprobe_saved_eflags = kcb->prev_kprobe.saved_eflags; |
108 | } | 103 | } |
109 | 104 | ||
110 | static inline void set_current_kprobe(struct kprobe *p, struct pt_regs *regs) | 105 | static inline void set_current_kprobe(struct kprobe *p, struct pt_regs *regs, |
106 | struct kprobe_ctlblk *kcb) | ||
111 | { | 107 | { |
112 | current_kprobe = p; | 108 | __get_cpu_var(current_kprobe) = p; |
113 | kprobe_saved_eflags = kprobe_old_eflags | 109 | kcb->kprobe_saved_eflags = kcb->kprobe_old_eflags |
114 | = (regs->eflags & (TF_MASK | IF_MASK)); | 110 | = (regs->eflags & (TF_MASK | IF_MASK)); |
115 | if (is_IF_modifier(p->opcode)) | 111 | if (is_IF_modifier(p->opcode)) |
116 | kprobe_saved_eflags &= ~IF_MASK; | 112 | kcb->kprobe_saved_eflags &= ~IF_MASK; |
117 | } | 113 | } |
118 | 114 | ||
119 | static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs) | 115 | static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs) |
@@ -157,6 +153,7 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) | |||
157 | int ret = 0; | 153 | int ret = 0; |
158 | kprobe_opcode_t *addr = NULL; | 154 | kprobe_opcode_t *addr = NULL; |
159 | unsigned long *lp; | 155 | unsigned long *lp; |
156 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | ||
160 | 157 | ||
161 | /* Check if the application is using LDT entry for its code segment and | 158 | /* Check if the application is using LDT entry for its code segment and |
162 | * calculate the address by reading the base address from the LDT entry. | 159 | * calculate the address by reading the base address from the LDT entry. |
@@ -175,10 +172,10 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) | |||
175 | Disarm the probe we just hit, and ignore it. */ | 172 | Disarm the probe we just hit, and ignore it. */ |
176 | p = get_kprobe(addr); | 173 | p = get_kprobe(addr); |
177 | if (p) { | 174 | if (p) { |
178 | if (kprobe_status == KPROBE_HIT_SS && | 175 | if (kcb->kprobe_status == KPROBE_HIT_SS && |
179 | *p->ainsn.insn == BREAKPOINT_INSTRUCTION) { | 176 | *p->ainsn.insn == BREAKPOINT_INSTRUCTION) { |
180 | regs->eflags &= ~TF_MASK; | 177 | regs->eflags &= ~TF_MASK; |
181 | regs->eflags |= kprobe_saved_eflags; | 178 | regs->eflags |= kcb->kprobe_saved_eflags; |
182 | unlock_kprobes(); | 179 | unlock_kprobes(); |
183 | goto no_kprobe; | 180 | goto no_kprobe; |
184 | } | 181 | } |
@@ -188,14 +185,14 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) | |||
188 | * just single step on the instruction of the new probe | 185 | * just single step on the instruction of the new probe |
189 | * without calling any user handlers. | 186 | * without calling any user handlers. |
190 | */ | 187 | */ |
191 | save_previous_kprobe(); | 188 | save_previous_kprobe(kcb); |
192 | set_current_kprobe(p, regs); | 189 | set_current_kprobe(p, regs, kcb); |
193 | p->nmissed++; | 190 | p->nmissed++; |
194 | prepare_singlestep(p, regs); | 191 | prepare_singlestep(p, regs); |
195 | kprobe_status = KPROBE_REENTER; | 192 | kcb->kprobe_status = KPROBE_REENTER; |
196 | return 1; | 193 | return 1; |
197 | } else { | 194 | } else { |
198 | p = current_kprobe; | 195 | p = __get_cpu_var(current_kprobe); |
199 | if (p->break_handler && p->break_handler(p, regs)) { | 196 | if (p->break_handler && p->break_handler(p, regs)) { |
200 | goto ss_probe; | 197 | goto ss_probe; |
201 | } | 198 | } |
@@ -235,8 +232,8 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) | |||
235 | * in post_kprobe_handler() | 232 | * in post_kprobe_handler() |
236 | */ | 233 | */ |
237 | preempt_disable(); | 234 | preempt_disable(); |
238 | kprobe_status = KPROBE_HIT_ACTIVE; | 235 | set_current_kprobe(p, regs, kcb); |
239 | set_current_kprobe(p, regs); | 236 | kcb->kprobe_status = KPROBE_HIT_ACTIVE; |
240 | 237 | ||
241 | if (p->pre_handler && p->pre_handler(p, regs)) | 238 | if (p->pre_handler && p->pre_handler(p, regs)) |
242 | /* handler has already set things up, so skip ss setup */ | 239 | /* handler has already set things up, so skip ss setup */ |
@@ -244,7 +241,7 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) | |||
244 | 241 | ||
245 | ss_probe: | 242 | ss_probe: |
246 | prepare_singlestep(p, regs); | 243 | prepare_singlestep(p, regs); |
247 | kprobe_status = KPROBE_HIT_SS; | 244 | kcb->kprobe_status = KPROBE_HIT_SS; |
248 | return 1; | 245 | return 1; |
249 | 246 | ||
250 | no_kprobe: | 247 | no_kprobe: |
@@ -312,6 +309,7 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) | |||
312 | BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address)); | 309 | BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address)); |
313 | regs->eip = orig_ret_address; | 310 | regs->eip = orig_ret_address; |
314 | 311 | ||
312 | reset_current_kprobe(); | ||
315 | unlock_kprobes(); | 313 | unlock_kprobes(); |
316 | preempt_enable_no_resched(); | 314 | preempt_enable_no_resched(); |
317 | 315 | ||
@@ -345,7 +343,8 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) | |||
345 | * that is atop the stack is the address following the copied instruction. | 343 | * that is atop the stack is the address following the copied instruction. |
346 | * We need to make it the address following the original instruction. | 344 | * We need to make it the address following the original instruction. |
347 | */ | 345 | */ |
348 | static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs) | 346 | static void __kprobes resume_execution(struct kprobe *p, |
347 | struct pt_regs *regs, struct kprobe_ctlblk *kcb) | ||
349 | { | 348 | { |
350 | unsigned long *tos = (unsigned long *)®s->esp; | 349 | unsigned long *tos = (unsigned long *)®s->esp; |
351 | unsigned long next_eip = 0; | 350 | unsigned long next_eip = 0; |
@@ -355,7 +354,7 @@ static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs) | |||
355 | switch (p->ainsn.insn[0]) { | 354 | switch (p->ainsn.insn[0]) { |
356 | case 0x9c: /* pushfl */ | 355 | case 0x9c: /* pushfl */ |
357 | *tos &= ~(TF_MASK | IF_MASK); | 356 | *tos &= ~(TF_MASK | IF_MASK); |
358 | *tos |= kprobe_old_eflags; | 357 | *tos |= kcb->kprobe_old_eflags; |
359 | break; | 358 | break; |
360 | case 0xc3: /* ret/lret */ | 359 | case 0xc3: /* ret/lret */ |
361 | case 0xcb: | 360 | case 0xcb: |
@@ -400,22 +399,26 @@ static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs) | |||
400 | */ | 399 | */ |
401 | static inline int post_kprobe_handler(struct pt_regs *regs) | 400 | static inline int post_kprobe_handler(struct pt_regs *regs) |
402 | { | 401 | { |
403 | if (!kprobe_running()) | 402 | struct kprobe *cur = kprobe_running(); |
403 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | ||
404 | |||
405 | if (!cur) | ||
404 | return 0; | 406 | return 0; |
405 | 407 | ||
406 | if ((kprobe_status != KPROBE_REENTER) && current_kprobe->post_handler) { | 408 | if ((kcb->kprobe_status != KPROBE_REENTER) && cur->post_handler) { |
407 | kprobe_status = KPROBE_HIT_SSDONE; | 409 | kcb->kprobe_status = KPROBE_HIT_SSDONE; |
408 | current_kprobe->post_handler(current_kprobe, regs, 0); | 410 | cur->post_handler(cur, regs, 0); |
409 | } | 411 | } |
410 | 412 | ||
411 | resume_execution(current_kprobe, regs); | 413 | resume_execution(cur, regs, kcb); |
412 | regs->eflags |= kprobe_saved_eflags; | 414 | regs->eflags |= kcb->kprobe_saved_eflags; |
413 | 415 | ||
414 | /*Restore back the original saved kprobes variables and continue. */ | 416 | /*Restore back the original saved kprobes variables and continue. */ |
415 | if (kprobe_status == KPROBE_REENTER) { | 417 | if (kcb->kprobe_status == KPROBE_REENTER) { |
416 | restore_previous_kprobe(); | 418 | restore_previous_kprobe(kcb); |
417 | goto out; | 419 | goto out; |
418 | } | 420 | } |
421 | reset_current_kprobe(); | ||
419 | unlock_kprobes(); | 422 | unlock_kprobes(); |
420 | out: | 423 | out: |
421 | preempt_enable_no_resched(); | 424 | preempt_enable_no_resched(); |
@@ -434,14 +437,17 @@ out: | |||
434 | /* Interrupts disabled, kprobe_lock held. */ | 437 | /* Interrupts disabled, kprobe_lock held. */ |
435 | static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr) | 438 | static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr) |
436 | { | 439 | { |
437 | if (current_kprobe->fault_handler | 440 | struct kprobe *cur = kprobe_running(); |
438 | && current_kprobe->fault_handler(current_kprobe, regs, trapnr)) | 441 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); |
442 | |||
443 | if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr)) | ||
439 | return 1; | 444 | return 1; |
440 | 445 | ||
441 | if (kprobe_status & KPROBE_HIT_SS) { | 446 | if (kcb->kprobe_status & KPROBE_HIT_SS) { |
442 | resume_execution(current_kprobe, regs); | 447 | resume_execution(cur, regs, kcb); |
443 | regs->eflags |= kprobe_old_eflags; | 448 | regs->eflags |= kcb->kprobe_old_eflags; |
444 | 449 | ||
450 | reset_current_kprobe(); | ||
445 | unlock_kprobes(); | 451 | unlock_kprobes(); |
446 | preempt_enable_no_resched(); | 452 | preempt_enable_no_resched(); |
447 | } | 453 | } |
@@ -484,10 +490,11 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) | |||
484 | { | 490 | { |
485 | struct jprobe *jp = container_of(p, struct jprobe, kp); | 491 | struct jprobe *jp = container_of(p, struct jprobe, kp); |
486 | unsigned long addr; | 492 | unsigned long addr; |
493 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | ||
487 | 494 | ||
488 | jprobe_saved_regs = *regs; | 495 | kcb->jprobe_saved_regs = *regs; |
489 | jprobe_saved_esp = ®s->esp; | 496 | kcb->jprobe_saved_esp = ®s->esp; |
490 | addr = (unsigned long)jprobe_saved_esp; | 497 | addr = (unsigned long)(kcb->jprobe_saved_esp); |
491 | 498 | ||
492 | /* | 499 | /* |
493 | * TBD: As Linus pointed out, gcc assumes that the callee | 500 | * TBD: As Linus pointed out, gcc assumes that the callee |
@@ -496,7 +503,8 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) | |||
496 | * we also save and restore enough stack bytes to cover | 503 | * we also save and restore enough stack bytes to cover |
497 | * the argument area. | 504 | * the argument area. |
498 | */ | 505 | */ |
499 | memcpy(jprobes_stack, (kprobe_opcode_t *) addr, MIN_STACK_SIZE(addr)); | 506 | memcpy(kcb->jprobes_stack, (kprobe_opcode_t *)addr, |
507 | MIN_STACK_SIZE(addr)); | ||
500 | regs->eflags &= ~IF_MASK; | 508 | regs->eflags &= ~IF_MASK; |
501 | regs->eip = (unsigned long)(jp->entry); | 509 | regs->eip = (unsigned long)(jp->entry); |
502 | return 1; | 510 | return 1; |
@@ -504,34 +512,38 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) | |||
504 | 512 | ||
505 | void __kprobes jprobe_return(void) | 513 | void __kprobes jprobe_return(void) |
506 | { | 514 | { |
515 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | ||
516 | |||
507 | asm volatile (" xchgl %%ebx,%%esp \n" | 517 | asm volatile (" xchgl %%ebx,%%esp \n" |
508 | " int3 \n" | 518 | " int3 \n" |
509 | " .globl jprobe_return_end \n" | 519 | " .globl jprobe_return_end \n" |
510 | " jprobe_return_end: \n" | 520 | " jprobe_return_end: \n" |
511 | " nop \n"::"b" | 521 | " nop \n"::"b" |
512 | (jprobe_saved_esp):"memory"); | 522 | (kcb->jprobe_saved_esp):"memory"); |
513 | } | 523 | } |
514 | 524 | ||
515 | int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) | 525 | int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) |
516 | { | 526 | { |
527 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | ||
517 | u8 *addr = (u8 *) (regs->eip - 1); | 528 | u8 *addr = (u8 *) (regs->eip - 1); |
518 | unsigned long stack_addr = (unsigned long)jprobe_saved_esp; | 529 | unsigned long stack_addr = (unsigned long)(kcb->jprobe_saved_esp); |
519 | struct jprobe *jp = container_of(p, struct jprobe, kp); | 530 | struct jprobe *jp = container_of(p, struct jprobe, kp); |
520 | 531 | ||
521 | if ((addr > (u8 *) jprobe_return) && (addr < (u8 *) jprobe_return_end)) { | 532 | if ((addr > (u8 *) jprobe_return) && (addr < (u8 *) jprobe_return_end)) { |
522 | if (®s->esp != jprobe_saved_esp) { | 533 | if (®s->esp != kcb->jprobe_saved_esp) { |
523 | struct pt_regs *saved_regs = | 534 | struct pt_regs *saved_regs = |
524 | container_of(jprobe_saved_esp, struct pt_regs, esp); | 535 | container_of(kcb->jprobe_saved_esp, |
536 | struct pt_regs, esp); | ||
525 | printk("current esp %p does not match saved esp %p\n", | 537 | printk("current esp %p does not match saved esp %p\n", |
526 | ®s->esp, jprobe_saved_esp); | 538 | ®s->esp, kcb->jprobe_saved_esp); |
527 | printk("Saved registers for jprobe %p\n", jp); | 539 | printk("Saved registers for jprobe %p\n", jp); |
528 | show_registers(saved_regs); | 540 | show_registers(saved_regs); |
529 | printk("Current registers\n"); | 541 | printk("Current registers\n"); |
530 | show_registers(regs); | 542 | show_registers(regs); |
531 | BUG(); | 543 | BUG(); |
532 | } | 544 | } |
533 | *regs = jprobe_saved_regs; | 545 | *regs = kcb->jprobe_saved_regs; |
534 | memcpy((kprobe_opcode_t *) stack_addr, jprobes_stack, | 546 | memcpy((kprobe_opcode_t *) stack_addr, kcb->jprobes_stack, |
535 | MIN_STACK_SIZE(stack_addr)); | 547 | MIN_STACK_SIZE(stack_addr)); |
536 | return 1; | 548 | return 1; |
537 | } | 549 | } |