diff options
author | Martin Pieuchot <mpi@cvs.openbsd.org> | 2017-02-06 09:13:42 +0000 |
---|---|---|
committer | Martin Pieuchot <mpi@cvs.openbsd.org> | 2017-02-06 09:13:42 +0000 |
commit | 2f5d8ba197d7f31af3b8a776cd44f7de20bd17aa (patch) | |
tree | 4c7465f43f75cba9ebaef0336e2463ebaa4f5187 /sys/arch | |
parent | f3b95d53b4db45d7362b2c3810a23024e7b1983f (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.c | 6 | ||||
-rw-r--r-- | sys/arch/i386/i386/db_trace.c | 21 | ||||
-rw-r--r-- | sys/arch/i386/i386/locore.s | 72 | ||||
-rw-r--r-- | sys/arch/i386/include/cpu.h | 4 | ||||
-rw-r--r-- | sys/arch/i386/include/cpufunc.h | 18 | ||||
-rw-r--r-- | sys/arch/i386/include/db_machdep.h | 5 |
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) |