17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5004388ebScasper * Common Development and Distribution License (the "License"). 6004388ebScasper * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 21e4586ebfSmws 227c478bd9Sstevel@tonic-gate /* 23c9a6ea2eSBryan Cantrill * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 24*a386cc11SRobert Mustacchi * Copyright (c) 2013, Joyent, Inc. All rights reserved. 25*a386cc11SRobert Mustacchi * Copyright (c) 2013 by Delphix. All rights reserved. 267c478bd9Sstevel@tonic-gate */ 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 297c478bd9Sstevel@tonic-gate #include <strings.h> 307c478bd9Sstevel@tonic-gate #include <stdlib.h> 317c478bd9Sstevel@tonic-gate #include <alloca.h> 327c478bd9Sstevel@tonic-gate #include <assert.h> 337c478bd9Sstevel@tonic-gate #include <ctype.h> 347c478bd9Sstevel@tonic-gate #include <errno.h> 357c478bd9Sstevel@tonic-gate #include <limits.h> 36c9a6ea2eSBryan Cantrill #include <sys/socket.h> 37c9a6ea2eSBryan Cantrill #include <netdb.h> 38c9a6ea2eSBryan Cantrill #include <netinet/in.h> 39c9a6ea2eSBryan Cantrill #include <arpa/inet.h> 40c9a6ea2eSBryan Cantrill #include <arpa/nameser.h> 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate #include <dt_printf.h> 437c478bd9Sstevel@tonic-gate #include <dt_string.h> 447c478bd9Sstevel@tonic-gate #include <dt_impl.h> 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 477c478bd9Sstevel@tonic-gate static int 48a1b5e537Sbmc pfcheck_addr(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp) 497c478bd9Sstevel@tonic-gate { 507c478bd9Sstevel@tonic-gate return (dt_node_is_pointer(dnp) || dt_node_is_integer(dnp)); 517c478bd9Sstevel@tonic-gate } 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 547c478bd9Sstevel@tonic-gate static int 55a1b5e537Sbmc pfcheck_kaddr(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp) 56a1b5e537Sbmc { 57a1b5e537Sbmc return (dt_node_is_pointer(dnp) || dt_node_is_integer(dnp) || 58a1b5e537Sbmc dt_node_is_symaddr(dnp)); 59a1b5e537Sbmc } 60a1b5e537Sbmc 61a1b5e537Sbmc /*ARGSUSED*/ 62a1b5e537Sbmc static int 63a1b5e537Sbmc pfcheck_uaddr(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp) 64a1b5e537Sbmc { 65a1b5e537Sbmc dtrace_hdl_t *dtp = pfv->pfv_dtp; 66a1b5e537Sbmc dt_ident_t *idp = dt_idhash_lookup(dtp->dt_macros, "target"); 67a1b5e537Sbmc 68a1b5e537Sbmc if (dt_node_is_usymaddr(dnp)) 69a1b5e537Sbmc return (1); 70a1b5e537Sbmc 71a1b5e537Sbmc if (idp == NULL || idp->di_id == 0) 72a1b5e537Sbmc return (0); 73a1b5e537Sbmc 74a1b5e537Sbmc return (dt_node_is_pointer(dnp) || dt_node_is_integer(dnp)); 75a1b5e537Sbmc } 76a1b5e537Sbmc 77a1b5e537Sbmc /*ARGSUSED*/ 78a1b5e537Sbmc static int 79a1b5e537Sbmc pfcheck_stack(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp) 80a1b5e537Sbmc { 81a1b5e537Sbmc return (dt_node_is_stack(dnp)); 82a1b5e537Sbmc } 83a1b5e537Sbmc 84a1b5e537Sbmc /*ARGSUSED*/ 85a1b5e537Sbmc static int 8630ef842dSbmc pfcheck_time(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp) 8730ef842dSbmc { 8830ef842dSbmc return (dt_node_is_integer(dnp) && 8930ef842dSbmc dt_node_type_size(dnp) == sizeof (uint64_t)); 9030ef842dSbmc } 9130ef842dSbmc 9230ef842dSbmc /*ARGSUSED*/ 9330ef842dSbmc static int 94a1b5e537Sbmc pfcheck_str(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp) 957c478bd9Sstevel@tonic-gate { 967c478bd9Sstevel@tonic-gate ctf_file_t *ctfp; 977c478bd9Sstevel@tonic-gate ctf_encoding_t e; 987c478bd9Sstevel@tonic-gate ctf_arinfo_t r; 997c478bd9Sstevel@tonic-gate ctf_id_t base; 1007c478bd9Sstevel@tonic-gate uint_t kind; 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate if (dt_node_is_string(dnp)) 1037c478bd9Sstevel@tonic-gate return (1); 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate ctfp = dnp->dn_ctfp; 1067c478bd9Sstevel@tonic-gate base = ctf_type_resolve(ctfp, dnp->dn_type); 1077c478bd9Sstevel@tonic-gate kind = ctf_type_kind(ctfp, base); 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate return (kind == CTF_K_ARRAY && ctf_array_info(ctfp, base, &r) == 0 && 1107c478bd9Sstevel@tonic-gate (base = ctf_type_resolve(ctfp, r.ctr_contents)) != CTF_ERR && 1117c478bd9Sstevel@tonic-gate ctf_type_encoding(ctfp, base, &e) == 0 && IS_CHAR(e)); 1127c478bd9Sstevel@tonic-gate } 1137c478bd9Sstevel@tonic-gate 1147c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1157c478bd9Sstevel@tonic-gate static int 116a1b5e537Sbmc pfcheck_wstr(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp) 1177c478bd9Sstevel@tonic-gate { 1187c478bd9Sstevel@tonic-gate ctf_file_t *ctfp = dnp->dn_ctfp; 1197c478bd9Sstevel@tonic-gate ctf_id_t base = ctf_type_resolve(ctfp, dnp->dn_type); 1207c478bd9Sstevel@tonic-gate uint_t kind = ctf_type_kind(ctfp, base); 1217c478bd9Sstevel@tonic-gate 1227c478bd9Sstevel@tonic-gate ctf_encoding_t e; 1237c478bd9Sstevel@tonic-gate ctf_arinfo_t r; 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate return (kind == CTF_K_ARRAY && ctf_array_info(ctfp, base, &r) == 0 && 1267c478bd9Sstevel@tonic-gate (base = ctf_type_resolve(ctfp, r.ctr_contents)) != CTF_ERR && 1277c478bd9Sstevel@tonic-gate ctf_type_kind(ctfp, base) == CTF_K_INTEGER && 1287c478bd9Sstevel@tonic-gate ctf_type_encoding(ctfp, base, &e) == 0 && e.cte_bits == 32); 1297c478bd9Sstevel@tonic-gate } 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1327c478bd9Sstevel@tonic-gate static int 133a1b5e537Sbmc pfcheck_csi(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp) 1347c478bd9Sstevel@tonic-gate { 1357c478bd9Sstevel@tonic-gate return (dt_node_is_integer(dnp) && 1367c478bd9Sstevel@tonic-gate dt_node_type_size(dnp) <= sizeof (int)); 1377c478bd9Sstevel@tonic-gate } 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1407c478bd9Sstevel@tonic-gate static int 141a1b5e537Sbmc pfcheck_fp(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp) 1427c478bd9Sstevel@tonic-gate { 1437c478bd9Sstevel@tonic-gate return (dt_node_is_float(dnp)); 1447c478bd9Sstevel@tonic-gate } 1457c478bd9Sstevel@tonic-gate 1467c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1477c478bd9Sstevel@tonic-gate static int 148a1b5e537Sbmc pfcheck_xint(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp) 1497c478bd9Sstevel@tonic-gate { 1507c478bd9Sstevel@tonic-gate return (dt_node_is_integer(dnp)); 1517c478bd9Sstevel@tonic-gate } 1527c478bd9Sstevel@tonic-gate 153a1b5e537Sbmc /*ARGSUSED*/ 1547c478bd9Sstevel@tonic-gate static int 155a1b5e537Sbmc pfcheck_dint(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp) 1567c478bd9Sstevel@tonic-gate { 1577c478bd9Sstevel@tonic-gate if (dnp->dn_flags & DT_NF_SIGNED) 158e5803b76SAdam H. Leventhal pfd->pfd_fmt[strlen(pfd->pfd_fmt) - 1] = 'i'; 1597c478bd9Sstevel@tonic-gate else 1607c478bd9Sstevel@tonic-gate pfd->pfd_fmt[strlen(pfd->pfd_fmt) - 1] = 'u'; 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate return (dt_node_is_integer(dnp)); 1637c478bd9Sstevel@tonic-gate } 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1667c478bd9Sstevel@tonic-gate static int 167a1b5e537Sbmc pfcheck_xshort(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp) 1687c478bd9Sstevel@tonic-gate { 1697c478bd9Sstevel@tonic-gate ctf_file_t *ctfp = dnp->dn_ctfp; 1707c478bd9Sstevel@tonic-gate ctf_id_t type = ctf_type_resolve(ctfp, dnp->dn_type); 1717c478bd9Sstevel@tonic-gate char n[DT_TYPE_NAMELEN]; 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate return (ctf_type_name(ctfp, type, n, sizeof (n)) != NULL && ( 1747c478bd9Sstevel@tonic-gate strcmp(n, "short") == 0 || strcmp(n, "signed short") == 0 || 1757c478bd9Sstevel@tonic-gate strcmp(n, "unsigned short") == 0)); 1767c478bd9Sstevel@tonic-gate } 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1797c478bd9Sstevel@tonic-gate static int 180a1b5e537Sbmc pfcheck_xlong(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp) 1817c478bd9Sstevel@tonic-gate { 1827c478bd9Sstevel@tonic-gate ctf_file_t *ctfp = dnp->dn_ctfp; 1837c478bd9Sstevel@tonic-gate ctf_id_t type = ctf_type_resolve(ctfp, dnp->dn_type); 1847c478bd9Sstevel@tonic-gate char n[DT_TYPE_NAMELEN]; 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate return (ctf_type_name(ctfp, type, n, sizeof (n)) != NULL && ( 1877c478bd9Sstevel@tonic-gate strcmp(n, "long") == 0 || strcmp(n, "signed long") == 0 || 1887c478bd9Sstevel@tonic-gate strcmp(n, "unsigned long") == 0)); 1897c478bd9Sstevel@tonic-gate } 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1927c478bd9Sstevel@tonic-gate static int 193a1b5e537Sbmc pfcheck_xlonglong(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp) 1947c478bd9Sstevel@tonic-gate { 1957c478bd9Sstevel@tonic-gate ctf_file_t *ctfp = dnp->dn_ctfp; 1967c478bd9Sstevel@tonic-gate ctf_id_t type = dnp->dn_type; 1977c478bd9Sstevel@tonic-gate char n[DT_TYPE_NAMELEN]; 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate if (ctf_type_name(ctfp, ctf_type_resolve(ctfp, type), n, 2007c478bd9Sstevel@tonic-gate sizeof (n)) != NULL && (strcmp(n, "long long") == 0 || 2017c478bd9Sstevel@tonic-gate strcmp(n, "signed long long") == 0 || 2027c478bd9Sstevel@tonic-gate strcmp(n, "unsigned long long") == 0)) 2037c478bd9Sstevel@tonic-gate return (1); 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate /* 2067c478bd9Sstevel@tonic-gate * If the type used for %llx or %llX is not an [unsigned] long long, we 2077c478bd9Sstevel@tonic-gate * also permit it to be a [u]int64_t or any typedef thereof. We know 2087c478bd9Sstevel@tonic-gate * that these typedefs are guaranteed to work with %ll[xX] in either 2097c478bd9Sstevel@tonic-gate * compilation environment even though they alias to "long" in LP64. 2107c478bd9Sstevel@tonic-gate */ 2117c478bd9Sstevel@tonic-gate while (ctf_type_kind(ctfp, type) == CTF_K_TYPEDEF) { 2127c478bd9Sstevel@tonic-gate if (ctf_type_name(ctfp, type, n, sizeof (n)) != NULL && 2137c478bd9Sstevel@tonic-gate (strcmp(n, "int64_t") == 0 || strcmp(n, "uint64_t") == 0)) 2147c478bd9Sstevel@tonic-gate return (1); 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate type = ctf_type_reference(ctfp, type); 2177c478bd9Sstevel@tonic-gate } 2187c478bd9Sstevel@tonic-gate 2197c478bd9Sstevel@tonic-gate return (0); 2207c478bd9Sstevel@tonic-gate } 2217c478bd9Sstevel@tonic-gate 222a1b5e537Sbmc /*ARGSUSED*/ 2237c478bd9Sstevel@tonic-gate static int 224a1b5e537Sbmc pfcheck_type(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp) 2257c478bd9Sstevel@tonic-gate { 2267c478bd9Sstevel@tonic-gate return (ctf_type_compat(dnp->dn_ctfp, ctf_type_resolve(dnp->dn_ctfp, 2277c478bd9Sstevel@tonic-gate dnp->dn_type), pfd->pfd_conv->pfc_dctfp, pfd->pfd_conv->pfc_dtype)); 2287c478bd9Sstevel@tonic-gate } 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2317c478bd9Sstevel@tonic-gate static int 2327c478bd9Sstevel@tonic-gate pfprint_sint(dtrace_hdl_t *dtp, FILE *fp, const char *format, 2337c478bd9Sstevel@tonic-gate const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t unormal) 2347c478bd9Sstevel@tonic-gate { 2357c478bd9Sstevel@tonic-gate int64_t normal = (int64_t)unormal; 2367c478bd9Sstevel@tonic-gate int32_t n = (int32_t)normal; 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate switch (size) { 2397c478bd9Sstevel@tonic-gate case sizeof (int8_t): 2407c478bd9Sstevel@tonic-gate return (dt_printf(dtp, fp, format, 2417c478bd9Sstevel@tonic-gate (int32_t)*((int8_t *)addr) / n)); 2427c478bd9Sstevel@tonic-gate case sizeof (int16_t): 2437c478bd9Sstevel@tonic-gate return (dt_printf(dtp, fp, format, 2447c478bd9Sstevel@tonic-gate (int32_t)*((int16_t *)addr) / n)); 2457c478bd9Sstevel@tonic-gate case sizeof (int32_t): 2467c478bd9Sstevel@tonic-gate return (dt_printf(dtp, fp, format, 2477c478bd9Sstevel@tonic-gate *((int32_t *)addr) / n)); 2487c478bd9Sstevel@tonic-gate case sizeof (int64_t): 2497c478bd9Sstevel@tonic-gate return (dt_printf(dtp, fp, format, 2507c478bd9Sstevel@tonic-gate *((int64_t *)addr) / normal)); 2517c478bd9Sstevel@tonic-gate default: 2527c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DMISMATCH)); 2537c478bd9Sstevel@tonic-gate } 2547c478bd9Sstevel@tonic-gate } 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2577c478bd9Sstevel@tonic-gate static int 2587c478bd9Sstevel@tonic-gate pfprint_uint(dtrace_hdl_t *dtp, FILE *fp, const char *format, 2597c478bd9Sstevel@tonic-gate const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal) 2607c478bd9Sstevel@tonic-gate { 2617c478bd9Sstevel@tonic-gate uint32_t n = (uint32_t)normal; 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate switch (size) { 2647c478bd9Sstevel@tonic-gate case sizeof (uint8_t): 2657c478bd9Sstevel@tonic-gate return (dt_printf(dtp, fp, format, 2667c478bd9Sstevel@tonic-gate (uint32_t)*((uint8_t *)addr) / n)); 2677c478bd9Sstevel@tonic-gate case sizeof (uint16_t): 2687c478bd9Sstevel@tonic-gate return (dt_printf(dtp, fp, format, 2697c478bd9Sstevel@tonic-gate (uint32_t)*((uint16_t *)addr) / n)); 2707c478bd9Sstevel@tonic-gate case sizeof (uint32_t): 2717c478bd9Sstevel@tonic-gate return (dt_printf(dtp, fp, format, 2727c478bd9Sstevel@tonic-gate *((uint32_t *)addr) / n)); 2737c478bd9Sstevel@tonic-gate case sizeof (uint64_t): 2747c478bd9Sstevel@tonic-gate return (dt_printf(dtp, fp, format, 2757c478bd9Sstevel@tonic-gate *((uint64_t *)addr) / normal)); 2767c478bd9Sstevel@tonic-gate default: 2777c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DMISMATCH)); 2787c478bd9Sstevel@tonic-gate } 2797c478bd9Sstevel@tonic-gate } 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate static int 2827c478bd9Sstevel@tonic-gate pfprint_dint(dtrace_hdl_t *dtp, FILE *fp, const char *format, 2837c478bd9Sstevel@tonic-gate const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal) 2847c478bd9Sstevel@tonic-gate { 2857c478bd9Sstevel@tonic-gate if (pfd->pfd_flags & DT_PFCONV_SIGNED) 2867c478bd9Sstevel@tonic-gate return (pfprint_sint(dtp, fp, format, pfd, addr, size, normal)); 2877c478bd9Sstevel@tonic-gate else 2887c478bd9Sstevel@tonic-gate return (pfprint_uint(dtp, fp, format, pfd, addr, size, normal)); 2897c478bd9Sstevel@tonic-gate } 2907c478bd9Sstevel@tonic-gate 2917c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2927c478bd9Sstevel@tonic-gate static int 2937c478bd9Sstevel@tonic-gate pfprint_fp(dtrace_hdl_t *dtp, FILE *fp, const char *format, 2947c478bd9Sstevel@tonic-gate const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal) 2957c478bd9Sstevel@tonic-gate { 2967c478bd9Sstevel@tonic-gate double n = (double)normal; 2977c478bd9Sstevel@tonic-gate long double ldn = (long double)normal; 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate switch (size) { 3007c478bd9Sstevel@tonic-gate case sizeof (float): 3017c478bd9Sstevel@tonic-gate return (dt_printf(dtp, fp, format, 3027c478bd9Sstevel@tonic-gate (double)*((float *)addr) / n)); 3037c478bd9Sstevel@tonic-gate case sizeof (double): 3047c478bd9Sstevel@tonic-gate return (dt_printf(dtp, fp, format, 3057c478bd9Sstevel@tonic-gate *((double *)addr) / n)); 3067c478bd9Sstevel@tonic-gate case sizeof (long double): 3077c478bd9Sstevel@tonic-gate return (dt_printf(dtp, fp, format, 3087c478bd9Sstevel@tonic-gate *((long double *)addr) / ldn)); 3097c478bd9Sstevel@tonic-gate default: 3107c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DMISMATCH)); 3117c478bd9Sstevel@tonic-gate } 3127c478bd9Sstevel@tonic-gate } 3137c478bd9Sstevel@tonic-gate 3147c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3157c478bd9Sstevel@tonic-gate static int 3167c478bd9Sstevel@tonic-gate pfprint_addr(dtrace_hdl_t *dtp, FILE *fp, const char *format, 3177c478bd9Sstevel@tonic-gate const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal) 3187c478bd9Sstevel@tonic-gate { 3197c478bd9Sstevel@tonic-gate char *s; 320a1b5e537Sbmc int n, len = 256; 321a1b5e537Sbmc uint64_t val; 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate switch (size) { 3247c478bd9Sstevel@tonic-gate case sizeof (uint32_t): 3257c478bd9Sstevel@tonic-gate val = *((uint32_t *)addr); 3267c478bd9Sstevel@tonic-gate break; 3277c478bd9Sstevel@tonic-gate case sizeof (uint64_t): 3287c478bd9Sstevel@tonic-gate val = *((uint64_t *)addr); 3297c478bd9Sstevel@tonic-gate break; 3307c478bd9Sstevel@tonic-gate default: 3317c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DMISMATCH)); 3327c478bd9Sstevel@tonic-gate } 3337c478bd9Sstevel@tonic-gate 334a1b5e537Sbmc do { 335a1b5e537Sbmc n = len; 3367c478bd9Sstevel@tonic-gate s = alloca(n); 33796400bb6SJonathan Haslam } while ((len = dtrace_addr2str(dtp, val, s, n)) > n); 3387c478bd9Sstevel@tonic-gate 3397c478bd9Sstevel@tonic-gate return (dt_printf(dtp, fp, format, s)); 3407c478bd9Sstevel@tonic-gate } 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3437c478bd9Sstevel@tonic-gate static int 344a1b5e537Sbmc pfprint_mod(dtrace_hdl_t *dtp, FILE *fp, const char *format, 345a1b5e537Sbmc const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal) 346a1b5e537Sbmc { 347a1b5e537Sbmc return (dt_print_mod(dtp, fp, format, (caddr_t)addr)); 348a1b5e537Sbmc } 349a1b5e537Sbmc 350a1b5e537Sbmc /*ARGSUSED*/ 351a1b5e537Sbmc static int 352a1b5e537Sbmc pfprint_umod(dtrace_hdl_t *dtp, FILE *fp, const char *format, 353a1b5e537Sbmc const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal) 354a1b5e537Sbmc { 355a1b5e537Sbmc return (dt_print_umod(dtp, fp, format, (caddr_t)addr)); 356a1b5e537Sbmc } 357a1b5e537Sbmc 358a1b5e537Sbmc /*ARGSUSED*/ 359a1b5e537Sbmc static int 3607c478bd9Sstevel@tonic-gate pfprint_uaddr(dtrace_hdl_t *dtp, FILE *fp, const char *format, 3617c478bd9Sstevel@tonic-gate const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal) 3627c478bd9Sstevel@tonic-gate { 363a1b5e537Sbmc char *s; 364a1b5e537Sbmc int n, len = 256; 365a1b5e537Sbmc uint64_t val, pid = 0; 366a1b5e537Sbmc 3677c478bd9Sstevel@tonic-gate dt_ident_t *idp = dt_idhash_lookup(dtp->dt_macros, "target"); 3687c478bd9Sstevel@tonic-gate 3697c478bd9Sstevel@tonic-gate switch (size) { 3707c478bd9Sstevel@tonic-gate case sizeof (uint32_t): 3717c478bd9Sstevel@tonic-gate val = (u_longlong_t)*((uint32_t *)addr); 3727c478bd9Sstevel@tonic-gate break; 3737c478bd9Sstevel@tonic-gate case sizeof (uint64_t): 3747c478bd9Sstevel@tonic-gate val = (u_longlong_t)*((uint64_t *)addr); 3757c478bd9Sstevel@tonic-gate break; 376a1b5e537Sbmc case sizeof (uint64_t) * 2: 377a1b5e537Sbmc pid = ((uint64_t *)(uintptr_t)addr)[0]; 378a1b5e537Sbmc val = ((uint64_t *)(uintptr_t)addr)[1]; 379a1b5e537Sbmc break; 3807c478bd9Sstevel@tonic-gate default: 3817c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DMISMATCH)); 3827c478bd9Sstevel@tonic-gate } 3837c478bd9Sstevel@tonic-gate 384a1b5e537Sbmc if (pid == 0 && dtp->dt_vector == NULL && idp != NULL) 385a1b5e537Sbmc pid = idp->di_id; 3867c478bd9Sstevel@tonic-gate 387a1b5e537Sbmc do { 388a1b5e537Sbmc n = len; 389a1b5e537Sbmc s = alloca(n); 39096400bb6SJonathan Haslam } while ((len = dtrace_uaddr2str(dtp, pid, val, s, n)) > n); 3917c478bd9Sstevel@tonic-gate 392a1b5e537Sbmc return (dt_printf(dtp, fp, format, s)); 3937c478bd9Sstevel@tonic-gate } 3947c478bd9Sstevel@tonic-gate 3957c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3967c478bd9Sstevel@tonic-gate static int 3977c478bd9Sstevel@tonic-gate pfprint_stack(dtrace_hdl_t *dtp, FILE *fp, const char *format, 3987c478bd9Sstevel@tonic-gate const dt_pfargd_t *pfd, const void *vaddr, size_t size, uint64_t normal) 3997c478bd9Sstevel@tonic-gate { 400a1b5e537Sbmc int width; 4017c478bd9Sstevel@tonic-gate dtrace_optval_t saved = dtp->dt_options[DTRACEOPT_STACKINDENT]; 4027c478bd9Sstevel@tonic-gate const dtrace_recdesc_t *rec = pfd->pfd_rec; 4037c478bd9Sstevel@tonic-gate caddr_t addr = (caddr_t)vaddr; 4047c478bd9Sstevel@tonic-gate int err = 0; 4057c478bd9Sstevel@tonic-gate 4067c478bd9Sstevel@tonic-gate /* 4077c478bd9Sstevel@tonic-gate * We have stashed the value of the STACKINDENT option, and we will 4087c478bd9Sstevel@tonic-gate * now override it for the purposes of formatting the stack. If the 4097c478bd9Sstevel@tonic-gate * field has been specified as left-aligned (i.e. (%-#), we set the 4107c478bd9Sstevel@tonic-gate * indentation to be the width. This is a slightly odd semantic, but 4117c478bd9Sstevel@tonic-gate * it's useful functionality -- and it's slightly odd to begin with to 4127c478bd9Sstevel@tonic-gate * be using a single format specifier to be formatting multiple lines 4137c478bd9Sstevel@tonic-gate * of text... 4147c478bd9Sstevel@tonic-gate */ 4157c478bd9Sstevel@tonic-gate if (pfd->pfd_dynwidth < 0) { 4167c478bd9Sstevel@tonic-gate assert(pfd->pfd_flags & DT_PFCONV_DYNWIDTH); 4177c478bd9Sstevel@tonic-gate width = -pfd->pfd_dynwidth; 4187c478bd9Sstevel@tonic-gate } else if (pfd->pfd_flags & DT_PFCONV_LEFT) { 4197c478bd9Sstevel@tonic-gate width = pfd->pfd_dynwidth ? pfd->pfd_dynwidth : pfd->pfd_width; 4207c478bd9Sstevel@tonic-gate } else { 4217c478bd9Sstevel@tonic-gate width = 0; 4227c478bd9Sstevel@tonic-gate } 4237c478bd9Sstevel@tonic-gate 4247c478bd9Sstevel@tonic-gate dtp->dt_options[DTRACEOPT_STACKINDENT] = width; 4257c478bd9Sstevel@tonic-gate 4267c478bd9Sstevel@tonic-gate switch (rec->dtrd_action) { 4277c478bd9Sstevel@tonic-gate case DTRACEACT_USTACK: 4287c478bd9Sstevel@tonic-gate case DTRACEACT_JSTACK: 4297c478bd9Sstevel@tonic-gate err = dt_print_ustack(dtp, fp, format, addr, rec->dtrd_arg); 4307c478bd9Sstevel@tonic-gate break; 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate case DTRACEACT_STACK: 433a1b5e537Sbmc err = dt_print_stack(dtp, fp, format, addr, rec->dtrd_arg, 434a1b5e537Sbmc rec->dtrd_size / rec->dtrd_arg); 4357c478bd9Sstevel@tonic-gate break; 4367c478bd9Sstevel@tonic-gate 4377c478bd9Sstevel@tonic-gate default: 4387c478bd9Sstevel@tonic-gate assert(0); 4397c478bd9Sstevel@tonic-gate } 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate dtp->dt_options[DTRACEOPT_STACKINDENT] = saved; 4427c478bd9Sstevel@tonic-gate 4437c478bd9Sstevel@tonic-gate return (err); 4447c478bd9Sstevel@tonic-gate } 4457c478bd9Sstevel@tonic-gate 4467c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4477c478bd9Sstevel@tonic-gate static int 4487c478bd9Sstevel@tonic-gate pfprint_time(dtrace_hdl_t *dtp, FILE *fp, const char *format, 4497c478bd9Sstevel@tonic-gate const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal) 4507c478bd9Sstevel@tonic-gate { 4517c478bd9Sstevel@tonic-gate char src[32], buf[32], *dst = buf; 4527c478bd9Sstevel@tonic-gate hrtime_t time = *((uint64_t *)addr); 4537c478bd9Sstevel@tonic-gate time_t sec = (time_t)(time / NANOSEC); 4547c478bd9Sstevel@tonic-gate int i; 4557c478bd9Sstevel@tonic-gate 4567c478bd9Sstevel@tonic-gate /* 4577c478bd9Sstevel@tonic-gate * ctime(3C) returns a string of the form "Dec 3 17:20:00 1973\n\0". 4587c478bd9Sstevel@tonic-gate * Below, we turn this into the canonical adb/mdb /[yY] format, 4597c478bd9Sstevel@tonic-gate * "1973 Dec 3 17:20:00". 4607c478bd9Sstevel@tonic-gate */ 4617c478bd9Sstevel@tonic-gate (void) ctime_r(&sec, src, sizeof (src)); 4627c478bd9Sstevel@tonic-gate 4637c478bd9Sstevel@tonic-gate /* 4647c478bd9Sstevel@tonic-gate * Place the 4-digit year at the head of the string... 4657c478bd9Sstevel@tonic-gate */ 4667c478bd9Sstevel@tonic-gate for (i = 20; i < 24; i++) 4677c478bd9Sstevel@tonic-gate *dst++ = src[i]; 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate /* 4707c478bd9Sstevel@tonic-gate * ...and follow it with the remainder (month, day, hh:mm:ss). 4717c478bd9Sstevel@tonic-gate */ 4727c478bd9Sstevel@tonic-gate for (i = 3; i < 19; i++) 4737c478bd9Sstevel@tonic-gate *dst++ = src[i]; 4747c478bd9Sstevel@tonic-gate 4757c478bd9Sstevel@tonic-gate *dst = '\0'; 4767c478bd9Sstevel@tonic-gate return (dt_printf(dtp, fp, format, buf)); 4777c478bd9Sstevel@tonic-gate } 4787c478bd9Sstevel@tonic-gate 4797c478bd9Sstevel@tonic-gate /* 4807c478bd9Sstevel@tonic-gate * This prints the time in RFC 822 standard form. This is useful for emitting 4817c478bd9Sstevel@tonic-gate * notions of time that are consumed by standard tools (e.g., as part of an 4827c478bd9Sstevel@tonic-gate * RSS feed). 4837c478bd9Sstevel@tonic-gate */ 4847c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4857c478bd9Sstevel@tonic-gate static int 4867c478bd9Sstevel@tonic-gate pfprint_time822(dtrace_hdl_t *dtp, FILE *fp, const char *format, 4877c478bd9Sstevel@tonic-gate const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal) 4887c478bd9Sstevel@tonic-gate { 4897c478bd9Sstevel@tonic-gate hrtime_t time = *((uint64_t *)addr); 4907c478bd9Sstevel@tonic-gate time_t sec = (time_t)(time / NANOSEC); 4917c478bd9Sstevel@tonic-gate struct tm tm; 4927c478bd9Sstevel@tonic-gate char buf[64]; 4937c478bd9Sstevel@tonic-gate 4947c478bd9Sstevel@tonic-gate (void) localtime_r(&sec, &tm); 4957c478bd9Sstevel@tonic-gate (void) strftime(buf, sizeof (buf), "%a, %d %b %G %T %Z", &tm); 4967c478bd9Sstevel@tonic-gate return (dt_printf(dtp, fp, format, buf)); 4977c478bd9Sstevel@tonic-gate } 4987c478bd9Sstevel@tonic-gate 4997c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5007c478bd9Sstevel@tonic-gate static int 501c9a6ea2eSBryan Cantrill pfprint_port(dtrace_hdl_t *dtp, FILE *fp, const char *format, 502c9a6ea2eSBryan Cantrill const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal) 503c9a6ea2eSBryan Cantrill { 504c9a6ea2eSBryan Cantrill uint16_t port = htons(*((uint16_t *)addr)); 505c9a6ea2eSBryan Cantrill char buf[256]; 506c9a6ea2eSBryan Cantrill struct servent *sv, res; 507c9a6ea2eSBryan Cantrill 508c9a6ea2eSBryan Cantrill if ((sv = getservbyport_r(port, NULL, &res, buf, sizeof (buf))) != NULL) 509c9a6ea2eSBryan Cantrill return (dt_printf(dtp, fp, format, sv->s_name)); 510c9a6ea2eSBryan Cantrill 511c9a6ea2eSBryan Cantrill (void) snprintf(buf, sizeof (buf), "%d", *((uint16_t *)addr)); 512c9a6ea2eSBryan Cantrill return (dt_printf(dtp, fp, format, buf)); 513c9a6ea2eSBryan Cantrill } 514c9a6ea2eSBryan Cantrill 515c9a6ea2eSBryan Cantrill /*ARGSUSED*/ 516c9a6ea2eSBryan Cantrill static int 517c9a6ea2eSBryan Cantrill pfprint_inetaddr(dtrace_hdl_t *dtp, FILE *fp, const char *format, 518c9a6ea2eSBryan Cantrill const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal) 519c9a6ea2eSBryan Cantrill { 520c9a6ea2eSBryan Cantrill char *s = alloca(size + 1); 521c9a6ea2eSBryan Cantrill struct hostent *host, res; 522c9a6ea2eSBryan Cantrill char inetaddr[NS_IN6ADDRSZ]; 523c9a6ea2eSBryan Cantrill char buf[1024]; 524c9a6ea2eSBryan Cantrill int e; 525c9a6ea2eSBryan Cantrill 526c9a6ea2eSBryan Cantrill bcopy(addr, s, size); 527c9a6ea2eSBryan Cantrill s[size] = '\0'; 528c9a6ea2eSBryan Cantrill 529c9a6ea2eSBryan Cantrill if (strchr(s, ':') == NULL && inet_pton(AF_INET, s, inetaddr) != -1) { 530c9a6ea2eSBryan Cantrill if ((host = gethostbyaddr_r(inetaddr, NS_INADDRSZ, 531c9a6ea2eSBryan Cantrill AF_INET, &res, buf, sizeof (buf), &e)) != NULL) 532c9a6ea2eSBryan Cantrill return (dt_printf(dtp, fp, format, host->h_name)); 533c9a6ea2eSBryan Cantrill } else if (inet_pton(AF_INET6, s, inetaddr) != -1) { 534c9a6ea2eSBryan Cantrill if ((host = getipnodebyaddr(inetaddr, NS_IN6ADDRSZ, 535c9a6ea2eSBryan Cantrill AF_INET6, &e)) != NULL) 536c9a6ea2eSBryan Cantrill return (dt_printf(dtp, fp, format, host->h_name)); 537c9a6ea2eSBryan Cantrill } 538c9a6ea2eSBryan Cantrill 539c9a6ea2eSBryan Cantrill return (dt_printf(dtp, fp, format, s)); 540c9a6ea2eSBryan Cantrill } 541c9a6ea2eSBryan Cantrill 542c9a6ea2eSBryan Cantrill /*ARGSUSED*/ 543c9a6ea2eSBryan Cantrill static int 5447c478bd9Sstevel@tonic-gate pfprint_cstr(dtrace_hdl_t *dtp, FILE *fp, const char *format, 5457c478bd9Sstevel@tonic-gate const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal) 5467c478bd9Sstevel@tonic-gate { 5477c478bd9Sstevel@tonic-gate char *s = alloca(size + 1); 5487c478bd9Sstevel@tonic-gate 5497c478bd9Sstevel@tonic-gate bcopy(addr, s, size); 5507c478bd9Sstevel@tonic-gate s[size] = '\0'; 5517c478bd9Sstevel@tonic-gate return (dt_printf(dtp, fp, format, s)); 5527c478bd9Sstevel@tonic-gate } 5537c478bd9Sstevel@tonic-gate 5547c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5557c478bd9Sstevel@tonic-gate static int 5567c478bd9Sstevel@tonic-gate pfprint_wstr(dtrace_hdl_t *dtp, FILE *fp, const char *format, 5577c478bd9Sstevel@tonic-gate const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal) 5587c478bd9Sstevel@tonic-gate { 5597c478bd9Sstevel@tonic-gate wchar_t *ws = alloca(size + sizeof (wchar_t)); 5607c478bd9Sstevel@tonic-gate 5617c478bd9Sstevel@tonic-gate bcopy(addr, ws, size); 5627c478bd9Sstevel@tonic-gate ws[size / sizeof (wchar_t)] = L'\0'; 5637c478bd9Sstevel@tonic-gate return (dt_printf(dtp, fp, format, ws)); 5647c478bd9Sstevel@tonic-gate } 5657c478bd9Sstevel@tonic-gate 5667c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5677c478bd9Sstevel@tonic-gate static int 5687c478bd9Sstevel@tonic-gate pfprint_estr(dtrace_hdl_t *dtp, FILE *fp, const char *format, 5697c478bd9Sstevel@tonic-gate const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal) 5707c478bd9Sstevel@tonic-gate { 5717c478bd9Sstevel@tonic-gate char *s; 5727c478bd9Sstevel@tonic-gate int n; 5737c478bd9Sstevel@tonic-gate 5747c478bd9Sstevel@tonic-gate if ((s = strchr2esc(addr, size)) == NULL) 5757c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 5767c478bd9Sstevel@tonic-gate 5777c478bd9Sstevel@tonic-gate n = dt_printf(dtp, fp, format, s); 5787c478bd9Sstevel@tonic-gate free(s); 5797c478bd9Sstevel@tonic-gate return (n); 5807c478bd9Sstevel@tonic-gate } 5817c478bd9Sstevel@tonic-gate 5827c478bd9Sstevel@tonic-gate static int 5837c478bd9Sstevel@tonic-gate pfprint_echr(dtrace_hdl_t *dtp, FILE *fp, const char *format, 5847c478bd9Sstevel@tonic-gate const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal) 5857c478bd9Sstevel@tonic-gate { 5867c478bd9Sstevel@tonic-gate char c; 5877c478bd9Sstevel@tonic-gate 5887c478bd9Sstevel@tonic-gate switch (size) { 5897c478bd9Sstevel@tonic-gate case sizeof (int8_t): 5907c478bd9Sstevel@tonic-gate c = *(int8_t *)addr; 5917c478bd9Sstevel@tonic-gate break; 5927c478bd9Sstevel@tonic-gate case sizeof (int16_t): 5937c478bd9Sstevel@tonic-gate c = *(int16_t *)addr; 5947c478bd9Sstevel@tonic-gate break; 5957c478bd9Sstevel@tonic-gate case sizeof (int32_t): 5967c478bd9Sstevel@tonic-gate c = *(int32_t *)addr; 5977c478bd9Sstevel@tonic-gate break; 5987c478bd9Sstevel@tonic-gate default: 5997c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DMISMATCH)); 6007c478bd9Sstevel@tonic-gate } 6017c478bd9Sstevel@tonic-gate 6027c478bd9Sstevel@tonic-gate return (pfprint_estr(dtp, fp, format, pfd, &c, 1, normal)); 6037c478bd9Sstevel@tonic-gate } 6047c478bd9Sstevel@tonic-gate 6057c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6067c478bd9Sstevel@tonic-gate static int 6077c478bd9Sstevel@tonic-gate pfprint_pct(dtrace_hdl_t *dtp, FILE *fp, const char *format, 6087c478bd9Sstevel@tonic-gate const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal) 6097c478bd9Sstevel@tonic-gate { 6107c478bd9Sstevel@tonic-gate return (dt_printf(dtp, fp, "%%")); 6117c478bd9Sstevel@tonic-gate } 6127c478bd9Sstevel@tonic-gate 6137c478bd9Sstevel@tonic-gate static const char pfproto_xint[] = "char, short, int, long, or long long"; 6147c478bd9Sstevel@tonic-gate static const char pfproto_csi[] = "char, short, or int"; 6157c478bd9Sstevel@tonic-gate static const char pfproto_fp[] = "float, double, or long double"; 6167c478bd9Sstevel@tonic-gate static const char pfproto_addr[] = "pointer or integer"; 617a1b5e537Sbmc static const char pfproto_uaddr[] = 618a1b5e537Sbmc "pointer or integer (with -p/-c) or _usymaddr (without -p/-c)"; 6197c478bd9Sstevel@tonic-gate static const char pfproto_cstr[] = "char [] or string (or use stringof)"; 6207c478bd9Sstevel@tonic-gate static const char pfproto_wstr[] = "wchar_t []"; 6217c478bd9Sstevel@tonic-gate 6227c478bd9Sstevel@tonic-gate /* 6237c478bd9Sstevel@tonic-gate * Printf format conversion dictionary. This table should match the set of 6247c478bd9Sstevel@tonic-gate * conversions offered by printf(3C), as well as some additional extensions. 6257c478bd9Sstevel@tonic-gate * The second parameter is an ASCII string which is either an actual type 6267c478bd9Sstevel@tonic-gate * name we should look up (if pfcheck_type is specified), or just a descriptive 6277c478bd9Sstevel@tonic-gate * string of the types expected for use in error messages. 6287c478bd9Sstevel@tonic-gate */ 6297c478bd9Sstevel@tonic-gate static const dt_pfconv_t _dtrace_conversions[] = { 630a1b5e537Sbmc { "a", "s", pfproto_addr, pfcheck_kaddr, pfprint_addr }, 631a1b5e537Sbmc { "A", "s", pfproto_uaddr, pfcheck_uaddr, pfprint_uaddr }, 6327c478bd9Sstevel@tonic-gate { "c", "c", pfproto_csi, pfcheck_csi, pfprint_sint }, 6337c478bd9Sstevel@tonic-gate { "C", "s", pfproto_csi, pfcheck_csi, pfprint_echr }, 6347c478bd9Sstevel@tonic-gate { "d", "d", pfproto_xint, pfcheck_dint, pfprint_dint }, 6357c478bd9Sstevel@tonic-gate { "e", "e", pfproto_fp, pfcheck_fp, pfprint_fp }, 6367c478bd9Sstevel@tonic-gate { "E", "E", pfproto_fp, pfcheck_fp, pfprint_fp }, 6377c478bd9Sstevel@tonic-gate { "f", "f", pfproto_fp, pfcheck_fp, pfprint_fp }, 6387c478bd9Sstevel@tonic-gate { "g", "g", pfproto_fp, pfcheck_fp, pfprint_fp }, 6397c478bd9Sstevel@tonic-gate { "G", "G", pfproto_fp, pfcheck_fp, pfprint_fp }, 6407c478bd9Sstevel@tonic-gate { "hd", "d", "short", pfcheck_type, pfprint_sint }, 6417c478bd9Sstevel@tonic-gate { "hi", "i", "short", pfcheck_type, pfprint_sint }, 6427c478bd9Sstevel@tonic-gate { "ho", "o", "unsigned short", pfcheck_type, pfprint_uint }, 6437c478bd9Sstevel@tonic-gate { "hu", "u", "unsigned short", pfcheck_type, pfprint_uint }, 6447c478bd9Sstevel@tonic-gate { "hx", "x", "short", pfcheck_xshort, pfprint_uint }, 6457c478bd9Sstevel@tonic-gate { "hX", "X", "short", pfcheck_xshort, pfprint_uint }, 646e5803b76SAdam H. Leventhal { "i", "i", pfproto_xint, pfcheck_xint, pfprint_sint }, 647c9a6ea2eSBryan Cantrill { "I", "s", pfproto_cstr, pfcheck_str, pfprint_inetaddr }, 648a1b5e537Sbmc { "k", "s", "stack", pfcheck_stack, pfprint_stack }, 6497c478bd9Sstevel@tonic-gate { "lc", "lc", "int", pfcheck_type, pfprint_sint }, /* a.k.a. wint_t */ 6507c478bd9Sstevel@tonic-gate { "ld", "d", "long", pfcheck_type, pfprint_sint }, 6517c478bd9Sstevel@tonic-gate { "li", "i", "long", pfcheck_type, pfprint_sint }, 6527c478bd9Sstevel@tonic-gate { "lo", "o", "unsigned long", pfcheck_type, pfprint_uint }, 6537c478bd9Sstevel@tonic-gate { "lu", "u", "unsigned long", pfcheck_type, pfprint_uint }, 6547c478bd9Sstevel@tonic-gate { "ls", "ls", pfproto_wstr, pfcheck_wstr, pfprint_wstr }, 6557c478bd9Sstevel@tonic-gate { "lx", "x", "long", pfcheck_xlong, pfprint_uint }, 6567c478bd9Sstevel@tonic-gate { "lX", "X", "long", pfcheck_xlong, pfprint_uint }, 6577c478bd9Sstevel@tonic-gate { "lld", "d", "long long", pfcheck_type, pfprint_sint }, 6587c478bd9Sstevel@tonic-gate { "lli", "i", "long long", pfcheck_type, pfprint_sint }, 6597c478bd9Sstevel@tonic-gate { "llo", "o", "unsigned long long", pfcheck_type, pfprint_uint }, 6607c478bd9Sstevel@tonic-gate { "llu", "u", "unsigned long long", pfcheck_type, pfprint_uint }, 6617c478bd9Sstevel@tonic-gate { "llx", "x", "long long", pfcheck_xlonglong, pfprint_uint }, 6627c478bd9Sstevel@tonic-gate { "llX", "X", "long long", pfcheck_xlonglong, pfprint_uint }, 6637c478bd9Sstevel@tonic-gate { "Le", "e", "long double", pfcheck_type, pfprint_fp }, 6647c478bd9Sstevel@tonic-gate { "LE", "E", "long double", pfcheck_type, pfprint_fp }, 6657c478bd9Sstevel@tonic-gate { "Lf", "f", "long double", pfcheck_type, pfprint_fp }, 6667c478bd9Sstevel@tonic-gate { "Lg", "g", "long double", pfcheck_type, pfprint_fp }, 6677c478bd9Sstevel@tonic-gate { "LG", "G", "long double", pfcheck_type, pfprint_fp }, 6687c478bd9Sstevel@tonic-gate { "o", "o", pfproto_xint, pfcheck_xint, pfprint_uint }, 6697c478bd9Sstevel@tonic-gate { "p", "x", pfproto_addr, pfcheck_addr, pfprint_uint }, 670c9a6ea2eSBryan Cantrill { "P", "s", "uint16_t", pfcheck_type, pfprint_port }, 6717c478bd9Sstevel@tonic-gate { "s", "s", "char [] or string (or use stringof)", pfcheck_str, pfprint_cstr }, 6727c478bd9Sstevel@tonic-gate { "S", "s", pfproto_cstr, pfcheck_str, pfprint_estr }, 67330ef842dSbmc { "T", "s", "int64_t", pfcheck_time, pfprint_time822 }, 6747c478bd9Sstevel@tonic-gate { "u", "u", pfproto_xint, pfcheck_xint, pfprint_uint }, 6757c478bd9Sstevel@tonic-gate { "wc", "wc", "int", pfcheck_type, pfprint_sint }, /* a.k.a. wchar_t */ 6767c478bd9Sstevel@tonic-gate { "ws", "ws", pfproto_wstr, pfcheck_wstr, pfprint_wstr }, 6777c478bd9Sstevel@tonic-gate { "x", "x", pfproto_xint, pfcheck_xint, pfprint_uint }, 6787c478bd9Sstevel@tonic-gate { "X", "X", pfproto_xint, pfcheck_xint, pfprint_uint }, 67930ef842dSbmc { "Y", "s", "int64_t", pfcheck_time, pfprint_time }, 6807c478bd9Sstevel@tonic-gate { "%", "%", "void", pfcheck_type, pfprint_pct }, 6817c478bd9Sstevel@tonic-gate { NULL, NULL, NULL, NULL, NULL } 6827c478bd9Sstevel@tonic-gate }; 6837c478bd9Sstevel@tonic-gate 6847c478bd9Sstevel@tonic-gate int 6857c478bd9Sstevel@tonic-gate dt_pfdict_create(dtrace_hdl_t *dtp) 6867c478bd9Sstevel@tonic-gate { 6877c478bd9Sstevel@tonic-gate uint_t n = _dtrace_strbuckets; 6887c478bd9Sstevel@tonic-gate const dt_pfconv_t *pfd; 6897c478bd9Sstevel@tonic-gate dt_pfdict_t *pdi; 6907c478bd9Sstevel@tonic-gate 6917c478bd9Sstevel@tonic-gate if ((pdi = malloc(sizeof (dt_pfdict_t))) == NULL || 6927c478bd9Sstevel@tonic-gate (pdi->pdi_buckets = malloc(sizeof (dt_pfconv_t *) * n)) == NULL) { 6937c478bd9Sstevel@tonic-gate free(pdi); 6947c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 6957c478bd9Sstevel@tonic-gate } 6967c478bd9Sstevel@tonic-gate 6977c478bd9Sstevel@tonic-gate dtp->dt_pfdict = pdi; 6987c478bd9Sstevel@tonic-gate bzero(pdi->pdi_buckets, sizeof (dt_pfconv_t *) * n); 6997c478bd9Sstevel@tonic-gate pdi->pdi_nbuckets = n; 7007c478bd9Sstevel@tonic-gate 7017c478bd9Sstevel@tonic-gate for (pfd = _dtrace_conversions; pfd->pfc_name != NULL; pfd++) { 7027c478bd9Sstevel@tonic-gate dtrace_typeinfo_t dtt; 7037c478bd9Sstevel@tonic-gate dt_pfconv_t *pfc; 7047c478bd9Sstevel@tonic-gate uint_t h; 7057c478bd9Sstevel@tonic-gate 7067c478bd9Sstevel@tonic-gate if ((pfc = malloc(sizeof (dt_pfconv_t))) == NULL) { 7077c478bd9Sstevel@tonic-gate dt_pfdict_destroy(dtp); 7087c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 7097c478bd9Sstevel@tonic-gate } 7107c478bd9Sstevel@tonic-gate 7117c478bd9Sstevel@tonic-gate bcopy(pfd, pfc, sizeof (dt_pfconv_t)); 7127c478bd9Sstevel@tonic-gate h = dt_strtab_hash(pfc->pfc_name, NULL) % n; 7137c478bd9Sstevel@tonic-gate pfc->pfc_next = pdi->pdi_buckets[h]; 7147c478bd9Sstevel@tonic-gate pdi->pdi_buckets[h] = pfc; 7157c478bd9Sstevel@tonic-gate 7167c478bd9Sstevel@tonic-gate dtt.dtt_ctfp = NULL; 7177c478bd9Sstevel@tonic-gate dtt.dtt_type = CTF_ERR; 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate /* 7207c478bd9Sstevel@tonic-gate * The "D" container or its parent must contain a definition of 7217c478bd9Sstevel@tonic-gate * any type referenced by a printf conversion. If none can be 7227c478bd9Sstevel@tonic-gate * found, we fail to initialize the printf dictionary. 7237c478bd9Sstevel@tonic-gate */ 7247c478bd9Sstevel@tonic-gate if (pfc->pfc_check == &pfcheck_type && dtrace_lookup_by_type( 7257c478bd9Sstevel@tonic-gate dtp, DTRACE_OBJ_DDEFS, pfc->pfc_tstr, &dtt) != 0) { 7267c478bd9Sstevel@tonic-gate dt_pfdict_destroy(dtp); 7277c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOCONV)); 7287c478bd9Sstevel@tonic-gate } 7297c478bd9Sstevel@tonic-gate 7307c478bd9Sstevel@tonic-gate pfc->pfc_dctfp = dtt.dtt_ctfp; 7317c478bd9Sstevel@tonic-gate pfc->pfc_dtype = dtt.dtt_type; 7327c478bd9Sstevel@tonic-gate 7337c478bd9Sstevel@tonic-gate /* 7347c478bd9Sstevel@tonic-gate * The "C" container may contain an alternate definition of an 7357c478bd9Sstevel@tonic-gate * explicit conversion type. If it does, use it; otherwise 7367c478bd9Sstevel@tonic-gate * just set pfc_ctype to pfc_dtype so it is always valid. 7377c478bd9Sstevel@tonic-gate */ 7387c478bd9Sstevel@tonic-gate if (pfc->pfc_check == &pfcheck_type && dtrace_lookup_by_type( 7397c478bd9Sstevel@tonic-gate dtp, DTRACE_OBJ_CDEFS, pfc->pfc_tstr, &dtt) == 0) { 7407c478bd9Sstevel@tonic-gate pfc->pfc_cctfp = dtt.dtt_ctfp; 7417c478bd9Sstevel@tonic-gate pfc->pfc_ctype = dtt.dtt_type; 7427c478bd9Sstevel@tonic-gate } else { 7437c478bd9Sstevel@tonic-gate pfc->pfc_cctfp = pfc->pfc_dctfp; 7447c478bd9Sstevel@tonic-gate pfc->pfc_ctype = pfc->pfc_dtype; 7457c478bd9Sstevel@tonic-gate } 7467c478bd9Sstevel@tonic-gate 7477c478bd9Sstevel@tonic-gate if (pfc->pfc_check == NULL || pfc->pfc_print == NULL || 7487c478bd9Sstevel@tonic-gate pfc->pfc_ofmt == NULL || pfc->pfc_tstr == NULL) { 7497c478bd9Sstevel@tonic-gate dt_pfdict_destroy(dtp); 7507c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADCONV)); 7517c478bd9Sstevel@tonic-gate } 7527c478bd9Sstevel@tonic-gate 7537c478bd9Sstevel@tonic-gate dt_dprintf("loaded printf conversion %%%s\n", pfc->pfc_name); 7547c478bd9Sstevel@tonic-gate } 7557c478bd9Sstevel@tonic-gate 7567c478bd9Sstevel@tonic-gate return (0); 7577c478bd9Sstevel@tonic-gate } 7587c478bd9Sstevel@tonic-gate 7597c478bd9Sstevel@tonic-gate void 7607c478bd9Sstevel@tonic-gate dt_pfdict_destroy(dtrace_hdl_t *dtp) 7617c478bd9Sstevel@tonic-gate { 7627c478bd9Sstevel@tonic-gate dt_pfdict_t *pdi = dtp->dt_pfdict; 7637c478bd9Sstevel@tonic-gate dt_pfconv_t *pfc, *nfc; 7647c478bd9Sstevel@tonic-gate uint_t i; 7657c478bd9Sstevel@tonic-gate 7667c478bd9Sstevel@tonic-gate if (pdi == NULL) 7677c478bd9Sstevel@tonic-gate return; 7687c478bd9Sstevel@tonic-gate 7697c478bd9Sstevel@tonic-gate for (i = 0; i < pdi->pdi_nbuckets; i++) { 7707c478bd9Sstevel@tonic-gate for (pfc = pdi->pdi_buckets[i]; pfc != NULL; pfc = nfc) { 7717c478bd9Sstevel@tonic-gate nfc = pfc->pfc_next; 7727c478bd9Sstevel@tonic-gate free(pfc); 7737c478bd9Sstevel@tonic-gate } 7747c478bd9Sstevel@tonic-gate } 7757c478bd9Sstevel@tonic-gate 7767c478bd9Sstevel@tonic-gate free(pdi->pdi_buckets); 7777c478bd9Sstevel@tonic-gate free(pdi); 7787c478bd9Sstevel@tonic-gate dtp->dt_pfdict = NULL; 7797c478bd9Sstevel@tonic-gate } 7807c478bd9Sstevel@tonic-gate 7817c478bd9Sstevel@tonic-gate static const dt_pfconv_t * 7827c478bd9Sstevel@tonic-gate dt_pfdict_lookup(dtrace_hdl_t *dtp, const char *name) 7837c478bd9Sstevel@tonic-gate { 7847c478bd9Sstevel@tonic-gate dt_pfdict_t *pdi = dtp->dt_pfdict; 7857c478bd9Sstevel@tonic-gate uint_t h = dt_strtab_hash(name, NULL) % pdi->pdi_nbuckets; 7867c478bd9Sstevel@tonic-gate const dt_pfconv_t *pfc; 7877c478bd9Sstevel@tonic-gate 7887c478bd9Sstevel@tonic-gate for (pfc = pdi->pdi_buckets[h]; pfc != NULL; pfc = pfc->pfc_next) { 7897c478bd9Sstevel@tonic-gate if (strcmp(pfc->pfc_name, name) == 0) 7907c478bd9Sstevel@tonic-gate break; 7917c478bd9Sstevel@tonic-gate } 7927c478bd9Sstevel@tonic-gate 7937c478bd9Sstevel@tonic-gate return (pfc); 7947c478bd9Sstevel@tonic-gate } 7957c478bd9Sstevel@tonic-gate 7967c478bd9Sstevel@tonic-gate static dt_pfargv_t * 7977c478bd9Sstevel@tonic-gate dt_printf_error(dtrace_hdl_t *dtp, int err) 7987c478bd9Sstevel@tonic-gate { 7997c478bd9Sstevel@tonic-gate if (yypcb != NULL) 8007c478bd9Sstevel@tonic-gate longjmp(yypcb->pcb_jmpbuf, err); 8017c478bd9Sstevel@tonic-gate 8027c478bd9Sstevel@tonic-gate (void) dt_set_errno(dtp, err); 8037c478bd9Sstevel@tonic-gate return (NULL); 8047c478bd9Sstevel@tonic-gate } 8057c478bd9Sstevel@tonic-gate 8067c478bd9Sstevel@tonic-gate dt_pfargv_t * 8077c478bd9Sstevel@tonic-gate dt_printf_create(dtrace_hdl_t *dtp, const char *s) 8087c478bd9Sstevel@tonic-gate { 8097c478bd9Sstevel@tonic-gate dt_pfargd_t *pfd, *nfd = NULL; 8107c478bd9Sstevel@tonic-gate dt_pfargv_t *pfv; 8117c478bd9Sstevel@tonic-gate const char *p, *q; 8127c478bd9Sstevel@tonic-gate char *format; 8137c478bd9Sstevel@tonic-gate 8147c478bd9Sstevel@tonic-gate if ((pfv = malloc(sizeof (dt_pfargv_t))) == NULL || 8157c478bd9Sstevel@tonic-gate (format = strdup(s)) == NULL) { 8167c478bd9Sstevel@tonic-gate free(pfv); 8177c478bd9Sstevel@tonic-gate return (dt_printf_error(dtp, EDT_NOMEM)); 8187c478bd9Sstevel@tonic-gate } 8197c478bd9Sstevel@tonic-gate 8207c478bd9Sstevel@tonic-gate pfv->pfv_format = format; 8217c478bd9Sstevel@tonic-gate pfv->pfv_argv = NULL; 8227c478bd9Sstevel@tonic-gate pfv->pfv_argc = 0; 8237c478bd9Sstevel@tonic-gate pfv->pfv_flags = 0; 824a1b5e537Sbmc pfv->pfv_dtp = dtp; 8257c478bd9Sstevel@tonic-gate 8267c478bd9Sstevel@tonic-gate for (q = format; (p = strchr(q, '%')) != NULL; q = *p ? p + 1 : p) { 8277c478bd9Sstevel@tonic-gate uint_t namelen = 0; 8287c478bd9Sstevel@tonic-gate int digits = 0; 8297c478bd9Sstevel@tonic-gate int dot = 0; 8307c478bd9Sstevel@tonic-gate 8317c478bd9Sstevel@tonic-gate char name[8]; 8327c478bd9Sstevel@tonic-gate char c; 8337c478bd9Sstevel@tonic-gate int n; 8347c478bd9Sstevel@tonic-gate 8357c478bd9Sstevel@tonic-gate if ((pfd = malloc(sizeof (dt_pfargd_t))) == NULL) { 8367c478bd9Sstevel@tonic-gate dt_printf_destroy(pfv); 8377c478bd9Sstevel@tonic-gate return (dt_printf_error(dtp, EDT_NOMEM)); 8387c478bd9Sstevel@tonic-gate } 8397c478bd9Sstevel@tonic-gate 8407c478bd9Sstevel@tonic-gate if (pfv->pfv_argv != NULL) 8417c478bd9Sstevel@tonic-gate nfd->pfd_next = pfd; 8427c478bd9Sstevel@tonic-gate else 8437c478bd9Sstevel@tonic-gate pfv->pfv_argv = pfd; 8447c478bd9Sstevel@tonic-gate 8457c478bd9Sstevel@tonic-gate bzero(pfd, sizeof (dt_pfargd_t)); 8467c478bd9Sstevel@tonic-gate pfv->pfv_argc++; 8477c478bd9Sstevel@tonic-gate nfd = pfd; 8487c478bd9Sstevel@tonic-gate 8497c478bd9Sstevel@tonic-gate if (p > q) { 8507c478bd9Sstevel@tonic-gate pfd->pfd_preflen = (size_t)(p - q); 8517c478bd9Sstevel@tonic-gate pfd->pfd_prefix = q; 8527c478bd9Sstevel@tonic-gate } 8537c478bd9Sstevel@tonic-gate 8547c478bd9Sstevel@tonic-gate fmt_switch: 8557c478bd9Sstevel@tonic-gate switch (c = *++p) { 8567c478bd9Sstevel@tonic-gate case '0': case '1': case '2': case '3': case '4': 8577c478bd9Sstevel@tonic-gate case '5': case '6': case '7': case '8': case '9': 8587c478bd9Sstevel@tonic-gate if (dot == 0 && digits == 0 && c == '0') { 8597c478bd9Sstevel@tonic-gate pfd->pfd_flags |= DT_PFCONV_ZPAD; 8607c478bd9Sstevel@tonic-gate pfd->pfd_flags &= ~DT_PFCONV_LEFT; 8617c478bd9Sstevel@tonic-gate goto fmt_switch; 8627c478bd9Sstevel@tonic-gate } 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate for (n = 0; isdigit(c); c = *++p) 8657c478bd9Sstevel@tonic-gate n = n * 10 + c - '0'; 8667c478bd9Sstevel@tonic-gate 8677c478bd9Sstevel@tonic-gate if (dot) 8687c478bd9Sstevel@tonic-gate pfd->pfd_prec = n; 8697c478bd9Sstevel@tonic-gate else 8707c478bd9Sstevel@tonic-gate pfd->pfd_width = n; 8717c478bd9Sstevel@tonic-gate 8727c478bd9Sstevel@tonic-gate p--; 8737c478bd9Sstevel@tonic-gate digits++; 8747c478bd9Sstevel@tonic-gate goto fmt_switch; 8757c478bd9Sstevel@tonic-gate 8767c478bd9Sstevel@tonic-gate case '#': 8777c478bd9Sstevel@tonic-gate pfd->pfd_flags |= DT_PFCONV_ALT; 8787c478bd9Sstevel@tonic-gate goto fmt_switch; 8797c478bd9Sstevel@tonic-gate 8807c478bd9Sstevel@tonic-gate case '*': 8817c478bd9Sstevel@tonic-gate n = dot ? DT_PFCONV_DYNPREC : DT_PFCONV_DYNWIDTH; 8827c478bd9Sstevel@tonic-gate 8837c478bd9Sstevel@tonic-gate if (pfd->pfd_flags & n) { 8847c478bd9Sstevel@tonic-gate yywarn("format conversion #%u has more than " 8857c478bd9Sstevel@tonic-gate "one '*' specified for the output %s\n", 8867c478bd9Sstevel@tonic-gate pfv->pfv_argc, n ? "precision" : "width"); 8877c478bd9Sstevel@tonic-gate 8887c478bd9Sstevel@tonic-gate dt_printf_destroy(pfv); 8897c478bd9Sstevel@tonic-gate return (dt_printf_error(dtp, EDT_COMPILER)); 8907c478bd9Sstevel@tonic-gate } 8917c478bd9Sstevel@tonic-gate 8927c478bd9Sstevel@tonic-gate pfd->pfd_flags |= n; 8937c478bd9Sstevel@tonic-gate goto fmt_switch; 8947c478bd9Sstevel@tonic-gate 8957c478bd9Sstevel@tonic-gate case '+': 8967c478bd9Sstevel@tonic-gate pfd->pfd_flags |= DT_PFCONV_SPOS; 8977c478bd9Sstevel@tonic-gate goto fmt_switch; 8987c478bd9Sstevel@tonic-gate 8997c478bd9Sstevel@tonic-gate case '-': 9007c478bd9Sstevel@tonic-gate pfd->pfd_flags |= DT_PFCONV_LEFT; 9017c478bd9Sstevel@tonic-gate pfd->pfd_flags &= ~DT_PFCONV_ZPAD; 9027c478bd9Sstevel@tonic-gate goto fmt_switch; 9037c478bd9Sstevel@tonic-gate 9047c478bd9Sstevel@tonic-gate case '.': 9057c478bd9Sstevel@tonic-gate if (dot++ != 0) { 9067c478bd9Sstevel@tonic-gate yywarn("format conversion #%u has more than " 9077c478bd9Sstevel@tonic-gate "one '.' specified\n", pfv->pfv_argc); 9087c478bd9Sstevel@tonic-gate 9097c478bd9Sstevel@tonic-gate dt_printf_destroy(pfv); 9107c478bd9Sstevel@tonic-gate return (dt_printf_error(dtp, EDT_COMPILER)); 9117c478bd9Sstevel@tonic-gate } 9127c478bd9Sstevel@tonic-gate digits = 0; 9137c478bd9Sstevel@tonic-gate goto fmt_switch; 9147c478bd9Sstevel@tonic-gate 9157c478bd9Sstevel@tonic-gate case '?': 9167c478bd9Sstevel@tonic-gate if (dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_LP64) 9177c478bd9Sstevel@tonic-gate pfd->pfd_width = 16; 9187c478bd9Sstevel@tonic-gate else 9197c478bd9Sstevel@tonic-gate pfd->pfd_width = 8; 9207c478bd9Sstevel@tonic-gate goto fmt_switch; 9217c478bd9Sstevel@tonic-gate 9227c478bd9Sstevel@tonic-gate case '@': 9237c478bd9Sstevel@tonic-gate pfd->pfd_flags |= DT_PFCONV_AGG; 9247c478bd9Sstevel@tonic-gate goto fmt_switch; 9257c478bd9Sstevel@tonic-gate 9267c478bd9Sstevel@tonic-gate case '\'': 9277c478bd9Sstevel@tonic-gate pfd->pfd_flags |= DT_PFCONV_GROUP; 9287c478bd9Sstevel@tonic-gate goto fmt_switch; 9297c478bd9Sstevel@tonic-gate 9307c478bd9Sstevel@tonic-gate case ' ': 9317c478bd9Sstevel@tonic-gate pfd->pfd_flags |= DT_PFCONV_SPACE; 9327c478bd9Sstevel@tonic-gate goto fmt_switch; 9337c478bd9Sstevel@tonic-gate 9347c478bd9Sstevel@tonic-gate case '$': 9357c478bd9Sstevel@tonic-gate yywarn("format conversion #%u uses unsupported " 9367c478bd9Sstevel@tonic-gate "positional format (%%n$)\n", pfv->pfv_argc); 9377c478bd9Sstevel@tonic-gate 9387c478bd9Sstevel@tonic-gate dt_printf_destroy(pfv); 9397c478bd9Sstevel@tonic-gate return (dt_printf_error(dtp, EDT_COMPILER)); 9407c478bd9Sstevel@tonic-gate 9417c478bd9Sstevel@tonic-gate case '%': 9427c478bd9Sstevel@tonic-gate if (p[-1] == '%') 9437c478bd9Sstevel@tonic-gate goto default_lbl; /* if %% then use "%" conv */ 9447c478bd9Sstevel@tonic-gate 9457c478bd9Sstevel@tonic-gate yywarn("format conversion #%u cannot be combined " 9467c478bd9Sstevel@tonic-gate "with other format flags: %%%%\n", pfv->pfv_argc); 9477c478bd9Sstevel@tonic-gate 9487c478bd9Sstevel@tonic-gate dt_printf_destroy(pfv); 9497c478bd9Sstevel@tonic-gate return (dt_printf_error(dtp, EDT_COMPILER)); 9507c478bd9Sstevel@tonic-gate 9517c478bd9Sstevel@tonic-gate case '\0': 9527c478bd9Sstevel@tonic-gate yywarn("format conversion #%u name expected before " 9537c478bd9Sstevel@tonic-gate "end of format string\n", pfv->pfv_argc); 9547c478bd9Sstevel@tonic-gate 9557c478bd9Sstevel@tonic-gate dt_printf_destroy(pfv); 9567c478bd9Sstevel@tonic-gate return (dt_printf_error(dtp, EDT_COMPILER)); 9577c478bd9Sstevel@tonic-gate 9587c478bd9Sstevel@tonic-gate case 'h': 9597c478bd9Sstevel@tonic-gate case 'l': 9607c478bd9Sstevel@tonic-gate case 'L': 9617c478bd9Sstevel@tonic-gate case 'w': 9627c478bd9Sstevel@tonic-gate if (namelen < sizeof (name) - 2) 9637c478bd9Sstevel@tonic-gate name[namelen++] = c; 9647c478bd9Sstevel@tonic-gate goto fmt_switch; 9657c478bd9Sstevel@tonic-gate 9667c478bd9Sstevel@tonic-gate default_lbl: 9677c478bd9Sstevel@tonic-gate default: 9687c478bd9Sstevel@tonic-gate name[namelen++] = c; 9697c478bd9Sstevel@tonic-gate name[namelen] = '\0'; 9707c478bd9Sstevel@tonic-gate } 9717c478bd9Sstevel@tonic-gate 9727c478bd9Sstevel@tonic-gate pfd->pfd_conv = dt_pfdict_lookup(dtp, name); 9737c478bd9Sstevel@tonic-gate 9747c478bd9Sstevel@tonic-gate if (pfd->pfd_conv == NULL) { 9757c478bd9Sstevel@tonic-gate yywarn("format conversion #%u is undefined: %%%s\n", 9767c478bd9Sstevel@tonic-gate pfv->pfv_argc, name); 9777c478bd9Sstevel@tonic-gate dt_printf_destroy(pfv); 9787c478bd9Sstevel@tonic-gate return (dt_printf_error(dtp, EDT_COMPILER)); 9797c478bd9Sstevel@tonic-gate } 9807c478bd9Sstevel@tonic-gate } 9817c478bd9Sstevel@tonic-gate 9827c478bd9Sstevel@tonic-gate if (*q != '\0' || *format == '\0') { 9837c478bd9Sstevel@tonic-gate if ((pfd = malloc(sizeof (dt_pfargd_t))) == NULL) { 9847c478bd9Sstevel@tonic-gate dt_printf_destroy(pfv); 9857c478bd9Sstevel@tonic-gate return (dt_printf_error(dtp, EDT_NOMEM)); 9867c478bd9Sstevel@tonic-gate } 9877c478bd9Sstevel@tonic-gate 9887c478bd9Sstevel@tonic-gate if (pfv->pfv_argv != NULL) 9897c478bd9Sstevel@tonic-gate nfd->pfd_next = pfd; 9907c478bd9Sstevel@tonic-gate else 9917c478bd9Sstevel@tonic-gate pfv->pfv_argv = pfd; 9927c478bd9Sstevel@tonic-gate 9937c478bd9Sstevel@tonic-gate bzero(pfd, sizeof (dt_pfargd_t)); 9947c478bd9Sstevel@tonic-gate pfv->pfv_argc++; 9957c478bd9Sstevel@tonic-gate 9967c478bd9Sstevel@tonic-gate pfd->pfd_prefix = q; 9977c478bd9Sstevel@tonic-gate pfd->pfd_preflen = strlen(q); 9987c478bd9Sstevel@tonic-gate } 9997c478bd9Sstevel@tonic-gate 10007c478bd9Sstevel@tonic-gate return (pfv); 10017c478bd9Sstevel@tonic-gate } 10027c478bd9Sstevel@tonic-gate 10037c478bd9Sstevel@tonic-gate void 10047c478bd9Sstevel@tonic-gate dt_printf_destroy(dt_pfargv_t *pfv) 10057c478bd9Sstevel@tonic-gate { 10067c478bd9Sstevel@tonic-gate dt_pfargd_t *pfd, *nfd; 10077c478bd9Sstevel@tonic-gate 10087c478bd9Sstevel@tonic-gate for (pfd = pfv->pfv_argv; pfd != NULL; pfd = nfd) { 10097c478bd9Sstevel@tonic-gate nfd = pfd->pfd_next; 10107c478bd9Sstevel@tonic-gate free(pfd); 10117c478bd9Sstevel@tonic-gate } 10127c478bd9Sstevel@tonic-gate 10137c478bd9Sstevel@tonic-gate free(pfv->pfv_format); 10147c478bd9Sstevel@tonic-gate free(pfv); 10157c478bd9Sstevel@tonic-gate } 10167c478bd9Sstevel@tonic-gate 10177c478bd9Sstevel@tonic-gate void 10187c478bd9Sstevel@tonic-gate dt_printf_validate(dt_pfargv_t *pfv, uint_t flags, 10197c478bd9Sstevel@tonic-gate dt_ident_t *idp, int foff, dtrace_actkind_t kind, dt_node_t *dnp) 10207c478bd9Sstevel@tonic-gate { 10217c478bd9Sstevel@tonic-gate dt_pfargd_t *pfd = pfv->pfv_argv; 10227c478bd9Sstevel@tonic-gate const char *func = idp->di_name; 10237c478bd9Sstevel@tonic-gate 10247c478bd9Sstevel@tonic-gate char n[DT_TYPE_NAMELEN]; 10257c478bd9Sstevel@tonic-gate dtrace_typeinfo_t dtt; 10267c478bd9Sstevel@tonic-gate const char *aggtype; 10277c478bd9Sstevel@tonic-gate dt_node_t aggnode; 10287c478bd9Sstevel@tonic-gate int i, j; 10297c478bd9Sstevel@tonic-gate 10307c478bd9Sstevel@tonic-gate if (pfv->pfv_format[0] == '\0') { 10317c478bd9Sstevel@tonic-gate xyerror(D_PRINTF_FMT_EMPTY, 10327c478bd9Sstevel@tonic-gate "%s( ) format string is empty\n", func); 10337c478bd9Sstevel@tonic-gate } 10347c478bd9Sstevel@tonic-gate 1035a1b5e537Sbmc pfv->pfv_flags = flags; 1036a1b5e537Sbmc 10377c478bd9Sstevel@tonic-gate /* 10387c478bd9Sstevel@tonic-gate * We fake up a parse node representing the type that can be used with 1039187eccf8Sbmc * an aggregation result conversion, which -- for all but count() -- 1040187eccf8Sbmc * is a signed quantity. 10417c478bd9Sstevel@tonic-gate */ 1042187eccf8Sbmc if (kind != DTRACEAGG_COUNT) 10437c478bd9Sstevel@tonic-gate aggtype = "int64_t"; 10447c478bd9Sstevel@tonic-gate else 10457c478bd9Sstevel@tonic-gate aggtype = "uint64_t"; 10467c478bd9Sstevel@tonic-gate 10477c478bd9Sstevel@tonic-gate if (dt_type_lookup(aggtype, &dtt) != 0) 10487c478bd9Sstevel@tonic-gate xyerror(D_TYPE_ERR, "failed to lookup agg type %s\n", aggtype); 10497c478bd9Sstevel@tonic-gate 10507c478bd9Sstevel@tonic-gate bzero(&aggnode, sizeof (aggnode)); 1051*a386cc11SRobert Mustacchi dt_node_type_assign(&aggnode, dtt.dtt_ctfp, dtt.dtt_type, B_FALSE); 10527c478bd9Sstevel@tonic-gate 10537c478bd9Sstevel@tonic-gate for (i = 0, j = 0; i < pfv->pfv_argc; i++, pfd = pfd->pfd_next) { 10547c478bd9Sstevel@tonic-gate const dt_pfconv_t *pfc = pfd->pfd_conv; 10557c478bd9Sstevel@tonic-gate const char *dyns[2]; 10567c478bd9Sstevel@tonic-gate int dync = 0; 10577c478bd9Sstevel@tonic-gate 10587c478bd9Sstevel@tonic-gate char vname[64]; 10597c478bd9Sstevel@tonic-gate dt_node_t *vnp; 10607c478bd9Sstevel@tonic-gate 10617c478bd9Sstevel@tonic-gate if (pfc == NULL) 10627c478bd9Sstevel@tonic-gate continue; /* no checking if argd is just a prefix */ 10637c478bd9Sstevel@tonic-gate 10647c478bd9Sstevel@tonic-gate if (pfc->pfc_print == &pfprint_pct) { 10657c478bd9Sstevel@tonic-gate (void) strcat(pfd->pfd_fmt, pfc->pfc_ofmt); 10667c478bd9Sstevel@tonic-gate continue; 10677c478bd9Sstevel@tonic-gate } 10687c478bd9Sstevel@tonic-gate 10697c478bd9Sstevel@tonic-gate if (pfd->pfd_flags & DT_PFCONV_DYNPREC) 10707c478bd9Sstevel@tonic-gate dyns[dync++] = ".*"; 10717c478bd9Sstevel@tonic-gate if (pfd->pfd_flags & DT_PFCONV_DYNWIDTH) 10727c478bd9Sstevel@tonic-gate dyns[dync++] = "*"; 10737c478bd9Sstevel@tonic-gate 10747c478bd9Sstevel@tonic-gate for (; dync != 0; dync--) { 10757c478bd9Sstevel@tonic-gate if (dnp == NULL) { 10767c478bd9Sstevel@tonic-gate xyerror(D_PRINTF_DYN_PROTO, 10777c478bd9Sstevel@tonic-gate "%s( ) prototype mismatch: conversion " 10787c478bd9Sstevel@tonic-gate "#%d (%%%s) is missing a corresponding " 10797c478bd9Sstevel@tonic-gate "\"%s\" argument\n", func, i + 1, 10807c478bd9Sstevel@tonic-gate pfc->pfc_name, dyns[dync - 1]); 10817c478bd9Sstevel@tonic-gate } 10827c478bd9Sstevel@tonic-gate 10837c478bd9Sstevel@tonic-gate if (dt_node_is_integer(dnp) == 0) { 10847c478bd9Sstevel@tonic-gate xyerror(D_PRINTF_DYN_TYPE, 10857c478bd9Sstevel@tonic-gate "%s( ) argument #%d is incompatible " 10867c478bd9Sstevel@tonic-gate "with conversion #%d prototype:\n" 10877c478bd9Sstevel@tonic-gate "\tconversion: %% %s %s\n" 10887c478bd9Sstevel@tonic-gate "\t prototype: int\n\t argument: %s\n", 10897c478bd9Sstevel@tonic-gate func, j + foff + 1, i + 1, 10907c478bd9Sstevel@tonic-gate dyns[dync - 1], pfc->pfc_name, 10917c478bd9Sstevel@tonic-gate dt_node_type_name(dnp, n, sizeof (n))); 10927c478bd9Sstevel@tonic-gate } 10937c478bd9Sstevel@tonic-gate 10947c478bd9Sstevel@tonic-gate dnp = dnp->dn_list; 10957c478bd9Sstevel@tonic-gate j++; 10967c478bd9Sstevel@tonic-gate } 10977c478bd9Sstevel@tonic-gate 10987c478bd9Sstevel@tonic-gate /* 10997c478bd9Sstevel@tonic-gate * If this conversion is consuming the aggregation data, set 11007c478bd9Sstevel@tonic-gate * the value node pointer (vnp) to a fake node based on the 11017c478bd9Sstevel@tonic-gate * aggregating function result type. Otherwise assign vnp to 11027c478bd9Sstevel@tonic-gate * the next parse node in the argument list, if there is one. 11037c478bd9Sstevel@tonic-gate */ 11047c478bd9Sstevel@tonic-gate if (pfd->pfd_flags & DT_PFCONV_AGG) { 11057c478bd9Sstevel@tonic-gate if (!(flags & DT_PRINTF_AGGREGATION)) { 11067c478bd9Sstevel@tonic-gate xyerror(D_PRINTF_AGG_CONV, 11077c478bd9Sstevel@tonic-gate "%%@ conversion requires an aggregation" 11087c478bd9Sstevel@tonic-gate " and is not for use with %s( )\n", func); 11097c478bd9Sstevel@tonic-gate } 11107c478bd9Sstevel@tonic-gate (void) strlcpy(vname, "aggregating action", 11117c478bd9Sstevel@tonic-gate sizeof (vname)); 11127c478bd9Sstevel@tonic-gate vnp = &aggnode; 11137c478bd9Sstevel@tonic-gate } else if (dnp == NULL) { 11147c478bd9Sstevel@tonic-gate xyerror(D_PRINTF_ARG_PROTO, 11157c478bd9Sstevel@tonic-gate "%s( ) prototype mismatch: conversion #%d (%%" 11167c478bd9Sstevel@tonic-gate "%s) is missing a corresponding value argument\n", 11177c478bd9Sstevel@tonic-gate func, i + 1, pfc->pfc_name); 11187c478bd9Sstevel@tonic-gate } else { 11197c478bd9Sstevel@tonic-gate (void) snprintf(vname, sizeof (vname), 11207c478bd9Sstevel@tonic-gate "argument #%d", j + foff + 1); 11217c478bd9Sstevel@tonic-gate vnp = dnp; 11227c478bd9Sstevel@tonic-gate dnp = dnp->dn_list; 11237c478bd9Sstevel@tonic-gate j++; 11247c478bd9Sstevel@tonic-gate } 11257c478bd9Sstevel@tonic-gate 11267c478bd9Sstevel@tonic-gate /* 11277c478bd9Sstevel@tonic-gate * Fill in the proposed final format string by prepending any 11287c478bd9Sstevel@tonic-gate * size-related prefixes to the pfconv's format string. The 11297c478bd9Sstevel@tonic-gate * pfc_check() function below may optionally modify the format 11307c478bd9Sstevel@tonic-gate * as part of validating the type of the input argument. 11317c478bd9Sstevel@tonic-gate */ 11327c478bd9Sstevel@tonic-gate if (pfc->pfc_print == &pfprint_sint || 11337c478bd9Sstevel@tonic-gate pfc->pfc_print == &pfprint_uint || 11347c478bd9Sstevel@tonic-gate pfc->pfc_print == &pfprint_dint) { 11357c478bd9Sstevel@tonic-gate if (dt_node_type_size(vnp) == sizeof (uint64_t)) 11367c478bd9Sstevel@tonic-gate (void) strcpy(pfd->pfd_fmt, "ll"); 11377c478bd9Sstevel@tonic-gate } else if (pfc->pfc_print == &pfprint_fp) { 11387c478bd9Sstevel@tonic-gate if (dt_node_type_size(vnp) == sizeof (long double)) 11397c478bd9Sstevel@tonic-gate (void) strcpy(pfd->pfd_fmt, "L"); 11407c478bd9Sstevel@tonic-gate } 11417c478bd9Sstevel@tonic-gate 11427c478bd9Sstevel@tonic-gate (void) strcat(pfd->pfd_fmt, pfc->pfc_ofmt); 11437c478bd9Sstevel@tonic-gate 11447c478bd9Sstevel@tonic-gate /* 11457c478bd9Sstevel@tonic-gate * Validate the format conversion against the value node type. 11467c478bd9Sstevel@tonic-gate * If the conversion is good, create the descriptor format 11477c478bd9Sstevel@tonic-gate * string by concatenating together any required printf(3C) 11487c478bd9Sstevel@tonic-gate * size prefixes with the conversion's native format string. 11497c478bd9Sstevel@tonic-gate */ 1150a1b5e537Sbmc if (pfc->pfc_check(pfv, pfd, vnp) == 0) { 11517c478bd9Sstevel@tonic-gate xyerror(D_PRINTF_ARG_TYPE, 11527c478bd9Sstevel@tonic-gate "%s( ) %s is incompatible with " 11537c478bd9Sstevel@tonic-gate "conversion #%d prototype:\n\tconversion: %%%s\n" 11547c478bd9Sstevel@tonic-gate "\t prototype: %s\n\t argument: %s\n", func, 11557c478bd9Sstevel@tonic-gate vname, i + 1, pfc->pfc_name, pfc->pfc_tstr, 11567c478bd9Sstevel@tonic-gate dt_node_type_name(vnp, n, sizeof (n))); 11577c478bd9Sstevel@tonic-gate } 11587c478bd9Sstevel@tonic-gate } 11597c478bd9Sstevel@tonic-gate 11607c478bd9Sstevel@tonic-gate if ((flags & DT_PRINTF_EXACTLEN) && dnp != NULL) { 11617c478bd9Sstevel@tonic-gate xyerror(D_PRINTF_ARG_EXTRA, 11627c478bd9Sstevel@tonic-gate "%s( ) prototype mismatch: only %d arguments " 11637c478bd9Sstevel@tonic-gate "required by this format string\n", func, j); 11647c478bd9Sstevel@tonic-gate } 11657c478bd9Sstevel@tonic-gate } 11667c478bd9Sstevel@tonic-gate 116730ef842dSbmc void 116830ef842dSbmc dt_printa_validate(dt_node_t *lhs, dt_node_t *rhs) 116930ef842dSbmc { 117030ef842dSbmc dt_ident_t *lid, *rid; 117130ef842dSbmc dt_node_t *lproto, *rproto; 117230ef842dSbmc int largc, rargc, argn; 117330ef842dSbmc char n1[DT_TYPE_NAMELEN]; 117430ef842dSbmc char n2[DT_TYPE_NAMELEN]; 117530ef842dSbmc 117630ef842dSbmc assert(lhs->dn_kind == DT_NODE_AGG); 117730ef842dSbmc assert(rhs->dn_kind == DT_NODE_AGG); 117830ef842dSbmc 117930ef842dSbmc lid = lhs->dn_ident; 118030ef842dSbmc rid = rhs->dn_ident; 118130ef842dSbmc 118230ef842dSbmc lproto = ((dt_idsig_t *)lid->di_data)->dis_args; 118330ef842dSbmc rproto = ((dt_idsig_t *)rid->di_data)->dis_args; 118430ef842dSbmc 118530ef842dSbmc /* 118630ef842dSbmc * First, get an argument count on each side. These must match. 118730ef842dSbmc */ 118830ef842dSbmc for (largc = 0; lproto != NULL; lproto = lproto->dn_list) 118930ef842dSbmc largc++; 119030ef842dSbmc 119130ef842dSbmc for (rargc = 0; rproto != NULL; rproto = rproto->dn_list) 119230ef842dSbmc rargc++; 119330ef842dSbmc 119430ef842dSbmc if (largc != rargc) { 119530ef842dSbmc xyerror(D_PRINTA_AGGKEY, "printa( ): @%s and @%s do not have " 119630ef842dSbmc "matching key signatures: @%s has %d key%s, @%s has %d " 119730ef842dSbmc "key%s", lid->di_name, rid->di_name, 119830ef842dSbmc lid->di_name, largc, largc == 1 ? "" : "s", 119930ef842dSbmc rid->di_name, rargc, rargc == 1 ? "" : "s"); 120030ef842dSbmc } 120130ef842dSbmc 120230ef842dSbmc /* 120330ef842dSbmc * Now iterate over the keys to verify that each type matches. 120430ef842dSbmc */ 120530ef842dSbmc lproto = ((dt_idsig_t *)lid->di_data)->dis_args; 120630ef842dSbmc rproto = ((dt_idsig_t *)rid->di_data)->dis_args; 120730ef842dSbmc 120830ef842dSbmc for (argn = 1; lproto != NULL; argn++, lproto = lproto->dn_list, 120930ef842dSbmc rproto = rproto->dn_list) { 121030ef842dSbmc assert(rproto != NULL); 121130ef842dSbmc 121230ef842dSbmc if (dt_node_is_argcompat(lproto, rproto)) 121330ef842dSbmc continue; 121430ef842dSbmc 121530ef842dSbmc xyerror(D_PRINTA_AGGPROTO, "printa( ): @%s[ ] key #%d is " 121630ef842dSbmc "incompatible with @%s:\n%9s key #%d: %s\n" 121730ef842dSbmc "%9s key #%d: %s\n", 121830ef842dSbmc rid->di_name, argn, lid->di_name, lid->di_name, argn, 121930ef842dSbmc dt_node_type_name(lproto, n1, sizeof (n1)), rid->di_name, 122030ef842dSbmc argn, dt_node_type_name(rproto, n2, sizeof (n2))); 122130ef842dSbmc } 122230ef842dSbmc } 122330ef842dSbmc 12247c478bd9Sstevel@tonic-gate static int 12257c478bd9Sstevel@tonic-gate dt_printf_getint(dtrace_hdl_t *dtp, const dtrace_recdesc_t *recp, 12267c478bd9Sstevel@tonic-gate uint_t nrecs, const void *buf, size_t len, int *ip) 12277c478bd9Sstevel@tonic-gate { 12287c478bd9Sstevel@tonic-gate uintptr_t addr; 12297c478bd9Sstevel@tonic-gate 12307c478bd9Sstevel@tonic-gate if (nrecs == 0) 12317c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DMISMATCH)); 12327c478bd9Sstevel@tonic-gate 12337c478bd9Sstevel@tonic-gate addr = (uintptr_t)buf + recp->dtrd_offset; 12347c478bd9Sstevel@tonic-gate 12357c478bd9Sstevel@tonic-gate if (addr + sizeof (int) > (uintptr_t)buf + len) 12367c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DOFFSET)); 12377c478bd9Sstevel@tonic-gate 12387c478bd9Sstevel@tonic-gate if (addr & (recp->dtrd_alignment - 1)) 12397c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DALIGN)); 12407c478bd9Sstevel@tonic-gate 12417c478bd9Sstevel@tonic-gate switch (recp->dtrd_size) { 12427c478bd9Sstevel@tonic-gate case sizeof (int8_t): 12437c478bd9Sstevel@tonic-gate *ip = (int)*((int8_t *)addr); 12447c478bd9Sstevel@tonic-gate break; 12457c478bd9Sstevel@tonic-gate case sizeof (int16_t): 12467c478bd9Sstevel@tonic-gate *ip = (int)*((int16_t *)addr); 12477c478bd9Sstevel@tonic-gate break; 12487c478bd9Sstevel@tonic-gate case sizeof (int32_t): 12497c478bd9Sstevel@tonic-gate *ip = (int)*((int32_t *)addr); 12507c478bd9Sstevel@tonic-gate break; 12517c478bd9Sstevel@tonic-gate case sizeof (int64_t): 12527c478bd9Sstevel@tonic-gate *ip = (int)*((int64_t *)addr); 12537c478bd9Sstevel@tonic-gate break; 12547c478bd9Sstevel@tonic-gate default: 12557c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DMISMATCH)); 12567c478bd9Sstevel@tonic-gate } 12577c478bd9Sstevel@tonic-gate 12587c478bd9Sstevel@tonic-gate return (0); 12597c478bd9Sstevel@tonic-gate } 12607c478bd9Sstevel@tonic-gate 12617c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 12627c478bd9Sstevel@tonic-gate static int 12637c478bd9Sstevel@tonic-gate pfprint_average(dtrace_hdl_t *dtp, FILE *fp, const char *format, 12647c478bd9Sstevel@tonic-gate const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal) 12657c478bd9Sstevel@tonic-gate { 12667c478bd9Sstevel@tonic-gate const uint64_t *data = addr; 12677c478bd9Sstevel@tonic-gate 12687c478bd9Sstevel@tonic-gate if (size != sizeof (uint64_t) * 2) 12697c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DMISMATCH)); 12707c478bd9Sstevel@tonic-gate 12717c478bd9Sstevel@tonic-gate return (dt_printf(dtp, fp, format, 12727c478bd9Sstevel@tonic-gate data[0] ? data[1] / normal / data[0] : 0)); 12737c478bd9Sstevel@tonic-gate } 12747c478bd9Sstevel@tonic-gate 12757c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 12767c478bd9Sstevel@tonic-gate static int 1277ccf8180eSRafael Vanoni pfprint_stddev(dtrace_hdl_t *dtp, FILE *fp, const char *format, 1278ccf8180eSRafael Vanoni const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal) 1279ccf8180eSRafael Vanoni { 1280ccf8180eSRafael Vanoni const uint64_t *data = addr; 1281ccf8180eSRafael Vanoni 1282ccf8180eSRafael Vanoni if (size != sizeof (uint64_t) * 4) 1283ccf8180eSRafael Vanoni return (dt_set_errno(dtp, EDT_DMISMATCH)); 1284ccf8180eSRafael Vanoni 1285ccf8180eSRafael Vanoni return (dt_printf(dtp, fp, format, 1286ccf8180eSRafael Vanoni dt_stddev((uint64_t *)data, normal))); 1287ccf8180eSRafael Vanoni } 1288ccf8180eSRafael Vanoni 1289ccf8180eSRafael Vanoni /*ARGSUSED*/ 1290ccf8180eSRafael Vanoni static int 12917c478bd9Sstevel@tonic-gate pfprint_quantize(dtrace_hdl_t *dtp, FILE *fp, const char *format, 12927c478bd9Sstevel@tonic-gate const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal) 12937c478bd9Sstevel@tonic-gate { 12947c478bd9Sstevel@tonic-gate return (dt_print_quantize(dtp, fp, addr, size, normal)); 12957c478bd9Sstevel@tonic-gate } 12967c478bd9Sstevel@tonic-gate 12977c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 12987c478bd9Sstevel@tonic-gate static int 12997c478bd9Sstevel@tonic-gate pfprint_lquantize(dtrace_hdl_t *dtp, FILE *fp, const char *format, 13007c478bd9Sstevel@tonic-gate const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal) 13017c478bd9Sstevel@tonic-gate { 13027c478bd9Sstevel@tonic-gate return (dt_print_lquantize(dtp, fp, addr, size, normal)); 13037c478bd9Sstevel@tonic-gate } 13047c478bd9Sstevel@tonic-gate 13052b6389efSBryan Cantrill /*ARGSUSED*/ 13062b6389efSBryan Cantrill static int 13072b6389efSBryan Cantrill pfprint_llquantize(dtrace_hdl_t *dtp, FILE *fp, const char *format, 13082b6389efSBryan Cantrill const dt_pfargd_t *pfd, const void *addr, size_t size, uint64_t normal) 13092b6389efSBryan Cantrill { 13102b6389efSBryan Cantrill return (dt_print_llquantize(dtp, fp, addr, size, normal)); 13112b6389efSBryan Cantrill } 13122b6389efSBryan Cantrill 13137c478bd9Sstevel@tonic-gate static int 13147c478bd9Sstevel@tonic-gate dt_printf_format(dtrace_hdl_t *dtp, FILE *fp, const dt_pfargv_t *pfv, 13157c478bd9Sstevel@tonic-gate const dtrace_recdesc_t *recs, uint_t nrecs, const void *buf, 131630ef842dSbmc size_t len, const dtrace_aggdata_t **aggsdata, int naggvars) 13177c478bd9Sstevel@tonic-gate { 13187c478bd9Sstevel@tonic-gate dt_pfargd_t *pfd = pfv->pfv_argv; 13197c478bd9Sstevel@tonic-gate const dtrace_recdesc_t *recp = recs; 132030ef842dSbmc const dtrace_aggdata_t *aggdata; 132130ef842dSbmc dtrace_aggdesc_t *agg; 132230ef842dSbmc caddr_t lim = (caddr_t)buf + len, limit; 13237c478bd9Sstevel@tonic-gate char format[64] = "%"; 132430ef842dSbmc int i, aggrec, curagg = -1; 132530ef842dSbmc uint64_t normal; 13267c478bd9Sstevel@tonic-gate 13277c478bd9Sstevel@tonic-gate /* 132830ef842dSbmc * If we are formatting an aggregation, set 'aggrec' to the index of 132930ef842dSbmc * the final record description (the aggregation result) so we can use 133030ef842dSbmc * this record index with any conversion where DT_PFCONV_AGG is set. 133130ef842dSbmc * (The actual aggregation used will vary as we increment through the 133230ef842dSbmc * aggregation variables that we have been passed.) Finally, we 133330ef842dSbmc * decrement nrecs to prevent this record from being used with any 133430ef842dSbmc * other conversion. 13357c478bd9Sstevel@tonic-gate */ 13367c478bd9Sstevel@tonic-gate if (pfv->pfv_flags & DT_PRINTF_AGGREGATION) { 133730ef842dSbmc assert(aggsdata != NULL); 133830ef842dSbmc assert(naggvars > 0); 133930ef842dSbmc 13407c478bd9Sstevel@tonic-gate if (nrecs == 0) 13417c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DMISMATCH)); 134230ef842dSbmc 134330ef842dSbmc curagg = naggvars > 1 ? 1 : 0; 134430ef842dSbmc aggdata = aggsdata[0]; 134530ef842dSbmc aggrec = aggdata->dtada_desc->dtagd_nrecs - 1; 13467c478bd9Sstevel@tonic-gate nrecs--; 13477c478bd9Sstevel@tonic-gate } 13487c478bd9Sstevel@tonic-gate 13497c478bd9Sstevel@tonic-gate for (i = 0; i < pfv->pfv_argc; i++, pfd = pfd->pfd_next) { 13507c478bd9Sstevel@tonic-gate const dt_pfconv_t *pfc = pfd->pfd_conv; 13517c478bd9Sstevel@tonic-gate int width = pfd->pfd_width; 13527c478bd9Sstevel@tonic-gate int prec = pfd->pfd_prec; 13537c478bd9Sstevel@tonic-gate int rval; 13547c478bd9Sstevel@tonic-gate 13557c478bd9Sstevel@tonic-gate char *f = format + 1; /* skip initial '%' */ 13567c478bd9Sstevel@tonic-gate const dtrace_recdesc_t *rec; 13577c478bd9Sstevel@tonic-gate dt_pfprint_f *func; 135830ef842dSbmc caddr_t addr; 13597c478bd9Sstevel@tonic-gate size_t size; 136030ef842dSbmc uint32_t flags; 13617c478bd9Sstevel@tonic-gate 13627c478bd9Sstevel@tonic-gate if (pfd->pfd_preflen != 0) { 13637c478bd9Sstevel@tonic-gate char *tmp = alloca(pfd->pfd_preflen + 1); 13647c478bd9Sstevel@tonic-gate 13657c478bd9Sstevel@tonic-gate bcopy(pfd->pfd_prefix, tmp, pfd->pfd_preflen); 13667c478bd9Sstevel@tonic-gate tmp[pfd->pfd_preflen] = '\0'; 13677c478bd9Sstevel@tonic-gate 13687c478bd9Sstevel@tonic-gate if ((rval = dt_printf(dtp, fp, tmp)) < 0) 13697c478bd9Sstevel@tonic-gate return (rval); 1370a1b5e537Sbmc 1371a1b5e537Sbmc if (pfv->pfv_flags & DT_PRINTF_AGGREGATION) { 1372a1b5e537Sbmc /* 1373a1b5e537Sbmc * For printa(), we flush the buffer after each 137430ef842dSbmc * prefix, setting the flags to indicate that 137530ef842dSbmc * this is part of the printa() format string. 1376a1b5e537Sbmc */ 137730ef842dSbmc flags = DTRACE_BUFDATA_AGGFORMAT; 137830ef842dSbmc 137930ef842dSbmc if (pfc == NULL && i == pfv->pfv_argc - 1) 138030ef842dSbmc flags |= DTRACE_BUFDATA_AGGLAST; 138130ef842dSbmc 138230ef842dSbmc if (dt_buffered_flush(dtp, NULL, NULL, 138330ef842dSbmc aggdata, flags) < 0) 1384a1b5e537Sbmc return (-1); 1385a1b5e537Sbmc } 13867c478bd9Sstevel@tonic-gate } 13877c478bd9Sstevel@tonic-gate 13887c478bd9Sstevel@tonic-gate if (pfc == NULL) { 13897c478bd9Sstevel@tonic-gate if (pfv->pfv_argc == 1) 13907c478bd9Sstevel@tonic-gate return (nrecs != 0); 13917c478bd9Sstevel@tonic-gate continue; 13927c478bd9Sstevel@tonic-gate } 13937c478bd9Sstevel@tonic-gate 13947c478bd9Sstevel@tonic-gate /* 13957c478bd9Sstevel@tonic-gate * If the conversion is %%, just invoke the print callback 13967c478bd9Sstevel@tonic-gate * with no data record and continue; it consumes no record. 13977c478bd9Sstevel@tonic-gate */ 13987c478bd9Sstevel@tonic-gate if (pfc->pfc_print == &pfprint_pct) { 13997c478bd9Sstevel@tonic-gate if (pfc->pfc_print(dtp, fp, NULL, pfd, NULL, 0, 1) >= 0) 14007c478bd9Sstevel@tonic-gate continue; 14017c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 14027c478bd9Sstevel@tonic-gate } 14037c478bd9Sstevel@tonic-gate 14047c478bd9Sstevel@tonic-gate if (pfd->pfd_flags & DT_PFCONV_DYNWIDTH) { 14057c478bd9Sstevel@tonic-gate if (dt_printf_getint(dtp, recp++, nrecs--, buf, 14067c478bd9Sstevel@tonic-gate len, &width) == -1) 14077c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 14087c478bd9Sstevel@tonic-gate pfd->pfd_dynwidth = width; 14097c478bd9Sstevel@tonic-gate } else { 14107c478bd9Sstevel@tonic-gate pfd->pfd_dynwidth = 0; 14117c478bd9Sstevel@tonic-gate } 14127c478bd9Sstevel@tonic-gate 14137c478bd9Sstevel@tonic-gate if ((pfd->pfd_flags & DT_PFCONV_DYNPREC) && dt_printf_getint( 14147c478bd9Sstevel@tonic-gate dtp, recp++, nrecs--, buf, len, &prec) == -1) 14157c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 14167c478bd9Sstevel@tonic-gate 14177c478bd9Sstevel@tonic-gate if (pfd->pfd_flags & DT_PFCONV_AGG) { 141830ef842dSbmc /* 141930ef842dSbmc * This should be impossible -- the compiler shouldn't 142030ef842dSbmc * create a DT_PFCONV_AGG conversion without an 142130ef842dSbmc * aggregation present. Still, we'd rather fail 142230ef842dSbmc * gracefully than blow up... 142330ef842dSbmc */ 142430ef842dSbmc if (aggsdata == NULL) 14257c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DMISMATCH)); 142630ef842dSbmc 142730ef842dSbmc aggdata = aggsdata[curagg]; 142830ef842dSbmc agg = aggdata->dtada_desc; 142930ef842dSbmc 143030ef842dSbmc /* 143130ef842dSbmc * We increment the current aggregation variable, but 143230ef842dSbmc * not beyond the number of aggregation variables that 143330ef842dSbmc * we're printing. This has the (desired) effect that 143430ef842dSbmc * DT_PFCONV_AGG conversions beyond the number of 143530ef842dSbmc * aggregation variables (re-)convert the aggregation 143630ef842dSbmc * value of the last aggregation variable. 143730ef842dSbmc */ 143830ef842dSbmc if (curagg < naggvars - 1) 143930ef842dSbmc curagg++; 144030ef842dSbmc 144130ef842dSbmc rec = &agg->dtagd_rec[aggrec]; 144230ef842dSbmc addr = aggdata->dtada_data + rec->dtrd_offset; 144330ef842dSbmc limit = addr + aggdata->dtada_size; 144430ef842dSbmc normal = aggdata->dtada_normal; 144530ef842dSbmc flags = DTRACE_BUFDATA_AGGVAL; 14467c478bd9Sstevel@tonic-gate } else { 14477c478bd9Sstevel@tonic-gate if (nrecs == 0) 14487c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DMISMATCH)); 144902198c0bSbmc 145002198c0bSbmc if (pfv->pfv_flags & DT_PRINTF_AGGREGATION) { 145102198c0bSbmc /* 145202198c0bSbmc * When printing aggregation keys, we always 145302198c0bSbmc * set the aggdata to be the representative 145402198c0bSbmc * (zeroth) aggregation. The aggdata isn't 145502198c0bSbmc * actually used here in this case, but it is 145602198c0bSbmc * passed to the buffer handler and must 145702198c0bSbmc * therefore still be correct. 145802198c0bSbmc */ 145902198c0bSbmc aggdata = aggsdata[0]; 146002198c0bSbmc flags = DTRACE_BUFDATA_AGGKEY; 146102198c0bSbmc } 146202198c0bSbmc 14637c478bd9Sstevel@tonic-gate rec = recp++; 14647c478bd9Sstevel@tonic-gate nrecs--; 146530ef842dSbmc addr = (caddr_t)buf + rec->dtrd_offset; 146630ef842dSbmc limit = lim; 146730ef842dSbmc normal = 1; 14687c478bd9Sstevel@tonic-gate } 14697c478bd9Sstevel@tonic-gate 14707c478bd9Sstevel@tonic-gate size = rec->dtrd_size; 14717c478bd9Sstevel@tonic-gate 147230ef842dSbmc if (addr + size > limit) { 14737c478bd9Sstevel@tonic-gate dt_dprintf("bad size: addr=%p size=0x%x lim=%p\n", 14747c478bd9Sstevel@tonic-gate (void *)addr, rec->dtrd_size, (void *)lim); 14757c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DOFFSET)); 14767c478bd9Sstevel@tonic-gate } 14777c478bd9Sstevel@tonic-gate 14787c478bd9Sstevel@tonic-gate if (rec->dtrd_alignment != 0 && 14797c478bd9Sstevel@tonic-gate ((uintptr_t)addr & (rec->dtrd_alignment - 1)) != 0) { 14807c478bd9Sstevel@tonic-gate dt_dprintf("bad align: addr=%p size=0x%x align=0x%x\n", 14817c478bd9Sstevel@tonic-gate (void *)addr, rec->dtrd_size, rec->dtrd_alignment); 14827c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DALIGN)); 14837c478bd9Sstevel@tonic-gate } 14847c478bd9Sstevel@tonic-gate 14857c478bd9Sstevel@tonic-gate switch (rec->dtrd_action) { 14867c478bd9Sstevel@tonic-gate case DTRACEAGG_AVG: 14877c478bd9Sstevel@tonic-gate func = pfprint_average; 14887c478bd9Sstevel@tonic-gate break; 1489ccf8180eSRafael Vanoni case DTRACEAGG_STDDEV: 1490ccf8180eSRafael Vanoni func = pfprint_stddev; 1491ccf8180eSRafael Vanoni break; 14927c478bd9Sstevel@tonic-gate case DTRACEAGG_QUANTIZE: 14937c478bd9Sstevel@tonic-gate func = pfprint_quantize; 14947c478bd9Sstevel@tonic-gate break; 14957c478bd9Sstevel@tonic-gate case DTRACEAGG_LQUANTIZE: 14967c478bd9Sstevel@tonic-gate func = pfprint_lquantize; 14977c478bd9Sstevel@tonic-gate break; 14982b6389efSBryan Cantrill case DTRACEAGG_LLQUANTIZE: 14992b6389efSBryan Cantrill func = pfprint_llquantize; 15002b6389efSBryan Cantrill break; 1501a1b5e537Sbmc case DTRACEACT_MOD: 1502a1b5e537Sbmc func = pfprint_mod; 1503a1b5e537Sbmc break; 1504a1b5e537Sbmc case DTRACEACT_UMOD: 1505a1b5e537Sbmc func = pfprint_umod; 1506a1b5e537Sbmc break; 15077c478bd9Sstevel@tonic-gate default: 15087c478bd9Sstevel@tonic-gate func = pfc->pfc_print; 15097c478bd9Sstevel@tonic-gate break; 15107c478bd9Sstevel@tonic-gate } 15117c478bd9Sstevel@tonic-gate 15127c478bd9Sstevel@tonic-gate if (pfd->pfd_flags & DT_PFCONV_ALT) 15137c478bd9Sstevel@tonic-gate *f++ = '#'; 15147c478bd9Sstevel@tonic-gate if (pfd->pfd_flags & DT_PFCONV_ZPAD) 15157c478bd9Sstevel@tonic-gate *f++ = '0'; 1516e4586ebfSmws if (width < 0 || (pfd->pfd_flags & DT_PFCONV_LEFT)) 15177c478bd9Sstevel@tonic-gate *f++ = '-'; 15187c478bd9Sstevel@tonic-gate if (pfd->pfd_flags & DT_PFCONV_SPOS) 15197c478bd9Sstevel@tonic-gate *f++ = '+'; 15207c478bd9Sstevel@tonic-gate if (pfd->pfd_flags & DT_PFCONV_GROUP) 15217c478bd9Sstevel@tonic-gate *f++ = '\''; 15227c478bd9Sstevel@tonic-gate if (pfd->pfd_flags & DT_PFCONV_SPACE) 15237c478bd9Sstevel@tonic-gate *f++ = ' '; 15247c478bd9Sstevel@tonic-gate 15257c478bd9Sstevel@tonic-gate /* 15267c478bd9Sstevel@tonic-gate * If we're printing a stack and DT_PFCONV_LEFT is set, we 15277c478bd9Sstevel@tonic-gate * don't add the width to the format string. See the block 15287c478bd9Sstevel@tonic-gate * comment in pfprint_stack() for a description of the 15297c478bd9Sstevel@tonic-gate * behavior in this case. 15307c478bd9Sstevel@tonic-gate */ 15317c478bd9Sstevel@tonic-gate if (func == pfprint_stack && (pfd->pfd_flags & DT_PFCONV_LEFT)) 15327c478bd9Sstevel@tonic-gate width = 0; 15337c478bd9Sstevel@tonic-gate 15347c478bd9Sstevel@tonic-gate if (width != 0) 1535e4586ebfSmws f += snprintf(f, sizeof (format), "%d", ABS(width)); 15367c478bd9Sstevel@tonic-gate 1537e4586ebfSmws if (prec > 0) 15387c478bd9Sstevel@tonic-gate f += snprintf(f, sizeof (format), ".%d", prec); 15397c478bd9Sstevel@tonic-gate 15407c478bd9Sstevel@tonic-gate (void) strcpy(f, pfd->pfd_fmt); 15417c478bd9Sstevel@tonic-gate pfd->pfd_rec = rec; 15427c478bd9Sstevel@tonic-gate 154330ef842dSbmc if (func(dtp, fp, format, pfd, addr, size, normal) < 0) 15447c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 1545a1b5e537Sbmc 1546a1b5e537Sbmc if (pfv->pfv_flags & DT_PRINTF_AGGREGATION) { 1547a1b5e537Sbmc /* 1548a1b5e537Sbmc * For printa(), we flush the buffer after each tuple 154930ef842dSbmc * element, inidicating that this is the last record 155030ef842dSbmc * as appropriate. 1551a1b5e537Sbmc */ 155230ef842dSbmc if (i == pfv->pfv_argc - 1) 155330ef842dSbmc flags |= DTRACE_BUFDATA_AGGLAST; 155430ef842dSbmc 155530ef842dSbmc if (dt_buffered_flush(dtp, NULL, 155630ef842dSbmc rec, aggdata, flags) < 0) 1557a1b5e537Sbmc return (-1); 1558a1b5e537Sbmc } 15597c478bd9Sstevel@tonic-gate } 15607c478bd9Sstevel@tonic-gate 15617c478bd9Sstevel@tonic-gate return ((int)(recp - recs)); 15627c478bd9Sstevel@tonic-gate } 15637c478bd9Sstevel@tonic-gate 15647c478bd9Sstevel@tonic-gate int 15657c478bd9Sstevel@tonic-gate dtrace_sprintf(dtrace_hdl_t *dtp, FILE *fp, void *fmtdata, 15667c478bd9Sstevel@tonic-gate const dtrace_recdesc_t *recp, uint_t nrecs, const void *buf, size_t len) 15677c478bd9Sstevel@tonic-gate { 15687c478bd9Sstevel@tonic-gate dtrace_optval_t size; 15697c478bd9Sstevel@tonic-gate int rval; 15707c478bd9Sstevel@tonic-gate 15717c478bd9Sstevel@tonic-gate rval = dtrace_getopt(dtp, "strsize", &size); 15727c478bd9Sstevel@tonic-gate assert(rval == 0); 15737c478bd9Sstevel@tonic-gate assert(dtp->dt_sprintf_buflen == 0); 15747c478bd9Sstevel@tonic-gate 15757c478bd9Sstevel@tonic-gate if (dtp->dt_sprintf_buf != NULL) 15767c478bd9Sstevel@tonic-gate free(dtp->dt_sprintf_buf); 15777c478bd9Sstevel@tonic-gate 15787c478bd9Sstevel@tonic-gate if ((dtp->dt_sprintf_buf = malloc(size)) == NULL) 15797c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 15807c478bd9Sstevel@tonic-gate 15817c478bd9Sstevel@tonic-gate bzero(dtp->dt_sprintf_buf, size); 15827c478bd9Sstevel@tonic-gate dtp->dt_sprintf_buflen = size; 158330ef842dSbmc rval = dt_printf_format(dtp, fp, fmtdata, recp, nrecs, buf, len, 158430ef842dSbmc NULL, 0); 15857c478bd9Sstevel@tonic-gate dtp->dt_sprintf_buflen = 0; 15867c478bd9Sstevel@tonic-gate 15877c478bd9Sstevel@tonic-gate if (rval == -1) 15887c478bd9Sstevel@tonic-gate free(dtp->dt_sprintf_buf); 15897c478bd9Sstevel@tonic-gate 15907c478bd9Sstevel@tonic-gate return (rval); 15917c478bd9Sstevel@tonic-gate } 15927c478bd9Sstevel@tonic-gate 15937c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 15947c478bd9Sstevel@tonic-gate int 15957c478bd9Sstevel@tonic-gate dtrace_system(dtrace_hdl_t *dtp, FILE *fp, void *fmtdata, 15967c478bd9Sstevel@tonic-gate const dtrace_probedata_t *data, const dtrace_recdesc_t *recp, 15977c478bd9Sstevel@tonic-gate uint_t nrecs, const void *buf, size_t len) 15987c478bd9Sstevel@tonic-gate { 15997c478bd9Sstevel@tonic-gate int rval = dtrace_sprintf(dtp, fp, fmtdata, recp, nrecs, buf, len); 16007c478bd9Sstevel@tonic-gate 16017c478bd9Sstevel@tonic-gate if (rval == -1) 16027c478bd9Sstevel@tonic-gate return (rval); 16037c478bd9Sstevel@tonic-gate 16047c478bd9Sstevel@tonic-gate /* 16057c478bd9Sstevel@tonic-gate * Before we execute the specified command, flush fp to assure that 16067c478bd9Sstevel@tonic-gate * any prior dt_printf()'s appear before the output of the command 16077c478bd9Sstevel@tonic-gate * not after it. 16087c478bd9Sstevel@tonic-gate */ 16097c478bd9Sstevel@tonic-gate (void) fflush(fp); 16107c478bd9Sstevel@tonic-gate 16117c478bd9Sstevel@tonic-gate if (system(dtp->dt_sprintf_buf) == -1) 16127c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, errno)); 16137c478bd9Sstevel@tonic-gate 16147c478bd9Sstevel@tonic-gate return (rval); 16157c478bd9Sstevel@tonic-gate } 16167c478bd9Sstevel@tonic-gate 16177c478bd9Sstevel@tonic-gate int 16187c478bd9Sstevel@tonic-gate dtrace_freopen(dtrace_hdl_t *dtp, FILE *fp, void *fmtdata, 16197c478bd9Sstevel@tonic-gate const dtrace_probedata_t *data, const dtrace_recdesc_t *recp, 16207c478bd9Sstevel@tonic-gate uint_t nrecs, const void *buf, size_t len) 16217c478bd9Sstevel@tonic-gate { 16227c478bd9Sstevel@tonic-gate char selfbuf[40], restorebuf[40], *filename; 16237c478bd9Sstevel@tonic-gate FILE *nfp; 16247c478bd9Sstevel@tonic-gate int rval, errval; 16257c478bd9Sstevel@tonic-gate dt_pfargv_t *pfv = fmtdata; 16267c478bd9Sstevel@tonic-gate dt_pfargd_t *pfd = pfv->pfv_argv; 16277c478bd9Sstevel@tonic-gate 16287c478bd9Sstevel@tonic-gate rval = dtrace_sprintf(dtp, fp, fmtdata, recp, nrecs, buf, len); 16297c478bd9Sstevel@tonic-gate 16307c478bd9Sstevel@tonic-gate if (rval == -1 || fp == NULL) 16317c478bd9Sstevel@tonic-gate return (rval); 16327c478bd9Sstevel@tonic-gate 16337c478bd9Sstevel@tonic-gate if (pfd->pfd_preflen != 0 && 16347c478bd9Sstevel@tonic-gate strcmp(pfd->pfd_prefix, DT_FREOPEN_RESTORE) == 0) { 16357c478bd9Sstevel@tonic-gate /* 16367c478bd9Sstevel@tonic-gate * The only way to have the format string set to the value 16377c478bd9Sstevel@tonic-gate * DT_FREOPEN_RESTORE is via the empty freopen() string -- 16387c478bd9Sstevel@tonic-gate * denoting that we should restore the old stdout. 16397c478bd9Sstevel@tonic-gate */ 16407c478bd9Sstevel@tonic-gate assert(strcmp(dtp->dt_sprintf_buf, DT_FREOPEN_RESTORE) == 0); 16417c478bd9Sstevel@tonic-gate 16427c478bd9Sstevel@tonic-gate if (dtp->dt_stdout_fd == -1) { 16437c478bd9Sstevel@tonic-gate /* 16447c478bd9Sstevel@tonic-gate * We could complain here by generating an error, 16457c478bd9Sstevel@tonic-gate * but it seems like overkill: it seems that calling 16467c478bd9Sstevel@tonic-gate * freopen() to restore stdout when freopen() has 16477c478bd9Sstevel@tonic-gate * never before been called should just be a no-op, 16487c478bd9Sstevel@tonic-gate * so we just return in this case. 16497c478bd9Sstevel@tonic-gate */ 16507c478bd9Sstevel@tonic-gate return (rval); 16517c478bd9Sstevel@tonic-gate } 16527c478bd9Sstevel@tonic-gate 16537c478bd9Sstevel@tonic-gate (void) snprintf(restorebuf, sizeof (restorebuf), 16547c478bd9Sstevel@tonic-gate "/dev/fd/%d", dtp->dt_stdout_fd); 16557c478bd9Sstevel@tonic-gate filename = restorebuf; 16567c478bd9Sstevel@tonic-gate } else { 16577c478bd9Sstevel@tonic-gate filename = dtp->dt_sprintf_buf; 16587c478bd9Sstevel@tonic-gate } 16597c478bd9Sstevel@tonic-gate 16607c478bd9Sstevel@tonic-gate /* 16617c478bd9Sstevel@tonic-gate * freopen(3C) will always close the specified stream and underlying 16627c478bd9Sstevel@tonic-gate * file descriptor -- even if the specified file can't be opened. 16637c478bd9Sstevel@tonic-gate * Even for the semantic cesspool that is standard I/O, this is 16647c478bd9Sstevel@tonic-gate * surprisingly brain-dead behavior: it means that any failure to 16657c478bd9Sstevel@tonic-gate * open the specified file destroys the specified stream in the 16667c478bd9Sstevel@tonic-gate * process -- which is particularly relevant when the specified stream 16677c478bd9Sstevel@tonic-gate * happens (or rather, happened) to be stdout. This could be resolved 16687c478bd9Sstevel@tonic-gate * were there an "fdreopen()" equivalent of freopen() that allowed one 16697c478bd9Sstevel@tonic-gate * to pass a file descriptor instead of the name of a file, but there 16707c478bd9Sstevel@tonic-gate * is no such thing. However, we can effect this ourselves by first 16717c478bd9Sstevel@tonic-gate * fopen()'ing the desired file, and then (assuming that that works), 16727c478bd9Sstevel@tonic-gate * freopen()'ing "/dev/fd/[fileno]", where [fileno] is the underlying 16737c478bd9Sstevel@tonic-gate * file descriptor for the fopen()'d file. This way, if the fopen() 16747c478bd9Sstevel@tonic-gate * fails, we can fail the operation without destroying stdout. 16757c478bd9Sstevel@tonic-gate */ 1676004388ebScasper if ((nfp = fopen(filename, "aF")) == NULL) { 16777c478bd9Sstevel@tonic-gate char *msg = strerror(errno), *faultstr; 16787c478bd9Sstevel@tonic-gate int len = 80; 16797c478bd9Sstevel@tonic-gate 16807c478bd9Sstevel@tonic-gate len += strlen(msg) + strlen(filename); 16817c478bd9Sstevel@tonic-gate faultstr = alloca(len); 16827c478bd9Sstevel@tonic-gate 16837c478bd9Sstevel@tonic-gate (void) snprintf(faultstr, len, "couldn't freopen() \"%s\": %s", 16847c478bd9Sstevel@tonic-gate filename, strerror(errno)); 16857c478bd9Sstevel@tonic-gate 16867c478bd9Sstevel@tonic-gate if ((errval = dt_handle_liberr(dtp, data, faultstr)) == 0) 16877c478bd9Sstevel@tonic-gate return (rval); 16887c478bd9Sstevel@tonic-gate 16897c478bd9Sstevel@tonic-gate return (errval); 16907c478bd9Sstevel@tonic-gate } 16917c478bd9Sstevel@tonic-gate 16927c478bd9Sstevel@tonic-gate (void) snprintf(selfbuf, sizeof (selfbuf), "/dev/fd/%d", fileno(nfp)); 16937c478bd9Sstevel@tonic-gate 16947c478bd9Sstevel@tonic-gate if (dtp->dt_stdout_fd == -1) { 16957c478bd9Sstevel@tonic-gate /* 16967c478bd9Sstevel@tonic-gate * If this is the first time that we're calling freopen(), 16977c478bd9Sstevel@tonic-gate * we're going to stash away the file descriptor for stdout. 16987c478bd9Sstevel@tonic-gate * We don't expect the dup(2) to fail, so if it does we must 16997c478bd9Sstevel@tonic-gate * return failure. 17007c478bd9Sstevel@tonic-gate */ 17017c478bd9Sstevel@tonic-gate if ((dtp->dt_stdout_fd = dup(fileno(fp))) == -1) { 17027c478bd9Sstevel@tonic-gate (void) fclose(nfp); 17037c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, errno)); 17047c478bd9Sstevel@tonic-gate } 17057c478bd9Sstevel@tonic-gate } 17067c478bd9Sstevel@tonic-gate 1707004388ebScasper if (freopen(selfbuf, "aF", fp) == NULL) { 17087c478bd9Sstevel@tonic-gate (void) fclose(nfp); 17097c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, errno)); 17107c478bd9Sstevel@tonic-gate } 17117c478bd9Sstevel@tonic-gate 17127c478bd9Sstevel@tonic-gate (void) fclose(nfp); 17137c478bd9Sstevel@tonic-gate 17147c478bd9Sstevel@tonic-gate return (rval); 17157c478bd9Sstevel@tonic-gate } 17167c478bd9Sstevel@tonic-gate 17177c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 17187c478bd9Sstevel@tonic-gate int 17197c478bd9Sstevel@tonic-gate dtrace_fprintf(dtrace_hdl_t *dtp, FILE *fp, void *fmtdata, 17207c478bd9Sstevel@tonic-gate const dtrace_probedata_t *data, const dtrace_recdesc_t *recp, 17217c478bd9Sstevel@tonic-gate uint_t nrecs, const void *buf, size_t len) 17227c478bd9Sstevel@tonic-gate { 1723a1b5e537Sbmc return (dt_printf_format(dtp, fp, fmtdata, 172430ef842dSbmc recp, nrecs, buf, len, NULL, 0)); 17257c478bd9Sstevel@tonic-gate } 17267c478bd9Sstevel@tonic-gate 17277c478bd9Sstevel@tonic-gate void * 17287c478bd9Sstevel@tonic-gate dtrace_printf_create(dtrace_hdl_t *dtp, const char *s) 17297c478bd9Sstevel@tonic-gate { 17307c478bd9Sstevel@tonic-gate dt_pfargv_t *pfv = dt_printf_create(dtp, s); 17317c478bd9Sstevel@tonic-gate dt_pfargd_t *pfd; 17327c478bd9Sstevel@tonic-gate int i; 17337c478bd9Sstevel@tonic-gate 17347c478bd9Sstevel@tonic-gate if (pfv == NULL) 17357c478bd9Sstevel@tonic-gate return (NULL); /* errno has been set for us */ 17367c478bd9Sstevel@tonic-gate 17377c478bd9Sstevel@tonic-gate pfd = pfv->pfv_argv; 17387c478bd9Sstevel@tonic-gate 17397c478bd9Sstevel@tonic-gate for (i = 0; i < pfv->pfv_argc; i++, pfd = pfd->pfd_next) { 17407c478bd9Sstevel@tonic-gate const dt_pfconv_t *pfc = pfd->pfd_conv; 17417c478bd9Sstevel@tonic-gate 17427c478bd9Sstevel@tonic-gate if (pfc == NULL) 17437c478bd9Sstevel@tonic-gate continue; 17447c478bd9Sstevel@tonic-gate 17457c478bd9Sstevel@tonic-gate /* 17467c478bd9Sstevel@tonic-gate * If the output format is not %s then we assume that we have 17477c478bd9Sstevel@tonic-gate * been given a correctly-sized format string, so we copy the 17487c478bd9Sstevel@tonic-gate * true format name including the size modifier. If the output 17497c478bd9Sstevel@tonic-gate * format is %s, then either the input format is %s as well or 17507c478bd9Sstevel@tonic-gate * it is one of our custom formats (e.g. pfprint_addr), so we 17517c478bd9Sstevel@tonic-gate * must set pfd_fmt to be the output format conversion "s". 17527c478bd9Sstevel@tonic-gate */ 17537c478bd9Sstevel@tonic-gate if (strcmp(pfc->pfc_ofmt, "s") != 0) 17547c478bd9Sstevel@tonic-gate (void) strcat(pfd->pfd_fmt, pfc->pfc_name); 17557c478bd9Sstevel@tonic-gate else 17567c478bd9Sstevel@tonic-gate (void) strcat(pfd->pfd_fmt, pfc->pfc_ofmt); 17577c478bd9Sstevel@tonic-gate } 17587c478bd9Sstevel@tonic-gate 17597c478bd9Sstevel@tonic-gate return (pfv); 17607c478bd9Sstevel@tonic-gate } 17617c478bd9Sstevel@tonic-gate 17627c478bd9Sstevel@tonic-gate void * 17637c478bd9Sstevel@tonic-gate dtrace_printa_create(dtrace_hdl_t *dtp, const char *s) 17647c478bd9Sstevel@tonic-gate { 17657c478bd9Sstevel@tonic-gate dt_pfargv_t *pfv = dtrace_printf_create(dtp, s); 17667c478bd9Sstevel@tonic-gate 17677c478bd9Sstevel@tonic-gate if (pfv == NULL) 17687c478bd9Sstevel@tonic-gate return (NULL); /* errno has been set for us */ 17697c478bd9Sstevel@tonic-gate 17707c478bd9Sstevel@tonic-gate pfv->pfv_flags |= DT_PRINTF_AGGREGATION; 17717c478bd9Sstevel@tonic-gate 17727c478bd9Sstevel@tonic-gate return (pfv); 17737c478bd9Sstevel@tonic-gate } 17747c478bd9Sstevel@tonic-gate 17757c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 17767c478bd9Sstevel@tonic-gate size_t 17777c478bd9Sstevel@tonic-gate dtrace_printf_format(dtrace_hdl_t *dtp, void *fmtdata, char *s, size_t len) 17787c478bd9Sstevel@tonic-gate { 17797c478bd9Sstevel@tonic-gate dt_pfargv_t *pfv = fmtdata; 17807c478bd9Sstevel@tonic-gate dt_pfargd_t *pfd = pfv->pfv_argv; 17817c478bd9Sstevel@tonic-gate 17827c478bd9Sstevel@tonic-gate /* 17837c478bd9Sstevel@tonic-gate * An upper bound on the string length is the length of the original 17847c478bd9Sstevel@tonic-gate * format string, plus three times the number of conversions (each 17857c478bd9Sstevel@tonic-gate * conversion could add up an additional "ll" and/or pfd_width digit 17867c478bd9Sstevel@tonic-gate * in the case of converting %? to %16) plus one for a terminating \0. 17877c478bd9Sstevel@tonic-gate */ 17887c478bd9Sstevel@tonic-gate size_t formatlen = strlen(pfv->pfv_format) + 3 * pfv->pfv_argc + 1; 17897c478bd9Sstevel@tonic-gate char *format = alloca(formatlen); 17907c478bd9Sstevel@tonic-gate char *f = format; 17917c478bd9Sstevel@tonic-gate int i, j; 17927c478bd9Sstevel@tonic-gate 17937c478bd9Sstevel@tonic-gate for (i = 0; i < pfv->pfv_argc; i++, pfd = pfd->pfd_next) { 17947c478bd9Sstevel@tonic-gate const dt_pfconv_t *pfc = pfd->pfd_conv; 17957c478bd9Sstevel@tonic-gate const char *str; 17967c478bd9Sstevel@tonic-gate int width = pfd->pfd_width; 17977c478bd9Sstevel@tonic-gate int prec = pfd->pfd_prec; 17987c478bd9Sstevel@tonic-gate 17997c478bd9Sstevel@tonic-gate if (pfd->pfd_preflen != 0) { 18007c478bd9Sstevel@tonic-gate for (j = 0; j < pfd->pfd_preflen; j++) 18017c478bd9Sstevel@tonic-gate *f++ = pfd->pfd_prefix[j]; 18027c478bd9Sstevel@tonic-gate } 18037c478bd9Sstevel@tonic-gate 18047c478bd9Sstevel@tonic-gate if (pfc == NULL) 18057c478bd9Sstevel@tonic-gate continue; 18067c478bd9Sstevel@tonic-gate 18077c478bd9Sstevel@tonic-gate *f++ = '%'; 18087c478bd9Sstevel@tonic-gate 18097c478bd9Sstevel@tonic-gate if (pfd->pfd_flags & DT_PFCONV_ALT) 18107c478bd9Sstevel@tonic-gate *f++ = '#'; 18117c478bd9Sstevel@tonic-gate if (pfd->pfd_flags & DT_PFCONV_ZPAD) 18127c478bd9Sstevel@tonic-gate *f++ = '0'; 18137c478bd9Sstevel@tonic-gate if (pfd->pfd_flags & DT_PFCONV_LEFT) 18147c478bd9Sstevel@tonic-gate *f++ = '-'; 18157c478bd9Sstevel@tonic-gate if (pfd->pfd_flags & DT_PFCONV_SPOS) 18167c478bd9Sstevel@tonic-gate *f++ = '+'; 18177c478bd9Sstevel@tonic-gate if (pfd->pfd_flags & DT_PFCONV_DYNWIDTH) 18187c478bd9Sstevel@tonic-gate *f++ = '*'; 18197c478bd9Sstevel@tonic-gate if (pfd->pfd_flags & DT_PFCONV_DYNPREC) { 18207c478bd9Sstevel@tonic-gate *f++ = '.'; 18217c478bd9Sstevel@tonic-gate *f++ = '*'; 18227c478bd9Sstevel@tonic-gate } 18237c478bd9Sstevel@tonic-gate if (pfd->pfd_flags & DT_PFCONV_GROUP) 18247c478bd9Sstevel@tonic-gate *f++ = '\''; 18257c478bd9Sstevel@tonic-gate if (pfd->pfd_flags & DT_PFCONV_SPACE) 18267c478bd9Sstevel@tonic-gate *f++ = ' '; 18277c478bd9Sstevel@tonic-gate if (pfd->pfd_flags & DT_PFCONV_AGG) 18287c478bd9Sstevel@tonic-gate *f++ = '@'; 18297c478bd9Sstevel@tonic-gate 18307c478bd9Sstevel@tonic-gate if (width != 0) 18317c478bd9Sstevel@tonic-gate f += snprintf(f, sizeof (format), "%d", width); 18327c478bd9Sstevel@tonic-gate 18337c478bd9Sstevel@tonic-gate if (prec != 0) 18347c478bd9Sstevel@tonic-gate f += snprintf(f, sizeof (format), ".%d", prec); 18357c478bd9Sstevel@tonic-gate 18367c478bd9Sstevel@tonic-gate /* 18377c478bd9Sstevel@tonic-gate * If the output format is %s, then either %s is the underlying 18387c478bd9Sstevel@tonic-gate * conversion or the conversion is one of our customized ones, 18397c478bd9Sstevel@tonic-gate * e.g. pfprint_addr. In these cases, put the original string 18407c478bd9Sstevel@tonic-gate * name of the conversion (pfc_name) into the pickled format 18417c478bd9Sstevel@tonic-gate * string rather than the derived conversion (pfd_fmt). 18427c478bd9Sstevel@tonic-gate */ 18437c478bd9Sstevel@tonic-gate if (strcmp(pfc->pfc_ofmt, "s") == 0) 18447c478bd9Sstevel@tonic-gate str = pfc->pfc_name; 18457c478bd9Sstevel@tonic-gate else 18467c478bd9Sstevel@tonic-gate str = pfd->pfd_fmt; 18477c478bd9Sstevel@tonic-gate 18487c478bd9Sstevel@tonic-gate for (j = 0; str[j] != '\0'; j++) 18497c478bd9Sstevel@tonic-gate *f++ = str[j]; 18507c478bd9Sstevel@tonic-gate } 18517c478bd9Sstevel@tonic-gate 18527c478bd9Sstevel@tonic-gate *f = '\0'; /* insert nul byte; do not count in return value */ 18537c478bd9Sstevel@tonic-gate 18547c478bd9Sstevel@tonic-gate assert(f < format + formatlen); 18557c478bd9Sstevel@tonic-gate (void) strncpy(s, format, len); 18567c478bd9Sstevel@tonic-gate 18577c478bd9Sstevel@tonic-gate return ((size_t)(f - format)); 18587c478bd9Sstevel@tonic-gate } 18597c478bd9Sstevel@tonic-gate 18607c478bd9Sstevel@tonic-gate static int 1861a1b5e537Sbmc dt_fprinta(const dtrace_aggdata_t *adp, void *arg) 18627c478bd9Sstevel@tonic-gate { 1863a1b5e537Sbmc const dtrace_aggdesc_t *agg = adp->dtada_desc; 18647c478bd9Sstevel@tonic-gate const dtrace_recdesc_t *recp = &agg->dtagd_rec[0]; 18657c478bd9Sstevel@tonic-gate uint_t nrecs = agg->dtagd_nrecs; 18667c478bd9Sstevel@tonic-gate dt_pfwalk_t *pfw = arg; 1867a1b5e537Sbmc dtrace_hdl_t *dtp = pfw->pfw_argv->pfv_dtp; 18687c478bd9Sstevel@tonic-gate int id; 18697c478bd9Sstevel@tonic-gate 1870a1b5e537Sbmc if (dt_printf_getint(dtp, recp++, nrecs--, 18717c478bd9Sstevel@tonic-gate adp->dtada_data, adp->dtada_size, &id) != 0 || pfw->pfw_aid != id) 18727c478bd9Sstevel@tonic-gate return (0); /* no aggregation id or id does not match */ 18737c478bd9Sstevel@tonic-gate 1874a1b5e537Sbmc if (dt_printf_format(dtp, pfw->pfw_fp, pfw->pfw_argv, 187530ef842dSbmc recp, nrecs, adp->dtada_data, adp->dtada_size, &adp, 1) == -1) 1876a1b5e537Sbmc return (pfw->pfw_err = dtp->dt_errno); 18777c478bd9Sstevel@tonic-gate 1878a1b5e537Sbmc /* 1879a1b5e537Sbmc * Cast away the const to set the bit indicating that this aggregation 1880a1b5e537Sbmc * has been printed. 1881a1b5e537Sbmc */ 1882a1b5e537Sbmc ((dtrace_aggdesc_t *)agg)->dtagd_flags |= DTRACE_AGD_PRINTED; 18837c478bd9Sstevel@tonic-gate 18847c478bd9Sstevel@tonic-gate return (0); 18857c478bd9Sstevel@tonic-gate } 18867c478bd9Sstevel@tonic-gate 188730ef842dSbmc static int 188830ef842dSbmc dt_fprintas(const dtrace_aggdata_t **aggsdata, int naggvars, void *arg) 188930ef842dSbmc { 189030ef842dSbmc const dtrace_aggdata_t *aggdata = aggsdata[0]; 189130ef842dSbmc const dtrace_aggdesc_t *agg = aggdata->dtada_desc; 189230ef842dSbmc const dtrace_recdesc_t *rec = &agg->dtagd_rec[1]; 189330ef842dSbmc uint_t nrecs = agg->dtagd_nrecs - 1; 189430ef842dSbmc dt_pfwalk_t *pfw = arg; 189530ef842dSbmc dtrace_hdl_t *dtp = pfw->pfw_argv->pfv_dtp; 189630ef842dSbmc int i; 189730ef842dSbmc 189830ef842dSbmc if (dt_printf_format(dtp, pfw->pfw_fp, pfw->pfw_argv, 189930ef842dSbmc rec, nrecs, aggdata->dtada_data, aggdata->dtada_size, 190030ef842dSbmc aggsdata, naggvars) == -1) 190130ef842dSbmc return (pfw->pfw_err = dtp->dt_errno); 190230ef842dSbmc 190330ef842dSbmc /* 190430ef842dSbmc * For each aggregation, indicate that it has been printed, casting 190530ef842dSbmc * away the const as necessary. 190630ef842dSbmc */ 190730ef842dSbmc for (i = 1; i < naggvars; i++) { 190830ef842dSbmc agg = aggsdata[i]->dtada_desc; 190930ef842dSbmc ((dtrace_aggdesc_t *)agg)->dtagd_flags |= DTRACE_AGD_PRINTED; 191030ef842dSbmc } 191130ef842dSbmc 191230ef842dSbmc return (0); 191330ef842dSbmc } 19147c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 19157c478bd9Sstevel@tonic-gate int 19167c478bd9Sstevel@tonic-gate dtrace_fprinta(dtrace_hdl_t *dtp, FILE *fp, void *fmtdata, 19177c478bd9Sstevel@tonic-gate const dtrace_probedata_t *data, const dtrace_recdesc_t *recs, 19187c478bd9Sstevel@tonic-gate uint_t nrecs, const void *buf, size_t len) 19197c478bd9Sstevel@tonic-gate { 19207c478bd9Sstevel@tonic-gate dt_pfwalk_t pfw; 192130ef842dSbmc int i, naggvars = 0; 192230ef842dSbmc dtrace_aggvarid_t *aggvars; 19237c478bd9Sstevel@tonic-gate 192430ef842dSbmc aggvars = alloca(nrecs * sizeof (dtrace_aggvarid_t)); 192530ef842dSbmc 192630ef842dSbmc /* 192730ef842dSbmc * This might be a printa() with multiple aggregation variables. We 192830ef842dSbmc * need to scan forward through the records until we find a record from 192930ef842dSbmc * a different statement. 193030ef842dSbmc */ 193130ef842dSbmc for (i = 0; i < nrecs; i++) { 193230ef842dSbmc const dtrace_recdesc_t *nrec = &recs[i]; 193330ef842dSbmc 193430ef842dSbmc if (nrec->dtrd_uarg != recs->dtrd_uarg) 193530ef842dSbmc break; 193630ef842dSbmc 193730ef842dSbmc if (nrec->dtrd_action != recs->dtrd_action) 193830ef842dSbmc return (dt_set_errno(dtp, EDT_BADAGG)); 193930ef842dSbmc 194030ef842dSbmc aggvars[naggvars++] = 194130ef842dSbmc /* LINTED - alignment */ 194230ef842dSbmc *((dtrace_aggvarid_t *)((caddr_t)buf + nrec->dtrd_offset)); 194330ef842dSbmc } 194430ef842dSbmc 194530ef842dSbmc if (naggvars == 0) 194630ef842dSbmc return (dt_set_errno(dtp, EDT_BADAGG)); 19477c478bd9Sstevel@tonic-gate 19487c478bd9Sstevel@tonic-gate pfw.pfw_argv = fmtdata; 19497c478bd9Sstevel@tonic-gate pfw.pfw_fp = fp; 19507c478bd9Sstevel@tonic-gate pfw.pfw_err = 0; 19517c478bd9Sstevel@tonic-gate 195230ef842dSbmc if (naggvars == 1) { 195330ef842dSbmc pfw.pfw_aid = aggvars[0]; 19547c478bd9Sstevel@tonic-gate 195530ef842dSbmc if (dtrace_aggregate_walk_sorted(dtp, 195630ef842dSbmc dt_fprinta, &pfw) == -1 || pfw.pfw_err != 0) 195730ef842dSbmc return (-1); /* errno is set for us */ 195830ef842dSbmc } else { 195930ef842dSbmc if (dtrace_aggregate_walk_joined(dtp, aggvars, naggvars, 196030ef842dSbmc dt_fprintas, &pfw) == -1 || pfw.pfw_err != 0) 196130ef842dSbmc return (-1); /* errno is set for us */ 196230ef842dSbmc } 196330ef842dSbmc 196430ef842dSbmc return (i); 19657c478bd9Sstevel@tonic-gate } 1966