This is the mail archive of the systemtap@sources.redhat.com 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]

[Bug fix] Exit probe patch


Hi,

This patch fixes the unregistreing problem that I found during test, I also include Jim's suggestion to pass the rprobe instance object to the rprobe handler (instead of kprobe object).

Also include here is a test module that inserts exit probes to almost all system calls, it will log a message (shows systemcall, return code, current pid) via printk if the return code for the particular system call is a negative value. I exclude some system calls due to

1) it does not return a negative code or void
2) high traffic

but you could turn it on if you want too (vi mksys_rprobe and remove the hyphen in front of the system call). I borrow some idea from the DTR tool, thanks Martin. Please give me feed back on this test module.


Kernel patch
------------
kernel-2.6.10-rprobe-accu.patch - Use this patch if you have applied the kernel-2.6.10-rprobe.patch that I sent out last week.


kernel-2.6.10-rprobe-2.patch - Use this patch on a clean 2.6.10 kernel.

System call test module
-----------------------
mksys_rprobe - use this script to generate the sys_rprobe.c and build the sys_rprobe.ko. Edit this file and change the KERNEL_SRC variable to fit your environment.


sys_rprobe.t - Source template to for mksys_rprobe.

Note: Put mksys_rprobe and sys_rprobe.t in the same directory.

Generic test module
-------------------
testrprobe.c - A generic test module. Use the included loadtestrprobe.sh script to load this module.


For example:

./loadtestrprobe.sh test_erprobe2

or

./loadtestrprobe.sh handle_mm_fault


Thanks, Hien.





--- linux-2.6.10.acc/include/linux/kprobes.h	2005-03-10 16:06:45.611716998 -0800
+++ linux-2.6.10.works/include/linux/kprobes.h	2005-03-09 15:43:20.000000000 -0800
@@ -41,7 +41,7 @@
 				       unsigned long flags);
 typedef int (*kprobe_fault_handler_t) (struct kprobe *, struct pt_regs *,
 				       int trapnr);
-typedef int (*rprobe_handler_t) (struct kprobe *, struct pt_regs *);
+typedef int (*rprobe_handler_t) (struct rprobe_instance *, struct pt_regs *);
 
 struct kprobe {
 	struct hlist_node hlist;
--- linux-2.6.10.acc/kernel/kprobes.c	2005-03-10 16:06:45.613716967 -0800
+++ linux-2.6.10.works/kernel/kprobes.c	2005-03-10 14:34:41.000000000 -0800
@@ -124,7 +124,7 @@
 	hlist_add_head(&ri->hlist, &rprobe_inst_table[hash_ptr(ri->stack_addr, RPROBE_HASH_BITS)]);
 }
 		
-int register_kprobe(struct kprobe *p)
+int _register_kprobe(struct kprobe *p)
 {
 	int ret = 0;
 	unsigned long flags;
@@ -151,10 +151,20 @@
 	return ret;
 }
 
+int register_kprobe(struct kprobe *p)
+{
+	p->rp = NULL;
+	return _register_kprobe(p);
+}
+
 void unregister_kprobe(struct kprobe *p)
 {
 	unsigned long flags;
 	spin_lock_irqsave(&kprobe_lock, flags);
+	if (get_kprobe(p->addr) == NULL) {
+		spin_unlock_irqrestore(&kprobe_lock, flags);
+		return;
+	}
 	arch_remove_kprobe(p);
 	*p->addr = p->opcode;
 	hlist_del(&p->hlist);
@@ -162,11 +172,19 @@
 			   (unsigned long) p->addr + sizeof(kprobe_opcode_t));
 	
 	if (p->rp != NULL) {
-		/* Also clean up rprobe */
 		if (p->rp->num_ri_running != 0) {
+			int i;
+			struct rprobe *rp;
+			struct rprobe_instance *ri;
 			/* Flag to tell the last running rprobe to clean up */
 			p->rp->unregistering = 1;
-		} else {
+			rp = kmalloc(sizeof(struct rprobe), GFP_KERNEL);
+			memcpy(rp, p->rp, sizeof(struct rprobe));
+			for (i = 0 ; i < p->rp->maxactive; i++) {
+				ri = p->rp->instances + i;
+				ri->rp = rp;
+			}
+		} else {	
 			kfree(p->rp->instances);
 		}
 	}
