16ff6d951SJohn Birrell /*
26ff6d951SJohn Birrell * CDDL HEADER START
36ff6d951SJohn Birrell *
46ff6d951SJohn Birrell * The contents of this file are subject to the terms of the
56ff6d951SJohn Birrell * Common Development and Distribution License (the "License").
66ff6d951SJohn Birrell * You may not use this file except in compliance with the License.
76ff6d951SJohn Birrell *
86ff6d951SJohn Birrell * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96ff6d951SJohn Birrell * or http://www.opensolaris.org/os/licensing.
106ff6d951SJohn Birrell * See the License for the specific language governing permissions
116ff6d951SJohn Birrell * and limitations under the License.
126ff6d951SJohn Birrell *
136ff6d951SJohn Birrell * When distributing Covered Code, include this CDDL HEADER in each
146ff6d951SJohn Birrell * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156ff6d951SJohn Birrell * If applicable, add the following below this CDDL HEADER, with the
166ff6d951SJohn Birrell * fields enclosed by brackets "[]" replaced with your own identifying
176ff6d951SJohn Birrell * information: Portions Copyright [yyyy] [name of copyright owner]
186ff6d951SJohn Birrell *
196ff6d951SJohn Birrell * CDDL HEADER END
206ff6d951SJohn Birrell */
216ff6d951SJohn Birrell
226ff6d951SJohn Birrell /*
231670a1c2SRui Paulo * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
248e648814SRui Paulo * Copyright (c) 2013, Joyent, Inc. All rights reserved.
258e648814SRui Paulo * Copyright (c) 2013 by Delphix. All rights reserved.
266ff6d951SJohn Birrell */
276ff6d951SJohn Birrell
28bc96366cSSteven Hartland #ifdef illumos
296ff6d951SJohn Birrell #include <sys/sysmacros.h>
3029f89dfcSJohn Birrell #else
3129f89dfcSJohn Birrell #define ABS(a) ((a) < 0 ? -(a) : (a))
3229f89dfcSJohn Birrell #endif
3329f89dfcSJohn Birrell #include <string.h>
346ff6d951SJohn Birrell #include <strings.h>
356ff6d951SJohn Birrell #include <stdlib.h>
36bc96366cSSteven Hartland #ifdef illumos
376ff6d951SJohn Birrell #include <alloca.h>
3829f89dfcSJohn Birrell #endif
396ff6d951SJohn Birrell #include <assert.h>
406ff6d951SJohn Birrell #include <ctype.h>
416ff6d951SJohn Birrell #include <errno.h>
426ff6d951SJohn Birrell #include <limits.h>
431670a1c2SRui Paulo #include <sys/socket.h>
441670a1c2SRui Paulo #include <netdb.h>
451670a1c2SRui Paulo #include <netinet/in.h>
461670a1c2SRui Paulo #include <arpa/inet.h>
479e5787d2SMatt Macy #include <sys/byteorder.h>
486ff6d951SJohn Birrell #include <dt_printf.h>
496ff6d951SJohn Birrell #include <dt_string.h>
506ff6d951SJohn Birrell #include <dt_impl.h>
516ff6d951SJohn Birrell
529e5787d2SMatt Macy #ifndef NS_IN6ADDRSZ
539e5787d2SMatt Macy #define NS_IN6ADDRSZ 16
549e5787d2SMatt Macy #endif
559e5787d2SMatt Macy
569e5787d2SMatt Macy #ifndef NS_INADDRSZ
579e5787d2SMatt Macy #define NS_INADDRSZ 4
589e5787d2SMatt Macy #endif
599e5787d2SMatt Macy
606ff6d951SJohn Birrell /*ARGSUSED*/
616ff6d951SJohn Birrell static int
pfcheck_addr(dt_pfargv_t * pfv,dt_pfargd_t * pfd,dt_node_t * dnp)626ff6d951SJohn Birrell pfcheck_addr(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
636ff6d951SJohn Birrell {
646ff6d951SJohn Birrell return (dt_node_is_pointer(dnp) || dt_node_is_integer(dnp));
656ff6d951SJohn Birrell }
666ff6d951SJohn Birrell
676ff6d951SJohn Birrell /*ARGSUSED*/
686ff6d951SJohn Birrell static int
pfcheck_kaddr(dt_pfargv_t * pfv,dt_pfargd_t * pfd,dt_node_t * dnp)696ff6d951SJohn Birrell pfcheck_kaddr(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
706ff6d951SJohn Birrell {
716ff6d951SJohn Birrell return (dt_node_is_pointer(dnp) || dt_node_is_integer(dnp) ||
726ff6d951SJohn Birrell dt_node_is_symaddr(dnp));
736ff6d951SJohn Birrell }
746ff6d951SJohn Birrell
756ff6d951SJohn Birrell /*ARGSUSED*/
766ff6d951SJohn Birrell static int
pfcheck_uaddr(dt_pfargv_t * pfv,dt_pfargd_t * pfd,dt_node_t * dnp)776ff6d951SJohn Birrell pfcheck_uaddr(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
786ff6d951SJohn Birrell {
796ff6d951SJohn Birrell dtrace_hdl_t *dtp = pfv->pfv_dtp;
806ff6d951SJohn Birrell dt_ident_t *idp = dt_idhash_lookup(dtp->dt_macros, "target");
816ff6d951SJohn Birrell
826ff6d951SJohn Birrell if (dt_node_is_usymaddr(dnp))
836ff6d951SJohn Birrell return (1);
846ff6d951SJohn Birrell
856ff6d951SJohn Birrell if (idp == NULL || idp->di_id == 0)
866ff6d951SJohn Birrell return (0);
876ff6d951SJohn Birrell
886ff6d951SJohn Birrell return (dt_node_is_pointer(dnp) || dt_node_is_integer(dnp));
896ff6d951SJohn Birrell }
906ff6d951SJohn Birrell
916ff6d951SJohn Birrell /*ARGSUSED*/
926ff6d951SJohn Birrell static int
pfcheck_stack(dt_pfargv_t * pfv,dt_pfargd_t * pfd,dt_node_t * dnp)936ff6d951SJohn Birrell pfcheck_stack(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
946ff6d951SJohn Birrell {
956ff6d951SJohn Birrell return (dt_node_is_stack(dnp));
966ff6d951SJohn Birrell }
976ff6d951SJohn Birrell
986ff6d951SJohn Birrell /*ARGSUSED*/
996ff6d951SJohn Birrell static int
pfcheck_time(dt_pfargv_t * pfv,dt_pfargd_t * pfd,dt_node_t * dnp)1006ff6d951SJohn Birrell pfcheck_time(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
1016ff6d951SJohn Birrell {
1026ff6d951SJohn Birrell return (dt_node_is_integer(dnp) &&
1036ff6d951SJohn Birrell dt_node_type_size(dnp) == sizeof (uint64_t));
1046ff6d951SJohn Birrell }
1056ff6d951SJohn Birrell
1066ff6d951SJohn Birrell /*ARGSUSED*/
1076ff6d951SJohn Birrell static int
pfcheck_str(dt_pfargv_t * pfv,dt_pfargd_t * pfd,dt_node_t * dnp)1086ff6d951SJohn Birrell pfcheck_str(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
1096ff6d951SJohn Birrell {
1106ff6d951SJohn Birrell ctf_file_t *ctfp;
1116ff6d951SJohn Birrell ctf_encoding_t e;
1126ff6d951SJohn Birrell ctf_arinfo_t r;
1136ff6d951SJohn Birrell ctf_id_t base;
1146ff6d951SJohn Birrell uint_t kind;
1156ff6d951SJohn Birrell
1166ff6d951SJohn Birrell if (dt_node_is_string(dnp))
1176ff6d951SJohn Birrell return (1);
1186ff6d951SJohn Birrell
1196ff6d951SJohn Birrell ctfp = dnp->dn_ctfp;
1206ff6d951SJohn Birrell base = ctf_type_resolve(ctfp, dnp->dn_type);
1216ff6d951SJohn Birrell kind = ctf_type_kind(ctfp, base);
1226ff6d951SJohn Birrell
1236ff6d951SJohn Birrell return (kind == CTF_K_ARRAY && ctf_array_info(ctfp, base, &r) == 0 &&
1246ff6d951SJohn Birrell (base = ctf_type_resolve(ctfp, r.ctr_contents)) != CTF_ERR &&
1256ff6d951SJohn Birrell ctf_type_encoding(ctfp, base, &e) == 0 && IS_CHAR(e));
1266ff6d951SJohn Birrell }
1276ff6d951SJohn Birrell
1286ff6d951SJohn Birrell /*ARGSUSED*/
1296ff6d951SJohn Birrell static int
pfcheck_wstr(dt_pfargv_t * pfv,dt_pfargd_t * pfd,dt_node_t * dnp)1306ff6d951SJohn Birrell pfcheck_wstr(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
1316ff6d951SJohn Birrell {
1326ff6d951SJohn Birrell ctf_file_t *ctfp = dnp->dn_ctfp;
1336ff6d951SJohn Birrell ctf_id_t base = ctf_type_resolve(ctfp, dnp->dn_type);
1346ff6d951SJohn Birrell uint_t kind = ctf_type_kind(ctfp, base);
1356ff6d951SJohn Birrell
1366ff6d951SJohn Birrell ctf_encoding_t e;
1376ff6d951SJohn Birrell ctf_arinfo_t r;
1386ff6d951SJohn Birrell
1396ff6d951SJohn Birrell return (kind == CTF_K_ARRAY && ctf_array_info(ctfp, base, &r) == 0 &&
1406ff6d951SJohn Birrell (base = ctf_type_resolve(ctfp, r.ctr_contents)) != CTF_ERR &&
1416ff6d951SJohn Birrell ctf_type_kind(ctfp, base) == CTF_K_INTEGER &&
1426ff6d951SJohn Birrell ctf_type_encoding(ctfp, base, &e) == 0 && e.cte_bits == 32);
1436ff6d951SJohn Birrell }
1446ff6d951SJohn Birrell
1456ff6d951SJohn Birrell /*ARGSUSED*/
1466ff6d951SJohn Birrell static int
pfcheck_csi(dt_pfargv_t * pfv,dt_pfargd_t * pfd,dt_node_t * dnp)1476ff6d951SJohn Birrell pfcheck_csi(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
1486ff6d951SJohn Birrell {
1496ff6d951SJohn Birrell return (dt_node_is_integer(dnp) &&
1506ff6d951SJohn Birrell dt_node_type_size(dnp) <= sizeof (int));
1516ff6d951SJohn Birrell }
1526ff6d951SJohn Birrell
1536ff6d951SJohn Birrell /*ARGSUSED*/
1546ff6d951SJohn Birrell static int
pfcheck_fp(dt_pfargv_t * pfv,dt_pfargd_t * pfd,dt_node_t * dnp)1556ff6d951SJohn Birrell pfcheck_fp(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
1566ff6d951SJohn Birrell {
1576ff6d951SJohn Birrell return (dt_node_is_float(dnp));
1586ff6d951SJohn Birrell }
1596ff6d951SJohn Birrell
1606ff6d951SJohn Birrell /*ARGSUSED*/
1616ff6d951SJohn Birrell static int
pfcheck_xint(dt_pfargv_t * pfv,dt_pfargd_t * pfd,dt_node_t * dnp)1626ff6d951SJohn Birrell pfcheck_xint(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
1636ff6d951SJohn Birrell {
1646ff6d951SJohn Birrell return (dt_node_is_integer(dnp));
1656ff6d951SJohn Birrell }
1666ff6d951SJohn Birrell
1676ff6d951SJohn Birrell /*ARGSUSED*/
1686ff6d951SJohn Birrell static int
pfcheck_dint(dt_pfargv_t * pfv,dt_pfargd_t * pfd,dt_node_t * dnp)1696ff6d951SJohn Birrell pfcheck_dint(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
1706ff6d951SJohn Birrell {
1716ff6d951SJohn Birrell if (dnp->dn_flags & DT_NF_SIGNED)
172a98ff317SPedro F. Giffuni pfd->pfd_fmt[strlen(pfd->pfd_fmt) - 1] = 'i';
1736ff6d951SJohn Birrell else
1746ff6d951SJohn Birrell pfd->pfd_fmt[strlen(pfd->pfd_fmt) - 1] = 'u';
1756ff6d951SJohn Birrell
1766ff6d951SJohn Birrell return (dt_node_is_integer(dnp));
1776ff6d951SJohn Birrell }
1786ff6d951SJohn Birrell
1796ff6d951SJohn Birrell /*ARGSUSED*/
1806ff6d951SJohn Birrell static int
pfcheck_xshort(dt_pfargv_t * pfv,dt_pfargd_t * pfd,dt_node_t * dnp)1816ff6d951SJohn Birrell pfcheck_xshort(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
1826ff6d951SJohn Birrell {
1836ff6d951SJohn Birrell ctf_file_t *ctfp = dnp->dn_ctfp;
1846ff6d951SJohn Birrell ctf_id_t type = ctf_type_resolve(ctfp, dnp->dn_type);
1856ff6d951SJohn Birrell char n[DT_TYPE_NAMELEN];
1866ff6d951SJohn Birrell
1876ff6d951SJohn Birrell return (ctf_type_name(ctfp, type, n, sizeof (n)) != NULL && (
1886ff6d951SJohn Birrell strcmp(n, "short") == 0 || strcmp(n, "signed short") == 0 ||
1896ff6d951SJohn Birrell strcmp(n, "unsigned short") == 0));
1906ff6d951SJohn Birrell }
1916ff6d951SJohn Birrell
1926ff6d951SJohn Birrell /*ARGSUSED*/
1936ff6d951SJohn Birrell static int
pfcheck_xlong(dt_pfargv_t * pfv,dt_pfargd_t * pfd,dt_node_t * dnp)1946ff6d951SJohn Birrell pfcheck_xlong(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
1956ff6d951SJohn Birrell {
1966ff6d951SJohn Birrell ctf_file_t *ctfp = dnp->dn_ctfp;
1976ff6d951SJohn Birrell ctf_id_t type = ctf_type_resolve(ctfp, dnp->dn_type);
1986ff6d951SJohn Birrell char n[DT_TYPE_NAMELEN];
1996ff6d951SJohn Birrell
2006ff6d951SJohn Birrell return (ctf_type_name(ctfp, type, n, sizeof (n)) != NULL && (
2016ff6d951SJohn Birrell strcmp(n, "long") == 0 || strcmp(n, "signed long") == 0 ||
2026ff6d951SJohn Birrell strcmp(n, "unsigned long") == 0));
2036ff6d951SJohn Birrell }
2046ff6d951SJohn Birrell
2056ff6d951SJohn Birrell /*ARGSUSED*/
2066ff6d951SJohn Birrell static int
pfcheck_xlonglong(dt_pfargv_t * pfv,dt_pfargd_t * pfd,dt_node_t * dnp)2076ff6d951SJohn Birrell pfcheck_xlonglong(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
2086ff6d951SJohn Birrell {
2096ff6d951SJohn Birrell ctf_file_t *ctfp = dnp->dn_ctfp;
2106ff6d951SJohn Birrell ctf_id_t type = dnp->dn_type;
2116ff6d951SJohn Birrell char n[DT_TYPE_NAMELEN];
2126ff6d951SJohn Birrell
2136ff6d951SJohn Birrell if (ctf_type_name(ctfp, ctf_type_resolve(ctfp, type), n,
2146ff6d951SJohn Birrell sizeof (n)) != NULL && (strcmp(n, "long long") == 0 ||
2156ff6d951SJohn Birrell strcmp(n, "signed long long") == 0 ||
2166ff6d951SJohn Birrell strcmp(n, "unsigned long long") == 0))
2176ff6d951SJohn Birrell return (1);
2186ff6d951SJohn Birrell
2196ff6d951SJohn Birrell /*
2206ff6d951SJohn Birrell * If the type used for %llx or %llX is not an [unsigned] long long, we
2216ff6d951SJohn Birrell * also permit it to be a [u]int64_t or any typedef thereof. We know
2226ff6d951SJohn Birrell * that these typedefs are guaranteed to work with %ll[xX] in either
2236ff6d951SJohn Birrell * compilation environment even though they alias to "long" in LP64.
2246ff6d951SJohn Birrell */
2256ff6d951SJohn Birrell while (ctf_type_kind(ctfp, type) == CTF_K_TYPEDEF) {
2266ff6d951SJohn Birrell if (ctf_type_name(ctfp, type, n, sizeof (n)) != NULL &&
2276ff6d951SJohn Birrell (strcmp(n, "int64_t") == 0 || strcmp(n, "uint64_t") == 0))
2286ff6d951SJohn Birrell return (1);
2296ff6d951SJohn Birrell
2306ff6d951SJohn Birrell type = ctf_type_reference(ctfp, type);
2316ff6d951SJohn Birrell }
2326ff6d951SJohn Birrell
2336ff6d951SJohn Birrell return (0);
2346ff6d951SJohn Birrell }
2356ff6d951SJohn Birrell
2366ff6d951SJohn Birrell /*ARGSUSED*/
2376ff6d951SJohn Birrell static int
pfcheck_type(dt_pfargv_t * pfv,dt_pfargd_t * pfd,dt_node_t * dnp)2386ff6d951SJohn Birrell pfcheck_type(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
2396ff6d951SJohn Birrell {
2406ff6d951SJohn Birrell return (ctf_type_compat(dnp->dn_ctfp, ctf_type_resolve(dnp->dn_ctfp,
2416ff6d951SJohn Birrell dnp->dn_type), pfd->pfd_conv->pfc_dctfp, pfd->pfd_conv->pfc_dtype));
2426ff6d951SJohn Birrell }
2436ff6d951SJohn Birrell
2446ff6d951SJohn Birrell /*ARGSUSED*/
2456ff6d951SJohn Birrell static int
pfprint_sint(dtrace_hdl_t * dtp,FILE * fp,const char * format,const dt_pfargd_t * pfd,const void * addr,size_t size,uint64_t unormal)2466ff6d951SJohn Birrell pfprint_sint(dtrace_hdl_t *dtp, FILE *fp, const char *format,
2476ff6d951SJohn Birrell const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t unormal)
2486ff6d951SJohn Birrell {
2496ff6d951SJohn Birrell int64_t normal = (int64_t)unormal;
2506ff6d951SJohn Birrell int32_t n = (int32_t)normal;
2516ff6d951SJohn Birrell
2526ff6d951SJohn Birrell switch (size) {
2536ff6d951SJohn Birrell case sizeof (int8_t):
2546ff6d951SJohn Birrell return (dt_printf(dtp, fp, format,
2556ff6d951SJohn Birrell (int32_t)*((int8_t *)addr) / n));
2566ff6d951SJohn Birrell case sizeof (int16_t):
2576ff6d951SJohn Birrell return (dt_printf(dtp, fp, format,
2586ff6d951SJohn Birrell (int32_t)*((int16_t *)addr) / n));
2596ff6d951SJohn Birrell case sizeof (int32_t):
2606ff6d951SJohn Birrell return (dt_printf(dtp, fp, format,
2616ff6d951SJohn Birrell *((int32_t *)addr) / n));
2626ff6d951SJohn Birrell case sizeof (int64_t):
2636ff6d951SJohn Birrell return (dt_printf(dtp, fp, format,
2646ff6d951SJohn Birrell *((int64_t *)addr) / normal));
2656ff6d951SJohn Birrell default:
2666ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_DMISMATCH));
2676ff6d951SJohn Birrell }
2686ff6d951SJohn Birrell }
2696ff6d951SJohn Birrell
2706ff6d951SJohn Birrell /*ARGSUSED*/
2716ff6d951SJohn Birrell static int
pfprint_uint(dtrace_hdl_t * dtp,FILE * fp,const char * format,const dt_pfargd_t * pfd,const void * addr,size_t size,uint64_t normal)2726ff6d951SJohn Birrell pfprint_uint(dtrace_hdl_t *dtp, FILE *fp, const char *format,
2736ff6d951SJohn Birrell const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
2746ff6d951SJohn Birrell {
2756ff6d951SJohn Birrell uint32_t n = (uint32_t)normal;
2766ff6d951SJohn Birrell
2776ff6d951SJohn Birrell switch (size) {
2786ff6d951SJohn Birrell case sizeof (uint8_t):
2796ff6d951SJohn Birrell return (dt_printf(dtp, fp, format,
2806ff6d951SJohn Birrell (uint32_t)*((uint8_t *)addr) / n));
2816ff6d951SJohn Birrell case sizeof (uint16_t):
2826ff6d951SJohn Birrell return (dt_printf(dtp, fp, format,
2836ff6d951SJohn Birrell (uint32_t)*((uint16_t *)addr) / n));
2846ff6d951SJohn Birrell case sizeof (uint32_t):
2856ff6d951SJohn Birrell return (dt_printf(dtp, fp, format,
2866ff6d951SJohn Birrell *((uint32_t *)addr) / n));
2876ff6d951SJohn Birrell case sizeof (uint64_t):
2886ff6d951SJohn Birrell return (dt_printf(dtp, fp, format,
2896ff6d951SJohn Birrell *((uint64_t *)addr) / normal));
2906ff6d951SJohn Birrell default:
2916ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_DMISMATCH));
2926ff6d951SJohn Birrell }
2936ff6d951SJohn Birrell }
2946ff6d951SJohn Birrell
2956ff6d951SJohn Birrell static int
pfprint_dint(dtrace_hdl_t * dtp,FILE * fp,const char * format,const dt_pfargd_t * pfd,const void * addr,size_t size,uint64_t normal)2966ff6d951SJohn Birrell pfprint_dint(dtrace_hdl_t *dtp, FILE *fp, const char *format,
2976ff6d951SJohn Birrell const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
2986ff6d951SJohn Birrell {
2996ff6d951SJohn Birrell if (pfd->pfd_flags & DT_PFCONV_SIGNED)
3006ff6d951SJohn Birrell return (pfprint_sint(dtp, fp, format, pfd, addr, size, normal));
3016ff6d951SJohn Birrell else
3026ff6d951SJohn Birrell return (pfprint_uint(dtp, fp, format, pfd, addr, size, normal));
3036ff6d951SJohn Birrell }
3046ff6d951SJohn Birrell
3056ff6d951SJohn Birrell /*ARGSUSED*/
3066ff6d951SJohn Birrell static int
pfprint_fp(dtrace_hdl_t * dtp,FILE * fp,const char * format,const dt_pfargd_t * pfd,const void * addr,size_t size,uint64_t normal)3076ff6d951SJohn Birrell pfprint_fp(dtrace_hdl_t *dtp, FILE *fp, const char *format,
3086ff6d951SJohn Birrell const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
3096ff6d951SJohn Birrell {
3106ff6d951SJohn Birrell double n = (double)normal;
3116ff6d951SJohn Birrell long double ldn = (long double)normal;
3126ff6d951SJohn Birrell
3136ff6d951SJohn Birrell switch (size) {
3146ff6d951SJohn Birrell case sizeof (float):
3156ff6d951SJohn Birrell return (dt_printf(dtp, fp, format,
3166ff6d951SJohn Birrell (double)*((float *)addr) / n));
3176ff6d951SJohn Birrell case sizeof (double):
3186ff6d951SJohn Birrell return (dt_printf(dtp, fp, format,
3196ff6d951SJohn Birrell *((double *)addr) / n));
320*2166649fSMitchell Horne #if !defined(__arm__) && !defined(__powerpc__) && !defined(__riscv)
3216ff6d951SJohn Birrell case sizeof (long double):
3226ff6d951SJohn Birrell return (dt_printf(dtp, fp, format,
3236ff6d951SJohn Birrell *((long double *)addr) / ldn));
32429f89dfcSJohn Birrell #endif
3256ff6d951SJohn Birrell default:
3266ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_DMISMATCH));
3276ff6d951SJohn Birrell }
3286ff6d951SJohn Birrell }
3296ff6d951SJohn Birrell
3306ff6d951SJohn Birrell /*ARGSUSED*/
3316ff6d951SJohn Birrell static int
pfprint_addr(dtrace_hdl_t * dtp,FILE * fp,const char * format,const dt_pfargd_t * pfd,const void * addr,size_t size,uint64_t normal)3326ff6d951SJohn Birrell pfprint_addr(dtrace_hdl_t *dtp, FILE *fp, const char *format,
3336ff6d951SJohn Birrell const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
3346ff6d951SJohn Birrell {
3356ff6d951SJohn Birrell char *s;
3366ff6d951SJohn Birrell int n, len = 256;
3376ff6d951SJohn Birrell uint64_t val;
3386ff6d951SJohn Birrell
3396ff6d951SJohn Birrell switch (size) {
3406ff6d951SJohn Birrell case sizeof (uint32_t):
3416ff6d951SJohn Birrell val = *((uint32_t *)addr);
3426ff6d951SJohn Birrell break;
3436ff6d951SJohn Birrell case sizeof (uint64_t):
3446ff6d951SJohn Birrell val = *((uint64_t *)addr);
3456ff6d951SJohn Birrell break;
3466ff6d951SJohn Birrell default:
3476ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_DMISMATCH));
3486ff6d951SJohn Birrell }
3496ff6d951SJohn Birrell
3506ff6d951SJohn Birrell do {
3516ff6d951SJohn Birrell n = len;
3526ff6d951SJohn Birrell s = alloca(n);
3531670a1c2SRui Paulo } while ((len = dtrace_addr2str(dtp, val, s, n)) > n);
3546ff6d951SJohn Birrell
3556ff6d951SJohn Birrell return (dt_printf(dtp, fp, format, s));
3566ff6d951SJohn Birrell }
3576ff6d951SJohn Birrell
3586ff6d951SJohn Birrell /*ARGSUSED*/
3596ff6d951SJohn Birrell static int
pfprint_mod(dtrace_hdl_t * dtp,FILE * fp,const char * format,const dt_pfargd_t * pfd,const void * addr,size_t size,uint64_t normal)3606ff6d951SJohn Birrell pfprint_mod(dtrace_hdl_t *dtp, FILE *fp, const char *format,
3616ff6d951SJohn Birrell const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
3626ff6d951SJohn Birrell {
3636ff6d951SJohn Birrell return (dt_print_mod(dtp, fp, format, (caddr_t)addr));
3646ff6d951SJohn Birrell }
3656ff6d951SJohn Birrell
3666ff6d951SJohn Birrell /*ARGSUSED*/
3676ff6d951SJohn Birrell static int
pfprint_umod(dtrace_hdl_t * dtp,FILE * fp,const char * format,const dt_pfargd_t * pfd,const void * addr,size_t size,uint64_t normal)3686ff6d951SJohn Birrell pfprint_umod(dtrace_hdl_t *dtp, FILE *fp, const char *format,
3696ff6d951SJohn Birrell const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
3706ff6d951SJohn Birrell {
3716ff6d951SJohn Birrell return (dt_print_umod(dtp, fp, format, (caddr_t)addr));
3726ff6d951SJohn Birrell }
3736ff6d951SJohn Birrell
3746ff6d951SJohn Birrell /*ARGSUSED*/
3756ff6d951SJohn Birrell static int
pfprint_uaddr(dtrace_hdl_t * dtp,FILE * fp,const char * format,const dt_pfargd_t * pfd,const void * addr,size_t size,uint64_t normal)3766ff6d951SJohn Birrell pfprint_uaddr(dtrace_hdl_t *dtp, FILE *fp, const char *format,
3776ff6d951SJohn Birrell const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
3786ff6d951SJohn Birrell {
3796ff6d951SJohn Birrell char *s;
3806ff6d951SJohn Birrell int n, len = 256;
3816ff6d951SJohn Birrell uint64_t val, pid = 0;
3826ff6d951SJohn Birrell
3836ff6d951SJohn Birrell dt_ident_t *idp = dt_idhash_lookup(dtp->dt_macros, "target");
3846ff6d951SJohn Birrell
3856ff6d951SJohn Birrell switch (size) {
3866ff6d951SJohn Birrell case sizeof (uint32_t):
3876ff6d951SJohn Birrell val = (u_longlong_t)*((uint32_t *)addr);
3886ff6d951SJohn Birrell break;
3896ff6d951SJohn Birrell case sizeof (uint64_t):
3906ff6d951SJohn Birrell val = (u_longlong_t)*((uint64_t *)addr);
3916ff6d951SJohn Birrell break;
3926ff6d951SJohn Birrell case sizeof (uint64_t) * 2:
3936ff6d951SJohn Birrell pid = ((uint64_t *)(uintptr_t)addr)[0];
3946ff6d951SJohn Birrell val = ((uint64_t *)(uintptr_t)addr)[1];
3956ff6d951SJohn Birrell break;
3966ff6d951SJohn Birrell default:
3976ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_DMISMATCH));
3986ff6d951SJohn Birrell }
3996ff6d951SJohn Birrell
4006ff6d951SJohn Birrell if (pid == 0 && dtp->dt_vector == NULL && idp != NULL)
4016ff6d951SJohn Birrell pid = idp->di_id;
4026ff6d951SJohn Birrell
4036ff6d951SJohn Birrell do {
4046ff6d951SJohn Birrell n = len;
4056ff6d951SJohn Birrell s = alloca(n);
4061670a1c2SRui Paulo } while ((len = dtrace_uaddr2str(dtp, pid, val, s, n)) > n);
4076ff6d951SJohn Birrell
4086ff6d951SJohn Birrell return (dt_printf(dtp, fp, format, s));
4096ff6d951SJohn Birrell }
4106ff6d951SJohn Birrell
4116ff6d951SJohn Birrell /*ARGSUSED*/
4126ff6d951SJohn Birrell static int
pfprint_stack(dtrace_hdl_t * dtp,FILE * fp,const char * format,const dt_pfargd_t * pfd,const void * vaddr,size_t size,uint64_t normal)4136ff6d951SJohn Birrell pfprint_stack(dtrace_hdl_t *dtp, FILE *fp, const char *format,
4146ff6d951SJohn Birrell const dt_pfargd_t *pfd, const void *vaddr, size_t size, uint64_t normal)
4156ff6d951SJohn Birrell {
4166ff6d951SJohn Birrell int width;
4176ff6d951SJohn Birrell dtrace_optval_t saved = dtp->dt_options[DTRACEOPT_STACKINDENT];
4186ff6d951SJohn Birrell const dtrace_recdesc_t *rec = pfd->pfd_rec;
4196ff6d951SJohn Birrell caddr_t addr = (caddr_t)vaddr;
4206ff6d951SJohn Birrell int err = 0;
4216ff6d951SJohn Birrell
4226ff6d951SJohn Birrell /*
4236ff6d951SJohn Birrell * We have stashed the value of the STACKINDENT option, and we will
4246ff6d951SJohn Birrell * now override it for the purposes of formatting the stack. If the
4256ff6d951SJohn Birrell * field has been specified as left-aligned (i.e. (%-#), we set the
4266ff6d951SJohn Birrell * indentation to be the width. This is a slightly odd semantic, but
4276ff6d951SJohn Birrell * it's useful functionality -- and it's slightly odd to begin with to
4286ff6d951SJohn Birrell * be using a single format specifier to be formatting multiple lines
4296ff6d951SJohn Birrell * of text...
4306ff6d951SJohn Birrell */
4316ff6d951SJohn Birrell if (pfd->pfd_dynwidth < 0) {
4326ff6d951SJohn Birrell assert(pfd->pfd_flags & DT_PFCONV_DYNWIDTH);
4336ff6d951SJohn Birrell width = -pfd->pfd_dynwidth;
4346ff6d951SJohn Birrell } else if (pfd->pfd_flags & DT_PFCONV_LEFT) {
4356ff6d951SJohn Birrell width = pfd->pfd_dynwidth ? pfd->pfd_dynwidth : pfd->pfd_width;
4366ff6d951SJohn Birrell } else {
4376ff6d951SJohn Birrell width = 0;
4386ff6d951SJohn Birrell }
4396ff6d951SJohn Birrell
4406ff6d951SJohn Birrell dtp->dt_options[DTRACEOPT_STACKINDENT] = width;
4416ff6d951SJohn Birrell
4426ff6d951SJohn Birrell switch (rec->dtrd_action) {
4436ff6d951SJohn Birrell case DTRACEACT_USTACK:
4446ff6d951SJohn Birrell case DTRACEACT_JSTACK:
4456ff6d951SJohn Birrell err = dt_print_ustack(dtp, fp, format, addr, rec->dtrd_arg);
4466ff6d951SJohn Birrell break;
4476ff6d951SJohn Birrell
4486ff6d951SJohn Birrell case DTRACEACT_STACK:
4496ff6d951SJohn Birrell err = dt_print_stack(dtp, fp, format, addr, rec->dtrd_arg,
4506ff6d951SJohn Birrell rec->dtrd_size / rec->dtrd_arg);
4516ff6d951SJohn Birrell break;
4526ff6d951SJohn Birrell
4536ff6d951SJohn Birrell default:
4546ff6d951SJohn Birrell assert(0);
4556ff6d951SJohn Birrell }
4566ff6d951SJohn Birrell
4576ff6d951SJohn Birrell dtp->dt_options[DTRACEOPT_STACKINDENT] = saved;
4586ff6d951SJohn Birrell
4596ff6d951SJohn Birrell return (err);
4606ff6d951SJohn Birrell }
4616ff6d951SJohn Birrell
4626ff6d951SJohn Birrell /*ARGSUSED*/
4636ff6d951SJohn Birrell static int
pfprint_time(dtrace_hdl_t * dtp,FILE * fp,const char * format,const dt_pfargd_t * pfd,const void * addr,size_t size,uint64_t normal)4646ff6d951SJohn Birrell pfprint_time(dtrace_hdl_t *dtp, FILE *fp, const char *format,
4656ff6d951SJohn Birrell const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
4666ff6d951SJohn Birrell {
4676ff6d951SJohn Birrell char src[32], buf[32], *dst = buf;
4686ff6d951SJohn Birrell hrtime_t time = *((uint64_t *)addr);
4696ff6d951SJohn Birrell time_t sec = (time_t)(time / NANOSEC);
4706ff6d951SJohn Birrell int i;
4716ff6d951SJohn Birrell
4726ff6d951SJohn Birrell /*
4736ff6d951SJohn Birrell * ctime(3C) returns a string of the form "Dec 3 17:20:00 1973\n\0".
4746ff6d951SJohn Birrell * Below, we turn this into the canonical adb/mdb /[yY] format,
4756ff6d951SJohn Birrell * "1973 Dec 3 17:20:00".
4766ff6d951SJohn Birrell */
477bc96366cSSteven Hartland #ifdef illumos
4786ff6d951SJohn Birrell (void) ctime_r(&sec, src, sizeof (src));
47929f89dfcSJohn Birrell #else
48029f89dfcSJohn Birrell (void) ctime_r(&sec, src);
48129f89dfcSJohn Birrell #endif
4826ff6d951SJohn Birrell
4836ff6d951SJohn Birrell /*
4846ff6d951SJohn Birrell * Place the 4-digit year at the head of the string...
4856ff6d951SJohn Birrell */
4866ff6d951SJohn Birrell for (i = 20; i < 24; i++)
4876ff6d951SJohn Birrell *dst++ = src[i];
4886ff6d951SJohn Birrell
4896ff6d951SJohn Birrell /*
4906ff6d951SJohn Birrell * ...and follow it with the remainder (month, day, hh:mm:ss).
4916ff6d951SJohn Birrell */
4926ff6d951SJohn Birrell for (i = 3; i < 19; i++)
4936ff6d951SJohn Birrell *dst++ = src[i];
4946ff6d951SJohn Birrell
4956ff6d951SJohn Birrell *dst = '\0';
4966ff6d951SJohn Birrell return (dt_printf(dtp, fp, format, buf));
4976ff6d951SJohn Birrell }
4986ff6d951SJohn Birrell
4996ff6d951SJohn Birrell /*
5006ff6d951SJohn Birrell * This prints the time in RFC 822 standard form. This is useful for emitting
5016ff6d951SJohn Birrell * notions of time that are consumed by standard tools (e.g., as part of an
5026ff6d951SJohn Birrell * RSS feed).
5036ff6d951SJohn Birrell */
5046ff6d951SJohn Birrell /*ARGSUSED*/
5056ff6d951SJohn Birrell static int
pfprint_time822(dtrace_hdl_t * dtp,FILE * fp,const char * format,const dt_pfargd_t * pfd,const void * addr,size_t size,uint64_t normal)5066ff6d951SJohn Birrell pfprint_time822(dtrace_hdl_t *dtp, FILE *fp, const char *format,
5076ff6d951SJohn Birrell const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
5086ff6d951SJohn Birrell {
5096ff6d951SJohn Birrell hrtime_t time = *((uint64_t *)addr);
5106ff6d951SJohn Birrell time_t sec = (time_t)(time / NANOSEC);
5116ff6d951SJohn Birrell struct tm tm;
5126ff6d951SJohn Birrell char buf[64];
5136ff6d951SJohn Birrell
5146ff6d951SJohn Birrell (void) localtime_r(&sec, &tm);
5156ff6d951SJohn Birrell (void) strftime(buf, sizeof (buf), "%a, %d %b %G %T %Z", &tm);
5166ff6d951SJohn Birrell return (dt_printf(dtp, fp, format, buf));
5176ff6d951SJohn Birrell }
5186ff6d951SJohn Birrell
5196ff6d951SJohn Birrell /*ARGSUSED*/
5206ff6d951SJohn Birrell static int
pfprint_port(dtrace_hdl_t * dtp,FILE * fp,const char * format,const dt_pfargd_t * pfd,const void * addr,size_t size,uint64_t normal)5211670a1c2SRui Paulo pfprint_port(dtrace_hdl_t *dtp, FILE *fp, const char *format,
5221670a1c2SRui Paulo const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
5231670a1c2SRui Paulo {
5241670a1c2SRui Paulo uint16_t port = htons(*((uint16_t *)addr));
5251670a1c2SRui Paulo char buf[256];
5261670a1c2SRui Paulo struct servent *sv, res;
5271670a1c2SRui Paulo
528bc96366cSSteven Hartland #ifdef illumos
5291670a1c2SRui Paulo if ((sv = getservbyport_r(port, NULL, &res, buf, sizeof (buf))) != NULL)
5301670a1c2SRui Paulo #else
5311670a1c2SRui Paulo if (getservbyport_r(port, NULL, &res, buf, sizeof (buf), &sv) > 0)
5321670a1c2SRui Paulo #endif
5331670a1c2SRui Paulo return (dt_printf(dtp, fp, format, sv->s_name));
5341670a1c2SRui Paulo
5351670a1c2SRui Paulo (void) snprintf(buf, sizeof (buf), "%d", *((uint16_t *)addr));
5361670a1c2SRui Paulo return (dt_printf(dtp, fp, format, buf));
5371670a1c2SRui Paulo }
5381670a1c2SRui Paulo
5391670a1c2SRui Paulo /*ARGSUSED*/
5401670a1c2SRui Paulo static int
pfprint_inetaddr(dtrace_hdl_t * dtp,FILE * fp,const char * format,const dt_pfargd_t * pfd,const void * addr,size_t size,uint64_t normal)5411670a1c2SRui Paulo pfprint_inetaddr(dtrace_hdl_t *dtp, FILE *fp, const char *format,
5421670a1c2SRui Paulo const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
5431670a1c2SRui Paulo {
5441670a1c2SRui Paulo char *s = alloca(size + 1);
5451670a1c2SRui Paulo struct hostent *host, res;
5461670a1c2SRui Paulo char inetaddr[NS_IN6ADDRSZ];
5471670a1c2SRui Paulo char buf[1024];
5481670a1c2SRui Paulo int e;
5491670a1c2SRui Paulo
5501670a1c2SRui Paulo bcopy(addr, s, size);
5511670a1c2SRui Paulo s[size] = '\0';
5521670a1c2SRui Paulo
5531670a1c2SRui Paulo if (strchr(s, ':') == NULL && inet_pton(AF_INET, s, inetaddr) != -1) {
554bc96366cSSteven Hartland #ifdef illumos
5551670a1c2SRui Paulo if ((host = gethostbyaddr_r(inetaddr, NS_INADDRSZ,
5561670a1c2SRui Paulo AF_INET, &res, buf, sizeof (buf), &e)) != NULL)
5571670a1c2SRui Paulo #else
5581670a1c2SRui Paulo if (gethostbyaddr_r(inetaddr, NS_INADDRSZ,
5591670a1c2SRui Paulo AF_INET, &res, buf, sizeof (buf), &host, &e) > 0)
5601670a1c2SRui Paulo #endif
5611670a1c2SRui Paulo return (dt_printf(dtp, fp, format, host->h_name));
5621670a1c2SRui Paulo } else if (inet_pton(AF_INET6, s, inetaddr) != -1) {
5631670a1c2SRui Paulo if ((host = getipnodebyaddr(inetaddr, NS_IN6ADDRSZ,
5641670a1c2SRui Paulo AF_INET6, &e)) != NULL)
5651670a1c2SRui Paulo return (dt_printf(dtp, fp, format, host->h_name));
5661670a1c2SRui Paulo }
5671670a1c2SRui Paulo
5681670a1c2SRui Paulo return (dt_printf(dtp, fp, format, s));
5691670a1c2SRui Paulo }
5701670a1c2SRui Paulo
5711670a1c2SRui Paulo /*ARGSUSED*/
5721670a1c2SRui Paulo static int
pfprint_cstr(dtrace_hdl_t * dtp,FILE * fp,const char * format,const dt_pfargd_t * pfd,const void * addr,size_t size,uint64_t normal)5736ff6d951SJohn Birrell pfprint_cstr(dtrace_hdl_t *dtp, FILE *fp, const char *format,
5746ff6d951SJohn Birrell const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
5756ff6d951SJohn Birrell {
5766ff6d951SJohn Birrell char *s = alloca(size + 1);
5776ff6d951SJohn Birrell
5786ff6d951SJohn Birrell bcopy(addr, s, size);
5796ff6d951SJohn Birrell s[size] = '\0';
5806ff6d951SJohn Birrell return (dt_printf(dtp, fp, format, s));
5816ff6d951SJohn Birrell }
5826ff6d951SJohn Birrell
5836ff6d951SJohn Birrell /*ARGSUSED*/
5846ff6d951SJohn Birrell static int
pfprint_wstr(dtrace_hdl_t * dtp,FILE * fp,const char * format,const dt_pfargd_t * pfd,const void * addr,size_t size,uint64_t normal)5856ff6d951SJohn Birrell pfprint_wstr(dtrace_hdl_t *dtp, FILE *fp, const char *format,
5866ff6d951SJohn Birrell const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
5876ff6d951SJohn Birrell {
5886ff6d951SJohn Birrell wchar_t *ws = alloca(size + sizeof (wchar_t));
5896ff6d951SJohn Birrell
5906ff6d951SJohn Birrell bcopy(addr, ws, size);
5916ff6d951SJohn Birrell ws[size / sizeof (wchar_t)] = L'\0';
5926ff6d951SJohn Birrell return (dt_printf(dtp, fp, format, ws));
5936ff6d951SJohn Birrell }
5946ff6d951SJohn Birrell
5956ff6d951SJohn Birrell /*ARGSUSED*/
5966ff6d951SJohn Birrell static int
pfprint_estr(dtrace_hdl_t * dtp,FILE * fp,const char * format,const dt_pfargd_t * pfd,const void * addr,size_t size,uint64_t normal)5976ff6d951SJohn Birrell pfprint_estr(dtrace_hdl_t *dtp, FILE *fp, const char *format,
5986ff6d951SJohn Birrell const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
5996ff6d951SJohn Birrell {
6006ff6d951SJohn Birrell char *s;
6016ff6d951SJohn Birrell int n;
6026ff6d951SJohn Birrell
6036ff6d951SJohn Birrell if ((s = strchr2esc(addr, size)) == NULL)
6046ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_NOMEM));
6056ff6d951SJohn Birrell
6066ff6d951SJohn Birrell n = dt_printf(dtp, fp, format, s);
6076ff6d951SJohn Birrell free(s);
6086ff6d951SJohn Birrell return (n);
6096ff6d951SJohn Birrell }
6106ff6d951SJohn Birrell
6116ff6d951SJohn Birrell static int
pfprint_echr(dtrace_hdl_t * dtp,FILE * fp,const char * format,const dt_pfargd_t * pfd,const void * addr,size_t size,uint64_t normal)6126ff6d951SJohn Birrell pfprint_echr(dtrace_hdl_t *dtp, FILE *fp, const char *format,
6136ff6d951SJohn Birrell const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
6146ff6d951SJohn Birrell {
6156ff6d951SJohn Birrell char c;
6166ff6d951SJohn Birrell
6176ff6d951SJohn Birrell switch (size) {
6186ff6d951SJohn Birrell case sizeof (int8_t):
6196ff6d951SJohn Birrell c = *(int8_t *)addr;
6206ff6d951SJohn Birrell break;
6216ff6d951SJohn Birrell case sizeof (int16_t):
6226ff6d951SJohn Birrell c = *(int16_t *)addr;
6236ff6d951SJohn Birrell break;
6246ff6d951SJohn Birrell case sizeof (int32_t):
6256ff6d951SJohn Birrell c = *(int32_t *)addr;
6266ff6d951SJohn Birrell break;
6276ff6d951SJohn Birrell default:
6286ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_DMISMATCH));
6296ff6d951SJohn Birrell }
6306ff6d951SJohn Birrell
6316ff6d951SJohn Birrell return (pfprint_estr(dtp, fp, format, pfd, &c, 1, normal));
6326ff6d951SJohn Birrell }
6336ff6d951SJohn Birrell
6346ff6d951SJohn Birrell /*ARGSUSED*/
6356ff6d951SJohn Birrell static int
pfprint_pct(dtrace_hdl_t * dtp,FILE * fp,const char * format,const dt_pfargd_t * pfd,const void * addr,size_t size,uint64_t normal)6366ff6d951SJohn Birrell pfprint_pct(dtrace_hdl_t *dtp, FILE *fp, const char *format,
6376ff6d951SJohn Birrell const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
6386ff6d951SJohn Birrell {
6396ff6d951SJohn Birrell return (dt_printf(dtp, fp, "%%"));
6406ff6d951SJohn Birrell }
6416ff6d951SJohn Birrell
6426ff6d951SJohn Birrell static const char pfproto_xint[] = "char, short, int, long, or long long";
6436ff6d951SJohn Birrell static const char pfproto_csi[] = "char, short, or int";
6446ff6d951SJohn Birrell static const char pfproto_fp[] = "float, double, or long double";
6456ff6d951SJohn Birrell static const char pfproto_addr[] = "pointer or integer";
6466ff6d951SJohn Birrell static const char pfproto_uaddr[] =
6476ff6d951SJohn Birrell "pointer or integer (with -p/-c) or _usymaddr (without -p/-c)";
6486ff6d951SJohn Birrell static const char pfproto_cstr[] = "char [] or string (or use stringof)";
6496ff6d951SJohn Birrell static const char pfproto_wstr[] = "wchar_t []";
6506ff6d951SJohn Birrell
6516ff6d951SJohn Birrell /*
6526ff6d951SJohn Birrell * Printf format conversion dictionary. This table should match the set of
6536ff6d951SJohn Birrell * conversions offered by printf(3C), as well as some additional extensions.
6546ff6d951SJohn Birrell * The second parameter is an ASCII string which is either an actual type
6556ff6d951SJohn Birrell * name we should look up (if pfcheck_type is specified), or just a descriptive
6566ff6d951SJohn Birrell * string of the types expected for use in error messages.
6576ff6d951SJohn Birrell */
6586ff6d951SJohn Birrell static const dt_pfconv_t _dtrace_conversions[] = {
6596ff6d951SJohn Birrell { "a", "s", pfproto_addr, pfcheck_kaddr, pfprint_addr },
6606ff6d951SJohn Birrell { "A", "s", pfproto_uaddr, pfcheck_uaddr, pfprint_uaddr },
6616ff6d951SJohn Birrell { "c", "c", pfproto_csi, pfcheck_csi, pfprint_sint },
6626ff6d951SJohn Birrell { "C", "s", pfproto_csi, pfcheck_csi, pfprint_echr },
6636ff6d951SJohn Birrell { "d", "d", pfproto_xint, pfcheck_dint, pfprint_dint },
6646ff6d951SJohn Birrell { "e", "e", pfproto_fp, pfcheck_fp, pfprint_fp },
6656ff6d951SJohn Birrell { "E", "E", pfproto_fp, pfcheck_fp, pfprint_fp },
6666ff6d951SJohn Birrell { "f", "f", pfproto_fp, pfcheck_fp, pfprint_fp },
6676ff6d951SJohn Birrell { "g", "g", pfproto_fp, pfcheck_fp, pfprint_fp },
6686ff6d951SJohn Birrell { "G", "G", pfproto_fp, pfcheck_fp, pfprint_fp },
6696ff6d951SJohn Birrell { "hd", "d", "short", pfcheck_type, pfprint_sint },
6706ff6d951SJohn Birrell { "hi", "i", "short", pfcheck_type, pfprint_sint },
6716ff6d951SJohn Birrell { "ho", "o", "unsigned short", pfcheck_type, pfprint_uint },
6726ff6d951SJohn Birrell { "hu", "u", "unsigned short", pfcheck_type, pfprint_uint },
6736ff6d951SJohn Birrell { "hx", "x", "short", pfcheck_xshort, pfprint_uint },
6746ff6d951SJohn Birrell { "hX", "X", "short", pfcheck_xshort, pfprint_uint },
675a98ff317SPedro F. Giffuni { "i", "i", pfproto_xint, pfcheck_xint, pfprint_sint },
6761670a1c2SRui Paulo { "I", "s", pfproto_cstr, pfcheck_str, pfprint_inetaddr },
6776ff6d951SJohn Birrell { "k", "s", "stack", pfcheck_stack, pfprint_stack },
6786ff6d951SJohn Birrell { "lc", "lc", "int", pfcheck_type, pfprint_sint }, /* a.k.a. wint_t */
6796ff6d951SJohn Birrell { "ld", "d", "long", pfcheck_type, pfprint_sint },
6806ff6d951SJohn Birrell { "li", "i", "long", pfcheck_type, pfprint_sint },
6816ff6d951SJohn Birrell { "lo", "o", "unsigned long", pfcheck_type, pfprint_uint },
6826ff6d951SJohn Birrell { "lu", "u", "unsigned long", pfcheck_type, pfprint_uint },
6836ff6d951SJohn Birrell { "ls", "ls", pfproto_wstr, pfcheck_wstr, pfprint_wstr },
6846ff6d951SJohn Birrell { "lx", "x", "long", pfcheck_xlong, pfprint_uint },
6856ff6d951SJohn Birrell { "lX", "X", "long", pfcheck_xlong, pfprint_uint },
6866ff6d951SJohn Birrell { "lld", "d", "long long", pfcheck_type, pfprint_sint },
6876ff6d951SJohn Birrell { "lli", "i", "long long", pfcheck_type, pfprint_sint },
6886ff6d951SJohn Birrell { "llo", "o", "unsigned long long", pfcheck_type, pfprint_uint },
6896ff6d951SJohn Birrell { "llu", "u", "unsigned long long", pfcheck_type, pfprint_uint },
6906ff6d951SJohn Birrell { "llx", "x", "long long", pfcheck_xlonglong, pfprint_uint },
6916ff6d951SJohn Birrell { "llX", "X", "long long", pfcheck_xlonglong, pfprint_uint },
6926ff6d951SJohn Birrell { "Le", "e", "long double", pfcheck_type, pfprint_fp },
6936ff6d951SJohn Birrell { "LE", "E", "long double", pfcheck_type, pfprint_fp },
6946ff6d951SJohn Birrell { "Lf", "f", "long double", pfcheck_type, pfprint_fp },
6956ff6d951SJohn Birrell { "Lg", "g", "long double", pfcheck_type, pfprint_fp },
6966ff6d951SJohn Birrell { "LG", "G", "long double", pfcheck_type, pfprint_fp },
6976ff6d951SJohn Birrell { "o", "o", pfproto_xint, pfcheck_xint, pfprint_uint },
6986ff6d951SJohn Birrell { "p", "x", pfproto_addr, pfcheck_addr, pfprint_uint },
6991670a1c2SRui Paulo { "P", "s", "uint16_t", pfcheck_type, pfprint_port },
7006ff6d951SJohn Birrell { "s", "s", "char [] or string (or use stringof)", pfcheck_str, pfprint_cstr },
7016ff6d951SJohn Birrell { "S", "s", pfproto_cstr, pfcheck_str, pfprint_estr },
7026ff6d951SJohn Birrell { "T", "s", "int64_t", pfcheck_time, pfprint_time822 },
7036ff6d951SJohn Birrell { "u", "u", pfproto_xint, pfcheck_xint, pfprint_uint },
704bc96366cSSteven Hartland #ifdef illumos
7056ff6d951SJohn Birrell { "wc", "wc", "int", pfcheck_type, pfprint_sint }, /* a.k.a. wchar_t */
7066ff6d951SJohn Birrell { "ws", "ws", pfproto_wstr, pfcheck_wstr, pfprint_wstr },
70728af9281SMark Johnston #else
70828af9281SMark Johnston { "wc", "lc", "int", pfcheck_type, pfprint_sint }, /* a.k.a. wchar_t */
70928af9281SMark Johnston { "ws", "ls", pfproto_wstr, pfcheck_wstr, pfprint_wstr },
71028af9281SMark Johnston #endif
7116ff6d951SJohn Birrell { "x", "x", pfproto_xint, pfcheck_xint, pfprint_uint },
7126ff6d951SJohn Birrell { "X", "X", pfproto_xint, pfcheck_xint, pfprint_uint },
7136ff6d951SJohn Birrell { "Y", "s", "int64_t", pfcheck_time, pfprint_time },
7146ff6d951SJohn Birrell { "%", "%", "void", pfcheck_type, pfprint_pct },
7156ff6d951SJohn Birrell { NULL, NULL, NULL, NULL, NULL }
7166ff6d951SJohn Birrell };
7176ff6d951SJohn Birrell
7186ff6d951SJohn Birrell int
dt_pfdict_create(dtrace_hdl_t * dtp)7196ff6d951SJohn Birrell dt_pfdict_create(dtrace_hdl_t *dtp)
7206ff6d951SJohn Birrell {
7216ff6d951SJohn Birrell uint_t n = _dtrace_strbuckets;
7226ff6d951SJohn Birrell const dt_pfconv_t *pfd;
7236ff6d951SJohn Birrell dt_pfdict_t *pdi;
7246ff6d951SJohn Birrell
7256ff6d951SJohn Birrell if ((pdi = malloc(sizeof (dt_pfdict_t))) == NULL ||
7266ff6d951SJohn Birrell (pdi->pdi_buckets = malloc(sizeof (dt_pfconv_t *) * n)) == NULL) {
7276ff6d951SJohn Birrell free(pdi);
7286ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_NOMEM));
7296ff6d951SJohn Birrell }
7306ff6d951SJohn Birrell
7316ff6d951SJohn Birrell dtp->dt_pfdict = pdi;
7326ff6d951SJohn Birrell bzero(pdi->pdi_buckets, sizeof (dt_pfconv_t *) * n);
7336ff6d951SJohn Birrell pdi->pdi_nbuckets = n;
7346ff6d951SJohn Birrell
7356ff6d951SJohn Birrell for (pfd = _dtrace_conversions; pfd->pfc_name != NULL; pfd++) {
7366ff6d951SJohn Birrell dtrace_typeinfo_t dtt;
7376ff6d951SJohn Birrell dt_pfconv_t *pfc;
7386ff6d951SJohn Birrell uint_t h;
7396ff6d951SJohn Birrell
7406ff6d951SJohn Birrell if ((pfc = malloc(sizeof (dt_pfconv_t))) == NULL) {
7416ff6d951SJohn Birrell dt_pfdict_destroy(dtp);
7426ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_NOMEM));
7436ff6d951SJohn Birrell }
7446ff6d951SJohn Birrell
7456ff6d951SJohn Birrell bcopy(pfd, pfc, sizeof (dt_pfconv_t));
7466ff6d951SJohn Birrell h = dt_strtab_hash(pfc->pfc_name, NULL) % n;
7476ff6d951SJohn Birrell pfc->pfc_next = pdi->pdi_buckets[h];
7486ff6d951SJohn Birrell pdi->pdi_buckets[h] = pfc;
7496ff6d951SJohn Birrell
7506ff6d951SJohn Birrell dtt.dtt_ctfp = NULL;
7516ff6d951SJohn Birrell dtt.dtt_type = CTF_ERR;
7526ff6d951SJohn Birrell
7536ff6d951SJohn Birrell /*
7546ff6d951SJohn Birrell * The "D" container or its parent must contain a definition of
7556ff6d951SJohn Birrell * any type referenced by a printf conversion. If none can be
7566ff6d951SJohn Birrell * found, we fail to initialize the printf dictionary.
7576ff6d951SJohn Birrell */
7586ff6d951SJohn Birrell if (pfc->pfc_check == &pfcheck_type && dtrace_lookup_by_type(
7596ff6d951SJohn Birrell dtp, DTRACE_OBJ_DDEFS, pfc->pfc_tstr, &dtt) != 0) {
7606ff6d951SJohn Birrell dt_pfdict_destroy(dtp);
7616ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_NOCONV));
7626ff6d951SJohn Birrell }
7636ff6d951SJohn Birrell
7646ff6d951SJohn Birrell pfc->pfc_dctfp = dtt.dtt_ctfp;
7656ff6d951SJohn Birrell pfc->pfc_dtype = dtt.dtt_type;
7666ff6d951SJohn Birrell
7676ff6d951SJohn Birrell /*
7686ff6d951SJohn Birrell * The "C" container may contain an alternate definition of an
7696ff6d951SJohn Birrell * explicit conversion type. If it does, use it; otherwise
7706ff6d951SJohn Birrell * just set pfc_ctype to pfc_dtype so it is always valid.
7716ff6d951SJohn Birrell */
7726ff6d951SJohn Birrell if (pfc->pfc_check == &pfcheck_type && dtrace_lookup_by_type(
7736ff6d951SJohn Birrell dtp, DTRACE_OBJ_CDEFS, pfc->pfc_tstr, &dtt) == 0) {
7746ff6d951SJohn Birrell pfc->pfc_cctfp = dtt.dtt_ctfp;
7756ff6d951SJohn Birrell pfc->pfc_ctype = dtt.dtt_type;
7766ff6d951SJohn Birrell } else {
7776ff6d951SJohn Birrell pfc->pfc_cctfp = pfc->pfc_dctfp;
7786ff6d951SJohn Birrell pfc->pfc_ctype = pfc->pfc_dtype;
7796ff6d951SJohn Birrell }
7806ff6d951SJohn Birrell
7816ff6d951SJohn Birrell if (pfc->pfc_check == NULL || pfc->pfc_print == NULL ||
7826ff6d951SJohn Birrell pfc->pfc_ofmt == NULL || pfc->pfc_tstr == NULL) {
7836ff6d951SJohn Birrell dt_pfdict_destroy(dtp);
7846ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_BADCONV));
7856ff6d951SJohn Birrell }
7866ff6d951SJohn Birrell
7876ff6d951SJohn Birrell dt_dprintf("loaded printf conversion %%%s\n", pfc->pfc_name);
7886ff6d951SJohn Birrell }
7896ff6d951SJohn Birrell
7906ff6d951SJohn Birrell return (0);
7916ff6d951SJohn Birrell }
7926ff6d951SJohn Birrell
7936ff6d951SJohn Birrell void
dt_pfdict_destroy(dtrace_hdl_t * dtp)7946ff6d951SJohn Birrell dt_pfdict_destroy(dtrace_hdl_t *dtp)
7956ff6d951SJohn Birrell {
7966ff6d951SJohn Birrell dt_pfdict_t *pdi = dtp->dt_pfdict;
7976ff6d951SJohn Birrell dt_pfconv_t *pfc, *nfc;
7986ff6d951SJohn Birrell uint_t i;
7996ff6d951SJohn Birrell
8006ff6d951SJohn Birrell if (pdi == NULL)
8016ff6d951SJohn Birrell return;
8026ff6d951SJohn Birrell
8036ff6d951SJohn Birrell for (i = 0; i < pdi->pdi_nbuckets; i++) {
8046ff6d951SJohn Birrell for (pfc = pdi->pdi_buckets[i]; pfc != NULL; pfc = nfc) {
8056ff6d951SJohn Birrell nfc = pfc->pfc_next;
8066ff6d951SJohn Birrell free(pfc);
8076ff6d951SJohn Birrell }
8086ff6d951SJohn Birrell }
8096ff6d951SJohn Birrell
8106ff6d951SJohn Birrell free(pdi->pdi_buckets);
8116ff6d951SJohn Birrell free(pdi);
8126ff6d951SJohn Birrell dtp->dt_pfdict = NULL;
8136ff6d951SJohn Birrell }
8146ff6d951SJohn Birrell
8156ff6d951SJohn Birrell static const dt_pfconv_t *
dt_pfdict_lookup(dtrace_hdl_t * dtp,const char * name)8166ff6d951SJohn Birrell dt_pfdict_lookup(dtrace_hdl_t *dtp, const char *name)
8176ff6d951SJohn Birrell {
8186ff6d951SJohn Birrell dt_pfdict_t *pdi = dtp->dt_pfdict;
8196ff6d951SJohn Birrell uint_t h = dt_strtab_hash(name, NULL) % pdi->pdi_nbuckets;
8206ff6d951SJohn Birrell const dt_pfconv_t *pfc;
8216ff6d951SJohn Birrell
8226ff6d951SJohn Birrell for (pfc = pdi->pdi_buckets[h]; pfc != NULL; pfc = pfc->pfc_next) {
8236ff6d951SJohn Birrell if (strcmp(pfc->pfc_name, name) == 0)
8246ff6d951SJohn Birrell break;
8256ff6d951SJohn Birrell }
8266ff6d951SJohn Birrell
8276ff6d951SJohn Birrell return (pfc);
8286ff6d951SJohn Birrell }
8296ff6d951SJohn Birrell
8306ff6d951SJohn Birrell static dt_pfargv_t *
dt_printf_error(dtrace_hdl_t * dtp,int err)8316ff6d951SJohn Birrell dt_printf_error(dtrace_hdl_t *dtp, int err)
8326ff6d951SJohn Birrell {
8336ff6d951SJohn Birrell if (yypcb != NULL)
8346ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, err);
8356ff6d951SJohn Birrell
8366ff6d951SJohn Birrell (void) dt_set_errno(dtp, err);
8376ff6d951SJohn Birrell return (NULL);
8386ff6d951SJohn Birrell }
8396ff6d951SJohn Birrell
8406ff6d951SJohn Birrell dt_pfargv_t *
dt_printf_create(dtrace_hdl_t * dtp,const char * s)8416ff6d951SJohn Birrell dt_printf_create(dtrace_hdl_t *dtp, const char *s)
8426ff6d951SJohn Birrell {
8436ff6d951SJohn Birrell dt_pfargd_t *pfd, *nfd = NULL;
8446ff6d951SJohn Birrell dt_pfargv_t *pfv;
8456ff6d951SJohn Birrell const char *p, *q;
8466ff6d951SJohn Birrell char *format;
8476ff6d951SJohn Birrell
8486ff6d951SJohn Birrell if ((pfv = malloc(sizeof (dt_pfargv_t))) == NULL ||
8496ff6d951SJohn Birrell (format = strdup(s)) == NULL) {
8506ff6d951SJohn Birrell free(pfv);
8516ff6d951SJohn Birrell return (dt_printf_error(dtp, EDT_NOMEM));
8526ff6d951SJohn Birrell }
8536ff6d951SJohn Birrell
8546ff6d951SJohn Birrell pfv->pfv_format = format;
8556ff6d951SJohn Birrell pfv->pfv_argv = NULL;
8566ff6d951SJohn Birrell pfv->pfv_argc = 0;
8576ff6d951SJohn Birrell pfv->pfv_flags = 0;
8586ff6d951SJohn Birrell pfv->pfv_dtp = dtp;
8596ff6d951SJohn Birrell
8606ff6d951SJohn Birrell for (q = format; (p = strchr(q, '%')) != NULL; q = *p ? p + 1 : p) {
8616ff6d951SJohn Birrell uint_t namelen = 0;
8626ff6d951SJohn Birrell int digits = 0;
8636ff6d951SJohn Birrell int dot = 0;
8646ff6d951SJohn Birrell
8656ff6d951SJohn Birrell char name[8];
8666ff6d951SJohn Birrell char c;
8676ff6d951SJohn Birrell int n;
8686ff6d951SJohn Birrell
8696ff6d951SJohn Birrell if ((pfd = malloc(sizeof (dt_pfargd_t))) == NULL) {
8706ff6d951SJohn Birrell dt_printf_destroy(pfv);
8716ff6d951SJohn Birrell return (dt_printf_error(dtp, EDT_NOMEM));
8726ff6d951SJohn Birrell }
8736ff6d951SJohn Birrell
8746ff6d951SJohn Birrell if (pfv->pfv_argv != NULL)
8756ff6d951SJohn Birrell nfd->pfd_next = pfd;
8766ff6d951SJohn Birrell else
8776ff6d951SJohn Birrell pfv->pfv_argv = pfd;
8786ff6d951SJohn Birrell
8796ff6d951SJohn Birrell bzero(pfd, sizeof (dt_pfargd_t));
8806ff6d951SJohn Birrell pfv->pfv_argc++;
8816ff6d951SJohn Birrell nfd = pfd;
8826ff6d951SJohn Birrell
8836ff6d951SJohn Birrell if (p > q) {
8846ff6d951SJohn Birrell pfd->pfd_preflen = (size_t)(p - q);
8856ff6d951SJohn Birrell pfd->pfd_prefix = q;
8866ff6d951SJohn Birrell }
8876ff6d951SJohn Birrell
8886ff6d951SJohn Birrell fmt_switch:
8896ff6d951SJohn Birrell switch (c = *++p) {
8906ff6d951SJohn Birrell case '0': case '1': case '2': case '3': case '4':
8916ff6d951SJohn Birrell case '5': case '6': case '7': case '8': case '9':
8926ff6d951SJohn Birrell if (dot == 0 && digits == 0 && c == '0') {
8936ff6d951SJohn Birrell pfd->pfd_flags |= DT_PFCONV_ZPAD;
8946ff6d951SJohn Birrell pfd->pfd_flags &= ~DT_PFCONV_LEFT;
8956ff6d951SJohn Birrell goto fmt_switch;
8966ff6d951SJohn Birrell }
8976ff6d951SJohn Birrell
8986ff6d951SJohn Birrell for (n = 0; isdigit(c); c = *++p)
8996ff6d951SJohn Birrell n = n * 10 + c - '0';
9006ff6d951SJohn Birrell
9016ff6d951SJohn Birrell if (dot)
9026ff6d951SJohn Birrell pfd->pfd_prec = n;
9036ff6d951SJohn Birrell else
9046ff6d951SJohn Birrell pfd->pfd_width = n;
9056ff6d951SJohn Birrell
9066ff6d951SJohn Birrell p--;
9076ff6d951SJohn Birrell digits++;
9086ff6d951SJohn Birrell goto fmt_switch;
9096ff6d951SJohn Birrell
9106ff6d951SJohn Birrell case '#':
9116ff6d951SJohn Birrell pfd->pfd_flags |= DT_PFCONV_ALT;
9126ff6d951SJohn Birrell goto fmt_switch;
9136ff6d951SJohn Birrell
9146ff6d951SJohn Birrell case '*':
9156ff6d951SJohn Birrell n = dot ? DT_PFCONV_DYNPREC : DT_PFCONV_DYNWIDTH;
9166ff6d951SJohn Birrell
9176ff6d951SJohn Birrell if (pfd->pfd_flags & n) {
9186ff6d951SJohn Birrell yywarn("format conversion #%u has more than "
9196ff6d951SJohn Birrell "one '*' specified for the output %s\n",
9206ff6d951SJohn Birrell pfv->pfv_argc, n ? "precision" : "width");
9216ff6d951SJohn Birrell
9226ff6d951SJohn Birrell dt_printf_destroy(pfv);
9236ff6d951SJohn Birrell return (dt_printf_error(dtp, EDT_COMPILER));
9246ff6d951SJohn Birrell }
9256ff6d951SJohn Birrell
9266ff6d951SJohn Birrell pfd->pfd_flags |= n;
9276ff6d951SJohn Birrell goto fmt_switch;
9286ff6d951SJohn Birrell
9296ff6d951SJohn Birrell case '+':
9306ff6d951SJohn Birrell pfd->pfd_flags |= DT_PFCONV_SPOS;
9316ff6d951SJohn Birrell goto fmt_switch;
9326ff6d951SJohn Birrell
9336ff6d951SJohn Birrell case '-':
9346ff6d951SJohn Birrell pfd->pfd_flags |= DT_PFCONV_LEFT;
9356ff6d951SJohn Birrell pfd->pfd_flags &= ~DT_PFCONV_ZPAD;
9366ff6d951SJohn Birrell goto fmt_switch;
9376ff6d951SJohn Birrell
9386ff6d951SJohn Birrell case '.':
9396ff6d951SJohn Birrell if (dot++ != 0) {
9406ff6d951SJohn Birrell yywarn("format conversion #%u has more than "
9416ff6d951SJohn Birrell "one '.' specified\n", pfv->pfv_argc);
9426ff6d951SJohn Birrell
9436ff6d951SJohn Birrell dt_printf_destroy(pfv);
9446ff6d951SJohn Birrell return (dt_printf_error(dtp, EDT_COMPILER));
9456ff6d951SJohn Birrell }
9466ff6d951SJohn Birrell digits = 0;
9476ff6d951SJohn Birrell goto fmt_switch;
9486ff6d951SJohn Birrell
9496ff6d951SJohn Birrell case '?':
9506ff6d951SJohn Birrell if (dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_LP64)
9516ff6d951SJohn Birrell pfd->pfd_width = 16;
9526ff6d951SJohn Birrell else
9536ff6d951SJohn Birrell pfd->pfd_width = 8;
9546ff6d951SJohn Birrell goto fmt_switch;
9556ff6d951SJohn Birrell
9566ff6d951SJohn Birrell case '@':
9576ff6d951SJohn Birrell pfd->pfd_flags |= DT_PFCONV_AGG;
9586ff6d951SJohn Birrell goto fmt_switch;
9596ff6d951SJohn Birrell
9606ff6d951SJohn Birrell case '\'':
9616ff6d951SJohn Birrell pfd->pfd_flags |= DT_PFCONV_GROUP;
9626ff6d951SJohn Birrell goto fmt_switch;
9636ff6d951SJohn Birrell
9646ff6d951SJohn Birrell case ' ':
9656ff6d951SJohn Birrell pfd->pfd_flags |= DT_PFCONV_SPACE;
9666ff6d951SJohn Birrell goto fmt_switch;
9676ff6d951SJohn Birrell
9686ff6d951SJohn Birrell case '$':
9696ff6d951SJohn Birrell yywarn("format conversion #%u uses unsupported "
9706ff6d951SJohn Birrell "positional format (%%n$)\n", pfv->pfv_argc);
9716ff6d951SJohn Birrell
9726ff6d951SJohn Birrell dt_printf_destroy(pfv);
9736ff6d951SJohn Birrell return (dt_printf_error(dtp, EDT_COMPILER));
9746ff6d951SJohn Birrell
9756ff6d951SJohn Birrell case '%':
9766ff6d951SJohn Birrell if (p[-1] == '%')
9776ff6d951SJohn Birrell goto default_lbl; /* if %% then use "%" conv */
9786ff6d951SJohn Birrell
9796ff6d951SJohn Birrell yywarn("format conversion #%u cannot be combined "
9806ff6d951SJohn Birrell "with other format flags: %%%%\n", pfv->pfv_argc);
9816ff6d951SJohn Birrell
9826ff6d951SJohn Birrell dt_printf_destroy(pfv);
9836ff6d951SJohn Birrell return (dt_printf_error(dtp, EDT_COMPILER));
9846ff6d951SJohn Birrell
9856ff6d951SJohn Birrell case '\0':
9866ff6d951SJohn Birrell yywarn("format conversion #%u name expected before "
9876ff6d951SJohn Birrell "end of format string\n", pfv->pfv_argc);
9886ff6d951SJohn Birrell
9896ff6d951SJohn Birrell dt_printf_destroy(pfv);
9906ff6d951SJohn Birrell return (dt_printf_error(dtp, EDT_COMPILER));
9916ff6d951SJohn Birrell
9926ff6d951SJohn Birrell case 'h':
9936ff6d951SJohn Birrell case 'l':
9946ff6d951SJohn Birrell case 'L':
9956ff6d951SJohn Birrell case 'w':
9966ff6d951SJohn Birrell if (namelen < sizeof (name) - 2)
9976ff6d951SJohn Birrell name[namelen++] = c;
9986ff6d951SJohn Birrell goto fmt_switch;
9996ff6d951SJohn Birrell
10006ff6d951SJohn Birrell default_lbl:
10016ff6d951SJohn Birrell default:
10026ff6d951SJohn Birrell name[namelen++] = c;
10036ff6d951SJohn Birrell name[namelen] = '\0';
10046ff6d951SJohn Birrell }
10056ff6d951SJohn Birrell
10066ff6d951SJohn Birrell pfd->pfd_conv = dt_pfdict_lookup(dtp, name);
10076ff6d951SJohn Birrell
10086ff6d951SJohn Birrell if (pfd->pfd_conv == NULL) {
10096ff6d951SJohn Birrell yywarn("format conversion #%u is undefined: %%%s\n",
10106ff6d951SJohn Birrell pfv->pfv_argc, name);
10116ff6d951SJohn Birrell dt_printf_destroy(pfv);
10126ff6d951SJohn Birrell return (dt_printf_error(dtp, EDT_COMPILER));
10136ff6d951SJohn Birrell }
10146ff6d951SJohn Birrell }
10156ff6d951SJohn Birrell
10166ff6d951SJohn Birrell if (*q != '\0' || *format == '\0') {
10176ff6d951SJohn Birrell if ((pfd = malloc(sizeof (dt_pfargd_t))) == NULL) {
10186ff6d951SJohn Birrell dt_printf_destroy(pfv);
10196ff6d951SJohn Birrell return (dt_printf_error(dtp, EDT_NOMEM));
10206ff6d951SJohn Birrell }
10216ff6d951SJohn Birrell
10226ff6d951SJohn Birrell if (pfv->pfv_argv != NULL)
10236ff6d951SJohn Birrell nfd->pfd_next = pfd;
10246ff6d951SJohn Birrell else
10256ff6d951SJohn Birrell pfv->pfv_argv = pfd;
10266ff6d951SJohn Birrell
10276ff6d951SJohn Birrell bzero(pfd, sizeof (dt_pfargd_t));
10286ff6d951SJohn Birrell pfv->pfv_argc++;
10296ff6d951SJohn Birrell
10306ff6d951SJohn Birrell pfd->pfd_prefix = q;
10316ff6d951SJohn Birrell pfd->pfd_preflen = strlen(q);
10326ff6d951SJohn Birrell }
10336ff6d951SJohn Birrell
10346ff6d951SJohn Birrell return (pfv);
10356ff6d951SJohn Birrell }
10366ff6d951SJohn Birrell
10376ff6d951SJohn Birrell void
dt_printf_destroy(dt_pfargv_t * pfv)10386ff6d951SJohn Birrell dt_printf_destroy(dt_pfargv_t *pfv)
10396ff6d951SJohn Birrell {
10406ff6d951SJohn Birrell dt_pfargd_t *pfd, *nfd;
10416ff6d951SJohn Birrell
10426ff6d951SJohn Birrell for (pfd = pfv->pfv_argv; pfd != NULL; pfd = nfd) {
10436ff6d951SJohn Birrell nfd = pfd->pfd_next;
10446ff6d951SJohn Birrell free(pfd);
10456ff6d951SJohn Birrell }
10466ff6d951SJohn Birrell
10476ff6d951SJohn Birrell free(pfv->pfv_format);
10486ff6d951SJohn Birrell free(pfv);
10496ff6d951SJohn Birrell }
10506ff6d951SJohn Birrell
10516ff6d951SJohn Birrell void
dt_printf_validate(dt_pfargv_t * pfv,uint_t flags,dt_ident_t * idp,int foff,dtrace_actkind_t kind,dt_node_t * dnp)10526ff6d951SJohn Birrell dt_printf_validate(dt_pfargv_t *pfv, uint_t flags,
10536ff6d951SJohn Birrell dt_ident_t *idp, int foff, dtrace_actkind_t kind, dt_node_t *dnp)
10546ff6d951SJohn Birrell {
10556ff6d951SJohn Birrell dt_pfargd_t *pfd = pfv->pfv_argv;
10566ff6d951SJohn Birrell const char *func = idp->di_name;
10576ff6d951SJohn Birrell
10586ff6d951SJohn Birrell char n[DT_TYPE_NAMELEN];
10596ff6d951SJohn Birrell dtrace_typeinfo_t dtt;
10606ff6d951SJohn Birrell const char *aggtype;
10616ff6d951SJohn Birrell dt_node_t aggnode;
10626ff6d951SJohn Birrell int i, j;
10636ff6d951SJohn Birrell
10646ff6d951SJohn Birrell if (pfv->pfv_format[0] == '\0') {
10656ff6d951SJohn Birrell xyerror(D_PRINTF_FMT_EMPTY,
10666ff6d951SJohn Birrell "%s( ) format string is empty\n", func);
10676ff6d951SJohn Birrell }
10686ff6d951SJohn Birrell
10696ff6d951SJohn Birrell pfv->pfv_flags = flags;
10706ff6d951SJohn Birrell
10716ff6d951SJohn Birrell /*
10726ff6d951SJohn Birrell * We fake up a parse node representing the type that can be used with
10736ff6d951SJohn Birrell * an aggregation result conversion, which -- for all but count() --
10746ff6d951SJohn Birrell * is a signed quantity.
10756ff6d951SJohn Birrell */
10766ff6d951SJohn Birrell if (kind != DTRACEAGG_COUNT)
10776ff6d951SJohn Birrell aggtype = "int64_t";
10786ff6d951SJohn Birrell else
10796ff6d951SJohn Birrell aggtype = "uint64_t";
10806ff6d951SJohn Birrell
10816ff6d951SJohn Birrell if (dt_type_lookup(aggtype, &dtt) != 0)
10826ff6d951SJohn Birrell xyerror(D_TYPE_ERR, "failed to lookup agg type %s\n", aggtype);
10836ff6d951SJohn Birrell
10846ff6d951SJohn Birrell bzero(&aggnode, sizeof (aggnode));
10858e648814SRui Paulo dt_node_type_assign(&aggnode, dtt.dtt_ctfp, dtt.dtt_type, B_FALSE);
10866ff6d951SJohn Birrell
10876ff6d951SJohn Birrell for (i = 0, j = 0; i < pfv->pfv_argc; i++, pfd = pfd->pfd_next) {
10886ff6d951SJohn Birrell const dt_pfconv_t *pfc = pfd->pfd_conv;
10896ff6d951SJohn Birrell const char *dyns[2];
10906ff6d951SJohn Birrell int dync = 0;
10916ff6d951SJohn Birrell
10926ff6d951SJohn Birrell char vname[64];
10936ff6d951SJohn Birrell dt_node_t *vnp;
10946ff6d951SJohn Birrell
10956ff6d951SJohn Birrell if (pfc == NULL)
10966ff6d951SJohn Birrell continue; /* no checking if argd is just a prefix */
10976ff6d951SJohn Birrell
10986ff6d951SJohn Birrell if (pfc->pfc_print == &pfprint_pct) {
10996ff6d951SJohn Birrell (void) strcat(pfd->pfd_fmt, pfc->pfc_ofmt);
11006ff6d951SJohn Birrell continue;
11016ff6d951SJohn Birrell }
11026ff6d951SJohn Birrell
11036ff6d951SJohn Birrell if (pfd->pfd_flags & DT_PFCONV_DYNPREC)
11046ff6d951SJohn Birrell dyns[dync++] = ".*";
11056ff6d951SJohn Birrell if (pfd->pfd_flags & DT_PFCONV_DYNWIDTH)
11066ff6d951SJohn Birrell dyns[dync++] = "*";
11076ff6d951SJohn Birrell
11086ff6d951SJohn Birrell for (; dync != 0; dync--) {
11096ff6d951SJohn Birrell if (dnp == NULL) {
11106ff6d951SJohn Birrell xyerror(D_PRINTF_DYN_PROTO,
11116ff6d951SJohn Birrell "%s( ) prototype mismatch: conversion "
11126ff6d951SJohn Birrell "#%d (%%%s) is missing a corresponding "
11136ff6d951SJohn Birrell "\"%s\" argument\n", func, i + 1,
11146ff6d951SJohn Birrell pfc->pfc_name, dyns[dync - 1]);
11156ff6d951SJohn Birrell }
11166ff6d951SJohn Birrell
11176ff6d951SJohn Birrell if (dt_node_is_integer(dnp) == 0) {
11186ff6d951SJohn Birrell xyerror(D_PRINTF_DYN_TYPE,
11196ff6d951SJohn Birrell "%s( ) argument #%d is incompatible "
11206ff6d951SJohn Birrell "with conversion #%d prototype:\n"
11216ff6d951SJohn Birrell "\tconversion: %% %s %s\n"
11226ff6d951SJohn Birrell "\t prototype: int\n\t argument: %s\n",
11236ff6d951SJohn Birrell func, j + foff + 1, i + 1,
11246ff6d951SJohn Birrell dyns[dync - 1], pfc->pfc_name,
11256ff6d951SJohn Birrell dt_node_type_name(dnp, n, sizeof (n)));
11266ff6d951SJohn Birrell }
11276ff6d951SJohn Birrell
11286ff6d951SJohn Birrell dnp = dnp->dn_list;
11296ff6d951SJohn Birrell j++;
11306ff6d951SJohn Birrell }
11316ff6d951SJohn Birrell
11326ff6d951SJohn Birrell /*
11336ff6d951SJohn Birrell * If this conversion is consuming the aggregation data, set
11346ff6d951SJohn Birrell * the value node pointer (vnp) to a fake node based on the
11356ff6d951SJohn Birrell * aggregating function result type. Otherwise assign vnp to
11366ff6d951SJohn Birrell * the next parse node in the argument list, if there is one.
11376ff6d951SJohn Birrell */
11386ff6d951SJohn Birrell if (pfd->pfd_flags & DT_PFCONV_AGG) {
11396ff6d951SJohn Birrell if (!(flags & DT_PRINTF_AGGREGATION)) {
11406ff6d951SJohn Birrell xyerror(D_PRINTF_AGG_CONV,
11416ff6d951SJohn Birrell "%%@ conversion requires an aggregation"
11426ff6d951SJohn Birrell " and is not for use with %s( )\n", func);
11436ff6d951SJohn Birrell }
11446ff6d951SJohn Birrell (void) strlcpy(vname, "aggregating action",
11456ff6d951SJohn Birrell sizeof (vname));
11466ff6d951SJohn Birrell vnp = &aggnode;
11476ff6d951SJohn Birrell } else if (dnp == NULL) {
11486ff6d951SJohn Birrell xyerror(D_PRINTF_ARG_PROTO,
11496ff6d951SJohn Birrell "%s( ) prototype mismatch: conversion #%d (%%"
11506ff6d951SJohn Birrell "%s) is missing a corresponding value argument\n",
11516ff6d951SJohn Birrell func, i + 1, pfc->pfc_name);
11526ff6d951SJohn Birrell } else {
11536ff6d951SJohn Birrell (void) snprintf(vname, sizeof (vname),
11546ff6d951SJohn Birrell "argument #%d", j + foff + 1);
11556ff6d951SJohn Birrell vnp = dnp;
11566ff6d951SJohn Birrell dnp = dnp->dn_list;
11576ff6d951SJohn Birrell j++;
11586ff6d951SJohn Birrell }
11596ff6d951SJohn Birrell
11606ff6d951SJohn Birrell /*
11616ff6d951SJohn Birrell * Fill in the proposed final format string by prepending any
11626ff6d951SJohn Birrell * size-related prefixes to the pfconv's format string. The
11636ff6d951SJohn Birrell * pfc_check() function below may optionally modify the format
11646ff6d951SJohn Birrell * as part of validating the type of the input argument.
11656ff6d951SJohn Birrell */
11666ff6d951SJohn Birrell if (pfc->pfc_print == &pfprint_sint ||
11676ff6d951SJohn Birrell pfc->pfc_print == &pfprint_uint ||
11686ff6d951SJohn Birrell pfc->pfc_print == &pfprint_dint) {
11696ff6d951SJohn Birrell if (dt_node_type_size(vnp) == sizeof (uint64_t))
11706ff6d951SJohn Birrell (void) strcpy(pfd->pfd_fmt, "ll");
11716ff6d951SJohn Birrell } else if (pfc->pfc_print == &pfprint_fp) {
11726ff6d951SJohn Birrell if (dt_node_type_size(vnp) == sizeof (long double))
11736ff6d951SJohn Birrell (void) strcpy(pfd->pfd_fmt, "L");
11746ff6d951SJohn Birrell }
11756ff6d951SJohn Birrell
11766ff6d951SJohn Birrell (void) strcat(pfd->pfd_fmt, pfc->pfc_ofmt);
11776ff6d951SJohn Birrell
11786ff6d951SJohn Birrell /*
11796ff6d951SJohn Birrell * Validate the format conversion against the value node type.
11806ff6d951SJohn Birrell * If the conversion is good, create the descriptor format
11816ff6d951SJohn Birrell * string by concatenating together any required printf(3C)
11826ff6d951SJohn Birrell * size prefixes with the conversion's native format string.
11836ff6d951SJohn Birrell */
11846ff6d951SJohn Birrell if (pfc->pfc_check(pfv, pfd, vnp) == 0) {
11856ff6d951SJohn Birrell xyerror(D_PRINTF_ARG_TYPE,
11866ff6d951SJohn Birrell "%s( ) %s is incompatible with "
11876ff6d951SJohn Birrell "conversion #%d prototype:\n\tconversion: %%%s\n"
11886ff6d951SJohn Birrell "\t prototype: %s\n\t argument: %s\n", func,
11896ff6d951SJohn Birrell vname, i + 1, pfc->pfc_name, pfc->pfc_tstr,
11906ff6d951SJohn Birrell dt_node_type_name(vnp, n, sizeof (n)));
11916ff6d951SJohn Birrell }
11926ff6d951SJohn Birrell }
11936ff6d951SJohn Birrell
11946ff6d951SJohn Birrell if ((flags & DT_PRINTF_EXACTLEN) && dnp != NULL) {
11956ff6d951SJohn Birrell xyerror(D_PRINTF_ARG_EXTRA,
11966ff6d951SJohn Birrell "%s( ) prototype mismatch: only %d arguments "
11976ff6d951SJohn Birrell "required by this format string\n", func, j);
11986ff6d951SJohn Birrell }
11996ff6d951SJohn Birrell }
12006ff6d951SJohn Birrell
12016ff6d951SJohn Birrell void
dt_printa_validate(dt_node_t * lhs,dt_node_t * rhs)12026ff6d951SJohn Birrell dt_printa_validate(dt_node_t *lhs, dt_node_t *rhs)
12036ff6d951SJohn Birrell {
12046ff6d951SJohn Birrell dt_ident_t *lid, *rid;
12056ff6d951SJohn Birrell dt_node_t *lproto, *rproto;
12066ff6d951SJohn Birrell int largc, rargc, argn;
12076ff6d951SJohn Birrell char n1[DT_TYPE_NAMELEN];
12086ff6d951SJohn Birrell char n2[DT_TYPE_NAMELEN];
12096ff6d951SJohn Birrell
12106ff6d951SJohn Birrell assert(lhs->dn_kind == DT_NODE_AGG);
12116ff6d951SJohn Birrell assert(rhs->dn_kind == DT_NODE_AGG);
12126ff6d951SJohn Birrell
12136ff6d951SJohn Birrell lid = lhs->dn_ident;
12146ff6d951SJohn Birrell rid = rhs->dn_ident;
12156ff6d951SJohn Birrell
12166ff6d951SJohn Birrell lproto = ((dt_idsig_t *)lid->di_data)->dis_args;
12176ff6d951SJohn Birrell rproto = ((dt_idsig_t *)rid->di_data)->dis_args;
12186ff6d951SJohn Birrell
12196ff6d951SJohn Birrell /*
12206ff6d951SJohn Birrell * First, get an argument count on each side. These must match.
12216ff6d951SJohn Birrell */
12226ff6d951SJohn Birrell for (largc = 0; lproto != NULL; lproto = lproto->dn_list)
12236ff6d951SJohn Birrell largc++;
12246ff6d951SJohn Birrell
12256ff6d951SJohn Birrell for (rargc = 0; rproto != NULL; rproto = rproto->dn_list)
12266ff6d951SJohn Birrell rargc++;
12276ff6d951SJohn Birrell
12286ff6d951SJohn Birrell if (largc != rargc) {
12296ff6d951SJohn Birrell xyerror(D_PRINTA_AGGKEY, "printa( ): @%s and @%s do not have "
12306ff6d951SJohn Birrell "matching key signatures: @%s has %d key%s, @%s has %d "
12316ff6d951SJohn Birrell "key%s", lid->di_name, rid->di_name,
12326ff6d951SJohn Birrell lid->di_name, largc, largc == 1 ? "" : "s",
12336ff6d951SJohn Birrell rid->di_name, rargc, rargc == 1 ? "" : "s");
12346ff6d951SJohn Birrell }
12356ff6d951SJohn Birrell
12366ff6d951SJohn Birrell /*
12376ff6d951SJohn Birrell * Now iterate over the keys to verify that each type matches.
12386ff6d951SJohn Birrell */
12396ff6d951SJohn Birrell lproto = ((dt_idsig_t *)lid->di_data)->dis_args;
12406ff6d951SJohn Birrell rproto = ((dt_idsig_t *)rid->di_data)->dis_args;
12416ff6d951SJohn Birrell
12426ff6d951SJohn Birrell for (argn = 1; lproto != NULL; argn++, lproto = lproto->dn_list,
12436ff6d951SJohn Birrell rproto = rproto->dn_list) {
12446ff6d951SJohn Birrell assert(rproto != NULL);
12456ff6d951SJohn Birrell
12466ff6d951SJohn Birrell if (dt_node_is_argcompat(lproto, rproto))
12476ff6d951SJohn Birrell continue;
12486ff6d951SJohn Birrell
12496ff6d951SJohn Birrell xyerror(D_PRINTA_AGGPROTO, "printa( ): @%s[ ] key #%d is "
12506ff6d951SJohn Birrell "incompatible with @%s:\n%9s key #%d: %s\n"
12516ff6d951SJohn Birrell "%9s key #%d: %s\n",
12526ff6d951SJohn Birrell rid->di_name, argn, lid->di_name, lid->di_name, argn,
12536ff6d951SJohn Birrell dt_node_type_name(lproto, n1, sizeof (n1)), rid->di_name,
12546ff6d951SJohn Birrell argn, dt_node_type_name(rproto, n2, sizeof (n2)));
12556ff6d951SJohn Birrell }
12566ff6d951SJohn Birrell }
12576ff6d951SJohn Birrell
12586ff6d951SJohn Birrell static int
dt_printf_getint(dtrace_hdl_t * dtp,const dtrace_recdesc_t * recp,uint_t nrecs,const void * buf,size_t len,int * ip)12596ff6d951SJohn Birrell dt_printf_getint(dtrace_hdl_t *dtp, const dtrace_recdesc_t *recp,
12606ff6d951SJohn Birrell uint_t nrecs, const void *buf, size_t len, int *ip)
12616ff6d951SJohn Birrell {
12626ff6d951SJohn Birrell uintptr_t addr;
12636ff6d951SJohn Birrell
12646ff6d951SJohn Birrell if (nrecs == 0)
12656ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_DMISMATCH));
12666ff6d951SJohn Birrell
12676ff6d951SJohn Birrell addr = (uintptr_t)buf + recp->dtrd_offset;
12686ff6d951SJohn Birrell
12696ff6d951SJohn Birrell if (addr + sizeof (int) > (uintptr_t)buf + len)
12706ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_DOFFSET));
12716ff6d951SJohn Birrell
12726ff6d951SJohn Birrell if (addr & (recp->dtrd_alignment - 1))
12736ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_DALIGN));
12746ff6d951SJohn Birrell
12756ff6d951SJohn Birrell switch (recp->dtrd_size) {
12766ff6d951SJohn Birrell case sizeof (int8_t):
12776ff6d951SJohn Birrell *ip = (int)*((int8_t *)addr);
12786ff6d951SJohn Birrell break;
12796ff6d951SJohn Birrell case sizeof (int16_t):
12806ff6d951SJohn Birrell *ip = (int)*((int16_t *)addr);
12816ff6d951SJohn Birrell break;
12826ff6d951SJohn Birrell case sizeof (int32_t):
12836ff6d951SJohn Birrell *ip = (int)*((int32_t *)addr);
12846ff6d951SJohn Birrell break;
12856ff6d951SJohn Birrell case sizeof (int64_t):
12866ff6d951SJohn Birrell *ip = (int)*((int64_t *)addr);
12876ff6d951SJohn Birrell break;
12886ff6d951SJohn Birrell default:
12896ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_DMISMATCH));
12906ff6d951SJohn Birrell }
12916ff6d951SJohn Birrell
12926ff6d951SJohn Birrell return (0);
12936ff6d951SJohn Birrell }
12946ff6d951SJohn Birrell
12956ff6d951SJohn Birrell /*ARGSUSED*/
12966ff6d951SJohn Birrell static int
pfprint_average(dtrace_hdl_t * dtp,FILE * fp,const char * format,const dt_pfargd_t * pfd,const void * addr,size_t size,uint64_t normal)12976ff6d951SJohn Birrell pfprint_average(dtrace_hdl_t *dtp, FILE *fp, const char *format,
12986ff6d951SJohn Birrell const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
12996ff6d951SJohn Birrell {
13006ff6d951SJohn Birrell const uint64_t *data = addr;
13016ff6d951SJohn Birrell
13026ff6d951SJohn Birrell if (size != sizeof (uint64_t) * 2)
13036ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_DMISMATCH));
13046ff6d951SJohn Birrell
13056ff6d951SJohn Birrell return (dt_printf(dtp, fp, format,
13066ff6d951SJohn Birrell data[0] ? data[1] / normal / data[0] : 0));
13076ff6d951SJohn Birrell }
13086ff6d951SJohn Birrell
13096ff6d951SJohn Birrell /*ARGSUSED*/
13106ff6d951SJohn Birrell static int
pfprint_stddev(dtrace_hdl_t * dtp,FILE * fp,const char * format,const dt_pfargd_t * pfd,const void * addr,size_t size,uint64_t normal)13111670a1c2SRui Paulo pfprint_stddev(dtrace_hdl_t *dtp, FILE *fp, const char *format,
13121670a1c2SRui Paulo const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
13131670a1c2SRui Paulo {
13141670a1c2SRui Paulo const uint64_t *data = addr;
13151670a1c2SRui Paulo
13161670a1c2SRui Paulo if (size != sizeof (uint64_t) * 4)
13171670a1c2SRui Paulo return (dt_set_errno(dtp, EDT_DMISMATCH));
13181670a1c2SRui Paulo
13191670a1c2SRui Paulo return (dt_printf(dtp, fp, format,
13201670a1c2SRui Paulo dt_stddev((uint64_t *)data, normal)));
13211670a1c2SRui Paulo }
13221670a1c2SRui Paulo
13231670a1c2SRui Paulo /*ARGSUSED*/
13241670a1c2SRui Paulo static int
pfprint_quantize(dtrace_hdl_t * dtp,FILE * fp,const char * format,const dt_pfargd_t * pfd,const void * addr,size_t size,uint64_t normal)13256ff6d951SJohn Birrell pfprint_quantize(dtrace_hdl_t *dtp, FILE *fp, const char *format,
13266ff6d951SJohn Birrell const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
13276ff6d951SJohn Birrell {
13286ff6d951SJohn Birrell return (dt_print_quantize(dtp, fp, addr, size, normal));
13296ff6d951SJohn Birrell }
13306ff6d951SJohn Birrell
13316ff6d951SJohn Birrell /*ARGSUSED*/
13326ff6d951SJohn Birrell static int
pfprint_lquantize(dtrace_hdl_t * dtp,FILE * fp,const char * format,const dt_pfargd_t * pfd,const void * addr,size_t size,uint64_t normal)13336ff6d951SJohn Birrell pfprint_lquantize(dtrace_hdl_t *dtp, FILE *fp, const char *format,
13346ff6d951SJohn Birrell const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
13356ff6d951SJohn Birrell {
13366ff6d951SJohn Birrell return (dt_print_lquantize(dtp, fp, addr, size, normal));
13376ff6d951SJohn Birrell }
13386ff6d951SJohn Birrell
1339675cf915SPedro F. Giffuni /*ARGSUSED*/
1340675cf915SPedro F. Giffuni static int
pfprint_llquantize(dtrace_hdl_t * dtp,FILE * fp,const char * format,const dt_pfargd_t * pfd,const void * addr,size_t size,uint64_t normal)1341675cf915SPedro F. Giffuni pfprint_llquantize(dtrace_hdl_t *dtp, FILE *fp, const char *format,
1342675cf915SPedro F. Giffuni const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal)
1343675cf915SPedro F. Giffuni {
1344675cf915SPedro F. Giffuni return (dt_print_llquantize(dtp, fp, addr, size, normal));
1345675cf915SPedro F. Giffuni }
1346675cf915SPedro F. Giffuni
13476ff6d951SJohn Birrell static int
dt_printf_format(dtrace_hdl_t * dtp,FILE * fp,const dt_pfargv_t * pfv,const dtrace_recdesc_t * recs,uint_t nrecs,const void * buf,size_t len,const dtrace_aggdata_t ** aggsdata,int naggvars)13486ff6d951SJohn Birrell dt_printf_format(dtrace_hdl_t *dtp, FILE *fp, const dt_pfargv_t *pfv,
13496ff6d951SJohn Birrell const dtrace_recdesc_t *recs, uint_t nrecs, const void *buf,
13506ff6d951SJohn Birrell size_t len, const dtrace_aggdata_t **aggsdata, int naggvars)
13516ff6d951SJohn Birrell {
13526ff6d951SJohn Birrell dt_pfargd_t *pfd = pfv->pfv_argv;
13536ff6d951SJohn Birrell const dtrace_recdesc_t *recp = recs;
13546ff6d951SJohn Birrell const dtrace_aggdata_t *aggdata;
13556ff6d951SJohn Birrell dtrace_aggdesc_t *agg;
13566ff6d951SJohn Birrell caddr_t lim = (caddr_t)buf + len, limit;
13576ff6d951SJohn Birrell char format[64] = "%";
135861ab25cdSMark Johnston size_t ret;
13596ff6d951SJohn Birrell int i, aggrec, curagg = -1;
13606ff6d951SJohn Birrell uint64_t normal;
13616ff6d951SJohn Birrell
13626ff6d951SJohn Birrell /*
13636ff6d951SJohn Birrell * If we are formatting an aggregation, set 'aggrec' to the index of
13646ff6d951SJohn Birrell * the final record description (the aggregation result) so we can use
13656ff6d951SJohn Birrell * this record index with any conversion where DT_PFCONV_AGG is set.
13666ff6d951SJohn Birrell * (The actual aggregation used will vary as we increment through the
13676ff6d951SJohn Birrell * aggregation variables that we have been passed.) Finally, we
13686ff6d951SJohn Birrell * decrement nrecs to prevent this record from being used with any
13696ff6d951SJohn Birrell * other conversion.
13706ff6d951SJohn Birrell */
13716ff6d951SJohn Birrell if (pfv->pfv_flags & DT_PRINTF_AGGREGATION) {
13726ff6d951SJohn Birrell assert(aggsdata != NULL);
13736ff6d951SJohn Birrell assert(naggvars > 0);
13746ff6d951SJohn Birrell
13756ff6d951SJohn Birrell if (nrecs == 0)
13766ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_DMISMATCH));
13776ff6d951SJohn Birrell
13786ff6d951SJohn Birrell curagg = naggvars > 1 ? 1 : 0;
13796ff6d951SJohn Birrell aggdata = aggsdata[0];
13806ff6d951SJohn Birrell aggrec = aggdata->dtada_desc->dtagd_nrecs - 1;
13816ff6d951SJohn Birrell nrecs--;
13826ff6d951SJohn Birrell }
13836ff6d951SJohn Birrell
13846ff6d951SJohn Birrell for (i = 0; i < pfv->pfv_argc; i++, pfd = pfd->pfd_next) {
13856ff6d951SJohn Birrell const dt_pfconv_t *pfc = pfd->pfd_conv;
13866ff6d951SJohn Birrell int width = pfd->pfd_width;
13876ff6d951SJohn Birrell int prec = pfd->pfd_prec;
13886ff6d951SJohn Birrell int rval;
13896ff6d951SJohn Birrell
139061ab25cdSMark Johnston const char *start;
13916ff6d951SJohn Birrell char *f = format + 1; /* skip initial '%' */
139261ab25cdSMark Johnston size_t fmtsz = sizeof(format) - 1;
13936ff6d951SJohn Birrell const dtrace_recdesc_t *rec;
13946ff6d951SJohn Birrell dt_pfprint_f *func;
13956ff6d951SJohn Birrell caddr_t addr;
13966ff6d951SJohn Birrell size_t size;
13976ff6d951SJohn Birrell uint32_t flags;
13986ff6d951SJohn Birrell
13996ff6d951SJohn Birrell if (pfd->pfd_preflen != 0) {
14006ff6d951SJohn Birrell char *tmp = alloca(pfd->pfd_preflen + 1);
14016ff6d951SJohn Birrell
14026ff6d951SJohn Birrell bcopy(pfd->pfd_prefix, tmp, pfd->pfd_preflen);
14036ff6d951SJohn Birrell tmp[pfd->pfd_preflen] = '\0';
14046ff6d951SJohn Birrell
14056ff6d951SJohn Birrell if ((rval = dt_printf(dtp, fp, tmp)) < 0)
14066ff6d951SJohn Birrell return (rval);
14076ff6d951SJohn Birrell
14086ff6d951SJohn Birrell if (pfv->pfv_flags & DT_PRINTF_AGGREGATION) {
14096ff6d951SJohn Birrell /*
14106ff6d951SJohn Birrell * For printa(), we flush the buffer after each
14116ff6d951SJohn Birrell * prefix, setting the flags to indicate that
14126ff6d951SJohn Birrell * this is part of the printa() format string.
14136ff6d951SJohn Birrell */
14146ff6d951SJohn Birrell flags = DTRACE_BUFDATA_AGGFORMAT;
14156ff6d951SJohn Birrell
14166ff6d951SJohn Birrell if (pfc == NULL && i == pfv->pfv_argc - 1)
14176ff6d951SJohn Birrell flags |= DTRACE_BUFDATA_AGGLAST;
14186ff6d951SJohn Birrell
14196ff6d951SJohn Birrell if (dt_buffered_flush(dtp, NULL, NULL,
14206ff6d951SJohn Birrell aggdata, flags) < 0)
14216ff6d951SJohn Birrell return (-1);
14226ff6d951SJohn Birrell }
14236ff6d951SJohn Birrell }
14246ff6d951SJohn Birrell
14256ff6d951SJohn Birrell if (pfc == NULL) {
14266ff6d951SJohn Birrell if (pfv->pfv_argc == 1)
14276ff6d951SJohn Birrell return (nrecs != 0);
14286ff6d951SJohn Birrell continue;
14296ff6d951SJohn Birrell }
14306ff6d951SJohn Birrell
14316ff6d951SJohn Birrell /*
14326ff6d951SJohn Birrell * If the conversion is %%, just invoke the print callback
14336ff6d951SJohn Birrell * with no data record and continue; it consumes no record.
14346ff6d951SJohn Birrell */
14356ff6d951SJohn Birrell if (pfc->pfc_print == &pfprint_pct) {
14366ff6d951SJohn Birrell if (pfc->pfc_print(dtp, fp, NULL, pfd, NULL, 0, 1) >= 0)
14376ff6d951SJohn Birrell continue;
14386ff6d951SJohn Birrell return (-1); /* errno is set for us */
14396ff6d951SJohn Birrell }
14406ff6d951SJohn Birrell
14416ff6d951SJohn Birrell if (pfd->pfd_flags & DT_PFCONV_DYNWIDTH) {
14426ff6d951SJohn Birrell if (dt_printf_getint(dtp, recp++, nrecs--, buf,
14436ff6d951SJohn Birrell len, &width) == -1)
14446ff6d951SJohn Birrell return (-1); /* errno is set for us */
14456ff6d951SJohn Birrell pfd->pfd_dynwidth = width;
14466ff6d951SJohn Birrell } else {
14476ff6d951SJohn Birrell pfd->pfd_dynwidth = 0;
14486ff6d951SJohn Birrell }
14496ff6d951SJohn Birrell
14506ff6d951SJohn Birrell if ((pfd->pfd_flags & DT_PFCONV_DYNPREC) && dt_printf_getint(
14516ff6d951SJohn Birrell dtp, recp++, nrecs--, buf, len, &prec) == -1)
14526ff6d951SJohn Birrell return (-1); /* errno is set for us */
14536ff6d951SJohn Birrell
14546ff6d951SJohn Birrell if (pfd->pfd_flags & DT_PFCONV_AGG) {
14556ff6d951SJohn Birrell /*
14566ff6d951SJohn Birrell * This should be impossible -- the compiler shouldn't
14576ff6d951SJohn Birrell * create a DT_PFCONV_AGG conversion without an
14586ff6d951SJohn Birrell * aggregation present. Still, we'd rather fail
14596ff6d951SJohn Birrell * gracefully than blow up...
14606ff6d951SJohn Birrell */
14616ff6d951SJohn Birrell if (aggsdata == NULL)
14626ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_DMISMATCH));
14636ff6d951SJohn Birrell
14646ff6d951SJohn Birrell aggdata = aggsdata[curagg];
14656ff6d951SJohn Birrell agg = aggdata->dtada_desc;
14666ff6d951SJohn Birrell
14676ff6d951SJohn Birrell /*
14686ff6d951SJohn Birrell * We increment the current aggregation variable, but
14696ff6d951SJohn Birrell * not beyond the number of aggregation variables that
14706ff6d951SJohn Birrell * we're printing. This has the (desired) effect that
14716ff6d951SJohn Birrell * DT_PFCONV_AGG conversions beyond the number of
14726ff6d951SJohn Birrell * aggregation variables (re-)convert the aggregation
14736ff6d951SJohn Birrell * value of the last aggregation variable.
14746ff6d951SJohn Birrell */
14756ff6d951SJohn Birrell if (curagg < naggvars - 1)
14766ff6d951SJohn Birrell curagg++;
14776ff6d951SJohn Birrell
14786ff6d951SJohn Birrell rec = &agg->dtagd_rec[aggrec];
14796ff6d951SJohn Birrell addr = aggdata->dtada_data + rec->dtrd_offset;
14806ff6d951SJohn Birrell limit = addr + aggdata->dtada_size;
14816ff6d951SJohn Birrell normal = aggdata->dtada_normal;
14826ff6d951SJohn Birrell flags = DTRACE_BUFDATA_AGGVAL;
14836ff6d951SJohn Birrell } else {
14846ff6d951SJohn Birrell if (nrecs == 0)
14856ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_DMISMATCH));
14866ff6d951SJohn Birrell
14876ff6d951SJohn Birrell if (pfv->pfv_flags & DT_PRINTF_AGGREGATION) {
14886ff6d951SJohn Birrell /*
14896ff6d951SJohn Birrell * When printing aggregation keys, we always
14906ff6d951SJohn Birrell * set the aggdata to be the representative
14916ff6d951SJohn Birrell * (zeroth) aggregation. The aggdata isn't
14926ff6d951SJohn Birrell * actually used here in this case, but it is
14936ff6d951SJohn Birrell * passed to the buffer handler and must
14946ff6d951SJohn Birrell * therefore still be correct.
14956ff6d951SJohn Birrell */
14966ff6d951SJohn Birrell aggdata = aggsdata[0];
14976ff6d951SJohn Birrell flags = DTRACE_BUFDATA_AGGKEY;
14986ff6d951SJohn Birrell }
14996ff6d951SJohn Birrell
15006ff6d951SJohn Birrell rec = recp++;
15016ff6d951SJohn Birrell nrecs--;
15026ff6d951SJohn Birrell addr = (caddr_t)buf + rec->dtrd_offset;
15036ff6d951SJohn Birrell limit = lim;
15046ff6d951SJohn Birrell normal = 1;
15056ff6d951SJohn Birrell }
15066ff6d951SJohn Birrell
15076ff6d951SJohn Birrell size = rec->dtrd_size;
15086ff6d951SJohn Birrell
15096ff6d951SJohn Birrell if (addr + size > limit) {
15106ff6d951SJohn Birrell dt_dprintf("bad size: addr=%p size=0x%x lim=%p\n",
15116ff6d951SJohn Birrell (void *)addr, rec->dtrd_size, (void *)lim);
15126ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_DOFFSET));
15136ff6d951SJohn Birrell }
15146ff6d951SJohn Birrell
15156ff6d951SJohn Birrell if (rec->dtrd_alignment != 0 &&
15166ff6d951SJohn Birrell ((uintptr_t)addr & (rec->dtrd_alignment - 1)) != 0) {
15176ff6d951SJohn Birrell dt_dprintf("bad align: addr=%p size=0x%x align=0x%x\n",
15186ff6d951SJohn Birrell (void *)addr, rec->dtrd_size, rec->dtrd_alignment);
15196ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_DALIGN));
15206ff6d951SJohn Birrell }
15216ff6d951SJohn Birrell
15226ff6d951SJohn Birrell switch (rec->dtrd_action) {
15236ff6d951SJohn Birrell case DTRACEAGG_AVG:
15246ff6d951SJohn Birrell func = pfprint_average;
15256ff6d951SJohn Birrell break;
15261670a1c2SRui Paulo case DTRACEAGG_STDDEV:
15271670a1c2SRui Paulo func = pfprint_stddev;
15281670a1c2SRui Paulo break;
15296ff6d951SJohn Birrell case DTRACEAGG_QUANTIZE:
15306ff6d951SJohn Birrell func = pfprint_quantize;
15316ff6d951SJohn Birrell break;
15326ff6d951SJohn Birrell case DTRACEAGG_LQUANTIZE:
15336ff6d951SJohn Birrell func = pfprint_lquantize;
15346ff6d951SJohn Birrell break;
1535675cf915SPedro F. Giffuni case DTRACEAGG_LLQUANTIZE:
1536675cf915SPedro F. Giffuni func = pfprint_llquantize;
1537675cf915SPedro F. Giffuni break;
15386ff6d951SJohn Birrell case DTRACEACT_MOD:
15396ff6d951SJohn Birrell func = pfprint_mod;
15406ff6d951SJohn Birrell break;
15416ff6d951SJohn Birrell case DTRACEACT_UMOD:
15426ff6d951SJohn Birrell func = pfprint_umod;
15436ff6d951SJohn Birrell break;
15446ff6d951SJohn Birrell default:
15456ff6d951SJohn Birrell func = pfc->pfc_print;
15466ff6d951SJohn Birrell break;
15476ff6d951SJohn Birrell }
15486ff6d951SJohn Birrell
154961ab25cdSMark Johnston start = f;
15506ff6d951SJohn Birrell if (pfd->pfd_flags & DT_PFCONV_ALT)
15516ff6d951SJohn Birrell *f++ = '#';
15526ff6d951SJohn Birrell if (pfd->pfd_flags & DT_PFCONV_ZPAD)
15536ff6d951SJohn Birrell *f++ = '0';
15546ff6d951SJohn Birrell if (width < 0 || (pfd->pfd_flags & DT_PFCONV_LEFT))
15556ff6d951SJohn Birrell *f++ = '-';
15566ff6d951SJohn Birrell if (pfd->pfd_flags & DT_PFCONV_SPOS)
15576ff6d951SJohn Birrell *f++ = '+';
15586ff6d951SJohn Birrell if (pfd->pfd_flags & DT_PFCONV_GROUP)
15596ff6d951SJohn Birrell *f++ = '\'';
15606ff6d951SJohn Birrell if (pfd->pfd_flags & DT_PFCONV_SPACE)
15616ff6d951SJohn Birrell *f++ = ' ';
156261ab25cdSMark Johnston fmtsz -= f - start;
15636ff6d951SJohn Birrell
15646ff6d951SJohn Birrell /*
15656ff6d951SJohn Birrell * If we're printing a stack and DT_PFCONV_LEFT is set, we
15666ff6d951SJohn Birrell * don't add the width to the format string. See the block
15676ff6d951SJohn Birrell * comment in pfprint_stack() for a description of the
15686ff6d951SJohn Birrell * behavior in this case.
15696ff6d951SJohn Birrell */
15706ff6d951SJohn Birrell if (func == pfprint_stack && (pfd->pfd_flags & DT_PFCONV_LEFT))
15716ff6d951SJohn Birrell width = 0;
15726ff6d951SJohn Birrell
157361ab25cdSMark Johnston if (width != 0) {
157461ab25cdSMark Johnston ret = snprintf(f, fmtsz, "%d", ABS(width));
157561ab25cdSMark Johnston f += ret;
157661ab25cdSMark Johnston fmtsz = MAX(0, fmtsz - ret);
157761ab25cdSMark Johnston }
15786ff6d951SJohn Birrell
157961ab25cdSMark Johnston if (prec > 0) {
158061ab25cdSMark Johnston ret = snprintf(f, fmtsz, ".%d", prec);
158161ab25cdSMark Johnston f += ret;
158261ab25cdSMark Johnston fmtsz = MAX(0, fmtsz - ret);
158361ab25cdSMark Johnston }
15846ff6d951SJohn Birrell
158561ab25cdSMark Johnston if (strlcpy(f, pfd->pfd_fmt, fmtsz) >= fmtsz)
158661ab25cdSMark Johnston return (dt_set_errno(dtp, EDT_COMPILER));
15876ff6d951SJohn Birrell pfd->pfd_rec = rec;
15886ff6d951SJohn Birrell
15896ff6d951SJohn Birrell if (func(dtp, fp, format, pfd, addr, size, normal) < 0)
15906ff6d951SJohn Birrell return (-1); /* errno is set for us */
15916ff6d951SJohn Birrell
15926ff6d951SJohn Birrell if (pfv->pfv_flags & DT_PRINTF_AGGREGATION) {
15936ff6d951SJohn Birrell /*
15946ff6d951SJohn Birrell * For printa(), we flush the buffer after each tuple
15956ff6d951SJohn Birrell * element, inidicating that this is the last record
15966ff6d951SJohn Birrell * as appropriate.
15976ff6d951SJohn Birrell */
15986ff6d951SJohn Birrell if (i == pfv->pfv_argc - 1)
15996ff6d951SJohn Birrell flags |= DTRACE_BUFDATA_AGGLAST;
16006ff6d951SJohn Birrell
16016ff6d951SJohn Birrell if (dt_buffered_flush(dtp, NULL,
16026ff6d951SJohn Birrell rec, aggdata, flags) < 0)
16036ff6d951SJohn Birrell return (-1);
16046ff6d951SJohn Birrell }
16056ff6d951SJohn Birrell }
16066ff6d951SJohn Birrell
16076ff6d951SJohn Birrell return ((int)(recp - recs));
16086ff6d951SJohn Birrell }
16096ff6d951SJohn Birrell
16106ff6d951SJohn Birrell int
dtrace_sprintf(dtrace_hdl_t * dtp,FILE * fp,void * fmtdata,const dtrace_recdesc_t * recp,uint_t nrecs,const void * buf,size_t len)16116ff6d951SJohn Birrell dtrace_sprintf(dtrace_hdl_t *dtp, FILE *fp, void *fmtdata,
16126ff6d951SJohn Birrell const dtrace_recdesc_t *recp, uint_t nrecs, const void *buf, size_t len)
16136ff6d951SJohn Birrell {
16146ff6d951SJohn Birrell dtrace_optval_t size;
16156ff6d951SJohn Birrell int rval;
16166ff6d951SJohn Birrell
16176ff6d951SJohn Birrell rval = dtrace_getopt(dtp, "strsize", &size);
16186ff6d951SJohn Birrell assert(rval == 0);
16196ff6d951SJohn Birrell assert(dtp->dt_sprintf_buflen == 0);
16206ff6d951SJohn Birrell
16216ff6d951SJohn Birrell if (dtp->dt_sprintf_buf != NULL)
16226ff6d951SJohn Birrell free(dtp->dt_sprintf_buf);
16236ff6d951SJohn Birrell
16246ff6d951SJohn Birrell if ((dtp->dt_sprintf_buf = malloc(size)) == NULL)
16256ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_NOMEM));
16266ff6d951SJohn Birrell
16276ff6d951SJohn Birrell bzero(dtp->dt_sprintf_buf, size);
16286ff6d951SJohn Birrell dtp->dt_sprintf_buflen = size;
16296ff6d951SJohn Birrell rval = dt_printf_format(dtp, fp, fmtdata, recp, nrecs, buf, len,
16306ff6d951SJohn Birrell NULL, 0);
16316ff6d951SJohn Birrell dtp->dt_sprintf_buflen = 0;
16326ff6d951SJohn Birrell
16336ff6d951SJohn Birrell if (rval == -1)
16346ff6d951SJohn Birrell free(dtp->dt_sprintf_buf);
16356ff6d951SJohn Birrell
16366ff6d951SJohn Birrell return (rval);
16376ff6d951SJohn Birrell }
16386ff6d951SJohn Birrell
16396ff6d951SJohn Birrell /*ARGSUSED*/
16406ff6d951SJohn Birrell int
dtrace_system(dtrace_hdl_t * dtp,FILE * fp,void * fmtdata,const dtrace_probedata_t * data,const dtrace_recdesc_t * recp,uint_t nrecs,const void * buf,size_t len)16416ff6d951SJohn Birrell dtrace_system(dtrace_hdl_t *dtp, FILE *fp, void *fmtdata,
16426ff6d951SJohn Birrell const dtrace_probedata_t *data, const dtrace_recdesc_t *recp,
16436ff6d951SJohn Birrell uint_t nrecs, const void *buf, size_t len)
16446ff6d951SJohn Birrell {
16456ff6d951SJohn Birrell int rval = dtrace_sprintf(dtp, fp, fmtdata, recp, nrecs, buf, len);
16466ff6d951SJohn Birrell
16476ff6d951SJohn Birrell if (rval == -1)
16486ff6d951SJohn Birrell return (rval);
16496ff6d951SJohn Birrell
16506ff6d951SJohn Birrell /*
16516ff6d951SJohn Birrell * Before we execute the specified command, flush fp to assure that
16526ff6d951SJohn Birrell * any prior dt_printf()'s appear before the output of the command
16536ff6d951SJohn Birrell * not after it.
16546ff6d951SJohn Birrell */
16556ff6d951SJohn Birrell (void) fflush(fp);
16566ff6d951SJohn Birrell
16576ff6d951SJohn Birrell if (system(dtp->dt_sprintf_buf) == -1)
16586ff6d951SJohn Birrell return (dt_set_errno(dtp, errno));
16596ff6d951SJohn Birrell
16606ff6d951SJohn Birrell return (rval);
16616ff6d951SJohn Birrell }
16626ff6d951SJohn Birrell
16636ff6d951SJohn Birrell int
dtrace_freopen(dtrace_hdl_t * dtp,FILE * fp,void * fmtdata,const dtrace_probedata_t * data,const dtrace_recdesc_t * recp,uint_t nrecs,const void * buf,size_t len)16646ff6d951SJohn Birrell dtrace_freopen(dtrace_hdl_t *dtp, FILE *fp, void *fmtdata,
16656ff6d951SJohn Birrell const dtrace_probedata_t *data, const dtrace_recdesc_t *recp,
16666ff6d951SJohn Birrell uint_t nrecs, const void *buf, size_t len)
16676ff6d951SJohn Birrell {
16686ff6d951SJohn Birrell char selfbuf[40], restorebuf[40], *filename;
16696ff6d951SJohn Birrell FILE *nfp;
16706ff6d951SJohn Birrell int rval, errval;
16716ff6d951SJohn Birrell dt_pfargv_t *pfv = fmtdata;
16726ff6d951SJohn Birrell dt_pfargd_t *pfd = pfv->pfv_argv;
16736ff6d951SJohn Birrell
16746ff6d951SJohn Birrell rval = dtrace_sprintf(dtp, fp, fmtdata, recp, nrecs, buf, len);
16756ff6d951SJohn Birrell
16766ff6d951SJohn Birrell if (rval == -1 || fp == NULL)
16776ff6d951SJohn Birrell return (rval);
16786ff6d951SJohn Birrell
1679bc96366cSSteven Hartland #ifdef illumos
16806ff6d951SJohn Birrell if (pfd->pfd_preflen != 0 &&
16816ff6d951SJohn Birrell strcmp(pfd->pfd_prefix, DT_FREOPEN_RESTORE) == 0) {
16826ff6d951SJohn Birrell /*
16836ff6d951SJohn Birrell * The only way to have the format string set to the value
16846ff6d951SJohn Birrell * DT_FREOPEN_RESTORE is via the empty freopen() string --
16856ff6d951SJohn Birrell * denoting that we should restore the old stdout.
16866ff6d951SJohn Birrell */
16876ff6d951SJohn Birrell assert(strcmp(dtp->dt_sprintf_buf, DT_FREOPEN_RESTORE) == 0);
16886ff6d951SJohn Birrell
16896ff6d951SJohn Birrell if (dtp->dt_stdout_fd == -1) {
16906ff6d951SJohn Birrell /*
16916ff6d951SJohn Birrell * We could complain here by generating an error,
16926ff6d951SJohn Birrell * but it seems like overkill: it seems that calling
16936ff6d951SJohn Birrell * freopen() to restore stdout when freopen() has
16946ff6d951SJohn Birrell * never before been called should just be a no-op,
16956ff6d951SJohn Birrell * so we just return in this case.
16966ff6d951SJohn Birrell */
16976ff6d951SJohn Birrell return (rval);
16986ff6d951SJohn Birrell }
16996ff6d951SJohn Birrell
17006ff6d951SJohn Birrell (void) snprintf(restorebuf, sizeof (restorebuf),
17016ff6d951SJohn Birrell "/dev/fd/%d", dtp->dt_stdout_fd);
17026ff6d951SJohn Birrell filename = restorebuf;
17036ff6d951SJohn Birrell } else {
17046ff6d951SJohn Birrell filename = dtp->dt_sprintf_buf;
17056ff6d951SJohn Birrell }
17066ff6d951SJohn Birrell
17076ff6d951SJohn Birrell /*
17086ff6d951SJohn Birrell * freopen(3C) will always close the specified stream and underlying
17096ff6d951SJohn Birrell * file descriptor -- even if the specified file can't be opened.
17106ff6d951SJohn Birrell * Even for the semantic cesspool that is standard I/O, this is
17116ff6d951SJohn Birrell * surprisingly brain-dead behavior: it means that any failure to
17126ff6d951SJohn Birrell * open the specified file destroys the specified stream in the
17136ff6d951SJohn Birrell * process -- which is particularly relevant when the specified stream
17146ff6d951SJohn Birrell * happens (or rather, happened) to be stdout. This could be resolved
17156ff6d951SJohn Birrell * were there an "fdreopen()" equivalent of freopen() that allowed one
17166ff6d951SJohn Birrell * to pass a file descriptor instead of the name of a file, but there
17176ff6d951SJohn Birrell * is no such thing. However, we can effect this ourselves by first
17186ff6d951SJohn Birrell * fopen()'ing the desired file, and then (assuming that that works),
17196ff6d951SJohn Birrell * freopen()'ing "/dev/fd/[fileno]", where [fileno] is the underlying
17206ff6d951SJohn Birrell * file descriptor for the fopen()'d file. This way, if the fopen()
17216ff6d951SJohn Birrell * fails, we can fail the operation without destroying stdout.
17226ff6d951SJohn Birrell */
17236ff6d951SJohn Birrell if ((nfp = fopen(filename, "aF")) == NULL) {
172429f89dfcSJohn Birrell char *msg = strerror(errno);
172529f89dfcSJohn Birrell char *faultstr;
17266ff6d951SJohn Birrell int len = 80;
17276ff6d951SJohn Birrell
17286ff6d951SJohn Birrell len += strlen(msg) + strlen(filename);
17296ff6d951SJohn Birrell faultstr = alloca(len);
17306ff6d951SJohn Birrell
17316ff6d951SJohn Birrell (void) snprintf(faultstr, len, "couldn't freopen() \"%s\": %s",
17326ff6d951SJohn Birrell filename, strerror(errno));
17336ff6d951SJohn Birrell
17346ff6d951SJohn Birrell if ((errval = dt_handle_liberr(dtp, data, faultstr)) == 0)
17356ff6d951SJohn Birrell return (rval);
17366ff6d951SJohn Birrell
17376ff6d951SJohn Birrell return (errval);
17386ff6d951SJohn Birrell }
17396ff6d951SJohn Birrell
17406ff6d951SJohn Birrell (void) snprintf(selfbuf, sizeof (selfbuf), "/dev/fd/%d", fileno(nfp));
17416ff6d951SJohn Birrell
17426ff6d951SJohn Birrell if (dtp->dt_stdout_fd == -1) {
17436ff6d951SJohn Birrell /*
17446ff6d951SJohn Birrell * If this is the first time that we're calling freopen(),
17456ff6d951SJohn Birrell * we're going to stash away the file descriptor for stdout.
17466ff6d951SJohn Birrell * We don't expect the dup(2) to fail, so if it does we must
17476ff6d951SJohn Birrell * return failure.
17486ff6d951SJohn Birrell */
17496ff6d951SJohn Birrell if ((dtp->dt_stdout_fd = dup(fileno(fp))) == -1) {
17506ff6d951SJohn Birrell (void) fclose(nfp);
17516ff6d951SJohn Birrell return (dt_set_errno(dtp, errno));
17526ff6d951SJohn Birrell }
17536ff6d951SJohn Birrell }
17546ff6d951SJohn Birrell
17556ff6d951SJohn Birrell if (freopen(selfbuf, "aF", fp) == NULL) {
17566ff6d951SJohn Birrell (void) fclose(nfp);
17576ff6d951SJohn Birrell return (dt_set_errno(dtp, errno));
17586ff6d951SJohn Birrell }
17596ff6d951SJohn Birrell
17606ff6d951SJohn Birrell (void) fclose(nfp);
1761bc96366cSSteven Hartland #else /* !illumos */
176229f89dfcSJohn Birrell /*
176329f89dfcSJohn Birrell * The 'standard output' (which is not necessarily stdout)
176429f89dfcSJohn Birrell * treatment on FreeBSD is implemented differently than on
176529f89dfcSJohn Birrell * Solaris because FreeBSD's freopen() will attempt to re-use
176629f89dfcSJohn Birrell * the current file descriptor, causing the previous file to
176729f89dfcSJohn Birrell * be closed and thereby preventing it from be re-activated
176829f89dfcSJohn Birrell * later.
176929f89dfcSJohn Birrell *
177029f89dfcSJohn Birrell * For FreeBSD we use the concept of setting an output file
177129f89dfcSJohn Birrell * pointer in the DTrace handle if a dtrace_freopen() has
177229f89dfcSJohn Birrell * enabled another output file and we leave the caller's
177329f89dfcSJohn Birrell * file pointer untouched. If it was actually stdout, then
177429f89dfcSJohn Birrell * stdout remains open. If it was another file, then that
177529f89dfcSJohn Birrell * file remains open. While a dtrace_freopen() has activated
177629f89dfcSJohn Birrell * another file, we keep a pointer to that which we use in
177729f89dfcSJohn Birrell * the output functions by preference and only use the caller's
177829f89dfcSJohn Birrell * file pointer if no dtrace_freopen() call has been made.
177929f89dfcSJohn Birrell *
178029f89dfcSJohn Birrell * The check to see if we're re-activating the caller's
178129f89dfcSJohn Birrell * output file is much the same as on Solaris.
178229f89dfcSJohn Birrell */
178329f89dfcSJohn Birrell if (pfd->pfd_preflen != 0 &&
178429f89dfcSJohn Birrell strcmp(pfd->pfd_prefix, DT_FREOPEN_RESTORE) == 0) {
178529f89dfcSJohn Birrell /*
178629f89dfcSJohn Birrell * The only way to have the format string set to the value
178729f89dfcSJohn Birrell * DT_FREOPEN_RESTORE is via the empty freopen() string --
178829f89dfcSJohn Birrell * denoting that we should restore the old stdout.
178929f89dfcSJohn Birrell */
179029f89dfcSJohn Birrell assert(strcmp(dtp->dt_sprintf_buf, DT_FREOPEN_RESTORE) == 0);
179129f89dfcSJohn Birrell
179229f89dfcSJohn Birrell if (dtp->dt_freopen_fp == NULL) {
179329f89dfcSJohn Birrell /*
179429f89dfcSJohn Birrell * We could complain here by generating an error,
179529f89dfcSJohn Birrell * but it seems like overkill: it seems that calling
179629f89dfcSJohn Birrell * freopen() to restore stdout when freopen() has
179729f89dfcSJohn Birrell * never before been called should just be a no-op,
179829f89dfcSJohn Birrell * so we just return in this case.
179929f89dfcSJohn Birrell */
180029f89dfcSJohn Birrell return (rval);
180129f89dfcSJohn Birrell }
180229f89dfcSJohn Birrell
180329f89dfcSJohn Birrell /*
180429f89dfcSJohn Birrell * At this point, to re-active the original output file,
180529f89dfcSJohn Birrell * on FreeBSD we only code the current file that this
180629f89dfcSJohn Birrell * function opened previously.
180729f89dfcSJohn Birrell */
180829f89dfcSJohn Birrell (void) fclose(dtp->dt_freopen_fp);
180929f89dfcSJohn Birrell dtp->dt_freopen_fp = NULL;
181029f89dfcSJohn Birrell
181129f89dfcSJohn Birrell return (rval);
181229f89dfcSJohn Birrell }
181329f89dfcSJohn Birrell
181429f89dfcSJohn Birrell if ((nfp = fopen(dtp->dt_sprintf_buf, "a")) == NULL) {
181529f89dfcSJohn Birrell char *msg = strerror(errno);
181629f89dfcSJohn Birrell char *faultstr;
181729f89dfcSJohn Birrell int len = 80;
181829f89dfcSJohn Birrell
181929f89dfcSJohn Birrell len += strlen(msg) + strlen(dtp->dt_sprintf_buf);
182029f89dfcSJohn Birrell faultstr = alloca(len);
182129f89dfcSJohn Birrell
182229f89dfcSJohn Birrell (void) snprintf(faultstr, len, "couldn't freopen() \"%s\": %s",
182329f89dfcSJohn Birrell dtp->dt_sprintf_buf, strerror(errno));
182429f89dfcSJohn Birrell
182529f89dfcSJohn Birrell if ((errval = dt_handle_liberr(dtp, data, faultstr)) == 0)
182629f89dfcSJohn Birrell return (rval);
182729f89dfcSJohn Birrell
182829f89dfcSJohn Birrell return (errval);
182929f89dfcSJohn Birrell }
183029f89dfcSJohn Birrell
183129f89dfcSJohn Birrell if (dtp->dt_freopen_fp != NULL)
183229f89dfcSJohn Birrell (void) fclose(dtp->dt_freopen_fp);
183329f89dfcSJohn Birrell
183429f89dfcSJohn Birrell /* Remember that the output has been redirected to the new file. */
183529f89dfcSJohn Birrell dtp->dt_freopen_fp = nfp;
1836bc96366cSSteven Hartland #endif /* illumos */
18376ff6d951SJohn Birrell
18386ff6d951SJohn Birrell return (rval);
18396ff6d951SJohn Birrell }
18406ff6d951SJohn Birrell
18416ff6d951SJohn Birrell /*ARGSUSED*/
18426ff6d951SJohn Birrell int
dtrace_fprintf(dtrace_hdl_t * dtp,FILE * fp,void * fmtdata,const dtrace_probedata_t * data,const dtrace_recdesc_t * recp,uint_t nrecs,const void * buf,size_t len)18436ff6d951SJohn Birrell dtrace_fprintf(dtrace_hdl_t *dtp, FILE *fp, void *fmtdata,
18446ff6d951SJohn Birrell const dtrace_probedata_t *data, const dtrace_recdesc_t *recp,
18456ff6d951SJohn Birrell uint_t nrecs, const void *buf, size_t len)
18466ff6d951SJohn Birrell {
18476ff6d951SJohn Birrell return (dt_printf_format(dtp, fp, fmtdata,
18486ff6d951SJohn Birrell recp, nrecs, buf, len, NULL, 0));
18496ff6d951SJohn Birrell }
18506ff6d951SJohn Birrell
18516ff6d951SJohn Birrell void *
dtrace_printf_create(dtrace_hdl_t * dtp,const char * s)18526ff6d951SJohn Birrell dtrace_printf_create(dtrace_hdl_t *dtp, const char *s)
18536ff6d951SJohn Birrell {
18546ff6d951SJohn Birrell dt_pfargv_t *pfv = dt_printf_create(dtp, s);
18556ff6d951SJohn Birrell dt_pfargd_t *pfd;
18566ff6d951SJohn Birrell int i;
18576ff6d951SJohn Birrell
18586ff6d951SJohn Birrell if (pfv == NULL)
18596ff6d951SJohn Birrell return (NULL); /* errno has been set for us */
18606ff6d951SJohn Birrell
18616ff6d951SJohn Birrell pfd = pfv->pfv_argv;
18626ff6d951SJohn Birrell
18636ff6d951SJohn Birrell for (i = 0; i < pfv->pfv_argc; i++, pfd = pfd->pfd_next) {
18646ff6d951SJohn Birrell const dt_pfconv_t *pfc = pfd->pfd_conv;
18656ff6d951SJohn Birrell
18666ff6d951SJohn Birrell if (pfc == NULL)
18676ff6d951SJohn Birrell continue;
18686ff6d951SJohn Birrell
18696ff6d951SJohn Birrell /*
18706ff6d951SJohn Birrell * If the output format is not %s then we assume that we have
18716ff6d951SJohn Birrell * been given a correctly-sized format string, so we copy the
18726ff6d951SJohn Birrell * true format name including the size modifier. If the output
18736ff6d951SJohn Birrell * format is %s, then either the input format is %s as well or
18746ff6d951SJohn Birrell * it is one of our custom formats (e.g. pfprint_addr), so we
18756ff6d951SJohn Birrell * must set pfd_fmt to be the output format conversion "s".
18766ff6d951SJohn Birrell */
18776ff6d951SJohn Birrell if (strcmp(pfc->pfc_ofmt, "s") != 0)
18786ff6d951SJohn Birrell (void) strcat(pfd->pfd_fmt, pfc->pfc_name);
18796ff6d951SJohn Birrell else
18806ff6d951SJohn Birrell (void) strcat(pfd->pfd_fmt, pfc->pfc_ofmt);
18816ff6d951SJohn Birrell }
18826ff6d951SJohn Birrell
18836ff6d951SJohn Birrell return (pfv);
18846ff6d951SJohn Birrell }
18856ff6d951SJohn Birrell
18866ff6d951SJohn Birrell void *
dtrace_printa_create(dtrace_hdl_t * dtp,const char * s)18876ff6d951SJohn Birrell dtrace_printa_create(dtrace_hdl_t *dtp, const char *s)
18886ff6d951SJohn Birrell {
18896ff6d951SJohn Birrell dt_pfargv_t *pfv = dtrace_printf_create(dtp, s);
18906ff6d951SJohn Birrell
18916ff6d951SJohn Birrell if (pfv == NULL)
18926ff6d951SJohn Birrell return (NULL); /* errno has been set for us */
18936ff6d951SJohn Birrell
18946ff6d951SJohn Birrell pfv->pfv_flags |= DT_PRINTF_AGGREGATION;
18956ff6d951SJohn Birrell
18966ff6d951SJohn Birrell return (pfv);
18976ff6d951SJohn Birrell }
18986ff6d951SJohn Birrell
18996ff6d951SJohn Birrell /*ARGSUSED*/
19006ff6d951SJohn Birrell size_t
dtrace_printf_format(dtrace_hdl_t * dtp,void * fmtdata,char * s,size_t len)19016ff6d951SJohn Birrell dtrace_printf_format(dtrace_hdl_t *dtp, void *fmtdata, char *s, size_t len)
19026ff6d951SJohn Birrell {
19036ff6d951SJohn Birrell dt_pfargv_t *pfv = fmtdata;
19046ff6d951SJohn Birrell dt_pfargd_t *pfd = pfv->pfv_argv;
19056ff6d951SJohn Birrell
19066ff6d951SJohn Birrell /*
19076ff6d951SJohn Birrell * An upper bound on the string length is the length of the original
19086ff6d951SJohn Birrell * format string, plus three times the number of conversions (each
19096ff6d951SJohn Birrell * conversion could add up an additional "ll" and/or pfd_width digit
19106ff6d951SJohn Birrell * in the case of converting %? to %16) plus one for a terminating \0.
19116ff6d951SJohn Birrell */
19126ff6d951SJohn Birrell size_t formatlen = strlen(pfv->pfv_format) + 3 * pfv->pfv_argc + 1;
19136ff6d951SJohn Birrell char *format = alloca(formatlen);
19146ff6d951SJohn Birrell char *f = format;
19156ff6d951SJohn Birrell int i, j;
19166ff6d951SJohn Birrell
19176ff6d951SJohn Birrell for (i = 0; i < pfv->pfv_argc; i++, pfd = pfd->pfd_next) {
19186ff6d951SJohn Birrell const dt_pfconv_t *pfc = pfd->pfd_conv;
19196ff6d951SJohn Birrell const char *str;
19206ff6d951SJohn Birrell int width = pfd->pfd_width;
19216ff6d951SJohn Birrell int prec = pfd->pfd_prec;
19226ff6d951SJohn Birrell
19236ff6d951SJohn Birrell if (pfd->pfd_preflen != 0) {
19246ff6d951SJohn Birrell for (j = 0; j < pfd->pfd_preflen; j++)
19256ff6d951SJohn Birrell *f++ = pfd->pfd_prefix[j];
19266ff6d951SJohn Birrell }
19276ff6d951SJohn Birrell
19286ff6d951SJohn Birrell if (pfc == NULL)
19296ff6d951SJohn Birrell continue;
19306ff6d951SJohn Birrell
19316ff6d951SJohn Birrell *f++ = '%';
19326ff6d951SJohn Birrell
19336ff6d951SJohn Birrell if (pfd->pfd_flags & DT_PFCONV_ALT)
19346ff6d951SJohn Birrell *f++ = '#';
19356ff6d951SJohn Birrell if (pfd->pfd_flags & DT_PFCONV_ZPAD)
19366ff6d951SJohn Birrell *f++ = '0';
19376ff6d951SJohn Birrell if (pfd->pfd_flags & DT_PFCONV_LEFT)
19386ff6d951SJohn Birrell *f++ = '-';
19396ff6d951SJohn Birrell if (pfd->pfd_flags & DT_PFCONV_SPOS)
19406ff6d951SJohn Birrell *f++ = '+';
19416ff6d951SJohn Birrell if (pfd->pfd_flags & DT_PFCONV_DYNWIDTH)
19426ff6d951SJohn Birrell *f++ = '*';
19436ff6d951SJohn Birrell if (pfd->pfd_flags & DT_PFCONV_DYNPREC) {
19446ff6d951SJohn Birrell *f++ = '.';
19456ff6d951SJohn Birrell *f++ = '*';
19466ff6d951SJohn Birrell }
19476ff6d951SJohn Birrell if (pfd->pfd_flags & DT_PFCONV_GROUP)
19486ff6d951SJohn Birrell *f++ = '\'';
19496ff6d951SJohn Birrell if (pfd->pfd_flags & DT_PFCONV_SPACE)
19506ff6d951SJohn Birrell *f++ = ' ';
19516ff6d951SJohn Birrell if (pfd->pfd_flags & DT_PFCONV_AGG)
19526ff6d951SJohn Birrell *f++ = '@';
19536ff6d951SJohn Birrell
19546ff6d951SJohn Birrell if (width != 0)
19556ff6d951SJohn Birrell f += snprintf(f, sizeof (format), "%d", width);
19566ff6d951SJohn Birrell
19576ff6d951SJohn Birrell if (prec != 0)
19586ff6d951SJohn Birrell f += snprintf(f, sizeof (format), ".%d", prec);
19596ff6d951SJohn Birrell
19606ff6d951SJohn Birrell /*
19616ff6d951SJohn Birrell * If the output format is %s, then either %s is the underlying
19626ff6d951SJohn Birrell * conversion or the conversion is one of our customized ones,
19636ff6d951SJohn Birrell * e.g. pfprint_addr. In these cases, put the original string
19646ff6d951SJohn Birrell * name of the conversion (pfc_name) into the pickled format
19656ff6d951SJohn Birrell * string rather than the derived conversion (pfd_fmt).
19666ff6d951SJohn Birrell */
19676ff6d951SJohn Birrell if (strcmp(pfc->pfc_ofmt, "s") == 0)
19686ff6d951SJohn Birrell str = pfc->pfc_name;
19696ff6d951SJohn Birrell else
19706ff6d951SJohn Birrell str = pfd->pfd_fmt;
19716ff6d951SJohn Birrell
19726ff6d951SJohn Birrell for (j = 0; str[j] != '\0'; j++)
19736ff6d951SJohn Birrell *f++ = str[j];
19746ff6d951SJohn Birrell }
19756ff6d951SJohn Birrell
19766ff6d951SJohn Birrell *f = '\0'; /* insert nul byte; do not count in return value */
19776ff6d951SJohn Birrell
19786ff6d951SJohn Birrell assert(f < format + formatlen);
19796ff6d951SJohn Birrell (void) strncpy(s, format, len);
19806ff6d951SJohn Birrell
19816ff6d951SJohn Birrell return ((size_t)(f - format));
19826ff6d951SJohn Birrell }
19836ff6d951SJohn Birrell
19846ff6d951SJohn Birrell static int
dt_fprinta(const dtrace_aggdata_t * adp,void * arg)19856ff6d951SJohn Birrell dt_fprinta(const dtrace_aggdata_t *adp, void *arg)
19866ff6d951SJohn Birrell {
19876ff6d951SJohn Birrell const dtrace_aggdesc_t *agg = adp->dtada_desc;
19886ff6d951SJohn Birrell const dtrace_recdesc_t *recp = &agg->dtagd_rec[0];
19896ff6d951SJohn Birrell uint_t nrecs = agg->dtagd_nrecs;
19906ff6d951SJohn Birrell dt_pfwalk_t *pfw = arg;
19916ff6d951SJohn Birrell dtrace_hdl_t *dtp = pfw->pfw_argv->pfv_dtp;
19926ff6d951SJohn Birrell int id;
19936ff6d951SJohn Birrell
19946ff6d951SJohn Birrell if (dt_printf_getint(dtp, recp++, nrecs--,
19956ff6d951SJohn Birrell adp->dtada_data, adp->dtada_size, &id) != 0 || pfw->pfw_aid != id)
19966ff6d951SJohn Birrell return (0); /* no aggregation id or id does not match */
19976ff6d951SJohn Birrell
19986ff6d951SJohn Birrell if (dt_printf_format(dtp, pfw->pfw_fp, pfw->pfw_argv,
19996ff6d951SJohn Birrell recp, nrecs, adp->dtada_data, adp->dtada_size, &adp, 1) == -1)
20006ff6d951SJohn Birrell return (pfw->pfw_err = dtp->dt_errno);
20016ff6d951SJohn Birrell
20026ff6d951SJohn Birrell /*
20036ff6d951SJohn Birrell * Cast away the const to set the bit indicating that this aggregation
20046ff6d951SJohn Birrell * has been printed.
20056ff6d951SJohn Birrell */
20066ff6d951SJohn Birrell ((dtrace_aggdesc_t *)agg)->dtagd_flags |= DTRACE_AGD_PRINTED;
20076ff6d951SJohn Birrell
20086ff6d951SJohn Birrell return (0);
20096ff6d951SJohn Birrell }
20106ff6d951SJohn Birrell
20116ff6d951SJohn Birrell static int
dt_fprintas(const dtrace_aggdata_t ** aggsdata,int naggvars,void * arg)20126ff6d951SJohn Birrell dt_fprintas(const dtrace_aggdata_t **aggsdata, int naggvars, void *arg)
20136ff6d951SJohn Birrell {
20146ff6d951SJohn Birrell const dtrace_aggdata_t *aggdata = aggsdata[0];
20156ff6d951SJohn Birrell const dtrace_aggdesc_t *agg = aggdata->dtada_desc;
20166ff6d951SJohn Birrell const dtrace_recdesc_t *rec = &agg->dtagd_rec[1];
20176ff6d951SJohn Birrell uint_t nrecs = agg->dtagd_nrecs - 1;
20186ff6d951SJohn Birrell dt_pfwalk_t *pfw = arg;
20196ff6d951SJohn Birrell dtrace_hdl_t *dtp = pfw->pfw_argv->pfv_dtp;
20206ff6d951SJohn Birrell int i;
20216ff6d951SJohn Birrell
20226ff6d951SJohn Birrell if (dt_printf_format(dtp, pfw->pfw_fp, pfw->pfw_argv,
20236ff6d951SJohn Birrell rec, nrecs, aggdata->dtada_data, aggdata->dtada_size,
20246ff6d951SJohn Birrell aggsdata, naggvars) == -1)
20256ff6d951SJohn Birrell return (pfw->pfw_err = dtp->dt_errno);
20266ff6d951SJohn Birrell
20276ff6d951SJohn Birrell /*
20286ff6d951SJohn Birrell * For each aggregation, indicate that it has been printed, casting
20296ff6d951SJohn Birrell * away the const as necessary.
20306ff6d951SJohn Birrell */
20316ff6d951SJohn Birrell for (i = 1; i < naggvars; i++) {
20326ff6d951SJohn Birrell agg = aggsdata[i]->dtada_desc;
20336ff6d951SJohn Birrell ((dtrace_aggdesc_t *)agg)->dtagd_flags |= DTRACE_AGD_PRINTED;
20346ff6d951SJohn Birrell }
20356ff6d951SJohn Birrell
20366ff6d951SJohn Birrell return (0);
20376ff6d951SJohn Birrell }
20386ff6d951SJohn Birrell /*ARGSUSED*/
20396ff6d951SJohn Birrell int
dtrace_fprinta(dtrace_hdl_t * dtp,FILE * fp,void * fmtdata,const dtrace_probedata_t * data,const dtrace_recdesc_t * recs,uint_t nrecs,const void * buf,size_t len)20406ff6d951SJohn Birrell dtrace_fprinta(dtrace_hdl_t *dtp, FILE *fp, void *fmtdata,
20416ff6d951SJohn Birrell const dtrace_probedata_t *data, const dtrace_recdesc_t *recs,
20426ff6d951SJohn Birrell uint_t nrecs, const void *buf, size_t len)
20436ff6d951SJohn Birrell {
20446ff6d951SJohn Birrell dt_pfwalk_t pfw;
20456ff6d951SJohn Birrell int i, naggvars = 0;
20466ff6d951SJohn Birrell dtrace_aggvarid_t *aggvars;
20476ff6d951SJohn Birrell
20486ff6d951SJohn Birrell aggvars = alloca(nrecs * sizeof (dtrace_aggvarid_t));
20496ff6d951SJohn Birrell
20506ff6d951SJohn Birrell /*
20516ff6d951SJohn Birrell * This might be a printa() with multiple aggregation variables. We
20526ff6d951SJohn Birrell * need to scan forward through the records until we find a record from
20536ff6d951SJohn Birrell * a different statement.
20546ff6d951SJohn Birrell */
20556ff6d951SJohn Birrell for (i = 0; i < nrecs; i++) {
20566ff6d951SJohn Birrell const dtrace_recdesc_t *nrec = &recs[i];
20576ff6d951SJohn Birrell
20586ff6d951SJohn Birrell if (nrec->dtrd_uarg != recs->dtrd_uarg)
20596ff6d951SJohn Birrell break;
20606ff6d951SJohn Birrell
20616ff6d951SJohn Birrell if (nrec->dtrd_action != recs->dtrd_action)
20626ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_BADAGG));
20636ff6d951SJohn Birrell
20646ff6d951SJohn Birrell aggvars[naggvars++] =
20656ff6d951SJohn Birrell /* LINTED - alignment */
20666ff6d951SJohn Birrell *((dtrace_aggvarid_t *)((caddr_t)buf + nrec->dtrd_offset));
20676ff6d951SJohn Birrell }
20686ff6d951SJohn Birrell
20696ff6d951SJohn Birrell if (naggvars == 0)
20706ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_BADAGG));
20716ff6d951SJohn Birrell
20726ff6d951SJohn Birrell pfw.pfw_argv = fmtdata;
20736ff6d951SJohn Birrell pfw.pfw_fp = fp;
20746ff6d951SJohn Birrell pfw.pfw_err = 0;
20756ff6d951SJohn Birrell
20766ff6d951SJohn Birrell if (naggvars == 1) {
20776ff6d951SJohn Birrell pfw.pfw_aid = aggvars[0];
20786ff6d951SJohn Birrell
20796ff6d951SJohn Birrell if (dtrace_aggregate_walk_sorted(dtp,
20806ff6d951SJohn Birrell dt_fprinta, &pfw) == -1 || pfw.pfw_err != 0)
20816ff6d951SJohn Birrell return (-1); /* errno is set for us */
20826ff6d951SJohn Birrell } else {
20836ff6d951SJohn Birrell if (dtrace_aggregate_walk_joined(dtp, aggvars, naggvars,
20846ff6d951SJohn Birrell dt_fprintas, &pfw) == -1 || pfw.pfw_err != 0)
20856ff6d951SJohn Birrell return (-1); /* errno is set for us */
20866ff6d951SJohn Birrell }
20876ff6d951SJohn Birrell
20886ff6d951SJohn Birrell return (i);
20896ff6d951SJohn Birrell }
2090