1 1.7 chs /* $NetBSD: dtrace_ioctl.c,v 1.7 2018/05/28 21:05:03 chs Exp $ */ 2 1.2 darran 3 1.1 darran /* 4 1.1 darran * CDDL HEADER START 5 1.1 darran * 6 1.1 darran * The contents of this file are subject to the terms of the 7 1.1 darran * Common Development and Distribution License (the "License"). 8 1.1 darran * You may not use this file except in compliance with the License. 9 1.1 darran * 10 1.1 darran * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 11 1.1 darran * or http://www.opensolaris.org/os/licensing. 12 1.1 darran * See the License for the specific language governing permissions 13 1.1 darran * and limitations under the License. 14 1.1 darran * 15 1.1 darran * When distributing Covered Code, include this CDDL HEADER in each 16 1.1 darran * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 17 1.1 darran * If applicable, add the following below this CDDL HEADER, with the 18 1.1 darran * fields enclosed by brackets "[]" replaced with your own identifying 19 1.1 darran * information: Portions Copyright [yyyy] [name of copyright owner] 20 1.1 darran * 21 1.1 darran * CDDL HEADER END 22 1.1 darran * 23 1.7 chs * $FreeBSD: head/sys/cddl/dev/dtrace/dtrace_ioctl.c 313262 2017-02-05 02:39:12Z markj $ 24 1.1 darran * 25 1.1 darran */ 26 1.1 darran 27 1.7 chs static int dtrace_verbose_ioctl; 28 1.7 chs SYSCTL_INT(_debug_dtrace, OID_AUTO, verbose_ioctl, CTLFLAG_RW, 29 1.7 chs &dtrace_verbose_ioctl, 0, "log DTrace ioctls"); 30 1.7 chs 31 1.7 chs #define pfind(pid) proc_find((pid)) 32 1.1 darran 33 1.1 darran #define DTRACE_IOCTL_PRINTF(fmt, ...) if (dtrace_verbose_ioctl) printf(fmt, ## __VA_ARGS__ ) 34 1.1 darran 35 1.7 chs #ifdef __FreeBSD__ 36 1.7 chs static int 37 1.7 chs dtrace_ioctl_helper(struct cdev *dev, u_long cmd, caddr_t addr, int flags, 38 1.7 chs struct thread *td) 39 1.7 chs #endif 40 1.7 chs #ifdef __NetBSD__ 41 1.7 chs static int 42 1.7 chs dtrace_ioctl_helper(dev_t dev, u_long cmd, caddr_t addr, int flags) 43 1.7 chs #endif 44 1.7 chs { 45 1.7 chs struct proc *p; 46 1.7 chs dof_helper_t *dhp; 47 1.7 chs dof_hdr_t *dof; 48 1.7 chs int rval; 49 1.7 chs 50 1.7 chs dhp = NULL; 51 1.7 chs dof = NULL; 52 1.7 chs rval = 0; 53 1.7 chs switch (cmd) { 54 1.7 chs case DTRACEHIOC_ADDDOF: 55 1.7 chs dhp = (dof_helper_t *)addr; 56 1.7 chs addr = (caddr_t)(uintptr_t)dhp->dofhp_dof; 57 1.7 chs p = curproc; 58 1.7 chs if (p->p_pid == dhp->dofhp_pid) { 59 1.7 chs dof = dtrace_dof_copyin((uintptr_t)addr, &rval); 60 1.7 chs } else { 61 1.7 chs #ifdef __FreeBSD__ 62 1.7 chs p = pfind(dhp->dofhp_pid); 63 1.7 chs if (p == NULL) 64 1.7 chs return (EINVAL); 65 1.7 chs if (!P_SHOULDSTOP(p) || 66 1.7 chs (p->p_flag & (P_TRACED | P_WEXIT)) != P_TRACED || 67 1.7 chs p->p_pptr != curproc) { 68 1.7 chs PROC_UNLOCK(p); 69 1.7 chs return (EINVAL); 70 1.7 chs } 71 1.7 chs _PHOLD(p); 72 1.7 chs PROC_UNLOCK(p); 73 1.7 chs dof = dtrace_dof_copyin_proc(p, (uintptr_t)addr, &rval); 74 1.7 chs #endif 75 1.7 chs #ifdef __NetBSD__ 76 1.7 chs dof = dtrace_dof_copyin_pid(dhp->dofhp_pid, addr, &rval); 77 1.7 chs #endif 78 1.7 chs } 79 1.7 chs 80 1.7 chs if (dof == NULL) { 81 1.7 chs #ifdef __FreeBSD__ 82 1.7 chs if (p != curproc) 83 1.7 chs PRELE(p); 84 1.7 chs #endif 85 1.7 chs break; 86 1.7 chs } 87 1.7 chs 88 1.7 chs mutex_enter(&dtrace_lock); 89 1.7 chs if ((rval = dtrace_helper_slurp(dof, dhp, p)) != -1) { 90 1.7 chs dhp->dofhp_gen = rval; 91 1.7 chs rval = 0; 92 1.7 chs } else { 93 1.7 chs rval = EINVAL; 94 1.7 chs } 95 1.7 chs mutex_exit(&dtrace_lock); 96 1.7 chs #ifdef __FreeBSD__ 97 1.7 chs if (p != curproc) 98 1.7 chs PRELE(p); 99 1.7 chs #endif 100 1.7 chs break; 101 1.7 chs case DTRACEHIOC_REMOVE: 102 1.7 chs mutex_enter(&dtrace_lock); 103 1.7 chs rval = dtrace_helper_destroygen(NULL, *(int *)(uintptr_t)addr); 104 1.7 chs mutex_exit(&dtrace_lock); 105 1.7 chs break; 106 1.7 chs default: 107 1.7 chs rval = ENOTTY; 108 1.7 chs break; 109 1.7 chs } 110 1.7 chs return (rval); 111 1.7 chs } 112 1.7 chs 113 1.1 darran /* ARGSUSED */ 114 1.7 chs #ifdef __FreeBSD__ 115 1.7 chs static int 116 1.7 chs dtrace_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, 117 1.7 chs int flags __unused, struct thread *td) 118 1.7 chs #endif 119 1.7 chs #ifdef __NetBSD__ 120 1.1 darran static int 121 1.2 darran dtrace_ioctl(struct file *fp, u_long cmd, void *addr) 122 1.7 chs #endif 123 1.1 darran { 124 1.2 darran dtrace_state_t *state = (dtrace_state_t *)fp->f_data; 125 1.1 darran int error = 0; 126 1.2 darran 127 1.1 darran if (state == NULL) 128 1.1 darran return (EINVAL); 129 1.1 darran 130 1.1 darran if (state->dts_anon) { 131 1.1 darran ASSERT(dtrace_anon.dta_state == NULL); 132 1.1 darran state = state->dts_anon; 133 1.1 darran } 134 1.1 darran 135 1.1 darran switch (cmd) { 136 1.1 darran case DTRACEIOC_AGGDESC: { 137 1.1 darran dtrace_aggdesc_t **paggdesc = (dtrace_aggdesc_t **) addr; 138 1.1 darran dtrace_aggdesc_t aggdesc; 139 1.1 darran dtrace_action_t *act; 140 1.1 darran dtrace_aggregation_t *agg; 141 1.1 darran int nrecs; 142 1.1 darran uint32_t offs; 143 1.1 darran dtrace_recdesc_t *lrec; 144 1.1 darran void *buf; 145 1.1 darran size_t size; 146 1.1 darran uintptr_t dest; 147 1.1 darran 148 1.1 darran DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_AGGDESC\n",__func__,__LINE__); 149 1.1 darran 150 1.1 darran if (copyin((void *) *paggdesc, &aggdesc, sizeof (aggdesc)) != 0) 151 1.1 darran return (EFAULT); 152 1.1 darran 153 1.1 darran mutex_enter(&dtrace_lock); 154 1.1 darran 155 1.1 darran if ((agg = dtrace_aggid2agg(state, aggdesc.dtagd_id)) == NULL) { 156 1.1 darran mutex_exit(&dtrace_lock); 157 1.1 darran return (EINVAL); 158 1.1 darran } 159 1.1 darran 160 1.1 darran aggdesc.dtagd_epid = agg->dtag_ecb->dte_epid; 161 1.1 darran 162 1.1 darran nrecs = aggdesc.dtagd_nrecs; 163 1.1 darran aggdesc.dtagd_nrecs = 0; 164 1.1 darran 165 1.1 darran offs = agg->dtag_base; 166 1.1 darran lrec = &agg->dtag_action.dta_rec; 167 1.1 darran aggdesc.dtagd_size = lrec->dtrd_offset + lrec->dtrd_size - offs; 168 1.1 darran 169 1.1 darran for (act = agg->dtag_first; ; act = act->dta_next) { 170 1.1 darran ASSERT(act->dta_intuple || 171 1.1 darran DTRACEACT_ISAGG(act->dta_kind)); 172 1.1 darran 173 1.1 darran /* 174 1.1 darran * If this action has a record size of zero, it 175 1.1 darran * denotes an argument to the aggregating action. 176 1.1 darran * Because the presence of this record doesn't (or 177 1.1 darran * shouldn't) affect the way the data is interpreted, 178 1.1 darran * we don't copy it out to save user-level the 179 1.1 darran * confusion of dealing with a zero-length record. 180 1.1 darran */ 181 1.1 darran if (act->dta_rec.dtrd_size == 0) { 182 1.1 darran ASSERT(agg->dtag_hasarg); 183 1.1 darran continue; 184 1.1 darran } 185 1.1 darran 186 1.1 darran aggdesc.dtagd_nrecs++; 187 1.1 darran 188 1.1 darran if (act == &agg->dtag_action) 189 1.1 darran break; 190 1.1 darran } 191 1.1 darran 192 1.1 darran /* 193 1.1 darran * Now that we have the size, we need to allocate a temporary 194 1.1 darran * buffer in which to store the complete description. We need 195 1.1 darran * the temporary buffer to be able to drop dtrace_lock() 196 1.1 darran * across the copyout(), below. 197 1.1 darran */ 198 1.1 darran size = sizeof (dtrace_aggdesc_t) + 199 1.1 darran (aggdesc.dtagd_nrecs * sizeof (dtrace_recdesc_t)); 200 1.1 darran 201 1.1 darran buf = kmem_alloc(size, KM_SLEEP); 202 1.1 darran dest = (uintptr_t)buf; 203 1.1 darran 204 1.1 darran bcopy(&aggdesc, (void *)dest, sizeof (aggdesc)); 205 1.1 darran dest += offsetof(dtrace_aggdesc_t, dtagd_rec[0]); 206 1.1 darran 207 1.1 darran for (act = agg->dtag_first; ; act = act->dta_next) { 208 1.1 darran dtrace_recdesc_t rec = act->dta_rec; 209 1.1 darran 210 1.1 darran /* 211 1.1 darran * See the comment in the above loop for why we pass 212 1.1 darran * over zero-length records. 213 1.1 darran */ 214 1.1 darran if (rec.dtrd_size == 0) { 215 1.1 darran ASSERT(agg->dtag_hasarg); 216 1.1 darran continue; 217 1.1 darran } 218 1.1 darran 219 1.1 darran if (nrecs-- == 0) 220 1.1 darran break; 221 1.1 darran 222 1.1 darran rec.dtrd_offset -= offs; 223 1.1 darran bcopy(&rec, (void *)dest, sizeof (rec)); 224 1.1 darran dest += sizeof (dtrace_recdesc_t); 225 1.1 darran 226 1.1 darran if (act == &agg->dtag_action) 227 1.1 darran break; 228 1.1 darran } 229 1.1 darran 230 1.1 darran mutex_exit(&dtrace_lock); 231 1.1 darran 232 1.1 darran if (copyout(buf, (void *) *paggdesc, dest - (uintptr_t)buf) != 0) { 233 1.1 darran kmem_free(buf, size); 234 1.1 darran return (EFAULT); 235 1.1 darran } 236 1.1 darran 237 1.1 darran kmem_free(buf, size); 238 1.1 darran return (0); 239 1.1 darran } 240 1.1 darran case DTRACEIOC_AGGSNAP: 241 1.1 darran case DTRACEIOC_BUFSNAP: { 242 1.1 darran dtrace_bufdesc_t **pdesc = (dtrace_bufdesc_t **) addr; 243 1.1 darran dtrace_bufdesc_t desc; 244 1.1 darran caddr_t cached; 245 1.1 darran dtrace_buffer_t *buf; 246 1.1 darran 247 1.1 darran dtrace_debug_output(); 248 1.1 darran 249 1.1 darran if (copyin((void *) *pdesc, &desc, sizeof (desc)) != 0) 250 1.1 darran return (EFAULT); 251 1.1 darran 252 1.1 darran DTRACE_IOCTL_PRINTF("%s(%d): %s curcpu %d cpu %d\n", 253 1.1 darran __func__,__LINE__, 254 1.1 darran cmd == DTRACEIOC_AGGSNAP ? 255 1.1 darran "DTRACEIOC_AGGSNAP":"DTRACEIOC_BUFSNAP", 256 1.2 darran cpu_number(), desc.dtbd_cpu); 257 1.1 darran 258 1.3 christos if (desc.dtbd_cpu >= ncpu) 259 1.1 darran return (ENOENT); 260 1.1 darran 261 1.1 darran mutex_enter(&dtrace_lock); 262 1.1 darran 263 1.1 darran if (cmd == DTRACEIOC_BUFSNAP) { 264 1.1 darran buf = &state->dts_buffer[desc.dtbd_cpu]; 265 1.1 darran } else { 266 1.1 darran buf = &state->dts_aggbuffer[desc.dtbd_cpu]; 267 1.1 darran } 268 1.1 darran 269 1.1 darran if (buf->dtb_flags & (DTRACEBUF_RING | DTRACEBUF_FILL)) { 270 1.1 darran size_t sz = buf->dtb_offset; 271 1.1 darran 272 1.1 darran if (state->dts_activity != DTRACE_ACTIVITY_STOPPED) { 273 1.1 darran mutex_exit(&dtrace_lock); 274 1.1 darran return (EBUSY); 275 1.1 darran } 276 1.1 darran 277 1.1 darran /* 278 1.1 darran * If this buffer has already been consumed, we're 279 1.1 darran * going to indicate that there's nothing left here 280 1.1 darran * to consume. 281 1.1 darran */ 282 1.1 darran if (buf->dtb_flags & DTRACEBUF_CONSUMED) { 283 1.1 darran mutex_exit(&dtrace_lock); 284 1.1 darran 285 1.1 darran desc.dtbd_size = 0; 286 1.1 darran desc.dtbd_drops = 0; 287 1.1 darran desc.dtbd_errors = 0; 288 1.1 darran desc.dtbd_oldest = 0; 289 1.1 darran sz = sizeof (desc); 290 1.1 darran 291 1.1 darran if (copyout(&desc, (void *) *pdesc, sz) != 0) 292 1.1 darran return (EFAULT); 293 1.1 darran 294 1.1 darran return (0); 295 1.1 darran } 296 1.1 darran 297 1.1 darran /* 298 1.1 darran * If this is a ring buffer that has wrapped, we want 299 1.1 darran * to copy the whole thing out. 300 1.1 darran */ 301 1.1 darran if (buf->dtb_flags & DTRACEBUF_WRAPPED) { 302 1.1 darran dtrace_buffer_polish(buf); 303 1.1 darran sz = buf->dtb_size; 304 1.1 darran } 305 1.1 darran 306 1.1 darran if (copyout(buf->dtb_tomax, desc.dtbd_data, sz) != 0) { 307 1.1 darran mutex_exit(&dtrace_lock); 308 1.1 darran return (EFAULT); 309 1.1 darran } 310 1.1 darran 311 1.1 darran desc.dtbd_size = sz; 312 1.1 darran desc.dtbd_drops = buf->dtb_drops; 313 1.1 darran desc.dtbd_errors = buf->dtb_errors; 314 1.1 darran desc.dtbd_oldest = buf->dtb_xamot_offset; 315 1.7 chs desc.dtbd_timestamp = dtrace_gethrtime(); 316 1.1 darran 317 1.1 darran mutex_exit(&dtrace_lock); 318 1.1 darran 319 1.1 darran if (copyout(&desc, (void *) *pdesc, sizeof (desc)) != 0) 320 1.1 darran return (EFAULT); 321 1.1 darran 322 1.1 darran buf->dtb_flags |= DTRACEBUF_CONSUMED; 323 1.1 darran 324 1.1 darran return (0); 325 1.1 darran } 326 1.1 darran 327 1.1 darran if (buf->dtb_tomax == NULL) { 328 1.1 darran ASSERT(buf->dtb_xamot == NULL); 329 1.1 darran mutex_exit(&dtrace_lock); 330 1.1 darran return (ENOENT); 331 1.1 darran } 332 1.1 darran 333 1.1 darran cached = buf->dtb_tomax; 334 1.1 darran ASSERT(!(buf->dtb_flags & DTRACEBUF_NOSWITCH)); 335 1.1 darran 336 1.1 darran dtrace_xcall(desc.dtbd_cpu, 337 1.1 darran (dtrace_xcall_t)dtrace_buffer_switch, buf); 338 1.1 darran 339 1.1 darran state->dts_errors += buf->dtb_xamot_errors; 340 1.1 darran 341 1.1 darran /* 342 1.1 darran * If the buffers did not actually switch, then the cross call 343 1.1 darran * did not take place -- presumably because the given CPU is 344 1.1 darran * not in the ready set. If this is the case, we'll return 345 1.1 darran * ENOENT. 346 1.1 darran */ 347 1.1 darran if (buf->dtb_tomax == cached) { 348 1.1 darran ASSERT(buf->dtb_xamot != cached); 349 1.1 darran mutex_exit(&dtrace_lock); 350 1.1 darran return (ENOENT); 351 1.1 darran } 352 1.1 darran 353 1.1 darran ASSERT(cached == buf->dtb_xamot); 354 1.1 darran 355 1.1 darran DTRACE_IOCTL_PRINTF("%s(%d): copyout the buffer snapshot\n",__func__,__LINE__); 356 1.1 darran 357 1.1 darran /* 358 1.1 darran * We have our snapshot; now copy it out. 359 1.1 darran */ 360 1.1 darran if (copyout(buf->dtb_xamot, desc.dtbd_data, 361 1.1 darran buf->dtb_xamot_offset) != 0) { 362 1.1 darran mutex_exit(&dtrace_lock); 363 1.1 darran return (EFAULT); 364 1.1 darran } 365 1.1 darran 366 1.1 darran desc.dtbd_size = buf->dtb_xamot_offset; 367 1.1 darran desc.dtbd_drops = buf->dtb_xamot_drops; 368 1.1 darran desc.dtbd_errors = buf->dtb_xamot_errors; 369 1.1 darran desc.dtbd_oldest = 0; 370 1.7 chs desc.dtbd_timestamp = buf->dtb_switched; 371 1.1 darran 372 1.1 darran mutex_exit(&dtrace_lock); 373 1.1 darran 374 1.1 darran DTRACE_IOCTL_PRINTF("%s(%d): copyout buffer desc: size %zd drops %lu errors %lu\n",__func__,__LINE__,(size_t) desc.dtbd_size,(u_long) desc.dtbd_drops,(u_long) desc.dtbd_errors); 375 1.1 darran 376 1.1 darran /* 377 1.1 darran * Finally, copy out the buffer description. 378 1.1 darran */ 379 1.1 darran if (copyout(&desc, (void *) *pdesc, sizeof (desc)) != 0) 380 1.1 darran return (EFAULT); 381 1.1 darran 382 1.1 darran return (0); 383 1.1 darran } 384 1.1 darran case DTRACEIOC_CONF: { 385 1.1 darran dtrace_conf_t conf; 386 1.1 darran 387 1.1 darran DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_CONF\n",__func__,__LINE__); 388 1.1 darran 389 1.1 darran bzero(&conf, sizeof (conf)); 390 1.1 darran conf.dtc_difversion = DIF_VERSION; 391 1.1 darran conf.dtc_difintregs = DIF_DIR_NREGS; 392 1.1 darran conf.dtc_diftupregs = DIF_DTR_NREGS; 393 1.1 darran conf.dtc_ctfmodel = CTF_MODEL_NATIVE; 394 1.1 darran 395 1.1 darran *((dtrace_conf_t *) addr) = conf; 396 1.1 darran 397 1.1 darran return (0); 398 1.1 darran } 399 1.1 darran case DTRACEIOC_DOFGET: { 400 1.1 darran dof_hdr_t **pdof = (dof_hdr_t **) addr; 401 1.1 darran dof_hdr_t hdr, *dof = *pdof; 402 1.1 darran int rval; 403 1.1 darran uint64_t len; 404 1.1 darran 405 1.1 darran DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_DOFGET\n",__func__,__LINE__); 406 1.1 darran 407 1.1 darran if (copyin((void *)dof, &hdr, sizeof (hdr)) != 0) 408 1.1 darran return (EFAULT); 409 1.1 darran 410 1.1 darran mutex_enter(&dtrace_lock); 411 1.1 darran dof = dtrace_dof_create(state); 412 1.1 darran mutex_exit(&dtrace_lock); 413 1.1 darran 414 1.1 darran len = MIN(hdr.dofh_loadsz, dof->dofh_loadsz); 415 1.1 darran rval = copyout(dof, (void *) *pdof, len); 416 1.1 darran dtrace_dof_destroy(dof); 417 1.1 darran 418 1.1 darran return (rval == 0 ? 0 : EFAULT); 419 1.1 darran } 420 1.1 darran case DTRACEIOC_ENABLE: { 421 1.1 darran dof_hdr_t *dof = NULL; 422 1.1 darran dtrace_enabling_t *enab = NULL; 423 1.1 darran dtrace_vstate_t *vstate; 424 1.1 darran int err = 0; 425 1.1 darran int rval; 426 1.1 darran dtrace_enable_io_t *p = (dtrace_enable_io_t *) addr; 427 1.1 darran 428 1.1 darran DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_ENABLE\n",__func__,__LINE__); 429 1.1 darran 430 1.1 darran /* 431 1.1 darran * If a NULL argument has been passed, we take this as our 432 1.1 darran * cue to reevaluate our enablings. 433 1.1 darran */ 434 1.1 darran if (p->dof == NULL) { 435 1.1 darran dtrace_enabling_matchall(); 436 1.1 darran 437 1.1 darran return (0); 438 1.1 darran } 439 1.1 darran 440 1.1 darran if ((dof = dtrace_dof_copyin((uintptr_t) p->dof, &rval)) == NULL) 441 1.1 darran return (EINVAL); 442 1.1 darran 443 1.1 darran mutex_enter(&cpu_lock); 444 1.1 darran mutex_enter(&dtrace_lock); 445 1.1 darran vstate = &state->dts_vstate; 446 1.1 darran 447 1.1 darran if (state->dts_activity != DTRACE_ACTIVITY_INACTIVE) { 448 1.1 darran mutex_exit(&dtrace_lock); 449 1.1 darran mutex_exit(&cpu_lock); 450 1.1 darran dtrace_dof_destroy(dof); 451 1.1 darran return (EBUSY); 452 1.1 darran } 453 1.1 darran 454 1.7 chs if (dtrace_dof_slurp(dof, vstate, CRED(), &enab, 0, 0, 455 1.7 chs B_TRUE) != 0) { 456 1.1 darran mutex_exit(&dtrace_lock); 457 1.1 darran mutex_exit(&cpu_lock); 458 1.1 darran dtrace_dof_destroy(dof); 459 1.1 darran return (EINVAL); 460 1.1 darran } 461 1.1 darran 462 1.1 darran if ((rval = dtrace_dof_options(dof, state)) != 0) { 463 1.1 darran dtrace_enabling_destroy(enab); 464 1.1 darran mutex_exit(&dtrace_lock); 465 1.1 darran mutex_exit(&cpu_lock); 466 1.1 darran dtrace_dof_destroy(dof); 467 1.1 darran return (rval); 468 1.1 darran } 469 1.1 darran 470 1.1 darran if ((err = dtrace_enabling_match(enab, &p->n_matched)) == 0) { 471 1.1 darran err = dtrace_enabling_retain(enab); 472 1.1 darran } else { 473 1.1 darran dtrace_enabling_destroy(enab); 474 1.1 darran } 475 1.1 darran 476 1.1 darran mutex_exit(&cpu_lock); 477 1.1 darran mutex_exit(&dtrace_lock); 478 1.1 darran dtrace_dof_destroy(dof); 479 1.1 darran 480 1.1 darran return (err); 481 1.1 darran } 482 1.1 darran case DTRACEIOC_EPROBE: { 483 1.1 darran dtrace_eprobedesc_t **pepdesc = (dtrace_eprobedesc_t **) addr; 484 1.1 darran dtrace_eprobedesc_t epdesc; 485 1.1 darran dtrace_ecb_t *ecb; 486 1.1 darran dtrace_action_t *act; 487 1.1 darran void *buf; 488 1.1 darran size_t size; 489 1.1 darran uintptr_t dest; 490 1.1 darran int nrecs; 491 1.1 darran 492 1.1 darran DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_EPROBE\n",__func__,__LINE__); 493 1.1 darran 494 1.1 darran if (copyin((void *)*pepdesc, &epdesc, sizeof (epdesc)) != 0) 495 1.1 darran return (EFAULT); 496 1.1 darran 497 1.1 darran mutex_enter(&dtrace_lock); 498 1.1 darran 499 1.1 darran if ((ecb = dtrace_epid2ecb(state, epdesc.dtepd_epid)) == NULL) { 500 1.1 darran mutex_exit(&dtrace_lock); 501 1.1 darran return (EINVAL); 502 1.1 darran } 503 1.1 darran 504 1.1 darran if (ecb->dte_probe == NULL) { 505 1.1 darran mutex_exit(&dtrace_lock); 506 1.1 darran return (EINVAL); 507 1.1 darran } 508 1.1 darran 509 1.1 darran epdesc.dtepd_probeid = ecb->dte_probe->dtpr_id; 510 1.1 darran epdesc.dtepd_uarg = ecb->dte_uarg; 511 1.1 darran epdesc.dtepd_size = ecb->dte_size; 512 1.1 darran 513 1.1 darran nrecs = epdesc.dtepd_nrecs; 514 1.1 darran epdesc.dtepd_nrecs = 0; 515 1.1 darran for (act = ecb->dte_action; act != NULL; act = act->dta_next) { 516 1.1 darran if (DTRACEACT_ISAGG(act->dta_kind) || act->dta_intuple) 517 1.1 darran continue; 518 1.1 darran 519 1.1 darran epdesc.dtepd_nrecs++; 520 1.1 darran } 521 1.1 darran 522 1.1 darran /* 523 1.1 darran * Now that we have the size, we need to allocate a temporary 524 1.1 darran * buffer in which to store the complete description. We need 525 1.1 darran * the temporary buffer to be able to drop dtrace_lock() 526 1.1 darran * across the copyout(), below. 527 1.1 darran */ 528 1.1 darran size = sizeof (dtrace_eprobedesc_t) + 529 1.1 darran (epdesc.dtepd_nrecs * sizeof (dtrace_recdesc_t)); 530 1.1 darran 531 1.1 darran buf = kmem_alloc(size, KM_SLEEP); 532 1.1 darran dest = (uintptr_t)buf; 533 1.1 darran 534 1.1 darran bcopy(&epdesc, (void *)dest, sizeof (epdesc)); 535 1.1 darran dest += offsetof(dtrace_eprobedesc_t, dtepd_rec[0]); 536 1.1 darran 537 1.1 darran for (act = ecb->dte_action; act != NULL; act = act->dta_next) { 538 1.1 darran if (DTRACEACT_ISAGG(act->dta_kind) || act->dta_intuple) 539 1.1 darran continue; 540 1.1 darran 541 1.1 darran if (nrecs-- == 0) 542 1.1 darran break; 543 1.1 darran 544 1.1 darran bcopy(&act->dta_rec, (void *)dest, 545 1.1 darran sizeof (dtrace_recdesc_t)); 546 1.1 darran dest += sizeof (dtrace_recdesc_t); 547 1.1 darran } 548 1.1 darran 549 1.1 darran mutex_exit(&dtrace_lock); 550 1.1 darran 551 1.1 darran if (copyout(buf, (void *) *pepdesc, dest - (uintptr_t)buf) != 0) { 552 1.1 darran kmem_free(buf, size); 553 1.1 darran return (EFAULT); 554 1.1 darran } 555 1.1 darran 556 1.1 darran kmem_free(buf, size); 557 1.1 darran return (0); 558 1.1 darran } 559 1.1 darran case DTRACEIOC_FORMAT: { 560 1.1 darran dtrace_fmtdesc_t *fmt = (dtrace_fmtdesc_t *) addr; 561 1.1 darran char *str; 562 1.1 darran int len; 563 1.1 darran 564 1.1 darran DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_FORMAT\n",__func__,__LINE__); 565 1.1 darran 566 1.1 darran mutex_enter(&dtrace_lock); 567 1.1 darran 568 1.1 darran if (fmt->dtfd_format == 0 || 569 1.1 darran fmt->dtfd_format > state->dts_nformats) { 570 1.1 darran mutex_exit(&dtrace_lock); 571 1.1 darran return (EINVAL); 572 1.1 darran } 573 1.1 darran 574 1.1 darran /* 575 1.1 darran * Format strings are allocated contiguously and they are 576 1.1 darran * never freed; if a format index is less than the number 577 1.1 darran * of formats, we can assert that the format map is non-NULL 578 1.1 darran * and that the format for the specified index is non-NULL. 579 1.1 darran */ 580 1.1 darran ASSERT(state->dts_formats != NULL); 581 1.1 darran str = state->dts_formats[fmt->dtfd_format - 1]; 582 1.1 darran ASSERT(str != NULL); 583 1.1 darran 584 1.1 darran len = strlen(str) + 1; 585 1.1 darran 586 1.1 darran if (len > fmt->dtfd_length) { 587 1.1 darran fmt->dtfd_length = len; 588 1.1 darran } else { 589 1.1 darran if (copyout(str, fmt->dtfd_string, len) != 0) { 590 1.1 darran mutex_exit(&dtrace_lock); 591 1.1 darran return (EINVAL); 592 1.1 darran } 593 1.1 darran } 594 1.1 darran 595 1.1 darran mutex_exit(&dtrace_lock); 596 1.1 darran return (0); 597 1.1 darran } 598 1.1 darran case DTRACEIOC_GO: { 599 1.1 darran int rval; 600 1.1 darran processorid_t *cpuid = (processorid_t *) addr; 601 1.1 darran 602 1.1 darran DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_GO\n",__func__,__LINE__); 603 1.1 darran 604 1.1 darran rval = dtrace_state_go(state, cpuid); 605 1.1 darran 606 1.1 darran return (rval); 607 1.1 darran } 608 1.1 darran case DTRACEIOC_PROBEARG: { 609 1.1 darran dtrace_argdesc_t *desc = (dtrace_argdesc_t *) addr; 610 1.1 darran dtrace_probe_t *probe; 611 1.1 darran dtrace_provider_t *prov; 612 1.1 darran 613 1.1 darran DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_PROBEARG\n",__func__,__LINE__); 614 1.1 darran 615 1.1 darran if (desc->dtargd_id == DTRACE_IDNONE) 616 1.1 darran return (EINVAL); 617 1.1 darran 618 1.1 darran if (desc->dtargd_ndx == DTRACE_ARGNONE) 619 1.1 darran return (EINVAL); 620 1.1 darran 621 1.1 darran mutex_enter(&dtrace_provider_lock); 622 1.7 chs #ifdef illumos 623 1.1 darran mutex_enter(&mod_lock); 624 1.7 chs #endif 625 1.1 darran mutex_enter(&dtrace_lock); 626 1.1 darran 627 1.1 darran if (desc->dtargd_id > dtrace_nprobes) { 628 1.1 darran mutex_exit(&dtrace_lock); 629 1.7 chs #ifdef illumos 630 1.1 darran mutex_exit(&mod_lock); 631 1.7 chs #endif 632 1.1 darran mutex_exit(&dtrace_provider_lock); 633 1.1 darran return (EINVAL); 634 1.1 darran } 635 1.1 darran 636 1.1 darran if ((probe = dtrace_probes[desc->dtargd_id - 1]) == NULL) { 637 1.1 darran mutex_exit(&dtrace_lock); 638 1.7 chs #ifdef illumos 639 1.1 darran mutex_exit(&mod_lock); 640 1.7 chs #endif 641 1.1 darran mutex_exit(&dtrace_provider_lock); 642 1.1 darran return (EINVAL); 643 1.1 darran } 644 1.1 darran 645 1.1 darran mutex_exit(&dtrace_lock); 646 1.1 darran 647 1.1 darran prov = probe->dtpr_provider; 648 1.1 darran 649 1.1 darran if (prov->dtpv_pops.dtps_getargdesc == NULL) { 650 1.1 darran /* 651 1.1 darran * There isn't any typed information for this probe. 652 1.1 darran * Set the argument number to DTRACE_ARGNONE. 653 1.1 darran */ 654 1.1 darran desc->dtargd_ndx = DTRACE_ARGNONE; 655 1.1 darran } else { 656 1.1 darran desc->dtargd_native[0] = '\0'; 657 1.1 darran desc->dtargd_xlate[0] = '\0'; 658 1.1 darran desc->dtargd_mapping = desc->dtargd_ndx; 659 1.1 darran 660 1.1 darran prov->dtpv_pops.dtps_getargdesc(prov->dtpv_arg, 661 1.1 darran probe->dtpr_id, probe->dtpr_arg, desc); 662 1.1 darran } 663 1.1 darran 664 1.7 chs #ifdef illumos 665 1.1 darran mutex_exit(&mod_lock); 666 1.7 chs #endif 667 1.1 darran mutex_exit(&dtrace_provider_lock); 668 1.1 darran 669 1.1 darran return (0); 670 1.1 darran } 671 1.1 darran case DTRACEIOC_PROBEMATCH: 672 1.1 darran case DTRACEIOC_PROBES: { 673 1.1 darran dtrace_probedesc_t *p_desc = (dtrace_probedesc_t *) addr; 674 1.1 darran dtrace_probe_t *probe = NULL; 675 1.1 darran dtrace_probekey_t pkey; 676 1.1 darran dtrace_id_t i; 677 1.1 darran int m = 0; 678 1.1 darran uint32_t priv = 0; 679 1.1 darran uid_t uid = 0; 680 1.1 darran zoneid_t zoneid = 0; 681 1.1 darran 682 1.1 darran DTRACE_IOCTL_PRINTF("%s(%d): %s\n",__func__,__LINE__, 683 1.1 darran cmd == DTRACEIOC_PROBEMATCH ? 684 1.1 darran "DTRACEIOC_PROBEMATCH":"DTRACEIOC_PROBES"); 685 1.1 darran 686 1.1 darran p_desc->dtpd_provider[DTRACE_PROVNAMELEN - 1] = '\0'; 687 1.1 darran p_desc->dtpd_mod[DTRACE_MODNAMELEN - 1] = '\0'; 688 1.1 darran p_desc->dtpd_func[DTRACE_FUNCNAMELEN - 1] = '\0'; 689 1.1 darran p_desc->dtpd_name[DTRACE_NAMELEN - 1] = '\0'; 690 1.1 darran 691 1.1 darran /* 692 1.1 darran * Before we attempt to match this probe, we want to give 693 1.1 darran * all providers the opportunity to provide it. 694 1.1 darran */ 695 1.1 darran if (p_desc->dtpd_id == DTRACE_IDNONE) { 696 1.1 darran mutex_enter(&dtrace_provider_lock); 697 1.1 darran dtrace_probe_provide(p_desc, NULL); 698 1.1 darran mutex_exit(&dtrace_provider_lock); 699 1.1 darran p_desc->dtpd_id++; 700 1.1 darran } 701 1.1 darran 702 1.1 darran if (cmd == DTRACEIOC_PROBEMATCH) { 703 1.1 darran dtrace_probekey(p_desc, &pkey); 704 1.1 darran pkey.dtpk_id = DTRACE_IDNONE; 705 1.1 darran } 706 1.1 darran 707 1.2 darran dtrace_cred2priv(curlwp->l_cred, &priv, &uid, &zoneid); 708 1.1 darran 709 1.1 darran mutex_enter(&dtrace_lock); 710 1.1 darran 711 1.1 darran if (cmd == DTRACEIOC_PROBEMATCH) { 712 1.1 darran for (i = p_desc->dtpd_id; i <= dtrace_nprobes; i++) { 713 1.1 darran if ((probe = dtrace_probes[i - 1]) != NULL && 714 1.1 darran (m = dtrace_match_probe(probe, &pkey, 715 1.1 darran priv, uid, zoneid)) != 0) 716 1.1 darran break; 717 1.1 darran } 718 1.1 darran 719 1.1 darran if (m < 0) { 720 1.1 darran mutex_exit(&dtrace_lock); 721 1.1 darran return (EINVAL); 722 1.1 darran } 723 1.1 darran 724 1.1 darran } else { 725 1.1 darran for (i = p_desc->dtpd_id; i <= dtrace_nprobes; i++) { 726 1.1 darran if ((probe = dtrace_probes[i - 1]) != NULL && 727 1.1 darran dtrace_match_priv(probe, priv, uid, zoneid)) 728 1.1 darran break; 729 1.1 darran } 730 1.1 darran } 731 1.1 darran 732 1.1 darran if (probe == NULL) { 733 1.1 darran mutex_exit(&dtrace_lock); 734 1.1 darran return (ESRCH); 735 1.1 darran } 736 1.1 darran 737 1.1 darran dtrace_probe_description(probe, p_desc); 738 1.1 darran mutex_exit(&dtrace_lock); 739 1.1 darran 740 1.1 darran return (0); 741 1.1 darran } 742 1.1 darran case DTRACEIOC_PROVIDER: { 743 1.1 darran dtrace_providerdesc_t *pvd = (dtrace_providerdesc_t *) addr; 744 1.1 darran dtrace_provider_t *pvp; 745 1.1 darran 746 1.1 darran DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_PROVIDER\n",__func__,__LINE__); 747 1.1 darran 748 1.1 darran pvd->dtvd_name[DTRACE_PROVNAMELEN - 1] = '\0'; 749 1.4 christos error = 0; 750 1.4 christos again: 751 1.1 darran mutex_enter(&dtrace_provider_lock); 752 1.1 darran 753 1.1 darran for (pvp = dtrace_provider; pvp != NULL; pvp = pvp->dtpv_next) { 754 1.1 darran if (strcmp(pvp->dtpv_name, pvd->dtvd_name) == 0) 755 1.1 darran break; 756 1.1 darran } 757 1.1 darran 758 1.1 darran mutex_exit(&dtrace_provider_lock); 759 1.1 darran 760 1.4 christos if (pvp == NULL && error == 0) { 761 1.5 riastrad char name[NAME_MAX]; 762 1.6 christos const char *provider; 763 1.6 christos if (strcmp(pvd->dtvd_name, "proc") == 0) 764 1.6 christos provider = "sdt"; 765 1.6 christos else 766 1.6 christos provider = pvd->dtvd_name; 767 1.5 riastrad 768 1.5 riastrad if (snprintf(name, sizeof name, "dtrace_%s", 769 1.6 christos provider) < sizeof name) { 770 1.5 riastrad error = module_autoload(name, 771 1.5 riastrad MODULE_CLASS_MISC); 772 1.5 riastrad if (error == 0) 773 1.5 riastrad goto again; 774 1.5 riastrad } 775 1.4 christos } 776 1.4 christos 777 1.1 darran if (pvp == NULL) 778 1.1 darran return (ESRCH); 779 1.1 darran 780 1.1 darran bcopy(&pvp->dtpv_priv, &pvd->dtvd_priv, sizeof (dtrace_ppriv_t)); 781 1.1 darran bcopy(&pvp->dtpv_attr, &pvd->dtvd_attr, sizeof (dtrace_pattr_t)); 782 1.1 darran 783 1.1 darran return (0); 784 1.1 darran } 785 1.1 darran case DTRACEIOC_REPLICATE: { 786 1.1 darran dtrace_repldesc_t *desc = (dtrace_repldesc_t *) addr; 787 1.1 darran dtrace_probedesc_t *match = &desc->dtrpd_match; 788 1.1 darran dtrace_probedesc_t *create = &desc->dtrpd_create; 789 1.1 darran int err; 790 1.1 darran 791 1.1 darran DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_REPLICATE\n",__func__,__LINE__); 792 1.1 darran 793 1.1 darran match->dtpd_provider[DTRACE_PROVNAMELEN - 1] = '\0'; 794 1.1 darran match->dtpd_mod[DTRACE_MODNAMELEN - 1] = '\0'; 795 1.1 darran match->dtpd_func[DTRACE_FUNCNAMELEN - 1] = '\0'; 796 1.1 darran match->dtpd_name[DTRACE_NAMELEN - 1] = '\0'; 797 1.1 darran 798 1.1 darran create->dtpd_provider[DTRACE_PROVNAMELEN - 1] = '\0'; 799 1.1 darran create->dtpd_mod[DTRACE_MODNAMELEN - 1] = '\0'; 800 1.1 darran create->dtpd_func[DTRACE_FUNCNAMELEN - 1] = '\0'; 801 1.1 darran create->dtpd_name[DTRACE_NAMELEN - 1] = '\0'; 802 1.1 darran 803 1.1 darran mutex_enter(&dtrace_lock); 804 1.1 darran err = dtrace_enabling_replicate(state, match, create); 805 1.1 darran mutex_exit(&dtrace_lock); 806 1.1 darran 807 1.1 darran return (err); 808 1.1 darran } 809 1.1 darran case DTRACEIOC_STATUS: { 810 1.1 darran dtrace_status_t *stat = (dtrace_status_t *) addr; 811 1.1 darran dtrace_dstate_t *dstate; 812 1.7 chs int i, j; 813 1.1 darran uint64_t nerrs; 814 1.2 darran CPU_INFO_ITERATOR cpuind; 815 1.2 darran struct cpu_info *cinfo; 816 1.1 darran 817 1.1 darran DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_STATUS\n",__func__,__LINE__); 818 1.1 darran 819 1.1 darran /* 820 1.1 darran * See the comment in dtrace_state_deadman() for the reason 821 1.1 darran * for setting dts_laststatus to INT64_MAX before setting 822 1.1 darran * it to the correct value. 823 1.1 darran */ 824 1.1 darran state->dts_laststatus = INT64_MAX; 825 1.1 darran dtrace_membar_producer(); 826 1.1 darran state->dts_laststatus = dtrace_gethrtime(); 827 1.1 darran 828 1.1 darran bzero(stat, sizeof (*stat)); 829 1.1 darran 830 1.1 darran mutex_enter(&dtrace_lock); 831 1.1 darran 832 1.1 darran if (state->dts_activity == DTRACE_ACTIVITY_INACTIVE) { 833 1.1 darran mutex_exit(&dtrace_lock); 834 1.1 darran return (ENOENT); 835 1.1 darran } 836 1.1 darran 837 1.1 darran if (state->dts_activity == DTRACE_ACTIVITY_DRAINING) 838 1.1 darran stat->dtst_exiting = 1; 839 1.1 darran 840 1.1 darran nerrs = state->dts_errors; 841 1.1 darran dstate = &state->dts_vstate.dtvs_dynvars; 842 1.1 darran 843 1.2 darran for (CPU_INFO_FOREACH(cpuind, cinfo)) { 844 1.7 chs i = cpu_index(cinfo); 845 1.7 chs 846 1.7 chs dtrace_dstate_percpu_t *dcpu = &dstate->dtds_percpu[i]; 847 1.1 darran 848 1.1 darran stat->dtst_dyndrops += dcpu->dtdsc_drops; 849 1.1 darran stat->dtst_dyndrops_dirty += dcpu->dtdsc_dirty_drops; 850 1.1 darran stat->dtst_dyndrops_rinsing += dcpu->dtdsc_rinsing_drops; 851 1.1 darran 852 1.7 chs if (state->dts_buffer[i].dtb_flags & DTRACEBUF_FULL) 853 1.1 darran stat->dtst_filled++; 854 1.1 darran 855 1.7 chs nerrs += state->dts_buffer[i].dtb_errors; 856 1.1 darran 857 1.1 darran for (j = 0; j < state->dts_nspeculations; j++) { 858 1.1 darran dtrace_speculation_t *spec; 859 1.1 darran dtrace_buffer_t *buf; 860 1.1 darran 861 1.1 darran spec = &state->dts_speculations[j]; 862 1.7 chs buf = &spec->dtsp_buffer[i]; 863 1.1 darran stat->dtst_specdrops += buf->dtb_xamot_drops; 864 1.1 darran } 865 1.1 darran } 866 1.1 darran 867 1.1 darran stat->dtst_specdrops_busy = state->dts_speculations_busy; 868 1.1 darran stat->dtst_specdrops_unavail = state->dts_speculations_unavail; 869 1.1 darran stat->dtst_stkstroverflows = state->dts_stkstroverflows; 870 1.1 darran stat->dtst_dblerrors = state->dts_dblerrors; 871 1.1 darran stat->dtst_killed = 872 1.1 darran (state->dts_activity == DTRACE_ACTIVITY_KILLED); 873 1.1 darran stat->dtst_errors = nerrs; 874 1.1 darran 875 1.1 darran mutex_exit(&dtrace_lock); 876 1.1 darran 877 1.1 darran return (0); 878 1.1 darran } 879 1.1 darran case DTRACEIOC_STOP: { 880 1.7 chs int rval; 881 1.1 darran processorid_t *cpuid = (processorid_t *) addr; 882 1.1 darran 883 1.1 darran DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_STOP\n",__func__,__LINE__); 884 1.1 darran 885 1.1 darran mutex_enter(&dtrace_lock); 886 1.7 chs rval = dtrace_state_stop(state, cpuid); 887 1.1 darran mutex_exit(&dtrace_lock); 888 1.1 darran 889 1.7 chs return (rval); 890 1.1 darran } 891 1.1 darran default: 892 1.1 darran error = ENOTTY; 893 1.1 darran } 894 1.1 darran return (error); 895 1.1 darran } 896