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 (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2013, Joyent, Inc. All rights reserved.
25 * Copyright (c) 2013 by Delphix. All rights reserved.
26 */
27
28#ifdef illumos
29#include <sys/sysmacros.h>
30#else
31#define	ABS(a)		((a) < 0 ? -(a) : (a))
32#endif
33#include <string.h>
34#include <strings.h>
35#include <stdlib.h>
36#ifdef illumos
37#include <alloca.h>
38#endif
39#include <assert.h>
40#include <ctype.h>
41#include <errno.h>
42#include <limits.h>
43#include <sys/socket.h>
44#include <netdb.h>
45#include <netinet/in.h>
46#include <arpa/inet.h>
47#include <arpa/nameser.h>
48
49#include <dt_printf.h>
50#include <dt_string.h>
51#include <dt_impl.h>
52
53/*ARGSUSED*/
54static int
55pfcheck_addr(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
56{
57	return (dt_node_is_pointer(dnp) || dt_node_is_integer(dnp));
58}
59
60/*ARGSUSED*/
61static int
62pfcheck_kaddr(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
63{
64	return (dt_node_is_pointer(dnp) || dt_node_is_integer(dnp) ||
65	    dt_node_is_symaddr(dnp));
66}
67
68/*ARGSUSED*/
69static int
70pfcheck_uaddr(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
71{
72	dtrace_hdl_t *dtp = pfv->pfv_dtp;
73	dt_ident_t *idp = dt_idhash_lookup(dtp->dt_macros, "target");
74
75	if (dt_node_is_usymaddr(dnp))
76		return (1);
77
78	if (idp == NULL || idp->di_id == 0)
79		return (0);
80
81	return (dt_node_is_pointer(dnp) || dt_node_is_integer(dnp));
82}
83
84/*ARGSUSED*/
85static int
86pfcheck_stack(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
87{
88	return (dt_node_is_stack(dnp));
89}
90
91/*ARGSUSED*/
92static int
93pfcheck_time(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
94{
95	return (dt_node_is_integer(dnp) &&
96	    dt_node_type_size(dnp) == sizeof (uint64_t));
97}
98
99/*ARGSUSED*/
100static int
101pfcheck_str(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
102{
103	ctf_file_t *ctfp;
104	ctf_encoding_t e;
105	ctf_arinfo_t r;
106	ctf_id_t base;
107	uint_t kind;
108
109	if (dt_node_is_string(dnp))
110		return (1);
111
112	ctfp = dnp->dn_ctfp;
113	base = ctf_type_resolve(ctfp, dnp->dn_type);
114	kind = ctf_type_kind(ctfp, base);
115
116	return (kind == CTF_K_ARRAY && ctf_array_info(ctfp, base, &r) == 0 &&
117	    (base = ctf_type_resolve(ctfp, r.ctr_contents)) != CTF_ERR &&
118	    ctf_type_encoding(ctfp, base, &e) == 0 && IS_CHAR(e));
119}
120
121/*ARGSUSED*/
122static int
123pfcheck_wstr(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
124{
125	ctf_file_t *ctfp = dnp->dn_ctfp;
126	ctf_id_t base = ctf_type_resolve(ctfp, dnp->dn_type);
127	uint_t kind = ctf_type_kind(ctfp, base);
128
129	ctf_encoding_t e;
130	ctf_arinfo_t r;
131
132	return (kind == CTF_K_ARRAY && ctf_array_info(ctfp, base, &r) == 0 &&
133	    (base = ctf_type_resolve(ctfp, r.ctr_contents)) != CTF_ERR &&
134	    ctf_type_kind(ctfp, base) == CTF_K_INTEGER &&
135	    ctf_type_encoding(ctfp, base, &e) == 0 && e.cte_bits == 32);
136}
137
138/*ARGSUSED*/
139static int
140pfcheck_csi(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
141{
142	return (dt_node_is_integer(dnp) &&
143	    dt_node_type_size(dnp) <= sizeof (int));
144}
145
146/*ARGSUSED*/
147static int
148pfcheck_fp(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
149{
150	return (dt_node_is_float(dnp));
151}
152
153/*ARGSUSED*/
154static int
155pfcheck_xint(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
156{
157	return (dt_node_is_integer(dnp));
158}
159
160/*ARGSUSED*/
161static int
162pfcheck_dint(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
163{
164	if (dnp->dn_flags & DT_NF_SIGNED)
165		pfd->pfd_fmt[strlen(pfd->pfd_fmt) - 1] = 'i';
166	else
167		pfd->pfd_fmt[strlen(pfd->pfd_fmt) - 1] = 'u';
168
169	return (dt_node_is_integer(dnp));
170}
171
172/*ARGSUSED*/
173static int
174pfcheck_xshort(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
175{
176	ctf_file_t *ctfp = dnp->dn_ctfp;
177	ctf_id_t type = ctf_type_resolve(ctfp, dnp->dn_type);
178	char n[DT_TYPE_NAMELEN];
179
180	return (ctf_type_name(ctfp, type, n, sizeof (n)) != NULL && (
181	    strcmp(n, "short") == 0 || strcmp(n, "signed short") == 0 ||
182	    strcmp(n, "unsigned short") == 0));
183}
184
185/*ARGSUSED*/
186static int
187pfcheck_xlong(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
188{
189	ctf_file_t *ctfp = dnp->dn_ctfp;
190	ctf_id_t type = ctf_type_resolve(ctfp, dnp->dn_type);
191	char n[DT_TYPE_NAMELEN];
192
193	return (ctf_type_name(ctfp, type, n, sizeof (n)) != NULL && (
194	    strcmp(n, "long") == 0 || strcmp(n, "signed long") == 0 ||
195	    strcmp(n, "unsigned long") == 0));
196}
197
198/*ARGSUSED*/
199static int
200pfcheck_xlonglong(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
201{
202	ctf_file_t *ctfp = dnp->dn_ctfp;
203	ctf_id_t type = dnp->dn_type;
204	char n[DT_TYPE_NAMELEN];
205
206	if (ctf_type_name(ctfp, ctf_type_resolve(ctfp, type), n,
207	    sizeof (n)) != NULL && (strcmp(n, "long long") == 0 ||
208	    strcmp(n, "signed long long") == 0 ||
209	    strcmp(n, "unsigned long long") == 0))
210		return (1);
211
212	/*
213	 * If the type used for %llx or %llX is not an [unsigned] long long, we
214	 * also permit it to be a [u]int64_t or any typedef thereof.  We know
215	 * that these typedefs are guaranteed to work with %ll[xX] in either
216	 * compilation environment even though they alias to "long" in LP64.
217	 */
218	while (ctf_type_kind(ctfp, type) == CTF_K_TYPEDEF) {
219		if (ctf_type_name(ctfp, type, n, sizeof (n)) != NULL &&
220		    (strcmp(n, "int64_t") == 0 || strcmp(n, "uint64_t") == 0))
221			return (1);
222
223		type = ctf_type_reference(ctfp, type);
224	}
225
226	return (0);
227}
228
229/*ARGSUSED*/
230static int
231pfcheck_type(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
232{
233	return (ctf_type_compat(dnp->dn_ctfp, ctf_type_resolve(dnp->dn_ctfp,
234	    dnp->dn_type), pfd->pfd_conv->pfc_dctfp, pfd->pfd_conv->pfc_dtype));
235}
236
237/*ARGSUSED*/
238static int
239pfprint_sint(dtrace_hdl_t *dtp, FILE *fp, const char *format,
240    const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t unormal)
241{
242	int64_t normal = (int64_t)unormal;
243	int32_t n = (int32_t)normal;
244
245	switch (size) {
246	case sizeof (int8_t):
247		return (dt_printf(dtp, fp, format,
248		    (int32_t)*((int8_t *)addr) / n));
249	case sizeof (int16_t):
250		return (dt_printf(dtp, fp, format,
251		    (int32_t)*((int16_t *)addr) / n));
252	case sizeof (int32_t):
253		return (dt_printf(dtp, fp, format,
254		    *((int32_t *)addr) / n));
255	case sizeof (int64_t):
256		return (dt_printf(dtp, fp, format,
257		    *((int64_t *)addr) / normal));
258	default:
259		return (dt_set_errno(dtp, EDT_DMISMATCH));
260	}
261}
262
263/*ARGSUSED*/
264static int
265pfprint_uint(dtrace_hdl_t *dtp, FILE *fp, const char *format,
266    const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
267{
268	uint32_t n = (uint32_t)normal;
269
270	switch (size) {
271	case sizeof (uint8_t):
272		return (dt_printf(dtp, fp, format,
273		    (uint32_t)*((uint8_t *)addr) / n));
274	case sizeof (uint16_t):
275		return (dt_printf(dtp, fp, format,
276		    (uint32_t)*((uint16_t *)addr) / n));
277	case sizeof (uint32_t):
278		return (dt_printf(dtp, fp, format,
279		    *((uint32_t *)addr) / n));
280	case sizeof (uint64_t):
281		return (dt_printf(dtp, fp, format,
282		    *((uint64_t *)addr) / normal));
283	default:
284		return (dt_set_errno(dtp, EDT_DMISMATCH));
285	}
286}
287
288static int
289pfprint_dint(dtrace_hdl_t *dtp, FILE *fp, const char *format,
290    const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
291{
292	if (pfd->pfd_flags & DT_PFCONV_SIGNED)
293		return (pfprint_sint(dtp, fp, format, pfd, addr, size, normal));
294	else
295		return (pfprint_uint(dtp, fp, format, pfd, addr, size, normal));
296}
297
298/*ARGSUSED*/
299static int
300pfprint_fp(dtrace_hdl_t *dtp, FILE *fp, const char *format,
301    const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
302{
303	double n = (double)normal;
304	long double ldn = (long double)normal;
305
306	switch (size) {
307	case sizeof (float):
308		return (dt_printf(dtp, fp, format,
309		    (double)*((float *)addr) / n));
310	case sizeof (double):
311		return (dt_printf(dtp, fp, format,
312		    *((double *)addr) / n));
313#if !defined(__arm__) && !defined(__powerpc__) && \
314    !defined(__mips__) && !defined(__riscv)
315	case sizeof (long double):
316		return (dt_printf(dtp, fp, format,
317		    *((long double *)addr) / ldn));
318#endif
319	default:
320		return (dt_set_errno(dtp, EDT_DMISMATCH));
321	}
322}
323
324/*ARGSUSED*/
325static int
326pfprint_addr(dtrace_hdl_t *dtp, FILE *fp, const char *format,
327    const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
328{
329	char *s;
330	int n, len = 256;
331	uint64_t val;
332
333	switch (size) {
334	case sizeof (uint32_t):
335		val = *((uint32_t *)addr);
336		break;
337	case sizeof (uint64_t):
338		val = *((uint64_t *)addr);
339		break;
340	default:
341		return (dt_set_errno(dtp, EDT_DMISMATCH));
342	}
343
344	do {
345		n = len;
346		s = alloca(n);
347	} while ((len = dtrace_addr2str(dtp, val, s, n)) > n);
348
349	return (dt_printf(dtp, fp, format, s));
350}
351
352/*ARGSUSED*/
353static int
354pfprint_mod(dtrace_hdl_t *dtp, FILE *fp, const char *format,
355    const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
356{
357	return (dt_print_mod(dtp, fp, format, (caddr_t)addr));
358}
359
360/*ARGSUSED*/
361static int
362pfprint_umod(dtrace_hdl_t *dtp, FILE *fp, const char *format,
363    const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
364{
365	return (dt_print_umod(dtp, fp, format, (caddr_t)addr));
366}
367
368/*ARGSUSED*/
369static int
370pfprint_uaddr(dtrace_hdl_t *dtp, FILE *fp, const char *format,
371    const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
372{
373	char *s;
374	int n, len = 256;
375	uint64_t val, pid = 0;
376
377	dt_ident_t *idp = dt_idhash_lookup(dtp->dt_macros, "target");
378
379	switch (size) {
380	case sizeof (uint32_t):
381		val = (u_longlong_t)*((uint32_t *)addr);
382		break;
383	case sizeof (uint64_t):
384		val = (u_longlong_t)*((uint64_t *)addr);
385		break;
386	case sizeof (uint64_t) * 2:
387		pid = ((uint64_t *)(uintptr_t)addr)[0];
388		val = ((uint64_t *)(uintptr_t)addr)[1];
389		break;
390	default:
391		return (dt_set_errno(dtp, EDT_DMISMATCH));
392	}
393
394	if (pid == 0 && dtp->dt_vector == NULL && idp != NULL)
395		pid = idp->di_id;
396
397	do {
398		n = len;
399		s = alloca(n);
400	} while ((len = dtrace_uaddr2str(dtp, pid, val, s, n)) > n);
401
402	return (dt_printf(dtp, fp, format, s));
403}
404
405/*ARGSUSED*/
406static int
407pfprint_stack(dtrace_hdl_t *dtp, FILE *fp, const char *format,
408    const dt_pfargd_t *pfd, const void *vaddr, size_t size, uint64_t normal)
409{
410	int width;
411	dtrace_optval_t saved = dtp->dt_options[DTRACEOPT_STACKINDENT];
412	const dtrace_recdesc_t *rec = pfd->pfd_rec;
413	caddr_t addr = (caddr_t)vaddr;
414	int err = 0;
415
416	/*
417	 * We have stashed the value of the STACKINDENT option, and we will
418	 * now override it for the purposes of formatting the stack.  If the
419	 * field has been specified as left-aligned (i.e. (%-#), we set the
420	 * indentation to be the width.  This is a slightly odd semantic, but
421	 * it's useful functionality -- and it's slightly odd to begin with to
422	 * be using a single format specifier to be formatting multiple lines
423	 * of text...
424	 */
425	if (pfd->pfd_dynwidth < 0) {
426		assert(pfd->pfd_flags & DT_PFCONV_DYNWIDTH);
427		width = -pfd->pfd_dynwidth;
428	} else if (pfd->pfd_flags & DT_PFCONV_LEFT) {
429		width = pfd->pfd_dynwidth ? pfd->pfd_dynwidth : pfd->pfd_width;
430	} else {
431		width = 0;
432	}
433
434	dtp->dt_options[DTRACEOPT_STACKINDENT] = width;
435
436	switch (rec->dtrd_action) {
437	case DTRACEACT_USTACK:
438	case DTRACEACT_JSTACK:
439		err = dt_print_ustack(dtp, fp, format, addr, rec->dtrd_arg);
440		break;
441
442	case DTRACEACT_STACK:
443		err = dt_print_stack(dtp, fp, format, addr, rec->dtrd_arg,
444		    rec->dtrd_size / rec->dtrd_arg);
445		break;
446
447	default:
448		assert(0);
449	}
450
451	dtp->dt_options[DTRACEOPT_STACKINDENT] = saved;
452
453	return (err);
454}
455
456/*ARGSUSED*/
457static int
458pfprint_time(dtrace_hdl_t *dtp, FILE *fp, const char *format,
459    const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
460{
461	char src[32], buf[32], *dst = buf;
462	hrtime_t time = *((uint64_t *)addr);
463	time_t sec = (time_t)(time / NANOSEC);
464	int i;
465
466	/*
467	 * ctime(3C) returns a string of the form "Dec  3 17:20:00 1973\n\0".
468	 * Below, we turn this into the canonical adb/mdb /[yY] format,
469	 * "1973 Dec  3 17:20:00".
470	 */
471#ifdef illumos
472	(void) ctime_r(&sec, src, sizeof (src));
473#else
474	(void) ctime_r(&sec, src);
475#endif
476
477	/*
478	 * Place the 4-digit year at the head of the string...
479	 */
480	for (i = 20; i < 24; i++)
481		*dst++ = src[i];
482
483	/*
484	 * ...and follow it with the remainder (month, day, hh:mm:ss).
485	 */
486	for (i = 3; i < 19; i++)
487		*dst++ = src[i];
488
489	*dst = '\0';
490	return (dt_printf(dtp, fp, format, buf));
491}
492
493/*
494 * This prints the time in RFC 822 standard form.  This is useful for emitting
495 * notions of time that are consumed by standard tools (e.g., as part of an
496 * RSS feed).
497 */
498/*ARGSUSED*/
499static int
500pfprint_time822(dtrace_hdl_t *dtp, FILE *fp, const char *format,
501    const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
502{
503	hrtime_t time = *((uint64_t *)addr);
504	time_t sec = (time_t)(time / NANOSEC);
505	struct tm tm;
506	char buf[64];
507
508	(void) localtime_r(&sec, &tm);
509	(void) strftime(buf, sizeof (buf), "%a, %d %b %G %T %Z", &tm);
510	return (dt_printf(dtp, fp, format, buf));
511}
512
513/*ARGSUSED*/
514static int
515pfprint_port(dtrace_hdl_t *dtp, FILE *fp, const char *format,
516    const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
517{
518	uint16_t port = htons(*((uint16_t *)addr));
519	char buf[256];
520	struct servent *sv, res;
521
522#ifdef illumos
523	if ((sv = getservbyport_r(port, NULL, &res, buf, sizeof (buf))) != NULL)
524#else
525	if (getservbyport_r(port, NULL, &res, buf, sizeof (buf), &sv) > 0)
526#endif
527		return (dt_printf(dtp, fp, format, sv->s_name));
528
529	(void) snprintf(buf, sizeof (buf), "%d", *((uint16_t *)addr));
530	return (dt_printf(dtp, fp, format, buf));
531}
532
533/*ARGSUSED*/
534static int
535pfprint_inetaddr(dtrace_hdl_t *dtp, FILE *fp, const char *format,
536    const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
537{
538	char *s = alloca(size + 1);
539	struct hostent *host, res;
540	char inetaddr[NS_IN6ADDRSZ];
541	char buf[1024];
542	int e;
543
544	bcopy(addr, s, size);
545	s[size] = '\0';
546
547	if (strchr(s, ':') == NULL && inet_pton(AF_INET, s, inetaddr) != -1) {
548#ifdef illumos
549		if ((host = gethostbyaddr_r(inetaddr, NS_INADDRSZ,
550		    AF_INET, &res, buf, sizeof (buf), &e)) != NULL)
551#else
552		if (gethostbyaddr_r(inetaddr, NS_INADDRSZ,
553		    AF_INET, &res, buf, sizeof (buf), &host, &e) > 0)
554#endif
555			return (dt_printf(dtp, fp, format, host->h_name));
556	} else if (inet_pton(AF_INET6, s, inetaddr) != -1) {
557		if ((host = getipnodebyaddr(inetaddr, NS_IN6ADDRSZ,
558		    AF_INET6, &e)) != NULL)
559			return (dt_printf(dtp, fp, format, host->h_name));
560	}
561
562	return (dt_printf(dtp, fp, format, s));
563}
564
565/*ARGSUSED*/
566static int
567pfprint_cstr(dtrace_hdl_t *dtp, FILE *fp, const char *format,
568    const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
569{
570	char *s = alloca(size + 1);
571
572	bcopy(addr, s, size);
573	s[size] = '\0';
574	return (dt_printf(dtp, fp, format, s));
575}
576
577/*ARGSUSED*/
578static int
579pfprint_wstr(dtrace_hdl_t *dtp, FILE *fp, const char *format,
580    const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
581{
582	wchar_t *ws = alloca(size + sizeof (wchar_t));
583
584	bcopy(addr, ws, size);
585	ws[size / sizeof (wchar_t)] = L'\0';
586	return (dt_printf(dtp, fp, format, ws));
587}
588
589/*ARGSUSED*/
590static int
591pfprint_estr(dtrace_hdl_t *dtp, FILE *fp, const char *format,
592    const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
593{
594	char *s;
595	int n;
596
597	if ((s = strchr2esc(addr, size)) == NULL)
598		return (dt_set_errno(dtp, EDT_NOMEM));
599
600	n = dt_printf(dtp, fp, format, s);
601	free(s);
602	return (n);
603}
604
605static int
606pfprint_echr(dtrace_hdl_t *dtp, FILE *fp, const char *format,
607    const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
608{
609	char c;
610
611	switch (size) {
612	case sizeof (int8_t):
613		c = *(int8_t *)addr;
614		break;
615	case sizeof (int16_t):
616		c = *(int16_t *)addr;
617		break;
618	case sizeof (int32_t):
619		c = *(int32_t *)addr;
620		break;
621	default:
622		return (dt_set_errno(dtp, EDT_DMISMATCH));
623	}
624
625	return (pfprint_estr(dtp, fp, format, pfd, &c, 1, normal));
626}
627
628/*ARGSUSED*/
629static int
630pfprint_pct(dtrace_hdl_t *dtp, FILE *fp, const char *format,
631    const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
632{
633	return (dt_printf(dtp, fp, "%%"));
634}
635
636static const char pfproto_xint[] = "char, short, int, long, or long long";
637static const char pfproto_csi[] = "char, short, or int";
638static const char pfproto_fp[] = "float, double, or long double";
639static const char pfproto_addr[] = "pointer or integer";
640static const char pfproto_uaddr[] =
641	"pointer or integer (with -p/-c) or _usymaddr (without -p/-c)";
642static const char pfproto_cstr[] = "char [] or string (or use stringof)";
643static const char pfproto_wstr[] = "wchar_t []";
644
645/*
646 * Printf format conversion dictionary.  This table should match the set of
647 * conversions offered by printf(3C), as well as some additional extensions.
648 * The second parameter is an ASCII string which is either an actual type
649 * name we should look up (if pfcheck_type is specified), or just a descriptive
650 * string of the types expected for use in error messages.
651 */
652static const dt_pfconv_t _dtrace_conversions[] = {
653{ "a", "s", pfproto_addr, pfcheck_kaddr, pfprint_addr },
654{ "A", "s", pfproto_uaddr, pfcheck_uaddr, pfprint_uaddr },
655{ "c", "c", pfproto_csi, pfcheck_csi, pfprint_sint },
656{ "C", "s", pfproto_csi, pfcheck_csi, pfprint_echr },
657{ "d", "d", pfproto_xint, pfcheck_dint, pfprint_dint },
658{ "e", "e", pfproto_fp, pfcheck_fp, pfprint_fp },
659{ "E", "E", pfproto_fp, pfcheck_fp, pfprint_fp },
660{ "f", "f", pfproto_fp, pfcheck_fp, pfprint_fp },
661{ "g", "g", pfproto_fp, pfcheck_fp, pfprint_fp },
662{ "G", "G", pfproto_fp, pfcheck_fp, pfprint_fp },
663{ "hd", "d", "short", pfcheck_type, pfprint_sint },
664{ "hi", "i", "short", pfcheck_type, pfprint_sint },
665{ "ho", "o", "unsigned short", pfcheck_type, pfprint_uint },
666{ "hu", "u", "unsigned short", pfcheck_type, pfprint_uint },
667{ "hx", "x", "short", pfcheck_xshort, pfprint_uint },
668{ "hX", "X", "short", pfcheck_xshort, pfprint_uint },
669{ "i", "i", pfproto_xint, pfcheck_xint, pfprint_sint },
670{ "I", "s", pfproto_cstr, pfcheck_str, pfprint_inetaddr },
671{ "k", "s", "stack", pfcheck_stack, pfprint_stack },
672{ "lc", "lc", "int", pfcheck_type, pfprint_sint }, /* a.k.a. wint_t */
673{ "ld",	"d", "long", pfcheck_type, pfprint_sint },
674{ "li",	"i", "long", pfcheck_type, pfprint_sint },
675{ "lo",	"o", "unsigned long", pfcheck_type, pfprint_uint },
676{ "lu", "u", "unsigned long", pfcheck_type, pfprint_uint },
677{ "ls",	"ls", pfproto_wstr, pfcheck_wstr, pfprint_wstr },
678{ "lx",	"x", "long", pfcheck_xlong, pfprint_uint },
679{ "lX",	"X", "long", pfcheck_xlong, pfprint_uint },
680{ "lld", "d", "long long", pfcheck_type, pfprint_sint },
681{ "lli", "i", "long long", pfcheck_type, pfprint_sint },
682{ "llo", "o", "unsigned long long", pfcheck_type, pfprint_uint },
683{ "llu", "u", "unsigned long long", pfcheck_type, pfprint_uint },
684{ "llx", "x", "long long", pfcheck_xlonglong, pfprint_uint },
685{ "llX", "X", "long long", pfcheck_xlonglong, pfprint_uint },
686{ "Le",	"e", "long double", pfcheck_type, pfprint_fp },
687{ "LE",	"E", "long double", pfcheck_type, pfprint_fp },
688{ "Lf",	"f", "long double", pfcheck_type, pfprint_fp },
689{ "Lg",	"g", "long double", pfcheck_type, pfprint_fp },
690{ "LG",	"G", "long double", pfcheck_type, pfprint_fp },
691{ "o", "o", pfproto_xint, pfcheck_xint, pfprint_uint },
692{ "p", "x", pfproto_addr, pfcheck_addr, pfprint_uint },
693{ "P", "s", "uint16_t", pfcheck_type, pfprint_port },
694{ "s", "s", "char [] or string (or use stringof)", pfcheck_str, pfprint_cstr },
695{ "S", "s", pfproto_cstr, pfcheck_str, pfprint_estr },
696{ "T", "s", "int64_t", pfcheck_time, pfprint_time822 },
697{ "u", "u", pfproto_xint, pfcheck_xint, pfprint_uint },
698#ifdef illumos
699{ "wc",	"wc", "int", pfcheck_type, pfprint_sint }, /* a.k.a. wchar_t */
700{ "ws", "ws", pfproto_wstr, pfcheck_wstr, pfprint_wstr },
701#else
702{ "wc", "lc", "int", pfcheck_type, pfprint_sint }, /* a.k.a. wchar_t */
703{ "ws", "ls", pfproto_wstr, pfcheck_wstr, pfprint_wstr },
704#endif
705{ "x", "x", pfproto_xint, pfcheck_xint, pfprint_uint },
706{ "X", "X", pfproto_xint, pfcheck_xint, pfprint_uint },
707{ "Y", "s", "int64_t", pfcheck_time, pfprint_time },
708{ "%", "%", "void", pfcheck_type, pfprint_pct },
709{ NULL, NULL, NULL, NULL, NULL }
710};
711
712int
713dt_pfdict_create(dtrace_hdl_t *dtp)
714{
715	uint_t n = _dtrace_strbuckets;
716	const dt_pfconv_t *pfd;
717	dt_pfdict_t *pdi;
718
719	if ((pdi = malloc(sizeof (dt_pfdict_t))) == NULL ||
720	    (pdi->pdi_buckets = malloc(sizeof (dt_pfconv_t *) * n)) == NULL) {
721		free(pdi);
722		return (dt_set_errno(dtp, EDT_NOMEM));
723	}
724
725	dtp->dt_pfdict = pdi;
726	bzero(pdi->pdi_buckets, sizeof (dt_pfconv_t *) * n);
727	pdi->pdi_nbuckets = n;
728
729	for (pfd = _dtrace_conversions; pfd->pfc_name != NULL; pfd++) {
730		dtrace_typeinfo_t dtt;
731		dt_pfconv_t *pfc;
732		uint_t h;
733
734		if ((pfc = malloc(sizeof (dt_pfconv_t))) == NULL) {
735			dt_pfdict_destroy(dtp);
736			return (dt_set_errno(dtp, EDT_NOMEM));
737		}
738
739		bcopy(pfd, pfc, sizeof (dt_pfconv_t));
740		h = dt_strtab_hash(pfc->pfc_name, NULL) % n;
741		pfc->pfc_next = pdi->pdi_buckets[h];
742		pdi->pdi_buckets[h] = pfc;
743
744		dtt.dtt_ctfp = NULL;
745		dtt.dtt_type = CTF_ERR;
746
747		/*
748		 * The "D" container or its parent must contain a definition of
749		 * any type referenced by a printf conversion.  If none can be
750		 * found, we fail to initialize the printf dictionary.
751		 */
752		if (pfc->pfc_check == &pfcheck_type && dtrace_lookup_by_type(
753		    dtp, DTRACE_OBJ_DDEFS, pfc->pfc_tstr, &dtt) != 0) {
754			dt_pfdict_destroy(dtp);
755			return (dt_set_errno(dtp, EDT_NOCONV));
756		}
757
758		pfc->pfc_dctfp = dtt.dtt_ctfp;
759		pfc->pfc_dtype = dtt.dtt_type;
760
761		/*
762		 * The "C" container may contain an alternate definition of an
763		 * explicit conversion type.  If it does, use it; otherwise
764		 * just set pfc_ctype to pfc_dtype so it is always valid.
765		 */
766		if (pfc->pfc_check == &pfcheck_type && dtrace_lookup_by_type(
767		    dtp, DTRACE_OBJ_CDEFS, pfc->pfc_tstr, &dtt) == 0) {
768			pfc->pfc_cctfp = dtt.dtt_ctfp;
769			pfc->pfc_ctype = dtt.dtt_type;
770		} else {
771			pfc->pfc_cctfp = pfc->pfc_dctfp;
772			pfc->pfc_ctype = pfc->pfc_dtype;
773		}
774
775		if (pfc->pfc_check == NULL || pfc->pfc_print == NULL ||
776		    pfc->pfc_ofmt == NULL || pfc->pfc_tstr == NULL) {
777			dt_pfdict_destroy(dtp);
778			return (dt_set_errno(dtp, EDT_BADCONV));
779		}
780
781		dt_dprintf("loaded printf conversion %%%s\n", pfc->pfc_name);
782	}
783
784	return (0);
785}
786
787void
788dt_pfdict_destroy(dtrace_hdl_t *dtp)
789{
790	dt_pfdict_t *pdi = dtp->dt_pfdict;
791	dt_pfconv_t *pfc, *nfc;
792	uint_t i;
793
794	if (pdi == NULL)
795		return;
796
797	for (i = 0; i < pdi->pdi_nbuckets; i++) {
798		for (pfc = pdi->pdi_buckets[i]; pfc != NULL; pfc = nfc) {
799			nfc = pfc->pfc_next;
800			free(pfc);
801		}
802	}
803
804	free(pdi->pdi_buckets);
805	free(pdi);
806	dtp->dt_pfdict = NULL;
807}
808
809static const dt_pfconv_t *
810dt_pfdict_lookup(dtrace_hdl_t *dtp, const char *name)
811{
812	dt_pfdict_t *pdi = dtp->dt_pfdict;
813	uint_t h = dt_strtab_hash(name, NULL) % pdi->pdi_nbuckets;
814	const dt_pfconv_t *pfc;
815
816	for (pfc = pdi->pdi_buckets[h]; pfc != NULL; pfc = pfc->pfc_next) {
817		if (strcmp(pfc->pfc_name, name) == 0)
818			break;
819	}
820
821	return (pfc);
822}
823
824static dt_pfargv_t *
825dt_printf_error(dtrace_hdl_t *dtp, int err)
826{
827	if (yypcb != NULL)
828		longjmp(yypcb->pcb_jmpbuf, err);
829
830	(void) dt_set_errno(dtp, err);
831	return (NULL);
832}
833
834dt_pfargv_t *
835dt_printf_create(dtrace_hdl_t *dtp, const char *s)
836{
837	dt_pfargd_t *pfd, *nfd = NULL;
838	dt_pfargv_t *pfv;
839	const char *p, *q;
840	char *format;
841
842	if ((pfv = malloc(sizeof (dt_pfargv_t))) == NULL ||
843	    (format = strdup(s)) == NULL) {
844		free(pfv);
845		return (dt_printf_error(dtp, EDT_NOMEM));
846	}
847
848	pfv->pfv_format = format;
849	pfv->pfv_argv = NULL;
850	pfv->pfv_argc = 0;
851	pfv->pfv_flags = 0;
852	pfv->pfv_dtp = dtp;
853
854	for (q = format; (p = strchr(q, '%')) != NULL; q = *p ? p + 1 : p) {
855		uint_t namelen = 0;
856		int digits = 0;
857		int dot = 0;
858
859		char name[8];
860		char c;
861		int n;
862
863		if ((pfd = malloc(sizeof (dt_pfargd_t))) == NULL) {
864			dt_printf_destroy(pfv);
865			return (dt_printf_error(dtp, EDT_NOMEM));
866		}
867
868		if (pfv->pfv_argv != NULL)
869			nfd->pfd_next = pfd;
870		else
871			pfv->pfv_argv = pfd;
872
873		bzero(pfd, sizeof (dt_pfargd_t));
874		pfv->pfv_argc++;
875		nfd = pfd;
876
877		if (p > q) {
878			pfd->pfd_preflen = (size_t)(p - q);
879			pfd->pfd_prefix = q;
880		}
881
882		fmt_switch:
883		switch (c = *++p) {
884		case '0': case '1': case '2': case '3': case '4':
885		case '5': case '6': case '7': case '8': case '9':
886			if (dot == 0 && digits == 0 && c == '0') {
887				pfd->pfd_flags |= DT_PFCONV_ZPAD;
888				pfd->pfd_flags &= ~DT_PFCONV_LEFT;
889				goto fmt_switch;
890			}
891
892			for (n = 0; isdigit(c); c = *++p)
893				n = n * 10 + c - '0';
894
895			if (dot)
896				pfd->pfd_prec = n;
897			else
898				pfd->pfd_width = n;
899
900			p--;
901			digits++;
902			goto fmt_switch;
903
904		case '#':
905			pfd->pfd_flags |= DT_PFCONV_ALT;
906			goto fmt_switch;
907
908		case '*':
909			n = dot ? DT_PFCONV_DYNPREC : DT_PFCONV_DYNWIDTH;
910
911			if (pfd->pfd_flags & n) {
912				yywarn("format conversion #%u has more than "
913				    "one '*' specified for the output %s\n",
914				    pfv->pfv_argc, n ? "precision" : "width");
915
916				dt_printf_destroy(pfv);
917				return (dt_printf_error(dtp, EDT_COMPILER));
918			}
919
920			pfd->pfd_flags |= n;
921			goto fmt_switch;
922
923		case '+':
924			pfd->pfd_flags |= DT_PFCONV_SPOS;
925			goto fmt_switch;
926
927		case '-':
928			pfd->pfd_flags |= DT_PFCONV_LEFT;
929			pfd->pfd_flags &= ~DT_PFCONV_ZPAD;
930			goto fmt_switch;
931
932		case '.':
933			if (dot++ != 0) {
934				yywarn("format conversion #%u has more than "
935				    "one '.' specified\n", pfv->pfv_argc);
936
937				dt_printf_destroy(pfv);
938				return (dt_printf_error(dtp, EDT_COMPILER));
939			}
940			digits = 0;
941			goto fmt_switch;
942
943		case '?':
944			if (dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_LP64)
945				pfd->pfd_width = 16;
946			else
947				pfd->pfd_width = 8;
948			goto fmt_switch;
949
950		case '@':
951			pfd->pfd_flags |= DT_PFCONV_AGG;
952			goto fmt_switch;
953
954		case '\'':
955			pfd->pfd_flags |= DT_PFCONV_GROUP;
956			goto fmt_switch;
957
958		case ' ':
959			pfd->pfd_flags |= DT_PFCONV_SPACE;
960			goto fmt_switch;
961
962		case '$':
963			yywarn("format conversion #%u uses unsupported "
964			    "positional format (%%n$)\n", pfv->pfv_argc);
965
966			dt_printf_destroy(pfv);
967			return (dt_printf_error(dtp, EDT_COMPILER));
968
969		case '%':
970			if (p[-1] == '%')
971				goto default_lbl; /* if %% then use "%" conv */
972
973			yywarn("format conversion #%u cannot be combined "
974			    "with other format flags: %%%%\n", pfv->pfv_argc);
975
976			dt_printf_destroy(pfv);
977			return (dt_printf_error(dtp, EDT_COMPILER));
978
979		case '\0':
980			yywarn("format conversion #%u name expected before "
981			    "end of format string\n", pfv->pfv_argc);
982
983			dt_printf_destroy(pfv);
984			return (dt_printf_error(dtp, EDT_COMPILER));
985
986		case 'h':
987		case 'l':
988		case 'L':
989		case 'w':
990			if (namelen < sizeof (name) - 2)
991				name[namelen++] = c;
992			goto fmt_switch;
993
994		default_lbl:
995		default:
996			name[namelen++] = c;
997			name[namelen] = '\0';
998		}
999
1000		pfd->pfd_conv = dt_pfdict_lookup(dtp, name);
1001
1002		if (pfd->pfd_conv == NULL) {
1003			yywarn("format conversion #%u is undefined: %%%s\n",
1004			    pfv->pfv_argc, name);
1005			dt_printf_destroy(pfv);
1006			return (dt_printf_error(dtp, EDT_COMPILER));
1007		}
1008	}
1009
1010	if (*q != '\0' || *format == '\0') {
1011		if ((pfd = malloc(sizeof (dt_pfargd_t))) == NULL) {
1012			dt_printf_destroy(pfv);
1013			return (dt_printf_error(dtp, EDT_NOMEM));
1014		}
1015
1016		if (pfv->pfv_argv != NULL)
1017			nfd->pfd_next = pfd;
1018		else
1019			pfv->pfv_argv = pfd;
1020
1021		bzero(pfd, sizeof (dt_pfargd_t));
1022		pfv->pfv_argc++;
1023
1024		pfd->pfd_prefix = q;
1025		pfd->pfd_preflen = strlen(q);
1026	}
1027
1028	return (pfv);
1029}
1030
1031void
1032dt_printf_destroy(dt_pfargv_t *pfv)
1033{
1034	dt_pfargd_t *pfd, *nfd;
1035
1036	for (pfd = pfv->pfv_argv; pfd != NULL; pfd = nfd) {
1037		nfd = pfd->pfd_next;
1038		free(pfd);
1039	}
1040
1041	free(pfv->pfv_format);
1042	free(pfv);
1043}
1044
1045void
1046dt_printf_validate(dt_pfargv_t *pfv, uint_t flags,
1047    dt_ident_t *idp, int foff, dtrace_actkind_t kind, dt_node_t *dnp)
1048{
1049	dt_pfargd_t *pfd = pfv->pfv_argv;
1050	const char *func = idp->di_name;
1051
1052	char n[DT_TYPE_NAMELEN];
1053	dtrace_typeinfo_t dtt;
1054	const char *aggtype;
1055	dt_node_t aggnode;
1056	int i, j;
1057
1058	if (pfv->pfv_format[0] == '\0') {
1059		xyerror(D_PRINTF_FMT_EMPTY,
1060		    "%s( ) format string is empty\n", func);
1061	}
1062
1063	pfv->pfv_flags = flags;
1064
1065	/*
1066	 * We fake up a parse node representing the type that can be used with
1067	 * an aggregation result conversion, which -- for all but count() --
1068	 * is a signed quantity.
1069	 */
1070	if (kind != DTRACEAGG_COUNT)
1071		aggtype = "int64_t";
1072	else
1073		aggtype = "uint64_t";
1074
1075	if (dt_type_lookup(aggtype, &dtt) != 0)
1076		xyerror(D_TYPE_ERR, "failed to lookup agg type %s\n", aggtype);
1077
1078	bzero(&aggnode, sizeof (aggnode));
1079	dt_node_type_assign(&aggnode, dtt.dtt_ctfp, dtt.dtt_type, B_FALSE);
1080
1081	for (i = 0, j = 0; i < pfv->pfv_argc; i++, pfd = pfd->pfd_next) {
1082		const dt_pfconv_t *pfc = pfd->pfd_conv;
1083		const char *dyns[2];
1084		int dync = 0;
1085
1086		char vname[64];
1087		dt_node_t *vnp;
1088
1089		if (pfc == NULL)
1090			continue; /* no checking if argd is just a prefix */
1091
1092		if (pfc->pfc_print == &pfprint_pct) {
1093			(void) strcat(pfd->pfd_fmt, pfc->pfc_ofmt);
1094			continue;
1095		}
1096
1097		if (pfd->pfd_flags & DT_PFCONV_DYNPREC)
1098			dyns[dync++] = ".*";
1099		if (pfd->pfd_flags & DT_PFCONV_DYNWIDTH)
1100			dyns[dync++] = "*";
1101
1102		for (; dync != 0; dync--) {
1103			if (dnp == NULL) {
1104				xyerror(D_PRINTF_DYN_PROTO,
1105				    "%s( ) prototype mismatch: conversion "
1106				    "#%d (%%%s) is missing a corresponding "
1107				    "\"%s\" argument\n", func, i + 1,
1108				    pfc->pfc_name, dyns[dync - 1]);
1109			}
1110
1111			if (dt_node_is_integer(dnp) == 0) {
1112				xyerror(D_PRINTF_DYN_TYPE,
1113				    "%s( ) argument #%d is incompatible "
1114				    "with conversion #%d prototype:\n"
1115				    "\tconversion: %% %s %s\n"
1116				    "\t prototype: int\n\t  argument: %s\n",
1117				    func, j + foff + 1, i + 1,
1118				    dyns[dync - 1], pfc->pfc_name,
1119				    dt_node_type_name(dnp, n, sizeof (n)));
1120			}
1121
1122			dnp = dnp->dn_list;
1123			j++;
1124		}
1125
1126		/*
1127		 * If this conversion is consuming the aggregation data, set
1128		 * the value node pointer (vnp) to a fake node based on the
1129		 * aggregating function result type.  Otherwise assign vnp to
1130		 * the next parse node in the argument list, if there is one.
1131		 */
1132		if (pfd->pfd_flags & DT_PFCONV_AGG) {
1133			if (!(flags & DT_PRINTF_AGGREGATION)) {
1134				xyerror(D_PRINTF_AGG_CONV,
1135				    "%%@ conversion requires an aggregation"
1136				    " and is not for use with %s( )\n", func);
1137			}
1138			(void) strlcpy(vname, "aggregating action",
1139			    sizeof (vname));
1140			vnp = &aggnode;
1141		} else if (dnp == NULL) {
1142			xyerror(D_PRINTF_ARG_PROTO,
1143			    "%s( ) prototype mismatch: conversion #%d (%%"
1144			    "%s) is missing a corresponding value argument\n",
1145			    func, i + 1, pfc->pfc_name);
1146		} else {
1147			(void) snprintf(vname, sizeof (vname),
1148			    "argument #%d", j + foff + 1);
1149			vnp = dnp;
1150			dnp = dnp->dn_list;
1151			j++;
1152		}
1153
1154		/*
1155		 * Fill in the proposed final format string by prepending any
1156		 * size-related prefixes to the pfconv's format string.  The
1157		 * pfc_check() function below may optionally modify the format
1158		 * as part of validating the type of the input argument.
1159		 */
1160		if (pfc->pfc_print == &pfprint_sint ||
1161		    pfc->pfc_print == &pfprint_uint ||
1162		    pfc->pfc_print == &pfprint_dint) {
1163			if (dt_node_type_size(vnp) == sizeof (uint64_t))
1164				(void) strcpy(pfd->pfd_fmt, "ll");
1165		} else if (pfc->pfc_print == &pfprint_fp) {
1166			if (dt_node_type_size(vnp) == sizeof (long double))
1167				(void) strcpy(pfd->pfd_fmt, "L");
1168		}
1169
1170		(void) strcat(pfd->pfd_fmt, pfc->pfc_ofmt);
1171
1172		/*
1173		 * Validate the format conversion against the value node type.
1174		 * If the conversion is good, create the descriptor format
1175		 * string by concatenating together any required printf(3C)
1176		 * size prefixes with the conversion's native format string.
1177		 */
1178		if (pfc->pfc_check(pfv, pfd, vnp) == 0) {
1179			xyerror(D_PRINTF_ARG_TYPE,
1180			    "%s( ) %s is incompatible with "
1181			    "conversion #%d prototype:\n\tconversion: %%%s\n"
1182			    "\t prototype: %s\n\t  argument: %s\n", func,
1183			    vname, i + 1, pfc->pfc_name, pfc->pfc_tstr,
1184			    dt_node_type_name(vnp, n, sizeof (n)));
1185		}
1186	}
1187
1188	if ((flags & DT_PRINTF_EXACTLEN) && dnp != NULL) {
1189		xyerror(D_PRINTF_ARG_EXTRA,
1190		    "%s( ) prototype mismatch: only %d arguments "
1191		    "required by this format string\n", func, j);
1192	}
1193}
1194
1195void
1196dt_printa_validate(dt_node_t *lhs, dt_node_t *rhs)
1197{
1198	dt_ident_t *lid, *rid;
1199	dt_node_t *lproto, *rproto;
1200	int largc, rargc, argn;
1201	char n1[DT_TYPE_NAMELEN];
1202	char n2[DT_TYPE_NAMELEN];
1203
1204	assert(lhs->dn_kind == DT_NODE_AGG);
1205	assert(rhs->dn_kind == DT_NODE_AGG);
1206
1207	lid = lhs->dn_ident;
1208	rid = rhs->dn_ident;
1209
1210	lproto = ((dt_idsig_t *)lid->di_data)->dis_args;
1211	rproto = ((dt_idsig_t *)rid->di_data)->dis_args;
1212
1213	/*
1214	 * First, get an argument count on each side.  These must match.
1215	 */
1216	for (largc = 0; lproto != NULL; lproto = lproto->dn_list)
1217		largc++;
1218
1219	for (rargc = 0; rproto != NULL; rproto = rproto->dn_list)
1220		rargc++;
1221
1222	if (largc != rargc) {
1223		xyerror(D_PRINTA_AGGKEY, "printa( ): @%s and @%s do not have "
1224		    "matching key signatures: @%s has %d key%s, @%s has %d "
1225		    "key%s", lid->di_name, rid->di_name,
1226		    lid->di_name, largc, largc == 1 ? "" : "s",
1227		    rid->di_name, rargc, rargc == 1 ? "" : "s");
1228	}
1229
1230	/*
1231	 * Now iterate over the keys to verify that each type matches.
1232	 */
1233	lproto = ((dt_idsig_t *)lid->di_data)->dis_args;
1234	rproto = ((dt_idsig_t *)rid->di_data)->dis_args;
1235
1236	for (argn = 1; lproto != NULL; argn++, lproto = lproto->dn_list,
1237	    rproto = rproto->dn_list) {
1238		assert(rproto != NULL);
1239
1240		if (dt_node_is_argcompat(lproto, rproto))
1241			continue;
1242
1243		xyerror(D_PRINTA_AGGPROTO, "printa( ): @%s[ ] key #%d is "
1244		    "incompatible with @%s:\n%9s key #%d: %s\n"
1245		    "%9s key #%d: %s\n",
1246		    rid->di_name, argn, lid->di_name, lid->di_name, argn,
1247		    dt_node_type_name(lproto, n1, sizeof (n1)), rid->di_name,
1248		    argn, dt_node_type_name(rproto, n2, sizeof (n2)));
1249	}
1250}
1251
1252static int
1253dt_printf_getint(dtrace_hdl_t *dtp, const dtrace_recdesc_t *recp,
1254    uint_t nrecs, const void *buf, size_t len, int *ip)
1255{
1256	uintptr_t addr;
1257
1258	if (nrecs == 0)
1259		return (dt_set_errno(dtp, EDT_DMISMATCH));
1260
1261	addr = (uintptr_t)buf + recp->dtrd_offset;
1262
1263	if (addr + sizeof (int) > (uintptr_t)buf + len)
1264		return (dt_set_errno(dtp, EDT_DOFFSET));
1265
1266	if (addr & (recp->dtrd_alignment - 1))
1267		return (dt_set_errno(dtp, EDT_DALIGN));
1268
1269	switch (recp->dtrd_size) {
1270	case sizeof (int8_t):
1271		*ip = (int)*((int8_t *)addr);
1272		break;
1273	case sizeof (int16_t):
1274		*ip = (int)*((int16_t *)addr);
1275		break;
1276	case sizeof (int32_t):
1277		*ip = (int)*((int32_t *)addr);
1278		break;
1279	case sizeof (int64_t):
1280		*ip = (int)*((int64_t *)addr);
1281		break;
1282	default:
1283		return (dt_set_errno(dtp, EDT_DMISMATCH));
1284	}
1285
1286	return (0);
1287}
1288
1289/*ARGSUSED*/
1290static int
1291pfprint_average(dtrace_hdl_t *dtp, FILE *fp, const char *format,
1292    const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
1293{
1294	const uint64_t *data = addr;
1295
1296	if (size != sizeof (uint64_t) * 2)
1297		return (dt_set_errno(dtp, EDT_DMISMATCH));
1298
1299	return (dt_printf(dtp, fp, format,
1300	    data[0] ? data[1] / normal / data[0] : 0));
1301}
1302
1303/*ARGSUSED*/
1304static int
1305pfprint_stddev(dtrace_hdl_t *dtp, FILE *fp, const char *format,
1306    const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
1307{
1308	const uint64_t *data = addr;
1309
1310	if (size != sizeof (uint64_t) * 4)
1311		return (dt_set_errno(dtp, EDT_DMISMATCH));
1312
1313	return (dt_printf(dtp, fp, format,
1314	    dt_stddev((uint64_t *)data, normal)));
1315}
1316
1317/*ARGSUSED*/
1318static int
1319pfprint_quantize(dtrace_hdl_t *dtp, FILE *fp, const char *format,
1320    const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
1321{
1322	return (dt_print_quantize(dtp, fp, addr, size, normal));
1323}
1324
1325/*ARGSUSED*/
1326static int
1327pfprint_lquantize(dtrace_hdl_t *dtp, FILE *fp, const char *format,
1328    const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
1329{
1330	return (dt_print_lquantize(dtp, fp, addr, size, normal));
1331}
1332
1333/*ARGSUSED*/
1334static int
1335pfprint_llquantize(dtrace_hdl_t *dtp, FILE *fp, const char *format,
1336    const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
1337{
1338	return (dt_print_llquantize(dtp, fp, addr, size, normal));
1339}
1340
1341static int
1342dt_printf_format(dtrace_hdl_t *dtp, FILE *fp, const dt_pfargv_t *pfv,
1343    const dtrace_recdesc_t *recs, uint_t nrecs, const void *buf,
1344    size_t len, const dtrace_aggdata_t **aggsdata, int naggvars)
1345{
1346	dt_pfargd_t *pfd = pfv->pfv_argv;
1347	const dtrace_recdesc_t *recp = recs;
1348	const dtrace_aggdata_t *aggdata;
1349	dtrace_aggdesc_t *agg;
1350	caddr_t lim = (caddr_t)buf + len, limit;
1351	char format[64] = "%";
1352	size_t ret;
1353	int i, aggrec, curagg = -1;
1354	uint64_t normal;
1355
1356	/*
1357	 * If we are formatting an aggregation, set 'aggrec' to the index of
1358	 * the final record description (the aggregation result) so we can use
1359	 * this record index with any conversion where DT_PFCONV_AGG is set.
1360	 * (The actual aggregation used will vary as we increment through the
1361	 * aggregation variables that we have been passed.)  Finally, we
1362	 * decrement nrecs to prevent this record from being used with any
1363	 * other conversion.
1364	 */
1365	if (pfv->pfv_flags & DT_PRINTF_AGGREGATION) {
1366		assert(aggsdata != NULL);
1367		assert(naggvars > 0);
1368
1369		if (nrecs == 0)
1370			return (dt_set_errno(dtp, EDT_DMISMATCH));
1371
1372		curagg = naggvars > 1 ? 1 : 0;
1373		aggdata = aggsdata[0];
1374		aggrec = aggdata->dtada_desc->dtagd_nrecs - 1;
1375		nrecs--;
1376	}
1377
1378	for (i = 0; i < pfv->pfv_argc; i++, pfd = pfd->pfd_next) {
1379		const dt_pfconv_t *pfc = pfd->pfd_conv;
1380		int width = pfd->pfd_width;
1381		int prec = pfd->pfd_prec;
1382		int rval;
1383
1384		const char *start;
1385		char *f = format + 1; /* skip initial '%' */
1386		size_t fmtsz = sizeof(format) - 1;
1387		const dtrace_recdesc_t *rec;
1388		dt_pfprint_f *func;
1389		caddr_t addr;
1390		size_t size;
1391		uint32_t flags;
1392
1393		if (pfd->pfd_preflen != 0) {
1394			char *tmp = alloca(pfd->pfd_preflen + 1);
1395
1396			bcopy(pfd->pfd_prefix, tmp, pfd->pfd_preflen);
1397			tmp[pfd->pfd_preflen] = '\0';
1398
1399			if ((rval = dt_printf(dtp, fp, tmp)) < 0)
1400				return (rval);
1401
1402			if (pfv->pfv_flags & DT_PRINTF_AGGREGATION) {
1403				/*
1404				 * For printa(), we flush the buffer after each
1405				 * prefix, setting the flags to indicate that
1406				 * this is part of the printa() format string.
1407				 */
1408				flags = DTRACE_BUFDATA_AGGFORMAT;
1409
1410				if (pfc == NULL && i == pfv->pfv_argc - 1)
1411					flags |= DTRACE_BUFDATA_AGGLAST;
1412
1413				if (dt_buffered_flush(dtp, NULL, NULL,
1414				    aggdata, flags) < 0)
1415					return (-1);
1416			}
1417		}
1418
1419		if (pfc == NULL) {
1420			if (pfv->pfv_argc == 1)
1421				return (nrecs != 0);
1422			continue;
1423		}
1424
1425		/*
1426		 * If the conversion is %%, just invoke the print callback
1427		 * with no data record and continue; it consumes no record.
1428		 */
1429		if (pfc->pfc_print == &pfprint_pct) {
1430			if (pfc->pfc_print(dtp, fp, NULL, pfd, NULL, 0, 1) >= 0)
1431				continue;
1432			return (-1); /* errno is set for us */
1433		}
1434
1435		if (pfd->pfd_flags & DT_PFCONV_DYNWIDTH) {
1436			if (dt_printf_getint(dtp, recp++, nrecs--, buf,
1437			    len, &width) == -1)
1438				return (-1); /* errno is set for us */
1439			pfd->pfd_dynwidth = width;
1440		} else {
1441			pfd->pfd_dynwidth = 0;
1442		}
1443
1444		if ((pfd->pfd_flags & DT_PFCONV_DYNPREC) && dt_printf_getint(
1445		    dtp, recp++, nrecs--, buf, len, &prec) == -1)
1446			return (-1); /* errno is set for us */
1447
1448		if (pfd->pfd_flags & DT_PFCONV_AGG) {
1449			/*
1450			 * This should be impossible -- the compiler shouldn't
1451			 * create a DT_PFCONV_AGG conversion without an
1452			 * aggregation present.  Still, we'd rather fail
1453			 * gracefully than blow up...
1454			 */
1455			if (aggsdata == NULL)
1456				return (dt_set_errno(dtp, EDT_DMISMATCH));
1457
1458			aggdata = aggsdata[curagg];
1459			agg = aggdata->dtada_desc;
1460
1461			/*
1462			 * We increment the current aggregation variable, but
1463			 * not beyond the number of aggregation variables that
1464			 * we're printing. This has the (desired) effect that
1465			 * DT_PFCONV_AGG conversions beyond the number of
1466			 * aggregation variables (re-)convert the aggregation
1467			 * value of the last aggregation variable.
1468			 */
1469			if (curagg < naggvars - 1)
1470				curagg++;
1471
1472			rec = &agg->dtagd_rec[aggrec];
1473			addr = aggdata->dtada_data + rec->dtrd_offset;
1474			limit = addr + aggdata->dtada_size;
1475			normal = aggdata->dtada_normal;
1476			flags = DTRACE_BUFDATA_AGGVAL;
1477		} else {
1478			if (nrecs == 0)
1479				return (dt_set_errno(dtp, EDT_DMISMATCH));
1480
1481			if (pfv->pfv_flags & DT_PRINTF_AGGREGATION) {
1482				/*
1483				 * When printing aggregation keys, we always
1484				 * set the aggdata to be the representative
1485				 * (zeroth) aggregation.  The aggdata isn't
1486				 * actually used here in this case, but it is
1487				 * passed to the buffer handler and must
1488				 * therefore still be correct.
1489				 */
1490				aggdata = aggsdata[0];
1491				flags = DTRACE_BUFDATA_AGGKEY;
1492			}
1493
1494			rec = recp++;
1495			nrecs--;
1496			addr = (caddr_t)buf + rec->dtrd_offset;
1497			limit = lim;
1498			normal = 1;
1499		}
1500
1501		size = rec->dtrd_size;
1502
1503		if (addr + size > limit) {
1504			dt_dprintf("bad size: addr=%p size=0x%x lim=%p\n",
1505			    (void *)addr, rec->dtrd_size, (void *)lim);
1506			return (dt_set_errno(dtp, EDT_DOFFSET));
1507		}
1508
1509		if (rec->dtrd_alignment != 0 &&
1510		    ((uintptr_t)addr & (rec->dtrd_alignment - 1)) != 0) {
1511			dt_dprintf("bad align: addr=%p size=0x%x align=0x%x\n",
1512			    (void *)addr, rec->dtrd_size, rec->dtrd_alignment);
1513			return (dt_set_errno(dtp, EDT_DALIGN));
1514		}
1515
1516		switch (rec->dtrd_action) {
1517		case DTRACEAGG_AVG:
1518			func = pfprint_average;
1519			break;
1520		case DTRACEAGG_STDDEV:
1521			func = pfprint_stddev;
1522			break;
1523		case DTRACEAGG_QUANTIZE:
1524			func = pfprint_quantize;
1525			break;
1526		case DTRACEAGG_LQUANTIZE:
1527			func = pfprint_lquantize;
1528			break;
1529		case DTRACEAGG_LLQUANTIZE:
1530			func = pfprint_llquantize;
1531			break;
1532		case DTRACEACT_MOD:
1533			func = pfprint_mod;
1534			break;
1535		case DTRACEACT_UMOD:
1536			func = pfprint_umod;
1537			break;
1538		default:
1539			func = pfc->pfc_print;
1540			break;
1541		}
1542
1543		start = f;
1544		if (pfd->pfd_flags & DT_PFCONV_ALT)
1545			*f++ = '#';
1546		if (pfd->pfd_flags & DT_PFCONV_ZPAD)
1547			*f++ = '0';
1548		if (width < 0 || (pfd->pfd_flags & DT_PFCONV_LEFT))
1549			*f++ = '-';
1550		if (pfd->pfd_flags & DT_PFCONV_SPOS)
1551			*f++ = '+';
1552		if (pfd->pfd_flags & DT_PFCONV_GROUP)
1553			*f++ = '\'';
1554		if (pfd->pfd_flags & DT_PFCONV_SPACE)
1555			*f++ = ' ';
1556		fmtsz -= f - start;
1557
1558		/*
1559		 * If we're printing a stack and DT_PFCONV_LEFT is set, we
1560		 * don't add the width to the format string.  See the block
1561		 * comment in pfprint_stack() for a description of the
1562		 * behavior in this case.
1563		 */
1564		if (func == pfprint_stack && (pfd->pfd_flags & DT_PFCONV_LEFT))
1565			width = 0;
1566
1567		if (width != 0) {
1568			ret = snprintf(f, fmtsz, "%d", ABS(width));
1569			f += ret;
1570			fmtsz = MAX(0, fmtsz - ret);
1571		}
1572
1573		if (prec > 0) {
1574			ret = snprintf(f, fmtsz, ".%d", prec);
1575			f += ret;
1576			fmtsz = MAX(0, fmtsz - ret);
1577		}
1578
1579		if (strlcpy(f, pfd->pfd_fmt, fmtsz) >= fmtsz)
1580			return (dt_set_errno(dtp, EDT_COMPILER));
1581		pfd->pfd_rec = rec;
1582
1583		if (func(dtp, fp, format, pfd, addr, size, normal) < 0)
1584			return (-1); /* errno is set for us */
1585
1586		if (pfv->pfv_flags & DT_PRINTF_AGGREGATION) {
1587			/*
1588			 * For printa(), we flush the buffer after each tuple
1589			 * element, inidicating that this is the last record
1590			 * as appropriate.
1591			 */
1592			if (i == pfv->pfv_argc - 1)
1593				flags |= DTRACE_BUFDATA_AGGLAST;
1594
1595			if (dt_buffered_flush(dtp, NULL,
1596			    rec, aggdata, flags) < 0)
1597				return (-1);
1598		}
1599	}
1600
1601	return ((int)(recp - recs));
1602}
1603
1604int
1605dtrace_sprintf(dtrace_hdl_t *dtp, FILE *fp, void *fmtdata,
1606    const dtrace_recdesc_t *recp, uint_t nrecs, const void *buf, size_t len)
1607{
1608	dtrace_optval_t size;
1609	int rval;
1610
1611	rval = dtrace_getopt(dtp, "strsize", &size);
1612	assert(rval == 0);
1613	assert(dtp->dt_sprintf_buflen == 0);
1614
1615	if (dtp->dt_sprintf_buf != NULL)
1616		free(dtp->dt_sprintf_buf);
1617
1618	if ((dtp->dt_sprintf_buf = malloc(size)) == NULL)
1619		return (dt_set_errno(dtp, EDT_NOMEM));
1620
1621	bzero(dtp->dt_sprintf_buf, size);
1622	dtp->dt_sprintf_buflen = size;
1623	rval = dt_printf_format(dtp, fp, fmtdata, recp, nrecs, buf, len,
1624	    NULL, 0);
1625	dtp->dt_sprintf_buflen = 0;
1626
1627	if (rval == -1)
1628		free(dtp->dt_sprintf_buf);
1629
1630	return (rval);
1631}
1632
1633/*ARGSUSED*/
1634int
1635dtrace_system(dtrace_hdl_t *dtp, FILE *fp, void *fmtdata,
1636    const dtrace_probedata_t *data, const dtrace_recdesc_t *recp,
1637    uint_t nrecs, const void *buf, size_t len)
1638{
1639	int rval = dtrace_sprintf(dtp, fp, fmtdata, recp, nrecs, buf, len);
1640
1641	if (rval == -1)
1642		return (rval);
1643
1644	/*
1645	 * Before we execute the specified command, flush fp to assure that
1646	 * any prior dt_printf()'s appear before the output of the command
1647	 * not after it.
1648	 */
1649	(void) fflush(fp);
1650
1651	if (system(dtp->dt_sprintf_buf) == -1)
1652		return (dt_set_errno(dtp, errno));
1653
1654	return (rval);
1655}
1656
1657int
1658dtrace_freopen(dtrace_hdl_t *dtp, FILE *fp, void *fmtdata,
1659    const dtrace_probedata_t *data, const dtrace_recdesc_t *recp,
1660    uint_t nrecs, const void *buf, size_t len)
1661{
1662	char selfbuf[40], restorebuf[40], *filename;
1663	FILE *nfp;
1664	int rval, errval;
1665	dt_pfargv_t *pfv = fmtdata;
1666	dt_pfargd_t *pfd = pfv->pfv_argv;
1667
1668	rval = dtrace_sprintf(dtp, fp, fmtdata, recp, nrecs, buf, len);
1669
1670	if (rval == -1 || fp == NULL)
1671		return (rval);
1672
1673#ifdef illumos
1674	if (pfd->pfd_preflen != 0 &&
1675	    strcmp(pfd->pfd_prefix, DT_FREOPEN_RESTORE) == 0) {
1676		/*
1677		 * The only way to have the format string set to the value
1678		 * DT_FREOPEN_RESTORE is via the empty freopen() string --
1679		 * denoting that we should restore the old stdout.
1680		 */
1681		assert(strcmp(dtp->dt_sprintf_buf, DT_FREOPEN_RESTORE) == 0);
1682
1683		if (dtp->dt_stdout_fd == -1) {
1684			/*
1685			 * We could complain here by generating an error,
1686			 * but it seems like overkill:  it seems that calling
1687			 * freopen() to restore stdout when freopen() has
1688			 * never before been called should just be a no-op,
1689			 * so we just return in this case.
1690			 */
1691			return (rval);
1692		}
1693
1694		(void) snprintf(restorebuf, sizeof (restorebuf),
1695		    "/dev/fd/%d", dtp->dt_stdout_fd);
1696		filename = restorebuf;
1697	} else {
1698		filename = dtp->dt_sprintf_buf;
1699	}
1700
1701	/*
1702	 * freopen(3C) will always close the specified stream and underlying
1703	 * file descriptor -- even if the specified file can't be opened.
1704	 * Even for the semantic cesspool that is standard I/O, this is
1705	 * surprisingly brain-dead behavior:  it means that any failure to
1706	 * open the specified file destroys the specified stream in the
1707	 * process -- which is particularly relevant when the specified stream
1708	 * happens (or rather, happened) to be stdout.  This could be resolved
1709	 * were there an "fdreopen()" equivalent of freopen() that allowed one
1710	 * to pass a file descriptor instead of the name of a file, but there
1711	 * is no such thing.  However, we can effect this ourselves by first
1712	 * fopen()'ing the desired file, and then (assuming that that works),
1713	 * freopen()'ing "/dev/fd/[fileno]", where [fileno] is the underlying
1714	 * file descriptor for the fopen()'d file.  This way, if the fopen()
1715	 * fails, we can fail the operation without destroying stdout.
1716	 */
1717	if ((nfp = fopen(filename, "aF")) == NULL) {
1718		char *msg = strerror(errno);
1719		char *faultstr;
1720		int len = 80;
1721
1722		len += strlen(msg) + strlen(filename);
1723		faultstr = alloca(len);
1724
1725		(void) snprintf(faultstr, len, "couldn't freopen() \"%s\": %s",
1726		    filename, strerror(errno));
1727
1728		if ((errval = dt_handle_liberr(dtp, data, faultstr)) == 0)
1729			return (rval);
1730
1731		return (errval);
1732	}
1733
1734	(void) snprintf(selfbuf, sizeof (selfbuf), "/dev/fd/%d", fileno(nfp));
1735
1736	if (dtp->dt_stdout_fd == -1) {
1737		/*
1738		 * If this is the first time that we're calling freopen(),
1739		 * we're going to stash away the file descriptor for stdout.
1740		 * We don't expect the dup(2) to fail, so if it does we must
1741		 * return failure.
1742		 */
1743		if ((dtp->dt_stdout_fd = dup(fileno(fp))) == -1) {
1744			(void) fclose(nfp);
1745			return (dt_set_errno(dtp, errno));
1746		}
1747	}
1748
1749	if (freopen(selfbuf, "aF", fp) == NULL) {
1750		(void) fclose(nfp);
1751		return (dt_set_errno(dtp, errno));
1752	}
1753
1754	(void) fclose(nfp);
1755#else	/* !illumos */
1756	/*
1757	 * The 'standard output' (which is not necessarily stdout)
1758	 * treatment on FreeBSD is implemented differently than on
1759	 * Solaris because FreeBSD's freopen() will attempt to re-use
1760	 * the current file descriptor, causing the previous file to
1761	 * be closed and thereby preventing it from be re-activated
1762	 * later.
1763	 *
1764	 * For FreeBSD we use the concept of setting an output file
1765	 * pointer in the DTrace handle if a dtrace_freopen() has
1766	 * enabled another output file and we leave the caller's
1767	 * file pointer untouched. If it was actually stdout, then
1768	 * stdout remains open. If it was another file, then that
1769	 * file remains open. While a dtrace_freopen() has activated
1770	 * another file, we keep a pointer to that which we use in
1771	 * the output functions by preference and only use the caller's
1772	 * file pointer if no dtrace_freopen() call has been made.
1773	 *
1774	 * The check to see if we're re-activating the caller's
1775	 * output file is much the same as on Solaris.
1776	 */
1777	if (pfd->pfd_preflen != 0 &&
1778	    strcmp(pfd->pfd_prefix, DT_FREOPEN_RESTORE) == 0) {
1779		/*
1780		 * The only way to have the format string set to the value
1781		 * DT_FREOPEN_RESTORE is via the empty freopen() string --
1782		 * denoting that we should restore the old stdout.
1783		 */
1784		assert(strcmp(dtp->dt_sprintf_buf, DT_FREOPEN_RESTORE) == 0);
1785
1786		if (dtp->dt_freopen_fp == NULL) {
1787			/*
1788			 * We could complain here by generating an error,
1789			 * but it seems like overkill:  it seems that calling
1790			 * freopen() to restore stdout when freopen() has
1791			 * never before been called should just be a no-op,
1792			 * so we just return in this case.
1793			 */
1794			return (rval);
1795		}
1796
1797		/*
1798		 * At this point, to re-active the original output file,
1799		 * on FreeBSD we only code the current file that this
1800		 * function opened previously.
1801		 */
1802		(void) fclose(dtp->dt_freopen_fp);
1803		dtp->dt_freopen_fp = NULL;
1804
1805		return (rval);
1806	}
1807
1808	if ((nfp = fopen(dtp->dt_sprintf_buf, "a")) == NULL) {
1809		char *msg = strerror(errno);
1810		char *faultstr;
1811		int len = 80;
1812
1813		len += strlen(msg) + strlen(dtp->dt_sprintf_buf);
1814		faultstr = alloca(len);
1815
1816		(void) snprintf(faultstr, len, "couldn't freopen() \"%s\": %s",
1817		    dtp->dt_sprintf_buf, strerror(errno));
1818
1819		if ((errval = dt_handle_liberr(dtp, data, faultstr)) == 0)
1820			return (rval);
1821
1822		return (errval);
1823	}
1824
1825	if (dtp->dt_freopen_fp != NULL)
1826		(void) fclose(dtp->dt_freopen_fp);
1827
1828	/* Remember that the output has been redirected to the new file. */
1829	dtp->dt_freopen_fp = nfp;
1830#endif	/* illumos */
1831
1832	return (rval);
1833}
1834
1835/*ARGSUSED*/
1836int
1837dtrace_fprintf(dtrace_hdl_t *dtp, FILE *fp, void *fmtdata,
1838    const dtrace_probedata_t *data, const dtrace_recdesc_t *recp,
1839    uint_t nrecs, const void *buf, size_t len)
1840{
1841	return (dt_printf_format(dtp, fp, fmtdata,
1842	    recp, nrecs, buf, len, NULL, 0));
1843}
1844
1845void *
1846dtrace_printf_create(dtrace_hdl_t *dtp, const char *s)
1847{
1848	dt_pfargv_t *pfv = dt_printf_create(dtp, s);
1849	dt_pfargd_t *pfd;
1850	int i;
1851
1852	if (pfv == NULL)
1853		return (NULL);		/* errno has been set for us */
1854
1855	pfd = pfv->pfv_argv;
1856
1857	for (i = 0; i < pfv->pfv_argc; i++, pfd = pfd->pfd_next) {
1858		const dt_pfconv_t *pfc = pfd->pfd_conv;
1859
1860		if (pfc == NULL)
1861			continue;
1862
1863		/*
1864		 * If the output format is not %s then we assume that we have
1865		 * been given a correctly-sized format string, so we copy the
1866		 * true format name including the size modifier.  If the output
1867		 * format is %s, then either the input format is %s as well or
1868		 * it is one of our custom formats (e.g. pfprint_addr), so we
1869		 * must set pfd_fmt to be the output format conversion "s".
1870		 */
1871		if (strcmp(pfc->pfc_ofmt, "s") != 0)
1872			(void) strcat(pfd->pfd_fmt, pfc->pfc_name);
1873		else
1874			(void) strcat(pfd->pfd_fmt, pfc->pfc_ofmt);
1875	}
1876
1877	return (pfv);
1878}
1879
1880void *
1881dtrace_printa_create(dtrace_hdl_t *dtp, const char *s)
1882{
1883	dt_pfargv_t *pfv = dtrace_printf_create(dtp, s);
1884
1885	if (pfv == NULL)
1886		return (NULL);		/* errno has been set for us */
1887
1888	pfv->pfv_flags |= DT_PRINTF_AGGREGATION;
1889
1890	return (pfv);
1891}
1892
1893/*ARGSUSED*/
1894size_t
1895dtrace_printf_format(dtrace_hdl_t *dtp, void *fmtdata, char *s, size_t len)
1896{
1897	dt_pfargv_t *pfv = fmtdata;
1898	dt_pfargd_t *pfd = pfv->pfv_argv;
1899
1900	/*
1901	 * An upper bound on the string length is the length of the original
1902	 * format string, plus three times the number of conversions (each
1903	 * conversion could add up an additional "ll" and/or pfd_width digit
1904	 * in the case of converting %? to %16) plus one for a terminating \0.
1905	 */
1906	size_t formatlen = strlen(pfv->pfv_format) + 3 * pfv->pfv_argc + 1;
1907	char *format = alloca(formatlen);
1908	char *f = format;
1909	int i, j;
1910
1911	for (i = 0; i < pfv->pfv_argc; i++, pfd = pfd->pfd_next) {
1912		const dt_pfconv_t *pfc = pfd->pfd_conv;
1913		const char *str;
1914		int width = pfd->pfd_width;
1915		int prec = pfd->pfd_prec;
1916
1917		if (pfd->pfd_preflen != 0) {
1918			for (j = 0; j < pfd->pfd_preflen; j++)
1919				*f++ = pfd->pfd_prefix[j];
1920		}
1921
1922		if (pfc == NULL)
1923			continue;
1924
1925		*f++ = '%';
1926
1927		if (pfd->pfd_flags & DT_PFCONV_ALT)
1928			*f++ = '#';
1929		if (pfd->pfd_flags & DT_PFCONV_ZPAD)
1930			*f++ = '0';
1931		if (pfd->pfd_flags & DT_PFCONV_LEFT)
1932			*f++ = '-';
1933		if (pfd->pfd_flags & DT_PFCONV_SPOS)
1934			*f++ = '+';
1935		if (pfd->pfd_flags & DT_PFCONV_DYNWIDTH)
1936			*f++ = '*';
1937		if (pfd->pfd_flags & DT_PFCONV_DYNPREC) {
1938			*f++ = '.';
1939			*f++ = '*';
1940		}
1941		if (pfd->pfd_flags & DT_PFCONV_GROUP)
1942			*f++ = '\'';
1943		if (pfd->pfd_flags & DT_PFCONV_SPACE)
1944			*f++ = ' ';
1945		if (pfd->pfd_flags & DT_PFCONV_AGG)
1946			*f++ = '@';
1947
1948		if (width != 0)
1949			f += snprintf(f, sizeof (format), "%d", width);
1950
1951		if (prec != 0)
1952			f += snprintf(f, sizeof (format), ".%d", prec);
1953
1954		/*
1955		 * If the output format is %s, then either %s is the underlying
1956		 * conversion or the conversion is one of our customized ones,
1957		 * e.g. pfprint_addr.  In these cases, put the original string
1958		 * name of the conversion (pfc_name) into the pickled format
1959		 * string rather than the derived conversion (pfd_fmt).
1960		 */
1961		if (strcmp(pfc->pfc_ofmt, "s") == 0)
1962			str = pfc->pfc_name;
1963		else
1964			str = pfd->pfd_fmt;
1965
1966		for (j = 0; str[j] != '\0'; j++)
1967			*f++ = str[j];
1968	}
1969
1970	*f = '\0'; /* insert nul byte; do not count in return value */
1971
1972	assert(f < format + formatlen);
1973	(void) strncpy(s, format, len);
1974
1975	return ((size_t)(f - format));
1976}
1977
1978static int
1979dt_fprinta(const dtrace_aggdata_t *adp, void *arg)
1980{
1981	const dtrace_aggdesc_t *agg = adp->dtada_desc;
1982	const dtrace_recdesc_t *recp = &agg->dtagd_rec[0];
1983	uint_t nrecs = agg->dtagd_nrecs;
1984	dt_pfwalk_t *pfw = arg;
1985	dtrace_hdl_t *dtp = pfw->pfw_argv->pfv_dtp;
1986	int id;
1987
1988	if (dt_printf_getint(dtp, recp++, nrecs--,
1989	    adp->dtada_data, adp->dtada_size, &id) != 0 || pfw->pfw_aid != id)
1990		return (0); /* no aggregation id or id does not match */
1991
1992	if (dt_printf_format(dtp, pfw->pfw_fp, pfw->pfw_argv,
1993	    recp, nrecs, adp->dtada_data, adp->dtada_size, &adp, 1) == -1)
1994		return (pfw->pfw_err = dtp->dt_errno);
1995
1996	/*
1997	 * Cast away the const to set the bit indicating that this aggregation
1998	 * has been printed.
1999	 */
2000	((dtrace_aggdesc_t *)agg)->dtagd_flags |= DTRACE_AGD_PRINTED;
2001
2002	return (0);
2003}
2004
2005static int
2006dt_fprintas(const dtrace_aggdata_t **aggsdata, int naggvars, void *arg)
2007{
2008	const dtrace_aggdata_t *aggdata = aggsdata[0];
2009	const dtrace_aggdesc_t *agg = aggdata->dtada_desc;
2010	const dtrace_recdesc_t *rec = &agg->dtagd_rec[1];
2011	uint_t nrecs = agg->dtagd_nrecs - 1;
2012	dt_pfwalk_t *pfw = arg;
2013	dtrace_hdl_t *dtp = pfw->pfw_argv->pfv_dtp;
2014	int i;
2015
2016	if (dt_printf_format(dtp, pfw->pfw_fp, pfw->pfw_argv,
2017	    rec, nrecs, aggdata->dtada_data, aggdata->dtada_size,
2018	    aggsdata, naggvars) == -1)
2019		return (pfw->pfw_err = dtp->dt_errno);
2020
2021	/*
2022	 * For each aggregation, indicate that it has been printed, casting
2023	 * away the const as necessary.
2024	 */
2025	for (i = 1; i < naggvars; i++) {
2026		agg = aggsdata[i]->dtada_desc;
2027		((dtrace_aggdesc_t *)agg)->dtagd_flags |= DTRACE_AGD_PRINTED;
2028	}
2029
2030	return (0);
2031}
2032/*ARGSUSED*/
2033int
2034dtrace_fprinta(dtrace_hdl_t *dtp, FILE *fp, void *fmtdata,
2035    const dtrace_probedata_t *data, const dtrace_recdesc_t *recs,
2036    uint_t nrecs, const void *buf, size_t len)
2037{
2038	dt_pfwalk_t pfw;
2039	int i, naggvars = 0;
2040	dtrace_aggvarid_t *aggvars;
2041
2042	aggvars = alloca(nrecs * sizeof (dtrace_aggvarid_t));
2043
2044	/*
2045	 * This might be a printa() with multiple aggregation variables.  We
2046	 * need to scan forward through the records until we find a record from
2047	 * a different statement.
2048	 */
2049	for (i = 0; i < nrecs; i++) {
2050		const dtrace_recdesc_t *nrec = &recs[i];
2051
2052		if (nrec->dtrd_uarg != recs->dtrd_uarg)
2053			break;
2054
2055		if (nrec->dtrd_action != recs->dtrd_action)
2056			return (dt_set_errno(dtp, EDT_BADAGG));
2057
2058		aggvars[naggvars++] =
2059		    /* LINTED - alignment */
2060		    *((dtrace_aggvarid_t *)((caddr_t)buf + nrec->dtrd_offset));
2061	}
2062
2063	if (naggvars == 0)
2064		return (dt_set_errno(dtp, EDT_BADAGG));
2065
2066	pfw.pfw_argv = fmtdata;
2067	pfw.pfw_fp = fp;
2068	pfw.pfw_err = 0;
2069
2070	if (naggvars == 1) {
2071		pfw.pfw_aid = aggvars[0];
2072
2073		if (dtrace_aggregate_walk_sorted(dtp,
2074		    dt_fprinta, &pfw) == -1 || pfw.pfw_err != 0)
2075			return (-1); /* errno is set for us */
2076	} else {
2077		if (dtrace_aggregate_walk_joined(dtp, aggvars, naggvars,
2078		    dt_fprintas, &pfw) == -1 || pfw.pfw_err != 0)
2079			return (-1); /* errno is set for us */
2080	}
2081
2082	return (i);
2083}
2084