1*91b2ecf6Smpi /* $OpenBSD: dt_dev.c,v 1.1 2020/01/21 16:16:23 mpi Exp $ */ 2*91b2ecf6Smpi 3*91b2ecf6Smpi /* 4*91b2ecf6Smpi * Copyright (c) 2019 Martin Pieuchot <mpi@openbsd.org> 5*91b2ecf6Smpi * 6*91b2ecf6Smpi * Permission to use, copy, modify, and distribute this software for any 7*91b2ecf6Smpi * purpose with or without fee is hereby granted, provided that the above 8*91b2ecf6Smpi * copyright notice and this permission notice appear in all copies. 9*91b2ecf6Smpi * 10*91b2ecf6Smpi * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11*91b2ecf6Smpi * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12*91b2ecf6Smpi * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13*91b2ecf6Smpi * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14*91b2ecf6Smpi * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15*91b2ecf6Smpi * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16*91b2ecf6Smpi * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17*91b2ecf6Smpi */ 18*91b2ecf6Smpi 19*91b2ecf6Smpi #include <sys/types.h> 20*91b2ecf6Smpi #include <sys/systm.h> 21*91b2ecf6Smpi #include <sys/param.h> 22*91b2ecf6Smpi #include <sys/device.h> 23*91b2ecf6Smpi #include <sys/malloc.h> 24*91b2ecf6Smpi #include <sys/proc.h> 25*91b2ecf6Smpi 26*91b2ecf6Smpi #include <dev/dt/dtvar.h> 27*91b2ecf6Smpi 28*91b2ecf6Smpi /* 29*91b2ecf6Smpi * How many frames are used by the profiling code? For example 30*91b2ecf6Smpi * on amd64: 31*91b2ecf6Smpi * 32*91b2ecf6Smpi * From syscall provider: 33*91b2ecf6Smpi * 34*91b2ecf6Smpi * dt_prov_syscall_entry+0x141 35*91b2ecf6Smpi * syscall+0x205 <--- start here 36*91b2ecf6Smpi * Xsyscall+0x128 37*91b2ecf6Smpi * 38*91b2ecf6Smpi * From profile provider: 39*91b2ecf6Smpi * 40*91b2ecf6Smpi * dt_prov_profile_enter+0x6e 41*91b2ecf6Smpi * hardclock+0x12c 42*91b2ecf6Smpi * clockintr+0x59 43*91b2ecf6Smpi * intr_handler+0x6e 44*91b2ecf6Smpi * Xresume_legacy0+0x1d3 45*91b2ecf6Smpi * cpu_idle_cycle+0x1b <---- start here. 46*91b2ecf6Smpi * proc_trampoline+0x1c 47*91b2ecf6Smpi */ 48*91b2ecf6Smpi #if notyet 49*91b2ecf6Smpi #define DT_HOOK_FRAME_ADDRESS __builtin_frame_address(4) 50*91b2ecf6Smpi #else 51*91b2ecf6Smpi #define DT_HOOK_FRAME_ADDRESS __builtin_frame_address(0) 52*91b2ecf6Smpi #endif 53*91b2ecf6Smpi 54*91b2ecf6Smpi #define DT_EVTRING_SIZE 16 /* # of slots in per PCB event ring */ 55*91b2ecf6Smpi 56*91b2ecf6Smpi #define DPRINTF(x...) /* nothing */ 57*91b2ecf6Smpi 58*91b2ecf6Smpi /* 59*91b2ecf6Smpi * Descriptor associated with each program opening /dev/dt. It is used 60*91b2ecf6Smpi * to keep track of enabled PCBs. 61*91b2ecf6Smpi * 62*91b2ecf6Smpi * Locks used to protect struct members in this file: 63*91b2ecf6Smpi * m per-softc mutex 64*91b2ecf6Smpi * k kernel lock 65*91b2ecf6Smpi */ 66*91b2ecf6Smpi struct dt_softc { 67*91b2ecf6Smpi SLIST_ENTRY(dt_softc) ds_next; /* [k] descriptor list */ 68*91b2ecf6Smpi int ds_unit; /* [I] D_CLONE unique unit */ 69*91b2ecf6Smpi pid_t ds_pid; /* [I] PID of tracing program */ 70*91b2ecf6Smpi 71*91b2ecf6Smpi struct mutex ds_mtx; 72*91b2ecf6Smpi 73*91b2ecf6Smpi struct dt_pcb_list ds_pcbs; /* [k] list of enabled PCBs */ 74*91b2ecf6Smpi struct dt_evt *ds_bufqueue; /* [k] copy evts to userland */ 75*91b2ecf6Smpi size_t ds_bufqlen; /* [k] length of the queue */ 76*91b2ecf6Smpi int ds_recording; /* [k] currently recording? */ 77*91b2ecf6Smpi int ds_evtcnt; /* [m] # of readable evts */ 78*91b2ecf6Smpi 79*91b2ecf6Smpi /* Counters */ 80*91b2ecf6Smpi uint64_t ds_readevt; /* [m] # of events read */ 81*91b2ecf6Smpi uint64_t ds_dropevt; /* [m] # of events dropped */ 82*91b2ecf6Smpi }; 83*91b2ecf6Smpi 84*91b2ecf6Smpi SLIST_HEAD(, dt_softc) dtdev_list; /* [k] list of open /dev/dt nodes */ 85*91b2ecf6Smpi 86*91b2ecf6Smpi /* 87*91b2ecf6Smpi * Probes are created during dt_attach() and never modified/freed during 88*91b2ecf6Smpi * the lifetime of the system. That's why we consider them as [I]mmutable. 89*91b2ecf6Smpi */ 90*91b2ecf6Smpi unsigned int dt_nprobes; /* [I] # of probes available */ 91*91b2ecf6Smpi SIMPLEQ_HEAD(, dt_probe) dt_probe_list; /* [I] list of probes */ 92*91b2ecf6Smpi 93*91b2ecf6Smpi struct rwlock dt_lock = RWLOCK_INITIALIZER("dtlk"); 94*91b2ecf6Smpi volatile uint32_t dt_tracing = 0; /* [d] # of processes tracing */ 95*91b2ecf6Smpi 96*91b2ecf6Smpi void dtattach(struct device *, struct device *, void *); 97*91b2ecf6Smpi int dtopen(dev_t, int, int, struct proc *); 98*91b2ecf6Smpi int dtclose(dev_t, int, int, struct proc *); 99*91b2ecf6Smpi int dtread(dev_t, struct uio *, int); 100*91b2ecf6Smpi int dtioctl(dev_t, u_long, caddr_t, int, struct proc *); 101*91b2ecf6Smpi 102*91b2ecf6Smpi struct dt_softc *dtlookup(int); 103*91b2ecf6Smpi 104*91b2ecf6Smpi int dt_ioctl_list_probes(struct dt_softc *, struct dtioc_probe *); 105*91b2ecf6Smpi int dt_ioctl_get_stats(struct dt_softc *, struct dtioc_stat *); 106*91b2ecf6Smpi int dt_ioctl_record_start(struct dt_softc *); 107*91b2ecf6Smpi void dt_ioctl_record_stop(struct dt_softc *); 108*91b2ecf6Smpi int dt_ioctl_probe_enable(struct dt_softc *, struct dtioc_req *); 109*91b2ecf6Smpi void dt_ioctl_probe_disable(struct dt_softc *, struct dtioc_req *); 110*91b2ecf6Smpi 111*91b2ecf6Smpi int dt_enter(void); 112*91b2ecf6Smpi void dt_leave(uint32_t); 113*91b2ecf6Smpi 114*91b2ecf6Smpi int dt_pcb_ring_copy(struct dt_pcb *, struct dt_evt *, size_t, uint64_t *); 115*91b2ecf6Smpi 116*91b2ecf6Smpi void 117*91b2ecf6Smpi dtattach(struct device *parent, struct device *self, void *aux) 118*91b2ecf6Smpi { 119*91b2ecf6Smpi SLIST_INIT(&dtdev_list); 120*91b2ecf6Smpi SIMPLEQ_INIT(&dt_probe_list); 121*91b2ecf6Smpi 122*91b2ecf6Smpi /* Init providers */ 123*91b2ecf6Smpi dt_nprobes += dt_prov_profile_init(); 124*91b2ecf6Smpi dt_nprobes += dt_prov_syscall_init(); 125*91b2ecf6Smpi dt_nprobes += dt_prov_static_init(); 126*91b2ecf6Smpi 127*91b2ecf6Smpi printf("dt: %u probes\n", dt_nprobes); 128*91b2ecf6Smpi } 129*91b2ecf6Smpi 130*91b2ecf6Smpi int 131*91b2ecf6Smpi dtopen(dev_t dev, int flags, int mode, struct proc *p) 132*91b2ecf6Smpi { 133*91b2ecf6Smpi struct dt_softc *sc; 134*91b2ecf6Smpi int unit = minor(dev); 135*91b2ecf6Smpi 136*91b2ecf6Smpi KASSERT(dtlookup(unit) == NULL); 137*91b2ecf6Smpi 138*91b2ecf6Smpi sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_CANFAIL|M_ZERO); 139*91b2ecf6Smpi if (sc == NULL) 140*91b2ecf6Smpi return ENOMEM; 141*91b2ecf6Smpi 142*91b2ecf6Smpi /* 143*91b2ecf6Smpi * Enough space to empty 2 full rings of events in a single read. 144*91b2ecf6Smpi */ 145*91b2ecf6Smpi sc->ds_bufqlen = 2 * DT_EVTRING_SIZE; 146*91b2ecf6Smpi sc->ds_bufqueue = mallocarray(sc->ds_bufqlen, sizeof(*sc->ds_bufqueue), 147*91b2ecf6Smpi M_DEVBUF, M_WAITOK|M_CANFAIL); 148*91b2ecf6Smpi if (sc->ds_bufqueue == NULL) 149*91b2ecf6Smpi goto bad; 150*91b2ecf6Smpi 151*91b2ecf6Smpi sc->ds_unit = unit; 152*91b2ecf6Smpi sc->ds_pid = p->p_p->ps_pid; 153*91b2ecf6Smpi TAILQ_INIT(&sc->ds_pcbs); 154*91b2ecf6Smpi mtx_init(&sc->ds_mtx, IPL_HIGH); 155*91b2ecf6Smpi sc->ds_evtcnt = 0; 156*91b2ecf6Smpi sc->ds_readevt = 0; 157*91b2ecf6Smpi sc->ds_dropevt = 0; 158*91b2ecf6Smpi 159*91b2ecf6Smpi SLIST_INSERT_HEAD(&dtdev_list, sc, ds_next); 160*91b2ecf6Smpi 161*91b2ecf6Smpi DPRINTF("dt%d: pid %d open\n", sc->ds_unit, sc->ds_pid); 162*91b2ecf6Smpi 163*91b2ecf6Smpi return 0; 164*91b2ecf6Smpi 165*91b2ecf6Smpi bad: 166*91b2ecf6Smpi free(sc, M_DEVBUF, sizeof(*sc)); 167*91b2ecf6Smpi return ENOMEM; 168*91b2ecf6Smpi } 169*91b2ecf6Smpi 170*91b2ecf6Smpi int 171*91b2ecf6Smpi dtclose(dev_t dev, int flags, int mode, struct proc *p) 172*91b2ecf6Smpi { 173*91b2ecf6Smpi struct dt_softc *sc; 174*91b2ecf6Smpi int unit = minor(dev); 175*91b2ecf6Smpi 176*91b2ecf6Smpi sc = dtlookup(unit); 177*91b2ecf6Smpi KASSERT(sc != NULL); 178*91b2ecf6Smpi 179*91b2ecf6Smpi DPRINTF("dt%d: pid %d close\n", sc->ds_unit, sc->ds_pid); 180*91b2ecf6Smpi 181*91b2ecf6Smpi SLIST_REMOVE(&dtdev_list, sc, dt_softc, ds_next); 182*91b2ecf6Smpi dt_ioctl_record_stop(sc); 183*91b2ecf6Smpi dt_pcb_purge(&sc->ds_pcbs); 184*91b2ecf6Smpi 185*91b2ecf6Smpi free(sc->ds_bufqueue, M_DEVBUF, 186*91b2ecf6Smpi sc->ds_bufqlen * sizeof(*sc->ds_bufqueue)); 187*91b2ecf6Smpi free(sc, M_DEVBUF, sizeof(*sc)); 188*91b2ecf6Smpi 189*91b2ecf6Smpi return 0; 190*91b2ecf6Smpi } 191*91b2ecf6Smpi 192*91b2ecf6Smpi int 193*91b2ecf6Smpi dtread(dev_t dev, struct uio *uio, int flags) 194*91b2ecf6Smpi { 195*91b2ecf6Smpi struct dt_softc *sc; 196*91b2ecf6Smpi struct dt_evt *estq; 197*91b2ecf6Smpi struct dt_pcb *dp; 198*91b2ecf6Smpi int error, unit = minor(dev); 199*91b2ecf6Smpi size_t qlen, count, read = 0; 200*91b2ecf6Smpi uint64_t dropped = 0; 201*91b2ecf6Smpi 202*91b2ecf6Smpi sc = dtlookup(unit); 203*91b2ecf6Smpi KASSERT(sc != NULL); 204*91b2ecf6Smpi 205*91b2ecf6Smpi count = howmany(uio->uio_resid, sizeof(struct dt_evt)); 206*91b2ecf6Smpi if (count < 1) 207*91b2ecf6Smpi return (EMSGSIZE); 208*91b2ecf6Smpi 209*91b2ecf6Smpi mtx_enter(&sc->ds_mtx); 210*91b2ecf6Smpi while (!sc->ds_evtcnt) { 211*91b2ecf6Smpi error = msleep(sc, &sc->ds_mtx, PWAIT|PCATCH, "dtread", 0); 212*91b2ecf6Smpi if (error == EINTR || error == ERESTART) 213*91b2ecf6Smpi break; 214*91b2ecf6Smpi } 215*91b2ecf6Smpi mtx_leave(&sc->ds_mtx); 216*91b2ecf6Smpi 217*91b2ecf6Smpi if (error) 218*91b2ecf6Smpi return error; 219*91b2ecf6Smpi 220*91b2ecf6Smpi estq = sc->ds_bufqueue; 221*91b2ecf6Smpi qlen = MIN(sc->ds_bufqlen, count); 222*91b2ecf6Smpi 223*91b2ecf6Smpi KERNEL_ASSERT_LOCKED(); 224*91b2ecf6Smpi TAILQ_FOREACH(dp, &sc->ds_pcbs, dp_snext) { 225*91b2ecf6Smpi count = dt_pcb_ring_copy(dp, estq, qlen, &dropped); 226*91b2ecf6Smpi read += count; 227*91b2ecf6Smpi estq += count; /* pointer aritmetic */ 228*91b2ecf6Smpi qlen -= count; 229*91b2ecf6Smpi if (qlen == 0) 230*91b2ecf6Smpi break; 231*91b2ecf6Smpi } 232*91b2ecf6Smpi if (read > 0) 233*91b2ecf6Smpi uiomove(sc->ds_bufqueue, read * sizeof(struct dt_evt), uio); 234*91b2ecf6Smpi 235*91b2ecf6Smpi mtx_enter(&sc->ds_mtx); 236*91b2ecf6Smpi sc->ds_evtcnt -= read; 237*91b2ecf6Smpi sc->ds_readevt += read; 238*91b2ecf6Smpi sc->ds_dropevt += dropped; 239*91b2ecf6Smpi mtx_leave(&sc->ds_mtx); 240*91b2ecf6Smpi 241*91b2ecf6Smpi return 0; 242*91b2ecf6Smpi } 243*91b2ecf6Smpi 244*91b2ecf6Smpi int 245*91b2ecf6Smpi dtioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) 246*91b2ecf6Smpi { 247*91b2ecf6Smpi struct dt_softc *sc; 248*91b2ecf6Smpi int unit = minor(dev); 249*91b2ecf6Smpi int on, error = 0; 250*91b2ecf6Smpi 251*91b2ecf6Smpi sc = dtlookup(unit); 252*91b2ecf6Smpi KASSERT(sc != NULL); 253*91b2ecf6Smpi 254*91b2ecf6Smpi switch (cmd) { 255*91b2ecf6Smpi case DTIOCGPLIST: 256*91b2ecf6Smpi return dt_ioctl_list_probes(sc, (struct dtioc_probe *)addr); 257*91b2ecf6Smpi case DTIOCGSTATS: 258*91b2ecf6Smpi return dt_ioctl_get_stats(sc, (struct dtioc_stat *)addr); 259*91b2ecf6Smpi case DTIOCRECORD: 260*91b2ecf6Smpi case DTIOCPRBENABLE: 261*91b2ecf6Smpi /* root only ioctl(2) */ 262*91b2ecf6Smpi break; 263*91b2ecf6Smpi default: 264*91b2ecf6Smpi return ENOTTY; 265*91b2ecf6Smpi } 266*91b2ecf6Smpi 267*91b2ecf6Smpi if ((error = suser(p)) != 0) 268*91b2ecf6Smpi return error; 269*91b2ecf6Smpi 270*91b2ecf6Smpi switch (cmd) { 271*91b2ecf6Smpi case DTIOCRECORD: 272*91b2ecf6Smpi on = *(int *)addr; 273*91b2ecf6Smpi if (on) 274*91b2ecf6Smpi error = dt_ioctl_record_start(sc); 275*91b2ecf6Smpi else 276*91b2ecf6Smpi dt_ioctl_record_stop(sc); 277*91b2ecf6Smpi break; 278*91b2ecf6Smpi case DTIOCPRBENABLE: 279*91b2ecf6Smpi error = dt_ioctl_probe_enable(sc, (struct dtioc_req *)addr); 280*91b2ecf6Smpi break; 281*91b2ecf6Smpi default: 282*91b2ecf6Smpi KASSERT(0); 283*91b2ecf6Smpi } 284*91b2ecf6Smpi 285*91b2ecf6Smpi return error; 286*91b2ecf6Smpi } 287*91b2ecf6Smpi 288*91b2ecf6Smpi struct dt_softc * 289*91b2ecf6Smpi dtlookup(int unit) 290*91b2ecf6Smpi { 291*91b2ecf6Smpi struct dt_softc *sc; 292*91b2ecf6Smpi 293*91b2ecf6Smpi KERNEL_ASSERT_LOCKED(); 294*91b2ecf6Smpi 295*91b2ecf6Smpi SLIST_FOREACH(sc, &dtdev_list, ds_next) { 296*91b2ecf6Smpi if (sc->ds_unit == unit) 297*91b2ecf6Smpi break; 298*91b2ecf6Smpi } 299*91b2ecf6Smpi 300*91b2ecf6Smpi return sc; 301*91b2ecf6Smpi } 302*91b2ecf6Smpi 303*91b2ecf6Smpi int 304*91b2ecf6Smpi dtioc_req_isvalid(struct dtioc_req *dtrq) 305*91b2ecf6Smpi { 306*91b2ecf6Smpi switch (dtrq->dtrq_filter.dtf_operand) { 307*91b2ecf6Smpi case DT_OP_NONE: 308*91b2ecf6Smpi case DT_OP_EQ: 309*91b2ecf6Smpi case DT_OP_NE: 310*91b2ecf6Smpi break; 311*91b2ecf6Smpi default: 312*91b2ecf6Smpi return 0; 313*91b2ecf6Smpi } 314*91b2ecf6Smpi 315*91b2ecf6Smpi switch (dtrq->dtrq_filter.dtf_variable) { 316*91b2ecf6Smpi case DT_FV_NONE: 317*91b2ecf6Smpi case DT_FV_PID: 318*91b2ecf6Smpi case DT_FV_TID: 319*91b2ecf6Smpi break; 320*91b2ecf6Smpi default: 321*91b2ecf6Smpi return 0; 322*91b2ecf6Smpi } 323*91b2ecf6Smpi 324*91b2ecf6Smpi return 1; 325*91b2ecf6Smpi } 326*91b2ecf6Smpi 327*91b2ecf6Smpi int 328*91b2ecf6Smpi dt_ioctl_list_probes(struct dt_softc *sc, struct dtioc_probe *dtpr) 329*91b2ecf6Smpi { 330*91b2ecf6Smpi struct dtioc_probe_info info, *dtpi; 331*91b2ecf6Smpi struct dt_probe *dtp; 332*91b2ecf6Smpi size_t size; 333*91b2ecf6Smpi int error = 0; 334*91b2ecf6Smpi 335*91b2ecf6Smpi if (dtpr->dtpr_size == 0) { 336*91b2ecf6Smpi dtpr->dtpr_size = dt_nprobes * sizeof(*dtpi); 337*91b2ecf6Smpi return 0; 338*91b2ecf6Smpi } 339*91b2ecf6Smpi 340*91b2ecf6Smpi size = dtpr->dtpr_size; 341*91b2ecf6Smpi dtpi = dtpr->dtpr_probes; 342*91b2ecf6Smpi memset(&info, 0, sizeof(info)); 343*91b2ecf6Smpi SIMPLEQ_FOREACH(dtp, &dt_probe_list, dtp_next) { 344*91b2ecf6Smpi if (size < sizeof(*dtpi)) { 345*91b2ecf6Smpi error = ENOSPC; 346*91b2ecf6Smpi break; 347*91b2ecf6Smpi } 348*91b2ecf6Smpi info.dtpi_pbn = dtp->dtp_pbn; 349*91b2ecf6Smpi strlcpy(info.dtpi_prov, dtp->dtp_prov->dtpv_name, 350*91b2ecf6Smpi sizeof(info.dtpi_prov)); 351*91b2ecf6Smpi strlcpy(info.dtpi_func, dtp->dtp_func, sizeof(info.dtpi_func)); 352*91b2ecf6Smpi strlcpy(info.dtpi_name, dtp->dtp_name, sizeof(info.dtpi_name)); 353*91b2ecf6Smpi error = copyout(&info, dtpi, sizeof(*dtpi)); 354*91b2ecf6Smpi if (error) 355*91b2ecf6Smpi break; 356*91b2ecf6Smpi size -= sizeof(*dtpi); 357*91b2ecf6Smpi dtpi++; 358*91b2ecf6Smpi }; 359*91b2ecf6Smpi 360*91b2ecf6Smpi return error; 361*91b2ecf6Smpi } 362*91b2ecf6Smpi 363*91b2ecf6Smpi int 364*91b2ecf6Smpi dt_ioctl_get_stats(struct dt_softc *sc, struct dtioc_stat *dtst) 365*91b2ecf6Smpi { 366*91b2ecf6Smpi mtx_enter(&sc->ds_mtx); 367*91b2ecf6Smpi dtst->dtst_readevt = sc->ds_readevt; 368*91b2ecf6Smpi dtst->dtst_dropevt = sc->ds_dropevt; 369*91b2ecf6Smpi mtx_leave(&sc->ds_mtx); 370*91b2ecf6Smpi 371*91b2ecf6Smpi return 0; 372*91b2ecf6Smpi } 373*91b2ecf6Smpi 374*91b2ecf6Smpi int 375*91b2ecf6Smpi dt_ioctl_record_start(struct dt_softc *sc) 376*91b2ecf6Smpi { 377*91b2ecf6Smpi struct dt_pcb *dp; 378*91b2ecf6Smpi int count; 379*91b2ecf6Smpi 380*91b2ecf6Smpi if (sc->ds_recording) 381*91b2ecf6Smpi return EBUSY; 382*91b2ecf6Smpi 383*91b2ecf6Smpi KERNEL_ASSERT_LOCKED(); 384*91b2ecf6Smpi if (TAILQ_EMPTY(&sc->ds_pcbs)) 385*91b2ecf6Smpi return ENOENT; 386*91b2ecf6Smpi 387*91b2ecf6Smpi count = dt_enter(); 388*91b2ecf6Smpi TAILQ_FOREACH(dp, &sc->ds_pcbs, dp_snext) { 389*91b2ecf6Smpi struct dt_probe *dtp = dp->dp_dtp; 390*91b2ecf6Smpi 391*91b2ecf6Smpi rw_assert_wrlock(&dt_lock); 392*91b2ecf6Smpi SMR_SLIST_INSERT_HEAD_LOCKED(&dtp->dtp_pcbs, dp, dp_pnext); 393*91b2ecf6Smpi dtp->dtp_recording++; 394*91b2ecf6Smpi dtp->dtp_prov->dtpv_recording++; 395*91b2ecf6Smpi } 396*91b2ecf6Smpi dt_leave(count); 397*91b2ecf6Smpi 398*91b2ecf6Smpi sc->ds_recording = 1; 399*91b2ecf6Smpi dt_tracing++; 400*91b2ecf6Smpi 401*91b2ecf6Smpi return 0; 402*91b2ecf6Smpi } 403*91b2ecf6Smpi 404*91b2ecf6Smpi void 405*91b2ecf6Smpi dt_ioctl_record_stop(struct dt_softc *sc) 406*91b2ecf6Smpi { 407*91b2ecf6Smpi struct dt_pcb *dp; 408*91b2ecf6Smpi int count; 409*91b2ecf6Smpi 410*91b2ecf6Smpi KASSERT(suser(curproc) == 0); 411*91b2ecf6Smpi 412*91b2ecf6Smpi if (!sc->ds_recording) 413*91b2ecf6Smpi return; 414*91b2ecf6Smpi 415*91b2ecf6Smpi DPRINTF("dt%d: pid %d disable\n", sc->ds_unit, sc->ds_pid); 416*91b2ecf6Smpi 417*91b2ecf6Smpi dt_tracing--; 418*91b2ecf6Smpi sc->ds_recording = 0; 419*91b2ecf6Smpi 420*91b2ecf6Smpi count = dt_enter(); 421*91b2ecf6Smpi TAILQ_FOREACH(dp, &sc->ds_pcbs, dp_snext) { 422*91b2ecf6Smpi struct dt_probe *dtp = dp->dp_dtp; 423*91b2ecf6Smpi 424*91b2ecf6Smpi rw_assert_wrlock(&dt_lock); 425*91b2ecf6Smpi dtp->dtp_recording--; 426*91b2ecf6Smpi dtp->dtp_prov->dtpv_recording--; 427*91b2ecf6Smpi SMR_SLIST_REMOVE_LOCKED(&dtp->dtp_pcbs, dp, dt_pcb, dp_pnext); 428*91b2ecf6Smpi } 429*91b2ecf6Smpi dt_leave(count); 430*91b2ecf6Smpi } 431*91b2ecf6Smpi 432*91b2ecf6Smpi int 433*91b2ecf6Smpi dt_ioctl_probe_enable(struct dt_softc *sc, struct dtioc_req *dtrq) 434*91b2ecf6Smpi { 435*91b2ecf6Smpi struct dt_pcb_list plist; 436*91b2ecf6Smpi struct dt_probe *dtp; 437*91b2ecf6Smpi struct dt_pcb *dp; 438*91b2ecf6Smpi int error; 439*91b2ecf6Smpi 440*91b2ecf6Smpi KASSERT(suser(curproc) == 0); 441*91b2ecf6Smpi 442*91b2ecf6Smpi if (!dtioc_req_isvalid(dtrq)) 443*91b2ecf6Smpi return EINVAL; 444*91b2ecf6Smpi 445*91b2ecf6Smpi SIMPLEQ_FOREACH(dtp, &dt_probe_list, dtp_next) { 446*91b2ecf6Smpi if (dtp->dtp_pbn == dtrq->dtrq_pbn) 447*91b2ecf6Smpi break; 448*91b2ecf6Smpi } 449*91b2ecf6Smpi if (dtp == NULL) 450*91b2ecf6Smpi return ENOENT; 451*91b2ecf6Smpi 452*91b2ecf6Smpi TAILQ_INIT(&plist); 453*91b2ecf6Smpi error = dtp->dtp_prov->dtpv_alloc(dtp, sc, &plist, dtrq); 454*91b2ecf6Smpi if (error) 455*91b2ecf6Smpi return error; 456*91b2ecf6Smpi 457*91b2ecf6Smpi DPRINTF("dt%d: pid %d enable %u : %b\n", sc->ds_unit, sc->ds_pid, 458*91b2ecf6Smpi dtrq->dtrq_pbn, (unsigned int)dtrq->dtrq_evtflags, DTEVT_FLAG_BITS); 459*91b2ecf6Smpi 460*91b2ecf6Smpi /* Append all PCBs to this instance */ 461*91b2ecf6Smpi while ((dp = TAILQ_FIRST(&plist)) != NULL) { 462*91b2ecf6Smpi TAILQ_REMOVE(&plist, dp, dp_snext); 463*91b2ecf6Smpi TAILQ_INSERT_HEAD(&sc->ds_pcbs, dp, dp_snext); 464*91b2ecf6Smpi } 465*91b2ecf6Smpi 466*91b2ecf6Smpi return 0; 467*91b2ecf6Smpi } 468*91b2ecf6Smpi 469*91b2ecf6Smpi int 470*91b2ecf6Smpi dt_enter(void) 471*91b2ecf6Smpi { 472*91b2ecf6Smpi uint32_t count; 473*91b2ecf6Smpi 474*91b2ecf6Smpi rw_enter_write(&dt_lock); 475*91b2ecf6Smpi count = dt_tracing; 476*91b2ecf6Smpi dt_tracing = 0; 477*91b2ecf6Smpi 478*91b2ecf6Smpi smr_barrier(); 479*91b2ecf6Smpi 480*91b2ecf6Smpi return count; 481*91b2ecf6Smpi } 482*91b2ecf6Smpi 483*91b2ecf6Smpi void 484*91b2ecf6Smpi dt_leave(uint32_t count) 485*91b2ecf6Smpi { 486*91b2ecf6Smpi dt_tracing = count; 487*91b2ecf6Smpi rw_exit_write(&dt_lock); 488*91b2ecf6Smpi } 489*91b2ecf6Smpi 490*91b2ecf6Smpi struct dt_probe * 491*91b2ecf6Smpi dt_dev_alloc_probe(const char *func, const char *name, struct dt_provider *dtpv) 492*91b2ecf6Smpi { 493*91b2ecf6Smpi struct dt_probe *dtp; 494*91b2ecf6Smpi 495*91b2ecf6Smpi dtp = malloc(sizeof(*dtp), M_DT, M_NOWAIT|M_ZERO); 496*91b2ecf6Smpi if (dtp == NULL) 497*91b2ecf6Smpi return NULL; 498*91b2ecf6Smpi 499*91b2ecf6Smpi SMR_SLIST_INIT(&dtp->dtp_pcbs); 500*91b2ecf6Smpi dtp->dtp_prov = dtpv; 501*91b2ecf6Smpi dtp->dtp_func = func; 502*91b2ecf6Smpi dtp->dtp_name = name; 503*91b2ecf6Smpi dtp->dtp_sysnum = -1; 504*91b2ecf6Smpi 505*91b2ecf6Smpi return dtp; 506*91b2ecf6Smpi } 507*91b2ecf6Smpi 508*91b2ecf6Smpi void 509*91b2ecf6Smpi dt_dev_register_probe(struct dt_probe *dtp) 510*91b2ecf6Smpi { 511*91b2ecf6Smpi static uint64_t probe_nb; 512*91b2ecf6Smpi 513*91b2ecf6Smpi dtp->dtp_pbn = ++probe_nb; 514*91b2ecf6Smpi SIMPLEQ_INSERT_TAIL(&dt_probe_list, dtp, dtp_next); 515*91b2ecf6Smpi } 516*91b2ecf6Smpi 517*91b2ecf6Smpi struct dt_pcb * 518*91b2ecf6Smpi dt_pcb_alloc(struct dt_probe *dtp, struct dt_softc *sc) 519*91b2ecf6Smpi { 520*91b2ecf6Smpi struct dt_pcb *dp; 521*91b2ecf6Smpi 522*91b2ecf6Smpi dp = malloc(sizeof(*dp), M_DT, M_WAITOK|M_CANFAIL|M_ZERO); 523*91b2ecf6Smpi if (dp == NULL) 524*91b2ecf6Smpi goto bad; 525*91b2ecf6Smpi 526*91b2ecf6Smpi dp->dp_ring = mallocarray(DT_EVTRING_SIZE, sizeof(*dp->dp_ring), M_DT, 527*91b2ecf6Smpi M_WAITOK|M_CANFAIL|M_ZERO); 528*91b2ecf6Smpi if (dp->dp_ring == NULL) 529*91b2ecf6Smpi goto bad; 530*91b2ecf6Smpi 531*91b2ecf6Smpi mtx_init(&dp->dp_mtx, IPL_HIGH); 532*91b2ecf6Smpi dp->dp_sc = sc; 533*91b2ecf6Smpi dp->dp_dtp = dtp; 534*91b2ecf6Smpi return dp; 535*91b2ecf6Smpi bad: 536*91b2ecf6Smpi dt_pcb_free(dp); 537*91b2ecf6Smpi return NULL; 538*91b2ecf6Smpi } 539*91b2ecf6Smpi 540*91b2ecf6Smpi void 541*91b2ecf6Smpi dt_pcb_free(struct dt_pcb *dp) 542*91b2ecf6Smpi { 543*91b2ecf6Smpi if (dp == NULL) 544*91b2ecf6Smpi return; 545*91b2ecf6Smpi free(dp->dp_ring, M_DT, DT_EVTRING_SIZE * sizeof(*dp->dp_ring)); 546*91b2ecf6Smpi free(dp, M_DT, sizeof(*dp)); 547*91b2ecf6Smpi } 548*91b2ecf6Smpi 549*91b2ecf6Smpi void 550*91b2ecf6Smpi dt_pcb_purge(struct dt_pcb_list *plist) 551*91b2ecf6Smpi { 552*91b2ecf6Smpi struct dt_pcb *dp; 553*91b2ecf6Smpi 554*91b2ecf6Smpi while ((dp = TAILQ_FIRST(plist)) != NULL) { 555*91b2ecf6Smpi TAILQ_REMOVE(plist, dp, dp_snext); 556*91b2ecf6Smpi dt_pcb_free(dp); 557*91b2ecf6Smpi } 558*91b2ecf6Smpi } 559*91b2ecf6Smpi 560*91b2ecf6Smpi int 561*91b2ecf6Smpi dt_pcb_filter(struct dt_pcb *dp) 562*91b2ecf6Smpi { 563*91b2ecf6Smpi struct dt_filter *dtf = &dp->dp_filter; 564*91b2ecf6Smpi struct proc *p = curproc; 565*91b2ecf6Smpi unsigned int var; 566*91b2ecf6Smpi int match = 1; 567*91b2ecf6Smpi 568*91b2ecf6Smpi /* Filter out tracing program. */ 569*91b2ecf6Smpi if (dp->dp_sc->ds_pid == p->p_p->ps_pid) 570*91b2ecf6Smpi return 1; 571*91b2ecf6Smpi 572*91b2ecf6Smpi switch (dtf->dtf_variable) { 573*91b2ecf6Smpi case DT_FV_PID: 574*91b2ecf6Smpi var = p->p_p->ps_pid; 575*91b2ecf6Smpi break; 576*91b2ecf6Smpi case DT_FV_TID: 577*91b2ecf6Smpi var = p->p_tid; 578*91b2ecf6Smpi break; 579*91b2ecf6Smpi case DT_FV_NONE: 580*91b2ecf6Smpi break; 581*91b2ecf6Smpi default: 582*91b2ecf6Smpi KASSERT(0); 583*91b2ecf6Smpi } 584*91b2ecf6Smpi 585*91b2ecf6Smpi switch (dtf->dtf_operand) { 586*91b2ecf6Smpi case DT_OP_EQ: 587*91b2ecf6Smpi match = !!(var == dtf->dtf_value); 588*91b2ecf6Smpi break; 589*91b2ecf6Smpi case DT_OP_NE: 590*91b2ecf6Smpi match = !!(var != dtf->dtf_value); 591*91b2ecf6Smpi break; 592*91b2ecf6Smpi case DT_OP_NONE: 593*91b2ecf6Smpi break; 594*91b2ecf6Smpi default: 595*91b2ecf6Smpi KASSERT(0); 596*91b2ecf6Smpi } 597*91b2ecf6Smpi 598*91b2ecf6Smpi return !match; 599*91b2ecf6Smpi } 600*91b2ecf6Smpi 601*91b2ecf6Smpi 602*91b2ecf6Smpi /* 603*91b2ecf6Smpi * Get a reference to the next free event state from the ring. 604*91b2ecf6Smpi */ 605*91b2ecf6Smpi struct dt_evt * 606*91b2ecf6Smpi dt_pcb_ring_get(struct dt_pcb *dp) 607*91b2ecf6Smpi { 608*91b2ecf6Smpi struct proc *p = curproc; 609*91b2ecf6Smpi struct dt_evt *dtev; 610*91b2ecf6Smpi int distance; 611*91b2ecf6Smpi 612*91b2ecf6Smpi if (dt_pcb_filter(dp)) 613*91b2ecf6Smpi return NULL; 614*91b2ecf6Smpi 615*91b2ecf6Smpi mtx_enter(&dp->dp_mtx); 616*91b2ecf6Smpi distance = dp->dp_prod - dp->dp_cons; 617*91b2ecf6Smpi if (distance == 1 || distance == (1 - DT_EVTRING_SIZE)) { 618*91b2ecf6Smpi /* read(2) isn't finished */ 619*91b2ecf6Smpi dp->dp_dropevt++; 620*91b2ecf6Smpi mtx_leave(&dp->dp_mtx); 621*91b2ecf6Smpi return NULL; 622*91b2ecf6Smpi } 623*91b2ecf6Smpi 624*91b2ecf6Smpi /* 625*91b2ecf6Smpi * Save states in next free event slot. 626*91b2ecf6Smpi */ 627*91b2ecf6Smpi dtev = &dp->dp_ring[dp->dp_cons]; 628*91b2ecf6Smpi memset(dtev, 0, sizeof(*dtev)); 629*91b2ecf6Smpi 630*91b2ecf6Smpi dtev->dtev_pbn = dp->dp_dtp->dtp_pbn; 631*91b2ecf6Smpi dtev->dtev_cpu = cpu_number(); 632*91b2ecf6Smpi dtev->dtev_pid = p->p_p->ps_pid; 633*91b2ecf6Smpi dtev->dtev_tid = p->p_tid; 634*91b2ecf6Smpi nanotime(&dtev->dtev_tsp); 635*91b2ecf6Smpi 636*91b2ecf6Smpi if (ISSET(dp->dp_evtflags, DTEVT_EXECNAME)) 637*91b2ecf6Smpi memcpy(dtev->dtev_comm, p->p_p->ps_comm, DTMAXCOMLEN - 1); 638*91b2ecf6Smpi 639*91b2ecf6Smpi if (ISSET(dp->dp_evtflags, DTEVT_KSTACK|DTEVT_USTACK)) { 640*91b2ecf6Smpi #if notyet 641*91b2ecf6Smpi stacktrace_save_at(&dtev->dtev_kstack, DT_HOOK_FRAME_ADDRESS); 642*91b2ecf6Smpi #else 643*91b2ecf6Smpi stacktrace_save(&dtev->dtev_kstack); 644*91b2ecf6Smpi #endif 645*91b2ecf6Smpi } 646*91b2ecf6Smpi 647*91b2ecf6Smpi return dtev; 648*91b2ecf6Smpi } 649*91b2ecf6Smpi 650*91b2ecf6Smpi void 651*91b2ecf6Smpi dt_pcb_ring_consume(struct dt_pcb *dp, struct dt_evt *dtev) 652*91b2ecf6Smpi { 653*91b2ecf6Smpi MUTEX_ASSERT_LOCKED(&dp->dp_mtx); 654*91b2ecf6Smpi KASSERT(dtev == &dp->dp_ring[dp->dp_cons]); 655*91b2ecf6Smpi 656*91b2ecf6Smpi dp->dp_cons = (dp->dp_cons + 1) % DT_EVTRING_SIZE; 657*91b2ecf6Smpi mtx_leave(&dp->dp_mtx); 658*91b2ecf6Smpi 659*91b2ecf6Smpi mtx_enter(&dp->dp_sc->ds_mtx); 660*91b2ecf6Smpi dp->dp_sc->ds_evtcnt++; 661*91b2ecf6Smpi mtx_leave(&dp->dp_sc->ds_mtx); 662*91b2ecf6Smpi wakeup(dp->dp_sc); 663*91b2ecf6Smpi } 664*91b2ecf6Smpi 665*91b2ecf6Smpi /* 666*91b2ecf6Smpi * Copy at most `qlen' events from `dp', producing the same amount 667*91b2ecf6Smpi * of free slots. 668*91b2ecf6Smpi */ 669*91b2ecf6Smpi int 670*91b2ecf6Smpi dt_pcb_ring_copy(struct dt_pcb *dp, struct dt_evt *estq, size_t qlen, 671*91b2ecf6Smpi uint64_t *dropped) 672*91b2ecf6Smpi { 673*91b2ecf6Smpi size_t count, copied = 0; 674*91b2ecf6Smpi unsigned int cons, prod; 675*91b2ecf6Smpi 676*91b2ecf6Smpi KASSERT(qlen > 0); 677*91b2ecf6Smpi 678*91b2ecf6Smpi mtx_enter(&dp->dp_mtx); 679*91b2ecf6Smpi cons = dp->dp_cons; 680*91b2ecf6Smpi prod = dp->dp_prod; 681*91b2ecf6Smpi 682*91b2ecf6Smpi if (cons < prod) 683*91b2ecf6Smpi count = DT_EVTRING_SIZE - prod; 684*91b2ecf6Smpi else 685*91b2ecf6Smpi count = cons - prod; 686*91b2ecf6Smpi 687*91b2ecf6Smpi if (count == 0) 688*91b2ecf6Smpi goto out; 689*91b2ecf6Smpi 690*91b2ecf6Smpi *dropped += dp->dp_dropevt; 691*91b2ecf6Smpi dp->dp_dropevt = 0; 692*91b2ecf6Smpi 693*91b2ecf6Smpi count = MIN(count, qlen); 694*91b2ecf6Smpi 695*91b2ecf6Smpi memcpy(&estq[0], &dp->dp_ring[prod], count * sizeof(*estq)); 696*91b2ecf6Smpi copied += count; 697*91b2ecf6Smpi 698*91b2ecf6Smpi /* Produce */ 699*91b2ecf6Smpi prod = (prod + count) % DT_EVTRING_SIZE; 700*91b2ecf6Smpi 701*91b2ecf6Smpi /* If the queue is full or the ring didn't wrap, stop here. */ 702*91b2ecf6Smpi if (qlen == copied || prod != 0 || cons == 0) 703*91b2ecf6Smpi goto out; 704*91b2ecf6Smpi 705*91b2ecf6Smpi count = MIN(cons, (qlen - copied)); 706*91b2ecf6Smpi memcpy(&estq[copied], &dp->dp_ring[0], count * sizeof(*estq)); 707*91b2ecf6Smpi copied += count; 708*91b2ecf6Smpi prod += count; 709*91b2ecf6Smpi 710*91b2ecf6Smpi out: 711*91b2ecf6Smpi dp->dp_prod = prod; 712*91b2ecf6Smpi mtx_leave(&dp->dp_mtx); 713*91b2ecf6Smpi return copied; 714*91b2ecf6Smpi } 715