#ifndef _DT_H_
#define _DT_H_
#include <sys/ioccom.h>
#include <sys/stacktrace.h>
#include <sys/time.h>
#include <sys/syslimits.h>
#define DTNAMESIZE 16
#define DTMAXCOMLEN _MAXCOMLEN
#define DTMAXFUNCARGS 10
#define DTMAXARGTYPES 5
struct dt_evt {
unsigned int dtev_pbn;
unsigned int dtev_cpu;
pid_t dtev_pid;
pid_t dtev_tid;
struct timespec dtev_tsp;
struct stacktrace dtev_kstack;
struct stacktrace dtev_ustack;
char dtev_comm[DTMAXCOMLEN];
union {
register_t E_entry[DTMAXFUNCARGS];
struct {
register_t __retval[2];
int __error;
} E_return;
} _args;
#define dtev_args _args.E_entry
#define dtev_retval _args.E_return.__retval
#define dtev_error _args.E_return.__error
};
#define DTEVT_EXECNAME (1 << 0)
#define DTEVT_USTACK (1 << 1)
#define DTEVT_KSTACK (1 << 2)
#define DTEVT_FUNCARGS (1 << 3)
#define DTEVT_FLAG_BITS \
"\020" \
"\001EXECNAME" \
"\002USTACK" \
"\003KSTACK" \
"\004FUNCARGS" \
struct dtioc_probe_info {
uint32_t dtpi_pbn;
uint8_t dtpi_nargs;
char dtpi_prov[DTNAMESIZE];
char dtpi_func[DTNAMESIZE];
char dtpi_name[DTNAMESIZE];
};
struct dtioc_probe {
size_t dtpr_size;
struct dtioc_probe_info *dtpr_probes;
};
struct dtioc_arg_info {
uint32_t dtai_pbn;
uint8_t dtai_argn;
char dtai_argtype[DTNAMESIZE];
};
struct dtioc_arg {
uint32_t dtar_pbn;
size_t dtar_size;
struct dtioc_arg_info *dtar_args;
};
struct dtioc_req {
uint32_t dtrq_pbn;
uint32_t __unused1;
uint64_t dtrq_evtflags;
uint64_t dtrq_nsecs;
};
struct dtioc_stat {
uint64_t dtst_readevt;
uint64_t dtst_dropevt;
uint64_t dtst_skiptick;
uint64_t dtst_recurevt;
};
struct dtioc_rdvn {
pid_t dtrv_pid;
int dtrv_fd;
caddr_t dtrv_va;
caddr_t dtrv_offset;
caddr_t dtrv_start;
size_t dtrv_len;
};
#define DTIOCGPLIST _IOWR('D', 1, struct dtioc_probe)
#define DTIOCGSTATS _IOR('D', 2, struct dtioc_stat)
#define DTIOCRECORD _IOW('D', 3, int)
#define DTIOCPRBENABLE _IOW('D', 4, struct dtioc_req)
#define DTIOCPRBDISABLE _IOW('D', 5, struct dtioc_req)
#define DTIOCGARGS _IOWR('D', 6, struct dtioc_arg)
#define DTIOCRDVNODE _IOWR('D', 8, struct dtioc_rdvn)
#ifdef _KERNEL
#include <sys/mutex.h>
#include <sys/queue.h>
#include <sys/smr.h>
#define DTEVT_COMMON (DTEVT_EXECNAME|DTEVT_KSTACK|DTEVT_USTACK)
#define M_DT M_DEVBUF
struct dt_softc;
struct dt_pcb {
SMR_SLIST_ENTRY(dt_pcb) dp_pnext;
TAILQ_ENTRY(dt_pcb) dp_snext;
struct dt_softc *dp_sc;
struct dt_probe *dp_dtp;
uint64_t dp_evtflags;
struct clockintr dp_clockintr;
uint64_t dp_nsecs;
struct cpu_info *dp_cpu;
};
TAILQ_HEAD(dt_pcb_list, dt_pcb);
struct dt_pcb *dt_pcb_alloc(struct dt_probe *, struct dt_softc *);
void dt_pcb_free(struct dt_pcb *);
void dt_pcb_purge(struct dt_pcb_list *);
void dt_pcb_ring_skiptick(struct dt_pcb *, unsigned int);
struct dt_evt *dt_pcb_ring_get(struct dt_pcb *, int);
void dt_pcb_ring_consume(struct dt_pcb *, struct dt_evt *);
struct dt_probe {
SIMPLEQ_ENTRY(dt_probe) dtp_next;
SMR_SLIST_HEAD(, dt_pcb) dtp_pcbs;
struct dt_provider *dtp_prov;
const char *dtp_func;
const char *dtp_name;
uint32_t dtp_pbn;
volatile uint32_t dtp_recording;
unsigned dtp_ref;
int dtp_sysnum;
const char *dtp_argtype[DTMAXARGTYPES];
int dtp_nargs;
#ifdef DDBPROF
int dtp_type;
vaddr_t dtp_addr;
SLIST_ENTRY(dt_probe) dtp_knext;
#endif
};
struct dt_provider {
const char *dtpv_name;
volatile uint32_t dtpv_recording;
int (*dtpv_alloc)(struct dt_probe *, struct dt_softc *,
struct dt_pcb_list *, struct dtioc_req *);
int (*dtpv_enter)(struct dt_provider *, ...);
void (*dtpv_leave)(struct dt_provider *, ...);
int (*dtpv_dealloc)(struct dt_probe *, struct dt_softc *,
struct dtioc_req *);
};
extern struct dt_provider dt_prov_kprobe;
int dt_prov_profile_init(void);
int dt_prov_syscall_init(void);
int dt_prov_static_init(void);
int dt_prov_kprobe_init(void);
struct dt_probe *dt_dev_alloc_probe(const char *, const char *,
struct dt_provider *);
void dt_dev_register_probe(struct dt_probe *);
void dt_clock(struct clockrequest *, void *, void *);
extern volatile uint32_t dt_tracing;
#define DT_ENTER(provname, args...) do { \
extern struct dt_provider dt_prov_ ## provname ; \
struct dt_provider *dtpv = &dt_prov_ ## provname ; \
\
if (__predict_false(dt_tracing) && \
__predict_false(dtpv->dtpv_recording)) { \
dtpv->dtpv_enter(dtpv, args); \
} \
} while (0)
#define DT_LEAVE(provname, args...) do { \
extern struct dt_provider dt_prov_ ## provname ; \
struct dt_provider *dtpv = &dt_prov_ ## provname ; \
\
if (__predict_false(dt_tracing) && \
__predict_false(dtpv->dtpv_recording)) { \
dtpv->dtpv_leave(dtpv, args); \
} \
} while (0)
#define _DT_STATIC_P(func, name) (dt_static_##func##_##name)
#define _DT_STATIC_PROBEN(func, name, arg0, arg1, arg2, arg3, arg4, n) \
struct dt_probe _DT_STATIC_P(func, name) = { \
.dtp_next = { NULL }, \
.dtp_pcbs = { NULL }, \
.dtp_prov = &dt_prov_static, \
.dtp_func = #func, \
.dtp_name = #name, \
.dtp_pbn = 0, \
.dtp_sysnum = 0, \
.dtp_argtype = { arg0, arg1, arg2, arg3, arg4 }, \
.dtp_nargs = n, \
} \
#define DT_STATIC_PROBE0(func, name) \
_DT_STATIC_PROBEN(func, name, NULL, NULL, NULL, NULL, NULL, 0)
#define DT_STATIC_PROBE1(func, name, arg0) \
_DT_STATIC_PROBEN(func, name, arg0, NULL, NULL, NULL, NULL, 1)
#define DT_STATIC_PROBE2(func, name, arg0, arg1) \
_DT_STATIC_PROBEN(func, name, arg0, arg1, NULL, NULL, NULL, 2)
#define DT_STATIC_PROBE3(func, name, arg0, arg1, arg2) \
_DT_STATIC_PROBEN(func, name, arg0, arg1, arg2, NULL, NULL, 3)
#define DT_STATIC_PROBE4(func, name, arg0, arg1, arg2, arg3) \
_DT_STATIC_PROBEN(func, name, arg0, arg1, arg2, arg3, NULL, 4)
#define DT_STATIC_PROBE5(func, name, arg0, arg1, arg2, arg3, arg4) \
_DT_STATIC_PROBEN(func, name, arg0, arg1, arg2, arg3, arg4, 5)
#define DT_STATIC_ENTER(func, name, args...) do { \
extern struct dt_probe _DT_STATIC_P(func, name); \
struct dt_probe *dtp = &_DT_STATIC_P(func, name); \
\
if (__predict_false(dt_tracing) && \
__predict_false(dtp->dtp_recording)) { \
struct dt_provider *dtpv = dtp->dtp_prov; \
\
dtpv->dtpv_enter(dtpv, dtp, args); \
} \
} while (0)
#define _DT_INDEX_P(func) (dtps_index_##func)
#define DT_INDEX_ENTER(func, index, args...) do { \
extern struct dt_probe **_DT_INDEX_P(func); \
\
if (__predict_false(dt_tracing) && \
__predict_false(index > 0) && \
__predict_true(_DT_INDEX_P(func) != NULL)) { \
struct dt_probe *dtp = _DT_INDEX_P(func)[index]; \
\
if(__predict_false(dtp->dtp_recording)) { \
struct dt_provider *dtpv = dtp->dtp_prov; \
\
dtpv->dtpv_enter(dtpv, dtp, args); \
} \
} \
} while (0)
#endif
#endif