Commit 644f6741 authored by Prasanna S. Panchamukhi's avatar Prasanna S. Panchamukhi Committed by Linus Torvalds

[PATCH] kprobes exception notifier fix

This patch modifies the return value of kprobes exceptions notify handler. 
The kprobes exception notifier returns NOTIFY_STOP on handling
notification.  This patch helps other debuggers to co-exists with the
Kprobes.  Other debuggers registered for exceptions notification must
return NOTIFY_STOP on handling the notification.
Signed-off-by: default avatarPrasanna S Panchamukhi <prasanna@in.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 5fe20d6e
......@@ -267,26 +267,26 @@ int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val,
switch (val) {
case DIE_INT3:
if (kprobe_handler(args->regs))
return NOTIFY_OK;
return NOTIFY_STOP;
break;
case DIE_DEBUG:
if (post_kprobe_handler(args->regs))
return NOTIFY_OK;
return NOTIFY_STOP;
break;
case DIE_GPF:
if (kprobe_running() &&
kprobe_fault_handler(args->regs, args->trapnr))
return NOTIFY_OK;
return NOTIFY_STOP;
break;
case DIE_PAGE_FAULT:
if (kprobe_running() &&
kprobe_fault_handler(args->regs, args->trapnr))
return NOTIFY_OK;
return NOTIFY_STOP;
break;
default:
break;
}
return NOTIFY_BAD;
return NOTIFY_DONE;
}
int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
......
......@@ -459,7 +459,7 @@ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
info.si_code = sicode; \
info.si_addr = (void __user *)siaddr; \
if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
== NOTIFY_OK) \
== NOTIFY_STOP) \
return; \
do_trap(trapnr, signr, str, 1, regs, error_code, &info); \
}
......@@ -528,7 +528,7 @@ asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
gp_in_kernel:
if (!fixup_exception(regs)) {
if (notify_die(DIE_GPF, "general protection fault", regs,
error_code, 13, SIGSEGV) == NOTIFY_OK);
error_code, 13, SIGSEGV) == NOTIFY_STOP);
return;
die("general protection fault", regs, error_code);
}
......@@ -602,7 +602,7 @@ static void default_do_nmi(struct pt_regs * regs)
if (!(reason & 0xc0)) {
if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 0, SIGINT)
== NOTIFY_BAD)
== NOTIFY_STOP)
return;
#ifdef CONFIG_X86_LOCAL_APIC
/*
......@@ -617,7 +617,7 @@ static void default_do_nmi(struct pt_regs * regs)
unknown_nmi_error(reason, regs);
return;
}
if (notify_die(DIE_NMI, "nmi", regs, reason, 0, SIGINT) == NOTIFY_BAD)
if (notify_die(DIE_NMI, "nmi", regs, reason, 0, SIGINT) == NOTIFY_STOP)
return;
if (reason & 0x80)
mem_parity_error(reason, regs);
......@@ -666,7 +666,7 @@ void unset_nmi_callback(void)
asmlinkage int do_int3(struct pt_regs *regs, long error_code)
{
if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP)
== NOTIFY_OK)
== NOTIFY_STOP)
return 1;
/* This is an interrupt gate, because kprobes wants interrupts
disabled. Normal trap handlers don't. */
......@@ -707,7 +707,7 @@ asmlinkage void do_debug(struct pt_regs * regs, long error_code)
__asm__ __volatile__("movl %%db6,%0" : "=r" (condition));
if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code,
SIGTRAP) == NOTIFY_OK)
SIGTRAP) == NOTIFY_STOP)
return;
/* It's safe to allow irq's after DR6 has been saved */
if (regs->eflags & X86_EFLAGS_IF)
......
......@@ -227,7 +227,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
__asm__("movl %%cr2,%0":"=r" (address));
if (notify_die(DIE_PAGE_FAULT, "page fault", regs, error_code, 14,
SIGSEGV) == NOTIFY_OK)
SIGSEGV) == NOTIFY_STOP)
return;
/* It's safe to allow irq's after cr2 has been saved */
if (regs->eflags & (X86_EFLAGS_IF|VM_MASK))
......
......@@ -179,26 +179,26 @@ int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val,
switch (val) {
case DIE_DEBUG:
if (kprobe_handler(args->regs))
return NOTIFY_OK;
return NOTIFY_STOP;
break;
case DIE_DEBUG_2:
if (post_kprobe_handler(args->regs))
return NOTIFY_OK;
return NOTIFY_STOP;
break;
case DIE_GPF:
if (kprobe_running() &&
kprobe_fault_handler(args->regs, args->trapnr))
return NOTIFY_OK;
return NOTIFY_STOP;
break;
case DIE_PAGE_FAULT:
if (kprobe_running() &&
kprobe_fault_handler(args->regs, args->trapnr))
return NOTIFY_OK;
return NOTIFY_STOP;
break;
default:
break;
}
return NOTIFY_BAD;
return NOTIFY_DONE;
}
asmlinkage void kprobe_trap(unsigned long trap_level, struct pt_regs *regs)
......@@ -216,7 +216,7 @@ asmlinkage void kprobe_trap(unsigned long trap_level, struct pt_regs *regs)
*/
if (notify_die((trap_level == 0x170) ? DIE_DEBUG : DIE_DEBUG_2,
(trap_level == 0x170) ? "debug" : "debug_2",
regs, 0, trap_level, SIGTRAP) != NOTIFY_OK)
regs, 0, trap_level, SIGTRAP) != NOTIFY_STOP)
bad_trap(regs, trap_level);
}
......
......@@ -96,7 +96,7 @@ void bad_trap(struct pt_regs *regs, long lvl)
siginfo_t info;
if (notify_die(DIE_TRAP, "bad trap", regs,
0, lvl, SIGTRAP) == NOTIFY_OK)
0, lvl, SIGTRAP) == NOTIFY_STOP)
return;
if (lvl < 0x100) {
......@@ -126,7 +126,7 @@ void bad_trap_tl1(struct pt_regs *regs, long lvl)
char buffer[32];
if (notify_die(DIE_TRAP_TL1, "bad trap tl1", regs,
0, lvl, SIGTRAP) == NOTIFY_OK)
0, lvl, SIGTRAP) == NOTIFY_STOP)
return;
dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
......@@ -149,7 +149,7 @@ void instruction_access_exception(struct pt_regs *regs,
siginfo_t info;
if (notify_die(DIE_TRAP, "instruction access exception", regs,
0, 0x8, SIGTRAP) == NOTIFY_OK)
0, 0x8, SIGTRAP) == NOTIFY_STOP)
return;
if (regs->tstate & TSTATE_PRIV) {
......@@ -173,7 +173,7 @@ void instruction_access_exception_tl1(struct pt_regs *regs,
unsigned long sfsr, unsigned long sfar)
{
if (notify_die(DIE_TRAP_TL1, "instruction access exception tl1", regs,
0, 0x8, SIGTRAP) == NOTIFY_OK)
0, 0x8, SIGTRAP) == NOTIFY_STOP)
return;
dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
......@@ -186,7 +186,7 @@ void data_access_exception(struct pt_regs *regs,
siginfo_t info;
if (notify_die(DIE_TRAP, "data access exception", regs,
0, 0x30, SIGTRAP) == NOTIFY_OK)
0, 0x30, SIGTRAP) == NOTIFY_STOP)
return;
if (regs->tstate & TSTATE_PRIV) {
......@@ -260,7 +260,7 @@ void do_iae(struct pt_regs *regs)
spitfire_clean_and_reenable_l1_caches();
if (notify_die(DIE_TRAP, "instruction access exception", regs,
0, 0x8, SIGTRAP) == NOTIFY_OK)
0, 0x8, SIGTRAP) == NOTIFY_STOP)
return;
info.si_signo = SIGBUS;
......@@ -292,7 +292,7 @@ void do_dae(struct pt_regs *regs)
spitfire_clean_and_reenable_l1_caches();
if (notify_die(DIE_TRAP, "data access exception", regs,
0, 0x30, SIGTRAP) == NOTIFY_OK)
0, 0x30, SIGTRAP) == NOTIFY_STOP)
return;
info.si_signo = SIGBUS;
......@@ -1695,7 +1695,7 @@ void do_fpe_common(struct pt_regs *regs)
void do_fpieee(struct pt_regs *regs)
{
if (notify_die(DIE_TRAP, "fpu exception ieee", regs,
0, 0x24, SIGFPE) == NOTIFY_OK)
0, 0x24, SIGFPE) == NOTIFY_STOP)
return;
do_fpe_common(regs);
......@@ -1709,7 +1709,7 @@ void do_fpother(struct pt_regs *regs)
int ret = 0;
if (notify_die(DIE_TRAP, "fpu exception other", regs,
0, 0x25, SIGFPE) == NOTIFY_OK)
0, 0x25, SIGFPE) == NOTIFY_STOP)
return;
switch ((current_thread_info()->xfsr[0] & 0x1c000)) {
......@@ -1728,7 +1728,7 @@ void do_tof(struct pt_regs *regs)
siginfo_t info;
if (notify_die(DIE_TRAP, "tagged arithmetic overflow", regs,
0, 0x26, SIGEMT) == NOTIFY_OK)
0, 0x26, SIGEMT) == NOTIFY_STOP)
return;
if (regs->tstate & TSTATE_PRIV)
......@@ -1750,7 +1750,7 @@ void do_div0(struct pt_regs *regs)
siginfo_t info;
if (notify_die(DIE_TRAP, "integer division by zero", regs,
0, 0x28, SIGFPE) == NOTIFY_OK)
0, 0x28, SIGFPE) == NOTIFY_STOP)
return;
if (regs->tstate & TSTATE_PRIV)
......@@ -1936,7 +1936,7 @@ void do_illegal_instruction(struct pt_regs *regs)
siginfo_t info;
if (notify_die(DIE_TRAP, "illegal instruction", regs,
0, 0x10, SIGILL) == NOTIFY_OK)
0, 0x10, SIGILL) == NOTIFY_STOP)
return;
if (tstate & TSTATE_PRIV)
......@@ -1965,7 +1965,7 @@ void mem_address_unaligned(struct pt_regs *regs, unsigned long sfar, unsigned lo
siginfo_t info;
if (notify_die(DIE_TRAP, "memory address unaligned", regs,
0, 0x34, SIGSEGV) == NOTIFY_OK)
0, 0x34, SIGSEGV) == NOTIFY_STOP)
return;
if (regs->tstate & TSTATE_PRIV) {
......@@ -1991,7 +1991,7 @@ void do_privop(struct pt_regs *regs)
siginfo_t info;
if (notify_die(DIE_TRAP, "privileged operation", regs,
0, 0x11, SIGILL) == NOTIFY_OK)
0, 0x11, SIGILL) == NOTIFY_STOP)
return;
if (test_thread_flag(TIF_32BIT)) {
......
......@@ -149,7 +149,7 @@ static void unhandled_fault(unsigned long address, struct task_struct *tsk,
(tsk->mm ? (unsigned long) tsk->mm->pgd :
(unsigned long) tsk->active_mm->pgd));
if (notify_die(DIE_GPF, "general protection fault", regs,
0, 0, SIGSEGV) == NOTIFY_OK)
0, 0, SIGSEGV) == NOTIFY_STOP)
return;
die_if_kernel("Oops", regs);
}
......@@ -325,7 +325,7 @@ asmlinkage void do_sparc64_fault(struct pt_regs *regs)
fault_code = get_thread_fault_code();
if (notify_die(DIE_PAGE_FAULT, "page_fault", regs,
fault_code, 0, SIGSEGV) == NOTIFY_OK)
fault_code, 0, SIGSEGV) == NOTIFY_STOP)
return;
si_code = SEGV_MAPERR;
......
......@@ -390,7 +390,8 @@ void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason)
*/
alert_counter[cpu]++;
if (alert_counter[cpu] == 5*nmi_hz) {
if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_BAD) {
if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT)
== NOTIFY_STOP) {
alert_counter[cpu] = 0;
return;
}
......
......@@ -437,7 +437,8 @@ static void do_trap(int trapnr, int signr, char *str,
#define DO_ERROR(trapnr, signr, str, name) \
asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
{ \
if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) == NOTIFY_BAD) \
if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
== NOTIFY_STOP) \
return; \
do_trap(trapnr, signr, str, regs, error_code, NULL); \
}
......@@ -450,7 +451,8 @@ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
info.si_errno = 0; \
info.si_code = sicode; \
info.si_addr = (void __user *)siaddr; \
if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) == NOTIFY_BAD) \
if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
== NOTIFY_STOP) \
return; \
do_trap(trapnr, signr, str, regs, error_code, &info); \
}
......@@ -471,7 +473,8 @@ DO_ERROR(18, SIGSEGV, "reserved", reserved)
asmlinkage void *do_##name(struct pt_regs * regs, long error_code) \
{ \
struct pt_regs *pr = ((struct pt_regs *)(current->thread.rsp0))-1; \
if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) == NOTIFY_BAD) \
if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
== NOTIFY_STOP) \
return regs; \
if (regs->cs & 3) { \
memcpy(pr, regs, sizeof(struct pt_regs)); \
......@@ -565,7 +568,8 @@ asmlinkage void default_do_nmi(struct pt_regs * regs)
unsigned char reason = inb(0x61);
if (!(reason & 0xc0)) {
if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 0, SIGINT) == NOTIFY_BAD)
if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 0, SIGINT)
== NOTIFY_STOP)
return;
#ifdef CONFIG_X86_LOCAL_APIC
/*
......@@ -580,7 +584,7 @@ asmlinkage void default_do_nmi(struct pt_regs * regs)
unknown_nmi_error(reason, regs);
return;
}
if (notify_die(DIE_NMI, "nmi", regs, reason, 0, SIGINT) == NOTIFY_BAD)
if (notify_die(DIE_NMI, "nmi", regs, reason, 0, SIGINT) == NOTIFY_STOP)
return;
if (reason & 0x80)
mem_parity_error(reason, regs);
......@@ -676,7 +680,7 @@ asmlinkage void *do_debug(struct pt_regs * regs, unsigned long error_code)
clear_TF:
/* RED-PEN could cause spurious errors */
if (notify_die(DIE_DEBUG, "debug2", regs, condition, 1, SIGTRAP)
!= NOTIFY_BAD)
!= NOTIFY_STOP)
regs->eflags &= ~TF_MASK;
return regs;
}
......
......@@ -29,6 +29,10 @@ extern int notifier_call_chain(struct notifier_block **n, unsigned long val, voi
#define NOTIFY_OK 0x0001 /* Suits me */
#define NOTIFY_STOP_MASK 0x8000 /* Don't call further */
#define NOTIFY_BAD (NOTIFY_STOP_MASK|0x0002) /* Bad/Veto action */
/*
* Clean way to return from the notifier and stop further calls.
*/
#define NOTIFY_STOP (NOTIFY_OK|NOTIFY_STOP_MASK)
/*
* Declared notifiers so far. I can imagine quite a few more chains
......
......@@ -25,6 +25,8 @@
* hlists and exceptions notifier as suggested by Andi Kleen.
* 2004-July Suparna Bhattacharya <suparna@in.ibm.com> added jumper probes
* interface to access function arguments.
* 2004-Sep Prasanna S Panchamukhi <prasanna@in.ibm.com> Changed Kprobes
* exceptions notifier to be first on the priority list.
*/
#include <linux/kprobes.h>
#include <linux/spinlock.h>
......@@ -108,6 +110,7 @@ void unregister_kprobe(struct kprobe *p)
static struct notifier_block kprobe_exceptions_nb = {
.notifier_call = kprobe_exceptions_notify,
.priority = 0x7fffffff /* we need to notified first */
};
int register_jprobe(struct jprobe *jp)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment