list.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <libintl.h>
#include <search.h>
#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("<no attr> ");
}
(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 : "<no value>");
} /* end printattrval */