1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright (c) 1994, by Sun Microsytems, Inc.
24 */
25
26#pragma ident	"%Z%%M%	%I%	%E% SMI"
27
28/*
29 * Includes
30 */
31
32#ifndef DEBUG
33#define	NDEBUG	1
34#endif
35
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#include <assert.h>
40#include <libintl.h>
41#include <search.h>
42
43#include "source.h"
44#include "queue.h"
45#include "list.h"
46#include "spec.h"
47#include "new.h"
48#include "fcn.h"
49
50extern caddr_t  g_commitfunc;
51
52
53/*
54 * Typedefs
55 */
56
57typedef struct list_probe_args {
58	spec_t		 *speclist_p;
59	expr_t		 *exprlist_p;
60} list_probe_args_t;
61
62typedef struct list_attrs_args {
63	spec_t		 *speclist_p;
64	void		   *attrroot_p;
65} list_attrs_args_t;
66
67typedef struct attr_node {
68	char		   *name;
69	void		   *valsroot_p;
70} attr_node_t;
71
72typedef struct vals_node {
73	char		   *name;
74} vals_node_t;
75
76
77/*
78 * Globals
79 */
80
81
82/*
83 * Declarations
84 */
85
86static tnfctl_errcode_t listprobe(tnfctl_handle_t *hndl,
87	tnfctl_probe_t *ref_p, void *calldata_p);
88static tnfctl_errcode_t probescan(tnfctl_handle_t *hndl,
89	tnfctl_probe_t *ref_p, void *calldata_p);
90static void printattrval(spec_t * spec_p, char *attr, char *value,
91	void *pdata);
92static void attrscan(spec_t * spec_p, char *attr, char *values, void *pdata);
93static int attrcompare(const void *node1, const void *node2);
94static int valscompare(const void *node1, const void *node2);
95static void printattrs(const void *node, VISIT order, int level);
96static void printvals(const void *node, VISIT order, int level);
97
98#if 0
99static void	 attrnodedel(attr_node_t * an_p);
100#endif
101
102static void valadd(spec_t * spec_p, char *val, void *calldata_p);
103
104
105/* ---------------------------------------------------------------- */
106/* ----------------------- Public Functions ----------------------- */
107/* ---------------------------------------------------------------- */
108
109extern tnfctl_handle_t	*g_hndl;
110
111/*
112 * list_set() - lists all of the current probes in a target process
113 */
114
115void
116list_set(spec_t * speclist_p, char *setname_p)
117{
118	set_t *set_p;
119	list_probe_args_t args;
120	tnfctl_errcode_t err;
121
122	set_p = set_find(setname_p);
123	if (!set_p) {
124		semantic_err(gettext("missing or invalid set"));
125		return;
126	}
127	args.speclist_p = speclist_p;
128	args.exprlist_p = set_p->exprlist_p;
129	err = tnfctl_probe_apply(g_hndl, listprobe, &args);
130	if (err) {
131		semantic_err(gettext("listing error : %s"),
132				tnfctl_strerror(err));
133	}
134}
135
136
137/*
138 * list_expr() - lists all of the current probes in an expression list
139 */
140
141void
142list_expr(spec_t * speclist_p, expr_t * expr_p)
143{
144	list_probe_args_t args;
145	tnfctl_errcode_t err;
146
147	args.speclist_p = speclist_p;
148	args.exprlist_p = expr_p;
149	err = tnfctl_probe_apply(g_hndl, listprobe, &args);
150	if (err) {
151		semantic_err(gettext("listing error : %s"),
152				tnfctl_strerror(err));
153	}
154}
155
156
157/*
158 * list_values() - list all the values for a supplied spec
159 */
160
161void
162list_values(spec_t * speclist_p)
163{
164	list_attrs_args_t args;
165	tnfctl_errcode_t err;
166
167	/* setup argument block */
168	args.speclist_p = speclist_p;
169	args.attrroot_p = NULL;
170
171	/* traverse the probes, recording attributes that match */
172	err = tnfctl_probe_apply(g_hndl, probescan, &args);
173	if (err) {
174		semantic_err(gettext("probe traversal error : %s"),
175				tnfctl_strerror(err));
176	}
177
178	/* pretty print the results */
179	twalk(args.attrroot_p, printattrs);
180
181	/* destroy the attribute tree */
182	while (args.attrroot_p) {
183		attr_node_t   **aptr;
184		char			*anameptr;
185
186		aptr = (attr_node_t **) args.attrroot_p;
187
188		/* destroy the value tree */
189		while ((*aptr)->valsroot_p) {
190			vals_node_t   **vptr;
191			char			*vnameptr;
192
193			vptr = (vals_node_t **) (*aptr)->valsroot_p;
194			vnameptr = (*vptr)->name;
195#ifdef LEAKCHK
196			(void) fprintf(stderr, "freeing value \"%s\"\n",
197				vnameptr);
198#endif
199			(void) tdelete((void *) *vptr, &(*aptr)->valsroot_p,
200				valscompare);
201			if (vnameptr) free(vnameptr);
202		}
203
204		anameptr = (*aptr)->name;
205#ifdef LEAKCHK
206		(void) fprintf(stderr, "freeing attr \"%s\"\n", anameptr);
207#endif
208		(void) tdelete((void *) *aptr, &args.attrroot_p, attrcompare);
209		if (anameptr) free(anameptr);
210	}
211
212}				/* end list_values */
213
214
215/*
216 * list_getattrs() - build an attribute string for this probe.
217 */
218
219
220#define	BUF_LIMIT	2048
221
222char *
223list_getattrs(tnfctl_probe_t *probe_p)
224{
225	tnfctl_errcode_t	err;
226	tnfctl_probe_state_t	p_state;
227	char			*attrs;
228	char			buffer[BUF_LIMIT];
229	char			*buf_p;
230	char			*buf_end;
231	int			str_len;
232	size_t			len;
233
234	err = tnfctl_probe_state_get(g_hndl, probe_p, &p_state);
235	if (err) {
236		attrs = malloc(2);
237		if (attrs)
238			attrs[0] = '\0';
239		return (attrs);
240	}
241
242	buf_p = buffer;
243	buf_end = buf_p + BUF_LIMIT;
244	str_len = sprintf(buf_p, "enable %s; trace %s; ",
245				(p_state.enabled) ? "on" : "off",
246				(p_state.traced) ? "on" : "off");
247	buf_p += str_len;
248	if (p_state.obj_name) {
249		str_len = strlen(p_state.obj_name);
250		if (buf_p + str_len < buf_end) {
251			str_len = sprintf(buf_p, "object %s; ",
252							p_state.obj_name);
253			buf_p += str_len;
254		}
255	}
256	str_len = sprintf(buf_p, "funcs");
257	buf_p += str_len;
258
259	/* REMIND: add limit for string size */
260	if (p_state.func_names) {
261		int 	i = 0;
262		char	*fcnname;
263
264		while (p_state.func_names[i]) {
265			(void) strcat(buffer, " ");
266
267			fcnname = fcn_findname(p_state.func_names[i]);
268			if (fcnname) {
269				(void) strcat(buffer, "&");
270				(void) strcat(buffer, fcnname);
271			} else
272				(void) strcat(buffer, p_state.func_names[i]);
273			i++;
274		}
275	}
276
277	(void) strcat(buffer, ";");
278
279	len = strlen(buffer) + strlen(p_state.attr_string) + 1;
280	attrs = (char *) malloc(len);
281
282	if (attrs) {
283		(void) strcpy(attrs, buffer);
284		(void) strcat(attrs, p_state.attr_string);
285	}
286
287	return (attrs);
288}
289
290
291/* ---------------------------------------------------------------- */
292/* ----------------------- Private Functions ---------------------- */
293/* ---------------------------------------------------------------- */
294
295/*
296 * probescan() - function used as a callback, gathers probe attributes and
297 * values
298 */
299/*ARGSUSED*/
300static tnfctl_errcode_t
301probescan(tnfctl_handle_t *hndl, tnfctl_probe_t *ref_p, void *calldata_p)
302{
303	list_attrs_args_t *args_p = (list_attrs_args_t *) calldata_p;
304	spec_t		*speclist_p;
305	spec_t		*spec_p;
306	char		*attrs;
307
308	speclist_p = args_p->speclist_p;
309	spec_p = NULL;
310
311	attrs = list_getattrs(ref_p);
312
313	while (spec_p = (spec_t *) queue_next(&speclist_p->qn, &spec_p->qn)) {
314		spec_attrtrav(spec_p, attrs, attrscan, calldata_p);
315	}
316
317	if (attrs)
318		free(attrs);
319
320	return (TNFCTL_ERR_NONE);
321}
322
323
324/*
325 * attrscan() - called on each matching attr/values component
326 */
327
328/*ARGSUSED*/
329static void
330attrscan(spec_t * spec_p,
331	char *attr,
332	char *values,
333	void *pdata)
334{
335	list_attrs_args_t *args_p = (list_attrs_args_t *) pdata;
336	attr_node_t	*an_p;
337	attr_node_t   **ret_pp;
338	static spec_t  *allspec = NULL;
339
340	if (!allspec)
341		allspec = spec(".*", SPEC_REGEXP);
342
343	an_p = new(attr_node_t);
344
345#ifdef LEAKCHK
346	(void) fprintf(stderr, "creating attr \"%s\"\n", attr);
347#endif
348	an_p->name = strdup(attr);
349	an_p->valsroot_p = NULL;
350
351	ret_pp = tfind((void *) an_p, &args_p->attrroot_p, attrcompare);
352
353	if (ret_pp) {
354		/*
355		 * we already had a node for this attribute; delete ours *
356		 * and point at the original instead.
357		 */
358#ifdef LEAKCHK
359		(void) fprintf(stderr, "attr already there \"%s\"\n", attr);
360#endif
361		if (an_p->name)
362			free(an_p->name);
363		free(an_p);
364
365		an_p = *ret_pp;
366	} else {
367		(void) tsearch((void *) an_p, &args_p->attrroot_p, attrcompare);
368	}
369
370	spec_valtrav(allspec, values, valadd, (void *) an_p);
371
372}				/* end attrscan */
373
374
375/*
376 * valadd() - add vals to an attributes tree
377 */
378
379/*ARGSUSED*/
380static void
381valadd(spec_t * spec_p,
382	char *val,
383	void *calldata_p)
384{
385	attr_node_t	*an_p = (attr_node_t *) calldata_p;
386
387	vals_node_t	*vn_p;
388	vals_node_t   **ret_pp;
389
390	vn_p = new(vals_node_t);
391#ifdef LEAKCHK
392	(void) fprintf(stderr, "creating value \"%s\"\n", val);
393#endif
394	vn_p->name = strdup(val);
395
396	ret_pp = tfind((void *) vn_p, &an_p->valsroot_p, valscompare);
397
398	if (ret_pp) {
399		/* we already had a node for this value */
400#ifdef LEAKCHK
401		(void) fprintf(stderr, "value already there \"%s\"\n", val);
402#endif
403		if (vn_p->name)
404			free(vn_p->name);
405		free(vn_p);
406	} else {
407		(void) tsearch((void *) vn_p, &an_p->valsroot_p, valscompare);
408	}
409
410
411}				/* end valadd */
412
413
414/*
415 * attrcompare() - compares attribute nodes, alphabetically
416 */
417
418static int
419attrcompare(const void *node1,
420		const void *node2)
421{
422	return strcmp(((attr_node_t *) node1)->name,
423		((attr_node_t *) node2)->name);
424
425}				/* end attrcompare */
426
427
428/*
429 * valscompare() - compares attribute nodes, alphabetically
430 */
431
432static int
433valscompare(const void *node1,
434		const void *node2)
435{
436	return strcmp(((vals_node_t *) node1)->name,
437		((vals_node_t *) node2)->name);
438
439}				/* end valscompare */
440
441
442/*
443 * printattrs() - prints attributes from the attr tree
444 */
445
446/*ARGSUSED*/
447static void
448printattrs(const void *node,
449	VISIT order,
450	int level)
451{
452	attr_node_t	*an_p = (*(attr_node_t **) node);
453
454	if (order == postorder || order == leaf) {
455		(void) printf("%s =\n", an_p->name);
456		twalk(an_p->valsroot_p, printvals);
457	}
458}				/* end printattrs */
459
460
461/*
462 * printvals() - prints values from a value tree
463 */
464
465/*ARGSUSED*/
466static void
467printvals(const void *node,
468	VISIT order,
469	int level)
470{
471	vals_node_t	*vn_p = (*(vals_node_t **) node);
472
473	if (order == postorder || order == leaf)
474		(void) printf("	   %s\n", vn_p->name);
475
476}				/* end printvals */
477
478
479#if 0
480/*
481 * attrnodedel() - deletes an attr_node_t after the action
482 */
483
484static void
485attrnodedel(attr_node_t * an_p)
486{
487	if (an_p->name)
488		free(an_p->name);
489
490	/* destroy the value tree */
491	while (an_p->valsroot_p) {
492		vals_node_t   **ptr;
493
494		ptr = (vals_node_t **) an_p->valsroot_p;
495		(void) tdelete((void *) *ptr, &an_p->valsroot_p, valscompare);
496	}
497
498	/* We don't need to free this object, since tdelete() appears to */
499	/* free(an_p); */
500
501}				/* end attrnodedel */
502#endif
503
504
505/*
506 * listprobe() - function used as a callback, pretty prints a probe
507 */
508/*ARGSUSED*/
509static tnfctl_errcode_t
510listprobe(tnfctl_handle_t *hndl, tnfctl_probe_t *ref_p, void *calldata_p)
511{
512	static spec_t	*default_speclist = NULL;
513	list_probe_args_t *args_p = (list_probe_args_t *) calldata_p;
514	spec_t		*speclist_p;
515	spec_t		*spec_p;
516	boolean_t	sawattr;
517	char		*attrs;
518
519	/* build a default speclist if there is not one built already */
520	if (!default_speclist) {
521		default_speclist = spec_list(
522			spec_list(
523				spec_list(
524					spec_list(
525						spec_list(
526							spec("name",
527								SPEC_EXACT),
528							spec("enable",
529								SPEC_EXACT)),
530						spec("trace", SPEC_EXACT)),
531					spec("file", SPEC_EXACT)),
532				spec("line", SPEC_EXACT)),
533			spec("funcs", SPEC_EXACT));
534	}
535	attrs = list_getattrs(ref_p);
536
537	if (expr_match(args_p->exprlist_p, attrs)) {
538		speclist_p = args_p->speclist_p;
539		speclist_p = (speclist_p) ? speclist_p : default_speclist;
540
541		spec_p = NULL;
542		while (spec_p = (spec_t *)
543			queue_next(&speclist_p->qn, &spec_p->qn)) {
544			sawattr = B_FALSE;
545			spec_attrtrav(spec_p, attrs, printattrval, &sawattr);
546			if (!sawattr)
547				(void) printf("<no attr> ");
548		}
549		(void) printf("\n");
550	}
551	if (attrs)
552		free(attrs);
553
554	return (TNFCTL_ERR_NONE);
555}
556
557
558/*ARGSUSED*/
559static void
560printattrval(spec_t * spec_p,
561	char *attr,
562	char *value,
563	void *pdata)
564{
565	boolean_t	  *bptr = (boolean_t *) pdata;
566
567	*bptr = B_TRUE;
568
569	(void) printf("%s=%s ", attr, (value && *value) ? value : "<no value>");
570
571}				/* end printattrval */
572