This is the mail archive of the systemtap@sourceware.org mailing list for the systemtap project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [4/5 PATCH] Kprobes fix for broken fault handling for ia64


Prasanna S Panchamukhi wrote:
This patch fixes the broken kprobes fault handling similar
to i386 architecture.

Signed-off-by: Prasanna S Panchamukhi <prasanna@in.ibm.com>
Acked-by: Anil S Keshavamurthy<anil.s.keshavamurthy@intel.com>


arch/ia64/kernel/kprobes.c | 55 ++++++++++++++++++++++++++++++++++++++++----- 1 files changed, 50 insertions(+), 5 deletions(-)

diff -puN arch/ia64/kernel/kprobes.c~kprobes-ia64-pagefault-handling arch/ia64/kernel/kprobes.c
--- linux-2.6.16-rc5-mm2/arch/ia64/kernel/kprobes.c~kprobes-ia64-pagefault-handling 2006-03-07 11:18:46.000000000 +0530
+++ linux-2.6.16-rc5-mm2-prasanna/arch/ia64/kernel/kprobes.c 2006-03-07 11:21:12.000000000 +0530
@@ -34,6 +34,7 @@
#include <asm/pgtable.h>
#include <asm/kdebug.h>
#include <asm/sections.h>
+#include <asm/uaccess.h>
extern void jprobe_inst_return(void);
@@ -722,13 +723,57 @@ static int __kprobes kprobes_fault_handl
struct kprobe *cur = kprobe_running();
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
- if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
- return 1;
- if (kcb->kprobe_status & KPROBE_HIT_SS) {
- resume_execution(cur, regs);
- reset_current_kprobe();
+ switch(kcb->kprobe_status) {
+ case KPROBE_HIT_SS:
+ case KPROBE_REENTER:
+ /*
+ * We are here because the instruction being single
+ * stepped caused a page fault. We reset the current
+ * kprobe and the instruction pointer points back to
+ * the probe address and allow the page fault handler
+ * to continue as a normal page fault.
+ */
+ regs->cr_iip = ((unsigned long)cur->addr) & ~0xFULL;
+ ia64_psr(regs) = ((unsigned long)cur->addr) & 0xf;
It should be:
regs->cr_iip = ((unsigned long)cur->addr) & ~0xFULL;
ia64_psr(regs)->ri = ((unsigned long)cur->addr) & 0xf;
And I test this patch in IA64 platform, it passed. But find that sometime user space copy is incomplete. If page fault happens in kprobe prehandler/posthandler, if will first call fix_exception() and return, Normally in page fault process procedure system will load page into memory, and the system will call fix_exceptioin if failed to load page into memory.


The attachment is my test case in IA64, it is easy to port to other platform.

Bibo,mao
/*kprobe_example.c*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kprobes.h>
#include <linux/kallsyms.h>
#include <linux/sched.h>
#include <asm/uaccess.h>

#define PATH_MAX        4096	/* # chars in a path name including nul */

/*For each probe you need to allocate a kprobe structure*/
static struct kprobe kp;
static char *filename, *filename1;
static int fault_happened;
static unsigned long r32;

struct ia64_stap_get_arbsp_param {
        unsigned long ip;
        unsigned long *address;
};

static void ia64_stap_get_arbsp(struct unw_frame_info *info, void *arg)
{
        unsigned long ip;
        struct ia64_stap_get_arbsp_param *lp = arg;

        do {
                unw_get_ip(info, &ip);
                if (ip == 0)
                        break;
                if (ip == lp->ip) {
                        unw_get_bsp(info, (unsigned long*)&lp->address);
                        return;
                }
        } while (unw_unwind(info) >= 0);
        lp->address = 0;
}

static long ia64_fetch_register(int regno, struct pt_regs *pt_regs)
{
        struct ia64_stap_get_arbsp_param pa;

        if (regno < 32 || regno > 127)
                return 0;

        pa.ip = pt_regs->cr_iip;
        unw_init_running(ia64_stap_get_arbsp, &pa);
        if (pa.address == 0)
                return 0;

        return *ia64_rse_skip_regs(pa.address, regno-32);
}

/*kprobe pre_handler: called just before the probed instruction is executed*/
int handler_pre(struct kprobe *p, struct pt_regs *regs)
{
	fault_happened = 0;
	r32 = ia64_fetch_register(32, regs);

	/* here r32 is pointer to filename parameter pointer */
	copy_from_user(filename, (void*)r32, PATH_MAX);
	printk("filename %s \n", filename);
        return 0;
}

/*kprobe post_handler: called after the probed instruction is executed*/
void handler_post(struct kprobe *p, struct pt_regs *regs, unsigned long flags)
{
	if (fault_happened == 1){
		copy_from_user(filename1, (void*)r32, PATH_MAX);
		printk("filename: %s \n", filename);
		printk("filename1: %s \n", filename1);
	}

	fault_happened = 0; 
}

/* fault_handler: this is called if an exception is generated for any
 * instruction within the pre- or post-handler, or when Kprobes
 * single-steps the probed instruction.
 */
int handler_fault(struct kprobe *p, struct pt_regs *regs, int trapnr)
{
        fault_happened = 1 ;

        return 0;
}

int init_module(void)
{
        int ret;
	
	filename = kzalloc(PATH_MAX, GFP_KERNEL);
	filename1 = kzalloc(PATH_MAX, GFP_KERNEL);
        kp.pre_handler = handler_pre;
        kp.post_handler = handler_post;
        kp.fault_handler = handler_fault;
        kp.addr = (kprobe_opcode_t*) kallsyms_lookup_name("sys_open");
        /* register the kprobe now */
        if (!kp.addr) {
                return -1;
        }
        if ((ret = register_kprobe(&kp) < 0)) {
                printk("register_kprobe failed, returned %d\n", ret);
                return -1;
        }
        printk("kprobe registered\n");
        return 0;
}

void cleanup_module(void)
{
	unregister_kprobe(&kp);
	kfree(filename);
	kfree(filename1);
	printk("kprobe unregistered\n");
}

MODULE_LICENSE("GPL");


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]