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]

Re: [Fwd: Re: [PATCH] Return probe]


Hi Prasanna,

Here's the new return probe patch for Ananth's multiprobe take3. I addressed most of your concerns. There is no changes in the existing kprobe layer (include kprobe data structure, un/register_kprobe) except for a small change to the arch/i386/post_kprobe_handler()

Per Vara's request, I cc'ed this message to the SystemTap mailing list.

Hien.

Prasanna S Panchamukhi wrote:

Hien and Jim,

Please see my comments below.

Thanks
Prasanna

+
struct kprobe {
	struct hlist_node hlist;

@@ -68,6 +71,9 @@

/* copy of the original instruction */
struct arch_specific_insn ainsn;
+
+ /* point to kretprobe */
+ struct kretprobe *rp;
};
^^^^^^^^^^^^^^^^^^^^^^^^
can we avoid adding this to the kprobes structure? since if every feature requires adding one/two pointers, 5-10 features will make the kprobe structure very big. And even tough to maintain/enhance the code as well in future. We have long term advantages by avoiding changes to the existing code.



Done. No more fussing with kprobe structure.



+struct kretprobe_instance {
+ struct list_head list;
+ struct hlist_node hlist;
+ struct kretprobe *rp;
+ void *ret_addr;
+ void *stack_addr;
+};
+
^^^^^^^^^^^^^^^^
can this be made per-cpu datastructure
+int register_kretprobe(struct kretprobe *rp)
+{
+ int ret = 0;
+ static int kretprobe_init_setup = 0;
+ struct kretprobe_instance *inst;
+ struct kprobe *p;
+ int maxinst, i;
+
+ if (!arch_supports_kretprobes) {
+ return -ENOSYS;
+ }
+ if (kretprobe_init_setup == 0) {
+ init_kretprobes();
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can we do this in init_kprobe() ???
+ /* Create a kprobe obj to associcate with the kretprobe. If there is an
+ * existing probe at this addr, we will use that probe and free this.
+ */
+ p = kmalloc(sizeof(struct kprobe), GFP_KERNEL);
^^^^^^^^^^^^^^^^^
since we need to register entrypoint probe for every exit probe, this structure can be part of kretprobe structure itself.
+ /* todo: we need to deal with probe that has been registered */
^^^^^^^^^^^^^^^^^^^^^^^ we need not bother if the probe is registered or not,
we need to register our handler at the entrypoint. It is the multiprobes headache
to worry about. All that we know is after we register entrypoint kprobe control
is passed to our defined handler. Multiprobe should assist us direclty allowing us
to register the entrypoint handler along with exisiting probes at the same address.
+
+ if ((ret = _register_kprobe(p)) != 0) {
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
can we use multiprobe's interface without even modifiying it.


We need to think, if return probe feature can be implemented without
even changing the existing kprobe/multiprobe code and data structures.
If something is unavoidable, then we can modify the kprobes code.
Hien, please get in touch with me before you start making the changes,
may be you can ST me. I need to discuss about this with you.
On Wed, Apr 13, 2005 at 11:39:18AM -0700, Hien Nguyen wrote:


Hi Prasanna,

Please see my reply below.

Annath, this is the return probe for your multiprobe take3. Please take a look.

Thanks, Hien.

Prasanna S Panchamukhi wrote:



Hien, Jim,

I have just started reviewing your code and I have few questions:

1. Now multiprobe feature is avaliable, using this feature some code from kreturn register/unregister routine can it be removed? Can you modify your
design to build on multiprobe interface.





Yes, you are right. Attached is the return probe patch for Ananth's multiprobe take3 (I just happened to pick up Ananth patch to carry on the returnprobe works). I also attached Ananth multiprobe take3 patch here for your convenience.



2. I found that unregister_kprobe() is modified , can this be avoided?




No change in the unregister_kprobe in this version since it is now just a wrapper. I made a very simply modification to unregister_kprobe_single and unregister_aggr_kprobe to avoid code duplication.



3. You can modified kprobe_handler(), which can be part of external handler,
can it be moved out?





Yes, I moved this code out to the kprobe's pre_handler that associated with the kretprobe.



4. You have again modified resume_execution(), which can be moved out to external handler.




I moved this code out to the trampoline probe post_handle. No modification to resume_execution() now.



Thanks
Prasanna












--- linux-2.6.12-rc2-mm2-mprobe3/include/linux/kprobes.h	2005-04-12 17:08:56.000000000 -0700
+++ linux-2.6.12-rc2-mm2-mprobe3.rprobe/include/linux/kprobes.h	2005-04-14 17:57:11.919632147 -0700
@@ -34,12 +34,15 @@
 
 struct kprobe;
 struct pt_regs;
+struct kretprobe_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 (*kretprobe_handler_t) (struct kretprobe_instance *, struct pt_regs *);
+
 struct kprobe {
 	struct hlist_node hlist;
 
@@ -85,6 +88,55 @@
 	kprobe_opcode_t *entry;	/* probe handling code to jump to */
 };
 
+#ifdef arch_supports_kretprobes
+extern int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs);
+extern void trampoline_post_handler(struct kprobe *p, struct pt_regs *regs,
+							unsigned long flags);
+extern struct task_struct *arch_get_kprobe_task(void *ptr);
+#else 
+#define arch_supports_kretprobes		0
+static void kretprobe_trampoline(void)
+{
+}
+static int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
+{
+	return 0;
+} 
+static void trampoline_post_handler(struct kprobe *p, struct pt_regs *regs,
+							unsigned long flags)
+{
+}
+#define arch_get_kprobe_task(ptr) ((struct task_struct *)NULL)
+#endif
+/*
+ * Function-return probe -
+ * Note:
+ * User needs to provide a handler function, and initialize maxactive.
+ * maxactive - The maximum number of instances of the probed function that
+ * can be active concurrently. 
+ * nmissed - tracks the number of times the probed function's return was 
+ * ignored, due to maxactive being too low.
+ *
+ */
+struct kretprobe {
+	struct kprobe kp;
+	kretprobe_handler_t handler;
+	int maxactive;
+	int nmissed;
+	int num_ri_running;
+	int unregistering;
+	struct kretprobe_instance *instances;	/* allocated memory */
+	struct list_head free_instances;
+};
+
+struct kretprobe_instance {
+	struct list_head list;
+	struct hlist_node hlist;
+	struct kretprobe *rp;
+	void *ret_addr;
+	void *stack_addr;
+};
+
 #ifdef CONFIG_KPROBES
 /* Locks kprobe: irq must be disabled */
 void lock_kprobes(void);
@@ -100,10 +152,12 @@
 extern int arch_prepare_kprobe(struct kprobe *p);
 extern void arch_copy_kprobe(struct kprobe *p);
 extern void arch_remove_kprobe(struct kprobe *p);
+extern void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs);
 extern void show_registers(struct pt_regs *regs);
 
 /* Get the kprobe at this addr (if any).  Must have called lock_kprobes */
 struct kprobe *get_kprobe(void *addr);
+struct hlist_head * kretprobe_inst_table_head(struct task_struct *tsk);
 
 int register_kprobe(struct kprobe *p);
 void unregister_kprobe(struct kprobe *p);
@@ -113,6 +167,14 @@
 void unregister_jprobe(struct jprobe *p);
 void jprobe_return(void);
 
+int register_kretprobe(struct kretprobe *rp);
+void unregister_kretprobe(struct kretprobe *rp);
+
+struct kretprobe_instance *get_free_rp_inst(struct kretprobe *rp);
+struct kretprobe_instance *get_rp_inst(void *sara);
+void add_kretprobe_inst_to_hash(struct kretprobe_instance *ri); 
+void kprobe_flush_task(struct task_struct *tk);
+void recycle_kretprobe_instance(struct kretprobe_instance *ri);
 #else
 static inline int kprobe_running(void)
 {
@@ -135,5 +197,12 @@
 static inline void jprobe_return(void)
 {
 }
+static inline int register_kretprobe(struct kretprobe *rp)
+{
+	return -ENOSYS;
+}
+static inline void unregister_kretprobe(struct kretprobe *rp)
+{
+}
 #endif
 #endif				/* _LINUX_KPROBES_H */
--- linux-2.6.12-rc2-mm2-mprobe3/kernel/kprobes.c	2005-04-12 17:08:56.000000000 -0700
+++ linux-2.6.12-rc2-mm2-mprobe3.rprobe/kernel/kprobes.c	2005-04-14 18:53:43.527663234 -0700
@@ -42,6 +42,10 @@
 
 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 kretprobe_inst_table[RPROBE_INST_TABLE_SIZE];
+
 unsigned int kprobe_cpu = NR_CPUS;
 static DEFINE_SPINLOCK(kprobe_lock);
 static struct kprobe *curr_kprobe;
@@ -117,6 +121,107 @@
 	return 0;
 }
 
+struct kprobe trampoline_p = {
+		.addr = (kprobe_opcode_t *) &kretprobe_trampoline,
+		.pre_handler = trampoline_probe_handler,
+		.post_handler = trampoline_post_handler
+};
+
+struct kretprobe_instance * get_free_rp_inst(struct kretprobe *rp)
+{
+	if (list_empty(&rp->free_instances)) {
+		return NULL;
+	}
+	return (struct kretprobe_instance *) rp->free_instances.next;
+}	
+
+struct kretprobe_instance *get_rp_inst(void *sara)
+{
+	struct hlist_head *head;
+	struct hlist_node *node;
+	struct task_struct *tsk;
+	struct kretprobe_instance *ri;
+
+	tsk = arch_get_kprobe_task(sara);
+	head = &kretprobe_inst_table[hash_ptr(tsk, RPROBE_HASH_BITS)];
+	hlist_for_each_entry(ri, node, head, hlist) {
+		if (ri->stack_addr == sara)
+			return ri;
+	}
+	return NULL;
+}
+
+void add_kretprobe_inst_to_hash(struct kretprobe_instance *ri)
+{
+	struct task_struct *tsk;
+	tsk = arch_get_kprobe_task(ri->stack_addr);	
+	hlist_add_head(&ri->hlist, &kretprobe_inst_table[hash_ptr(tsk, RPROBE_HASH_BITS)]);
+}
+
+void recycle_kretprobe_instance(struct kretprobe_instance *ri)
+{
+	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 onto free list */
+		list_add(&ri->list, &ri->rp->free_instances);
+	}
+}
+
+struct hlist_head * kretprobe_inst_table_head(struct task_struct *tsk)
+{
+	return &kretprobe_inst_table[hash_ptr(tsk, RPROBE_HASH_BITS)];
+}
+
+/*
+ * This function is called from do_exit or do_execv when task tk's stack is
+ * about to be recycled. Recycle any function-return probe instances 
+ * associated with this task. These represent probed functions that have 
+ * been called but may never return.
+ */
+void kprobe_flush_task(struct task_struct *tk)
+{
+	unsigned long flags = 0;
+	struct kretprobe_instance *ri;
+	struct task_struct *tsk;
+	struct hlist_head *head;
+	struct hlist_node *node;
+
+	if (!arch_supports_kretprobes) {
+		return;
+	}
+	spin_lock_irqsave(&kprobe_lock, flags);
+	head = &kretprobe_inst_table[hash_ptr(tk, RPROBE_HASH_BITS)];
+	hlist_for_each_entry(ri, node, head, hlist) {
+		tsk = arch_get_kprobe_task(ri->stack_addr);
+		if (tsk == tk) {
+			/* Put the original return address back into stack */
+			*((unsigned long *)(ri->stack_addr)) = (unsigned long) ri->ret_addr;
+			hlist_del_rcu(&ri->hlist);
+			recycle_kretprobe_instance(ri);
+		}
+	}
+	spin_unlock_irqrestore(&kprobe_lock, flags);	
+}
+
+/*
+ * This kprobe pre_handler is registered with every kretprobe. When probe hits it
+ * will set up the return probe.
+ */
+int pre_handler_kretprobe(struct kprobe *p, struct pt_regs *regs)
+{
+	struct kretprobe *rp = container_of(p, struct kretprobe, kp);
+
+	/*TODO: consider to only swap the RA after the last pre_handler fired */
+	arch_prepare_kretprobe(rp, regs);
+	return 0;
+}
+
 static int register_kprobe_single(struct kprobe *p)
 {
 	int ret = 0;
@@ -293,6 +398,102 @@
 	unregister_kprobe(&jp->kp);
 }
 
