This is the mail archive of the
systemtap@sourceware.org
mailing list for the systemtap project.
arm64 kprobes/systemtap support progress
- From: William Cohen <wcohen at redhat dot com>
- To: systemtap at sourceware dot org
- Cc: "dave. >> Dave Long" <dave dot long at linaro dot org>
- Date: Sun, 02 Nov 2014 16:02:46 -0500
- Subject: arm64 kprobes/systemtap support progress
- Authentication-results: sourceware.org; auth=none
Hi All,
Dave Long has been working on getting arm64 kprobes support merged into the upstream kernels. The kprobes64 branch of the git tree at
https://git.linaro.org/people/dave.long/linux.git
I have been using systemtap to exercise the arm64 kprobes support and flush out any problems with them. The attached kernel patch fixes a couple problems observed in the arm64 kprobes:
- irq needs to be masked during single step
- the address to continue execution should be statically computed and not change
With the attached patch and recent correction to the systemtap runtime time.c for arm64. periodic.stp run on arm64:
# ~/systemtap_write/install/bin/stap --all-modules periodic.stp
#monitoring timer periods (press control-c for output)
^C#type function period(us) count
kernel 0xfffffdfffcaf2c50 [stap_41b9ddd4f103a617201d73e05 10008 1230
kernel 0xfffffdfffcaf3280 [stap_41b9ddd4f103a617201d73e05 20032 614
process xfsaild/dm-0(404) 50000 246
process rcu_sched(7) 159873 77
work_q phy_state_machine 1000011 11
work_q vmstat_update 1000009 11
work_q vmstat_update 1000919 11
work_q vmstat_update 1000010 11
work_q vmstat_update 1000018 11
work_q vmstat_update 1352511 8
work_q vmstat_update 1512865 7
kernel br_hello_timer_expired+0x0/0x90 [bridge] 1999999 5
kernel dev_watchdog+0x0/0x280 [kernel] 4999999 2
kernel 0xfffffdfffcaf1b40 [stap_41b9ddd4f103a617201d73e05 10021293 1
kernel 0xfffffdfffcaf1b40 [stap_41b9ddd4f103a617201d73e05 10021056 1
work_q bdi_writeback_workfn 5010523 1
kernel 0xfffffdfffcaf1b40 [stap_41b9ddd4f103a617201d73e05 10021037 1
work_q xfs_reclaim_worker 5010503 1
kernel 0xfffffdfffcaf1b40 [stap_41b9ddd4f103a617201d73e05 10011035 1
work_q vmstat_update 5941334 1
kernel 0xfffffdfffcaf1b40 [stap_41b9ddd4f103a617201d73e05 10022237 1
work_q vmstat_update 5992305 1
kernel 0xfffffdfffcaf1b40 [stap_41b9ddd4f103a617201d73e05 10023836 1
kernel writeout_period+0x0/0x9c [kernel] 5992292 1
kernel 0xfffffdfffcaf1b40 [stap_41b9ddd4f103a617201d73e05 10021077 1
kernel 0xfffffdfffcaf1b40 [stap_41b9ddd4f103a617201d73e05 10021999 1
-Will
diff -up arch/arm64/kernel/kprobes.c.irq arch/arm64/kernel/kprobes.c
--- arch/arm64/kernel/kprobes.c.irq 2014-10-29 22:01:35.234174228 -0400
+++ arch/arm64/kernel/kprobes.c 2014-10-30 16:10:16.165804247 -0400
@@ -23,6 +23,7 @@
#include <linux/stop_machine.h>
#include <linux/stringify.h>
#include <asm/traps.h>
+#include <asm/ptrace.h>
#include <asm/cacheflush.h>
#include <asm/debug-monitors.h>
#include <asm/system_misc.h>
@@ -47,12 +48,23 @@ static void __kprobes arch_prepare_ss_sl
flush_icache_range((uintptr_t) (p->ainsn.insn),
(uintptr_t) (p->ainsn.insn) + MAX_INSN_SIZE);
+
+ /*
+ * Needs restoring of return address after stepping xol.
+ */
+ p->ainsn.restore.addr = (unsigned long) p->addr +
+ sizeof(kprobe_opcode_t);
+ p->ainsn.restore.type = RESTORE_PC;
}
static void __kprobes arch_prepare_simulate(struct kprobe *p)
{
if (p->ainsn.prepare)
p->ainsn.prepare(p, &p->ainsn);
+
+ /* This instructions is not executed xol. No need to adjust the PC */
+ p->ainsn.restore.addr = 0;
+ p->ainsn.restore.type = NO_RESTORE;
}
static void __kprobes arch_simulate_insn(struct kprobe *p, struct pt_regs *regs)
@@ -167,9 +179,9 @@ spsr_set_debug_flag(struct pt_regs *regs
unsigned long spsr = regs->pstate;
if (mask)
- spsr |= (1 << 9);
+ spsr |= PSR_D_BIT;
else
- spsr &= ~(1 << 9);
+ spsr &= ~PSR_D_BIT;
regs->pstate = spsr;
}
@@ -186,7 +198,7 @@ static void __kprobes kprobes_save_local
{
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
- kcb->saved_irqflag = (interrupts_enabled(regs)) ? 0 : 1;
+ kcb->saved_irqflag = regs->pstate;
regs->pstate |= PSR_I_BIT;
}
@@ -194,10 +206,10 @@ static void __kprobes kprobes_restore_lo
{
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
- if (kcb->saved_irqflag)
- regs->pstate &= ~PSR_I_BIT;
- else
+ if (kcb->saved_irqflag & PSR_I_BIT)
regs->pstate |= PSR_I_BIT;
+ else
+ regs->pstate &= ~PSR_I_BIT;
}
static void __kprobes
@@ -243,19 +255,13 @@ static void __kprobes setup_singlestep(s
/* prepare for single stepping */
slot = (unsigned long)p->ainsn.insn;
- /*
- * Needs restoring of return address after stepping xol.
- */
- p->ainsn.restore.addr = instruction_pointer(regs) +
- sizeof(kprobe_opcode_t);
-
- p->ainsn.restore.type = RESTORE_PC;
-
set_ss_context(kcb, slot); /* mark pending ss */
if (kcb->kprobe_status == KPROBE_REENTER)
spsr_set_debug_flag(regs, 0);
+ /* IRQs and single stepping do not mix well. */
+ local_irq_disable();
kernel_enable_single_step(regs);
instruction_pointer(regs) = slot;
} else {
@@ -304,8 +310,7 @@ post_kprobe_handler(struct kprobe_ctlblk
/* return addr restore if non-branching insn */
if (cur->ainsn.restore.type == RESTORE_PC) {
instruction_pointer(regs) = cur->ainsn.restore.addr;
- cur->ainsn.restore.addr = 0;
- cur->ainsn.restore.type = NO_RESTORE;
+ if (!instruction_pointer(regs)) BUG();
}
/* restore back original saved kprobe variables and continue */
@@ -343,6 +348,7 @@ int __kprobes kprobe_fault_handler(struc
* normal page fault.
*/
instruction_pointer(regs) = (unsigned long)cur->addr;
+ if (!instruction_pointer(regs)) BUG();
if (kcb->kprobe_status == KPROBE_REENTER)
restore_previous_kprobe(kcb);
else