[RFC Patch 4/9] Modify kprobe exception handler to recognisesingle-stepping by HW Breakpoint handler

From: K.Prasad
Date: Tue Oct 07 2008 - 07:44:18 EST


This patch modifies the kprobe handler to help it recognise single-stepping by
the HW Breakpoint exception code. A per-cpu variable called 'sstep_reason' to
distinguish the source of single-step exceptions.

Signed-off-by: K.Prasad <prasad@xxxxxxxxxxxxxxxxxx>
Signed-off-by: Alan Stern <stern@xxxxxxxxxxxxxxxxxxx>
---
arch/x86/kernel/kprobes.c | 18 ++++++++++++++++--
include/asm-x86/kprobes.h | 8 ++++++++
2 files changed, 24 insertions(+), 2 deletions(-)

Index: linux-bkpt-lkml-27-rc9/arch/x86/kernel/kprobes.c
===================================================================
--- linux-bkpt-lkml-27-rc9.orig/arch/x86/kernel/kprobes.c
+++ linux-bkpt-lkml-27-rc9/arch/x86/kernel/kprobes.c
@@ -54,6 +54,7 @@
#include <asm/pgtable.h>
#include <asm/uaccess.h>
#include <asm/alternative.h>
+#include <asm/debugreg.h>

void jprobe_return_end(void);

@@ -517,6 +518,7 @@ static int __kprobes kprobe_handler(stru
kprobe_opcode_t *addr;
struct kprobe *p;
struct kprobe_ctlblk *kcb;
+ unsigned int *ssr;

addr = (kprobe_opcode_t *)(regs->ip - sizeof(kprobe_opcode_t));
if (*addr != BREAKPOINT_INSTRUCTION) {
@@ -541,6 +543,7 @@ static int __kprobes kprobe_handler(stru
*/
preempt_disable();

+ ssr = &(__get_cpu_var(sstep_reason));
kcb = get_kprobe_ctlblk();
p = get_kprobe(addr);

@@ -560,14 +563,17 @@ static int __kprobes kprobe_handler(stru
* for jprobe processing, so get out doing nothing
* more here.
*/
- if (!p->pre_handler || !p->pre_handler(p, regs))
+ if (!p->pre_handler || !p->pre_handler(p, regs)) {
setup_singlestep(p, regs, kcb);
+ (*ssr) |= SSTEP_KPROBE;
+ }
return 1;
}
} else if (kprobe_running()) {
p = __get_cpu_var(current_kprobe);
if (p->break_handler && p->break_handler(p, regs)) {
setup_singlestep(p, regs, kcb);
+ (*ssr) |= SSTEP_KPROBE;
return 1;
}
} /* else: not a kprobe fault; let the kernel handle it */
@@ -952,6 +958,7 @@ int __kprobes kprobe_exceptions_notify(s
{
struct die_args *args = data;
int ret = NOTIFY_DONE;
+ unsigned int *ssr = &(__get_cpu_var(sstep_reason));

if (args->regs && user_mode_vm(args->regs))
return ret;
@@ -962,8 +969,15 @@ int __kprobes kprobe_exceptions_notify(s
ret = NOTIFY_STOP;
break;
case DIE_DEBUG:
- if (post_kprobe_handler(args->regs))
+ /* We could be here due to single-stepping after a pre-handler
+ * execution of HW Breakpoint or kprobes. We determine the cause
+ * using the bitmask flag 'sstep_reason'.
+ */
+ if (((*ssr) & SSTEP_KPROBE) &&
+ post_kprobe_handler(args->regs)) {
+ current->thread.vdr6 &= ~DR_STEP;
ret = NOTIFY_STOP;
+ }
break;
case DIE_GPF:
/*
Index: linux-bkpt-lkml-27-rc9/include/asm-x86/kprobes.h
===================================================================
--- linux-bkpt-lkml-27-rc9.orig/include/asm-x86/kprobes.h
+++ linux-bkpt-lkml-27-rc9/include/asm-x86/kprobes.h
@@ -30,6 +30,14 @@
struct pt_regs;
struct kprobe;

+/* Single stepping can be initiated for kprobes post handler or following HW
+ * Breakpoint exception. The bitmask below is used to identify the cause.
+ */
+#define SSTEP_KPROBE 1
+#define SSTEP_HWBKPT 2
+
+DECLARE_PER_CPU(unsigned int, sstep_reason);
+
typedef u8 kprobe_opcode_t;
#define BREAKPOINT_INSTRUCTION 0xcc
#define RELATIVEJUMP_INSTRUCTION 0xe9
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/