+int register_kretprobe(struct kretprobe *rp)
+{
+	int ret = 0;
+	struct kretprobe_instance *inst;
+	int maxinst, i;
+	
+	if (!arch_supports_kretprobes) {
+		return -ENOSYS;
+	}
+	
+	rp->kp.pre_handler = pre_handler_kretprobe;
+	
+	/* Pre-allocate memory for max kretprobe 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 kretprobe_instance), 
+					GFP_KERNEL);
+	if (rp->instances == NULL) {
+		return -ENOMEM;
+	}
+	
+	INIT_LIST_HEAD(&rp->free_instances);
+	/* Put all kretprobe_instance objects 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;
+
+	/* Establish function entry probe point */
+	if ((ret = register_kprobe(&rp->kp)) != 0) {
+		kfree(rp->instances);
+	}
+	return ret;
+}
+
+void remove_kprobe(struct kprobe *kp, unsigned long flags)
+{
+	spin_unlock_irqrestore(&kprobe_lock, flags);
+	arch_remove_kprobe(kp);
+	spin_lock_irqsave(&kprobe_lock, flags);
+	*kp->addr = kp->opcode;
+	hlist_del(&kp->hlist);
+	flush_icache_range((unsigned long) kp->addr,
+			   (unsigned long) kp->addr + sizeof(kprobe_opcode_t));
+}
+
+void unregister_kretprobe(struct kretprobe *rp)
+{
+	unsigned long flags;
+	struct kretprobe *rp_tmp;
+	struct kprobe *old_p;
+
+	rp_tmp = kmalloc(sizeof(struct kretprobe), GFP_KERNEL);
+	BUG_ON(rp_tmp == NULL);
+	
+	spin_lock_irqsave(&kprobe_lock, flags);
+	old_p = get_kprobe(rp->kp.addr);
+	if (old_p && (old_p->pre_handler == aggr_pre_handler)) {
+		list_del(&rp->kp.list);
+		if (list_empty(&old_p->list)) {
+			remove_kprobe(old_p, flags);
+			kfree(old_p);
+		} 
+	} else if (old_p == &rp->kp) {
+		remove_kprobe(&rp->kp, flags);
+	}
+		
+	if (rp->num_ri_running != 0) {
+		int i;
+		struct kretprobe_instance *ri;
+		/* Make a copy of kretprobe so we can relinquish the 
+		 * user's original.
+		 */
+		memcpy(rp_tmp, rp, sizeof(struct kretprobe));
+		rp_tmp->unregistering = 1;
+		for (i = 0 ; i < rp->maxactive; i++) {
+			ri = rp->instances + i;
+			ri->rp = rp_tmp;
+		}
+	} else {
+		kfree(rp->instances);
+		kfree(rp_tmp);
+	}
+	spin_unlock_irqrestore(&kprobe_lock, flags);
+}	
+
 static int __init init_kprobes(void)
 {
 	int i, err = 0;
@@ -300,9 +501,13 @@
 	/* FIXME allocate the probe table, currently defined statically */
 	/* initialize all list heads */
 	for (i = 0; i < KPROBE_TABLE_SIZE; i++)
-		INIT_HLIST_HEAD(&kprobe_table[i]);
-
+		INIT_HLIST_HEAD(&kprobe_table[i]);	
+	for (i = 0; i < RPROBE_INST_TABLE_SIZE; i++)
+		INIT_HLIST_HEAD(&kretprobe_inst_table[i]);
+		
 	err = register_die_notifier(&kprobe_exceptions_nb);
+	/* Register the trampoline probe for return probe */
+	register_kprobe(&trampoline_p);
 	return err;
 }
 