@@ -234,7 +252,7 @@
 	/* Establish function entry probe point */
 	/* todo: we need to deal with probe that has been registered */
 	
-	if((ret = register_kprobe(p)) != 0) {
+	if((ret = _register_kprobe(p)) != 0) {
 		kfree(rp->instances);
 		return ret;
 	}
--- linux-2.6.10.acc/arch/i386/kernel/kprobes.c	2005-03-10 16:06:45.633716665 -0800
+++ linux-2.6.10.works/arch/i386/kernel/kprobes.c	2005-03-10 15:41:34.000000000 -0800
@@ -196,8 +196,7 @@
 		return 0;
 	}
 	if (ri->rp && !ri->rp->unregistering) {
-
-		return ri->rp->handler(p, regs);
+		return ri->rp->handler(ri, regs);
 	}
 	return 0;
 }
@@ -271,7 +270,7 @@
 					 * the unregister
 					 */
 					kfree(ri->rp->instances);
-					ri->rp->unregistering = 0;
+					kfree(ri->rp);
 				} else {
 					/* put ri obj back to free list */
 					list_add(&ri->list, &ri->rp->free_instances);
--- linux-2.6.10/include/linux/kprobes.h	2004-12-24 13:34:27.000000000 -0800
+++ linux-2.6.10.works/include/linux/kprobes.h	2005-03-09 15:43:20.000000000 -0800
@@ -34,12 +34,15 @@
 
 struct kprobe;
 struct pt_regs;
+struct rprobe_instance;
 typedef int (*kprobe_pre_handler_t) (struct kprobe *, struct pt_regs *);
 typedef int (*kprobe_break_handler_t) (struct kprobe *, struct pt_regs *);
 typedef void (*kprobe_post_handler_t) (struct kprobe *, struct pt_regs *,
 				       unsigned long flags);
 typedef int (*kprobe_fault_handler_t) (struct kprobe *, struct pt_regs *,
 				       int trapnr);
+typedef int (*rprobe_handler_t) (struct rprobe_instance *, struct pt_regs *);
+
 struct kprobe {
 	struct hlist_node hlist;
 
@@ -65,6 +68,9 @@
 
 	/* copy of the original instruction */
 	struct arch_specific_insn ainsn;
+	
+	/* point to rprobe */
+	struct rprobe *rp;
 };
 
 /*
@@ -82,6 +88,26 @@
 	kprobe_opcode_t *entry;	/* probe handling code to jump to */
 };
 
+struct rprobe {
+	rprobe_handler_t handler;
+	kprobe_fault_handler_t fault_handler;
+	int maxactive;
+	int nmissed;
+	int num_ri_running;
+	int unregistering;
+	struct kprobe *kprobe;
+	struct rprobe_instance *instances;	/* allocated memory */
+	struct list_head free_instances;
+};
+
+struct rprobe_instance {
+	struct list_head list;
+	struct hlist_node hlist;
+	struct rprobe *rp;
+	void *ret_addr;
+	void *stack_addr;
+};
+
 #ifdef CONFIG_KPROBES
 /* Locks kprobe: irq must be disabled */
 void lock_kprobes(void);
@@ -94,9 +120,12 @@
 	return kprobe_cpu == smp_processor_id();
 }
 
+asmlinkage void rprobe_trampoline(void) __asm__("rprobe_trampoline");
+
 extern int arch_prepare_kprobe(struct kprobe *p);
 extern void arch_remove_kprobe(struct kprobe *p);
 extern void show_registers(struct pt_regs *regs);
+extern int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs);
 
 /* Get the kprobe at this addr (if any).  Must have called lock_kprobes */
 struct kprobe *get_kprobe(void *addr);
@@ -109,6 +138,15 @@
 void unregister_jprobe(struct jprobe *p);
 void jprobe_return(void);
 
