summaryrefslogtreecommitdiff
path: root/sys/arch
diff options
context:
space:
mode:
authorMartin Pieuchot <mpi@cvs.openbsd.org>2017-02-06 09:13:42 +0000
committerMartin Pieuchot <mpi@cvs.openbsd.org>2017-02-06 09:13:42 +0000
commit2f5d8ba197d7f31af3b8a776cd44f7de20bd17aa (patch)
tree4c7465f43f75cba9ebaef0336e2463ebaa4f5187 /sys/arch
parentf3b95d53b4db45d7362b2c3810a23024e7b1983f (diff)
Implement Dynamic Profiling, a ddb(4) based & gprof compatible kernel
profiling framework, for i386. Code patching is used to enable probes when entering functions. The probes will call a mcount()-like function to match the behavior of a GPROF kernel. A new sysctl knob, ddb.profile, need to be set to 1 in securelevel 0 to be able to use this feature. ok jasper@, guenther@, mlarkin@
Diffstat (limited to 'sys/arch')
-rw-r--r--sys/arch/amd64/amd64/db_trace.c6
-rw-r--r--sys/arch/i386/i386/db_trace.c21
-rw-r--r--sys/arch/i386/i386/locore.s72
-rw-r--r--sys/arch/i386/include/cpu.h4
-rw-r--r--sys/arch/i386/include/cpufunc.h18
-rw-r--r--sys/arch/i386/include/db_machdep.h5
6 files changed, 113 insertions, 13 deletions
diff --git a/sys/arch/amd64/amd64/db_trace.c b/sys/arch/amd64/amd64/db_trace.c
index 3615b2c84df..a24b8ba0371 100644
--- a/sys/arch/amd64/amd64/db_trace.c
+++ b/sys/arch/amd64/amd64/db_trace.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: db_trace.c,v 1.24 2017/01/24 00:58:55 mpi Exp $ */
+/* $OpenBSD: db_trace.c,v 1.25 2017/02/06 09:13:41 mpi Exp $ */
/* $NetBSD: db_trace.c,v 1.1 2003/04/26 18:39:27 fvdl Exp $ */
/*
@@ -325,9 +325,9 @@ db_stack_trace_print(db_expr_t addr, boolean_t have_addr, db_expr_t count,
vaddr_t
db_get_pc(struct trapframe *tf)
{
- struct callframe *cf = (struct callframe *)(tf->tf_rsp - 8);
+ struct callframe *cf = (struct callframe *)(tf->tf_rsp - sizeof(long));
- return db_get_value((db_addr_t)&cf->f_retaddr, 8, 0);
+ return db_get_value((db_addr_t)&cf->f_retaddr, sizeof(long), 0);
}
vaddr_t
diff --git a/sys/arch/i386/i386/db_trace.c b/sys/arch/i386/i386/db_trace.c
index 0a49cdbae50..4ef17ce2333 100644
--- a/sys/arch/i386/i386/db_trace.c
+++ b/sys/arch/i386/i386/db_trace.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: db_trace.c,v 1.23 2017/01/24 00:58:55 mpi Exp $ */
+/* $OpenBSD: db_trace.c,v 1.24 2017/02/06 09:13:41 mpi Exp $ */
/* $NetBSD: db_trace.c,v 1.18 1996/05/03 19:42:01 christos Exp $ */
/*
@@ -319,3 +319,22 @@ db_stack_trace_print(db_expr_t addr, boolean_t have_addr, db_expr_t count,
(*pr)(":\n");
}
}
+
+vaddr_t
+db_get_pc(struct trapframe *tf)
+{
+ struct callframe *cf;
+
+ if (KERNELMODE(tf->tf_cs, tf->tf_eflags))
+ cf = (struct callframe *)((long)&tf->tf_esp - sizeof(long));
+ else
+ cf = (struct callframe *)(tf->tf_esp - sizeof(long));
+
+ return db_get_value((db_addr_t)&cf->f_retaddr, sizeof(long), 0);
+}
+
+vaddr_t
+db_get_probe_addr(struct trapframe *tf)
+{
+ return tf->tf_eip - BKPT_SIZE;
+}
diff --git a/sys/arch/i386/i386/locore.s b/sys/arch/i386/i386/locore.s
index 82e4a1df64a..9969b8e782c 100644
--- a/sys/arch/i386/i386/locore.s
+++ b/sys/arch/i386/i386/locore.s
@@ -1,4 +1,4 @@
-/* $OpenBSD: locore.s,v 1.171 2016/10/13 09:01:04 mlarkin Exp $ */
+/* $OpenBSD: locore.s,v 1.172 2017/02/06 09:13:41 mpi Exp $ */
/* $NetBSD: locore.s,v 1.145 1996/05/03 19:41:19 christos Exp $ */
/*-
@@ -133,7 +133,8 @@
pushl %fs ; \
movl $GSEL(GCPU_SEL, SEL_KPL),%eax ; \
movw %ax,%fs
-#define INTRFASTEXIT \
+
+#define INTR_RESTORE_ALL \
popl %fs ; \
popl %gs ; \
popl %es ; \
@@ -144,10 +145,14 @@
popl %ebx ; \
popl %edx ; \
popl %ecx ; \
- popl %eax ; \
+ popl %eax
+
+#define INTRFASTEXIT \
+ INTR_RESTORE_ALL ;\
addl $8,%esp ; \
iret
+#define INTR_FAKE_TRAP 0xbadabada
/*
* PTmap is recursive pagemap at top of virtual address space.
@@ -1445,6 +1450,24 @@ calltrap:
#ifdef DIAGNOSTIC
movl CPL,%ebx
#endif /* DIAGNOSTIC */
+#if !defined(GPROF) && defined(DDBPROF)
+ cmpl $T_BPTFLT,TF_TRAPNO(%esp)
+ jne .Lreal_trap
+
+ pushl %esp
+ call _C_LABEL(db_prof_hook)
+ addl $4,%esp
+ cmpl $1,%eax
+ jne .Lreal_trap
+
+ /*
+ * Abuse the error field to indicate that INTRFASTEXIT needs
+ * to emulate the patched instruction.
+ */
+ movl $INTR_FAKE_TRAP, TF_ERR(%esp)
+ jz 2f
+.Lreal_trap:
+#endif /* !defined(GPROF) && defined(DDBPROF) */
pushl %esp
call _C_LABEL(trap)
addl $4,%esp
@@ -1464,10 +1487,22 @@ calltrap:
call _C_LABEL(ast)
addl $4,%esp
jmp 2b
+1:
+#if !defined(GPROF) && defined(DDBPROF)
+ /*
+ * If we are returning from a probe trap we need to fix the
+ * stack layout and emulate the patched instruction.
+ *
+ * The code below does that by trashing %eax, so it MUST be
+ * restored afterward.
+ */
+ cmpl $INTR_FAKE_TRAP, TF_ERR(%esp)
+ je .Lprobe_fixup
+#endif /* !defined(GPROF) && defined(DDBPROF) */
#ifndef DIAGNOSTIC
-1: INTRFASTEXIT
+ INTRFASTEXIT
#else
-1: cmpl CPL,%ebx
+ cmpl CPL,%ebx
jne 3f
INTRFASTEXIT
3: sti
@@ -1482,6 +1517,33 @@ calltrap:
4: .asciz "WARNING: SPL NOT LOWERED ON TRAP EXIT\n"
#endif /* DIAGNOSTIC */
+#if !defined(GPROF) && defined(DDBPROF)
+.Lprobe_fixup:
+ /* Restore all register unwinding the stack. */
+ INTR_RESTORE_ALL
+
+ /*
+ * Use the space left by ``err'' and ``trapno'' to emulate
+ * "pushl %ebp".
+ *
+ * Temporarily save %eax.
+ */
+ movl %eax,0(%esp)
+
+ /* Shift hardware-saved registers: eip, cs, eflags */
+ movl 8(%esp),%eax
+ movl %eax,4(%esp)
+ movl 12(%esp),%eax
+ movl %eax,8(%esp)
+ movl 16(%esp),%eax
+ movl %eax,12(%esp)
+
+ /* Store %ebp in the expected location to finish the emulation. */
+ movl %ebp,16(%esp)
+
+ popl %eax
+ iret
+#endif /* !defined(GPROF) && defined(DDBPROF) */
/*
* Trap gate entry for syscall
*/
diff --git a/sys/arch/i386/include/cpu.h b/sys/arch/i386/include/cpu.h
index 27980979b6d..bde738031e7 100644
--- a/sys/arch/i386/include/cpu.h
+++ b/sys/arch/i386/include/cpu.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.h,v 1.151 2017/01/03 09:48:15 mlarkin Exp $ */
+/* $OpenBSD: cpu.h,v 1.152 2017/02/06 09:13:41 mpi Exp $ */
/* $NetBSD: cpu.h,v 1.35 1996/05/05 19:29:26 christos Exp $ */
/*-
@@ -185,7 +185,7 @@ struct cpu_info {
struct ksensordev ci_sensordev;
struct ksensor ci_sensor;
-#ifdef GPROF
+#if defined(GPROF) || defined(DDBPROF)
struct gmonparam *ci_gmon;
#endif
u_int32_t ci_vmm_flags;
diff --git a/sys/arch/i386/include/cpufunc.h b/sys/arch/i386/include/cpufunc.h
index 7b025d1bbd7..2262237c229 100644
--- a/sys/arch/i386/include/cpufunc.h
+++ b/sys/arch/i386/include/cpufunc.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpufunc.h,v 1.22 2014/03/29 18:09:29 guenther Exp $ */
+/* $OpenBSD: cpufunc.h,v 1.23 2017/02/06 09:13:41 mpi Exp $ */
/* $NetBSD: cpufunc.h,v 1.8 1994/10/27 04:15:59 cgd Exp $ */
/*
@@ -215,6 +215,22 @@ write_eflags(u_int ef)
__asm volatile("pushl %0; popfl" : : "r" (ef));
}
+static inline u_long
+intr_disable(void)
+{
+ u_long ef;
+
+ ef = read_eflags();
+ disable_intr();
+ return (ef);
+}
+
+static inline void
+intr_restore(u_long ef)
+{
+ write_eflags(ef);
+}
+
static __inline void
wbinvd(void)
{
diff --git a/sys/arch/i386/include/db_machdep.h b/sys/arch/i386/include/db_machdep.h
index 6866b8b316d..5d9fb9bd5e8 100644
--- a/sys/arch/i386/include/db_machdep.h
+++ b/sys/arch/i386/include/db_machdep.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: db_machdep.h,v 1.25 2016/04/27 11:10:48 mpi Exp $ */
+/* $OpenBSD: db_machdep.h,v 1.26 2017/02/06 09:13:41 mpi Exp $ */
/* $NetBSD: db_machdep.h,v 1.9 1996/05/03 19:23:59 christos Exp $ */
/*
@@ -51,6 +51,9 @@ extern db_regs_t ddb_regs; /* register state */
#define BKPT_SIZE (1) /* size of breakpoint inst */
#define BKPT_SET(inst) (BKPT_INST)
+#define SSF_INST 0x55
+#define SSF_SIZE (1)
+
#define FIXUP_PC_AFTER_BREAK(regs) ((regs)->tf_eip -= BKPT_SIZE)
#define db_clear_single_step(regs) ((regs)->tf_eflags &= ~PSL_T)