@@ -313,3 +518,5 @@
 EXPORT_SYMBOL_GPL(register_jprobe);
 EXPORT_SYMBOL_GPL(unregister_jprobe);
 EXPORT_SYMBOL_GPL(jprobe_return);
+EXPORT_SYMBOL_GPL(register_kretprobe);
+EXPORT_SYMBOL_GPL(unregister_kretprobe);
--- linux-2.6.12-rc2-mm2-mprobe3/arch/i386/kernel/kprobes.c	2005-04-11 13:54:37.000000000 -0700
+++ linux-2.6.12-rc2-mm2-mprobe3.rprobe/arch/i386/kernel/kprobes.c	2005-04-14 18:43:00.975272433 -0700
@@ -60,6 +60,11 @@
 	return 0;
 }
 
+struct task_struct  *arch_get_kprobe_task(void *ptr)
+{
+	return ((struct thread_info *) (((unsigned long) ptr) & (~(THREAD_SIZE -1))))->task;
+}
+
 int arch_prepare_kprobe(struct kprobe *p)
 {
 	return 0;
@@ -91,6 +96,41 @@
 		regs->eip = (unsigned long)&p->ainsn.insn;
 }
 
+void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
+{
+	unsigned long *sara = (unsigned long *)&regs->esp;
+	struct kretprobe_instance *ri;
+	static void *orig_ret_addr;
+
+	/*
+	 * Save the return address when the return probe hits
+	 * the first time, and use it to populate the (krprobe
+	 * instance)->ret_addr for subsequent return probes at
+	 * the same addrress since stack address would have 
+	 * the kretprobe_trampoline by then.
+	 */
+	if (((void*) *sara) != kretprobe_trampoline)
+		orig_ret_addr = (void*) *sara;
+		
+	if ((ri = get_free_rp_inst(rp)) != NULL) {
+		INIT_HLIST_NODE(&ri->hlist);
+		ri->rp = rp;
+		ri->stack_addr = sara;
+		ri->ret_addr = orig_ret_addr;
+		add_kretprobe_inst_to_hash(ri);
+		/* Replace the return addr with trampoline addr */
+		*sara = (unsigned long) &kretprobe_trampoline;
+		/* 
+		 * Remove obj in free list - 
+		 * will add it back when probed function returns 
+		 */
+		list_del(&ri->list);
+		rp->num_ri_running++;
+	} else {
+		rp->nmissed++;
+	}
+}
+
 /*
  * Interrupts are disabled on entry as trap3 is an interrupt gate and they
  * remain disabled thorough out this function.
@@ -184,6 +224,45 @@
 }
 
 /*
+ * Called when we hit the probe point at kretprobe_trampoline
+ */  
+int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
+{
+	struct task_struct *tsk;
+	struct kretprobe_instance *ri;
+	struct hlist_head *head;
+	struct hlist_node *node;
+	unsigned long *sara = ((unsigned long *) &regs->esp) - 1;
+	
+	tsk = arch_get_kprobe_task(sara);
+	head = kretprobe_inst_table_head(tsk);
+
+	hlist_for_each_entry(ri, node, head, hlist) {
+		if (ri->stack_addr == sara) {
+			if (ri->rp && !ri->rp->unregistering) {
+				ri->rp->handler(ri, regs);
+			}
+		}
+	}
+	return 0;
+}
+
+void trampoline_post_handler(struct kprobe *p, struct pt_regs *regs, 
+						unsigned long flags)
+{
+	struct kretprobe_instance *ri;
+	/* RA already popped */
+	unsigned long *sara = ((unsigned long *)&regs->esp) - 1;
+	
+	while ((ri = get_rp_inst(sara))) {
+		regs->eip = (unsigned long)ri->ret_addr;
+		hlist_del(&ri->hlist);
+		recycle_kretprobe_instance(ri);
+	}
+	regs->eflags &= ~TF_MASK;
+}
+
+/*
  * Called after single-stepping.  p->addr is the address of the
  * instruction whose first byte has been replaced by the "int 3"
  * instruction.  To avoid the SMP problems that can occur when we
@@ -265,8 +344,9 @@
 
 	if (current_kprobe->post_handler)
 		current_kprobe->post_handler(current_kprobe, regs, 0);
-
-	resume_execution(current_kprobe, regs);
+		
+	if (current_kprobe->post_handler != trampoline_post_handler)
+		resume_execution(current_kprobe, regs);
 	regs->eflags |= kprobe_saved_eflags;
 
 	unlock_kprobes();
--- linux-2.6.12-rc2-mm2-mprobe3/arch/i386/kernel/entry.S	2005-04-11 13:54:37.000000000 -0700
+++ linux-2.6.12-rc2-mm2-mprobe3.rprobe/arch/i386/kernel/entry.S	2005-04-12 16:57:09.000000000 -0700
@@ -135,6 +135,16 @@
 	.long 2b,4b;	\
 .previous
 
+#ifdef CONFIG_KPROBES
+/*
+ * For function-return probes, init_kretprobes() establishes a probepoint
+ * here. When a retprobed function returns, this probe is hit and
+ * trampoline_probe_handler() runs, calling the kretprobe's handler.
+ */
+ENTRY(kretprobe_trampoline)
+        nop
+/* NOT REACHED */
+#endif
 
 ENTRY(ret_from_fork)
 	pushl %eax