+int register_erprobe(struct kprobe *p, struct rprobe *rp);
+int register_jrprobe(struct jprobe *p, struct rprobe *rp);
+
+struct rprobe_instance *get_free_rinst(struct rprobe *rp);
+struct rprobe_instance *get_rinst(void *sara);
+void add_rprobe_inst_to_hash(struct rprobe_instance *ri); 
+
+void test_erprobe(void);
+int test_erprobe2(int a, int b, int c, char *str);
 #else
 static inline int kprobe_running(void)
 {
@@ -131,5 +169,13 @@
 static inline void jprobe_return(void)
 {
 }
+static inline int register_erprobe(struct kprobe *p, struct rprobe *rp)
+{
+	return -ENOSYS;
+}
+static inline int register_jrprobe(struct jprobe *p, struct rprobe *rp)
+{
+	return -ENOSYS;
+}
 #endif
 #endif				/* _LINUX_KPROBES_H */
--- linux-2.6.10/kernel/kprobes.c	2004-12-24 13:35:59.000000000 -0800
+++ linux-2.6.10.works/kernel/kprobes.c	2005-03-10 14:34:41.000000000 -0800
@@ -42,6 +42,11 @@
 
 static struct hlist_head kprobe_table[KPROBE_TABLE_SIZE];
 
+#define RPROBE_HASH_BITS	KPROBE_HASH_BITS	
+
+#define RPROBE_INST_TABLE_SIZE  KPROBE_TABLE_SIZE
+static struct hlist_head rprobe_inst_table[RPROBE_INST_TABLE_SIZE];
+
 unsigned int kprobe_cpu = NR_CPUS;
 static spinlock_t kprobe_lock = SPIN_LOCK_UNLOCKED;
 
@@ -58,6 +63,24 @@
 	spin_unlock(&kprobe_lock);
 }
 
+struct kprobe trampoline_p = {
+		.addr = (kprobe_opcode_t *) &rprobe_trampoline,
+		.pre_handler = trampoline_probe_handler,
+		.rp = NULL
+};
+
+static void init_rprobe(void)
+{
+	int i;
+
+	/* Register a probe point at the rprobe trampoline */
+	register_kprobe(&trampoline_p);
+
+	/* Allocate rprobe instances table */	
+	for (i = 0; i < RPROBE_INST_TABLE_SIZE; i++)
+		INIT_HLIST_HEAD(&rprobe_inst_table[i]);
+}
+
 /* You have to be holding the kprobe_lock */
 struct kprobe *get_kprobe(void *addr)
 {
@@ -73,7 +96,35 @@
 	return NULL;
 }
 
-int register_kprobe(struct kprobe *p)
+struct rprobe_instance * get_free_rinst(struct rprobe *rp)
+{
+	if (list_empty(&rp->free_instances)) {
+		return NULL;
+	}
+	return (struct rprobe_instance *) rp->free_instances.next;
+}	
+
+struct rprobe_instance *get_rinst(void *sara)
+{
+	struct hlist_head *head;
+	struct hlist_node *node;
+
+	head = &rprobe_inst_table[hash_ptr(sara, RPROBE_HASH_BITS)];
+	hlist_for_each(node, head) {
+		struct rprobe_instance *ri = hlist_entry(node, 
+						struct rprobe_instance, hlist);
+		if (ri->stack_addr == sara)
+			return ri;
+	}
+	return NULL;
+}
+
+void add_rprobe_inst_to_hash(struct rprobe_instance *ri)
+{
+	hlist_add_head(&ri->hlist, &rprobe_inst_table[hash_ptr(ri->stack_addr, RPROBE_HASH_BITS)]);
+}
+		
+int _register_kprobe(struct kprobe *p)
 {
 	int ret = 0;
 	unsigned long flags;
@@ -100,15 +151,43 @@
 	return ret;
 }
 
+int register_kprobe(struct kprobe *p)
+{
+	p->rp = NULL;
+	return _register_kprobe(p);
+}
+
 void unregister_kprobe(struct kprobe *p)
 {
 	unsigned long flags;
 	spin_lock_irqsave(&kprobe_lock, flags);
+	if (get_kprobe(p->addr) == NULL) {
+		spin_unlock_irqrestore(&kprobe_lock, flags);
+		return;
+	}
 	arch_remove_kprobe(p);
 	*p->addr = p->opcode;
 	hlist_del(&p->hlist);
 	flush_icache_range((unsigned long) p->addr,
 			   (unsigned long) p->addr + sizeof(kprobe_opcode_t));
+	
+	if (p->rp != NULL) {
+		if (p->rp->num_ri_running != 0) {
+			int i;
+			struct rprobe *rp;
+			struct rprobe_instance *ri;
+			/* Flag to tell the last running rprobe to clean up */
+			p->rp->unregistering = 1;
+			rp = kmalloc(sizeof(struct rprobe), GFP_KERNEL);
+			memcpy(rp, p->rp, sizeof(struct rprobe));
+			for (i = 0 ; i < p->rp->maxactive; i++) {
+				ri = p->rp->instances + i;
+				ri->rp = rp;
+			}
+		} else {	
+			kfree(p->rp->instances);
+		}
+	}
 	spin_unlock_irqrestore(&kprobe_lock, flags);
 }
 
