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_program.h> 37 #include <dt_printf.h> 38 39 dtrace_prog_t * 40 dt_program_create(dtrace_hdl_t *dtp) 41 { 42 dtrace_prog_t *pgp = dt_zalloc(dtp, sizeof (dtrace_prog_t)); 43 44 if (pgp != NULL) 45 dt_list_append(&dtp->dt_programs, pgp); 46 else 47 (void) dt_set_errno(dtp, EDT_NOMEM); 48 49 return (pgp); 50 } 51 52 void 53 dt_program_destroy(dtrace_hdl_t *dtp, dtrace_prog_t *pgp) 54 { 55 dt_stmt_t *stp, *next; 56 uint_t i; 57 58 for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) { 59 next = dt_list_next(stp); 60 dtrace_stmt_destroy(dtp, stp->ds_desc); 61 dt_free(dtp, stp); 62 } 63 64 for (i = 0; i < pgp->dp_xrefslen; i++) 65 dt_free(dtp, pgp->dp_xrefs[i]); 66 67 dt_free(dtp, pgp->dp_xrefs); 68 dt_list_delete(&dtp->dt_programs, pgp); 69 dt_free(dtp, pgp); 70 } 71 72 /*ARGSUSED*/ 73 void 74 dtrace_program_info(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, 75 dtrace_proginfo_t *pip) 76 { 77 dt_stmt_t *stp; 78 dtrace_actdesc_t *ap; 79 dtrace_ecbdesc_t *last = NULL; 80 81 if (pip == NULL) 82 return; 83 84 bzero(pip, sizeof (dtrace_proginfo_t)); 85 86 if (dt_list_next(&pgp->dp_stmts) != NULL) { 87 pip->dpi_descattr = _dtrace_maxattr; 88 pip->dpi_stmtattr = _dtrace_maxattr; 89 } else { 90 pip->dpi_descattr = _dtrace_defattr; 91 pip->dpi_stmtattr = _dtrace_defattr; 92 } 93 94 for (stp = dt_list_next(&pgp->dp_stmts); stp; stp = dt_list_next(stp)) { 95 dtrace_ecbdesc_t *edp = stp->ds_desc->dtsd_ecbdesc; 96 97 if (edp == last) 98 continue; 99 last = edp; 100 101 pip->dpi_descattr = 102 dt_attr_min(stp->ds_desc->dtsd_descattr, pip->dpi_descattr); 103 104 pip->dpi_stmtattr = 105 dt_attr_min(stp->ds_desc->dtsd_stmtattr, pip->dpi_stmtattr); 106 107 /* 108 * If there aren't any actions, account for the fact that 109 * recording the epid will generate a record. 110 */ 111 if (edp->dted_action == NULL) 112 pip->dpi_recgens++; 113 114 for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) { 115 if (ap->dtad_kind == DTRACEACT_SPECULATE) { 116 pip->dpi_speculations++; 117 continue; 118 } 119 120 if (DTRACEACT_ISAGG(ap->dtad_kind)) { 121 pip->dpi_recgens -= ap->dtad_arg; 122 pip->dpi_aggregates++; 123 continue; 124 } 125 126 if (DTRACEACT_ISDESTRUCTIVE(ap->dtad_kind)) 127 continue; 128 129 if (ap->dtad_kind == DTRACEACT_DIFEXPR && 130 ap->dtad_difo->dtdo_rtype.dtdt_kind == 131 DIF_TYPE_CTF && 132 ap->dtad_difo->dtdo_rtype.dtdt_size == 0) 133 continue; 134 135 pip->dpi_recgens++; 136 } 137 } 138 } 139 140 int 141 dtrace_program_exec(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, 142 dtrace_proginfo_t *pip) 143 { 144 void *dof; 145 int n, err; 146 147 dtrace_program_info(dtp, pgp, pip); 148 149 if ((dof = dtrace_dof_create(dtp, pgp, DTRACE_D_STRIP)) == NULL) 150 return (-1); 151 152 n = dt_ioctl(dtp, DTRACEIOC_ENABLE, dof); 153 dtrace_dof_destroy(dtp, dof); 154 155 if (n == -1) { 156 switch (errno) { 157 case EINVAL: 158 err = EDT_DIFINVAL; 159 break; 160 case EFAULT: 161 err = EDT_DIFFAULT; 162 break; 163 case E2BIG: 164 err = EDT_DIFSIZE; 165 break; 166 default: 167 err = errno; 168 } 169 170 return (dt_set_errno(dtp, err)); 171 } 172 173 if (pip != NULL) 174 pip->dpi_matches += n; 175 176 return (0); 177 } 178 179 static void 180 dt_ecbdesc_hold(dtrace_ecbdesc_t *edp) 181 { 182 edp->dted_refcnt++; 183 } 184 185 void 186 dt_ecbdesc_release(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp) 187 { 188 if (--edp->dted_refcnt > 0) 189 return; 190 191 dt_difo_free(dtp, edp->dted_pred.dtpdd_difo); 192 assert(edp->dted_action == NULL); 193 dt_free(dtp, edp); 194 } 195 196 dtrace_ecbdesc_t * 197 dt_ecbdesc_create(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp) 198 { 199 dtrace_ecbdesc_t *edp; 200 201 if ((edp = dt_zalloc(dtp, sizeof (dtrace_ecbdesc_t))) == NULL) { 202 (void) dt_set_errno(dtp, EDT_NOMEM); 203 return (NULL); 204 } 205 206 edp->dted_probe = *pdp; 207 dt_ecbdesc_hold(edp); 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 = dt_zalloc(dtp, sizeof (dtrace_stmtdesc_t))) == NULL) 217 return (NULL); 218 219 dt_ecbdesc_hold(edp); 220 sdp->dtsd_ecbdesc = edp; 221 sdp->dtsd_descattr = _dtrace_defattr; 222 sdp->dtsd_stmtattr = _dtrace_defattr; 223 224 return (sdp); 225 } 226 227 dtrace_actdesc_t * 228 dtrace_stmt_action(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp) 229 { 230 dtrace_actdesc_t *new; 231 dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc; 232 233 if ((new = dt_alloc(dtp, sizeof (dtrace_actdesc_t))) == NULL) 234 return (NULL); 235 236 if (sdp->dtsd_action_last != NULL) { 237 assert(sdp->dtsd_action != NULL); 238 assert(sdp->dtsd_action_last->dtad_next == NULL); 239 sdp->dtsd_action_last->dtad_next = new; 240 } else { 241 dtrace_actdesc_t *ap = edp->dted_action; 242 243 assert(sdp->dtsd_action == NULL); 244 sdp->dtsd_action = new; 245 246 while (ap != NULL && ap->dtad_next != NULL) 247 ap = ap->dtad_next; 248 249 if (ap == NULL) 250 edp->dted_action = new; 251 else 252 ap->dtad_next = new; 253 } 254 255 sdp->dtsd_action_last = new; 256 bzero(new, sizeof (dtrace_actdesc_t)); 257 new->dtad_uarg = (uintptr_t)sdp; 258 259 return (new); 260 } 261 262 int 263 dtrace_stmt_add(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, dtrace_stmtdesc_t *sdp) 264 { 265 dt_stmt_t *stp = dt_alloc(dtp, sizeof (dt_stmt_t)); 266 267 if (stp == NULL) 268 return (-1); /* errno is set for us */ 269 270 dt_list_append(&pgp->dp_stmts, stp); 271 stp->ds_desc = sdp; 272 273 return (0); 274 } 275 276 int 277 dtrace_stmt_iter(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, 278 dtrace_stmt_f *func, void *data) 279 { 280 dt_stmt_t *stp, *next; 281 int status = 0; 282 283 for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) { 284 next = dt_list_next(stp); 285 if ((status = func(dtp, pgp, stp->ds_desc, data)) != 0) 286 break; 287 } 288 289 return (status); 290 } 291 292 void 293 dtrace_stmt_destroy(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp) 294 { 295 dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc; 296 297 /* 298 * We need to remove any actions that we have on this ECB, and 299 * remove our hold on the ECB itself. 300 */ 301 if (sdp->dtsd_action != NULL) { 302 dtrace_actdesc_t *last = sdp->dtsd_action_last; 303 dtrace_actdesc_t *ap, *next; 304 305 assert(last != NULL); 306 307 for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) { 308 if (ap == sdp->dtsd_action) 309 break; 310 311 if (ap->dtad_next == sdp->dtsd_action) 312 break; 313 } 314 315 assert(ap != NULL); 316 317 if (ap == edp->dted_action) 318 edp->dted_action = last->dtad_next; 319 else 320 ap->dtad_next = last->dtad_next; 321 322 /* 323 * We have now removed our action list from its ECB; we can 324 * safely destroy the list. 325 */ 326 last->dtad_next = NULL; 327 328 for (ap = sdp->dtsd_action; ap != NULL; ap = next) { 329 assert(ap->dtad_uarg == (uintptr_t)sdp); 330 dt_difo_free(dtp, ap->dtad_difo); 331 next = ap->dtad_next; 332 dt_free(dtp, ap); 333 } 334 } 335 336 if (sdp->dtsd_fmtdata != NULL) 337 dt_printf_destroy(sdp->dtsd_fmtdata); 338 339 dt_ecbdesc_release(dtp, sdp->dtsd_ecbdesc); 340 dt_free(dtp, sdp); 341 } 342