1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <unistd.h> 30 #include <strings.h> 31 #include <stdlib.h> 32 #include <errno.h> 33 #include <assert.h> 34 35 #include <dt_impl.h> 36 #include <dt_printf.h> 37 38 dtrace_prog_t * 39 dtrace_program_create(dtrace_hdl_t *dtp) 40 { 41 dtrace_prog_t *pgp = calloc(1, sizeof (dtrace_prog_t)); 42 43 if (pgp != NULL) 44 dt_list_append(&dtp->dt_programs, pgp); 45 else 46 (void) dt_set_errno(dtp, EDT_NOMEM); 47 48 return (pgp); 49 } 50 51 void 52 dtrace_program_destroy(dtrace_hdl_t *dtp, dtrace_prog_t *pgp) 53 { 54 dt_stmt_t *stp, *next; 55 56 for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) { 57 next = dt_list_next(stp); 58 dtrace_stmt_destroy(stp->ds_desc); 59 free(stp); 60 } 61 62 dt_list_delete(&dtp->dt_programs, pgp); 63 free(pgp); 64 } 65 66 /*ARGSUSED*/ 67 void 68 dtrace_program_info(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, 69 dtrace_proginfo_t *pip) 70 { 71 dt_stmt_t *stp; 72 dtrace_actdesc_t *ap; 73 dtrace_ecbdesc_t *last = NULL; 74 75 if (pip == NULL) 76 return; 77 78 bzero(pip, sizeof (dtrace_proginfo_t)); 79 80 if (dt_list_next(&pgp->dp_stmts) != NULL) { 81 pip->dpi_descattr = _dtrace_maxattr; 82 pip->dpi_stmtattr = _dtrace_maxattr; 83 } else { 84 pip->dpi_descattr = _dtrace_defattr; 85 pip->dpi_stmtattr = _dtrace_defattr; 86 } 87 88 for (stp = dt_list_next(&pgp->dp_stmts); stp; stp = dt_list_next(stp)) { 89 dtrace_ecbdesc_t *edp = stp->ds_desc->dtsd_ecbdesc; 90 91 if (edp == last) 92 continue; 93 last = edp; 94 95 pip->dpi_descattr = 96 dt_attr_min(stp->ds_desc->dtsd_descattr, pip->dpi_descattr); 97 98 pip->dpi_stmtattr = 99 dt_attr_min(stp->ds_desc->dtsd_stmtattr, pip->dpi_stmtattr); 100 101 /* 102 * If there aren't any actions, account for the fact that 103 * recording the epid will generate a record. 104 */ 105 if (edp->dted_action == NULL) 106 pip->dpi_recgens++; 107 108 for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) { 109 if (ap->dtad_kind == DTRACEACT_SPECULATE) { 110 pip->dpi_speculations++; 111 continue; 112 } 113 114 if (DTRACEACT_ISAGG(ap->dtad_kind)) { 115 pip->dpi_recgens -= ap->dtad_arg; 116 pip->dpi_aggregates++; 117 continue; 118 } 119 120 if (DTRACEACT_ISDESTRUCTIVE(ap->dtad_kind)) 121 continue; 122 123 if (ap->dtad_kind == DTRACEACT_DIFEXPR && 124 ap->dtad_difo->dtdo_rtype.dtdt_kind == 125 DIF_TYPE_CTF && 126 ap->dtad_difo->dtdo_rtype.dtdt_size == 0) 127 continue; 128 129 pip->dpi_recgens++; 130 } 131 } 132 } 133 134 int 135 dtrace_program_exec(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, 136 dtrace_proginfo_t *pip) 137 { 138 void *dof; 139 int n, err; 140 141 dtrace_program_info(dtp, pgp, pip); 142 143 if ((dof = dtrace_dof_create(dtp, pgp, DTRACE_D_STRIP)) == NULL) 144 return (-1); 145 146 n = dt_ioctl(dtp, DTRACEIOC_ENABLE, dof); 147 dtrace_dof_destroy(dtp, dof); 148 149 if (n == -1) { 150 switch (errno) { 151 case EINVAL: 152 err = EDT_DIFINVAL; 153 break; 154 case EFAULT: 155 err = EDT_DIFFAULT; 156 break; 157 case E2BIG: 158 err = EDT_DIFSIZE; 159 break; 160 default: 161 err = errno; 162 } 163 164 return (dt_set_errno(dtp, err)); 165 } 166 167 if (pip != NULL) 168 pip->dpi_matches += n; 169 170 return (0); 171 } 172 173 void 174 dtrace_ecbdesc_hold(dtrace_ecbdesc_t *edp) 175 { 176 edp->dted_refcnt++; 177 } 178 179 void 180 dtrace_ecbdesc_release(dtrace_ecbdesc_t *edp) 181 { 182 dtrace_difo_t *dp; 183 184 if (--edp->dted_refcnt > 0) 185 return; 186 187 if ((dp = edp->dted_pred.dtpdd_difo) != NULL) 188 dtrace_difo_release(dp); 189 190 assert(edp->dted_action == NULL); 191 free(edp); 192 } 193 194 dtrace_ecbdesc_t * 195 dtrace_ecbdesc_create(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp) 196 { 197 dtrace_ecbdesc_t *edp; 198 199 if ((edp = malloc(sizeof (dtrace_ecbdesc_t))) == NULL) { 200 (void) dt_set_errno(dtp, EDT_NOMEM); 201 return (NULL); 202 } 203 204 bzero(edp, sizeof (dtrace_ecbdesc_t)); 205 edp->dted_probe = *pdp; 206 dtrace_ecbdesc_hold(edp); 207 208 return (edp); 209 } 210 211 dtrace_stmtdesc_t * 212 dtrace_stmt_create(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp) 213 { 214 dtrace_stmtdesc_t *sdp; 215 216 if ((sdp = malloc(sizeof (dtrace_stmtdesc_t))) == NULL) { 217 (void) dt_set_errno(dtp, EDT_NOMEM); 218 return (NULL); 219 } 220 221 bzero(sdp, sizeof (dtrace_stmtdesc_t)); 222 dtrace_ecbdesc_hold(edp); 223 sdp->dtsd_ecbdesc = edp; 224 sdp->dtsd_descattr = _dtrace_defattr; 225 sdp->dtsd_stmtattr = _dtrace_defattr; 226 227 return (sdp); 228 } 229 230 dtrace_actdesc_t * 231 dtrace_stmt_action(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp) 232 { 233 dtrace_actdesc_t *new; 234 dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc; 235 236 if ((new = malloc(sizeof (dtrace_actdesc_t))) == NULL) { 237 (void) dt_set_errno(dtp, EDT_NOMEM); 238 return (NULL); 239 } 240 241 if (sdp->dtsd_action_last != NULL) { 242 assert(sdp->dtsd_action != NULL); 243 assert(sdp->dtsd_action_last->dtad_next == NULL); 244 sdp->dtsd_action_last->dtad_next = new; 245 } else { 246 dtrace_actdesc_t *ap = edp->dted_action; 247 248 assert(sdp->dtsd_action == NULL); 249 sdp->dtsd_action = new; 250 251 while (ap != NULL && ap->dtad_next != NULL) 252 ap = ap->dtad_next; 253 254 if (ap == NULL) 255 edp->dted_action = new; 256 else 257 ap->dtad_next = new; 258 } 259 260 sdp->dtsd_action_last = new; 261 bzero(new, sizeof (dtrace_actdesc_t)); 262 new->dtad_uarg = (uintptr_t)sdp; 263 264 return (new); 265 } 266 267 int 268 dtrace_stmt_add(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, dtrace_stmtdesc_t *sdp) 269 { 270 dt_stmt_t *stp = malloc(sizeof (dt_stmt_t)); 271 272 if (stp == NULL) 273 return (dt_set_errno(dtp, EDT_NOMEM)); 274 275 dt_list_append(&pgp->dp_stmts, stp); 276 stp->ds_desc = sdp; 277 278 return (0); 279 } 280 281 int 282 dtrace_stmt_iter(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, 283 dtrace_stmt_f *func, void *data) 284 { 285 dt_stmt_t *stp, *next; 286 int status = 0; 287 288 for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) { 289 next = dt_list_next(stp); 290 if ((status = func(dtp, pgp, stp->ds_desc, data)) != 0) 291 break; 292 } 293 294 return (status); 295 } 296 297 void 298 dtrace_stmt_destroy(dtrace_stmtdesc_t *sdp) 299 { 300 dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc; 301 302 /* 303 * We need to remove any actions that we have on this ECB, and 304 * remove our hold on the ECB itself. 305 */ 306 if (sdp->dtsd_action != NULL) { 307 dtrace_actdesc_t *last = sdp->dtsd_action_last; 308 dtrace_actdesc_t *ap, *next; 309 310 assert(last != NULL); 311 312 for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) { 313 if (ap == sdp->dtsd_action) 314 break; 315 316 if (ap->dtad_next == sdp->dtsd_action) 317 break; 318 } 319 320 assert(ap != NULL); 321 322 if (ap == edp->dted_action) { 323 edp->dted_action = last->dtad_next; 324 } else { 325 ap->dtad_next = last->dtad_next; 326 } 327 328 /* 329 * We have now removed our action list from its ECB; we can 330 * safely destroy the list. 331 */ 332 last->dtad_next = NULL; 333 334 for (ap = sdp->dtsd_action; ap != NULL; ap = next) { 335 dtrace_difo_t *dp; 336 337 assert(ap->dtad_uarg == (uintptr_t)sdp); 338 339 if ((dp = ap->dtad_difo) != NULL) 340 dtrace_difo_release(dp); 341 342 next = ap->dtad_next; 343 free(ap); 344 } 345 } 346 347 if (sdp->dtsd_fmtdata != NULL) 348 dt_printf_destroy(sdp->dtsd_fmtdata); 349 350 dtrace_ecbdesc_release(sdp->dtsd_ecbdesc); 351 free(sdp); 352 } 353