@@ -131,6 +210,79 @@
 	unregister_kprobe(&jp->kp);
 }
 
+int register_erprobe(struct kprobe *p, struct rprobe *rp)
+{
+	int ret = 0;
+	static int rprobe_init_setup = 0;
+	struct rprobe_instance *inst;
+	int maxinst, i;
+	
+	if (rprobe_init_setup == 0) {
+		init_rprobe();
+		rprobe_init_setup = 1;
+	}
+	/* Pre-allocate memory for max rprobe instances */
+	if (rp->maxactive > 0) {
+		maxinst = rp->maxactive;
+	} else {
+#ifdef CONFIG_PREEMPT
+		maxinst = max(10, 2 * NR_CPUS);
+#else
+		maxinst = NR_CPUS;
+#endif
+	} 
+	rp->instances = kmalloc(maxinst * sizeof(struct rprobe_instance), 
+					GFP_KERNEL);
+	if (rp->instances == NULL) {
+		return -ENOMEM;
+	}
+	
+	INIT_LIST_HEAD(&rp->free_instances);
+	/* Put all rprobe_instance object on the free list */
+	for (i = 0; i < maxinst; i++) {
+		inst = rp->instances + i;
+		list_add(&inst->list, &rp->free_instances);
+	}
+	rp->num_ri_running = 0;
+	rp->nmissed = 0;
+	rp->unregistering = 0;
+	rp->kprobe = p;
+	p->rp = rp;
+
+	/* Establish function entry probe point */
+	/* todo: we need to deal with probe that has been registered */
+	
+	if((ret = _register_kprobe(p)) != 0) {
+		kfree(rp->instances);
+		return ret;
+	}
+	return ret;
+}
+
+int register_jrprobe(struct jprobe *jp, struct rprobe *rp)
+{
+
+	jp->kp.pre_handler = setjmp_pre_handler;
+	jp->kp.break_handler = longjmp_break_handler;
+
+	return register_erprobe(&jp->kp, rp);
+}
+	
+/* Just for testing - remove when done */
+void test_erprobe()
+{
+	int a,b,c;
+	a=15;
+	b=10;
+	c=20;
+	printk("test_erprobe invoked: a=%d, b=%d, c=%d.\n", a,b,c);
+}
+int test_erprobe2(int a, int b, int c, char *str)
+{
+	printk("test_erprobe2 invoked: a=%d, b=%d, c=%d, str=%s.\n", a,b,c, str);
+	return 1;
+}
+
 static int __init init_kprobes(void)
 {
 	int i, err = 0;
@@ -139,11 +291,12 @@
 	/* initialize all list heads */
 	for (i = 0; i < KPROBE_TABLE_SIZE; i++)
 		INIT_HLIST_HEAD(&kprobe_table[i]);
-
+	
 	err = register_die_notifier(&kprobe_exceptions_nb);
 	return err;
 }
 
+
 __initcall(init_kprobes);
 
 EXPORT_SYMBOL_GPL(register_kprobe);
@@ -151,3 +304,7 @@
 EXPORT_SYMBOL_GPL(register_jprobe);
 EXPORT_SYMBOL_GPL(unregister_jprobe);
 EXPORT_SYMBOL_GPL(jprobe_return);
+EXPORT_SYMBOL_GPL(register_erprobe);
+EXPORT_SYMBOL_GPL(register_jrprobe);
+EXPORT_SYMBOL_GPL(test_erprobe);
+EXPORT_SYMBOL_GPL(test_erprobe2);
--- linux-2.6.10/arch/i386/kernel/kprobes.c	2004-12-24 13:34:33.000000000 -0800
+++ linux-2.6.10.works/arch/i386/kernel/kprobes.c	2005-03-10 15:41:34.000000000 -0800
@@ -143,11 +143,38 @@
 	if (is_IF_modifier(p->opcode))
 		kprobe_saved_eflags &= ~IF_MASK;
 
