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