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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <stdlib.h> 29 #include <strings.h> 30 #include <errno.h> 31 #include <unistd.h> 32 #include <assert.h> 33 34 #include <dt_impl.h> 35 #include <dt_printf.h> 36 37 static int 38 dt_epid_add(dtrace_hdl_t *dtp, dtrace_epid_t id) 39 { 40 dtrace_id_t max; 41 int rval, i, maxformat; 42 dtrace_eprobedesc_t *enabled, *nenabled; 43 dtrace_probedesc_t *probe; 44 45 while (id >= (max = dtp->dt_maxprobe) || dtp->dt_pdesc == NULL) { 46 dtrace_id_t new_max = max ? (max << 1) : 1; 47 size_t nsize = new_max * sizeof (void *); 48 dtrace_probedesc_t **new_pdesc; 49 dtrace_eprobedesc_t **new_edesc; 50 51 if ((new_pdesc = malloc(nsize)) == NULL || 52 (new_edesc = malloc(nsize)) == NULL) { 53 free(new_pdesc); 54 return (dt_set_errno(dtp, EDT_NOMEM)); 55 } 56 57 bzero(new_pdesc, nsize); 58 bzero(new_edesc, nsize); 59 60 if (dtp->dt_pdesc != NULL) { 61 size_t osize = max * sizeof (void *); 62 63 bcopy(dtp->dt_pdesc, new_pdesc, osize); 64 free(dtp->dt_pdesc); 65 66 bcopy(dtp->dt_edesc, new_edesc, osize); 67 free(dtp->dt_edesc); 68 } 69 70 dtp->dt_pdesc = new_pdesc; 71 dtp->dt_edesc = new_edesc; 72 dtp->dt_maxprobe = new_max; 73 } 74 75 if (dtp->dt_pdesc[id] != NULL) 76 return (0); 77 78 if ((enabled = malloc(sizeof (dtrace_eprobedesc_t))) == NULL) 79 return (dt_set_errno(dtp, EDT_NOMEM)); 80 81 bzero(enabled, sizeof (dtrace_eprobedesc_t)); 82 enabled->dtepd_epid = id; 83 enabled->dtepd_nrecs = 1; 84 85 #if defined(sun) 86 if (dt_ioctl(dtp, DTRACEIOC_EPROBE, enabled) == -1) { 87 #else 88 if (dt_ioctl(dtp, DTRACEIOC_EPROBE, &enabled) == -1) { 89 #endif 90 rval = dt_set_errno(dtp, errno); 91 free(enabled); 92 return (rval); 93 } 94 95 if (DTRACE_SIZEOF_EPROBEDESC(enabled) != sizeof (*enabled)) { 96 /* 97 * There must be more than one action. Allocate the 98 * appropriate amount of space and try again. 99 */ 100 if ((nenabled = 101 malloc(DTRACE_SIZEOF_EPROBEDESC(enabled))) != NULL) 102 bcopy(enabled, nenabled, sizeof (*enabled)); 103 104 free(enabled); 105 106 if ((enabled = nenabled) == NULL) 107 return (dt_set_errno(dtp, EDT_NOMEM)); 108 109 #if defined(sun) 110 rval = dt_ioctl(dtp, DTRACEIOC_EPROBE, enabled); 111 #else 112 rval = dt_ioctl(dtp, DTRACEIOC_EPROBE, &enabled); 113 #endif 114 115 if (rval == -1) { 116 rval = dt_set_errno(dtp, errno); 117 free(enabled); 118 return (rval); 119 } 120 } 121 122 if ((probe = malloc(sizeof (dtrace_probedesc_t))) == NULL) { 123 free(enabled); 124 return (dt_set_errno(dtp, EDT_NOMEM)); 125 } 126 127 probe->dtpd_id = enabled->dtepd_probeid; 128 129 if (dt_ioctl(dtp, DTRACEIOC_PROBES, probe) == -1) { 130 rval = dt_set_errno(dtp, errno); 131 goto err; 132 } 133 134 for (i = 0; i < enabled->dtepd_nrecs; i++) { 135 dtrace_fmtdesc_t fmt; 136 dtrace_recdesc_t *rec = &enabled->dtepd_rec[i]; 137 138 if (!DTRACEACT_ISPRINTFLIKE(rec->dtrd_action)) 139 continue; 140 141 if (rec->dtrd_format == 0) 142 continue; 143 144 if (rec->dtrd_format <= dtp->dt_maxformat && 145 dtp->dt_formats[rec->dtrd_format - 1] != NULL) 146 continue; 147 148 bzero(&fmt, sizeof (fmt)); 149 fmt.dtfd_format = rec->dtrd_format; 150 fmt.dtfd_string = NULL; 151 fmt.dtfd_length = 0; 152 153 if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) { 154 rval = dt_set_errno(dtp, errno); 155 goto err; 156 } 157 158 if ((fmt.dtfd_string = malloc(fmt.dtfd_length)) == NULL) { 159 rval = dt_set_errno(dtp, EDT_NOMEM); 160 goto err; 161 } 162 163 if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) { 164 rval = dt_set_errno(dtp, errno); 165 free(fmt.dtfd_string); 166 goto err; 167 } 168 169 while (rec->dtrd_format > (maxformat = dtp->dt_maxformat)) { 170 int new_max = maxformat ? (maxformat << 1) : 1; 171 size_t nsize = new_max * sizeof (void *); 172 size_t osize = maxformat * sizeof (void *); 173 void **new_formats = malloc(nsize); 174 175 if (new_formats == NULL) { 176 rval = dt_set_errno(dtp, EDT_NOMEM); 177 free(fmt.dtfd_string); 178 goto err; 179 } 180 181 bzero(new_formats, nsize); 182 bcopy(dtp->dt_formats, new_formats, osize); 183 free(dtp->dt_formats); 184 185 dtp->dt_formats = new_formats; 186 dtp->dt_maxformat = new_max; 187 } 188 189 dtp->dt_formats[rec->dtrd_format - 1] = 190 rec->dtrd_action == DTRACEACT_PRINTA ? 191 dtrace_printa_create(dtp, fmt.dtfd_string) : 192 dtrace_printf_create(dtp, fmt.dtfd_string); 193 194 free(fmt.dtfd_string); 195 196 if (dtp->dt_formats[rec->dtrd_format - 1] == NULL) { 197 rval = -1; /* dt_errno is set for us */ 198 goto err; 199 } 200 } 201 202 dtp->dt_pdesc[id] = probe; 203 dtp->dt_edesc[id] = enabled; 204 205 return (0); 206 207 err: 208 /* 209 * If we failed, free our allocated probes. Note that if we failed 210 * while allocating formats, we aren't going to free formats that 211 * we have already allocated. This is okay; these formats are 212 * hanging off of dt_formats and will therefore not be leaked. 213 */ 214 free(enabled); 215 free(probe); 216 return (rval); 217 } 218 219 int 220 dt_epid_lookup(dtrace_hdl_t *dtp, dtrace_epid_t epid, 221 dtrace_eprobedesc_t **epdp, dtrace_probedesc_t **pdp) 222 { 223 int rval; 224 225 if (epid >= dtp->dt_maxprobe || dtp->dt_pdesc[epid] == NULL) { 226 if ((rval = dt_epid_add(dtp, epid)) != 0) 227 return (rval); 228 } 229 230 assert(epid < dtp->dt_maxprobe); 231 assert(dtp->dt_edesc[epid] != NULL); 232 assert(dtp->dt_pdesc[epid] != NULL); 233 *epdp = dtp->dt_edesc[epid]; 234 *pdp = dtp->dt_pdesc[epid]; 235 236 return (0); 237 } 238 239 void 240 dt_epid_destroy(dtrace_hdl_t *dtp) 241 { 242 size_t i; 243 244 assert((dtp->dt_pdesc != NULL && dtp->dt_edesc != NULL && 245 dtp->dt_maxprobe > 0) || (dtp->dt_pdesc == NULL && 246 dtp->dt_edesc == NULL && dtp->dt_maxprobe == 0)); 247 248 if (dtp->dt_pdesc == NULL) 249 return; 250 251 for (i = 0; i < dtp->dt_maxprobe; i++) { 252 if (dtp->dt_edesc[i] == NULL) { 253 assert(dtp->dt_pdesc[i] == NULL); 254 continue; 255 } 256 257 assert(dtp->dt_pdesc[i] != NULL); 258 free(dtp->dt_edesc[i]); 259 free(dtp->dt_pdesc[i]); 260 } 261 262 free(dtp->dt_pdesc); 263 dtp->dt_pdesc = NULL; 264 265 free(dtp->dt_edesc); 266 dtp->dt_edesc = NULL; 267 dtp->dt_maxprobe = 0; 268 } 269 270 void * 271 dt_format_lookup(dtrace_hdl_t *dtp, int format) 272 { 273 if (format == 0 || format > dtp->dt_maxformat) 274 return (NULL); 275 276 if (dtp->dt_formats == NULL) 277 return (NULL); 278 279 return (dtp->dt_formats[format - 1]); 280 } 281 282 void 283 dt_format_destroy(dtrace_hdl_t *dtp) 284 { 285 int i; 286 287 for (i = 0; i < dtp->dt_maxformat; i++) { 288 if (dtp->dt_formats[i] != NULL) 289 dt_printf_destroy(dtp->dt_formats[i]); 290 } 291 292 free(dtp->dt_formats); 293 dtp->dt_formats = NULL; 294 } 295 296 static int 297 dt_aggid_add(dtrace_hdl_t *dtp, dtrace_aggid_t id) 298 { 299 dtrace_id_t max; 300 dtrace_epid_t epid; 301 int rval; 302 303 while (id >= (max = dtp->dt_maxagg) || dtp->dt_aggdesc == NULL) { 304 dtrace_id_t new_max = max ? (max << 1) : 1; 305 size_t nsize = new_max * sizeof (void *); 306 dtrace_aggdesc_t **new_aggdesc; 307 308 if ((new_aggdesc = malloc(nsize)) == NULL) 309 return (dt_set_errno(dtp, EDT_NOMEM)); 310 311 bzero(new_aggdesc, nsize); 312 313 if (dtp->dt_aggdesc != NULL) { 314 bcopy(dtp->dt_aggdesc, new_aggdesc, 315 max * sizeof (void *)); 316 free(dtp->dt_aggdesc); 317 } 318 319 dtp->dt_aggdesc = new_aggdesc; 320 dtp->dt_maxagg = new_max; 321 } 322 323 if (dtp->dt_aggdesc[id] == NULL) { 324 dtrace_aggdesc_t *agg, *nagg; 325 326 if ((agg = malloc(sizeof (dtrace_aggdesc_t))) == NULL) 327 return (dt_set_errno(dtp, EDT_NOMEM)); 328 329 bzero(agg, sizeof (dtrace_aggdesc_t)); 330 agg->dtagd_id = id; 331 agg->dtagd_nrecs = 1; 332 333 #if defined(sun) 334 if (dt_ioctl(dtp, DTRACEIOC_AGGDESC, agg) == -1) { 335 #else 336 if (dt_ioctl(dtp, DTRACEIOC_AGGDESC, &agg) == -1) { 337 #endif 338 rval = dt_set_errno(dtp, errno); 339 free(agg); 340 return (rval); 341 } 342 343 if (DTRACE_SIZEOF_AGGDESC(agg) != sizeof (*agg)) { 344 /* 345 * There must be more than one action. Allocate the 346 * appropriate amount of space and try again. 347 */ 348 if ((nagg = malloc(DTRACE_SIZEOF_AGGDESC(agg))) != NULL) 349 bcopy(agg, nagg, sizeof (*agg)); 350 351 free(agg); 352 353 if ((agg = nagg) == NULL) 354 return (dt_set_errno(dtp, EDT_NOMEM)); 355 356 #if defined(sun) 357 rval = dt_ioctl(dtp, DTRACEIOC_AGGDESC, agg); 358 #else 359 rval = dt_ioctl(dtp, DTRACEIOC_AGGDESC, &agg); 360 #endif 361 362 if (rval == -1) { 363 rval = dt_set_errno(dtp, errno); 364 free(agg); 365 return (rval); 366 } 367 } 368 369 /* 370 * If we have a uarg, it's a pointer to the compiler-generated 371 * statement; we'll use this value to get the name and 372 * compiler-generated variable ID for the aggregation. If 373 * we're grabbing an anonymous enabling, this pointer value 374 * is obviously meaningless -- and in this case, we can't 375 * provide the compiler-generated aggregation information. 376 */ 377 if (dtp->dt_options[DTRACEOPT_GRABANON] == DTRACEOPT_UNSET && 378 agg->dtagd_rec[0].dtrd_uarg != 0) { 379 dtrace_stmtdesc_t *sdp; 380 dt_ident_t *aid; 381 382 sdp = (dtrace_stmtdesc_t *)(uintptr_t) 383 agg->dtagd_rec[0].dtrd_uarg; 384 aid = sdp->dtsd_aggdata; 385 agg->dtagd_name = aid->di_name; 386 agg->dtagd_varid = aid->di_id; 387 } else { 388 agg->dtagd_varid = DTRACE_AGGVARIDNONE; 389 } 390 391 if ((epid = agg->dtagd_epid) >= dtp->dt_maxprobe || 392 dtp->dt_pdesc[epid] == NULL) { 393 if ((rval = dt_epid_add(dtp, epid)) != 0) { 394 free(agg); 395 return (rval); 396 } 397 } 398 399 dtp->dt_aggdesc[id] = agg; 400 } 401 402 return (0); 403 } 404 405 int 406 dt_aggid_lookup(dtrace_hdl_t *dtp, dtrace_aggid_t aggid, 407 dtrace_aggdesc_t **adp) 408 { 409 int rval; 410 411 if (aggid >= dtp->dt_maxagg || dtp->dt_aggdesc[aggid] == NULL) { 412 if ((rval = dt_aggid_add(dtp, aggid)) != 0) 413 return (rval); 414 } 415 416 assert(aggid < dtp->dt_maxagg); 417 assert(dtp->dt_aggdesc[aggid] != NULL); 418 *adp = dtp->dt_aggdesc[aggid]; 419 420 return (0); 421 } 422 423 void 424 dt_aggid_destroy(dtrace_hdl_t *dtp) 425 { 426 size_t i; 427 428 assert((dtp->dt_aggdesc != NULL && dtp->dt_maxagg != 0) || 429 (dtp->dt_aggdesc == NULL && dtp->dt_maxagg == 0)); 430 431 if (dtp->dt_aggdesc == NULL) 432 return; 433 434 for (i = 0; i < dtp->dt_maxagg; i++) { 435 if (dtp->dt_aggdesc[i] != NULL) 436 free(dtp->dt_aggdesc[i]); 437 } 438 439 free(dtp->dt_aggdesc); 440 dtp->dt_aggdesc = NULL; 441 dtp->dt_maxagg = 0; 442 } 443