+	if (p->rp != NULL) {
+		/* 
+	 	 * Get a rprobe instance off the free list and populate it
+	 	 * with the return addr, stack addr, and rp.
+	 	 */
+		struct rprobe_instance *ri;
+		unsigned long *sara = (unsigned long *)&regs->esp;
+
+		if ((ri = get_free_rinst(p->rp)) != NULL) {
+			INIT_HLIST_NODE(&ri->hlist);
+			ri->rp = p->rp;
+			ri->stack_addr = sara;
+			ri->ret_addr =  (void *) *sara;
+			/* Add probe instance in hash */
+			add_rprobe_inst_to_hash(ri);
+			/* Replace the return addr with trampoline addr */
+			*sara = (unsigned long) &rprobe_trampoline;
+			/* 
+			 * Remove obj in free list - 
+			 * will add it back when resume execution
+			 */
+			list_del(&ri->list);
+			p->rp->num_ri_running++;
+		} else {
+			p->rp->nmissed++;
+		}
+	}	
+
 	if (p->pre_handler(p, regs)) {
 		/* handler has already set things up, so skip ss setup */
 		return 1;
 	}
-
       ss_probe:
 	prepare_singlestep(p, regs);
 	kprobe_status = KPROBE_HIT_SS;
@@ -157,6 +184,22 @@
 	preempt_enable_no_resched();
 	return ret;
 }
+/*
+ * Called when we hit the probe point at rprobe_trampoline
+ */  
+int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
+{
+	struct rprobe_instance *ri;
+	unsigned long *sara = (unsigned long *)(&regs->esp - 1);
+	
+	if ((ri = get_rinst(sara)) == NULL) {
+		return 0;
+	}
+	if (ri->rp && !ri->rp->unregistering) {
+		return ri->rp->handler(ri, regs);
+	}
+	return 0;
+}
 
 /*
  * Called after single-stepping.  p->addr is the address of the
@@ -210,6 +253,31 @@
 	case 0xea:		/* jmp absolute -- eip is correct */
 		next_eip = regs->eip;
 		break;
+	case 0x90: 	/* nop */
+		/* Check to make sure this is from the trampoline probe */
+		if (orig_eip  == (unsigned long) rprobe_trampoline) {
+			struct rprobe_instance *ri;
+			unsigned long *sara = tos - 1;	/* RA already popped */
+			ri = get_rinst(sara);
+			if (ri != NULL) {
+				next_eip = (unsigned long)ri->ret_addr;
+				hlist_del(&ri->hlist);
+				ri->rp->num_ri_running--;
+				if (ri->rp->num_ri_running == 0 &&
+				    ri->rp->unregistering == 1) {
+					/* This is the last running ri during
+					 * unregister, free memory to complete
+					 * the unregister
+					 */
+					kfree(ri->rp->instances);
+					kfree(ri->rp);
+				} else {
+					/* put ri obj back to free list */
+					list_add(&ri->list, &ri->rp->free_instances);
+				}
+			}
+		}
+		break;
 	default:
 		break;
 	}
--- linux-2.6.10/arch/i386/kernel/entry.S	2004-12-24 13:34:27.000000000 -0800
+++ linux-2.6.10.works/arch/i386/kernel/entry.S	2005-03-04 11:33:50.000000000 -0800
@@ -140,6 +140,12 @@
 .previous
 
 
+#ifdef CONFIG_KPROBES
+ENTRY(rprobe_trampoline)
+	nop
+/* NOT REACHED */
+#endif
+
 ENTRY(ret_from_fork)
 	pushl %eax
 	call schedule_tail
