#include <linux/cred.h>
#include <linux/cyclic.h>
+#include <linux/dtrace_cpu.h>
#include <linux/dtrace_os.h>
#include <linux/idr.h>
#include <linux/ktime.h>
typedef uint32_t dtrace_epid_t;
typedef uint32_t dtrace_optid_t;
typedef uint32_t dtrace_specid_t;
-typedef uint32_t processorid_t;
typedef uint64_t dtrace_aggvarid_t;
typedef uint64_t dtrace_genid_t;
#define DIF_VAR_UID 0x011e
#define DIF_VAR_GID 0x011f
#define DIF_VAR_ERRNO 0x0120
+#define DIF_VAR_CURCPU 0x0121
#define DIF_SUBR_RAND 0
#define DIF_SUBR_MUTEX_OWNED 1
#define DIF_SUBR_INET_NTOP 41
#define DIF_SUBR_INET_NTOA 42
#define DIF_SUBR_INET_NTOA6 43
+#define DIF_SUBR_D_PATH 44
-#define DIF_SUBR_MAX 43
+#define DIF_SUBR_MAX 44
#define DIF_INSTR_OP(i) (((i) >> 24) & 0xff)
#define DIF_INSTR_R1(i) (((i) >> 16) & 0xff)
extern uint64_t dtrace_getarg(int, int);
extern int dtrace_getstackdepth(int);
extern int dtrace_getustackdepth(void);
-extern ulong_t dtrace_getreg(struct pt_regs *, uint_t);
+extern ulong_t dtrace_getreg(struct task_struct *, uint_t);
extern void dtrace_copyin(uintptr_t, uintptr_t, size_t, volatile uint16_t *);
extern void dtrace_copyout(uintptr_t, uintptr_t, size_t, volatile uint16_t *);
extern void dtrace_copyinstr(uintptr_t, uintptr_t, size_t,
# define REG_FS 1
# define REG_GS 0
#else
-# define REG_DS 25
-# define REG_ES 24
-# define REG_GS 23
-# define REG_FS 22
-# define REG_SS 21
-# define REG_RSP 20
-# define REG_RFL 19
-# define REG_CS 18
-# define REG_RIP 17
-# define REG_ERR 16
+# define REG_GS 24
+# define REG_FS 23
+# define REG_ES 22
+# define REG_DS 21
+# define REG_SS 20
+# define REG_RSP 19
+# define REG_RFL 18
+# define REG_CS 17
+# define REG_RIP 16
+# define REG_ERR 15
# define REG_TRAPNO 15
-# define REG_RAX 14
-# define REG_RCX 13
+# define REG_RDI 14
+# define REG_RSI 13
# define REG_RDX 12
-# define REG_RBX 11
-# define REG_RBP 10
-# define REG_RSI 9
-# define REG_RDI 8
-# define REG_R8 7
-# define REG_R9 6
-# define REG_R10 5
-# define REG_R11 4
+# define REG_RCX 11
+# define REG_RAX 10
+# define REG_R8 9
+# define REG_R9 8
+# define REG_R10 7
+# define REG_R11 6
+# define REG_RBX 5
+# define REG_RBP 4
# define REG_R12 3
# define REG_R13 2
# define REG_R14 1
#include <linux/socket.h>
#include <net/ipv6.h>
+#include <linux/mount.h>
+
#include "dtrace.h"
size_t dtrace_global_maxsize = 16 * 1024;
*/
#define DTRACE_TLS_THRKEY(where) \
{ \
- uint_t intr = in_interrupt() ? 1 : 0; \
+ uint_t intr = in_irq() ? 1 : 0; \
\
(where) = ((current->pid + DIF_VARIABLE_MAX) & \
(((uint64_t)1 << 63) - 1)) | \
*/
static int
dtrace_canload(uint64_t addr, size_t sz, dtrace_mstate_t *mstate,
- dtrace_vstate_t *vstate)
+ dtrace_vstate_t *vstate)
{
volatile uintptr_t *illval = &this_cpu_core->cpuc_dtrace_illval;
return mstate->dtms_arg[ndx];
case DIF_VAR_UREGS: {
- struct pt_regs *regs = task_pt_regs(current);
-
if (!dtrace_priv_proc(state))
return 0;
- return dtrace_getreg(regs, ndx);
+ return dtrace_getreg(current, ndx);
}
case DIF_VAR_CURTHREAD:
if (!dtrace_priv_proc(state))
return 0;
- /*
- * Note that we are assuming that an unanchored probe is
- * always due to a high-level interrupt. (And we're assuming
- * that there is only a single high level interrupt.)
- */
- if (DTRACE_ANCHORED(mstate->dtms_probe) && in_interrupt())
- return init_task.pid;
-
/*
* It is always safe to dereference current, it always points
* to a valid task_struct.
if (!dtrace_priv_proc(state))
return 0;
- /*
- * See comment in DIF_VAR_PID.
- */
- if (DTRACE_ANCHORED(mstate->dtms_probe) && in_interrupt())
- return init_task.real_parent->pid;
-
/*
* It is always safe to dereference current, it always points
* to a valid task_struct.
return (uint64_t)current->real_parent->pid;
case DIF_VAR_TID:
- /*
- * See comment in DIF_VAR_PID.
- */
- if (DTRACE_ANCHORED(mstate->dtms_probe) && in_interrupt())
- return init_task.pid;
-
return (uint64_t)current->pid;
case DIF_VAR_EXECNAME:
if (!dtrace_priv_proc(state))
return 0;
- /*
- * See comment in DIF_VAR_PID.
- */
- if (DTRACE_ANCHORED(mstate->dtms_probe) && in_interrupt())
- return (uint64_t)(uintptr_t)init_task.comm;
-
/*
* It is always safe to dereference current, it always points
* to a valid task_struct.
if (!dtrace_priv_proc(state))
return 0;
- /*
- * See comment in DIF_VAR_PID.
- */
- if (DTRACE_ANCHORED(mstate->dtms_probe) && in_interrupt())
- return (uint64_t)init_task.real_cred->uid;
-
/*
* It is always safe to dereference current, it always points
* to a valid task_struct.
if (!dtrace_priv_proc(state))
return 0;
- /*
- * See comment in DIF_VAR_PID.
- */
- if (DTRACE_ANCHORED(mstate->dtms_probe) && in_interrupt())
- return (uint64_t)init_task.real_cred->gid;
-
/*
* It is always safe to dereference current, it always points
* to a valid task_struct.
if (!dtrace_priv_proc(state))
return 0;
- /*
- * See comment in DIF_VAR_PID.
- */
- if (DTRACE_ANCHORED(mstate->dtms_probe) && in_interrupt())
- return 0;
-
/*
* It is always safe to dereference current, it always points
* to a valid task_struct.
*/
return (uint64_t)current->thread.error_code;
+ case DIF_VAR_CURCPU:
+ return (uint64_t)(uintptr_t)this_cpu_info;
+
default:
DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
return 0;
break;
}
+ case DIF_SUBR_D_PATH: {
+ struct path *path = (struct path *)tupregs[0].dttk_value;
+ char *dest = (char *)mstate->dtms_scratch_ptr;
+ char *ptr;
+ uint64_t size = state->dts_options[DTRACEOPT_STRSIZE];
+
+ if (!dtrace_canload((uintptr_t)path, sizeof(struct path),
+ mstate, vstate)) {
+ regs[rd] = 0;
+ break;
+ }
+
+ if (!DTRACE_INSCRATCH(mstate, size)) {
+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH);
+ regs[rd] = 0;
+ break;
+ }
+
+ ptr = d_path(path, dest, size);
+ if (ptr < 0) {
+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH);
+ regs[rd] = 0;
+ break;
+ }
+
+ regs[rd] = (uintptr_t)ptr;
+ mstate->dtms_scratch_ptr += size;
+ break;
+ }
+
}
}
return in_interrupt();
}
-ulong_t dtrace_getreg(struct pt_regs *rp, uint_t reg)
+ulong_t dtrace_getreg(struct task_struct *task, uint_t reg)
{
+ struct pt_regs *rp = task_pt_regs(task);
+
#ifdef __i386__
if (reg > REG_SS) {
DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
}
#else
int regmap[] = {
- REG_GS, /* 0 -> GS */
- REG_FS, /* 1 -> FS */
- REG_ES, /* 2 -> ES */
- REG_DS, /* 3 -> DS */
+ REG_RBX, /* 0 -> EBX */
+ REG_RCX, /* 1 -> ECX */
+ REG_RDX, /* 2 -> EDX */
+ REG_RSI, /* 3 -> ESI */
REG_RDI, /* 4 -> EDI */
- REG_RSI, /* 5 -> ESI */
- REG_RBP, /* 6 -> EBP */
- REG_RSP, /* 7 -> ESP */
- REG_RBX, /* 8 -> EBX */
- REG_RDX, /* 9 -> EDX */
- REG_RCX, /* 10 -> ECX */
- REG_RAX, /* 11 -> EAX */
- REG_TRAPNO, /* 12 -> TRAPNO */
- REG_ERR, /* 13 -> ERR */
- REG_RIP, /* 14 -> EIP */
- REG_CS, /* 15 -> CS */
- REG_RFL, /* 16 -> EFL */
- REG_RSP, /* 17 -> UESP */
- REG_SS, /* 18 -> SS */
+ REG_RBP, /* 5 -> EBP */
+ REG_RAX, /* 6 -> EAX */
+ REG_DS, /* 7 -> DS */
+ REG_ES, /* 8 -> ES */
+ REG_FS, /* 9 -> FS */
+ REG_GS, /* 10 -> GS */
+ REG_TRAPNO, /* 11 -> TRAPNO */
+ REG_RIP, /* 12 -> EIP */
+ REG_CS, /* 13 -> CS */
+ REG_RFL, /* 14 -> EFL */
+ REG_RSP, /* 15 -> UESP */
+ REG_SS, /* 16 -> SS */
};
+ if (reg > REG_GS) {
+ /*
+ * Convert register alias index into register mapping index.
+ */
+ reg -= REG_GS + 1;
- if (reg <= REG_SS) {
if (reg >= sizeof(regmap) / sizeof(int)) {
DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
return 0;
}
reg = regmap[reg];
- } else
- reg -= REG_SS + 1;
+ }
+
+ /*
+ * Most common case: direct index into pt_regs structure.
+ */
+ if (reg <= REG_SS)
+ return (&rp->r15)[reg];
switch (reg) {
- case REG_RDI:
- return rp->di;
- case REG_RSI:
- return rp->si;
- case REG_RDX:
- return rp->dx;
- case REG_RCX:
- return rp->cx;
- case REG_R8:
- return rp->r8;
- case REG_R9:
- return rp->r9;
- case REG_RAX:
- return rp->ax;
- case REG_RBX:
- return rp->bx;
- case REG_RBP:
- return rp->bp;
- case REG_R10:
- return rp->r10;
- case REG_R11:
- return rp->r11;
- case REG_R12:
- return rp->r12;
- case REG_R13:
- return rp->r13;
- case REG_R14:
- return rp->r14;
- case REG_R15:
- return rp->r15;
- case REG_CS:
case REG_DS:
+ return task->thread.ds;
case REG_ES:
+ return task->thread.es;
case REG_FS:
+ return task->thread.fs;
case REG_GS:
- return rp->cs;
- case REG_TRAPNO:
- return rp->orig_ax;
- case REG_ERR:
- return rp->di;
- case REG_RIP:
- return rp->ip;
- case REG_SS:
- return rp->ss;
- case REG_RFL:
- return rp->flags;
- case REG_RSP:
- return rp->sp;
+ return task->thread.gs;
default:
DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
return 0;
* raise() has a queue depth of 1 -- we ignore all subsequent
* invocations of the raise() action.
*/
+#if 0
+
+ sigaddset(¤t->pending.signal, sig);
+ set_thread_flag(TIF_SIGPENDING);
+#else
if (current->dtrace_sig == 0)
current->dtrace_sig = (uint8_t)sig;
-
-// current->sig_check = 1; /* FIXME */
-// aston(current); /* FIXME */
+#endif
}
static void dtrace_action_stop(void)
current->dtrace_start = dtrace_gethrtime();
local_irq_restore(cookie);
+
+ if (current->dtrace_sig != 0) {
+ int sig = current->dtrace_sig;
+
+ current->dtrace_sig = 0;
+
+ send_sig(sig, current, 0);
+ }
}
EXPORT_SYMBOL(dtrace_probe);
dtrace_optval_t dtrace_statusrate_max = (uint64_t)10 * NANOSEC;
dtrace_optval_t dtrace_jstackframes_default = 50;
dtrace_optval_t dtrace_jstackstrsize_default = 512;
+#if 1
+ktime_t dtrace_deadman_interval = KTIME_INIT(10, 0);
+ktime_t dtrace_deadman_timeout = KTIME_INIT(120, 0);
+ktime_t dtrace_deadman_user = KTIME_INIT(120, 0);
+#else
ktime_t dtrace_deadman_interval = KTIME_INIT(1, 0);
ktime_t dtrace_deadman_timeout = KTIME_INIT(10, 0);
ktime_t dtrace_deadman_user = KTIME_INIT(30, 0);
+#endif
dtrace_id_t dtrace_probeid_begin;
dtrace_id_t dtrace_probeid_end;