/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1994, by Sun Microsytems, Inc. */ #pragma ident "%Z%%M% %I% %E% SMI" /* * Includes */ #ifndef DEBUG #define NDEBUG 1 #endif #include #include #include #include #include #include #include "source.h" #include "queue.h" #include "list.h" #include "spec.h" #include "new.h" #include "fcn.h" extern caddr_t g_commitfunc; /* * Typedefs */ typedef struct list_probe_args { spec_t *speclist_p; expr_t *exprlist_p; } list_probe_args_t; typedef struct list_attrs_args { spec_t *speclist_p; void *attrroot_p; } list_attrs_args_t; typedef struct attr_node { char *name; void *valsroot_p; } attr_node_t; typedef struct vals_node { char *name; } vals_node_t; /* * Globals */ /* * Declarations */ static tnfctl_errcode_t listprobe(tnfctl_handle_t *hndl, tnfctl_probe_t *ref_p, void *calldata_p); static tnfctl_errcode_t probescan(tnfctl_handle_t *hndl, tnfctl_probe_t *ref_p, void *calldata_p); static void printattrval(spec_t * spec_p, char *attr, char *value, void *pdata); static void attrscan(spec_t * spec_p, char *attr, char *values, void *pdata); static int attrcompare(const void *node1, const void *node2); static int valscompare(const void *node1, const void *node2); static void printattrs(const void *node, VISIT order, int level); static void printvals(const void *node, VISIT order, int level); #if 0 static void attrnodedel(attr_node_t * an_p); #endif static void valadd(spec_t * spec_p, char *val, void *calldata_p); /* ---------------------------------------------------------------- */ /* ----------------------- Public Functions ----------------------- */ /* ---------------------------------------------------------------- */ extern tnfctl_handle_t *g_hndl; /* * list_set() - lists all of the current probes in a target process */ void list_set(spec_t * speclist_p, char *setname_p) { set_t *set_p; list_probe_args_t args; tnfctl_errcode_t err; set_p = set_find(setname_p); if (!set_p) { semantic_err(gettext("missing or invalid set")); return; } args.speclist_p = speclist_p; args.exprlist_p = set_p->exprlist_p; err = tnfctl_probe_apply(g_hndl, listprobe, &args); if (err) { semantic_err(gettext("listing error : %s"), tnfctl_strerror(err)); } } /* * list_expr() - lists all of the current probes in an expression list */ void list_expr(spec_t * speclist_p, expr_t * expr_p) { list_probe_args_t args; tnfctl_errcode_t err; args.speclist_p = speclist_p; args.exprlist_p = expr_p; err = tnfctl_probe_apply(g_hndl, listprobe, &args); if (err) { semantic_err(gettext("listing error : %s"), tnfctl_strerror(err)); } } /* * list_values() - list all the values for a supplied spec */ void list_values(spec_t * speclist_p) { list_attrs_args_t args; tnfctl_errcode_t err; /* setup argument block */ args.speclist_p = speclist_p; args.attrroot_p = NULL; /* traverse the probes, recording attributes that match */ err = tnfctl_probe_apply(g_hndl, probescan, &args); if (err) { semantic_err(gettext("probe traversal error : %s"), tnfctl_strerror(err)); } /* pretty print the results */ twalk(args.attrroot_p, printattrs); /* destroy the attribute tree */ while (args.attrroot_p) { attr_node_t **aptr; char *anameptr; aptr = (attr_node_t **) args.attrroot_p; /* destroy the value tree */ while ((*aptr)->valsroot_p) { vals_node_t **vptr; char *vnameptr; vptr = (vals_node_t **) (*aptr)->valsroot_p; vnameptr = (*vptr)->name; #ifdef LEAKCHK (void) fprintf(stderr, "freeing value \"%s\"\n", vnameptr); #endif (void) tdelete((void *) *vptr, &(*aptr)->valsroot_p, valscompare); if (vnameptr) free(vnameptr); } anameptr = (*aptr)->name; #ifdef LEAKCHK (void) fprintf(stderr, "freeing attr \"%s\"\n", anameptr); #endif (void) tdelete((void *) *aptr, &args.attrroot_p, attrcompare); if (anameptr) free(anameptr); } } /* end list_values */ /* * list_getattrs() - build an attribute string for this probe. */ #define BUF_LIMIT 2048 char * list_getattrs(tnfctl_probe_t *probe_p) { tnfctl_errcode_t err; tnfctl_probe_state_t p_state; char *attrs; char buffer[BUF_LIMIT]; char *buf_p; char *buf_end; int str_len; size_t len; err = tnfctl_probe_state_get(g_hndl, probe_p, &p_state); if (err) { attrs = malloc(2); if (attrs) attrs[0] = '\0'; return (attrs); } buf_p = buffer; buf_end = buf_p + BUF_LIMIT; str_len = sprintf(buf_p, "enable %s; trace %s; ", (p_state.enabled) ? "on" : "off", (p_state.traced) ? "on" : "off"); buf_p += str_len; if (p_state.obj_name) { str_len = strlen(p_state.obj_name); if (buf_p + str_len < buf_end) { str_len = sprintf(buf_p, "object %s; ", p_state.obj_name); buf_p += str_len; } } str_len = sprintf(buf_p, "funcs"); buf_p += str_len; /* REMIND: add limit for string size */ if (p_state.func_names) { int i = 0; char *fcnname; while (p_state.func_names[i]) { (void) strcat(buffer, " "); fcnname = fcn_findname(p_state.func_names[i]); if (fcnname) { (void) strcat(buffer, "&"); (void) strcat(buffer, fcnname); } else (void) strcat(buffer, p_state.func_names[i]); i++; } } (void) strcat(buffer, ";"); len = strlen(buffer) + strlen(p_state.attr_string) + 1; attrs = (char *) malloc(len); if (attrs) { (void) strcpy(attrs, buffer); (void) strcat(attrs, p_state.attr_string); } return (attrs); } /* ---------------------------------------------------------------- */ /* ----------------------- Private Functions ---------------------- */ /* ---------------------------------------------------------------- */ /* * probescan() - function used as a callback, gathers probe attributes and * values */ /*ARGSUSED*/ static tnfctl_errcode_t probescan(tnfctl_handle_t *hndl, tnfctl_probe_t *ref_p, void *calldata_p) { list_attrs_args_t *args_p = (list_attrs_args_t *) calldata_p; spec_t *speclist_p; spec_t *spec_p; char *attrs; speclist_p = args_p->speclist_p; spec_p = NULL; attrs = list_getattrs(ref_p); while (spec_p = (spec_t *) queue_next(&speclist_p->qn, &spec_p->qn)) { spec_attrtrav(spec_p, attrs, attrscan, calldata_p); } if (attrs) free(attrs); return (TNFCTL_ERR_NONE); } /* * attrscan() - called on each matching attr/values component */ /*ARGSUSED*/ static void attrscan(spec_t * spec_p, char *attr, char *values, void *pdata) { list_attrs_args_t *args_p = (list_attrs_args_t *) pdata; attr_node_t *an_p; attr_node_t **ret_pp; static spec_t *allspec = NULL; if (!allspec) allspec = spec(".*", SPEC_REGEXP); an_p = new(attr_node_t); #ifdef LEAKCHK (void) fprintf(stderr, "creating attr \"%s\"\n", attr); #endif an_p->name = strdup(attr); an_p->valsroot_p = NULL; ret_pp = tfind((void *) an_p, &args_p->attrroot_p, attrcompare); if (ret_pp) { /* * we already had a node for this attribute; delete ours * * and point at the original instead. */ #ifdef LEAKCHK (void) fprintf(stderr, "attr already there \"%s\"\n", attr); #endif if (an_p->name) free(an_p->name); free(an_p); an_p = *ret_pp; } else { (void) tsearch((void *) an_p, &args_p->attrroot_p, attrcompare); } spec_valtrav(allspec, values, valadd, (void *) an_p); } /* end attrscan */ /* * valadd() - add vals to an attributes tree */ /*ARGSUSED*/ static void valadd(spec_t * spec_p, char *val, void *calldata_p) { attr_node_t *an_p = (attr_node_t *) calldata_p; vals_node_t *vn_p; vals_node_t **ret_pp; vn_p = new(vals_node_t); #ifdef LEAKCHK (void) fprintf(stderr, "creating value \"%s\"\n", val); #endif vn_p->name = strdup(val); ret_pp = tfind((void *) vn_p, &an_p->valsroot_p, valscompare); if (ret_pp) { /* we already had a node for this value */ #ifdef LEAKCHK (void) fprintf(stderr, "value already there \"%s\"\n", val); #endif if (vn_p->name) free(vn_p->name); free(vn_p); } else { (void) tsearch((void *) vn_p, &an_p->valsroot_p, valscompare); } } /* end valadd */ /* * attrcompare() - compares attribute nodes, alphabetically */ static int attrcompare(const void *node1, const void *node2) { return strcmp(((attr_node_t *) node1)->name, ((attr_node_t *) node2)->name); } /* end attrcompare */ /* * valscompare() - compares attribute nodes, alphabetically */ static int valscompare(const void *node1, const void *node2) { return strcmp(((vals_node_t *) node1)->name, ((vals_node_t *) node2)->name); } /* end valscompare */ /* * printattrs() - prints attributes from the attr tree */ /*ARGSUSED*/ static void printattrs(const void *node, VISIT order, int level) { attr_node_t *an_p = (*(attr_node_t **) node); if (order == postorder || order == leaf) { (void) printf("%s =\n", an_p->name); twalk(an_p->valsroot_p, printvals); } } /* end printattrs */ /* * printvals() - prints values from a value tree */ /*ARGSUSED*/ static void printvals(const void *node, VISIT order, int level) { vals_node_t *vn_p = (*(vals_node_t **) node); if (order == postorder || order == leaf) (void) printf(" %s\n", vn_p->name); } /* end printvals */ #if 0 /* * attrnodedel() - deletes an attr_node_t after the action */ static void attrnodedel(attr_node_t * an_p) { if (an_p->name) free(an_p->name); /* destroy the value tree */ while (an_p->valsroot_p) { vals_node_t **ptr; ptr = (vals_node_t **) an_p->valsroot_p; (void) tdelete((void *) *ptr, &an_p->valsroot_p, valscompare); } /* We don't need to free this object, since tdelete() appears to */ /* free(an_p); */ } /* end attrnodedel */ #endif /* * listprobe() - function used as a callback, pretty prints a probe */ /*ARGSUSED*/ static tnfctl_errcode_t listprobe(tnfctl_handle_t *hndl, tnfctl_probe_t *ref_p, void *calldata_p) { static spec_t *default_speclist = NULL; list_probe_args_t *args_p = (list_probe_args_t *) calldata_p; spec_t *speclist_p; spec_t *spec_p; boolean_t sawattr; char *attrs; /* build a default speclist if there is not one built already */ if (!default_speclist) { default_speclist = spec_list( spec_list( spec_list( spec_list( spec_list( spec("name", SPEC_EXACT), spec("enable", SPEC_EXACT)), spec("trace", SPEC_EXACT)), spec("file", SPEC_EXACT)), spec("line", SPEC_EXACT)), spec("funcs", SPEC_EXACT)); } attrs = list_getattrs(ref_p); if (expr_match(args_p->exprlist_p, attrs)) { speclist_p = args_p->speclist_p; speclist_p = (speclist_p) ? speclist_p : default_speclist; spec_p = NULL; while (spec_p = (spec_t *) queue_next(&speclist_p->qn, &spec_p->qn)) { sawattr = B_FALSE; spec_attrtrav(spec_p, attrs, printattrval, &sawattr); if (!sawattr) (void) printf(" "); } (void) printf("\n"); } if (attrs) free(attrs); return (TNFCTL_ERR_NONE); } /*ARGSUSED*/ static void printattrval(spec_t * spec_p, char *attr, char *value, void *pdata) { boolean_t *bptr = (boolean_t *) pdata; *bptr = B_TRUE; (void) printf("%s=%s ", attr, (value && *value) ? value : ""); } /* end printattrval */