1178479Sjb/* 2178479Sjb * CDDL HEADER START 3178479Sjb * 4178479Sjb * The contents of this file are subject to the terms of the 5178479Sjb * Common Development and Distribution License (the "License"). 6178479Sjb * You may not use this file except in compliance with the License. 7178479Sjb * 8178479Sjb * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9178479Sjb * or http://www.opensolaris.org/os/licensing. 10178479Sjb * See the License for the specific language governing permissions 11178479Sjb * and limitations under the License. 12178479Sjb * 13178479Sjb * When distributing Covered Code, include this CDDL HEADER in each 14178479Sjb * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15178479Sjb * If applicable, add the following below this CDDL HEADER, with the 16178479Sjb * fields enclosed by brackets "[]" replaced with your own identifying 17178479Sjb * information: Portions Copyright [yyyy] [name of copyright owner] 18178479Sjb * 19178479Sjb * CDDL HEADER END 20178479Sjb */ 21178479Sjb/* 22178479Sjb * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23178479Sjb * Use is subject to license terms. 24178479Sjb */ 25178479Sjb 26248708Spfg/* 27248708Spfg * Copyright (c) 2011 by Delphix. All rights reserved. 28248708Spfg */ 29178479Sjb 30178479Sjb#include <stdlib.h> 31178479Sjb#include <strings.h> 32178479Sjb#include <errno.h> 33178479Sjb#include <unistd.h> 34178479Sjb#include <assert.h> 35178479Sjb 36178479Sjb#include <dt_impl.h> 37178479Sjb#include <dt_printf.h> 38178479Sjb 39178479Sjbstatic int 40248708Spfgdt_strdata_add(dtrace_hdl_t *dtp, dtrace_recdesc_t *rec, void ***data, int *max) 41248708Spfg{ 42270214Smarkj int maxformat, rval; 43248708Spfg dtrace_fmtdesc_t fmt; 44248708Spfg void *result; 45248708Spfg 46248708Spfg if (rec->dtrd_format == 0) 47248708Spfg return (0); 48248708Spfg 49248708Spfg if (rec->dtrd_format <= *max && 50248708Spfg (*data)[rec->dtrd_format - 1] != NULL) { 51248708Spfg return (0); 52248708Spfg } 53248708Spfg 54248708Spfg bzero(&fmt, sizeof (fmt)); 55248708Spfg fmt.dtfd_format = rec->dtrd_format; 56248708Spfg fmt.dtfd_string = NULL; 57248708Spfg fmt.dtfd_length = 0; 58248708Spfg 59248708Spfg if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) 60248708Spfg return (dt_set_errno(dtp, errno)); 61248708Spfg 62248708Spfg if ((fmt.dtfd_string = dt_alloc(dtp, fmt.dtfd_length)) == NULL) 63248708Spfg return (dt_set_errno(dtp, EDT_NOMEM)); 64248708Spfg 65248708Spfg if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) { 66270214Smarkj rval = dt_set_errno(dtp, errno); 67248708Spfg free(fmt.dtfd_string); 68270214Smarkj return (rval); 69248708Spfg } 70248708Spfg 71248708Spfg while (rec->dtrd_format > (maxformat = *max)) { 72248708Spfg int new_max = maxformat ? (maxformat << 1) : 1; 73248708Spfg size_t nsize = new_max * sizeof (void *); 74248708Spfg size_t osize = maxformat * sizeof (void *); 75248708Spfg void **new_data = dt_zalloc(dtp, nsize); 76248708Spfg 77248708Spfg if (new_data == NULL) { 78248708Spfg dt_free(dtp, fmt.dtfd_string); 79248708Spfg return (dt_set_errno(dtp, EDT_NOMEM)); 80248708Spfg } 81248708Spfg 82248708Spfg bcopy(*data, new_data, osize); 83248708Spfg free(*data); 84248708Spfg 85248708Spfg *data = new_data; 86248708Spfg *max = new_max; 87248708Spfg } 88248708Spfg 89248708Spfg switch (rec->dtrd_action) { 90248708Spfg case DTRACEACT_DIFEXPR: 91248708Spfg result = fmt.dtfd_string; 92248708Spfg break; 93248708Spfg case DTRACEACT_PRINTA: 94248708Spfg result = dtrace_printa_create(dtp, fmt.dtfd_string); 95248708Spfg dt_free(dtp, fmt.dtfd_string); 96248708Spfg break; 97248708Spfg default: 98248708Spfg result = dtrace_printf_create(dtp, fmt.dtfd_string); 99248708Spfg dt_free(dtp, fmt.dtfd_string); 100248708Spfg break; 101248708Spfg } 102248708Spfg 103248708Spfg if (result == NULL) 104248708Spfg return (-1); 105248708Spfg 106248708Spfg (*data)[rec->dtrd_format - 1] = result; 107248708Spfg 108248708Spfg return (0); 109248708Spfg} 110248708Spfg 111248708Spfgstatic int 112178479Sjbdt_epid_add(dtrace_hdl_t *dtp, dtrace_epid_t id) 113178479Sjb{ 114178479Sjb dtrace_id_t max; 115248708Spfg int rval, i; 116178479Sjb dtrace_eprobedesc_t *enabled, *nenabled; 117178479Sjb dtrace_probedesc_t *probe; 118178479Sjb 119178479Sjb while (id >= (max = dtp->dt_maxprobe) || dtp->dt_pdesc == NULL) { 120178479Sjb dtrace_id_t new_max = max ? (max << 1) : 1; 121178479Sjb size_t nsize = new_max * sizeof (void *); 122178479Sjb dtrace_probedesc_t **new_pdesc; 123178479Sjb dtrace_eprobedesc_t **new_edesc; 124178479Sjb 125178479Sjb if ((new_pdesc = malloc(nsize)) == NULL || 126178479Sjb (new_edesc = malloc(nsize)) == NULL) { 127178479Sjb free(new_pdesc); 128178479Sjb return (dt_set_errno(dtp, EDT_NOMEM)); 129178479Sjb } 130178479Sjb 131178479Sjb bzero(new_pdesc, nsize); 132178479Sjb bzero(new_edesc, nsize); 133178479Sjb 134178479Sjb if (dtp->dt_pdesc != NULL) { 135178479Sjb size_t osize = max * sizeof (void *); 136178479Sjb 137178479Sjb bcopy(dtp->dt_pdesc, new_pdesc, osize); 138178479Sjb free(dtp->dt_pdesc); 139178479Sjb 140178479Sjb bcopy(dtp->dt_edesc, new_edesc, osize); 141178479Sjb free(dtp->dt_edesc); 142178479Sjb } 143178479Sjb 144178479Sjb dtp->dt_pdesc = new_pdesc; 145178479Sjb dtp->dt_edesc = new_edesc; 146178479Sjb dtp->dt_maxprobe = new_max; 147178479Sjb } 148178479Sjb 149178479Sjb if (dtp->dt_pdesc[id] != NULL) 150178479Sjb return (0); 151178479Sjb 152178479Sjb if ((enabled = malloc(sizeof (dtrace_eprobedesc_t))) == NULL) 153178479Sjb return (dt_set_errno(dtp, EDT_NOMEM)); 154178479Sjb 155178479Sjb bzero(enabled, sizeof (dtrace_eprobedesc_t)); 156178479Sjb enabled->dtepd_epid = id; 157178479Sjb enabled->dtepd_nrecs = 1; 158178479Sjb 159297077Smav#ifdef illumos 160178479Sjb if (dt_ioctl(dtp, DTRACEIOC_EPROBE, enabled) == -1) { 161178562Sjb#else 162178562Sjb if (dt_ioctl(dtp, DTRACEIOC_EPROBE, &enabled) == -1) { 163178562Sjb#endif 164178479Sjb rval = dt_set_errno(dtp, errno); 165178479Sjb free(enabled); 166178479Sjb return (rval); 167178479Sjb } 168178479Sjb 169178479Sjb if (DTRACE_SIZEOF_EPROBEDESC(enabled) != sizeof (*enabled)) { 170178479Sjb /* 171178479Sjb * There must be more than one action. Allocate the 172178479Sjb * appropriate amount of space and try again. 173178479Sjb */ 174178479Sjb if ((nenabled = 175178479Sjb malloc(DTRACE_SIZEOF_EPROBEDESC(enabled))) != NULL) 176178479Sjb bcopy(enabled, nenabled, sizeof (*enabled)); 177178479Sjb 178178479Sjb free(enabled); 179178479Sjb 180178479Sjb if ((enabled = nenabled) == NULL) 181178479Sjb return (dt_set_errno(dtp, EDT_NOMEM)); 182178479Sjb 183297077Smav#ifdef illumos 184178479Sjb rval = dt_ioctl(dtp, DTRACEIOC_EPROBE, enabled); 185178562Sjb#else 186178562Sjb rval = dt_ioctl(dtp, DTRACEIOC_EPROBE, &enabled); 187178562Sjb#endif 188178479Sjb 189178479Sjb if (rval == -1) { 190178479Sjb rval = dt_set_errno(dtp, errno); 191178479Sjb free(enabled); 192178479Sjb return (rval); 193178479Sjb } 194178479Sjb } 195178479Sjb 196178479Sjb if ((probe = malloc(sizeof (dtrace_probedesc_t))) == NULL) { 197178479Sjb free(enabled); 198178479Sjb return (dt_set_errno(dtp, EDT_NOMEM)); 199178479Sjb } 200178479Sjb 201178479Sjb probe->dtpd_id = enabled->dtepd_probeid; 202178479Sjb 203178479Sjb if (dt_ioctl(dtp, DTRACEIOC_PROBES, probe) == -1) { 204178479Sjb rval = dt_set_errno(dtp, errno); 205178479Sjb goto err; 206178479Sjb } 207178479Sjb 208178479Sjb for (i = 0; i < enabled->dtepd_nrecs; i++) { 209178479Sjb dtrace_recdesc_t *rec = &enabled->dtepd_rec[i]; 210178479Sjb 211248708Spfg if (DTRACEACT_ISPRINTFLIKE(rec->dtrd_action)) { 212248708Spfg if (dt_strdata_add(dtp, rec, &dtp->dt_formats, 213248708Spfg &dtp->dt_maxformat) != 0) { 214248708Spfg rval = -1; 215178479Sjb goto err; 216178479Sjb } 217248708Spfg } else if (rec->dtrd_action == DTRACEACT_DIFEXPR) { 218248708Spfg if (dt_strdata_add(dtp, rec, 219248708Spfg (void ***)&dtp->dt_strdata, 220248708Spfg &dtp->dt_maxstrdata) != 0) { 221248708Spfg rval = -1; 222248708Spfg goto err; 223248708Spfg } 224178479Sjb } 225178479Sjb 226178479Sjb } 227178479Sjb 228178479Sjb dtp->dt_pdesc[id] = probe; 229178479Sjb dtp->dt_edesc[id] = enabled; 230178479Sjb 231178479Sjb return (0); 232178479Sjb 233178479Sjberr: 234178479Sjb /* 235178479Sjb * If we failed, free our allocated probes. Note that if we failed 236178479Sjb * while allocating formats, we aren't going to free formats that 237178479Sjb * we have already allocated. This is okay; these formats are 238178479Sjb * hanging off of dt_formats and will therefore not be leaked. 239178479Sjb */ 240178479Sjb free(enabled); 241178479Sjb free(probe); 242178479Sjb return (rval); 243178479Sjb} 244178479Sjb 245178479Sjbint 246178479Sjbdt_epid_lookup(dtrace_hdl_t *dtp, dtrace_epid_t epid, 247178479Sjb dtrace_eprobedesc_t **epdp, dtrace_probedesc_t **pdp) 248178479Sjb{ 249178479Sjb int rval; 250178479Sjb 251178479Sjb if (epid >= dtp->dt_maxprobe || dtp->dt_pdesc[epid] == NULL) { 252178479Sjb if ((rval = dt_epid_add(dtp, epid)) != 0) 253178479Sjb return (rval); 254178479Sjb } 255178479Sjb 256178479Sjb assert(epid < dtp->dt_maxprobe); 257178479Sjb assert(dtp->dt_edesc[epid] != NULL); 258178479Sjb assert(dtp->dt_pdesc[epid] != NULL); 259178479Sjb *epdp = dtp->dt_edesc[epid]; 260178479Sjb *pdp = dtp->dt_pdesc[epid]; 261178479Sjb 262178479Sjb return (0); 263178479Sjb} 264178479Sjb 265178479Sjbvoid 266178479Sjbdt_epid_destroy(dtrace_hdl_t *dtp) 267178479Sjb{ 268178479Sjb size_t i; 269178479Sjb 270178479Sjb assert((dtp->dt_pdesc != NULL && dtp->dt_edesc != NULL && 271178479Sjb dtp->dt_maxprobe > 0) || (dtp->dt_pdesc == NULL && 272178479Sjb dtp->dt_edesc == NULL && dtp->dt_maxprobe == 0)); 273178479Sjb 274178479Sjb if (dtp->dt_pdesc == NULL) 275178479Sjb return; 276178479Sjb 277178479Sjb for (i = 0; i < dtp->dt_maxprobe; i++) { 278178479Sjb if (dtp->dt_edesc[i] == NULL) { 279178479Sjb assert(dtp->dt_pdesc[i] == NULL); 280178479Sjb continue; 281178479Sjb } 282178479Sjb 283178479Sjb assert(dtp->dt_pdesc[i] != NULL); 284178479Sjb free(dtp->dt_edesc[i]); 285178479Sjb free(dtp->dt_pdesc[i]); 286178479Sjb } 287178479Sjb 288178479Sjb free(dtp->dt_pdesc); 289178479Sjb dtp->dt_pdesc = NULL; 290178479Sjb 291178479Sjb free(dtp->dt_edesc); 292178479Sjb dtp->dt_edesc = NULL; 293178479Sjb dtp->dt_maxprobe = 0; 294178479Sjb} 295178479Sjb 296178479Sjbvoid * 297178479Sjbdt_format_lookup(dtrace_hdl_t *dtp, int format) 298178479Sjb{ 299178479Sjb if (format == 0 || format > dtp->dt_maxformat) 300178479Sjb return (NULL); 301178479Sjb 302178479Sjb if (dtp->dt_formats == NULL) 303178479Sjb return (NULL); 304178479Sjb 305178479Sjb return (dtp->dt_formats[format - 1]); 306178479Sjb} 307178479Sjb 308178479Sjbvoid 309178479Sjbdt_format_destroy(dtrace_hdl_t *dtp) 310178479Sjb{ 311178479Sjb int i; 312178479Sjb 313178479Sjb for (i = 0; i < dtp->dt_maxformat; i++) { 314178479Sjb if (dtp->dt_formats[i] != NULL) 315178479Sjb dt_printf_destroy(dtp->dt_formats[i]); 316178479Sjb } 317178479Sjb 318178479Sjb free(dtp->dt_formats); 319178479Sjb dtp->dt_formats = NULL; 320178479Sjb} 321178479Sjb 322178479Sjbstatic int 323178479Sjbdt_aggid_add(dtrace_hdl_t *dtp, dtrace_aggid_t id) 324178479Sjb{ 325178479Sjb dtrace_id_t max; 326178479Sjb dtrace_epid_t epid; 327178479Sjb int rval; 328178479Sjb 329178479Sjb while (id >= (max = dtp->dt_maxagg) || dtp->dt_aggdesc == NULL) { 330178479Sjb dtrace_id_t new_max = max ? (max << 1) : 1; 331178479Sjb size_t nsize = new_max * sizeof (void *); 332178479Sjb dtrace_aggdesc_t **new_aggdesc; 333178479Sjb 334178479Sjb if ((new_aggdesc = malloc(nsize)) == NULL) 335178479Sjb return (dt_set_errno(dtp, EDT_NOMEM)); 336178479Sjb 337178479Sjb bzero(new_aggdesc, nsize); 338178479Sjb 339178479Sjb if (dtp->dt_aggdesc != NULL) { 340178479Sjb bcopy(dtp->dt_aggdesc, new_aggdesc, 341178479Sjb max * sizeof (void *)); 342178479Sjb free(dtp->dt_aggdesc); 343178479Sjb } 344178479Sjb 345178479Sjb dtp->dt_aggdesc = new_aggdesc; 346178479Sjb dtp->dt_maxagg = new_max; 347178479Sjb } 348178479Sjb 349178479Sjb if (dtp->dt_aggdesc[id] == NULL) { 350178479Sjb dtrace_aggdesc_t *agg, *nagg; 351178479Sjb 352178479Sjb if ((agg = malloc(sizeof (dtrace_aggdesc_t))) == NULL) 353178479Sjb return (dt_set_errno(dtp, EDT_NOMEM)); 354178479Sjb 355178479Sjb bzero(agg, sizeof (dtrace_aggdesc_t)); 356178479Sjb agg->dtagd_id = id; 357178479Sjb agg->dtagd_nrecs = 1; 358178479Sjb 359297077Smav#ifdef illumos 360178479Sjb if (dt_ioctl(dtp, DTRACEIOC_AGGDESC, agg) == -1) { 361178562Sjb#else 362178562Sjb if (dt_ioctl(dtp, DTRACEIOC_AGGDESC, &agg) == -1) { 363178562Sjb#endif 364178479Sjb rval = dt_set_errno(dtp, errno); 365178479Sjb free(agg); 366178479Sjb return (rval); 367178479Sjb } 368178479Sjb 369178479Sjb if (DTRACE_SIZEOF_AGGDESC(agg) != sizeof (*agg)) { 370178479Sjb /* 371178479Sjb * There must be more than one action. Allocate the 372178479Sjb * appropriate amount of space and try again. 373178479Sjb */ 374178479Sjb if ((nagg = malloc(DTRACE_SIZEOF_AGGDESC(agg))) != NULL) 375178479Sjb bcopy(agg, nagg, sizeof (*agg)); 376178479Sjb 377178479Sjb free(agg); 378178479Sjb 379178479Sjb if ((agg = nagg) == NULL) 380178479Sjb return (dt_set_errno(dtp, EDT_NOMEM)); 381178479Sjb 382297077Smav#ifdef illumos 383178479Sjb rval = dt_ioctl(dtp, DTRACEIOC_AGGDESC, agg); 384178562Sjb#else 385178562Sjb rval = dt_ioctl(dtp, DTRACEIOC_AGGDESC, &agg); 386178562Sjb#endif 387178479Sjb 388178479Sjb if (rval == -1) { 389178479Sjb rval = dt_set_errno(dtp, errno); 390178479Sjb free(agg); 391178479Sjb return (rval); 392178479Sjb } 393178479Sjb } 394178479Sjb 395178479Sjb /* 396178479Sjb * If we have a uarg, it's a pointer to the compiler-generated 397178479Sjb * statement; we'll use this value to get the name and 398178479Sjb * compiler-generated variable ID for the aggregation. If 399178479Sjb * we're grabbing an anonymous enabling, this pointer value 400178479Sjb * is obviously meaningless -- and in this case, we can't 401178479Sjb * provide the compiler-generated aggregation information. 402178479Sjb */ 403178479Sjb if (dtp->dt_options[DTRACEOPT_GRABANON] == DTRACEOPT_UNSET && 404178562Sjb agg->dtagd_rec[0].dtrd_uarg != 0) { 405178479Sjb dtrace_stmtdesc_t *sdp; 406178479Sjb dt_ident_t *aid; 407178479Sjb 408178479Sjb sdp = (dtrace_stmtdesc_t *)(uintptr_t) 409178479Sjb agg->dtagd_rec[0].dtrd_uarg; 410178479Sjb aid = sdp->dtsd_aggdata; 411178479Sjb agg->dtagd_name = aid->di_name; 412178479Sjb agg->dtagd_varid = aid->di_id; 413178479Sjb } else { 414178479Sjb agg->dtagd_varid = DTRACE_AGGVARIDNONE; 415178479Sjb } 416178479Sjb 417178479Sjb if ((epid = agg->dtagd_epid) >= dtp->dt_maxprobe || 418178479Sjb dtp->dt_pdesc[epid] == NULL) { 419178479Sjb if ((rval = dt_epid_add(dtp, epid)) != 0) { 420178479Sjb free(agg); 421178479Sjb return (rval); 422178479Sjb } 423178479Sjb } 424178479Sjb 425178479Sjb dtp->dt_aggdesc[id] = agg; 426178479Sjb } 427178479Sjb 428178479Sjb return (0); 429178479Sjb} 430178479Sjb 431178479Sjbint 432178479Sjbdt_aggid_lookup(dtrace_hdl_t *dtp, dtrace_aggid_t aggid, 433178479Sjb dtrace_aggdesc_t **adp) 434178479Sjb{ 435178479Sjb int rval; 436178479Sjb 437178479Sjb if (aggid >= dtp->dt_maxagg || dtp->dt_aggdesc[aggid] == NULL) { 438178479Sjb if ((rval = dt_aggid_add(dtp, aggid)) != 0) 439178479Sjb return (rval); 440178479Sjb } 441178479Sjb 442178479Sjb assert(aggid < dtp->dt_maxagg); 443178479Sjb assert(dtp->dt_aggdesc[aggid] != NULL); 444178479Sjb *adp = dtp->dt_aggdesc[aggid]; 445178479Sjb 446178479Sjb return (0); 447178479Sjb} 448178479Sjb 449178479Sjbvoid 450178479Sjbdt_aggid_destroy(dtrace_hdl_t *dtp) 451178479Sjb{ 452178479Sjb size_t i; 453178479Sjb 454178479Sjb assert((dtp->dt_aggdesc != NULL && dtp->dt_maxagg != 0) || 455178479Sjb (dtp->dt_aggdesc == NULL && dtp->dt_maxagg == 0)); 456178479Sjb 457178479Sjb if (dtp->dt_aggdesc == NULL) 458178479Sjb return; 459178479Sjb 460178479Sjb for (i = 0; i < dtp->dt_maxagg; i++) { 461178479Sjb if (dtp->dt_aggdesc[i] != NULL) 462178479Sjb free(dtp->dt_aggdesc[i]); 463178479Sjb } 464178479Sjb 465178479Sjb free(dtp->dt_aggdesc); 466178479Sjb dtp->dt_aggdesc = NULL; 467178479Sjb dtp->dt_maxagg = 0; 468178479Sjb} 469248708Spfg 470248708Spfgconst char * 471248708Spfgdt_strdata_lookup(dtrace_hdl_t *dtp, int idx) 472248708Spfg{ 473248708Spfg if (idx == 0 || idx > dtp->dt_maxstrdata) 474248708Spfg return (NULL); 475248708Spfg 476248708Spfg if (dtp->dt_strdata == NULL) 477248708Spfg return (NULL); 478248708Spfg 479248708Spfg return (dtp->dt_strdata[idx - 1]); 480248708Spfg} 481248708Spfg 482248708Spfgvoid 483248708Spfgdt_strdata_destroy(dtrace_hdl_t *dtp) 484248708Spfg{ 485248708Spfg int i; 486248708Spfg 487248708Spfg for (i = 0; i < dtp->dt_maxstrdata; i++) { 488248708Spfg free(dtp->dt_strdata[i]); 489248708Spfg } 490248708Spfg 491248708Spfg free(dtp->dt_strdata); 492248708Spfg dtp->dt_strdata = NULL; 493248708Spfg} 494