This is the mail archive of the
systemtap@sourceware.org
mailing list for the systemtap project.
Re: [RFC PATCH 2/3] Djprobe improvement patches (Re: Dynamic djprobe)
- From: Masami Hiramatsu <hiramatu at sdl dot hitachi dot co dot jp>
- To: Mathieu Desnoyers <compudj at krystal dot dyndns dot org>
- Cc: systemtap at sources dot redhat dot com,"Keshavamurthy, Anil S" <anil dot s dot keshavamurthy at intel dot com>,Roland McGrath <roland at redhat dot com>,Richard J Moore <richardj_moore at uk dot ibm dot com>, Andi Kleen <ak at muc dot de>,michel dot dagenais at polymtl dot ca, "Frank Ch. Eigler" <fche at redhat dot com>,Karim Yaghmour <karim at opersys dot com>,Satoshi Oshima <soshima at redhat dot com>, Hideo Aoki <haoki at redhat dot com>,Yumiko Sugita <sugita at sdl dot hitachi dot co dot jp>
- Date: Fri, 05 Aug 2005 02:31:50 +0900
- Subject: Re: [RFC PATCH 2/3] Djprobe improvement patches (Re: Dynamic djprobe)
- References: <42EA740A.10601@sdl.hitachi.co.jp> <42EFA85A.6010901@sdl.hitachi.co.jp> <20050804034642.GB20153@Krystal>
Hi, Mathieu
Mathieu Desnoyers wrote:
If the stack inspection becomes considered too costy (push/pop at each interrupt
entry/exit) or too uncertain (looking at all the stack's data),
I developed a patch to check in the entire stack's data. It is attached
in this mail.
I would suggest
a different approach for this interruption problem :
1 - Replace the first byte of the segment you want to modify with a int3
2 - Wait until each other CPU has reach a point where we know they are not in
interrupt context anymore (interrupt or softirq). This could be done by
spawning a kernel thread on each CPU which would inform us when it runs. If
there is no kernel preemption, then we are sure there is no interruption
having a wrong EIP saved on its stack.
3 - Write the jmp instruction.
In a context where there is no preemption, this should work.
It seems a good idea! Can I use a workqueue instead of a kernel thread?
Thanks.
Best regards,
--
Masami HIRAMATSU
2nd Research Dept.
Hitachi, Ltd., Systems Development Laboratory
E-mail: hiramatu@sdl.hitachi.co.jp
diff -Narup linux-2.6.12-djprobe.2/arch/i386/kernel/kprobes.c linux-2.6.12-djprobe.3/arch/i386/kernel/kprobes.c
--- linux-2.6.12-djprobe.2/arch/i386/kernel/kprobes.c 2005-08-01 22:00:17.000000000 +0900
+++ linux-2.6.12-djprobe.3/arch/i386/kernel/kprobes.c 2005-08-03 01:26:46.000000000 +0900
@@ -472,6 +472,26 @@ int arch_prepare_djprobe_instance(struct
return 0;
}
+int arch_find_region_from_stack(unsigned long saddr, unsigned long eaddr)
+{
+ unsigned long * esp, *p;
+ struct pt_regs *pr_tmp;
+ esp = (unsigned long *)current_stack_pointer;
+ p = current_thread_info() + (THREAD_SIZE - 1)
+ - sizeof(struct pt_regs);
+ for (;p > esp; p--) {
+ pr_tmp = (struct pt_regs *)p;
+ if (pr_tmp->xcs == __KERNEL_CS &&
+ pr_tmp->xds == __KERNEL_DS) {
+ if (saddr < pr_tmp->eip &&
+ pr_tmp->eip <= eaddr ){
+ return 1; //found
+ }
+ }
+ }
+ return 0;//not found
+}
+
/* Insert "jmp" instruction into the probing point. */
static void arch_install_djprobe_instance(struct djprobe_instance *djpi)
{
@@ -497,7 +517,7 @@ int djprobe_bypass_handler(struct kprobe
kprobe_opcode_t *stub = djpi->stub.insn;
int cpu = smp_processor_id();
- if (!DJPI_CHECKED(djpi)) {
+ if (!DJPI_CHECKED(djpi) && check_safety_djprobe_instance(djpi)) {
cpu_set(cpu, djpi->checked_cpus); /* check this cpu */
if (DJPI_CHECKED(djpi)) { /* all cpus are checked */
diff -Narup linux-2.6.12-djprobe.2/include/linux/kprobes.h linux-2.6.12-djprobe.3/include/linux/kprobes.h
--- linux-2.6.12-djprobe.2/include/linux/kprobes.h 2005-08-02 20:29:44.000000000 +0900
+++ linux-2.6.12-djprobe.3/include/linux/kprobes.h 2005-08-03 01:29:19.000000000 +0900
@@ -155,7 +155,9 @@ extern int arch_prepare_djprobe_instance
extern int djprobe_bypass_handler(struct kprobe * kp, struct pt_regs * regs);
extern void arch_uninstall_djprobe_instance(struct djprobe_instance *djpi);
extern void schdule_release_djprobe_instance(void);
-
+extern int check_safety_djprobe_instance(struct djprobe_instance *djpi);
+extern int arch_find_region_from_stack(unsigned long saddr, unsigned long eaddr);
+
int register_djprobe(struct djprobe *p);
void unregister_djprobe(struct djprobe *p);
#else
diff -Narup linux-2.6.12-djprobe.2/kernel/kprobes.c linux-2.6.12-djprobe.3/kernel/kprobes.c
--- linux-2.6.12-djprobe.2/kernel/kprobes.c 2005-08-01 22:00:17.000000000 +0900
+++ linux-2.6.12-djprobe.3/kernel/kprobes.c 2005-08-03 01:32:01.000000000 +0900
@@ -269,6 +269,19 @@ static DEFINE_SPINLOCK(djprobe_lock);
static LIST_HEAD(djprobe_list);
static int nr_instances = 0;
+/* safety check routine */
+int check_safety_djprobe_instance(struct djprobe_instance *djpi)
+{
+ int sp;
+ preempt_disable();
+ if(arch_find_region_from_stack((unsigned long)djpi->kp.addr,
+ (unsigned long)djpi->kp.addr
+ + djpi->stub.size))
+ return 0; /*we find insertion address in the stack*/
+ preempt_enable();
+ return 1;
+}
+
static void work_free_djprobe_instances(void *data)
{
struct list_head *pos;