/*
* Kernel Probes (KProbes)
- * arch/i386/kernel/kprobes.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
+struct kretprobe_blackpoint kretprobe_blacklist[] = {
+ {"__switch_to", }, /* This function switches only current task, but
+ doesn't switch kernel stack.*/
+ {NULL, NULL} /* Terminator */
+};
+const int kretprobe_blacklist_size = ARRAY_SIZE(kretprobe_blacklist);
+
/* insert a jmp code */
static __always_inline void set_jmp_op(void *from, void *to)
{
{
__get_cpu_var(current_kprobe) = p;
kcb->kprobe_saved_eflags = kcb->kprobe_old_eflags
- = (regs->eflags & (TF_MASK | IF_MASK));
+ = (regs->flags & (TF_MASK | IF_MASK));
if (is_IF_modifier(p->opcode))
kcb->kprobe_saved_eflags &= ~IF_MASK;
}
+static __always_inline void clear_btf(void)
+{
+ if (test_thread_flag(TIF_DEBUGCTLMSR))
+ wrmsr(MSR_IA32_DEBUGCTLMSR, 0, 0);
+}
+
+static __always_inline void restore_btf(void)
+{
+ if (test_thread_flag(TIF_DEBUGCTLMSR))
+ wrmsr(MSR_IA32_DEBUGCTLMSR, current->thread.debugctlmsr, 0);
+}
+
static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
{
- regs->eflags |= TF_MASK;
- regs->eflags &= ~IF_MASK;
+ clear_btf();
+ regs->flags |= TF_MASK;
+ regs->flags &= ~IF_MASK;
/*single step inline if the instruction is an int3*/
if (p->opcode == BREAKPOINT_INSTRUCTION)
- regs->eip = (unsigned long)p->addr;
+ regs->ip = (unsigned long)p->addr;
else
- regs->eip = (unsigned long)p->ainsn.insn;
+ regs->ip = (unsigned long)p->ainsn.insn;
}
/* Called with kretprobe_lock held */
void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
struct pt_regs *regs)
{
- unsigned long *sara = (unsigned long *)®s->esp;
+ unsigned long *sara = (unsigned long *)®s->sp;
ri->ret_addr = (kprobe_opcode_t *) *sara;
kprobe_opcode_t *addr;
struct kprobe_ctlblk *kcb;
- addr = (kprobe_opcode_t *)(regs->eip - sizeof(kprobe_opcode_t));
+ addr = (kprobe_opcode_t *)(regs->ip - sizeof(kprobe_opcode_t));
/*
* We don't want to be preempted for the entire
if (p) {
if (kcb->kprobe_status == KPROBE_HIT_SS &&
*p->ainsn.insn == BREAKPOINT_INSTRUCTION) {
- regs->eflags &= ~TF_MASK;
- regs->eflags |= kcb->kprobe_saved_eflags;
+ regs->flags &= ~TF_MASK;
+ regs->flags |= kcb->kprobe_saved_eflags;
goto no_kprobe;
}
/* We have reentered the kprobe_handler(), since
* another cpu right after we hit, no further
* handling of this interrupt is appropriate
*/
- regs->eip -= sizeof(kprobe_opcode_t);
+ regs->ip -= sizeof(kprobe_opcode_t);
ret = 1;
goto no_kprobe;
}
* Back up over the (now missing) int3 and run
* the original instruction.
*/
- regs->eip -= sizeof(kprobe_opcode_t);
+ regs->ip -= sizeof(kprobe_opcode_t);
ret = 1;
}
/* Not one of ours: let kernel handle it */
if (p->ainsn.boostable == 1 && !p->post_handler){
/* Boost up -- we can execute copied instructions directly */
reset_current_kprobe();
- regs->eip = (unsigned long)p->ainsn.insn;
+ regs->ip = (unsigned long)p->ainsn.insn;
preempt_enable_no_resched();
return 1;
}
asm volatile ( ".global kretprobe_trampoline\n"
"kretprobe_trampoline: \n"
" pushf\n"
- /* skip cs, eip, orig_eax */
+ /* skip cs, ip, orig_ax */
" subl $12, %esp\n"
" pushl %fs\n"
" pushl %ds\n"
" pushl %ebx\n"
" movl %esp, %eax\n"
" call trampoline_handler\n"
- /* move eflags to cs */
+ /* move flags to cs */
" movl 52(%esp), %edx\n"
" movl %edx, 48(%esp)\n"
- /* save true return address on eflags */
+ /* save true return address on flags */
" movl %eax, 52(%esp)\n"
" popl %ebx\n"
" popl %ecx\n"
" popl %edi\n"
" popl %ebp\n"
" popl %eax\n"
- /* skip eip, orig_eax, es, ds, fs */
+ /* skip ip, orig_ax, es, ds, fs */
" addl $20, %esp\n"
" popf\n"
" ret\n");
/*
* Called from kretprobe_trampoline
*/
-fastcall void *__kprobes trampoline_handler(struct pt_regs *regs)
+void *__kprobes trampoline_handler(struct pt_regs *regs)
{
struct kretprobe_instance *ri = NULL;
struct hlist_head *head, empty_rp;
spin_lock_irqsave(&kretprobe_lock, flags);
head = kretprobe_inst_table_head(current);
/* fixup registers */
- regs->xcs = __KERNEL_CS | get_kernel_rpl();
- regs->eip = trampoline_address;
- regs->orig_eax = 0xffffffff;
+ regs->cs = __KERNEL_CS | get_kernel_rpl();
+ regs->ip = trampoline_address;
+ regs->orig_ax = 0xffffffff;
/*
* It is possible to have multiple instances associated with a given
* interrupt. We have to fix up the stack as follows:
*
* 0) Except in the case of absolute or indirect jump or call instructions,
- * the new eip is relative to the copied instruction. We need to make
+ * the new ip is relative to the copied instruction. We need to make
* it relative to the original instruction.
*
* 1) If the single-stepped instruction was pushfl, then the TF and IF
- * flags are set in the just-pushed eflags, and may need to be cleared.
+ * flags are set in the just-pushed flags, and may need to be cleared.
*
* 2) If the single-stepped instruction was a call, the return address
* that is atop the stack is the address following the copied instruction.
static void __kprobes resume_execution(struct kprobe *p,
struct pt_regs *regs, struct kprobe_ctlblk *kcb)
{
- unsigned long *tos = (unsigned long *)®s->esp;
+ unsigned long *tos = (unsigned long *)®s->sp;
unsigned long copy_eip = (unsigned long)p->ainsn.insn;
unsigned long orig_eip = (unsigned long)p->addr;
- regs->eflags &= ~TF_MASK;
+ regs->flags &= ~TF_MASK;
switch (p->ainsn.insn[0]) {
case 0x9c: /* pushfl */
*tos &= ~(TF_MASK | IF_MASK);
case 0xca:
case 0xcb:
case 0xcf:
- case 0xea: /* jmp absolute -- eip is correct */
- /* eip is already adjusted, no more changes required */
+ case 0xea: /* jmp absolute -- ip is correct */
+ /* ip is already adjusted, no more changes required */
p->ainsn.boostable = 1;
goto no_change;
case 0xe8: /* call relative - Fix return addr */
if ((p->ainsn.insn[1] & 0x30) == 0x10) {
/*
* call absolute, indirect
- * Fix return addr; eip is correct.
+ * Fix return addr; ip is correct.
* But this is not boostable
*/
*tos = orig_eip + (*tos - copy_eip);
goto no_change;
} else if (((p->ainsn.insn[1] & 0x31) == 0x20) || /* jmp near, absolute indirect */
((p->ainsn.insn[1] & 0x31) == 0x21)) { /* jmp far, absolute indirect */
- /* eip is correct. And this is boostable */
+ /* ip is correct. And this is boostable */
p->ainsn.boostable = 1;
goto no_change;
}
}
if (p->ainsn.boostable == 0) {
- if ((regs->eip > copy_eip) &&
- (regs->eip - copy_eip) + 5 < MAX_INSN_SIZE) {
+ if ((regs->ip > copy_eip) &&
+ (regs->ip - copy_eip) + 5 < MAX_INSN_SIZE) {
/*
* These instructions can be executed directly if it
* jumps back to correct address.
*/
- set_jmp_op((void *)regs->eip,
- (void *)orig_eip + (regs->eip - copy_eip));
+ set_jmp_op((void *)regs->ip,
+ (void *)orig_eip + (regs->ip - copy_eip));
p->ainsn.boostable = 1;
} else {
p->ainsn.boostable = -1;
}
}
- regs->eip = orig_eip + (regs->eip - copy_eip);
+ regs->ip = orig_eip + (regs->ip - copy_eip);
no_change:
+ restore_btf();
+
return;
}
}
resume_execution(cur, regs, kcb);
- regs->eflags |= kcb->kprobe_saved_eflags;
+ regs->flags |= kcb->kprobe_saved_eflags;
+ trace_hardirqs_fixup_flags(regs->flags);
/*Restore back the original saved kprobes variables and continue. */
if (kcb->kprobe_status == KPROBE_REENTER) {
preempt_enable_no_resched();
/*
- * if somebody else is singlestepping across a probe point, eflags
+ * if somebody else is singlestepping across a probe point, flags
* will have TF set, in which case, continue the remaining processing
* of do_debug, as if this is not a probe hit.
*/
- if (regs->eflags & TF_MASK)
+ if (regs->flags & TF_MASK)
return 0;
return 1;
}
-static int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
+int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
{
struct kprobe *cur = kprobe_running();
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
/*
* We are here because the instruction being single
* stepped caused a page fault. We reset the current
- * kprobe and the eip points back to the probe address
+ * kprobe and the ip points back to the probe address
* and allow the page fault handler to continue as a
* normal page fault.
*/
- regs->eip = (unsigned long)cur->addr;
- regs->eflags |= kcb->kprobe_old_eflags;
+ regs->ip = (unsigned long)cur->addr;
+ regs->flags |= kcb->kprobe_old_eflags;
if (kcb->kprobe_status == KPROBE_REENTER)
restore_previous_kprobe(kcb);
else
ret = NOTIFY_STOP;
break;
case DIE_GPF:
- case DIE_PAGE_FAULT:
/* kprobe_running() needs smp_processor_id() */
preempt_disable();
if (kprobe_running() &&
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
kcb->jprobe_saved_regs = *regs;
- kcb->jprobe_saved_esp = ®s->esp;
+ kcb->jprobe_saved_esp = ®s->sp;
addr = (unsigned long)(kcb->jprobe_saved_esp);
/*
*/
memcpy(kcb->jprobes_stack, (kprobe_opcode_t *)addr,
MIN_STACK_SIZE(addr));
- regs->eflags &= ~IF_MASK;
- regs->eip = (unsigned long)(jp->entry);
+ regs->flags &= ~IF_MASK;
+ trace_hardirqs_off();
+ regs->ip = (unsigned long)(jp->entry);
return 1;
}
int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
{
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
- u8 *addr = (u8 *) (regs->eip - 1);
+ u8 *addr = (u8 *) (regs->ip - 1);
unsigned long stack_addr = (unsigned long)(kcb->jprobe_saved_esp);
struct jprobe *jp = container_of(p, struct jprobe, kp);
if ((addr > (u8 *) jprobe_return) && (addr < (u8 *) jprobe_return_end)) {
- if (®s->esp != kcb->jprobe_saved_esp) {
- struct pt_regs *saved_regs =
- container_of(kcb->jprobe_saved_esp,
- struct pt_regs, esp);
- printk("current esp %p does not match saved esp %p\n",
- ®s->esp, kcb->jprobe_saved_esp);
+ if (®s->sp != kcb->jprobe_saved_esp) {
+ struct pt_regs *saved_regs = &kcb->jprobe_saved_regs;
+ printk("current sp %p does not match saved sp %p\n",
+ ®s->sp, kcb->jprobe_saved_esp);
printk("Saved registers for jprobe %p\n", jp);
show_registers(saved_regs);
printk("Current registers\n");