Add the DTrace hooks for exception handling (Function boundary trace

-fbt- provider), cyclic clock and syscalls.
This commit is contained in:
John Birrell 2008-05-24 06:32:26 +00:00
parent f1bd3c150c
commit 367f3ce5e6
3 changed files with 125 additions and 0 deletions

View file

@ -37,6 +37,7 @@
#include "opt_atpic.h"
#include "opt_compat.h"
#include "opt_hwpmc_hooks.h"
#include "opt_kdtrace.h"
#include <machine/asmacros.h>
#include <machine/psl.h>
@ -44,6 +45,21 @@
#include "assym.s"
#ifdef KDTRACE_HOOKS
.bss
.globl dtrace_invop_jump_addr
.align 8
.type dtrace_invop_jump_addr, @object
.size dtrace_invop_jump_addr, 8
dtrace_invop_jump_addr:
.zero 8
.globl dtrace_invop_calltrap_addr
.align 8
.type dtrace_invop_calltrap_addr, @object
.size dtrace_invop_calltrap_addr, 8
dtrace_invop_calltrap_addr:
.zero 8
#endif
.text
#ifdef HWPMC_HOOKS
ENTRY(start_exceptions)
@ -170,6 +186,30 @@ alltraps_pushregs_no_rdi:
movq %r14,TF_R14(%rsp)
movq %r15,TF_R15(%rsp)
FAKE_MCOUNT(TF_RIP(%rsp))
#ifdef KDTRACE_HOOKS
/*
* DTrace Function Boundary Trace (fbt) probes are triggered
* by int3 (0xcc) which causes the #BP (T_BPTFLT) breakpoint
* interrupt. For all other trap types, just handle them in
* the usual way.
*/
cmpq $T_BPTFLT,TF_TRAPNO(%rsp)
jne calltrap
/* Check if there is no DTrace hook registered. */
cmpq $0,dtrace_invop_jump_addr
je calltrap
/*
* Set our jump address for the jump back in the event that
* the breakpoint wasn't caused by DTrace at all.
*/
movq $calltrap, dtrace_invop_calltrap_addr(%rip)
/* Jump to the code hooked in by DTrace. */
movq dtrace_invop_jump_addr, %rax
jmpq *dtrace_invop_jump_addr
#endif
.globl calltrap
.type calltrap,@function
calltrap:

View file

@ -35,6 +35,7 @@
__FBSDID("$FreeBSD$");
#include "opt_hwpmc_hooks.h"
#include "opt_kdtrace.h"
#include "opt_ddb.h"
@ -65,6 +66,11 @@ __FBSDID("$FreeBSD$");
#include <ddb/ddb.h>
#endif
#ifdef KDTRACE_HOOKS
#include <sys/dtrace_bsd.h>
cyclic_clock_func_t lapic_cyclic_clock_func[MAXCPU];
#endif
/* Sanity checks on IDT vectors. */
CTASSERT(APIC_IO_INTS + APIC_NUM_IOINTS == APIC_TIMER_INT);
CTASSERT(APIC_TIMER_INT < APIC_LOCAL_INTS);
@ -668,6 +674,17 @@ lapic_handle_timer(struct trapframe *frame)
(*la->la_timer_count)++;
critical_enter();
#ifdef KDTRACE_HOOKS
/*
* If the DTrace hooks are configured and a callback function
* has been registered, then call it to process the high speed
* timers.
*/
int cpu = PCPU_GET(cpuid);
if (lapic_cyclic_clock_func[cpu] != NULL)
(*lapic_cyclic_clock_func[cpu])(frame);
#endif
/* Fire hardclock at hz. */
la->la_hard_ticks += hz;
if (la->la_hard_ticks >= lapic_timer_hz) {

View file

@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$");
#include "opt_hwpmc_hooks.h"
#include "opt_isa.h"
#include "opt_kdb.h"
#include "opt_kdtrace.h"
#include "opt_ktrace.h"
#include <sys/param.h>
@ -94,6 +95,26 @@ __FBSDID("$FreeBSD$");
#endif
#include <machine/tss.h>
#ifdef KDTRACE_HOOKS
#include <sys/dtrace_bsd.h>
/*
* This is a hook which is initialised by the dtrace module
* to handle traps which might occur during DTrace probe
* execution.
*/
dtrace_trap_func_t dtrace_trap_func;
dtrace_doubletrap_func_t dtrace_doubletrap_func;
/*
* This is a hook which is initialised by the systrace module
* when it is loaded. This keeps the DTrace syscall provider
* implementation opaque.
*/
systrace_probe_func_t systrace_probe_func;
#endif
extern void trap(struct trapframe *frame);
extern void syscall(struct trapframe *frame);
void dblfault_handler(struct trapframe *frame);
@ -199,6 +220,24 @@ trap(struct trapframe *frame)
goto out;
#endif
#ifdef KDTRACE_HOOKS
/*
* A trap can occur while DTrace executes a probe. Before
* executing the probe, DTrace blocks re-scheduling and sets
* a flag in it's per-cpu flags to indicate that it doesn't
* want to fault. On returning from the the probe, the no-fault
* flag is cleared and finally re-scheduling is enabled.
*
* If the DTrace kernel module has registered a trap handler,
* call it and if it returns non-zero, assume that it has
* handled the trap and modified the trap frame so that this
* function can return normally.
*/
if (dtrace_trap_func != NULL)
if ((*dtrace_trap_func)(frame, type))
goto out;
#endif
if ((frame->tf_rflags & PSL_I) == 0) {
/*
* Buggy application or kernel code has disabled
@ -730,6 +769,10 @@ trap_fatal(frame, eva)
void
dblfault_handler(struct trapframe *frame)
{
#ifdef KDTRACE_HOOKS
if (dtrace_doubletrap_func != NULL)
(*dtrace_doubletrap_func)();
#endif
printf("\nFatal double fault\n");
printf("rip = 0x%lx\n", frame->tf_rip);
printf("rsp = 0x%lx\n", frame->tf_rsp);
@ -839,9 +882,34 @@ syscall(struct trapframe *frame)
PTRACESTOP_SC(p, td, S_PT_SCE);
#ifdef KDTRACE_HOOKS
/*
* If the systrace module has registered it's probe
* callback and if there is a probe active for the
* syscall 'entry', process the probe.
*/
if (systrace_probe_func != NULL && callp->sy_entry != 0)
(*systrace_probe_func)(callp->sy_entry, code, callp,
args);
#endif
AUDIT_SYSCALL_ENTER(code, td);
error = (*callp->sy_call)(td, argp);
AUDIT_SYSCALL_EXIT(error, td);
/* Save the latest error return value. */
td->td_errno = error;
#ifdef KDTRACE_HOOKS
/*
* If the systrace module has registered it's probe
* callback and if there is a probe active for the
* syscall 'return', process the probe.
*/
if (systrace_probe_func != NULL && callp->sy_return != 0)
(*systrace_probe_func)(callp->sy_return, code, callp,
args);
#endif
}
switch (error) {