#!/bin/sh
KERNEl_SRC=/home/nguyhien/sandbox/dprobes/linux-2.6.10.works
SYS_CALLS="sys_restart_syscall \
sys_exit \
-sys_fork \
sys_read \
sys_write \
-sys_open \
-sys_close \
sys_waitpid \
sys_creat \
sys_link \
sys_unlink \
-sys_execve \
sys_chdir \
-sys_time \
sys_mknod \
sys_chmod \
sys_lchown16 \
sys_stat \
sys_lseek \
-sys_getpid \
sys_mount \
sys_oldumount \
sys_setuid16 \
-sys_getuid16 \
sys_stime \
sys_ptrace \
-sys_alarm \
sys_fstat \
sys_pause \
-sys_utime \
sys_access \
sys_nice \
sys_sync \
sys_kill \
sys_rename \
sys_mkdir \
sys_rmdir \
sys_dup \
sys_pipe \
sys_times \
sys_brk \
sys_setgid16 \
-sys_getgid16 \
-sys_signal \
-sys_geteuid16 \
-sys_getegid16 \
sys_acct \
sys_umount \
sys_ioctl \
sys_fcntl \
sys_setpgid \
sys_olduname \
sys_umask \
sys_chroot \
sys_ustat \
sys_dup2 \
-sys_getppid \
-sys_getpgrp \
sys_setsid \
sys_sigaction \
sys_sgetmask \
sys_ssetmask \
sys_setreuid16 \
sys_setregid16 \
sys_sigsuspend \
sys_sigpending \
sys_sethostname \
sys_setrlimit \
sys_old_getrlimit \
sys_getrusage \
sys_gettimeofday \
sys_settimeofday \
sys_getgroups16 \
sys_setgroups16 \
old_select \
sys_symlink \
sys_lstat \
sys_readlink \
sys_uselib \
sys_swapon \
sys_reboot \
old_readdir \
-old_mmap \
sys_munmap \
sys_truncate \
sys_ftruncate \
sys_fchmod \
sys_fchown16 \
sys_getpriority \
sys_setpriority \
sys_statfs \
sys_fstatfs \
sys_ioperm \
sys_socketcall \
sys_syslog \
sys_setitimer \
sys_getitimer \
sys_newstat \
sys_newlstat \
sys_newfstat \
sys_uname \
sys_iopl \
sys_vhangup \
sys_vm86old \
sys_wait4 \
sys_swapoff \
sys_sysinfo \
sys_ipc \
sys_fsync \
-sys_sigreturn \
sys_clone \
sys_setdomainname \
sys_newuname \
sys_modify_ldt \
sys_adjtimex \
sys_mprotect \
sys_sigprocmask \
-sys_init_module \
-sys_delete_module \
sys_quotactl \
sys_getpgid \
sys_fchdir \
sys_bdflush \
sys_sysfs \
sys_personality \
sys_setfsuid16 \
sys_setfsgid16 \
sys_llseek \
sys_getdents \
-sys_select \
sys_flock \
sys_msync \
sys_readv \
sys_writev \
-sys_getsid \
sys_fdatasync \
sys_sysctl \
sys_mlock \
sys_munlock \
sys_mlockall \
sys_munlockall \
sys_sched_setparam \
sys_sched_getparam \
sys_sched_setscheduler \
sys_sched_getscheduler \
sys_sched_yield \
sys_sched_get_priority_max \
sys_sched_get_priority_min \
sys_sched_rr_get_interval \
sys_nanosleep \
sys_mremap \
sys_setresuid16 \
-sys_getresuid16 \
sys_vm86 \
sys_poll \
sys_nfsservctl \
sys_setresgid16 \
-sys_getresgid16 \
sys_prctl \
-sys_rt_sigreturn \
sys_rt_sigaction \
sys_rt_sigprocmask \
-sys_rt_sigpending \
-sys_rt_sigtimedwait \
sys_rt_sigqueueinfo \
-sys_rt_sigsuspend \
sys_pread64 \
sys_pwrite64 \
sys_chown16 \
sys_getcwd \
sys_capget \
sys_capset \
sys_sigaltstack \
sys_sendfile \
-sys_vfork \
sys_getrlimit \
-sys_mmap2 \
sys_truncate64 \
sys_ftruncate64 \
-sys_stat64 \
sys_lstat64 \
sys_fstat64 \
sys_lchown \
sys_getuid \
sys_getgid \
sys_geteuid \
sys_getegid \
sys_setreuid \
sys_setregid \
sys_getgroups \
sys_setgroups \
sys_fchown \
sys_setresuid \
sys_getresuid \
sys_setresgid \
sys_getresgid \
sys_chown \
sys_setuid \
sys_setgid \
sys_setfsuid \
sys_setfsgid \
sys_pivot_root \
sys_mincore \
sys_madvise \
sys_getdents64 \
sys_fcntl64 \
-sys_gettid \
sys_readahead \
sys_setxattr \
sys_lsetxattr \
sys_fsetxattr \
sys_getxattr \
sys_lgetxattr \
sys_fgetxattr \
sys_listxattr \
sys_llistxattr \
sys_flistxattr \
sys_removexattr \
sys_lremovexattr \
sys_fremovexattr \
sys_tkill \
sys_sendfile64 \
sys_futex \
sys_sched_setaffinity \
sys_sched_getaffinity \
sys_set_thread_area \
sys_get_thread_area \
sys_io_setup \
sys_io_destroy \
sys_io_getevents \
sys_io_submit \
sys_io_cancel \
sys_fadvise64 \
sys_exit_group \
sys_lookup_dcookie \
sys_epoll_create \
sys_epoll_ctl \
sys_epoll_wait \
sys_remap_file_pages \
sys_set_tid_address \
sys_timer_create \
sys_timer_settime \
sys_timer_gettime \
sys_timer_getoverrun \
sys_timer_delete \
sys_clock_settime \
sys_clock_gettime \
sys_clock_getres \
sys_clock_nanosleep \
sys_statfs64 \
sys_fstatfs64 \
sys_tgkill \
sys_utimes \
sys_fadvise64_64 \
-sys_mbind \
-sys_get_mempolicy \
-sys_set_mempolicy \
-sys_mq_open \
-sys_mq_unlink \
-sys_mq_timedsend \
-sys_mq_timedreceive \
-sys_mq_notify \
-sys_mq_getsetattr \
-sys_waitid \
-sys_add_key \
-sys_request_key \
-sys_keyctl"

