Path: blob/main/cddl/contrib/opensolaris/lib/libdtrace/common/dt_map.c
39562 views
/*1* CDDL HEADER START2*3* The contents of this file are subject to the terms of the4* Common Development and Distribution License (the "License").5* You may not use this file except in compliance with the License.6*7* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE8* or http://www.opensolaris.org/os/licensing.9* See the License for the specific language governing permissions10* and limitations under the License.11*12* When distributing Covered Code, include this CDDL HEADER in each13* file and include the License file at usr/src/OPENSOLARIS.LICENSE.14* If applicable, add the following below this CDDL HEADER, with the15* fields enclosed by brackets "[]" replaced with your own identifying16* information: Portions Copyright [yyyy] [name of copyright owner]17*18* CDDL HEADER END19*/20/*21* Copyright 2006 Sun Microsystems, Inc. All rights reserved.22* Use is subject to license terms.23*/2425/*26* Copyright (c) 2011 by Delphix. All rights reserved.27*/2829#include <stdlib.h>30#include <strings.h>31#include <errno.h>32#include <unistd.h>33#include <assert.h>3435#include <dt_impl.h>36#include <dt_printf.h>3738static int39dt_strdata_add(dtrace_hdl_t *dtp, dtrace_recdesc_t *rec, void ***data, int *max)40{41int maxformat, rval;42dtrace_fmtdesc_t fmt;43void *result;4445if (rec->dtrd_format == 0)46return (0);4748if (rec->dtrd_format <= *max &&49(*data)[rec->dtrd_format - 1] != NULL) {50return (0);51}5253bzero(&fmt, sizeof (fmt));54fmt.dtfd_format = rec->dtrd_format;55fmt.dtfd_string = NULL;56fmt.dtfd_length = 0;5758if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1)59return (dt_set_errno(dtp, errno));6061if ((fmt.dtfd_string = dt_alloc(dtp, fmt.dtfd_length)) == NULL)62return (dt_set_errno(dtp, EDT_NOMEM));6364if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) {65rval = dt_set_errno(dtp, errno);66free(fmt.dtfd_string);67return (rval);68}6970while (rec->dtrd_format > (maxformat = *max)) {71int new_max = maxformat ? (maxformat << 1) : 1;72size_t nsize = new_max * sizeof (void *);73size_t osize = maxformat * sizeof (void *);74void **new_data = dt_zalloc(dtp, nsize);7576if (new_data == NULL) {77dt_free(dtp, fmt.dtfd_string);78return (dt_set_errno(dtp, EDT_NOMEM));79}8081bcopy(*data, new_data, osize);82free(*data);8384*data = new_data;85*max = new_max;86}8788switch (rec->dtrd_action) {89case DTRACEACT_DIFEXPR:90result = fmt.dtfd_string;91break;92case DTRACEACT_PRINTA:93result = dtrace_printa_create(dtp, fmt.dtfd_string);94dt_free(dtp, fmt.dtfd_string);95break;96default:97result = dtrace_printf_create(dtp, fmt.dtfd_string);98dt_free(dtp, fmt.dtfd_string);99break;100}101102if (result == NULL)103return (-1);104105(*data)[rec->dtrd_format - 1] = result;106107return (0);108}109110static int111dt_epid_add(dtrace_hdl_t *dtp, dtrace_epid_t id)112{113dtrace_id_t max;114int rval, i;115dtrace_eprobedesc_t *enabled, *nenabled;116dtrace_probedesc_t *probe;117118while (id >= (max = dtp->dt_maxprobe) || dtp->dt_pdesc == NULL) {119dtrace_id_t new_max = max ? (max << 1) : 1;120size_t nsize = new_max * sizeof (void *);121dtrace_probedesc_t **new_pdesc;122dtrace_eprobedesc_t **new_edesc;123124if ((new_pdesc = malloc(nsize)) == NULL ||125(new_edesc = malloc(nsize)) == NULL) {126free(new_pdesc);127return (dt_set_errno(dtp, EDT_NOMEM));128}129130bzero(new_pdesc, nsize);131bzero(new_edesc, nsize);132133if (dtp->dt_pdesc != NULL) {134size_t osize = max * sizeof (void *);135136bcopy(dtp->dt_pdesc, new_pdesc, osize);137free(dtp->dt_pdesc);138139bcopy(dtp->dt_edesc, new_edesc, osize);140free(dtp->dt_edesc);141}142143dtp->dt_pdesc = new_pdesc;144dtp->dt_edesc = new_edesc;145dtp->dt_maxprobe = new_max;146}147148if (dtp->dt_pdesc[id] != NULL)149return (0);150151if ((enabled = malloc(sizeof (dtrace_eprobedesc_t))) == NULL)152return (dt_set_errno(dtp, EDT_NOMEM));153154bzero(enabled, sizeof (dtrace_eprobedesc_t));155enabled->dtepd_epid = id;156enabled->dtepd_nrecs = 1;157158#ifdef illumos159if (dt_ioctl(dtp, DTRACEIOC_EPROBE, enabled) == -1) {160#else161if (dt_ioctl(dtp, DTRACEIOC_EPROBE, &enabled) == -1) {162#endif163rval = dt_set_errno(dtp, errno);164free(enabled);165return (rval);166}167168if (DTRACE_SIZEOF_EPROBEDESC(enabled) != sizeof (*enabled)) {169/*170* There must be more than one action. Allocate the171* appropriate amount of space and try again.172*/173if ((nenabled =174malloc(DTRACE_SIZEOF_EPROBEDESC(enabled))) != NULL)175bcopy(enabled, nenabled, sizeof (*enabled));176177free(enabled);178179if ((enabled = nenabled) == NULL)180return (dt_set_errno(dtp, EDT_NOMEM));181182#ifdef illumos183rval = dt_ioctl(dtp, DTRACEIOC_EPROBE, enabled);184#else185rval = dt_ioctl(dtp, DTRACEIOC_EPROBE, &enabled);186#endif187188if (rval == -1) {189rval = dt_set_errno(dtp, errno);190free(enabled);191return (rval);192}193}194195if ((probe = malloc(sizeof (dtrace_probedesc_t))) == NULL) {196free(enabled);197return (dt_set_errno(dtp, EDT_NOMEM));198}199200probe->dtpd_id = enabled->dtepd_probeid;201202if (dt_ioctl(dtp, DTRACEIOC_PROBES, probe) == -1) {203rval = dt_set_errno(dtp, errno);204goto err;205}206207for (i = 0; i < enabled->dtepd_nrecs; i++) {208dtrace_recdesc_t *rec = &enabled->dtepd_rec[i];209210if (DTRACEACT_ISPRINTFLIKE(rec->dtrd_action)) {211if (dt_strdata_add(dtp, rec, &dtp->dt_formats,212&dtp->dt_maxformat) != 0) {213rval = -1;214goto err;215}216} else if (rec->dtrd_action == DTRACEACT_DIFEXPR) {217if (dt_strdata_add(dtp, rec,218(void ***)&dtp->dt_strdata,219&dtp->dt_maxstrdata) != 0) {220rval = -1;221goto err;222}223}224225}226227dtp->dt_pdesc[id] = probe;228dtp->dt_edesc[id] = enabled;229230return (0);231232err:233/*234* If we failed, free our allocated probes. Note that if we failed235* while allocating formats, we aren't going to free formats that236* we have already allocated. This is okay; these formats are237* hanging off of dt_formats and will therefore not be leaked.238*/239free(enabled);240free(probe);241return (rval);242}243244int245dt_epid_lookup(dtrace_hdl_t *dtp, dtrace_epid_t epid,246dtrace_eprobedesc_t **epdp, dtrace_probedesc_t **pdp)247{248int rval;249250if (epid >= dtp->dt_maxprobe || dtp->dt_pdesc[epid] == NULL) {251if ((rval = dt_epid_add(dtp, epid)) != 0)252return (rval);253}254255assert(epid < dtp->dt_maxprobe);256assert(dtp->dt_edesc[epid] != NULL);257assert(dtp->dt_pdesc[epid] != NULL);258*epdp = dtp->dt_edesc[epid];259*pdp = dtp->dt_pdesc[epid];260261return (0);262}263264void265dt_epid_destroy(dtrace_hdl_t *dtp)266{267size_t i;268269assert((dtp->dt_pdesc != NULL && dtp->dt_edesc != NULL &&270dtp->dt_maxprobe > 0) || (dtp->dt_pdesc == NULL &&271dtp->dt_edesc == NULL && dtp->dt_maxprobe == 0));272273if (dtp->dt_pdesc == NULL)274return;275276for (i = 0; i < dtp->dt_maxprobe; i++) {277if (dtp->dt_edesc[i] == NULL) {278assert(dtp->dt_pdesc[i] == NULL);279continue;280}281282assert(dtp->dt_pdesc[i] != NULL);283free(dtp->dt_edesc[i]);284free(dtp->dt_pdesc[i]);285}286287free(dtp->dt_pdesc);288dtp->dt_pdesc = NULL;289290free(dtp->dt_edesc);291dtp->dt_edesc = NULL;292dtp->dt_maxprobe = 0;293}294295void *296dt_format_lookup(dtrace_hdl_t *dtp, int format)297{298if (format == 0 || format > dtp->dt_maxformat)299return (NULL);300301if (dtp->dt_formats == NULL)302return (NULL);303304return (dtp->dt_formats[format - 1]);305}306307void308dt_format_destroy(dtrace_hdl_t *dtp)309{310int i;311312for (i = 0; i < dtp->dt_maxformat; i++) {313if (dtp->dt_formats[i] != NULL)314dt_printf_destroy(dtp->dt_formats[i]);315}316317free(dtp->dt_formats);318dtp->dt_formats = NULL;319}320321static int322dt_aggid_add(dtrace_hdl_t *dtp, dtrace_aggid_t id)323{324dtrace_id_t max;325dtrace_epid_t epid;326int rval;327328while (id >= (max = dtp->dt_maxagg) || dtp->dt_aggdesc == NULL) {329dtrace_id_t new_max = max ? (max << 1) : 1;330size_t nsize = new_max * sizeof (void *);331dtrace_aggdesc_t **new_aggdesc;332333if ((new_aggdesc = malloc(nsize)) == NULL)334return (dt_set_errno(dtp, EDT_NOMEM));335336bzero(new_aggdesc, nsize);337338if (dtp->dt_aggdesc != NULL) {339bcopy(dtp->dt_aggdesc, new_aggdesc,340max * sizeof (void *));341free(dtp->dt_aggdesc);342}343344dtp->dt_aggdesc = new_aggdesc;345dtp->dt_maxagg = new_max;346}347348if (dtp->dt_aggdesc[id] == NULL) {349dtrace_aggdesc_t *agg, *nagg;350351if ((agg = malloc(sizeof (dtrace_aggdesc_t))) == NULL)352return (dt_set_errno(dtp, EDT_NOMEM));353354bzero(agg, sizeof (dtrace_aggdesc_t));355agg->dtagd_id = id;356agg->dtagd_nrecs = 1;357358#ifdef illumos359if (dt_ioctl(dtp, DTRACEIOC_AGGDESC, agg) == -1) {360#else361if (dt_ioctl(dtp, DTRACEIOC_AGGDESC, &agg) == -1) {362#endif363rval = dt_set_errno(dtp, errno);364free(agg);365return (rval);366}367368if (DTRACE_SIZEOF_AGGDESC(agg) != sizeof (*agg)) {369/*370* There must be more than one action. Allocate the371* appropriate amount of space and try again.372*/373if ((nagg = malloc(DTRACE_SIZEOF_AGGDESC(agg))) != NULL)374bcopy(agg, nagg, sizeof (*agg));375376free(agg);377378if ((agg = nagg) == NULL)379return (dt_set_errno(dtp, EDT_NOMEM));380381#ifdef illumos382rval = dt_ioctl(dtp, DTRACEIOC_AGGDESC, agg);383#else384rval = dt_ioctl(dtp, DTRACEIOC_AGGDESC, &agg);385#endif386387if (rval == -1) {388rval = dt_set_errno(dtp, errno);389free(agg);390return (rval);391}392}393394/*395* If we have a uarg, it's a pointer to the compiler-generated396* statement; we'll use this value to get the name and397* compiler-generated variable ID for the aggregation. If398* we're grabbing an anonymous enabling, this pointer value399* is obviously meaningless -- and in this case, we can't400* provide the compiler-generated aggregation information.401*/402if (dtp->dt_options[DTRACEOPT_GRABANON] == DTRACEOPT_UNSET &&403agg->dtagd_rec[0].dtrd_uarg != 0) {404dtrace_stmtdesc_t *sdp;405dt_ident_t *aid;406407sdp = (dtrace_stmtdesc_t *)(uintptr_t)408agg->dtagd_rec[0].dtrd_uarg;409aid = sdp->dtsd_aggdata;410agg->dtagd_name = aid->di_name;411agg->dtagd_varid = aid->di_id;412} else {413agg->dtagd_varid = DTRACE_AGGVARIDNONE;414}415416if ((epid = agg->dtagd_epid) >= dtp->dt_maxprobe ||417dtp->dt_pdesc[epid] == NULL) {418if ((rval = dt_epid_add(dtp, epid)) != 0) {419free(agg);420return (rval);421}422}423424dtp->dt_aggdesc[id] = agg;425}426427return (0);428}429430int431dt_aggid_lookup(dtrace_hdl_t *dtp, dtrace_aggid_t aggid,432dtrace_aggdesc_t **adp)433{434int rval;435436if (aggid >= dtp->dt_maxagg || dtp->dt_aggdesc[aggid] == NULL) {437if ((rval = dt_aggid_add(dtp, aggid)) != 0)438return (rval);439}440441assert(aggid < dtp->dt_maxagg);442assert(dtp->dt_aggdesc[aggid] != NULL);443*adp = dtp->dt_aggdesc[aggid];444445return (0);446}447448void449dt_aggid_destroy(dtrace_hdl_t *dtp)450{451size_t i;452453assert((dtp->dt_aggdesc != NULL && dtp->dt_maxagg != 0) ||454(dtp->dt_aggdesc == NULL && dtp->dt_maxagg == 0));455456if (dtp->dt_aggdesc == NULL)457return;458459for (i = 0; i < dtp->dt_maxagg; i++) {460if (dtp->dt_aggdesc[i] != NULL)461free(dtp->dt_aggdesc[i]);462}463464free(dtp->dt_aggdesc);465dtp->dt_aggdesc = NULL;466dtp->dt_maxagg = 0;467}468469const char *470dt_strdata_lookup(dtrace_hdl_t *dtp, int idx)471{472if (idx == 0 || idx > dtp->dt_maxstrdata)473return (NULL);474475if (dtp->dt_strdata == NULL)476return (NULL);477478return (dtp->dt_strdata[idx - 1]);479}480481void482dt_strdata_destroy(dtrace_hdl_t *dtp)483{484int i;485486for (i = 0; i < dtp->dt_maxstrdata; i++) {487free(dtp->dt_strdata[i]);488}489490free(dtp->dt_strdata);491dtp->dt_strdata = NULL;492}493494495