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