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 /* 27 * Copyright (c) 2011 by Delphix. All rights reserved. 28 */ 29 30 #include <stdlib.h> 31 #include <strings.h> 32 #include <errno.h> 33 #include <unistd.h> 34 #include <assert.h> 35 36 #include <dt_impl.h> 37 #include <dt_printf.h> 38 39 static int 40 dt_strdata_add(dtrace_hdl_t *dtp, dtrace_recdesc_t *rec, void ***data, int *max) 41 { 42 int maxformat, rval; 43 dtrace_fmtdesc_t fmt; 44 void *result; 45 46 if (rec->dtrd_format == 0) 47 return (0); 48 49 if (rec->dtrd_format <= *max && 50 (*data)[rec->dtrd_format - 1] != NULL) { 51 return (0); 52 } 53 54 bzero(&fmt, sizeof (fmt)); 55 fmt.dtfd_format = rec->dtrd_format; 56 fmt.dtfd_string = NULL; 57 fmt.dtfd_length = 0; 58 59 if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) 60 return (dt_set_errno(dtp, errno)); 61 62 if ((fmt.dtfd_string = dt_alloc(dtp, fmt.dtfd_length)) == NULL) 63 return (dt_set_errno(dtp, EDT_NOMEM)); 64 65 if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) { 66 rval = dt_set_errno(dtp, errno); 67 free(fmt.dtfd_string); 68 return (rval); 69 } 70 71 while (rec->dtrd_format > (maxformat = *max)) { 72 int new_max = maxformat ? (maxformat << 1) : 1; 73 size_t nsize = new_max * sizeof (void *); 74 size_t osize = maxformat * sizeof (void *); 75 void **new_data = dt_zalloc(dtp, nsize); 76 77 if (new_data == NULL) { 78 dt_free(dtp, fmt.dtfd_string); 79 return (dt_set_errno(dtp, EDT_NOMEM)); 80 } 81 82 bcopy(*data, new_data, osize); 83 free(*data); 84 85 *data = new_data; 86 *max = new_max; 87 } 88 89 switch (rec->dtrd_action) { 90 case DTRACEACT_DIFEXPR: 91 result = fmt.dtfd_string; 92 break; 93 case DTRACEACT_PRINTA: 94 result = dtrace_printa_create(dtp, fmt.dtfd_string); 95 dt_free(dtp, fmt.dtfd_string); 96 break; 97 default: 98 result = dtrace_printf_create(dtp, fmt.dtfd_string); 99 dt_free(dtp, fmt.dtfd_string); 100 break; 101 } 102 103 if (result == NULL) 104 return (-1); 105 106 (*data)[rec->dtrd_format - 1] = result; 107 108 return (0); 109 } 110 111 static int 112 dt_epid_add(dtrace_hdl_t *dtp, dtrace_epid_t id) 113 { 114 dtrace_id_t max; 115 int rval, i; 116 dtrace_eprobedesc_t *enabled, *nenabled; 117 dtrace_probedesc_t *probe; 118 119 while (id >= (max = dtp->dt_maxprobe) || dtp->dt_pdesc == NULL) { 120 dtrace_id_t new_max = max ? (max << 1) : 1; 121 size_t nsize = new_max * sizeof (void *); 122 dtrace_probedesc_t **new_pdesc; 123 dtrace_eprobedesc_t **new_edesc; 124 125 if ((new_pdesc = malloc(nsize)) == NULL || 126 (new_edesc = malloc(nsize)) == NULL) { 127 free(new_pdesc); 128 return (dt_set_errno(dtp, EDT_NOMEM)); 129 } 130 131 bzero(new_pdesc, nsize); 132 bzero(new_edesc, nsize); 133 134 if (dtp->dt_pdesc != NULL) { 135 size_t osize = max * sizeof (void *); 136 137 bcopy(dtp->dt_pdesc, new_pdesc, osize); 138 free(dtp->dt_pdesc); 139 140 bcopy(dtp->dt_edesc, new_edesc, osize); 141 free(dtp->dt_edesc); 142 } 143 144 dtp->dt_pdesc = new_pdesc; 145 dtp->dt_edesc = new_edesc; 146 dtp->dt_maxprobe = new_max; 147 } 148 149 if (dtp->dt_pdesc[id] != NULL) 150 return (0); 151 152 if ((enabled = malloc(sizeof (dtrace_eprobedesc_t))) == NULL) 153 return (dt_set_errno(dtp, EDT_NOMEM)); 154 155 bzero(enabled, sizeof (dtrace_eprobedesc_t)); 156 enabled->dtepd_epid = id; 157 enabled->dtepd_nrecs = 1; 158 159 #ifdef illumos 160 if (dt_ioctl(dtp, DTRACEIOC_EPROBE, enabled) == -1) { 161 #else 162 if (dt_ioctl(dtp, DTRACEIOC_EPROBE, &enabled) == -1) { 163 #endif 164 rval = dt_set_errno(dtp, errno); 165 free(enabled); 166 return (rval); 167 } 168 169 if (DTRACE_SIZEOF_EPROBEDESC(enabled) != sizeof (*enabled)) { 170 /* 171 * There must be more than one action. Allocate the 172 * appropriate amount of space and try again. 173 */ 174 if ((nenabled = 175 malloc(DTRACE_SIZEOF_EPROBEDESC(enabled))) != NULL) 176 bcopy(enabled, nenabled, sizeof (*enabled)); 177 178 free(enabled); 179 180 if ((enabled = nenabled) == NULL) 181 return (dt_set_errno(dtp, EDT_NOMEM)); 182 183 #ifdef illumos 184 rval = dt_ioctl(dtp, DTRACEIOC_EPROBE, enabled); 185 #else 186 rval = dt_ioctl(dtp, DTRACEIOC_EPROBE, &enabled); 187 #endif 188 189 if (rval == -1) { 190 rval = dt_set_errno(dtp, errno); 191 free(enabled); 192 return (rval); 193 } 194 } 195 196 if ((probe = malloc(sizeof (dtrace_probedesc_t))) == NULL) { 197 free(enabled); 198 return (dt_set_errno(dtp, EDT_NOMEM)); 199 } 200 201 probe->dtpd_id = enabled->dtepd_probeid; 202 203 if (dt_ioctl(dtp, DTRACEIOC_PROBES, probe) == -1) { 204 rval = dt_set_errno(dtp, errno); 205 goto err; 206 } 207 208 for (i = 0; i < enabled->dtepd_nrecs; i++) { 209 dtrace_recdesc_t *rec = &enabled->dtepd_rec[i]; 210 211 if (DTRACEACT_ISPRINTFLIKE(rec->dtrd_action)) { 212 if (dt_strdata_add(dtp, rec, &dtp->dt_formats, 213 &dtp->dt_maxformat) != 0) { 214 rval = -1; 215 goto err; 216 } 217 } else if (rec->dtrd_action == DTRACEACT_DIFEXPR) { 218 if (dt_strdata_add(dtp, rec, 219 (void ***)&dtp->dt_strdata, 220 &dtp->dt_maxstrdata) != 0) { 221 rval = -1; 222 goto err; 223 } 224 } 225 226 } 227 228 dtp->dt_pdesc[id] = probe; 229 dtp->dt_edesc[id] = enabled; 230 231 return (0); 232 233 err: 234 /* 235 * If we failed, free our allocated probes. Note that if we failed 236 * while allocating formats, we aren't going to free formats that 237 * we have already allocated. This is okay; these formats are 238 * hanging off of dt_formats and will therefore not be leaked. 239 */ 240 free(enabled); 241 free(probe); 242 return (rval); 243 } 244 245 int 246 dt_epid_lookup(dtrace_hdl_t *dtp, dtrace_epid_t epid, 247 dtrace_eprobedesc_t **epdp, dtrace_probedesc_t **pdp) 248 { 249 int rval; 250 251 if (epid >= dtp->dt_maxprobe || dtp->dt_pdesc[epid] == NULL) { 252 if ((rval = dt_epid_add(dtp, epid)) != 0) 253 return (rval); 254 } 255 256 assert(epid < dtp->dt_maxprobe); 257 assert(dtp->dt_edesc[epid] != NULL); 258 assert(dtp->dt_pdesc[epid] != NULL); 259 *epdp = dtp->dt_edesc[epid]; 260 *pdp = dtp->dt_pdesc[epid]; 261 262 return (0); 263 } 264 265 void 266 dt_epid_destroy(dtrace_hdl_t *dtp) 267 { 268 size_t i; 269 270 assert((dtp->dt_pdesc != NULL && dtp->dt_edesc != NULL && 271 dtp->dt_maxprobe > 0) || (dtp->dt_pdesc == NULL && 272 dtp->dt_edesc == NULL && dtp->dt_maxprobe == 0)); 273 274 if (dtp->dt_pdesc == NULL) 275 return; 276 277 for (i = 0; i < dtp->dt_maxprobe; i++) { 278 if (dtp->dt_edesc[i] == NULL) { 279 assert(dtp->dt_pdesc[i] == NULL); 280 continue; 281 } 282 283 assert(dtp->dt_pdesc[i] != NULL); 284 free(dtp->dt_edesc[i]); 285 free(dtp->dt_pdesc[i]); 286 } 287 288 free(dtp->dt_pdesc); 289 dtp->dt_pdesc = NULL; 290 291 free(dtp->dt_edesc); 292 dtp->dt_edesc = NULL; 293 dtp->dt_maxprobe = 0; 294 } 295 296 void * 297 dt_format_lookup(dtrace_hdl_t *dtp, int format) 298 { 299 if (format == 0 || format > dtp->dt_maxformat) 300 return (NULL); 301 302 if (dtp->dt_formats == NULL) 303 return (NULL); 304 305 return (dtp->dt_formats[format - 1]); 306 } 307 308 void 309 dt_format_destroy(dtrace_hdl_t *dtp) 310 { 311 int i; 312 313 for (i = 0; i < dtp->dt_maxformat; i++) { 314 if (dtp->dt_formats[i] != NULL) 315 dt_printf_destroy(dtp->dt_formats[i]); 316 } 317 318 free(dtp->dt_formats); 319 dtp->dt_formats = NULL; 320 } 321 322 static int 323 dt_aggid_add(dtrace_hdl_t *dtp, dtrace_aggid_t id) 324 { 325 dtrace_id_t max; 326 dtrace_epid_t epid; 327 int rval; 328 329 while (id >= (max = dtp->dt_maxagg) || dtp->dt_aggdesc == NULL) { 330 dtrace_id_t new_max = max ? (max << 1) : 1; 331 size_t nsize = new_max * sizeof (void *); 332 dtrace_aggdesc_t **new_aggdesc; 333 334 if ((new_aggdesc = malloc(nsize)) == NULL) 335 return (dt_set_errno(dtp, EDT_NOMEM)); 336 337 bzero(new_aggdesc, nsize); 338 339 if (dtp->dt_aggdesc != NULL) { 340 bcopy(dtp->dt_aggdesc, new_aggdesc, 341 max * sizeof (void *)); 342 free(dtp->dt_aggdesc); 343 } 344 345 dtp->dt_aggdesc = new_aggdesc; 346 dtp->dt_maxagg = new_max; 347 } 348 349 if (dtp->dt_aggdesc[id] == NULL) { 350 dtrace_aggdesc_t *agg, *nagg; 351 352 if ((agg = malloc(sizeof (dtrace_aggdesc_t))) == NULL) 353 return (dt_set_errno(dtp, EDT_NOMEM)); 354 355 bzero(agg, sizeof (dtrace_aggdesc_t)); 356 agg->dtagd_id = id; 357 agg->dtagd_nrecs = 1; 358 359 #ifdef illumos 360 if (dt_ioctl(dtp, DTRACEIOC_AGGDESC, agg) == -1) { 361 #else 362 if (dt_ioctl(dtp, DTRACEIOC_AGGDESC, &agg) == -1) { 363 #endif 364 rval = dt_set_errno(dtp, errno); 365 free(agg); 366 return (rval); 367 } 368 369 if (DTRACE_SIZEOF_AGGDESC(agg) != sizeof (*agg)) { 370 /* 371 * There must be more than one action. Allocate the 372 * appropriate amount of space and try again. 373 */ 374 if ((nagg = malloc(DTRACE_SIZEOF_AGGDESC(agg))) != NULL) 375 bcopy(agg, nagg, sizeof (*agg)); 376 377 free(agg); 378 379 if ((agg = nagg) == NULL) 380 return (dt_set_errno(dtp, EDT_NOMEM)); 381 382 #ifdef illumos 383 rval = dt_ioctl(dtp, DTRACEIOC_AGGDESC, agg); 384 #else 385 rval = dt_ioctl(dtp, DTRACEIOC_AGGDESC, &agg); 386 #endif 387 388 if (rval == -1) { 389 rval = dt_set_errno(dtp, errno); 390 free(agg); 391 return (rval); 392 } 393 } 394 395 /* 396 * If we have a uarg, it's a pointer to the compiler-generated 397 * statement; we'll use this value to get the name and 398 * compiler-generated variable ID for the aggregation. If 399 * we're grabbing an anonymous enabling, this pointer value 400 * is obviously meaningless -- and in this case, we can't 401 * provide the compiler-generated aggregation information. 402 */ 403 if (dtp->dt_options[DTRACEOPT_GRABANON] == DTRACEOPT_UNSET && 404 agg->dtagd_rec[0].dtrd_uarg != 0) { 405 dtrace_stmtdesc_t *sdp; 406 dt_ident_t *aid; 407 408 sdp = (dtrace_stmtdesc_t *)(uintptr_t) 409 agg->dtagd_rec[0].dtrd_uarg; 410 aid = sdp->dtsd_aggdata; 411 agg->dtagd_name = aid->di_name; 412 agg->dtagd_varid = aid->di_id; 413 } else { 414 agg->dtagd_varid = DTRACE_AGGVARIDNONE; 415 } 416 417 if ((epid = agg->dtagd_epid) >= dtp->dt_maxprobe || 418 dtp->dt_pdesc[epid] == NULL) { 419 if ((rval = dt_epid_add(dtp, epid)) != 0) { 420 free(agg); 421 return (rval); 422 } 423 } 424 425 dtp->dt_aggdesc[id] = agg; 426 } 427 428 return (0); 429 } 430 431 int 432 dt_aggid_lookup(dtrace_hdl_t *dtp, dtrace_aggid_t aggid, 433 dtrace_aggdesc_t **adp) 434 { 435 int rval; 436 437 if (aggid >= dtp->dt_maxagg || dtp->dt_aggdesc[aggid] == NULL) { 438 if ((rval = dt_aggid_add(dtp, aggid)) != 0) 439 return (rval); 440 } 441 442 assert(aggid < dtp->dt_maxagg); 443 assert(dtp->dt_aggdesc[aggid] != NULL); 444 *adp = dtp->dt_aggdesc[aggid]; 445 446 return (0); 447 } 448 449 void 450 dt_aggid_destroy(dtrace_hdl_t *dtp) 451 { 452 size_t i; 453 454 assert((dtp->dt_aggdesc != NULL && dtp->dt_maxagg != 0) || 455 (dtp->dt_aggdesc == NULL && dtp->dt_maxagg == 0)); 456 457 if (dtp->dt_aggdesc == NULL) 458 return; 459 460 for (i = 0; i < dtp->dt_maxagg; i++) { 461 if (dtp->dt_aggdesc[i] != NULL) 462 free(dtp->dt_aggdesc[i]); 463 } 464 465 free(dtp->dt_aggdesc); 466 dtp->dt_aggdesc = NULL; 467 dtp->dt_maxagg = 0; 468 } 469 470 const char * 471 dt_strdata_lookup(dtrace_hdl_t *dtp, int idx) 472 { 473 if (idx == 0 || idx > dtp->dt_maxstrdata) 474 return (NULL); 475 476 if (dtp->dt_strdata == NULL) 477 return (NULL); 478 479 return (dtp->dt_strdata[idx - 1]); 480 } 481 482 void 483 dt_strdata_destroy(dtrace_hdl_t *dtp) 484 { 485 int i; 486 487 for (i = 0; i < dtp->dt_maxstrdata; i++) { 488 free(dtp->dt_strdata[i]); 489 } 490 491 free(dtp->dt_strdata); 492 dtp->dt_strdata = NULL; 493 } 494