Home | History | Annotate | Line # | Download | only in common
      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