--- linux-2.6.12-rc2-mm2-mprobe3/arch/i386/kernel/process.c	2005-04-11 13:54:37.000000000 -0700
+++ linux-2.6.12-rc2-mm2-mprobe3.rprobe/arch/i386/kernel/process.c	2005-04-12 16:03:51.000000000 -0700
@@ -39,6 +39,7 @@
 #include <linux/kallsyms.h>
 #include <linux/ptrace.h>
 #include <linux/random.h>
+#include <linux/kprobes.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -371,7 +372,14 @@
 {
 	struct task_struct *tsk = current;
 	struct thread_struct *t = &tsk->thread;
-
+#ifdef CONFIG_KPROBES
+	/* 
+	 * Remove function-return probe instances associated with this task
+	 * and put them back on the free list. Do not insert an exit probe for
+	 * this function, it will be disabled by kprobe_flush_task if you do. 
+	 */
+	kprobe_flush_task(tsk);
+#endif
 	/* The process may have allocated an io port bitmap... nuke it. */
 	if (unlikely(NULL != t->io_bitmap_ptr)) {
 		int cpu = get_cpu();
@@ -395,7 +403,14 @@
 void flush_thread(void)
 {
 	struct task_struct *tsk = current;
-
+#ifdef CONFIG_KPROBES
+	/* 
+	 * Remove function-return probe instances associated with this task
+	 * and put them back on the free list. Do not insert an exit probe for
+	 * this function, it will be disabled by kprobe_flush_task if you do. 
+	 */
+	kprobe_flush_task(tsk);
+#endif
 	memset(tsk->thread.debugreg, 0, sizeof(unsigned long)*8);
 	memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array));	
 	/*
--- linux-2.6.12-rc2-mm2-mprobe3/include/asm-i386/kprobes.h	2005-03-01 23:38:12.000000000 -0800
+++ linux-2.6.12-rc2-mm2-mprobe3.rprobe/include/asm-i386/kprobes.h	2005-04-12 16:57:12.000000000 -0700
@@ -39,6 +39,9 @@
 	: (((unsigned long)current_thread_info()) + THREAD_SIZE - (ADDR)))
 
 #define JPROBE_ENTRY(pentry)	(kprobe_opcode_t *)pentry
+#define arch_supports_kretprobes 1
+
+asmlinkage void kretprobe_trampoline(void) __asm__("kretprobe_trampoline");
 
 /* Architecture specific copy of original instruction*/
 struct arch_specific_insn {

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