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