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 26249856Spfg/* 27249856Spfg * Copyright (c) 2011 by Delphix. All rights reserved. 28249856Spfg */ 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 40249856Spfgdt_strdata_add(dtrace_hdl_t *dtp, dtrace_recdesc_t *rec, void ***data, int *max) 41249856Spfg{ 42249856Spfg int maxformat; 43249856Spfg dtrace_fmtdesc_t fmt; 44249856Spfg void *result; 45249856Spfg 46249856Spfg if (rec->dtrd_format == 0) 47249856Spfg return (0); 48249856Spfg 49249856Spfg if (rec->dtrd_format <= *max && 50249856Spfg (*data)[rec->dtrd_format - 1] != NULL) { 51249856Spfg return (0); 52249856Spfg } 53249856Spfg 54249856Spfg bzero(&fmt, sizeof (fmt)); 55249856Spfg fmt.dtfd_format = rec->dtrd_format; 56249856Spfg fmt.dtfd_string = NULL; 57249856Spfg fmt.dtfd_length = 0; 58249856Spfg 59249856Spfg if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) 60249856Spfg return (dt_set_errno(dtp, errno)); 61249856Spfg 62249856Spfg if ((fmt.dtfd_string = dt_alloc(dtp, fmt.dtfd_length)) == NULL) 63249856Spfg return (dt_set_errno(dtp, EDT_NOMEM)); 64249856Spfg 65249856Spfg if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) { 66249856Spfg free(fmt.dtfd_string); 67249856Spfg return (dt_set_errno(dtp, errno)); 68249856Spfg } 69249856Spfg 70249856Spfg while (rec->dtrd_format > (maxformat = *max)) { 71249856Spfg int new_max = maxformat ? (maxformat << 1) : 1; 72249856Spfg size_t nsize = new_max * sizeof (void *); 73249856Spfg size_t osize = maxformat * sizeof (void *); 74249856Spfg void **new_data = dt_zalloc(dtp, nsize); 75249856Spfg 76249856Spfg if (new_data == NULL) { 77249856Spfg dt_free(dtp, fmt.dtfd_string); 78249856Spfg return (dt_set_errno(dtp, EDT_NOMEM)); 79249856Spfg } 80249856Spfg 81249856Spfg bcopy(*data, new_data, osize); 82249856Spfg free(*data); 83249856Spfg 84249856Spfg *data = new_data; 85249856Spfg *max = new_max; 86249856Spfg } 87249856Spfg 88249856Spfg switch (rec->dtrd_action) { 89249856Spfg case DTRACEACT_DIFEXPR: 90249856Spfg result = fmt.dtfd_string; 91249856Spfg break; 92249856Spfg case DTRACEACT_PRINTA: 93249856Spfg result = dtrace_printa_create(dtp, fmt.dtfd_string); 94249856Spfg dt_free(dtp, fmt.dtfd_string); 95249856Spfg break; 96249856Spfg default: 97249856Spfg result = dtrace_printf_create(dtp, fmt.dtfd_string); 98249856Spfg dt_free(dtp, fmt.dtfd_string); 99249856Spfg break; 100249856Spfg } 101249856Spfg 102249856Spfg if (result == NULL) 103249856Spfg return (-1); 104249856Spfg 105249856Spfg (*data)[rec->dtrd_format - 1] = result; 106249856Spfg 107249856Spfg return (0); 108249856Spfg} 109249856Spfg 110249856Spfgstatic int 111178479Sjbdt_epid_add(dtrace_hdl_t *dtp, dtrace_epid_t id) 112178479Sjb{ 113178479Sjb dtrace_id_t max; 114249856Spfg int rval, i; 115178479Sjb dtrace_eprobedesc_t *enabled, *nenabled; 116178479Sjb dtrace_probedesc_t *probe; 117178479Sjb 118178479Sjb while (id >= (max = dtp->dt_maxprobe) || dtp->dt_pdesc == NULL) { 119178479Sjb dtrace_id_t new_max = max ? (max << 1) : 1; 120178479Sjb size_t nsize = new_max * sizeof (void *); 121178479Sjb dtrace_probedesc_t **new_pdesc; 122178479Sjb dtrace_eprobedesc_t **new_edesc; 123178479Sjb 124178479Sjb if ((new_pdesc = malloc(nsize)) == NULL || 125178479Sjb (new_edesc = malloc(nsize)) == NULL) { 126178479Sjb free(new_pdesc); 127178479Sjb return (dt_set_errno(dtp, EDT_NOMEM)); 128178479Sjb } 129178479Sjb 130178479Sjb bzero(new_pdesc, nsize); 131178479Sjb bzero(new_edesc, nsize); 132178479Sjb 133178479Sjb if (dtp->dt_pdesc != NULL) { 134178479Sjb size_t osize = max * sizeof (void *); 135178479Sjb 136178479Sjb bcopy(dtp->dt_pdesc, new_pdesc, osize); 137178479Sjb free(dtp->dt_pdesc); 138178479Sjb 139178479Sjb bcopy(dtp->dt_edesc, new_edesc, osize); 140178479Sjb free(dtp->dt_edesc); 141178479Sjb } 142178479Sjb 143178479Sjb dtp->dt_pdesc = new_pdesc; 144178479Sjb dtp->dt_edesc = new_edesc; 145178479Sjb dtp->dt_maxprobe = new_max; 146178479Sjb } 147178479Sjb 148178479Sjb if (dtp->dt_pdesc[id] != NULL) 149178479Sjb return (0); 150178479Sjb 151178479Sjb if ((enabled = malloc(sizeof (dtrace_eprobedesc_t))) == NULL) 152178479Sjb return (dt_set_errno(dtp, EDT_NOMEM)); 153178479Sjb 154178479Sjb bzero(enabled, sizeof (dtrace_eprobedesc_t)); 155178479Sjb enabled->dtepd_epid = id; 156178479Sjb enabled->dtepd_nrecs = 1; 157178479Sjb 158178562Sjb#if defined(sun) 159178479Sjb if (dt_ioctl(dtp, DTRACEIOC_EPROBE, enabled) == -1) { 160178562Sjb#else 161178562Sjb if (dt_ioctl(dtp, DTRACEIOC_EPROBE, &enabled) == -1) { 162178562Sjb#endif 163178479Sjb rval = dt_set_errno(dtp, errno); 164178479Sjb free(enabled); 165178479Sjb return (rval); 166178479Sjb } 167178479Sjb 168178479Sjb if (DTRACE_SIZEOF_EPROBEDESC(enabled) != sizeof (*enabled)) { 169178479Sjb /* 170178479Sjb * There must be more than one action. Allocate the 171178479Sjb * appropriate amount of space and try again. 172178479Sjb */ 173178479Sjb if ((nenabled = 174178479Sjb malloc(DTRACE_SIZEOF_EPROBEDESC(enabled))) != NULL) 175178479Sjb bcopy(enabled, nenabled, sizeof (*enabled)); 176178479Sjb 177178479Sjb free(enabled); 178178479Sjb 179178479Sjb if ((enabled = nenabled) == NULL) 180178479Sjb return (dt_set_errno(dtp, EDT_NOMEM)); 181178479Sjb 182178562Sjb#if defined(sun) 183178479Sjb rval = dt_ioctl(dtp, DTRACEIOC_EPROBE, enabled); 184178562Sjb#else 185178562Sjb rval = dt_ioctl(dtp, DTRACEIOC_EPROBE, &enabled); 186178562Sjb#endif 187178479Sjb 188178479Sjb if (rval == -1) { 189178479Sjb rval = dt_set_errno(dtp, errno); 190178479Sjb free(enabled); 191178479Sjb return (rval); 192178479Sjb } 193178479Sjb } 194178479Sjb 195178479Sjb if ((probe = malloc(sizeof (dtrace_probedesc_t))) == NULL) { 196178479Sjb free(enabled); 197178479Sjb return (dt_set_errno(dtp, EDT_NOMEM)); 198178479Sjb } 199178479Sjb 200178479Sjb probe->dtpd_id = enabled->dtepd_probeid; 201178479Sjb 202178479Sjb if (dt_ioctl(dtp, DTRACEIOC_PROBES, probe) == -1) { 203178479Sjb rval = dt_set_errno(dtp, errno); 204178479Sjb goto err; 205178479Sjb } 206178479Sjb 207178479Sjb for (i = 0; i < enabled->dtepd_nrecs; i++) { 208178479Sjb dtrace_recdesc_t *rec = &enabled->dtepd_rec[i]; 209178479Sjb 210249856Spfg if (DTRACEACT_ISPRINTFLIKE(rec->dtrd_action)) { 211249856Spfg if (dt_strdata_add(dtp, rec, &dtp->dt_formats, 212249856Spfg &dtp->dt_maxformat) != 0) { 213249856Spfg rval = -1; 214178479Sjb goto err; 215178479Sjb } 216249856Spfg } else if (rec->dtrd_action == DTRACEACT_DIFEXPR) { 217249856Spfg if (dt_strdata_add(dtp, rec, 218249856Spfg (void ***)&dtp->dt_strdata, 219249856Spfg &dtp->dt_maxstrdata) != 0) { 220249856Spfg rval = -1; 221249856Spfg goto err; 222249856Spfg } 223178479Sjb } 224178479Sjb 225178479Sjb } 226178479Sjb 227178479Sjb dtp->dt_pdesc[id] = probe; 228178479Sjb dtp->dt_edesc[id] = enabled; 229178479Sjb 230178479Sjb return (0); 231178479Sjb 232178479Sjberr: 233178479Sjb /* 234178479Sjb * If we failed, free our allocated probes. Note that if we failed 235178479Sjb * while allocating formats, we aren't going to free formats that 236178479Sjb * we have already allocated. This is okay; these formats are 237178479Sjb * hanging off of dt_formats and will therefore not be leaked. 238178479Sjb */ 239178479Sjb free(enabled); 240178479Sjb free(probe); 241178479Sjb return (rval); 242178479Sjb} 243178479Sjb 244178479Sjbint 245178479Sjbdt_epid_lookup(dtrace_hdl_t *dtp, dtrace_epid_t epid, 246178479Sjb dtrace_eprobedesc_t **epdp, dtrace_probedesc_t **pdp) 247178479Sjb{ 248178479Sjb int rval; 249178479Sjb 250178479Sjb if (epid >= dtp->dt_maxprobe || dtp->dt_pdesc[epid] == NULL) { 251178479Sjb if ((rval = dt_epid_add(dtp, epid)) != 0) 252178479Sjb return (rval); 253178479Sjb } 254178479Sjb 255178479Sjb assert(epid < dtp->dt_maxprobe); 256178479Sjb assert(dtp->dt_edesc[epid] != NULL); 257178479Sjb assert(dtp->dt_pdesc[epid] != NULL); 258178479Sjb *epdp = dtp->dt_edesc[epid]; 259178479Sjb *pdp = dtp->dt_pdesc[epid]; 260178479Sjb 261178479Sjb return (0); 262178479Sjb} 263178479Sjb 264178479Sjbvoid 265178479Sjbdt_epid_destroy(dtrace_hdl_t *dtp) 266178479Sjb{ 267178479Sjb size_t i; 268178479Sjb 269178479Sjb assert((dtp->dt_pdesc != NULL && dtp->dt_edesc != NULL && 270178479Sjb dtp->dt_maxprobe > 0) || (dtp->dt_pdesc == NULL && 271178479Sjb dtp->dt_edesc == NULL && dtp->dt_maxprobe == 0)); 272178479Sjb 273178479Sjb if (dtp->dt_pdesc == NULL) 274178479Sjb return; 275178479Sjb 276178479Sjb for (i = 0; i < dtp->dt_maxprobe; i++) { 277178479Sjb if (dtp->dt_edesc[i] == NULL) { 278178479Sjb assert(dtp->dt_pdesc[i] == NULL); 279178479Sjb continue; 280178479Sjb } 281178479Sjb 282178479Sjb assert(dtp->dt_pdesc[i] != NULL); 283178479Sjb free(dtp->dt_edesc[i]); 284178479Sjb free(dtp->dt_pdesc[i]); 285178479Sjb } 286178479Sjb 287178479Sjb free(dtp->dt_pdesc); 288178479Sjb dtp->dt_pdesc = NULL; 289178479Sjb 290178479Sjb free(dtp->dt_edesc); 291178479Sjb dtp->dt_edesc = NULL; 292178479Sjb dtp->dt_maxprobe = 0; 293178479Sjb} 294178479Sjb 295178479Sjbvoid * 296178479Sjbdt_format_lookup(dtrace_hdl_t *dtp, int format) 297178479Sjb{ 298178479Sjb if (format == 0 || format > dtp->dt_maxformat) 299178479Sjb return (NULL); 300178479Sjb 301178479Sjb if (dtp->dt_formats == NULL) 302178479Sjb return (NULL); 303178479Sjb 304178479Sjb return (dtp->dt_formats[format - 1]); 305178479Sjb} 306178479Sjb 307178479Sjbvoid 308178479Sjbdt_format_destroy(dtrace_hdl_t *dtp) 309178479Sjb{ 310178479Sjb int i; 311178479Sjb 312178479Sjb for (i = 0; i < dtp->dt_maxformat; i++) { 313178479Sjb if (dtp->dt_formats[i] != NULL) 314178479Sjb dt_printf_destroy(dtp->dt_formats[i]); 315178479Sjb } 316178479Sjb 317178479Sjb free(dtp->dt_formats); 318178479Sjb dtp->dt_formats = NULL; 319178479Sjb} 320178479Sjb 321178479Sjbstatic int 322178479Sjbdt_aggid_add(dtrace_hdl_t *dtp, dtrace_aggid_t id) 323178479Sjb{ 324178479Sjb dtrace_id_t max; 325178479Sjb dtrace_epid_t epid; 326178479Sjb int rval; 327178479Sjb 328178479Sjb while (id >= (max = dtp->dt_maxagg) || dtp->dt_aggdesc == NULL) { 329178479Sjb dtrace_id_t new_max = max ? (max << 1) : 1; 330178479Sjb size_t nsize = new_max * sizeof (void *); 331178479Sjb dtrace_aggdesc_t **new_aggdesc; 332178479Sjb 333178479Sjb if ((new_aggdesc = malloc(nsize)) == NULL) 334178479Sjb return (dt_set_errno(dtp, EDT_NOMEM)); 335178479Sjb 336178479Sjb bzero(new_aggdesc, nsize); 337178479Sjb 338178479Sjb if (dtp->dt_aggdesc != NULL) { 339178479Sjb bcopy(dtp->dt_aggdesc, new_aggdesc, 340178479Sjb max * sizeof (void *)); 341178479Sjb free(dtp->dt_aggdesc); 342178479Sjb } 343178479Sjb 344178479Sjb dtp->dt_aggdesc = new_aggdesc; 345178479Sjb dtp->dt_maxagg = new_max; 346178479Sjb } 347178479Sjb 348178479Sjb if (dtp->dt_aggdesc[id] == NULL) { 349178479Sjb dtrace_aggdesc_t *agg, *nagg; 350178479Sjb 351178479Sjb if ((agg = malloc(sizeof (dtrace_aggdesc_t))) == NULL) 352178479Sjb return (dt_set_errno(dtp, EDT_NOMEM)); 353178479Sjb 354178479Sjb bzero(agg, sizeof (dtrace_aggdesc_t)); 355178479Sjb agg->dtagd_id = id; 356178479Sjb agg->dtagd_nrecs = 1; 357178479Sjb 358178562Sjb#if defined(sun) 359178479Sjb if (dt_ioctl(dtp, DTRACEIOC_AGGDESC, agg) == -1) { 360178562Sjb#else 361178562Sjb if (dt_ioctl(dtp, DTRACEIOC_AGGDESC, &agg) == -1) { 362178562Sjb#endif 363178479Sjb rval = dt_set_errno(dtp, errno); 364178479Sjb free(agg); 365178479Sjb return (rval); 366178479Sjb } 367178479Sjb 368178479Sjb if (DTRACE_SIZEOF_AGGDESC(agg) != sizeof (*agg)) { 369178479Sjb /* 370178479Sjb * There must be more than one action. Allocate the 371178479Sjb * appropriate amount of space and try again. 372178479Sjb */ 373178479Sjb if ((nagg = malloc(DTRACE_SIZEOF_AGGDESC(agg))) != NULL) 374178479Sjb bcopy(agg, nagg, sizeof (*agg)); 375178479Sjb 376178479Sjb free(agg); 377178479Sjb 378178479Sjb if ((agg = nagg) == NULL) 379178479Sjb return (dt_set_errno(dtp, EDT_NOMEM)); 380178479Sjb 381178562Sjb#if defined(sun) 382178479Sjb rval = dt_ioctl(dtp, DTRACEIOC_AGGDESC, agg); 383178562Sjb#else 384178562Sjb rval = dt_ioctl(dtp, DTRACEIOC_AGGDESC, &agg); 385178562Sjb#endif 386178479Sjb 387178479Sjb if (rval == -1) { 388178479Sjb rval = dt_set_errno(dtp, errno); 389178479Sjb free(agg); 390178479Sjb return (rval); 391178479Sjb } 392178479Sjb } 393178479Sjb 394178479Sjb /* 395178479Sjb * If we have a uarg, it's a pointer to the compiler-generated 396178479Sjb * statement; we'll use this value to get the name and 397178479Sjb * compiler-generated variable ID for the aggregation. If 398178479Sjb * we're grabbing an anonymous enabling, this pointer value 399178479Sjb * is obviously meaningless -- and in this case, we can't 400178479Sjb * provide the compiler-generated aggregation information. 401178479Sjb */ 402178479Sjb if (dtp->dt_options[DTRACEOPT_GRABANON] == DTRACEOPT_UNSET && 403178562Sjb agg->dtagd_rec[0].dtrd_uarg != 0) { 404178479Sjb dtrace_stmtdesc_t *sdp; 405178479Sjb dt_ident_t *aid; 406178479Sjb 407178479Sjb sdp = (dtrace_stmtdesc_t *)(uintptr_t) 408178479Sjb agg->dtagd_rec[0].dtrd_uarg; 409178479Sjb aid = sdp->dtsd_aggdata; 410178479Sjb agg->dtagd_name = aid->di_name; 411178479Sjb agg->dtagd_varid = aid->di_id; 412178479Sjb } else { 413178479Sjb agg->dtagd_varid = DTRACE_AGGVARIDNONE; 414178479Sjb } 415178479Sjb 416178479Sjb if ((epid = agg->dtagd_epid) >= dtp->dt_maxprobe || 417178479Sjb dtp->dt_pdesc[epid] == NULL) { 418178479Sjb if ((rval = dt_epid_add(dtp, epid)) != 0) { 419178479Sjb free(agg); 420178479Sjb return (rval); 421178479Sjb } 422178479Sjb } 423178479Sjb 424178479Sjb dtp->dt_aggdesc[id] = agg; 425178479Sjb } 426178479Sjb 427178479Sjb return (0); 428178479Sjb} 429178479Sjb 430178479Sjbint 431178479Sjbdt_aggid_lookup(dtrace_hdl_t *dtp, dtrace_aggid_t aggid, 432178479Sjb dtrace_aggdesc_t **adp) 433178479Sjb{ 434178479Sjb int rval; 435178479Sjb 436178479Sjb if (aggid >= dtp->dt_maxagg || dtp->dt_aggdesc[aggid] == NULL) { 437178479Sjb if ((rval = dt_aggid_add(dtp, aggid)) != 0) 438178479Sjb return (rval); 439178479Sjb } 440178479Sjb 441178479Sjb assert(aggid < dtp->dt_maxagg); 442178479Sjb assert(dtp->dt_aggdesc[aggid] != NULL); 443178479Sjb *adp = dtp->dt_aggdesc[aggid]; 444178479Sjb 445178479Sjb return (0); 446178479Sjb} 447178479Sjb 448178479Sjbvoid 449178479Sjbdt_aggid_destroy(dtrace_hdl_t *dtp) 450178479Sjb{ 451178479Sjb size_t i; 452178479Sjb 453178479Sjb assert((dtp->dt_aggdesc != NULL && dtp->dt_maxagg != 0) || 454178479Sjb (dtp->dt_aggdesc == NULL && dtp->dt_maxagg == 0)); 455178479Sjb 456178479Sjb if (dtp->dt_aggdesc == NULL) 457178479Sjb return; 458178479Sjb 459178479Sjb for (i = 0; i < dtp->dt_maxagg; i++) { 460178479Sjb if (dtp->dt_aggdesc[i] != NULL) 461178479Sjb free(dtp->dt_aggdesc[i]); 462178479Sjb } 463178479Sjb 464178479Sjb free(dtp->dt_aggdesc); 465178479Sjb dtp->dt_aggdesc = NULL; 466178479Sjb dtp->dt_maxagg = 0; 467178479Sjb} 468249856Spfg 469249856Spfgconst char * 470249856Spfgdt_strdata_lookup(dtrace_hdl_t *dtp, int idx) 471249856Spfg{ 472249856Spfg if (idx == 0 || idx > dtp->dt_maxstrdata) 473249856Spfg return (NULL); 474249856Spfg 475249856Spfg if (dtp->dt_strdata == NULL) 476249856Spfg return (NULL); 477249856Spfg 478249856Spfg return (dtp->dt_strdata[idx - 1]); 479249856Spfg} 480249856Spfg 481249856Spfgvoid 482249856Spfgdt_strdata_destroy(dtrace_hdl_t *dtp) 483249856Spfg{ 484249856Spfg int i; 485249856Spfg 486249856Spfg for (i = 0; i < dtp->dt_maxstrdata; i++) { 487249856Spfg free(dtp->dt_strdata[i]); 488249856Spfg } 489249856Spfg 490249856Spfg free(dtp->dt_strdata); 491249856Spfg dtp->dt_strdata = NULL; 492249856Spfg} 493