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{ 42248708Spfg int maxformat; 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) { 66248708Spfg free(fmt.dtfd_string); 67248708Spfg return (dt_set_errno(dtp, errno)); 68248708Spfg } 69248708Spfg 70248708Spfg while (rec->dtrd_format > (maxformat = *max)) { 71248708Spfg int new_max = maxformat ? (maxformat << 1) : 1; 72248708Spfg size_t nsize = new_max * sizeof (void *); 73248708Spfg size_t osize = maxformat * sizeof (void *); 74248708Spfg void **new_data = dt_zalloc(dtp, nsize); 75248708Spfg 76248708Spfg if (new_data == NULL) { 77248708Spfg dt_free(dtp, fmt.dtfd_string); 78248708Spfg return (dt_set_errno(dtp, EDT_NOMEM)); 79248708Spfg } 80248708Spfg 81248708Spfg bcopy(*data, new_data, osize); 82248708Spfg free(*data); 83248708Spfg 84248708Spfg *data = new_data; 85248708Spfg *max = new_max; 86248708Spfg } 87248708Spfg 88248708Spfg switch (rec->dtrd_action) { 89248708Spfg case DTRACEACT_DIFEXPR: 90248708Spfg result = fmt.dtfd_string; 91248708Spfg break; 92248708Spfg case DTRACEACT_PRINTA: 93248708Spfg result = dtrace_printa_create(dtp, fmt.dtfd_string); 94248708Spfg dt_free(dtp, fmt.dtfd_string); 95248708Spfg break; 96248708Spfg default: 97248708Spfg result = dtrace_printf_create(dtp, fmt.dtfd_string); 98248708Spfg dt_free(dtp, fmt.dtfd_string); 99248708Spfg break; 100248708Spfg } 101248708Spfg 102248708Spfg if (result == NULL) 103248708Spfg return (-1); 104248708Spfg 105248708Spfg (*data)[rec->dtrd_format - 1] = result; 106248708Spfg 107248708Spfg return (0); 108248708Spfg} 109248708Spfg 110248708Spfgstatic int 111178479Sjbdt_epid_add(dtrace_hdl_t *dtp, dtrace_epid_t id) 112178479Sjb{ 113178479Sjb dtrace_id_t max; 114248708Spfg 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 210248708Spfg if (DTRACEACT_ISPRINTFLIKE(rec->dtrd_action)) { 211248708Spfg if (dt_strdata_add(dtp, rec, &dtp->dt_formats, 212248708Spfg &dtp->dt_maxformat) != 0) { 213248708Spfg rval = -1; 214178479Sjb goto err; 215178479Sjb } 216248708Spfg } else if (rec->dtrd_action == DTRACEACT_DIFEXPR) { 217248708Spfg if (dt_strdata_add(dtp, rec, 218248708Spfg (void ***)&dtp->dt_strdata, 219248708Spfg &dtp->dt_maxstrdata) != 0) { 220248708Spfg rval = -1; 221248708Spfg goto err; 222248708Spfg } 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} 468248708Spfg 469248708Spfgconst char * 470248708Spfgdt_strdata_lookup(dtrace_hdl_t *dtp, int idx) 471248708Spfg{ 472248708Spfg if (idx == 0 || idx > dtp->dt_maxstrdata) 473248708Spfg return (NULL); 474248708Spfg 475248708Spfg if (dtp->dt_strdata == NULL) 476248708Spfg return (NULL); 477248708Spfg 478248708Spfg return (dtp->dt_strdata[idx - 1]); 479248708Spfg} 480248708Spfg 481248708Spfgvoid 482248708Spfgdt_strdata_destroy(dtrace_hdl_t *dtp) 483248708Spfg{ 484248708Spfg int i; 485248708Spfg 486248708Spfg for (i = 0; i < dtp->dt_maxstrdata; i++) { 487248708Spfg free(dtp->dt_strdata[i]); 488248708Spfg } 489248708Spfg 490248708Spfg free(dtp->dt_strdata); 491248708Spfg dtp->dt_strdata = NULL; 492248708Spfg} 493