kprobes_stack.patch
Jim Keniston
jkenisto@us.ibm.com
Wed May 11 17:45:00 GMT 2005
Per an AR from the 4/20/05 meeting, here is a patch that runs kprobes'
pre_handlers on a separate kprobes_stack. This code is i386-specific
and is based on the CONFIG_4KSTACKS stack-switch code in do_IRQ().
This patch is against Linux 2.6.12-rc4 + Hien's i386 return-probes
patch. (2.6.12-rc4 contains Ananth's multi-probes patch.)
Effect on Return Probes
kretprobe handlers will run on the kprobes stack because they are
called by trampoline_p.pre_handler.
Effect on Jprobes
jprobe handlers will not run on the kprobes stack. (The whole point
of jprobes is that the handler is presented with exactly the stack
that is presented to the probed function.)
Testing
I have tested with a combination of kprobes, jprobes, and return
probes, including a probe set in an interrupt handler. I have not
done severe stress testing or SMP testing. I'll post this patch and
accompanying test modules to CVS.
I haven't tested this with REGPARM configured, but the register usage
is such that it should work with or without REGPARM.
Limitations/TODO
A similar function could be copied-and-pasted for post_handlers.
I thought about trying to support both pre_ and post_handlers with
a single function, but they have different signatures.
I haven't figured out kprobes fault handling well enough to understand
the implications of this separate stack.
Once Ananth's SMP scalability patch is factored in, this kprobes_stack
patch will need to be adjusted to use per-CPU stacks, as in the
CONFIG_4KSTACKS code.
Comments/advice welcome.
Jim
-------------- next part --------------
--- orig-2.6.11/arch/i386/kernel/kprobes.c 2005-05-11 10:37:40.000000000 -0700
+++ linux-2.6.11/arch/i386/kernel/kprobes.c 2005-05-11 09:11:14.000000000 -0700
@@ -48,6 +48,12 @@
static kprobe_opcode_t jprobes_stack[MAX_STACK_SIZE];
void jprobe_return_end(void);
+/* special stack for running kprobes handlers */
+static char kprobes_stack[THREAD_SIZE]
+ __attribute__((__aligned__(THREAD_SIZE)));
+static struct thread_info *kprobes_tinfo = (struct thread_info*) kprobes_stack;
+static char *kprobes_esp = kprobes_stack + THREAD_SIZE;
+
/*
* returns non-zero if opcode modifies the interrupt flag.
*/
@@ -129,6 +135,46 @@
}
/*
+ * Switch to kprobes_stack, call handler(kp, regs), and switch back.
+ * Called with kprobe_lock held and interrupts disabled, so we don't have
+ * to worry about subsequent interactions with the CONFIG_4KSTACKS code
+ * in do_IRQ(). Based on the CONFIG_4KSTACKS stack-switch code.
+ */
+static int run_pre_handler_on_kprobes_stack(kprobe_pre_handler_t handler,
+ struct kprobe *kp, struct pt_regs *regs)
+{
+ struct thread_info *cur_tinfo = current_thread_info();
+
+ if (cur_tinfo != kprobes_tinfo) {
+ int result;
+ kprobes_tinfo->task = cur_tinfo->task;
+ kprobes_tinfo->previous_esp = current_stack_pointer;
+ /*
+ * %ebx = kprobes_esp
+ * swap current %esp and %ebx
+ * push regs, kp
+ * call handler
+ * result = %eax
+ * restore %esp from %ebx
+ */
+ asm volatile(
+ " xchgl %%ebx,%%esp \n"
+ " pushl %%edx \n"
+ " pushl %%eax \n"
+ " call *%%ecx \n"
+ " movl %%ebx,%%esp \n"
+ : "=a" (result)
+ : "d" (regs), "a" (kp), "c" (handler),
+ "b" (kprobes_esp)
+ : "memory", "cc"
+ );
+ return result;
+ } else {
+ return handler(kp, regs);
+ }
+}
+
+/*
* Interrupts are disabled on entry as trap3 is an interrupt gate and they
* remain disabled thorough out this function.
*/
@@ -206,7 +252,8 @@
if (is_IF_modifier(p->opcode))
kprobe_saved_eflags &= ~IF_MASK;
- if (p->pre_handler && p->pre_handler(p, regs))
+ if (p->pre_handler
+ && run_pre_handler_on_kprobes_stack(p->pre_handler, p, regs))
/* handler has already set things up, so skip ss setup */
return 1;
More information about the Systemtap
mailing list