cp sys_rprobe.t sys_rprobe.c
for sys_call in $SYS_CALLS; do
	sys_call_entry_addr=`cat /proc/kallsyms | grep " ${sys_call}$" | awk '{print $1}'` 
	echo "${sys_call} : ${sys_call_entry_addr}"
	if [ "${sys_call_entry_addr}X" = "X" ]; then
		continue
	fi 
#	echo $sys_call_entry_addr
	jprobe_init="\/\* ${sys_call} \*\/\n\t{\n\t.kp.addr = (kprobe_opcode_t *) 0x${sys_call_entry_addr},\n\t.entry = (kprobe_opcode_t *) inst_sys_call\n\t},\n\t\/\*<jprobe>\*\/"
	name_addr_init="{\n\t.name=\"${sys_call}\",\n\t.addr=0x${sys_call_entry_addr}\n\t},\n\t\/\*<nameaddr>\*\/"

	cat sys_rprobe.c | sed "s/\/\*<jprobe>\*\//${jprobe_init}/" | sed "s/\/\*<nameaddr>\*\//${name_addr_init}/" > tmp_rp1.tmp

	cp tmp_rp1.tmp sys_rprobe.c
done
echo "obj-m := sys_rprobe.o" > Makefile
make -C $KERNEl_SRC M=`pwd` modules

Attachment: sys_rprobe.t
Description: Troff document

Attachment: loadtestrprobe.sh
Description: Bourne shell script

#include <linux/module.h>
#include <linux/kprobes.h>

static unsigned long entryaddr;
module_param(entryaddr, ulong, 0);
MODULE_PARM_DESC(addr,
		 "\nfunction entry address.\n");

int inst_test_erprobe2 (void)
{
	printk("test_eprobe2 entry handler\n");
	jprobe_return();
	return 0;
}


int rp_handler(struct rprobe_instance *ri, struct pt_regs *regs)
{
	printk("rprobe handler: p->addr=0x%p\n", ri->rp->kprobe->addr);
	printk("return code is stored in eax=0x%lx\n", regs->eax);
	return 0;
}
	
static struct jprobe jp = {
	.entry = (kprobe_opcode_t *) inst_test_erprobe2,
};


static struct rprobe rp = {
	.handler = rp_handler,
	.maxactive = 1,
	.nmissed = 0
};


static int init_testrp(void)
{
  if (entryaddr == 0 ) {
    printk("Need to input an function entry address as parameter.\n");
    return -EINVAL;
  }
  jp.kp.addr = (kprobe_opcode_t *) entryaddr;

  register_jrprobe(&jp, &rp);
  printk("exit probe init: instrumentation is enabled...\n");
  return 0;
}

static void cleanup_testrp(void)
{
  unregister_jprobe(&jp);
  printk("exit probe cleanup.\n");
}

module_init(init_testrp);
module_exit(cleanup_testrp);
MODULE_LICENSE("GPL");


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