Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F108574070
D41745.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
131 KB
Referenced Files
None
Subscribers
None
D41745.diff
View Options
diff --git a/Makefile.inc1 b/Makefile.inc1
--- a/Makefile.inc1
+++ b/Makefile.inc1
@@ -3139,6 +3139,7 @@
${_cddl_lib_libctf} ${_cddl_lib_libzfsbootenv} \
lib/libufs \
lib/libutil lib/libpjdlog ${_lib_libypclnt} lib/libz lib/msun \
+ lib/libxo \
${_secure_lib_libcrypto} ${_secure_lib_libssl} \
${_lib_libldns} ${_secure_lib_libssh}
@@ -3194,6 +3195,7 @@
.endfor
lib/libtacplus__L: lib/libmd__L lib/libpam/libpam__L
+lib/libxo__L: lib/libutil__L
.if ${MK_CDDL} != "no"
_cddl_lib_libumem= cddl/lib/libumem
@@ -3234,6 +3236,7 @@
_cddl_lib_libctf= cddl/lib/libctf
_cddl_lib= cddl/lib
cddl/lib/libctf__L: lib/libz__L cddl/lib/libspl__L
+cddl/lib/libdtrace__L: lib/libxo__L
.endif
# cddl/lib/libdtrace requires lib/libproc and lib/librtld_db
_prebuild_libs+= lib/libprocstat lib/libproc lib/librtld_db
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/dtrace.1 b/cddl/contrib/opensolaris/cmd/dtrace/dtrace.1
--- a/cddl/contrib/opensolaris/cmd/dtrace/dtrace.1
+++ b/cddl/contrib/opensolaris/cmd/dtrace/dtrace.1
@@ -18,7 +18,9 @@
.\" CDDL HEADER END
.\" Copyright (c) 2006, Sun Microsystems, Inc. All Rights Reserved.
.\"
-.Dd February 24, 2023
+.\" $FreeBSD$
+.\"
+.Dd September 8, 2023
.Dt DTRACE 1
.Os
.Sh NAME
@@ -27,7 +29,8 @@
.Sh SYNOPSIS
.Nm
.Op Fl 32 | Fl 64
-.Op Fl aACdeFGhHlqSvVwZ
+.Op Fl aACdeFGhHlOqSvVwZ
+.Op Fl -libxo
.Op Fl b Ar bufsz
.Op Fl c Ar cmd
.Op Fl D Ar name Op Ns = Ns value
@@ -355,6 +358,11 @@
The specified
.Ar path
is added after the default library search path.
+.It Fl -libxo
+Generate output via
+.Xr libxo 3 .
+This option is the same as specifying
+.Sy oformat .
.It Fl m Oo Ar provider : Oc Ar module Oo Oo Ar predicate Oc Ar action Oc
Specify module name to trace or list
.Fl ( l
@@ -398,6 +406,14 @@
More than one
.Fl n
option can be specified on the command line at a time.
+.It Fl O
+This option causes
+.Nm
+to print all the aggregations upon exiting if
+.Sy oformat
+or
+.Fl -libxo
+are specified.
.It Fl o Ar output
Specify the
.Ar output
@@ -650,6 +666,32 @@
and
.Fn ustack
output.
+.It Sy oformat Ns = Ns Ar format
+Specify the format to use for output.
+Setting
+.Sy oformat
+to
+.Ql text
+makes
+.Nm
+use regular human-readable output which is its default behavior.
+The options passed to
+.Sy oformat
+are directly forwarded to
+.Xr libxo 3 .
+Some of the supported formatters include
+.Ql json ,
+.Ql xml
+and
+.Ql html .
+Note that this option will cause
+.Nm
+to not produce any output unless printing functions are explicitly called,
+or the
+.Fl O
+flag is specified.
+For more information see
+.Sx STRUCTURED OUTPUT .
.It Sy statusrate Ns = Ns Ar time
Rate of status checking.
.It Sy switchrate Ns = Ns Ar time
@@ -776,6 +818,376 @@
.Fl i
options) contain descriptions that do not match any known probes.
.El
+.Sh STRUCTURED OUTPUT
+.Nm
+supports structured output using
+.Xr libxo 3 .
+The output will always have a top-level object called
+.Dq dtrace ,
+followed by a list of objects
+.Dq probes .
+Each of the probe objects will to have a timestamp which is generated at
+output time rather than probe firing time, an identifier for the CPU on
+which the probe was executed, and the probe's full specification:
+.Bd -literal
+{
+ "dtrace": {
+ "probes": [
+ {
+ "timestamp": ...,
+ "cpu": ...,
+ "id": ...,
+ "provider": ...,
+ "module": ...,
+ "function": ...,
+ "name": ...,
+ "output": [
+ ... (script-specific output)
+ ]
+ }
+ ]
+ }
+}
+
+<?xml version="1.0"?>
+<dtrace>
+ <probes>
+ <timestamp>...</timestamp>
+ <cpu>...</cpu>
+ <id>...</id>
+ <provider>...</provider>
+ <module>...</module>
+ <function>...</function>
+ <name>...</name>
+ <output>
+ ... (script-specific output)
+ </output>
+ </probes>
+</dtrace>
+.Ed
+.Pp
+It is also possible for XML output to take the following form if some
+of the fields are empty (in this example, module and function values
+are absent):
+.Bd -literal
+<?xml version="1.0"?>
+<dtrace>
+ <probes>
+ ...
+ <module/>
+ <function/>
+ ...
+ <output>
+ ... (script-specific output)
+ </output>
+ </probes>
+</dtrace>
+.Ed
+.Pp
+Similarly,
+.Sy oformat
+can be used to generate HTML:
+.Bd -literal
+<div class="line">
+<div class="data" data-tag="timestamp">...</div>
+<div class="text"></div>
+<div class="data" data-tag="cpu">...</div>
+<div class="text"></div>
+<div class="data" data-tag="id">...</div>
+<div class="text"></div>
+<div class="data" data-tag="provider">...</div>
+<div class="text"></div>
+<div class="data" data-tag="module">...</div>
+<div class="text"></div>
+<div class="data" data-tag="function">...</div>
+<div class="text"></div>
+<div class="data" data-tag="name">...</div>
+<div class="data" data-tag="... (script-specific output)">...</div>
+</div>
+.Ed
+.Pp
+Unlike JSON and XML, the
+.Dq output
+array is not present.
+Instead, data is simply formatted into a div of class
+.Dq data
+and a data-tag is associated with each of the keys.
+.Pp
+The
+.Dq output
+array's contents depend on the probes' actions and is explained below.
+The examples here are presented in JSON form as opposed to XML or HTML,
+however the conversion explained above applies for all output formats.
+.Pp
+Any scalar output, such as output produced by the
+.Fn trace
+action is of form:
+.Bd -literal
+{
+ "value": ...
+}
+.Ed
+.Pp
+The
+.Fn printf
+action begins with an object containing the formatted output of the
+.Fn printf
+action.
+Subsequent objects contains the value of each of the arguments to
+.Fn printf
+in its raw form as if the
+.Fn trace
+action was used instead.
+A
+.Fn printf
+statement which contains no arguments other than the message will only have
+one object following the message object and its value will always be 0.
+This is an artefact of the implementation and can safely be ignored.
+.Bd -literal
+# dtrace --libxo json,pretty -n 'BEGIN { printf("... %Y, ..", walltimestamp); }'
+
+{
+ "message": "... 2023 Sep 7 16:49:02, .."
+},
+{
+ "value": 1694105342633402400
+},
+{
+ ...
+}
+.Ed
+.Pp
+Scalar aggregations are aggregations which produce a single value for a given
+key.
+These aggregations include
+.Fn count ,
+.Fn min ,
+.Fn max ,
+.Fn stddev
+and
+.Fn sum .
+Each one of them is represented by the key containing their name.
+For example, the output of a
+.Fn stddev
+aggregation will contain a key
+.Dq stddev
+inside an
+.Dq aggregation-data
+object:
+.Bd -literal
+{
+ "aggregation-data": [
+ {
+ "keys": [
+ ...
+ ],
+ "stddev": ...
+ }
+ ],
+ "aggregation-name": ...
+}
+.Ed
+.Pp
+The
+.Dq keys
+field remains consistent across all aggregations, however
+.Fn quantize ,
+.Fn lquantize
+and
+.Fn llquantize
+need to be treated differently.
+.Sy oformat
+will create a new array of objects called
+.Dq buckets .
+Each of the objects contains a
+.Dq value
+and a
+.Dq count
+field which are
+the left-hand side and the right-hand side of human-readable
+.Nm
+output respectively.
+The full object has the following format:
+.Bd -literal
+{
+ "aggregation-data": [
+ ...
+ {
+ "keys": [
+ ...
+ ],
+ "buckets": [
+ {
+ "value": 32,
+ "count": 0
+ },
+ {
+ "value": 64,
+ "count": 17
+ },
+ ...
+ ],
+ },
+ ...
+ ]
+ "aggregation-name": ...
+}
+.Ed
+.Pp
+Similar to scalar aggregations, named scalar actions such as
+.Fn mod ,
+.Fn umod ,
+.Fn usym ,
+.Fn tracemem
+and
+.Fn printm
+will output an object with the key being equal to the
+name of the action.
+For example,
+.Fn printm
+output would produce the following object:
+.Bd -literal
+{
+ "printm": "0x4054171100"
+}
+.Ed
+.Pp
+.Fn sym
+is slightly different.
+While it will create a
+.Dq sym
+field which contains its value, in some cases it will also create additional
+fields
+.Dq object ,
+.Dq name
+and
+.Dq offset :
+.Bd -literal
+# dtrace -x oformat=json,pretty -On 'BEGIN { sym((uintptr_t)&`prison0); }'
+
+{
+ "sym": "kernel`prison0",
+ "object": "kernel",
+ "name": "prison0"
+}
+
+# dtrace --libxo json,pretty -On 'BEGIN { sym((uintptr_t)curthread); }'
+
+{
+ "sym": "0xfffffe00c18d2000",
+ "offset": "0xfffffe00c18d2000"
+}
+.Ed
+.Pp
+.Fn stack
+and
+.Fn ustack
+actions unroll each of the stack frames into its own object in an array.
+The only real difference between them is that the
+.Fn stack
+action will produce a list called
+.Dq stack-frames
+while
+.Fn ustack
+will produce one called
+.Dq ustack-frames .
+The following is an example of their
+.Sy oformat
+output:
+.Bd -literal
+{
+ "stack-frames": [
+ {
+ "symbol": "dtrace.ko`dtrace_dof_create+0x35",
+ "module": "dtrace.ko",
+ "name": "dtrace_dof_create",
+ "offset": "0x35"
+ },
+ {
+ "symbol": "dtrace.ko`dtrace_ioctl+0x81c",
+ "module": "dtrace.ko",
+ "name": "dtrace_ioctl",
+ "offset": "0x81c"
+ },
+ ...
+ ]
+}
+
+{
+ "ustack-frames": [
+ {
+ "symbol": "libc.so.7`ioctl+0xa",
+ "module": "libc.so.7",
+ "name": "ioctl",
+ "offset": "0xa"
+ },
+ {
+ "symbol": "libdtrace.so.2`dtrace_go+0xf3",
+ "module": "libdtrace.so.2",
+ "name": "dtrace_go",
+ "offset": "0xf3"
+ },
+ ...
+ ]
+}
+.Ed
+.Pp
+The
+.Fn print
+action produces a
+.Dq type
+list in the following form:
+.Bd -literal
+{
+ "type": [
+ {
+ "object-name": "kernel",
+ "name": "struct thread",
+ "ctfid": 2372
+ },
+ {
+ "member-name": "td_lock",
+ "name": "struct mtx *volatile",
+ "ctfid": 2035,
+ "value": "0xffffffff82158440"
+ },
+ ...
+}
+.Ed
+.Pp
+If the type is invalid, a
+.Dq warning
+object will be produced containing the diagnostic message as well as two
+possible optional fields:
+.Dq type-identifier
+which contains the CTF identifier of the type and
+.Dq size containing the size of an integer, enum or float.
+The fields generated will depend on the kind of error that was encountered
+while processing the trace data.
+.Pp
+Finally,
+.Sy oformat
+provides a special pseudo-probe to represent drops.
+As
+.Nm
+polls for various kinds of drops
+.Sy oformat
+will produce output similar to the following in order to represent drops:
+.Bd -literal
+{
+ "cpu": -1,
+ "id": -1,
+ "provider": "dtrace",
+ "module": "INTERNAL",
+ "function": "INTERNAL",
+ "name": "DROP",
+ "timestamp": ...,
+ "count": ...,
+ "total": ...,
+ "kind": 2,
+ "msg": "... dynamic variable drops\n"
+}
+.Ed
.Sh OPERANDS
You can specify zero or more additional arguments on the
.Nm
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/dtrace.c b/cddl/contrib/opensolaris/cmd/dtrace/dtrace.c
--- a/cddl/contrib/opensolaris/cmd/dtrace/dtrace.c
+++ b/cddl/contrib/opensolaris/cmd/dtrace/dtrace.c
@@ -26,6 +26,7 @@
/*
* Copyright (c) 2012 by Delphix. All rights reserved.
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2023, Domagoj Stolfa. All rights reserved.
*/
#include <sys/types.h>
@@ -55,6 +56,9 @@
#include <spawn.h>
#endif
+#undef NORETURN /* needed because libxo redefines it */
+#include <libxo/xo.h>
+
typedef struct dtrace_cmd {
void (*dc_func)(struct dtrace_cmd *); /* function to compile arg */
dtrace_probespec_t dc_spec; /* probe specifier context */
@@ -77,7 +81,7 @@
#define E_USAGE 2
static const char DTRACE_OPTSTR[] =
- "3:6:aAb:Bc:CdD:ef:FGhHi:I:lL:m:n:o:p:P:qs:SU:vVwx:X:Z";
+ "3:6:aAb:Bc:CdD:ef:FGhHi:I:lL:m:n:o:Op:P:qs:SU:vVwx:X:Z";
static char **g_argv;
static int g_argc;
@@ -167,6 +171,7 @@
"\t-m enable or list probes matching the specified module name\n"
"\t-n enable or list probes matching the specified probe name\n"
"\t-o set output file\n"
+ "\t-O print output upon exiting (specific to oformat)\n"
"\t-p grab specified process-ID and cache its symbol tables\n"
"\t-P enable or list probes matching the specified provider name\n"
"\t-q set quiet mode (only output explicitly traced data)\n"
@@ -907,7 +912,10 @@
static int
drophandler(const dtrace_dropdata_t *data, void *arg)
{
- error(data->dtdda_msg);
+ if (!dtrace_oformat(g_dtp)) {
+ error(data->dtdda_msg);
+ }
+
return (DTRACE_HANDLE_OK);
}
@@ -1126,7 +1134,9 @@
}
if (!g_flowindent) {
- if (!g_quiet) {
+ if (dtrace_oformat(g_dtp)) {
+ dtrace_oformat_probe(g_dtp, data, cpu, pd);
+ } else if (!g_quiet) {
char name[DTRACE_FUNCNAMELEN + DTRACE_NAMELEN + 2];
(void) snprintf(name, sizeof (name), "%s:%s",
@@ -1313,7 +1323,8 @@
g_ofp = stdout;
int done = 0, mode = 0;
- int err, i, c;
+ int err, i, c, new_argc, libxo_specified;
+ int print_upon_exit = 0;
char *p, **v;
struct ps_prochandle *P;
pid_t pid;
@@ -1336,6 +1347,15 @@
(g_psv = malloc(sizeof (struct ps_prochandle *) * argc)) == NULL)
fatal("failed to allocate memory for arguments");
+ new_argc = xo_parse_args(argc, argv);
+ if (new_argc < 0)
+ return (usage(stderr));
+
+ if (new_argc != argc)
+ libxo_specified = 1;
+
+ argc = new_argc;
+
g_argv[g_argc++] = argv[0]; /* propagate argv[0] to D as $0/$$0 */
argv[0] = g_pname; /* rewrite argv[0] for getopt errors */
@@ -1532,6 +1552,10 @@
} else if (g_mode == DMODE_ANON)
(void) dtrace_setopt(g_dtp, "linkmode", "primary");
+
+ if (libxo_specified)
+ dtrace_oformat_configure(g_dtp);
+
/*
* Now that we have libdtrace open, make a second pass through argv[]
* to perform any dtrace_setopt() calls and change any compiler flags.
@@ -1624,6 +1648,10 @@
dcp->dc_arg = optarg;
break;
+ case 'O':
+ print_upon_exit = 1;
+ break;
+
case 'q':
if (dtrace_setopt(g_dtp, "quiet", 0) != 0)
dfatal("failed to set -q");
@@ -1765,6 +1793,11 @@
(void) dtrace_getopt(g_dtp, "quiet", &opt);
g_quiet = opt != DTRACEOPT_UNSET;
+ if (dtrace_oformat(g_dtp)) {
+ if (dtrace_setopt(g_dtp, "quiet", 0) != 0)
+ dfatal("failed to set quiet (caused by oformat)");
+ }
+
/*
* Now make a fifth and final pass over the options that have been
* turned into programs and saved in g_cmdv[], performing any mode-
@@ -1777,6 +1810,9 @@
if (g_ofile != NULL && (g_ofp = fopen(g_ofile, "a")) == NULL)
fatal("failed to open output file '%s'", g_ofile);
+ if (dtrace_oformat(g_dtp))
+ dtrace_set_outfp(g_ofp);
+
for (i = 0; i < g_cmdc; i++)
exec_prog(&g_cmdv[i]);
@@ -1811,6 +1847,9 @@
if ((g_ofp = fopen(g_ofile, "a")) == NULL)
fatal("failed to open output file '%s'", g_ofile);
+ if (dtrace_oformat(g_dtp))
+ dtrace_set_outfp(g_ofp);
+
for (i = 0; i < g_cmdc; i++) {
anon_prog(&g_cmdv[i],
dtrace_dof_create(g_dtp, g_cmdv[i].dc_prog, 0), i);
@@ -1971,12 +2010,21 @@
g_pslive = g_psc; /* count for prochandler() */
+ dtrace_oformat_setup(g_dtp);
do {
if (!g_intr && !done)
dtrace_sleep(g_dtp);
#ifdef __FreeBSD__
- if (g_siginfo) {
+ /*
+ * XXX: Supporting SIGINFO with oformat makes little sense, as
+ * it can't really produce sensible DTrace output.
+ *
+ * If needed, we could support it by having an imaginary
+ * "SIGINFO" probe that we can construct in the output but leave
+ * it out for now.
+ */
+ if (g_siginfo && !dtrace_oformat(g_dtp)) {
(void)dtrace_aggregate_print(g_dtp, g_ofp, NULL);
g_siginfo = 0;
}
@@ -2013,14 +2061,24 @@
clearerr(g_ofp);
} while (!done);
- oprintf("\n");
+ if (!dtrace_oformat(g_dtp))
+ oprintf("\n");
- if (!g_impatient) {
+ /*
+ * Since there is no way to format a probe here and machine-readable
+ * output makes little sense without explicitly asking for it, we print
+ * nothing upon Ctrl-C if oformat is specified. If the user wishes to
+ * get output upon exit, they must write an explicit dtrace:::END probe
+ * to do so.
+ */
+ if ((!g_impatient && !dtrace_oformat(g_dtp)) ||
+ (!g_impatient && print_upon_exit)) {
if (dtrace_aggregate_print(g_dtp, g_ofp, NULL) == -1 &&
dtrace_errno(g_dtp) != EINTR)
dfatal("failed to print aggregations");
}
+ dtrace_oformat_teardown(g_dtp);
dtrace_close(g_dtp);
return (g_status);
}
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.agg.avg.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.agg.avg.ksh
new file mode 100644
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.agg.avg.ksh
@@ -0,0 +1,66 @@
+#!/usr/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2023 Domagoj Stolfa
+#
+
+bname=`basename $0`
+dtraceout=/tmp/dtrace.$bname
+
+script()
+{
+ $dtrace -o $dtraceout.$1 -x oformat=$1 -s /dev/stdin <<__EOF__
+syscall:::entry
+{
+ @[probefunc] = avg(tid);
+}
+
+tick-5s
+{
+ exit(0);
+}
+
+END
+{
+ printa(@);
+}
+__EOF__
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+script json
+jq . $dtraceout.json
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid JSON. see $dtraceout.json
+ exit 1
+fi
+
+script xml
+xmllint $dtraceout.xml
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid XML. see $dtraceout.xml
+ exit 1
+fi
+
+rm $dtraceout.json
+rm $dtraceout.xml
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.agg.count.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.agg.count.ksh
new file mode 100644
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.agg.count.ksh
@@ -0,0 +1,66 @@
+#!/usr/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2023 Domagoj Stolfa
+#
+
+bname=`basename $0`
+dtraceout=/tmp/dtrace.$bname
+
+script()
+{
+ $dtrace -o $dtraceout.$1 -x oformat=$1 -s /dev/stdin <<__EOF__
+syscall:::entry
+{
+ @[execname] = count();
+}
+
+tick-5s
+{
+ exit(0);
+}
+
+END
+{
+ printa(@);
+}
+__EOF__
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+script json
+jq . $dtraceout.json
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid JSON. see $dtraceout.json
+ exit 1
+fi
+
+script xml
+xmllint $dtraceout.xml
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid XML. see $dtraceout.xml
+ exit 1
+fi
+
+rm $dtraceout.json
+rm $dtraceout.xml
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.agg.llquantize.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.agg.llquantize.ksh
new file mode 100644
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.agg.llquantize.ksh
@@ -0,0 +1,73 @@
+#!/usr/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2023 Domagoj Stolfa
+#
+
+bname=`basename $0`
+dtraceout=/tmp/dtrace.$bname
+
+script()
+{
+ $dtrace -o $dtraceout.$1 -x oformat=$1 -s /dev/stdin <<__EOF__
+syscall:::entry
+{
+ self->ts = timestamp;
+}
+
+syscall:::return
+/self->ts/
+{
+ @[probefunc] = llquantize(timestamp - self->ts, 2, 1, 32, 32);
+ self->ts = 0;
+}
+
+tick-5s
+{
+ exit(0);
+}
+
+END
+{
+ printa(@);
+}
+__EOF__
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+script json
+jq . $dtraceout.json
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid JSON. see $dtraceout.json
+ exit 1
+fi
+
+script xml
+xmllint $dtraceout.xml
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid XML. see $dtraceout.xml
+ exit 1
+fi
+
+rm $dtraceout.json
+rm $dtraceout.xml
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.agg.lquantize.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.agg.lquantize.ksh
new file mode 100644
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.agg.lquantize.ksh
@@ -0,0 +1,73 @@
+#!/usr/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2023 Domagoj Stolfa
+#
+
+bname=`basename $0`
+dtraceout=/tmp/dtrace.$bname
+
+script()
+{
+ $dtrace -o $dtraceout.$1 -x oformat=$1 -s /dev/stdin <<__EOF__
+syscall:::entry
+{
+ self->ts = timestamp;
+}
+
+syscall:::return
+/self->ts/
+{
+ @[probefunc] = lquantize(timestamp - self->ts, 0, 1000000, 100);
+ self->ts = 0;
+}
+
+tick-5s
+{
+ exit(0);
+}
+
+END
+{
+ printa(@);
+}
+__EOF__
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+script json
+jq . $dtraceout.json
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid JSON. see $dtraceout.json
+ exit 1
+fi
+
+script xml
+xmllint $dtraceout.xml
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid XML. see $dtraceout.xml
+ exit 1
+fi
+
+rm $dtraceout.json
+rm $dtraceout.xml
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.agg.max.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.agg.max.ksh
new file mode 100644
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.agg.max.ksh
@@ -0,0 +1,66 @@
+#!/usr/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2023 Domagoj Stolfa
+#
+
+bname=`basename $0`
+dtraceout=/tmp/dtrace.$bname
+
+script()
+{
+ $dtrace -o $dtraceout.$1 -x oformat=$1 -s /dev/stdin <<__EOF__
+syscall:::entry
+{
+ @[probefunc] = max(tid);
+}
+
+tick-5s
+{
+ exit(0);
+}
+
+END
+{
+ printa(@);
+}
+__EOF__
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+script json
+jq . $dtraceout.json
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid JSON. see $dtraceout.json
+ exit 1
+fi
+
+script xml
+xmllint $dtraceout.xml
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid XML. see $dtraceout.xml
+ exit 1
+fi
+
+rm $dtraceout.json
+rm $dtraceout.xml
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.agg.min.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.agg.min.ksh
new file mode 100644
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.agg.min.ksh
@@ -0,0 +1,66 @@
+#!/usr/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2023 Domagoj Stolfa
+#
+
+bname=`basename $0`
+dtraceout=/tmp/dtrace.$bname
+
+script()
+{
+ $dtrace -o $dtraceout.$1 -x oformat=$1 -s /dev/stdin <<__EOF__
+syscall:::entry
+{
+ @[probefunc] = min(tid);
+}
+
+tick-5s
+{
+ exit(0);
+}
+
+END
+{
+ printa(@);
+}
+__EOF__
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+script json
+jq . $dtraceout.json
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid JSON. see $dtraceout.json
+ exit 1
+fi
+
+script xml
+xmllint $dtraceout.xml
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid XML. see $dtraceout.xml
+ exit 1
+fi
+
+rm $dtraceout.json
+rm $dtraceout.xml
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.agg.quantize.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.agg.quantize.ksh
new file mode 100644
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.agg.quantize.ksh
@@ -0,0 +1,73 @@
+#!/usr/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2023 Domagoj Stolfa
+#
+
+bname=`basename $0`
+dtraceout=/tmp/dtrace.$bname
+
+script()
+{
+ $dtrace -o $dtraceout.$1 -x oformat=$1 -s /dev/stdin <<__EOF__
+syscall:::entry
+{
+ self->ts = timestamp;
+}
+
+syscall:::return
+/self->ts/
+{
+ @[probefunc] = quantize(timestamp - self->ts);
+ self->ts = 0;
+}
+
+tick-5s
+{
+ exit(0);
+}
+
+END
+{
+ printa(@);
+}
+__EOF__
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+script json
+jq . $dtraceout.json
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid JSON. see $dtraceout.json
+ exit 1
+fi
+
+script xml
+xmllint $dtraceout.xml
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid XML. see $dtraceout.xml
+ exit 1
+fi
+
+rm $dtraceout.json
+rm $dtraceout.xml
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.agg.stddev.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.agg.stddev.ksh
new file mode 100644
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.agg.stddev.ksh
@@ -0,0 +1,66 @@
+#!/usr/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2023 Domagoj Stolfa
+#
+
+bname=`basename $0`
+dtraceout=/tmp/dtrace.$bname
+
+script()
+{
+ $dtrace -o $dtraceout.$1 -x oformat=$1 -s /dev/stdin <<__EOF__
+syscall:::entry
+{
+ @[probefunc] = stddev(tid);
+}
+
+tick-5s
+{
+ exit(0);
+}
+
+END
+{
+ printa(@);
+}
+__EOF__
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+script json
+jq . $dtraceout.json
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid JSON. see $dtraceout.json
+ exit 1
+fi
+
+script xml
+xmllint $dtraceout.xml
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid XML. see $dtraceout.xml
+ exit 1
+fi
+
+rm $dtraceout.json
+rm $dtraceout.xml
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.agg.sum.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.agg.sum.ksh
new file mode 100644
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.agg.sum.ksh
@@ -0,0 +1,66 @@
+#!/usr/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2023 Domagoj Stolfa
+#
+
+bname=`basename $0`
+dtraceout=/tmp/dtrace.$bname
+
+script()
+{
+ $dtrace -o $dtraceout.$1 -x oformat=$1 -s /dev/stdin <<__EOF__
+syscall:::entry
+{
+ @[probefunc] = sum(1);
+}
+
+tick-5s
+{
+ exit(0);
+}
+
+END
+{
+ printa(@);
+}
+__EOF__
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+script json
+jq . $dtraceout.json
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid JSON. see $dtraceout.json
+ exit 1
+fi
+
+script xml
+xmllint $dtraceout.xml
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid XML. see $dtraceout.xml
+ exit 1
+fi
+
+rm $dtraceout.json
+rm $dtraceout.xml
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.aggmod.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.aggmod.ksh
new file mode 100644
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.aggmod.ksh
@@ -0,0 +1,66 @@
+#!/usr/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2023 Domagoj Stolfa
+#
+
+bname=`basename $0`
+dtraceout=/tmp/dtrace.$bname
+
+script()
+{
+ $dtrace -o $dtraceout.$1 -x oformat=$1 -s /dev/stdin <<__EOF__
+syscall:::entry
+{
+ @[mod((uintptr_t)rand())] = count();
+}
+
+tick-5s
+{
+ exit(0);
+}
+
+END
+{
+ printa(@);
+}
+__EOF__
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+script json
+jq . $dtraceout.json
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid JSON. see $dtraceout.json
+ exit 1
+fi
+
+script xml
+xmllint $dtraceout.xml
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid XML. see $dtraceout.xml
+ exit 1
+fi
+
+rm $dtraceout.json
+rm $dtraceout.xml
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.aggstack.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.aggstack.ksh
new file mode 100644
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.aggstack.ksh
@@ -0,0 +1,66 @@
+#!/usr/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2023 Domagoj Stolfa
+#
+
+bname=`basename $0`
+dtraceout=/tmp/dtrace.$bname
+
+script()
+{
+ $dtrace -o $dtraceout.$1 -x oformat=$1 -s /dev/stdin <<__EOF__
+fbt:::entry
+{
+ @[stack()] = count();
+}
+
+tick-5s
+{
+ exit(0);
+}
+
+END
+{
+ printa(@);
+}
+__EOF__
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+script json
+jq . $dtraceout.json
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid JSON. see $dtraceout.json
+ exit 1
+fi
+
+script xml
+xmllint $dtraceout.xml
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid XML. see $dtraceout.xml
+ exit 1
+fi
+
+rm $dtraceout.json
+rm $dtraceout.xml
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.aggsym.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.aggsym.ksh
new file mode 100644
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.aggsym.ksh
@@ -0,0 +1,66 @@
+#!/usr/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2023 Domagoj Stolfa
+#
+
+bname=`basename $0`
+dtraceout=/tmp/dtrace.$bname
+
+script()
+{
+ $dtrace -o $dtraceout.$1 -x oformat=$1 -s /dev/stdin <<__EOF__
+syscall:::entry
+{
+ @[sym((uintptr_t)rand())] = count();
+}
+
+tick-5s
+{
+ exit(0);
+}
+
+END
+{
+ printa(@);
+}
+__EOF__
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+script json
+jq . $dtraceout.json
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid JSON. see $dtraceout.json
+ exit 1
+fi
+
+script xml
+xmllint $dtraceout.xml
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid XML. see $dtraceout.xml
+ exit 1
+fi
+
+rm $dtraceout.json
+rm $dtraceout.xml
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.aggustack.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.aggustack.ksh
new file mode 100644
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.aggustack.ksh
@@ -0,0 +1,66 @@
+#!/usr/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2023 Domagoj Stolfa
+#
+
+bname=`basename $0`
+dtraceout=/tmp/dtrace.$bname
+
+script()
+{
+ $dtrace -o $dtraceout.$1 -x oformat=$1 -s /dev/stdin <<__EOF__
+syscall:::entry
+{
+ @[ustack()] = count();
+}
+
+tick-5s
+{
+ exit(0);
+}
+
+END
+{
+ printa(@);
+}
+__EOF__
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+script json
+jq . $dtraceout.json
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid JSON. see $dtraceout.json
+ exit 1
+fi
+
+script xml
+xmllint $dtraceout.xml
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid XML. see $dtraceout.xml
+ exit 1
+fi
+
+rm $dtraceout.json
+rm $dtraceout.xml
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.aggusym.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.aggusym.ksh
new file mode 100644
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.aggusym.ksh
@@ -0,0 +1,66 @@
+#!/usr/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2023 Domagoj Stolfa
+#
+
+bname=`basename $0`
+dtraceout=/tmp/dtrace.$bname
+
+script()
+{
+ $dtrace -o $dtraceout.$1 -x oformat=$1 -s /dev/stdin <<__EOF__
+syscall:::entry
+{
+ @[usym((uintptr_t)rand())] = count();
+}
+
+tick-5s
+{
+ exit(0);
+}
+
+END
+{
+ printa(@);
+}
+__EOF__
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+script json
+jq . $dtraceout.json
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid JSON. see $dtraceout.json
+ exit 1
+fi
+
+script xml
+xmllint $dtraceout.xml
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid XML. see $dtraceout.xml
+ exit 1
+fi
+
+rm $dtraceout.json
+rm $dtraceout.xml
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.drop.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.drop.ksh
new file mode 100644
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.drop.ksh
@@ -0,0 +1,61 @@
+#!/usr/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2023 Domagoj Stolfa
+#
+
+bname=`basename $0`
+dtraceout=/tmp/dtrace.$bname
+
+script()
+{
+ $dtrace -o $dtraceout.$1 -x oformat=$1 -s /dev/stdin <<__EOF__
+fbt:::entry
+{
+ x[timestamp] = 1;
+}
+
+tick-5s
+{
+ exit(0);
+}
+__EOF__
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+script json
+jq . $dtraceout.json
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid JSON. see $dtraceout.json
+ exit 1
+fi
+
+script xml
+xmllint $dtraceout.xml
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid XML. see $dtraceout.xml
+ exit 1
+fi
+
+rm $dtraceout.json
+rm $dtraceout.xml
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.mod.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.mod.ksh
new file mode 100644
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.mod.ksh
@@ -0,0 +1,57 @@
+#!/usr/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2023 Domagoj Stolfa
+#
+
+bname=`basename $0`
+dtraceout=/tmp/dtrace.$bname
+
+script()
+{
+ $dtrace -o $dtraceout.$1 -x oformat=$1 -s /dev/stdin <<__EOF__
+BEGIN
+{
+ mod(0);
+ exit(0);
+}
+__EOF__
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+script json
+jq . $dtraceout.json
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid JSON. see $dtraceout.json
+ exit 1
+fi
+
+script xml
+xmllint $dtraceout.xml
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid XML. see $dtraceout.xml
+ exit 1
+fi
+
+rm $dtraceout.json
+rm $dtraceout.xml
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.print.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.print.ksh
new file mode 100644
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.print.ksh
@@ -0,0 +1,60 @@
+#!/usr/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2023 Domagoj Stolfa
+#
+
+bname=`basename $0`
+dtraceout=/tmp/dtrace.$bname
+
+script()
+{
+ $dtrace -o $dtraceout.$1 -x oformat=$1 -s /dev/stdin <<__EOF__
+BEGIN
+{
+ print(*curthread);
+ print(*curthread->td_proc);
+ print(*curthread->td_ucred);
+ print(*curthread->td_ucred->cr_prison);
+ exit(0);
+}
+__EOF__
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+script json
+jq . $dtraceout.json
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid JSON. see $dtraceout.json
+ exit 1
+fi
+
+script xml
+xmllint $dtraceout.xml
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid XML. see $dtraceout.xml
+ exit 1
+fi
+
+rm $dtraceout.json
+rm $dtraceout.xml
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.printf.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.printf.ksh
new file mode 100644
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.printf.ksh
@@ -0,0 +1,57 @@
+#!/usr/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2023 Domagoj Stolfa
+#
+
+bname=`basename $0`
+dtraceout=/tmp/dtrace.$bname
+
+script()
+{
+ $dtrace -o $dtraceout.$1 -x oformat=$1 -s /dev/stdin <<__EOF__
+BEGIN
+{
+ printf("Hello World!");
+ exit(0);
+}
+__EOF__
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+script json
+jq . $dtraceout.json
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid JSON. see $dtraceout.json
+ exit 1
+fi
+
+script xml
+xmllint $dtraceout.xml
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid XML. see $dtraceout.xml
+ exit 1
+fi
+
+rm $dtraceout.json
+rm $dtraceout.xml
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.printm.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.printm.ksh
new file mode 100644
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.printm.ksh
@@ -0,0 +1,57 @@
+#!/usr/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2023 Domagoj Stolfa
+#
+
+bname=`basename $0`
+dtraceout=/tmp/dtrace.$bname
+
+script()
+{
+ $dtrace -o $dtraceout.$1 -x oformat=$1 -s /dev/stdin <<__EOF__
+BEGIN
+{
+ printm(100, memref(curthread, 10));
+ exit(0);
+}
+__EOF__
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+script json
+jq . $dtraceout.json
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid JSON. see $dtraceout.json
+ exit 1
+fi
+
+script xml
+xmllint $dtraceout.xml
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid XML. see $dtraceout.xml
+ exit 1
+fi
+
+rm $dtraceout.json
+rm $dtraceout.xml
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.stack.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.stack.ksh
new file mode 100644
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.stack.ksh
@@ -0,0 +1,61 @@
+#!/usr/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2023 Domagoj Stolfa
+#
+
+bname=`basename $0`
+dtraceout=/tmp/dtrace.$bname
+
+script()
+{
+ $dtrace -o $dtraceout.$1 -x oformat=$1 -s /dev/stdin <<__EOF__
+syscall:::entry
+{
+ stack();
+}
+
+tick-1s
+{
+ exit(0);
+}
+__EOF__
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+script json
+jq . $dtraceout.json
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid JSON. see $dtraceout.json
+ exit 1
+fi
+
+script xml
+xmllint $dtraceout.xml
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid XML. see $dtraceout.xml
+ exit 1
+fi
+
+rm $dtraceout.json
+rm $dtraceout.xml
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.sym.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.sym.ksh
new file mode 100644
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.sym.ksh
@@ -0,0 +1,57 @@
+#!/usr/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2023 Domagoj Stolfa
+#
+
+bname=`basename $0`
+dtraceout=/tmp/dtrace.$bname
+
+script()
+{
+ $dtrace -o $dtraceout.$1 -x oformat=$1 -s /dev/stdin <<__EOF__
+BEGIN
+{
+ sym(0);
+ exit(0);
+}
+__EOF__
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+script json
+jq . $dtraceout.json
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid JSON. see $dtraceout.json
+ exit 1
+fi
+
+script xml
+xmllint $dtraceout.xml
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid XML. see $dtraceout.xml
+ exit 1
+fi
+
+rm $dtraceout.json
+rm $dtraceout.xml
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.trace.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.trace.ksh
new file mode 100644
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.trace.ksh
@@ -0,0 +1,66 @@
+#!/usr/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2023 Domagoj Stolfa
+#
+
+bname=`basename $0`
+dtraceout=/tmp/dtrace.$bname
+
+script()
+{
+ $dtrace -o $dtraceout.$1 -x oformat=$1 -s /dev/stdin <<__EOF__
+BEGIN
+{
+ trace(0);
+ trace(1);
+ trace(2);
+ trace(3);
+ trace(4);
+ trace(5);
+ trace(6);
+ trace(7);
+ trace(8);
+ trace(9);
+ exit(0);
+}
+__EOF__
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+script json
+jq . $dtraceout.json
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid JSON. see $dtraceout.json
+ exit 1
+fi
+
+script xml
+xmllint $dtraceout.xml
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid XML. see $dtraceout.xml
+ exit 1
+fi
+
+rm $dtraceout.json
+rm $dtraceout.xml
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.tracemem.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.tracemem.ksh
new file mode 100644
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.tracemem.ksh
@@ -0,0 +1,57 @@
+#!/usr/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2023 Domagoj Stolfa
+#
+
+bname=`basename $0`
+dtraceout=/tmp/dtrace.$bname
+
+script()
+{
+ $dtrace -o $dtraceout.$1 -x oformat=$1 -s /dev/stdin <<__EOF__
+BEGIN
+{
+ tracemem(curthread, 10);
+ exit(0);
+}
+__EOF__
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+script json
+jq . $dtraceout.json
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid JSON. see $dtraceout.json
+ exit 1
+fi
+
+script xml
+xmllint $dtraceout.xml
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid XML. see $dtraceout.xml
+ exit 1
+fi
+
+rm $dtraceout.json
+rm $dtraceout.xml
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.umod.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.umod.ksh
new file mode 100644
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.umod.ksh
@@ -0,0 +1,57 @@
+#!/usr/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2023 Domagoj Stolfa
+#
+
+bname=`basename $0`
+dtraceout=/tmp/dtrace.$bname
+
+script()
+{
+ $dtrace -o $dtraceout.$1 -x oformat=$1 -s /dev/stdin <<__EOF__
+BEGIN
+{
+ umod(0);
+ exit(0);
+}
+__EOF__
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+script json
+jq . $dtraceout.json
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid JSON. see $dtraceout.json
+ exit 1
+fi
+
+script xml
+xmllint $dtraceout.xml
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid XML. see $dtraceout.xml
+ exit 1
+fi
+
+rm $dtraceout.json
+rm $dtraceout.xml
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.ustack.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.ustack.ksh
new file mode 100644
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.ustack.ksh
@@ -0,0 +1,61 @@
+#!/usr/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2023 Domagoj Stolfa
+#
+
+bname=`basename $0`
+dtraceout=/tmp/dtrace.$bname
+
+script()
+{
+ $dtrace -o $dtraceout.$1 -x oformat=$1 -s /dev/stdin <<__EOF__
+syscall:::entry
+{
+ ustack();
+}
+
+tick-1s
+{
+ exit(0);
+}
+__EOF__
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+script json
+jq . $dtraceout.json
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid JSON. see $dtraceout.json
+ exit 1
+fi
+
+script xml
+xmllint $dtraceout.xml
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid XML. see $dtraceout.xml
+ exit 1
+fi
+
+rm $dtraceout.json
+rm $dtraceout.xml
+
+exit 0
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.usym.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.usym.ksh
new file mode 100644
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.usym.ksh
@@ -0,0 +1,57 @@
+#!/usr/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2023 Domagoj Stolfa
+#
+
+bname=`basename $0`
+dtraceout=/tmp/dtrace.$bname
+
+script()
+{
+ $dtrace -o $dtraceout.$1 -x oformat=$1 -s /dev/stdin <<__EOF__
+BEGIN
+{
+ usym(0);
+ exit(0);
+}
+__EOF__
+}
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+
+script json
+jq . $dtraceout.json
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid JSON. see $dtraceout.json
+ exit 1
+fi
+
+script xml
+xmllint $dtraceout.xml
+
+if [ $? != 0 ]; then
+ echo $bname: failed to produce valid XML. see $dtraceout.xml
+ exit 1
+fi
+
+rm $dtraceout.json
+rm $dtraceout.xml
+
+exit 0
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_aggregate.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_aggregate.c
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_aggregate.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_aggregate.c
@@ -35,6 +35,7 @@
#include <unistd.h>
#include <dt_impl.h>
#include <assert.h>
+#include <dt_oformat.h>
#ifdef illumos
#include <alloca.h>
#else
@@ -471,9 +472,14 @@
}
if (buf->dtbd_drops != 0) {
+ xo_open_instance("probes");
+ dt_oformat_drop(dtp, cpu);
if (dt_handle_cpudrop(dtp, cpu,
- DTRACEDROP_AGGREGATION, buf->dtbd_drops) == -1)
+ DTRACEDROP_AGGREGATION, buf->dtbd_drops) == -1) {
+ xo_close_instance("probes");
return (-1);
+ }
+ xo_close_instance("probes");
}
if (buf->dtbd_size == 0)
@@ -2127,8 +2133,13 @@
if (func == NULL)
func = dtrace_aggregate_walk_sorted;
- if ((*func)(dtp, dt_print_agg, &pd) == -1)
- return (dt_set_errno(dtp, dtp->dt_errno));
+ if (dtp->dt_oformat) {
+ if ((*func)(dtp, dt_format_agg, &pd) == -1)
+ return (dt_set_errno(dtp, dtp->dt_errno));
+ } else {
+ if ((*func)(dtp, dt_print_agg, &pd) == -1)
+ return (dt_set_errno(dtp, dtp->dt_errno));
+ }
return (0);
}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_consume.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_consume.c
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_consume.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_consume.c
@@ -24,6 +24,7 @@
*/
/*
+ * Copyright (c) 2023, Domagoj Stolfa. All rights reserved.
* Copyright (c) 2017, Joyent, Inc. All rights reserved.
* Copyright (c) 2012 by Delphix. All rights reserved.
*/
@@ -40,12 +41,50 @@
#endif
#include <dt_impl.h>
#include <dt_pq.h>
+#include <dt_oformat.h>
#ifndef illumos
#include <libproc_compat.h>
#endif
#define DT_MASK_LO 0x00000000FFFFFFFFULL
+#define dt_format_sym(dtp, addr) dt_print_sym((dtp), NULL, NULL, addr)
+
+typedef struct dt_prepare_args {
+ int first_bin;
+ int last_bin;
+ union {
+ struct lquantize_args {
+#define lquantize_step u.lquantize.step
+#define lquantize_levels u.lquantize.levels
+#define lquantize_base u.lquantize.base
+ int base;
+ uint16_t step;
+ uint16_t levels;
+ } lquantize;
+ struct llquantize_args {
+#define llquantize_next u.llquantize.next
+#define llquantize_step u.llquantize.step
+#define llquantize_value u.llquantize.value
+#define llquantize_levels u.llquantize.levels
+#define llquantize_order u.llquantize.order
+#define llquantize_factor u.llquantize.factor
+#define llquantize_low u.llquantize.low
+#define llquantize_high u.llquantize.high
+#define llquantize_nsteps u.llquantize.nsteps
+ int64_t next;
+ int64_t step;
+ int64_t value;
+ int levels;
+ int order;
+ uint16_t factor;
+ uint16_t low;
+ uint16_t high;
+ uint16_t nsteps;
+ } llquantize;
+ } u;
+} dt_prepare_args_t;
+
/*
* We declare this here because (1) we need it and (2) we want to avoid a
* dependency on libm in libdtrace.
@@ -761,17 +800,17 @@
return (dt_printf(dtp, fp, "%c", ascii[(uint_t)(val + 0.5)]));
}
-int
-dt_print_quantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr,
- size_t size, uint64_t normal)
+static const int64_t *
+dt_format_quantize_prepare(dtrace_hdl_t *dtp, const void *addr, size_t size,
+ dt_prepare_args_t *args)
{
const int64_t *data = addr;
- int i, first_bin = 0, last_bin = DTRACE_QUANTIZE_NBUCKETS - 1;
- long double total = 0;
- char positives = 0, negatives = 0;
+ int first_bin = 0, last_bin = DTRACE_QUANTIZE_NBUCKETS - 1;
- if (size != DTRACE_QUANTIZE_NBUCKETS * sizeof (uint64_t))
- return (dt_set_errno(dtp, EDT_DMISMATCH));
+ if (size != DTRACE_QUANTIZE_NBUCKETS * sizeof (uint64_t)) {
+ (void) dt_set_errno(dtp, EDT_DMISMATCH);
+ return (NULL);
+ }
while (first_bin < DTRACE_QUANTIZE_NBUCKETS - 1 && data[first_bin] == 0)
first_bin++;
@@ -795,6 +834,58 @@
last_bin++;
}
+ args->first_bin = first_bin;
+ args->last_bin = last_bin;
+ return (data);
+}
+
+int
+dt_format_quantize(dtrace_hdl_t *dtp, const void *addr, size_t size,
+ uint64_t normal)
+{
+ const int64_t *data;
+ dt_prepare_args_t args = { 0 };
+ int i, first_bin = 0, last_bin = DTRACE_QUANTIZE_NBUCKETS - 1;
+
+ data = dt_format_quantize_prepare(dtp, addr, size, &args);
+ /* dt_errno is set for us */
+ if (data == NULL)
+ return (-1);
+
+ first_bin = args.first_bin;
+ last_bin = args.last_bin;
+
+ xo_open_list("buckets");
+ for (i = first_bin; i <= last_bin; i++) {
+ long long value = (long long)DTRACE_QUANTIZE_BUCKETVAL(i);
+ xo_open_instance("buckets");
+ xo_emit("{:value/%lld} {:count/%lld}", value,
+ (long long)data[i] / normal);
+ xo_close_instance("buckets");
+ }
+ xo_close_list("buckets");
+
+ return (0);
+}
+
+int
+dt_print_quantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr,
+ size_t size, uint64_t normal)
+{
+ const int64_t *data;
+ dt_prepare_args_t args = { 0 };
+ int i, first_bin = 0, last_bin = DTRACE_QUANTIZE_NBUCKETS - 1;
+ long double total = 0;
+ char positives = 0, negatives = 0;
+
+ data = dt_format_quantize_prepare(dtp, addr, size, &args);
+ /* dt_errno is set for us */
+ if (data == NULL)
+ return (-1);
+
+ first_bin = args.first_bin;
+ last_bin = args.last_bin;
+
for (i = first_bin; i <= last_bin; i++) {
positives |= (data[i] > 0);
negatives |= (data[i] < 0);
@@ -859,19 +950,19 @@
return (0);
}
-int
-dt_print_lquantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr,
- size_t size, uint64_t normal)
+static const int64_t *
+dt_format_lquantize_prepare(dtrace_hdl_t *dtp, const void *addr, size_t size,
+ dt_prepare_args_t *args)
{
const int64_t *data = addr;
- int i, first_bin, last_bin, base;
+ int first_bin = 0, last_bin = DTRACE_QUANTIZE_NBUCKETS - 1, base;
uint64_t arg;
- long double total = 0;
uint16_t step, levels;
- char positives = 0, negatives = 0;
- if (size < sizeof (uint64_t))
- return (dt_set_errno(dtp, EDT_DMISMATCH));
+ if (size < sizeof (uint64_t)) {
+ (void) dt_set_errno(dtp, EDT_DMISMATCH);
+ return (NULL);
+ }
arg = *data++;
size -= sizeof (uint64_t);
@@ -883,8 +974,10 @@
first_bin = 0;
last_bin = levels + 1;
- if (size != sizeof (uint64_t) * (levels + 2))
- return (dt_set_errno(dtp, EDT_DMISMATCH));
+ if (size != sizeof (uint64_t) * (levels + 2)) {
+ (void) dt_set_errno(dtp, EDT_DMISMATCH);
+ return (NULL);
+ }
while (first_bin <= levels + 1 && data[first_bin] == 0)
first_bin++;
@@ -903,6 +996,80 @@
last_bin++;
}
+ args->first_bin = first_bin;
+ args->last_bin = last_bin;
+ args->lquantize_base = base;
+ args->lquantize_step = step;
+ args->lquantize_levels = levels;
+ return (data);
+}
+
+int
+dt_format_lquantize(dtrace_hdl_t *dtp, const void *addr, size_t size,
+ uint64_t normal)
+{
+ const int64_t *data;
+ dt_prepare_args_t args = { 0 };
+ int i, first_bin, last_bin, base;
+ uint16_t step, levels;
+
+ data = dt_format_lquantize_prepare(dtp, addr, size, &args);
+ /* dt_errno is set for us */
+ if (data == NULL)
+ return (-1);
+
+ first_bin = args.first_bin;
+ last_bin = args.last_bin;
+ step = args.lquantize_step;
+ levels = args.lquantize_levels;
+ base = args.lquantize_base;
+
+ xo_open_list("buckets");
+ for (i = first_bin; i <= last_bin; i++) {
+ char c[32];
+ int err;
+
+ xo_open_instance("buckets");
+ if (i == 0) {
+ xo_emit("{:value/%d} {:operator/%s}", base, "<");
+ } else if (i == levels + 1) {
+ xo_emit("{:value/%d} {:operator/%s}",
+ base + (levels * step), ">=");
+ } else {
+ xo_emit("{:value/%d}", base + (i - 1) * step);
+ }
+
+ xo_emit("{:count/%lld}", (long long)data[i] / normal);
+ xo_close_instance("buckets");
+ }
+ xo_close_list("buckets");
+
+ return (0);
+}
+
+int
+dt_print_lquantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr,
+ size_t size, uint64_t normal)
+{
+ const int64_t *data;
+ dt_prepare_args_t args = { 0 };
+ int i, first_bin, last_bin, base;
+ uint64_t arg;
+ long double total = 0;
+ uint16_t step, levels;
+ char positives = 0, negatives = 0;
+
+ data = dt_format_lquantize_prepare(dtp, addr, size, &args);
+ /* dt_errno is set for us */
+ if (data == NULL)
+ return (-1);
+
+ first_bin = args.first_bin;
+ last_bin = args.last_bin;
+ step = args.lquantize_step;
+ levels = args.lquantize_levels;
+ base = args.lquantize_base;
+
for (i = first_bin; i <= last_bin; i++) {
positives |= (data[i] > 0);
negatives |= (data[i] < 0);
@@ -990,21 +1157,20 @@
return (dt_printf(dtp, fp, ": %-8s | %lld\n", c, (long long)count));
}
-int
-dt_print_llquantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr,
- size_t size, uint64_t normal)
+static const int64_t *
+dt_format_llquantize_prepare(dtrace_hdl_t *dtp, const void *addr, size_t size,
+ dt_prepare_args_t *args)
{
int i, first_bin, last_bin, bin = 1, order, levels;
uint16_t factor, low, high, nsteps;
const int64_t *data = addr;
int64_t value = 1, next, step;
- char positives = 0, negatives = 0;
- long double total = 0;
uint64_t arg;
- char c[32];
- if (size < sizeof (uint64_t))
- return (dt_set_errno(dtp, EDT_DMISMATCH));
+ if (size < sizeof(uint64_t)) {
+ (void) dt_set_errno(dtp, EDT_DMISMATCH);
+ return (NULL);
+ }
arg = *data++;
size -= sizeof (uint64_t);
@@ -1019,8 +1185,10 @@
* but sanity check them (to a degree) nonetheless.
*/
if (size > INT32_MAX || factor < 2 || low >= high ||
- nsteps == 0 || factor > nsteps)
- return (dt_set_errno(dtp, EDT_DMISMATCH));
+ nsteps == 0 || factor > nsteps) {
+ (void) dt_set_errno(dtp, EDT_DMISMATCH);
+ return (NULL);
+ }
levels = (int)size / sizeof (uint64_t);
@@ -1044,6 +1212,133 @@
last_bin++;
}
+ for (order = 0; order < low; order++)
+ value *= factor;
+
+ next = value * factor;
+ step = next > nsteps ? next / nsteps : 1;
+
+ args->first_bin = first_bin;
+ args->last_bin = last_bin;
+ args->llquantize_factor = factor;
+ args->llquantize_low = low;
+ args->llquantize_high = high;
+ args->llquantize_nsteps = nsteps;
+ args->llquantize_levels = levels;
+ args->llquantize_order = order;
+ args->llquantize_next = next;
+ args->llquantize_step = step;
+ args->llquantize_value = value;
+
+ return (data);
+}
+
+int
+dt_format_llquantize(dtrace_hdl_t *dtp, const void *addr, size_t size,
+ uint64_t normal)
+{
+ int first_bin, last_bin, bin = 1, order, levels;
+ uint16_t factor, low, high, nsteps;
+ const int64_t *data;
+ dt_prepare_args_t args = { 0 };
+ int64_t value = 1, next, step;
+ uint64_t arg;
+ char c[32];
+
+ data = dt_format_llquantize_prepare(dtp, addr, size, &args);
+ /* dt_errno is set for us */
+ if (data == NULL)
+ return (-1);
+
+ first_bin = args.first_bin;
+ last_bin = args.last_bin;
+ factor = args.llquantize_factor;
+ low = args.llquantize_low;
+ high = args.llquantize_high;
+ nsteps = args.llquantize_nsteps;
+ levels = args.llquantize_levels;
+ order = args.llquantize_order;
+ next = args.llquantize_next;
+ step = args.llquantize_step;
+ value = args.llquantize_value;
+
+ xo_open_list("buckets");
+ if (first_bin == 0) {
+ /*
+ * We have to represent < value somehow in JSON, so we bundle an
+ * optional "operator" in llquantize buckets.
+ */
+ xo_open_instance("buckets");
+ xo_emit("{:value/%lld} {:count/%lld} {:operator/%s}",
+ (long long)value, (long long)data[0] / normal, "<");
+ xo_close_instance("buckets");
+ }
+
+ while (order <= high) {
+ if (bin >= first_bin && bin <= last_bin) {
+ xo_open_instance("buckets");
+ xo_emit("{:value/%lld} {:count/%lld}", (long long)value,
+ (long long)data[bin] / normal);
+ xo_close_instance("buckets");
+ }
+
+ assert(value < next);
+ bin++;
+
+ if ((value += step) != next)
+ continue;
+
+ next = value * factor;
+ step = next > nsteps ? next / nsteps : 1;
+ order++;
+ }
+
+ if (last_bin < bin) {
+ xo_close_list("buckets");
+ return (0);
+ }
+
+ assert(last_bin == bin);
+ xo_open_instance("buckets");
+ xo_emit("{:value/%lld} {:count/%lld} {:operator/%s}", (long long)value,
+ (long long)data[bin] / normal, ">=");
+ xo_close_instance("buckets");
+
+ xo_close_list("buckets");
+ return (0);
+}
+
+int
+dt_print_llquantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr,
+ size_t size, uint64_t normal)
+{
+ int i, first_bin, last_bin, bin = 1, order, levels;
+ uint16_t factor, low, high, nsteps;
+ const int64_t *data;
+ dt_prepare_args_t args = { 0 };
+ int64_t value = 1, next, step;
+ char positives = 0, negatives = 0;
+ long double total = 0;
+ uint64_t arg;
+ char c[32];
+
+ data = dt_format_llquantize_prepare(dtp, addr, size, &args);
+ /* dt_errno is set for us */
+ if (data == NULL)
+ return (-1);
+
+ first_bin = args.first_bin;
+ last_bin = args.last_bin;
+ factor = args.llquantize_factor;
+ low = args.llquantize_low;
+ high = args.llquantize_high;
+ nsteps = args.llquantize_nsteps;
+ levels = args.llquantize_levels;
+ order = args.llquantize_order;
+ next = args.llquantize_next;
+ step = args.llquantize_step;
+ value = args.llquantize_value;
+
for (i = first_bin; i <= last_bin; i++) {
positives |= (data[i] > 0);
negatives |= (data[i] < 0);
@@ -1054,12 +1349,6 @@
"------------- Distribution -------------", "count") < 0)
return (-1);
- for (order = 0; order < low; order++)
- value *= factor;
-
- next = value * factor;
- step = next > nsteps ? next / nsteps : 1;
-
if (first_bin == 0) {
(void) snprintf(c, sizeof (c), "< %lld", (long long)value);
@@ -1105,6 +1394,16 @@
total, positives, negatives));
}
+static int
+dt_format_average(dtrace_hdl_t *dtp, caddr_t addr, size_t size, uint64_t normal)
+{
+ int64_t *data = (int64_t *)addr;
+
+ xo_emit("{:average/%lld}",
+ data[0] ? (long long)(data[1] / (int64_t)normal / data[0]) : 0);
+ return (0);
+}
+
/*ARGSUSED*/
static int
dt_print_average(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr,
@@ -1117,6 +1416,16 @@
(long long)(data[1] / (int64_t)normal / data[0]) : 0));
}
+static int
+dt_format_stddev(dtrace_hdl_t *dtp, caddr_t addr, size_t size, uint64_t normal)
+{
+ uint64_t *data = (uint64_t *)addr;
+
+ xo_emit("{:stddev/%llu}",
+ data[0] ? (unsigned long long)dt_stddev(data, normal) : 0);
+ return (0);
+}
+
/*ARGSUSED*/
static int
dt_print_stddev(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr,
@@ -1249,35 +1558,21 @@
}
int
-dt_print_stack(dtrace_hdl_t *dtp, FILE *fp, const char *format,
- caddr_t addr, int depth, int size)
+dt_format_stack(dtrace_hdl_t *dtp, caddr_t addr, int depth, int size)
{
dtrace_syminfo_t dts;
GElf_Sym sym;
- int i, indent;
- char c[PATH_MAX * 2];
+ int i;
uint64_t pc;
- if (dt_printf(dtp, fp, "\n") < 0)
- return (-1);
-
- if (format == NULL)
- format = "%s";
-
- if (dtp->dt_options[DTRACEOPT_STACKINDENT] != DTRACEOPT_UNSET)
- indent = (int)dtp->dt_options[DTRACEOPT_STACKINDENT];
- else
- indent = _dtrace_stkindent;
-
+ xo_open_list("stack-frames");
for (i = 0; i < depth; i++) {
switch (size) {
case sizeof (uint32_t):
- /* LINTED - alignment */
pc = *((uint32_t *)addr);
break;
case sizeof (uint64_t):
- /* LINTED - alignment */
pc = *((uint64_t *)addr);
break;
@@ -1290,16 +1585,19 @@
addr += size;
- if (dt_printf(dtp, fp, "%*s", indent, "") < 0)
- return (-1);
-
+ xo_open_instance("stack-frames");
if (dtrace_lookup_by_addr(dtp, pc, &sym, &dts) == 0) {
if (pc > sym.st_value) {
- (void) snprintf(c, sizeof (c), "%s`%s+0x%llx",
+ xo_emit("{:symbol/%s`%s+0x%llx} {:module/%s} "
+ "{:name/%s} {:offset/0x%llx}",
+ dts.dts_object, dts.dts_name,
+ (u_longlong_t)(pc - sym.st_value),
dts.dts_object, dts.dts_name,
(u_longlong_t)(pc - sym.st_value));
} else {
- (void) snprintf(c, sizeof (c), "%s`%s",
+ xo_emit("{:symbol/%s`%s} {:module/%s} "
+ "{:name/%s}",
+ dts.dts_object, dts.dts_name,
dts.dts_object, dts.dts_name);
}
} else {
@@ -1309,29 +1607,25 @@
* interested in the containing module.
*/
if (dtrace_lookup_by_addr(dtp, pc, NULL, &dts) == 0) {
- (void) snprintf(c, sizeof (c), "%s`0x%llx",
+ xo_emit("{:symbol/%s`0x%llx} {:module/%s} "
+ "{:offset/0x%llx}",
+ dts.dts_object, (u_longlong_t)pc,
dts.dts_object, (u_longlong_t)pc);
} else {
- (void) snprintf(c, sizeof (c), "0x%llx",
- (u_longlong_t)pc);
+ xo_emit("{:symbol/0x%llx} {:offset/0x%llx}",
+ (u_longlong_t)pc, (u_longlong_t)pc);
}
}
-
- if (dt_printf(dtp, fp, format, c) < 0)
- return (-1);
-
- if (dt_printf(dtp, fp, "\n") < 0)
- return (-1);
+ xo_close_instance("stack-frames");
}
+ xo_close_list("stack-frames");
return (0);
}
int
-dt_print_ustack(dtrace_hdl_t *dtp, FILE *fp, const char *format,
- caddr_t addr, uint64_t arg)
+dt_format_ustack(dtrace_hdl_t *dtp, caddr_t addr, uint64_t arg)
{
- /* LINTED - alignment */
uint64_t *pc = (uint64_t *)addr;
uint32_t depth = DTRACE_USTACK_NFRAMES(arg);
uint32_t strsize = DTRACE_USTACK_STRSIZE(arg);
@@ -1350,17 +1644,6 @@
pid = (pid_t)*pc++;
- if (dt_printf(dtp, fp, "\n") < 0)
- return (-1);
-
- if (format == NULL)
- format = "%s";
-
- if (dtp->dt_options[DTRACEOPT_STACKINDENT] != DTRACEOPT_UNSET)
- indent = (int)dtp->dt_options[DTRACEOPT_STACKINDENT];
- else
- indent = _dtrace_stkindent;
-
/*
* Ultimately, we need to add an entry point in the library vector for
* determining <symbol, offset> from <pid, address>. For now, if
@@ -1374,23 +1657,27 @@
if (P != NULL)
dt_proc_lock(dtp, P); /* lock handle while we perform lookups */
+ xo_open_list("ustack-frames");
for (i = 0; i < depth && pc[i] != 0; i++) {
const prmap_t *map;
- if ((err = dt_printf(dtp, fp, "%*s", indent, "")) < 0)
- break;
-
+ xo_open_instance("ustack-frames");
if (P != NULL && Plookup_by_addr(P, pc[i],
name, sizeof (name), &sym) == 0) {
(void) Pobjname(P, pc[i], objname, sizeof (objname));
if (pc[i] > sym.st_value) {
- (void) snprintf(c, sizeof (c),
- "%s`%s+0x%llx", dt_basename(objname), name,
+ xo_emit("{:symbol/%s`%s+0x%llx} {:module/%s} "
+ "{:name/%s} {:offset/0x%llx}",
+ dt_basename(objname), name,
+ (u_longlong_t)(pc[i] - sym.st_value),
+ dt_basename(objname), name,
(u_longlong_t)(pc[i] - sym.st_value));
} else {
- (void) snprintf(c, sizeof (c),
- "%s`%s", dt_basename(objname), name);
+ xo_emit("{:symbol/%s`%s} {:module/%s} "
+ "{:name/%s}",
+ dt_basename(objname), name,
+ dt_basename(objname), name);
}
} else if (str != NULL && str[0] != '\0' && str[0] != '@' &&
(P != NULL && ((map = Paddr_to_map(P, pc[i])) == NULL ||
@@ -1408,24 +1695,20 @@
* writable, we assume that we have fallen into this
* case and we refuse to use the string.
*/
- (void) snprintf(c, sizeof (c), "%s", str);
+ xo_emit("{:symbol/%s}", str);
} else {
if (P != NULL && Pobjname(P, pc[i], objname,
sizeof (objname)) != 0) {
- (void) snprintf(c, sizeof (c), "%s`0x%llx",
+ xo_emit("{:symbol/%s`0x%llx} {:module/%s} "
+ "{:offset/0x%llx}",
+ dt_basename(objname), (u_longlong_t)pc[i],
dt_basename(objname), (u_longlong_t)pc[i]);
} else {
- (void) snprintf(c, sizeof (c), "0x%llx",
- (u_longlong_t)pc[i]);
+ xo_emit("{:symbol/0x%llx} {:offset/0x%llx}",
+ (u_longlong_t)pc[i], (u_longlong_t)pc[i]);
}
}
- if ((err = dt_printf(dtp, fp, format, c)) < 0)
- break;
-
- if ((err = dt_printf(dtp, fp, "\n")) < 0)
- break;
-
if (str != NULL && str[0] == '@') {
/*
* If the first character of the string is an "at" sign,
@@ -1433,16 +1716,7 @@
* and it is printed out beneath the frame and offset
* with brackets.
*/
- if ((err = dt_printf(dtp, fp, "%*s", indent, "")) < 0)
- break;
-
- (void) snprintf(c, sizeof (c), " [ %s ]", &str[1]);
-
- if ((err = dt_printf(dtp, fp, format, c)) < 0)
- break;
-
- if ((err = dt_printf(dtp, fp, "\n")) < 0)
- break;
+ xo_emit("{:annotation/%s}", &str[1]);
}
if (str != NULL) {
@@ -1450,7 +1724,9 @@
if (str - strbase >= strsize)
str = NULL;
}
+ xo_close_instance("ustack-frames");
}
+ xo_close_list("ustack-frames");
if (P != NULL) {
dt_proc_unlock(dtp, P);
@@ -1460,8 +1736,255 @@
return (err);
}
-static int
-dt_print_usym(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, dtrace_actkind_t act)
+int
+dt_print_stack(dtrace_hdl_t *dtp, FILE *fp, const char *format,
+ caddr_t addr, int depth, int size)
+{
+ dtrace_syminfo_t dts;
+ GElf_Sym sym;
+ int i, indent;
+ char c[PATH_MAX * 2];
+ uint64_t pc;
+
+ if (dt_printf(dtp, fp, "\n") < 0)
+ return (-1);
+
+ if (format == NULL)
+ format = "%s";
+
+ if (dtp->dt_options[DTRACEOPT_STACKINDENT] != DTRACEOPT_UNSET)
+ indent = (int)dtp->dt_options[DTRACEOPT_STACKINDENT];
+ else
+ indent = _dtrace_stkindent;
+
+ for (i = 0; i < depth; i++) {
+ switch (size) {
+ case sizeof (uint32_t):
+ /* LINTED - alignment */
+ pc = *((uint32_t *)addr);
+ break;
+
+ case sizeof (uint64_t):
+ /* LINTED - alignment */
+ pc = *((uint64_t *)addr);
+ break;
+
+ default:
+ return (dt_set_errno(dtp, EDT_BADSTACKPC));
+ }
+
+ if (pc == 0)
+ break;
+
+ addr += size;
+
+ if (dt_printf(dtp, fp, "%*s", indent, "") < 0)
+ return (-1);
+
+ if (dtrace_lookup_by_addr(dtp, pc, &sym, &dts) == 0) {
+ if (pc > sym.st_value) {
+ (void) snprintf(c, sizeof (c), "%s`%s+0x%llx",
+ dts.dts_object, dts.dts_name,
+ (u_longlong_t)(pc - sym.st_value));
+ } else {
+ (void) snprintf(c, sizeof (c), "%s`%s",
+ dts.dts_object, dts.dts_name);
+ }
+ } else {
+ /*
+ * We'll repeat the lookup, but this time we'll specify
+ * a NULL GElf_Sym -- indicating that we're only
+ * interested in the containing module.
+ */
+ if (dtrace_lookup_by_addr(dtp, pc, NULL, &dts) == 0) {
+ (void) snprintf(c, sizeof (c), "%s`0x%llx",
+ dts.dts_object, (u_longlong_t)pc);
+ } else {
+ (void) snprintf(c, sizeof (c), "0x%llx",
+ (u_longlong_t)pc);
+ }
+ }
+
+ if (dt_printf(dtp, fp, format, c) < 0)
+ return (-1);
+
+ if (dt_printf(dtp, fp, "\n") < 0)
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+dt_print_ustack(dtrace_hdl_t *dtp, FILE *fp, const char *format,
+ caddr_t addr, uint64_t arg)
+{
+ /* LINTED - alignment */
+ uint64_t *pc = (uint64_t *)addr;
+ uint32_t depth = DTRACE_USTACK_NFRAMES(arg);
+ uint32_t strsize = DTRACE_USTACK_STRSIZE(arg);
+ const char *strbase = addr + (depth + 1) * sizeof (uint64_t);
+ const char *str = strsize ? strbase : NULL;
+ int err = 0;
+
+ char name[PATH_MAX], objname[PATH_MAX], c[PATH_MAX * 2];
+ struct ps_prochandle *P;
+ GElf_Sym sym;
+ int i, indent;
+ pid_t pid;
+
+ if (depth == 0)
+ return (0);
+
+ pid = (pid_t)*pc++;
+
+ if (dt_printf(dtp, fp, "\n") < 0)
+ return (-1);
+
+ if (format == NULL)
+ format = "%s";
+
+ if (dtp->dt_options[DTRACEOPT_STACKINDENT] != DTRACEOPT_UNSET)
+ indent = (int)dtp->dt_options[DTRACEOPT_STACKINDENT];
+ else
+ indent = _dtrace_stkindent;
+
+ /*
+ * Ultimately, we need to add an entry point in the library vector for
+ * determining <symbol, offset> from <pid, address>. For now, if
+ * this is a vector open, we just print the raw address or string.
+ */
+ if (dtp->dt_vector == NULL)
+ P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0);
+ else
+ P = NULL;
+
+ if (P != NULL)
+ dt_proc_lock(dtp, P); /* lock handle while we perform lookups */
+
+ for (i = 0; i < depth && pc[i] != 0; i++) {
+ const prmap_t *map;
+
+ if ((err = dt_printf(dtp, fp, "%*s", indent, "")) < 0)
+ break;
+
+ if (P != NULL && Plookup_by_addr(P, pc[i],
+ name, sizeof (name), &sym) == 0) {
+ (void) Pobjname(P, pc[i], objname, sizeof (objname));
+
+ if (pc[i] > sym.st_value) {
+ (void) snprintf(c, sizeof (c),
+ "%s`%s+0x%llx", dt_basename(objname), name,
+ (u_longlong_t)(pc[i] - sym.st_value));
+ } else {
+ (void) snprintf(c, sizeof (c),
+ "%s`%s", dt_basename(objname), name);
+ }
+ } else if (str != NULL && str[0] != '\0' && str[0] != '@' &&
+ (P != NULL && ((map = Paddr_to_map(P, pc[i])) == NULL ||
+ (map->pr_mflags & MA_WRITE)))) {
+ /*
+ * If the current string pointer in the string table
+ * does not point to an empty string _and_ the program
+ * counter falls in a writable region, we'll use the
+ * string from the string table instead of the raw
+ * address. This last condition is necessary because
+ * some (broken) ustack helpers will return a string
+ * even for a program counter that they can't
+ * identify. If we have a string for a program
+ * counter that falls in a segment that isn't
+ * writable, we assume that we have fallen into this
+ * case and we refuse to use the string.
+ */
+ (void) snprintf(c, sizeof (c), "%s", str);
+ } else {
+ if (P != NULL && Pobjname(P, pc[i], objname,
+ sizeof (objname)) != 0) {
+ (void) snprintf(c, sizeof (c), "%s`0x%llx",
+ dt_basename(objname), (u_longlong_t)pc[i]);
+ } else {
+ (void) snprintf(c, sizeof (c), "0x%llx",
+ (u_longlong_t)pc[i]);
+ }
+ }
+
+ if ((err = dt_printf(dtp, fp, format, c)) < 0)
+ break;
+
+ if ((err = dt_printf(dtp, fp, "\n")) < 0)
+ break;
+
+ if (str != NULL && str[0] == '@') {
+ /*
+ * If the first character of the string is an "at" sign,
+ * then the string is inferred to be an annotation --
+ * and it is printed out beneath the frame and offset
+ * with brackets.
+ */
+ if ((err = dt_printf(dtp, fp, "%*s", indent, "")) < 0)
+ break;
+
+ (void) snprintf(c, sizeof (c), " [ %s ]", &str[1]);
+
+ if ((err = dt_printf(dtp, fp, format, c)) < 0)
+ break;
+
+ if ((err = dt_printf(dtp, fp, "\n")) < 0)
+ break;
+ }
+
+ if (str != NULL) {
+ str += strlen(str) + 1;
+ if (str - strbase >= strsize)
+ str = NULL;
+ }
+ }
+
+ if (P != NULL) {
+ dt_proc_unlock(dtp, P);
+ dt_proc_release(dtp, P);
+ }
+
+ return (err);
+}
+
+static int
+dt_format_usym(dtrace_hdl_t *dtp, caddr_t addr, dtrace_actkind_t act)
+{
+ uint64_t pid = ((uint64_t *)addr)[0];
+ uint64_t pc = ((uint64_t *)addr)[1];
+ char *s;
+ int n, len = 256;
+
+ if (act == DTRACEACT_USYM && dtp->dt_vector == NULL) {
+ struct ps_prochandle *P;
+
+ if ((P = dt_proc_grab(dtp, pid,
+ PGRAB_RDONLY | PGRAB_FORCE, 0)) != NULL) {
+ GElf_Sym sym;
+
+ dt_proc_lock(dtp, P);
+
+ if (Plookup_by_addr(P, pc, NULL, 0, &sym) == 0)
+ pc = sym.st_value;
+
+ dt_proc_unlock(dtp, P);
+ dt_proc_release(dtp, P);
+ }
+ }
+
+ do {
+ n = len;
+ s = alloca(n);
+ } while ((len = dtrace_uaddr2str(dtp, pid, pc, s, n)) > n);
+
+ xo_emit("{:usym/%s}", s);
+ return (0);
+}
+
+
+static int
+dt_print_usym(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, dtrace_actkind_t act)
{
/* LINTED - alignment */
uint64_t pid = ((uint64_t *)addr)[0];
@@ -1496,6 +2019,42 @@
return (dt_printf(dtp, fp, format, s));
}
+int
+dt_format_umod(dtrace_hdl_t *dtp, caddr_t addr)
+{
+ uint64_t pid = ((uint64_t *)addr)[0];
+ uint64_t pc = ((uint64_t *)addr)[1];
+ int err = 0;
+
+ char objname[PATH_MAX];
+ struct ps_prochandle *P;
+
+ /*
+ * See the comment in dt_print_ustack() for the rationale for
+ * printing raw addresses in the vectored case.
+ */
+ if (dtp->dt_vector == NULL)
+ P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0);
+ else
+ P = NULL;
+
+ if (P != NULL)
+ dt_proc_lock(dtp, P); /* lock handle while we perform lookups */
+
+ if (P != NULL && Pobjname(P, pc, objname, sizeof (objname)) != 0) {
+ xo_emit("{:umod/%s}", dt_basename(objname));
+ } else {
+ xo_emit("{:umod/0x%llx}", (u_longlong_t)pc);
+ }
+
+ if (P != NULL) {
+ dt_proc_unlock(dtp, P);
+ dt_proc_release(dtp, P);
+ }
+
+ return (0);
+}
+
int
dt_print_umod(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr)
{
@@ -1552,8 +2111,13 @@
format = " %-50s";
if (dtrace_lookup_by_addr(dtp, pc, &sym, &dts) == 0) {
- (void) snprintf(c, sizeof (c), "%s`%s",
- dts.dts_object, dts.dts_name);
+ if (dtp->dt_oformat)
+ xo_emit("{:sym/%s`%s} {:object/%s} {:name/%s}",
+ dts.dts_object, dts.dts_name, dts.dts_object,
+ dts.dts_name);
+ else
+ (void) snprintf(c, sizeof (c), "%s`%s",
+ dts.dts_object, dts.dts_name);
} else {
/*
* We'll repeat the lookup, but this time we'll specify a
@@ -1561,20 +2125,46 @@
* the containing module.
*/
if (dtrace_lookup_by_addr(dtp, pc, NULL, &dts) == 0) {
- (void) snprintf(c, sizeof (c), "%s`0x%llx",
- dts.dts_object, (u_longlong_t)pc);
+ if (dtp->dt_oformat)
+ xo_emit("{:sym/%s`0x%llx} {:object/%s} "
+ "{:offset/0x%llx}",
+ dts.dts_object, (u_longlong_t)pc,
+ dts.dts_object, (u_longlong_t)pc);
+ else
+ (void) snprintf(c, sizeof (c), "%s`0x%llx",
+ dts.dts_object, (u_longlong_t)pc);
} else {
- (void) snprintf(c, sizeof (c), "0x%llx",
- (u_longlong_t)pc);
+ if (dtp->dt_oformat)
+ xo_emit("{:sym/0x%llx} {:offset/0x%llx}",
+ (u_longlong_t)pc, (u_longlong_t)pc);
+ else
+ (void) snprintf(c, sizeof (c), "0x%llx",
+ (u_longlong_t)pc);
}
}
- if (dt_printf(dtp, fp, format, c) < 0)
+ if (dtp->dt_oformat != 0 && dt_printf(dtp, fp, format, c) < 0)
return (-1);
return (0);
}
+int
+dt_format_mod(dtrace_hdl_t *dtp, caddr_t addr)
+{
+ /* LINTED - alignment */
+ uint64_t pc = *((uint64_t *)addr);
+ dtrace_syminfo_t dts;
+
+ if (dtrace_lookup_by_addr(dtp, pc, NULL, &dts) == 0) {
+ xo_emit("{:mod/%s}", dts.dts_object);
+ } else {
+ xo_emit("{:mod/0x%llx}", (u_longlong_t)pc);
+ }
+
+ return (0);
+}
+
int
dt_print_mod(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr)
{
@@ -1598,6 +2188,74 @@
return (0);
}
+static char *
+dt_format_bytes_get(dtrace_hdl_t *dtp, caddr_t addr, size_t nbytes)
+{
+ char *s = dt_alloc(dtp, nbytes * 2 + 2 + 1); /* 2 bytes per byte + 0x + '\0' */
+ char t[6];
+ char *c = (char *)addr;
+ size_t i, j;
+
+ if (s == NULL)
+ return (NULL);
+
+ /*
+ * XXX: Some duplication with dt_print_bytes().
+ */
+ for (i = 0; i < nbytes; i++) {
+ if (isprint(c[i]) || isspace(c[i]) || c[i] == '\b' || c[i] == '\a')
+ continue;
+
+ if (c[i] == '\0' && i > 0) {
+ for (j = i + 1; j < nbytes; j++) {
+ if (c[j] != '\0')
+ break;
+ }
+
+ if (j != nbytes)
+ break;
+
+ memcpy(s, c, nbytes);
+ return (s);
+ }
+
+ break;
+ }
+
+ if (i == nbytes) {
+ memcpy(s, c, nbytes);
+ s[nbytes] = '\0';
+ return (s);
+ }
+
+ s[0] = '0';
+ s[1] = 'x';
+ for (i = 0; i < nbytes; i++) {
+ snprintf(t, sizeof(t), "%02x", (uchar_t)c[i]);
+ memcpy(s + (i * 2) + 2, t, 2);
+ }
+
+ s[nbytes * 2 + 2] = 0;
+ return (s);
+}
+
+static int
+dt_format_memory(dtrace_hdl_t *dtp, caddr_t addr)
+{
+
+ size_t nbytes = *((uintptr_t *) addr);
+ char *s;
+
+ s = dt_format_bytes_get(dtp, addr + sizeof(uintptr_t), nbytes);
+ if (s == NULL)
+ return (-1);
+
+ xo_emit("{:printm/%s}", s);
+ dt_free(dtp, s);
+
+ return (0);
+}
+
static int
dt_print_memory(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr)
{
@@ -1745,60 +2403,144 @@
int64_t remaining;
int (*func)(dtrace_hdl_t *, dtrace_aggregate_f *, void *);
- /*
- * We (should) have two records: the aggregation ID followed by the
- * number of aggregation entries after which the aggregation is to be
- * truncated.
- */
- addr = base + rec->dtrd_offset;
+ /*
+ * We (should) have two records: the aggregation ID followed by the
+ * number of aggregation entries after which the aggregation is to be
+ * truncated.
+ */
+ addr = base + rec->dtrd_offset;
+
+ if (rec->dtrd_size != sizeof (dtrace_aggvarid_t))
+ return (dt_set_errno(dtp, EDT_BADTRUNC));
+
+ /* LINTED - alignment */
+ trunc.dttd_id = *((dtrace_aggvarid_t *)addr);
+ rec++;
+
+ if (rec->dtrd_action != DTRACEACT_LIBACT)
+ return (dt_set_errno(dtp, EDT_BADTRUNC));
+
+ if (rec->dtrd_arg != DT_ACT_TRUNC)
+ return (dt_set_errno(dtp, EDT_BADTRUNC));
+
+ addr = base + rec->dtrd_offset;
+
+ switch (rec->dtrd_size) {
+ case sizeof (uint64_t):
+ /* LINTED - alignment */
+ remaining = *((int64_t *)addr);
+ break;
+ case sizeof (uint32_t):
+ /* LINTED - alignment */
+ remaining = *((int32_t *)addr);
+ break;
+ case sizeof (uint16_t):
+ /* LINTED - alignment */
+ remaining = *((int16_t *)addr);
+ break;
+ case sizeof (uint8_t):
+ remaining = *((int8_t *)addr);
+ break;
+ default:
+ return (dt_set_errno(dtp, EDT_BADNORMAL));
+ }
+
+ if (remaining < 0) {
+ func = dtrace_aggregate_walk_valsorted;
+ remaining = -remaining;
+ } else {
+ func = dtrace_aggregate_walk_valrevsorted;
+ }
+
+ assert(remaining >= 0);
+ trunc.dttd_remaining = remaining;
+
+ (void) func(dtp, dt_trunc_agg, &trunc);
+
+ return (0);
+}
+
+static int
+dt_format_datum(dtrace_hdl_t *dtp, dtrace_recdesc_t *rec, caddr_t addr,
+ size_t size, const dtrace_aggdata_t *aggdata, uint64_t normal,
+ dt_print_aggdata_t *pd)
+{
+ dtrace_actkind_t act = rec->dtrd_action;
+ boolean_t packed = pd->dtpa_agghist || pd->dtpa_aggpack;
+ dtrace_aggdesc_t *agg = aggdata->dtada_desc;
+ char fmt[512];
+ char *s;
+
+ if (packed && pd->dtpa_agghisthdr != agg->dtagd_varid)
+ pd->dtpa_agghisthdr = agg->dtagd_varid;
+
+ switch (act) {
+ case DTRACEACT_STACK:
+ return (dt_format_stack(dtp, addr, rec->dtrd_arg,
+ rec->dtrd_size / rec->dtrd_arg));
+
+ case DTRACEACT_USTACK:
+ case DTRACEACT_JSTACK:
+ return (dt_format_ustack(dtp, addr, rec->dtrd_arg));
+
+ case DTRACEACT_USYM:
+ case DTRACEACT_UADDR:
+ return (dt_format_usym(dtp, addr, act));
+
+ case DTRACEACT_UMOD:
+ return (dt_format_umod(dtp, addr));
+
+ case DTRACEACT_SYM:
+ return (dt_format_sym(dtp, addr));
+ case DTRACEACT_MOD:
+ return (dt_format_mod(dtp, addr));
- if (rec->dtrd_size != sizeof (dtrace_aggvarid_t))
- return (dt_set_errno(dtp, EDT_BADTRUNC));
+ case DTRACEAGG_QUANTIZE:
+ return (dt_format_quantize(dtp, addr, size, normal));
- /* LINTED - alignment */
- trunc.dttd_id = *((dtrace_aggvarid_t *)addr);
- rec++;
+ case DTRACEAGG_LQUANTIZE:
+ return (dt_format_lquantize(dtp, addr, size, normal));
- if (rec->dtrd_action != DTRACEACT_LIBACT)
- return (dt_set_errno(dtp, EDT_BADTRUNC));
+ case DTRACEAGG_LLQUANTIZE:
+ return (dt_format_llquantize(dtp, addr, size, normal));
- if (rec->dtrd_arg != DT_ACT_TRUNC)
- return (dt_set_errno(dtp, EDT_BADTRUNC));
+ case DTRACEAGG_AVG:
+ return (dt_format_average(dtp, addr, size, normal));
- addr = base + rec->dtrd_offset;
+ case DTRACEAGG_STDDEV:
+ return (dt_format_stddev(dtp, addr, size, normal));
- switch (rec->dtrd_size) {
+ default:
+ break;
+ }
+
+ switch (size) {
case sizeof (uint64_t):
- /* LINTED - alignment */
- remaining = *((int64_t *)addr);
+ snprintf(fmt, sizeof(fmt), "{:%s/%%lld}", pd->dtpa_keyname);
+ xo_emit(fmt, (long long)*((uint64_t *)addr) / normal);
break;
case sizeof (uint32_t):
- /* LINTED - alignment */
- remaining = *((int32_t *)addr);
+ snprintf(fmt, sizeof(fmt), "{:%s/%%d}", pd->dtpa_keyname);
+ xo_emit(fmt, *((uint32_t *)addr) / (uint32_t)normal);
break;
case sizeof (uint16_t):
- /* LINTED - alignment */
- remaining = *((int16_t *)addr);
+ snprintf(fmt, sizeof(fmt), "{:%s/%%d}", pd->dtpa_keyname);
+ xo_emit(fmt, *((uint16_t *)addr) / (uint32_t)normal);
break;
case sizeof (uint8_t):
- remaining = *((int8_t *)addr);
+ snprintf(fmt, sizeof(fmt), "{:%s/%%d}", pd->dtpa_keyname);
+ xo_emit(fmt, *((uint8_t *)addr) / (uint32_t)normal);
break;
default:
- return (dt_set_errno(dtp, EDT_BADNORMAL));
- }
+ s = dt_format_bytes_get(dtp, addr, size);
+ if (s == NULL)
+ return (-1);
- if (remaining < 0) {
- func = dtrace_aggregate_walk_valsorted;
- remaining = -remaining;
- } else {
- func = dtrace_aggregate_walk_valrevsorted;
+ xo_emit("{:value/%s}", s);
+ dt_free(dtp, s);
+ break;
}
- assert(remaining >= 0);
- trunc.dttd_remaining = remaining;
-
- (void) func(dtp, dt_trunc_agg, &trunc);
-
return (0);
}
@@ -1956,6 +2698,119 @@
return (err);
}
+int
+dt_format_aggs(const dtrace_aggdata_t **aggsdata, int naggvars, void *arg)
+{
+ int i, aggact = 0;
+ dt_print_aggdata_t *pd = arg;
+ const dtrace_aggdata_t *aggdata = aggsdata[0];
+ dtrace_aggdesc_t *agg = aggdata->dtada_desc;
+ dtrace_hdl_t *dtp = pd->dtpa_dtp;
+ dtrace_recdesc_t *rec;
+ dtrace_actkind_t act;
+ caddr_t addr;
+ size_t size;
+
+ if (pd->dtpa_aggname == NULL)
+ pd->dtpa_aggname = agg->dtagd_name;
+
+ xo_open_instance("aggregation-data");
+ strcpy(pd->dtpa_keyname, "value");
+ xo_open_list("keys");
+
+ /*
+ * Iterate over each record description in the key, printing the traced
+ * data, skipping the first datum (the tuple member created by the
+ * compiler).
+ */
+ for (i = 1; i < agg->dtagd_nrecs; i++) {
+ rec = &agg->dtagd_rec[i];
+ act = rec->dtrd_action;
+ addr = aggdata->dtada_data + rec->dtrd_offset;
+ size = rec->dtrd_size;
+
+ if (DTRACEACT_ISAGG(act)) {
+ aggact = i;
+ break;
+ }
+
+ xo_open_instance("keys");
+ if (dt_format_datum(dtp, rec, addr,
+ size, aggdata, 1, pd) < 0) {
+ xo_close_instance("keys");
+ xo_close_instance("aggregation-data");
+ return (-1);
+ }
+ xo_close_instance("keys");
+
+ if (dt_buffered_flush(dtp, NULL, rec, aggdata,
+ DTRACE_BUFDATA_AGGKEY) < 0) {
+ xo_close_instance("aggregation-data");
+ return (-1);
+ }
+ }
+ xo_close_list("keys");
+
+ assert(aggact != 0);
+
+ for (i = (naggvars == 1 ? 0 : 1); i < naggvars; i++) {
+ uint64_t normal;
+
+ aggdata = aggsdata[i];
+ agg = aggdata->dtada_desc;
+ rec = &agg->dtagd_rec[aggact];
+ act = rec->dtrd_action;
+ addr = aggdata->dtada_data + rec->dtrd_offset;
+ size = rec->dtrd_size;
+
+ assert(DTRACEACT_ISAGG(act));
+
+ switch (act) {
+ case DTRACEAGG_MIN:
+ strcpy(pd->dtpa_keyname, "min");
+ break;
+ case DTRACEAGG_MAX:
+ strcpy(pd->dtpa_keyname, "max");
+ break;
+ case DTRACEAGG_COUNT:
+ strcpy(pd->dtpa_keyname, "count");
+ break;
+ case DTRACEAGG_SUM:
+ strcpy(pd->dtpa_keyname, "sum");
+ break;
+ default:
+ strcpy(pd->dtpa_keyname, "UNKNOWN");
+ break;
+ }
+
+ normal = aggdata->dtada_normal;
+
+ if (dt_format_datum(dtp, rec, addr, size,
+ aggdata, normal, pd) < 0) {
+ xo_close_instance("aggregation-data");
+ return (-1);
+ }
+
+ if (dt_buffered_flush(dtp, NULL, rec, aggdata,
+ DTRACE_BUFDATA_AGGVAL) < 0) {
+ xo_close_instance("aggregation-data");
+ return (-1);
+ }
+
+ if (!pd->dtpa_allunprint)
+ agg->dtagd_flags |= DTRACE_AGD_PRINTED;
+ }
+
+ if (dt_buffered_flush(dtp, NULL, NULL, aggdata,
+ DTRACE_BUFDATA_AGGFORMAT | DTRACE_BUFDATA_AGGLAST) < 0) {
+ xo_close_instance("aggregation-data");
+ return (-1);
+ }
+
+ xo_close_instance("aggregation-data");
+ return (0);
+}
+
int
dt_print_aggs(const dtrace_aggdata_t **aggsdata, int naggvars, void *arg)
{
@@ -2037,6 +2892,33 @@
return (0);
}
+int
+dt_format_agg(const dtrace_aggdata_t *aggdata, void *arg)
+{
+ dt_print_aggdata_t *pd = arg;
+ dtrace_aggdesc_t *agg = aggdata->dtada_desc;
+ dtrace_aggvarid_t aggvarid = pd->dtpa_id;
+
+ if (pd->dtpa_allunprint) {
+ if (agg->dtagd_flags & DTRACE_AGD_PRINTED)
+ return (0);
+ } else {
+ /*
+ * If we're not printing all unprinted aggregations, then the
+ * aggregation variable ID denotes a specific aggregation
+ * variable that we should print -- skip any other aggregations
+ * that we encounter.
+ */
+ if (agg->dtagd_nrecs == 0)
+ return (0);
+
+ if (aggvarid != agg->dtagd_varid)
+ return (0);
+ }
+
+ return (dt_format_aggs(&aggdata, 1, arg));
+}
+
int
dt_print_agg(const dtrace_aggdata_t *aggdata, void *arg)
{
@@ -2101,6 +2983,33 @@
return (rval);
}
+/*
+ * Helper functions to help maintain style(9) in dt_consume_cpu().
+ */
+static int
+dt_oformat_agg_sorted(dtrace_hdl_t *dtp, dtrace_aggregate_f *func,
+ dt_print_aggdata_t *pd)
+{
+ int r;
+
+ r = dtrace_aggregate_walk_sorted(dtp, dt_format_agg, pd);
+ if (r < 0) {
+ xo_close_list("aggregation-data");
+ xo_emit("{:aggregation-name/%s}", pd->dtpa_aggname);
+ xo_close_instance("output");
+ }
+
+ return (r);
+}
+
+static void
+dt_oformat_agg_name(dt_print_aggdata_t *pd)
+{
+
+ xo_close_list("aggregation-data");
+ xo_emit("{:aggregation-name/%s}", pd->dtpa_aggname);
+}
+
static int
dt_consume_cpu(dtrace_hdl_t *dtp, FILE *fp, int cpu,
dtrace_bufdesc_t *buf, boolean_t just_one,
@@ -2114,6 +3023,7 @@
uint64_t tracememsize = 0;
dtrace_probedata_t data;
uint64_t drops;
+ size_t skip_format;
bzero(&data, sizeof (data));
data.dtpda_handle = dtp;
@@ -2145,6 +3055,8 @@
epd = data.dtpda_edesc;
data.dtpda_data = buf->dtbd_data + offs;
+ data.dtpda_timestamp = DTRACE_RECORD_LOAD_TIMESTAMP(
+ (struct dtrace_rechdr *)data.dtpda_data);
if (data.dtpda_edesc->dtepd_uarg != DT_ECB_DEFAULT) {
rval = dt_handle(dtp, &data);
@@ -2160,6 +3072,8 @@
(void) dt_flowindent(dtp, &data, dtp->dt_last_epid,
buf, offs);
+ if (dtp->dt_oformat)
+ xo_open_instance("probes");
rval = (*efunc)(&data, arg);
if (flow) {
@@ -2176,11 +3090,17 @@
if (rval != DTRACE_CONSUME_THIS)
return (dt_set_errno(dtp, EDT_BADRVAL));
+ skip_format = 0;
+ if (dtp->dt_oformat)
+ xo_open_list("output");
for (i = 0; i < epd->dtepd_nrecs; i++) {
caddr_t addr;
dtrace_recdesc_t *rec = &epd->dtepd_rec[i];
dtrace_actkind_t act = rec->dtrd_action;
+ if (skip_format > 0)
+ skip_format--;
+
data.dtpda_data = buf->dtbd_data + offs +
rec->dtrd_offset;
addr = data.dtpda_data;
@@ -2301,54 +3221,109 @@
if (rval != DTRACE_CONSUME_THIS)
return (dt_set_errno(dtp, EDT_BADRVAL));
+ if (dtp->dt_oformat && rec->dtrd_size > 0)
+ xo_open_instance("output");
if (act == DTRACEACT_STACK) {
int depth = rec->dtrd_arg;
- if (dt_print_stack(dtp, fp, NULL, addr, depth,
- rec->dtrd_size / depth) < 0)
+ if (dtp->dt_oformat) {
+ if (dt_format_stack(dtp, addr, depth,
+ rec->dtrd_size / depth) < 0) {
+ xo_close_instance("output");
+ return (-1);
+ }
+ } else {
+ if (dt_print_stack(dtp,
+ fp, NULL, addr, depth,
+ rec->dtrd_size / depth) < 0)
return (-1);
+ }
goto nextrec;
}
if (act == DTRACEACT_USTACK ||
act == DTRACEACT_JSTACK) {
- if (dt_print_ustack(dtp, fp, NULL,
- addr, rec->dtrd_arg) < 0)
- return (-1);
+ if (dtp->dt_oformat) {
+ if (dt_format_ustack(dtp, addr,
+ rec->dtrd_arg) < 0) {
+ xo_close_instance("output");
+ return (-1);
+ }
+ } else {
+ if (dt_print_ustack(dtp, fp, NULL,
+ addr, rec->dtrd_arg) < 0)
+ return (-1);
+ }
goto nextrec;
}
if (act == DTRACEACT_SYM) {
- if (dt_print_sym(dtp, fp, NULL, addr) < 0)
- return (-1);
+ if (dtp->dt_oformat) {
+ if (dt_format_sym(dtp, addr) < 0) {
+ xo_close_instance("output");
+ return (-1);
+ }
+ } else {
+ if (dt_print_sym(dtp, fp, NULL, addr) < 0)
+ return (-1);
+ }
goto nextrec;
}
if (act == DTRACEACT_MOD) {
- if (dt_print_mod(dtp, fp, NULL, addr) < 0)
- return (-1);
+ if (dtp->dt_oformat) {
+ if (dt_format_mod(dtp, addr) < 0) {
+ xo_close_instance("output");
+ return (-1);
+ }
+ } else {
+ if (dt_print_mod(dtp, fp, NULL, addr) < 0)
+ return (-1);
+ }
goto nextrec;
}
if (act == DTRACEACT_USYM || act == DTRACEACT_UADDR) {
- if (dt_print_usym(dtp, fp, addr, act) < 0)
- return (-1);
+ if (dtp->dt_oformat) {
+ if (dt_format_usym(dtp, addr, act) < 0) {
+ xo_close_instance("output");
+ return (-1);
+ }
+ } else {
+ if (dt_print_usym(dtp, fp, addr, act) < 0)
+ return (-1);
+ }
goto nextrec;
}
if (act == DTRACEACT_UMOD) {
- if (dt_print_umod(dtp, fp, NULL, addr) < 0)
- return (-1);
+ if (dtp->dt_oformat) {
+ if (dt_format_umod(dtp, addr) < 0) {
+ xo_close_instance("output");
+ return (-1);
+ }
+ } else {
+ if (dt_print_umod(dtp, fp, NULL, addr) < 0)
+ return (-1);
+ }
goto nextrec;
}
if (act == DTRACEACT_PRINTM) {
- if (dt_print_memory(dtp, fp, addr) < 0)
- return (-1);
+ if (dtp->dt_oformat) {
+ if (dt_format_memory(dtp, addr) < 0) {
+ xo_close_instance("output");
+ return (-1);
+ }
+ } else {
+ if (dt_print_memory(dtp, fp, addr) < 0)
+ return (-1);
+ }
goto nextrec;
}
- if (DTRACEACT_ISPRINTFLIKE(act)) {
+ if (dtp->dt_oformat == DTRACE_OFORMAT_TEXT &&
+ DTRACEACT_ISPRINTFLIKE(act)) {
void *fmtdata;
int (*func)(dtrace_hdl_t *, FILE *, void *,
const dtrace_probedata_t *,
@@ -2387,6 +3362,54 @@
goto nextrec;
}
+ /*
+ * We don't care about a formatted printa, system or
+ * freopen for oformat.
+ */
+ if (dtp->dt_oformat && act == DTRACEACT_PRINTF &&
+ skip_format == 0) {
+ void *fmtdata;
+ if ((fmtdata = dt_format_lookup(dtp,
+ rec->dtrd_format)) == NULL)
+ goto nofmt;
+
+ n = dtrace_sprintf(dtp, fp, fmtdata, rec,
+ epd->dtepd_nrecs - i,
+ (uchar_t *)buf->dtbd_data + offs,
+ buf->dtbd_size - offs);
+
+ if (n < 0) {
+ xo_close_instance("output");
+ return (-1); /* errno is set for us */
+ }
+
+ xo_emit("{:message/%s}", dtp->dt_sprintf_buf);
+ skip_format += n;
+
+ /*
+ * We want the "message" object to be its own
+ * thing, but we still want to process the
+ * current DIFEXPR in case there is a value
+ * attached to it. If there is, we need to
+ * re-open a new output instance, as otherwise
+ * the message ends up bundled with the first
+ * value.
+ *
+ * XXX: There is an edge case where a
+ * printf("hello"); will produce a DIFO that
+ * returns 0 attached to it and we have no good
+ * way to determine if this 0 value is because
+ * there's no real data attached to the printf
+ * as an argument, or it's because the argument
+ * actually returns 0.
+ */
+ if (skip_format == 0)
+ goto nextrec;
+
+ xo_close_instance("output");
+ xo_open_instance("output");
+ }
+
/*
* If this is a DIF expression, and the record has a
* format set, this indicates we have a CTF type name
@@ -2397,8 +3420,14 @@
const char *strdata = dt_strdata_lookup(dtp,
rec->dtrd_format);
if (strdata != NULL) {
- n = dtrace_print(dtp, fp, strdata,
- addr, rec->dtrd_size);
+ if (dtp->dt_oformat)
+ n = dtrace_format_print(dtp, fp,
+ strdata, addr,
+ rec->dtrd_size);
+ else
+ n = dtrace_print(dtp, fp,
+ strdata, addr,
+ rec->dtrd_size);
/*
* dtrace_print() will return -1 on
@@ -2408,8 +3437,12 @@
* should fall through to the normal
* trace method.
*/
- if (n < 0)
+ if (n < 0) {
+ if (dtp->dt_oformat)
+ xo_close_instance(
+ "output");
return (-1);
+ }
if (n > 0)
goto nextrec;
@@ -2424,8 +3457,11 @@
size_t size = ((epd->dtepd_nrecs - i) *
sizeof (dtrace_aggvarid_t));
- if ((aggvars = dt_alloc(dtp, size)) == NULL)
+ if ((aggvars = dt_alloc(dtp, size)) == NULL) {
+ if (dtp->dt_oformat)
+ xo_close_instance("output");
return (-1);
+ }
/*
* This might be a printa() with multiple
@@ -2443,6 +3479,9 @@
break;
if (nrec->dtrd_action != act) {
+ if (dtp->dt_oformat)
+ xo_close_instance(
+ "output");
return (dt_set_errno(dtp,
EDT_BADAGG));
}
@@ -2462,24 +3501,50 @@
assert(naggvars >= 1);
+ if (dtp->dt_oformat)
+ xo_open_list("aggregation-data");
if (naggvars == 1) {
pd.dtpa_id = aggvars[0];
dt_free(dtp, aggvars);
- if (dt_printf(dtp, fp, "\n") < 0 ||
- dtrace_aggregate_walk_sorted(dtp,
- dt_print_agg, &pd) < 0)
- return (-1);
+ if (dtp->dt_oformat) {
+ n = dt_oformat_agg_sorted(dtp,
+ dt_format_agg, &pd);
+ if (n < 0)
+ return (-1);
+ } else {
+ if (dt_printf(dtp, fp, "\n") < 0 ||
+ dtrace_aggregate_walk_sorted(dtp,
+ dt_print_agg, &pd) < 0)
+ return (-1);
+ }
+
+ if (dtp->dt_oformat)
+ dt_oformat_agg_name(&pd);
goto nextrec;
}
- if (dt_printf(dtp, fp, "\n") < 0 ||
- dtrace_aggregate_walk_joined(dtp, aggvars,
- naggvars, dt_print_aggs, &pd) < 0) {
- dt_free(dtp, aggvars);
- return (-1);
+ if (dtp->dt_oformat) {
+ if (dtrace_aggregate_walk_joined(dtp,
+ aggvars, naggvars,
+ dt_format_aggs, &pd) < 0) {
+ dt_oformat_agg_name(&pd);
+ xo_close_instance("output");
+ dt_free(dtp, aggvars);
+ return (-1);
+ }
+ } else {
+ if (dt_printf(dtp, fp, "\n") < 0 ||
+ dtrace_aggregate_walk_joined(dtp,
+ aggvars, naggvars,
+ dt_print_aggs, &pd) < 0) {
+ dt_free(dtp, aggvars);
+ return (-1);
+ }
}
+ if (dtp->dt_oformat)
+ dt_oformat_agg_name(&pd);
dt_free(dtp, aggvars);
goto nextrec;
}
@@ -2490,8 +3555,17 @@
tracememsize = rec->dtrd_size;
}
- n = dt_print_bytes(dtp, fp, addr,
- tracememsize, -33, quiet, 1);
+ if (dtp->dt_oformat) {
+ char *s;
+
+ s = dt_format_bytes_get(dtp, addr,
+ tracememsize);
+ n = xo_emit("{:tracemem/%s}", s);
+ dt_free(dtp, s);
+ } else {
+ n = dt_print_bytes(dtp, fp, addr,
+ tracememsize, -33, quiet, 1);
+ }
tracememsize = 0;
@@ -2503,31 +3577,67 @@
switch (rec->dtrd_size) {
case sizeof (uint64_t):
- n = dt_printf(dtp, fp,
- quiet ? "%lld" : " %16lld",
- /* LINTED - alignment */
- *((unsigned long long *)addr));
+ if (dtp->dt_oformat) {
+ xo_emit("{:value/%lld}",
+ *((unsigned long long *)addr));
+ n = 0;
+ } else
+ n = dt_printf(dtp, fp,
+ quiet ? "%lld" : " %16lld",
+ /* LINTED - alignment */
+ *((unsigned long long *)addr));
break;
case sizeof (uint32_t):
- n = dt_printf(dtp, fp, quiet ? "%d" : " %8d",
- /* LINTED - alignment */
- *((uint32_t *)addr));
+ if (dtp->dt_oformat) {
+ xo_emit("{:value/%d}",
+ *((uint32_t *)addr));
+ n = 0;
+ } else
+ n = dt_printf(dtp, fp,
+ quiet ? "%d" : " %8d",
+ /* LINTED - alignment */
+ *((uint32_t *)addr));
break;
case sizeof (uint16_t):
- n = dt_printf(dtp, fp, quiet ? "%d" : " %5d",
- /* LINTED - alignment */
- *((uint16_t *)addr));
+ if (dtp->dt_oformat) {
+ xo_emit("{:value/%d}",
+ *((uint16_t *)addr));
+ n = 0;
+ } else
+ n = dt_printf(dtp, fp,
+ quiet ? "%d" : " %5d",
+ /* LINTED - alignment */
+ *((uint16_t *)addr));
break;
case sizeof (uint8_t):
- n = dt_printf(dtp, fp, quiet ? "%d" : " %3d",
- *((uint8_t *)addr));
+ if (dtp->dt_oformat) {
+ xo_emit("{:value/%d}",
+ *((uint8_t *)addr));
+ n = 0;
+ } else
+ n = dt_printf(dtp, fp,
+ quiet ? "%d" : " %3d",
+ *((uint8_t *)addr));
break;
default:
- n = dt_print_bytes(dtp, fp, addr,
- rec->dtrd_size, -33, quiet, 0);
+ if (dtp->dt_oformat && rec->dtrd_size > 0) {
+ char *s;
+
+ s = dt_format_bytes_get(dtp, addr,
+ rec->dtrd_size);
+ xo_emit("{:value/%s}", s);
+ dt_free(dtp, s);
+ n = 0;
+ } else {
+ n = dt_print_bytes(dtp, fp, addr,
+ rec->dtrd_size, -33, quiet, 0);
+ }
break;
}
+ if (dtp->dt_oformat && rec->dtrd_size > 0)
+ xo_close_instance("output");
+
if (n < 0)
return (-1); /* errno is set for us */
@@ -2544,6 +3654,12 @@
nextepid:
offs += epd->dtepd_size;
dtp->dt_last_epid = id;
+
+ if (dtp->dt_oformat) {
+ xo_close_list("output");
+ xo_close_instance("probes");
+ xo_flush();
+ }
if (just_one) {
buf->dtbd_oldest = offs;
break;
@@ -2562,7 +3678,12 @@
*/
buf->dtbd_drops = 0;
- return (dt_handle_cpudrop(dtp, cpu, DTRACEDROP_PRINCIPAL, drops));
+ xo_open_instance("probes");
+ dt_oformat_drop(dtp, cpu);
+ rval = dt_handle_cpudrop(dtp, cpu, DTRACEDROP_PRINCIPAL, drops);
+ xo_close_instance("probes");
+
+ return (rval);
}
/*
@@ -3065,8 +4186,12 @@
/* Consume drops. */
for (i = 0; i < max_ncpus; i++) {
if (drops[i] != 0) {
- int error = dt_handle_cpudrop(dtp, i,
+ int error;
+ xo_open_instance("probes");
+ dt_oformat_drop(dtp, i);
+ error = dt_handle_cpudrop(dtp, i,
DTRACEDROP_PRINCIPAL, drops[i]);
+ xo_close_instance("probes");
if (error != 0)
return (error);
}
@@ -3082,3 +4207,22 @@
return (0);
}
+
+void
+dtrace_oformat_probe(dtrace_hdl_t *dtp __unused, const dtrace_probedata_t *data,
+ processorid_t cpu, dtrace_probedesc_t *pd)
+{
+
+ xo_emit("{:timestamp/%llu} {:cpu/%d} {:id/%d} {:provider/%s} "
+ "{:module/%s} {:function/%s} {:name/%s}",
+ (unsigned long long)data->dtpda_timestamp, cpu, pd->dtpd_id,
+ pd->dtpd_provider, pd->dtpd_mod, pd->dtpd_func, pd->dtpd_name);
+}
+
+void
+dt_oformat_drop(dtrace_hdl_t *dtp, processorid_t cpu)
+{
+ xo_emit("{:cpu/%d} {:id/%d} {:provider/%s} "
+ "{:module/%s} {:function/%s} {:name/%s}",
+ cpu, -1, "dtrace", "INTERNAL", "INTERNAL", "DROP");
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_handle.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_handle.c
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_handle.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_handle.c
@@ -36,6 +36,7 @@
#endif
#include <dt_impl.h>
+#include <dt_oformat.h>
#include <dt_program.h>
static const char _dt_errprog[] =
@@ -315,6 +316,7 @@
dtrace_dropdata_t drop;
char str[80], *s;
int size;
+ struct timeval tv;
assert(what == DTRACEDROP_PRINCIPAL || what == DTRACEDROP_AGGREGATION);
@@ -339,6 +341,15 @@
what == DTRACEDROP_PRINCIPAL ? "" : "aggregation ",
howmany > 1 ? "s" : "", cpu);
+ if (dtp->dt_oformat) {
+ (void) gettimeofday(&tv, NULL);
+ xo_emit("{:timestamp/%ld.%06ld} {:count/%ju} "
+ "{:total/%ju} {:kind/%d} {:msg/%s}",
+ tv.tv_sec, tv.tv_usec, (uintmax_t)drop.dtdda_drops,
+ (uintmax_t)drop.dtdda_total, drop.dtdda_kind,
+ drop.dtdda_msg);
+ }
+
if (dtp->dt_drophdlr == NULL)
return (dt_set_errno(dtp, EDT_DROPABORT));
@@ -396,6 +407,7 @@
char str[80], *s;
uintptr_t base = (uintptr_t)new, obase = (uintptr_t)old;
int i, size;
+ struct timeval tv;
bzero(&drop, sizeof (drop));
drop.dtdda_handle = dtp;
@@ -408,6 +420,8 @@
if (new->dtst_killed && !old->dtst_killed)
return (dt_set_errno(dtp, EDT_BRICKED));
+ (void) gettimeofday(&tv, NULL);
+
for (i = 0; _dt_droptab[i].dtdrt_str != NULL; i++) {
uintptr_t naddr = base + _dt_droptab[i].dtdrt_offset;
uintptr_t oaddr = obase + _dt_droptab[i].dtdrt_offset;
@@ -438,12 +452,31 @@
drop.dtdda_total = nval;
drop.dtdda_drops = nval - oval;
- if (dtp->dt_drophdlr == NULL)
+ if (dtp->dt_oformat) {
+ xo_open_instance("probes");
+ dt_oformat_drop(dtp, DTRACE_CPUALL);
+ xo_emit("{:timestamp/%ld.%06ld} {:count/%ju} "
+ "{:total/%ju} {:kind/%d} {:msg/%s}",
+ tv.tv_sec, tv.tv_usec, (uintmax_t)drop.dtdda_drops,
+ (uintmax_t)drop.dtdda_total, drop.dtdda_kind,
+ drop.dtdda_msg);
+ }
+
+ if (dtp->dt_drophdlr == NULL) {
+ if (dtp->dt_oformat)
+ xo_close_instance("probes");
return (dt_set_errno(dtp, EDT_DROPABORT));
+ }
if ((*dtp->dt_drophdlr)(&drop,
- dtp->dt_droparg) == DTRACE_HANDLE_ABORT)
+ dtp->dt_droparg) == DTRACE_HANDLE_ABORT) {
+ if (dtp->dt_oformat)
+ xo_close_instance("probes");
return (dt_set_errno(dtp, EDT_DROPABORT));
+ }
+
+ if (dtp->dt_oformat)
+ xo_close_instance("probes");
}
return (0);
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h
@@ -211,6 +211,8 @@
int dtpa_agghist; /* print aggregation as histogram */
int dtpa_agghisthdr; /* aggregation histogram hdr printed */
int dtpa_aggpack; /* pack quantized aggregations */
+ char dtpa_keyname[256]; /* key name for oformat */
+ char *dtpa_aggname; /* aggregate name for oformat */
} dt_print_aggdata_t;
typedef struct dt_dirpath {
@@ -364,6 +366,7 @@
dtrace_epid_t dt_last_epid; /* most recently consumed EPID */
uint64_t dt_last_timestamp; /* most recently consumed timestamp */
boolean_t dt_has_sugar; /* syntactic sugar used? */
+ int dt_oformat; /* output format (none, json, xml, html) */
};
/*
@@ -702,6 +705,8 @@
const void *, size_t, uint64_t);
extern int dt_print_agg(const dtrace_aggdata_t *, void *);
+extern int dt_format_agg(const dtrace_aggdata_t *, void *);
+
extern int dt_handle(dtrace_hdl_t *, dtrace_probedata_t *);
extern int dt_handle_liberr(dtrace_hdl_t *,
const dtrace_probedata_t *, const char *);
@@ -711,6 +716,8 @@
dtrace_status_t *, dtrace_status_t *);
extern int dt_handle_setopt(dtrace_hdl_t *, dtrace_setoptdata_t *);
+extern void dt_oformat_drop(dtrace_hdl_t *, processorid_t);
+
extern int dt_lib_depend_add(dtrace_hdl_t *, dt_list_t *, const char *);
extern dt_lib_depend_t *dt_lib_depend_lookup(dt_list_t *, const char *);
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_oformat.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_oformat.h
new file mode 100644
--- /dev/null
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_oformat.h
@@ -0,0 +1,34 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Domagoj Stolfa
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _DT_OFORMAT_H_
+#define _DT_OFORMAT_H_
+
+#undef NORETURN /* needed because libxo redefines it */
+#include <libxo/xo.h>
+
+#endif /* _DT_OFORMAT_H_ */
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c
@@ -59,6 +59,7 @@
#include <dt_printf.h>
#include <dt_string.h>
#include <dt_provider.h>
+#include <dt_oformat.h>
#ifndef illumos
#include <sys/sysctl.h>
#include <string.h>
@@ -1736,6 +1737,8 @@
free(dtp->dt_kmods);
#endif
free(dtp->dt_provs);
+
+ xo_finish();
free(dtp);
}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_options.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_options.c
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_options.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_options.c
@@ -43,6 +43,7 @@
#include <dt_impl.h>
#include <dt_string.h>
+#include <dt_oformat.h>
static int
dt_opt_agg(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
@@ -723,6 +724,18 @@
return (0);
}
+static int
+dt_opt_oformat(dtrace_hdl_t *dtp, const char *arg, uintptr_t option __unused)
+{
+ if (arg == NULL)
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ if (xo_set_options(NULL, arg) < 0)
+ return (dt_set_errno(dtp, EDT_BADOPTVAL));
+
+ return (dtrace_oformat_configure(dtp));
+}
+
static int
dt_opt_rate(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
{
@@ -1046,6 +1059,7 @@
{ "jstackframes", dt_opt_runtime, DTRACEOPT_JSTACKFRAMES },
{ "jstackstrsize", dt_opt_size, DTRACEOPT_JSTACKSTRSIZE },
{ "nspec", dt_opt_runtime, DTRACEOPT_NSPEC },
+ { "oformat", dt_opt_oformat, 0 },
{ "specsize", dt_opt_size, DTRACEOPT_SPECSIZE },
{ "stackframes", dt_opt_runtime, DTRACEOPT_STACKFRAMES },
{ "statusrate", dt_opt_rate, DTRACEOPT_STATUSRATE },
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_print.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_print.c
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_print.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_print.c
@@ -27,6 +27,7 @@
*/
/*
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2023, Domagoj Stolfa. All rights reserved.
*/
/*
@@ -82,6 +83,7 @@
#include <dt_printf.h>
#include <dt_string.h>
#include <dt_impl.h>
+#include <dt_oformat.h>
/* determines whether the given integer CTF encoding is a character */
#define CTF_IS_CHAR(e) \
@@ -101,8 +103,10 @@
int pa_depth; /* member depth */
int pa_nest; /* nested array depth */
FILE *pa_file; /* output file */
+ const char *pa_object; /* object name */
} dt_printarg_t;
+static int dt_format_member(const char *, ctf_id_t, ulong_t, int, void *);
static int dt_print_member(const char *, ctf_id_t, ulong_t, int, void *);
/*
@@ -189,7 +193,10 @@
value >>= shift;
value &= mask;
- (void) fprintf(fp, "%#llx", (u_longlong_t)value);
+ xo_emit("{:value/%#llx}", (u_longlong_t)value);
+
+ /* Flush in order to ensure output is aligned properly */
+ xo_flush();
}
/*
@@ -200,24 +207,25 @@
{
switch (size) {
case sizeof (uint8_t):
- (void) fprintf(fp, "%#x", *(uint8_t *)addr);
+ xo_emit("{:value/%#x}", *(uint8_t *)addr);
break;
case sizeof (uint16_t):
- /* LINTED - alignment */
- (void) fprintf(fp, "%#x", *(uint16_t *)addr);
+ xo_emit("{:value/%#x}", *(uint16_t *)addr);
break;
case sizeof (uint32_t):
- /* LINTED - alignment */
- (void) fprintf(fp, "%#x", *(uint32_t *)addr);
+ xo_emit("{:value/%#x}", *(uint32_t *)addr);
break;
case sizeof (uint64_t):
- (void) fprintf(fp, "%#llx",
- /* LINTED - alignment */
+ xo_emit("{:value/%#llx}",
(unsigned long long)*(uint64_t *)addr);
break;
default:
- (void) fprintf(fp, "<invalid size %u>", (uint_t)size);
+ xo_emit("<{:warning} {:size/%u}>", "invalid size",
+ (uint_t)size);
}
+
+ /* Flush in order to ensure output is aligned properly */
+ xo_flush();
}
/*
@@ -229,12 +237,16 @@
{
FILE *fp = pap->pa_file;
ctf_file_t *ctfp = pap->pa_ctfp;
+ dtrace_hdl_t *dtp = pap->pa_dtp;
ctf_encoding_t e;
size_t size;
caddr_t addr = pap->pa_addr + off / NBBY;
if (ctf_type_encoding(ctfp, base, &e) == CTF_ERR) {
- (void) fprintf(fp, "<unknown encoding>");
+ xo_emit("<{:warning}>", "unknown encoding");
+
+ /* Flush in order to ensure output is aligned properly */
+ xo_flush();
return;
}
@@ -243,7 +255,8 @@
* would be found.
*/
if (e.cte_format & CTF_INT_VARARGS) {
- (void) fprintf(fp, "...");
+ if (!dtp->dt_oformat)
+ (void)fprintf(fp, "...");
return;
}
@@ -263,11 +276,14 @@
if (CTF_IS_CHAR(e)) {
char c = *(char *)addr;
if (isprint(c))
- (void) fprintf(fp, "'%c'", c);
+ xo_emit("'{:value/%c}'", c);
else if (c == 0)
- (void) fprintf(fp, "'\\0'");
+ xo_emit("'\\{:value/0}'");
else
- (void) fprintf(fp, "'\\%03o'", c);
+ xo_emit("'\\{:value/%03o}'", c);
+
+ /* Flush in order to ensure output is aligned properly */
+ xo_flush();
return;
}
@@ -285,22 +301,20 @@
ctf_file_t *ctfp = pap->pa_ctfp;
ctf_encoding_t e;
caddr_t addr = pap->pa_addr + off / NBBY;
+ dtrace_hdl_t *dtp = pap->pa_dtp;
if (ctf_type_encoding(ctfp, base, &e) == 0) {
if (e.cte_format == CTF_FP_SINGLE &&
e.cte_bits == sizeof (float) * NBBY) {
- /* LINTED - alignment */
- (void) fprintf(fp, "%+.7e", *((float *)addr));
+ xo_emit("{:value/%+.7e}", *((float *)addr));
} else if (e.cte_format == CTF_FP_DOUBLE &&
e.cte_bits == sizeof (double) * NBBY) {
- /* LINTED - alignment */
- (void) fprintf(fp, "%+.7e", *((double *)addr));
+ xo_emit("{:value/%+.7e}", *((double *)addr));
} else if (e.cte_format == CTF_FP_LDOUBLE &&
e.cte_bits == sizeof (long double) * NBBY) {
- /* LINTED - alignment */
- (void) fprintf(fp, "%+.16LE", *((long double *)addr));
+ xo_emit("{:value/%+.16LE}", *((long double *)addr));
} else {
- (void) fprintf(fp, "<unknown encoding>");
+ xo_emit("<{:warning}>", "unknown encoding");
}
}
}
@@ -329,8 +343,7 @@
if (dtrace_lookup_by_addr(pap->pa_dtp, pc, &sym, &dts) != 0) {
dt_print_hex(fp, addr, size);
} else {
- (void) fprintf(fp, "%s`%s", dts.dts_object,
- dts.dts_name);
+ xo_emit("{:value/%s`%s}", dts.dts_object, dts.dts_name);
}
}
}
@@ -367,6 +380,7 @@
FILE *fp = pap->pa_file;
ctf_file_t *ctfp = pap->pa_ctfp;
caddr_t addr = pap->pa_addr + off / NBBY;
+ char *str;
ctf_arinfo_t car;
ssize_t eltsize;
ctf_encoding_t e;
@@ -374,16 +388,18 @@
boolean_t isstring;
int kind;
ctf_id_t rtype;
+ dtrace_hdl_t *dtp = pap->pa_dtp;
if (ctf_array_info(ctfp, base, &car) == CTF_ERR) {
- (void) fprintf(fp, "%p", (void *)addr);
+ xo_emit("{:value/%p}", (void *)addr);
return;
}
if ((eltsize = ctf_type_size(ctfp, car.ctr_contents)) < 0 ||
(rtype = ctf_type_resolve(ctfp, car.ctr_contents)) == CTF_ERR ||
(kind = ctf_type_kind(ctfp, rtype)) == CTF_ERR) {
- (void) fprintf(fp, "<invalid type %lu>", car.ctr_contents);
+ xo_emit("<{:warning} {:type-identifier/%lu}>", "invalid type",
+ car.ctr_contents);
return;
}
@@ -411,18 +427,44 @@
*
* As D will internally represent this as a char[256] array.
*/
- if (!isstring || pap->pa_depth != 0)
- (void) fprintf(fp, "[ ");
+ if (dtp->dt_oformat) {
+ if (!isstring)
+ xo_open_list("value");
+ else {
+ str = malloc(car.ctr_nelems);
+ if (str == NULL)
+ return;
+ *str = 0;
+ }
+ } else {
+ if (!isstring || pap->pa_depth != 0)
+ (void)fprintf(fp, "[ ");
- if (isstring)
- (void) fprintf(fp, "\"");
+ if (isstring)
+ (void)fprintf(fp, "\"");
+ }
for (i = 0; i < car.ctr_nelems; i++) {
if (isstring) {
char c = *((char *)addr + eltsize * i);
- if (c == '\0')
+ if (c == '\0') {
+ if (dtp->dt_oformat)
+ str[i] = 0;
break;
- (void) fprintf(fp, "%c", c);
+ }
+
+ if (dtp->dt_oformat)
+ str[i] = c;
+ else
+ (void)fprintf(fp, "%c", c);
+ } else if (dtp->dt_oformat) {
+ dt_printarg_t pa = *pap;
+ pa.pa_nest += pap->pa_depth + 1;
+ pa.pa_depth = 0;
+ pa.pa_addr = addr + eltsize * i;
+
+ (void) ctf_type_visit(ctfp, car.ctr_contents,
+ dt_format_member, &pa);
} else {
/*
* Recursively invoke ctf_type_visit() on each member.
@@ -444,15 +486,24 @@
}
}
- if (isstring)
- (void) fprintf(fp, "\"");
-
- if (!isstring || pap->pa_depth != 0) {
- if (CTF_IS_STRUCTLIKE(kind))
- dt_print_indent(pap);
- else
- (void) fprintf(fp, " ");
- (void) fprintf(fp, "]");
+ if (dtp->dt_oformat) {
+ if (!isstring)
+ xo_close_list("value");
+ else {
+ xo_emit("{:value/%s}", str);
+ free(str);
+ }
+ } else {
+ if (isstring)
+ (void)fprintf(fp, "\"");
+
+ if (!isstring || pap->pa_depth != 0) {
+ if (CTF_IS_STRUCTLIKE(kind))
+ dt_print_indent(pap);
+ else
+ (void)fprintf(fp, " ");
+ (void)fprintf(fp, "]");
+ }
}
}
@@ -463,7 +514,8 @@
static void
dt_print_structlike(ctf_id_t id, ulong_t off, dt_printarg_t *pap)
{
- (void) fprintf(pap->pa_file, "{");
+ if (pap->pa_dtp->dt_oformat == DTRACE_OFORMAT_TEXT)
+ (void)fprintf(pap->pa_file, "{");
}
/*
@@ -480,6 +532,7 @@
ssize_t size;
caddr_t addr = pap->pa_addr + off / NBBY;
int value = 0;
+ dtrace_hdl_t *dtp = pap->pa_dtp;
/*
* The C standard says that an enum will be at most the sizeof (int).
@@ -498,14 +551,19 @@
value = *(int32_t *)addr;
break;
default:
- (void) fprintf(fp, "<invalid enum size %u>", (uint_t)size);
+ xo_emit("<{:warning} {:size/%u}>", "invalid enum size",
+ (uint_t)size);
return;
}
- if ((ename = ctf_enum_name(ctfp, base, value)) != NULL)
- (void) fprintf(fp, "%s", ename);
- else
- (void) fprintf(fp, "%d", value);
+ if ((ename = ctf_enum_name(ctfp, base, value)) != NULL) {
+ xo_emit("{:value/%s}", ename);
+ } else {
+ xo_emit("{:value/%d}", value);
+ }
+
+ /* Flush in order to ensure output is aligned properly */
+ xo_flush();
}
/*
@@ -516,7 +574,8 @@
static void
dt_print_tag(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
{
- (void) fprintf(pap->pa_file, "<forward decl>");
+ if (pap->pa_dtp->dt_oformat == DTRACE_OFORMAT_TEXT)
+ (void)fprintf(pap->pa_file, "<forward decl>");
}
typedef void dt_printarg_f(ctf_id_t, ulong_t, dt_printarg_t *);
@@ -533,6 +592,46 @@
dt_print_tag /* CTF_K_FORWARD */
};
+static int
+dt_format_member(const char *name, ctf_id_t id, ulong_t off, int depth,
+ void *data)
+{
+ char type[DT_TYPE_NAMELEN];
+ int kind;
+ dt_printarg_t *pap = data;
+ FILE *fp = pap->pa_file;
+ ctf_file_t *ctfp = pap->pa_ctfp;
+ boolean_t arraymember;
+ boolean_t brief;
+ ctf_encoding_t e;
+ ctf_id_t rtype;
+
+ if ((rtype = ctf_type_resolve(ctfp, id)) == CTF_ERR ||
+ (kind = ctf_type_kind(ctfp, rtype)) == CTF_ERR ||
+ kind < CTF_K_INTEGER || kind > CTF_K_FORWARD) {
+ xo_emit("{:name/%s} <{:warning} {:type-identifier/%lu}>"
+ " {:value/0x%llx}",
+ name, "invalid type", id, pap->pa_addr);
+ return (0);
+ }
+
+ dt_print_type_name(ctfp, id, type, sizeof (type));
+ xo_open_instance("type");
+ if (pap->pa_object) {
+ xo_emit("{:object-name/%s}", pap->pa_object);
+ /* Clear the object to avoid duplication */
+ pap->pa_object = NULL;
+ }
+
+ if (*name != 0)
+ xo_emit("{:member-name/%s}", name);
+ xo_emit("{:name/%s} {:ctfid/%ld}", type, id);
+ dt_printfuncs[kind - 1](rtype, off, pap);
+
+ xo_close_instance("type");
+ return (0);
+}
+
/*
* Print one member of a structure. This callback is invoked from
* ctf_type_visit() recursively.
@@ -634,16 +733,12 @@
return (0);
}
-/*
- * Main print function invoked by dt_consume_cpu().
- */
-int
-dtrace_print(dtrace_hdl_t *dtp, FILE *fp, const char *typename,
- caddr_t addr, size_t len)
+static ctf_id_t
+dt_print_prepare(dtrace_hdl_t *dtp, const char *typename, caddr_t addr,
+ size_t len, dt_printarg_t *pa)
{
const char *s;
char *object;
- dt_printarg_t pa;
ctf_id_t id;
dt_module_t *dmp;
ctf_file_t *ctfp;
@@ -661,20 +756,20 @@
;
if (*s != '`')
- return (0);
+ return (CTF_ERR);
object = alloca(s - typename + 1);
bcopy(typename, object, s - typename);
object[s - typename] = '\0';
dmp = dt_module_lookup_by_name(dtp, object);
if (dmp == NULL)
- return (0);
+ return (CTF_ERR);
if (dmp->dm_pid != 0) {
libid = atoi(s + 1);
s = strchr(s + 1, '`');
if (s == NULL || libid > dmp->dm_nctflibs)
- return (0);
+ return (CTF_ERR);
ctfp = dmp->dm_libctfp[libid];
} else {
ctfp = dt_module_getctf(dtp, dmp);
@@ -688,18 +783,63 @@
* work.
*/
if (ctfp == NULL || ctf_type_kind(ctfp, id) == CTF_ERR)
+ return (CTF_ERR);
+
+ pa->pa_dtp = dtp;
+ pa->pa_addr = addr;
+ pa->pa_ctfp = ctfp;
+ pa->pa_nest = 0;
+ pa->pa_depth = 0;
+ pa->pa_object = strdup(object);
+ return (id);
+}
+
+/*
+ * Main print function invoked by dt_consume_cpu().
+ */
+int
+dtrace_print(dtrace_hdl_t *dtp, FILE *fp, const char *typename,
+ caddr_t addr, size_t len)
+{
+ dt_printarg_t pa;
+ ctf_id_t id;
+
+ id = dt_print_prepare(dtp, typename, addr, len, &pa);
+ if (id == CTF_ERR)
return (0);
- /* setup the print structure and kick off the main print routine */
- pa.pa_dtp = dtp;
- pa.pa_addr = addr;
- pa.pa_ctfp = ctfp;
- pa.pa_nest = 0;
- pa.pa_depth = 0;
pa.pa_file = fp;
(void) ctf_type_visit(pa.pa_ctfp, id, dt_print_member, &pa);
dt_print_trailing_braces(&pa, 0);
+ dt_free(dtp, (void *)pa.pa_object);
+
+ return (len);
+}
+
+/*
+ * Main format function invoked by dt_consume_cpu().
+ */
+int
+dtrace_format_print(dtrace_hdl_t *dtp, FILE *fp, const char *typename,
+ caddr_t addr, size_t len)
+{
+ dt_printarg_t pa;
+ ctf_id_t id;
+ char toplevel[1024];
+
+ id = dt_print_prepare(dtp, typename, addr, len, &pa);
+ if (id == CTF_ERR)
+ return (0);
+
+ if (ctf_type_name(pa.pa_ctfp, id, toplevel, sizeof(toplevel)) < 0)
+ return (0);
+
+ xo_open_list("type");
+ (void) ctf_type_visit(pa.pa_ctfp, id, dt_format_member, &pa);
+ xo_close_list("type");
+ dt_free(dtp, (void *)pa.pa_object);
return (len);
}
+
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_printf.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_printf.h
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_printf.h
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_printf.h
@@ -21,6 +21,7 @@
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2023 Domagoj Stolfa. All rights reserved.
* Use is subject to license terms.
*/
@@ -128,6 +129,11 @@
extern int dt_print_mod(dtrace_hdl_t *, FILE *, const char *, caddr_t);
extern int dt_print_umod(dtrace_hdl_t *, FILE *, const char *, caddr_t);
+extern int dt_format_stack(dtrace_hdl_t *, caddr_t, int, int);
+extern int dt_format_ustack(dtrace_hdl_t *, caddr_t, uint64_t);
+extern int dt_format_mod(dtrace_hdl_t *, caddr_t);
+extern int dt_format_umod(dtrace_hdl_t *, caddr_t);
+
#ifdef __cplusplus
}
#endif
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_subr.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_subr.c
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_subr.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_subr.c
@@ -50,6 +50,7 @@
#include <stdint.h>
#include <dt_impl.h>
+#include <dt_oformat.h>
static const struct {
size_t dtps_offset;
@@ -992,3 +993,44 @@
return (dt_string2str(c, str, nbytes));
}
+
+int
+dtrace_oformat_configure(dtrace_hdl_t *dtp)
+{
+
+ dtp->dt_oformat = xo_get_style(NULL) == XO_STYLE_TEXT ?
+ DTRACE_OFORMAT_TEXT :
+ DTRACE_OFORMAT_STRUCTURED;
+ xo_set_flags(NULL, XOF_DTRT);
+ return (0);
+}
+
+int
+dtrace_oformat(dtrace_hdl_t *dtp)
+{
+
+ return (dtp->dt_oformat != DTRACE_OFORMAT_TEXT);
+}
+
+void
+dtrace_set_outfp(const FILE *ofp)
+{
+
+ xo_set_file((FILE *)ofp);
+}
+
+void
+dtrace_oformat_setup(dtrace_hdl_t *dtp)
+{
+
+ xo_open_container("dtrace");
+ xo_open_list("probes");
+}
+
+void
+dtrace_oformat_teardown(dtrace_hdl_t *dtp)
+{
+
+ xo_close_list("probes");
+ xo_close_container("dtrace");
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dtrace.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dtrace.h
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dtrace.h
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dtrace.h
@@ -25,6 +25,7 @@
*/
/*
+ * Copyright (c) 2023 by Domagoj Stolfa. All rights reserved.
* Copyright (c) 2014, 2016 by Delphix. All rights reserved.
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
*/
@@ -200,6 +201,7 @@
dtrace_flowkind_t dtpda_flow; /* flow kind */
const char *dtpda_prefix; /* recommended flow prefix */
int dtpda_indent; /* recommended flow indent */
+ uint64_t dtpda_timestamp; /* hrtime of snapshot */
} dtrace_probedata_t;
typedef int dtrace_consume_probe_f(const dtrace_probedata_t *, void *);
@@ -233,6 +235,10 @@
extern void *dtrace_printa_create(dtrace_hdl_t *, const char *);
extern size_t dtrace_printf_format(dtrace_hdl_t *, void *, char *, size_t);
+extern int dtrace_sprintf(dtrace_hdl_t *, FILE *, void *,
+ const dtrace_recdesc_t *, uint_t,
+ const void *, size_t);
+
extern int dtrace_fprintf(dtrace_hdl_t *, FILE *, void *,
const dtrace_probedata_t *, const dtrace_recdesc_t *, uint_t,
const void *, size_t);
@@ -260,6 +266,8 @@
*/
extern int dtrace_print(dtrace_hdl_t *, FILE *, const char *,
caddr_t, size_t);
+extern int dtrace_format_print(dtrace_hdl_t *, FILE *, const char *,
+ caddr_t, size_t);
/*
* DTrace Work Interface
@@ -616,4 +624,18 @@
#define _SC_NPROCESSORS_MAX _SC_NPROCESSORS_CONF
#endif
+/*
+ * Values for the dt_oformat property.
+ */
+#define DTRACE_OFORMAT_TEXT 0
+#define DTRACE_OFORMAT_STRUCTURED 1
+
+extern int dtrace_oformat_configure(dtrace_hdl_t *);
+extern int dtrace_oformat(dtrace_hdl_t *);
+extern void dtrace_set_outfp(const FILE *);
+extern void dtrace_oformat_setup(dtrace_hdl_t *);
+extern void dtrace_oformat_teardown(dtrace_hdl_t *);
+extern void dtrace_oformat_probe(dtrace_hdl_t *, const dtrace_probedata_t *,
+ processorid_t, dtrace_probedesc_t *);
+
#endif /* _DTRACE_H */
diff --git a/cddl/lib/libdtrace/Makefile b/cddl/lib/libdtrace/Makefile
--- a/cddl/lib/libdtrace/Makefile
+++ b/cddl/lib/libdtrace/Makefile
@@ -147,7 +147,7 @@
LDFLAGS+= -fsanitize=address -fsanitize=undefined
.endif
-LIBADD= ctf elf proc pthread rtld_db
+LIBADD= ctf elf proc pthread rtld_db xo
CLEANFILES= dt_errtags.c dt_names.c
diff --git a/cddl/usr.sbin/dtrace/Makefile b/cddl/usr.sbin/dtrace/Makefile
--- a/cddl/usr.sbin/dtrace/Makefile
+++ b/cddl/usr.sbin/dtrace/Makefile
@@ -34,7 +34,7 @@
LDFLAGS+= -fsanitize=address -fsanitize=undefined
.endif
-LIBADD= dtrace ctf elf proc spl
+LIBADD= dtrace ctf elf proc spl xo
.if ${MK_DTRACE_TESTS} != "no"
SUBDIR+= tests
diff --git a/cddl/usr.sbin/dtrace/tests/common/Makefile b/cddl/usr.sbin/dtrace/tests/common/Makefile
--- a/cddl/usr.sbin/dtrace/tests/common/Makefile
+++ b/cddl/usr.sbin/dtrace/tests/common/Makefile
@@ -39,6 +39,7 @@
misc \
multiaggs \
offsetof \
+ oformat \
operators \
pid \
plockstat \
diff --git a/cddl/usr.sbin/dtrace/tests/common/oformat/Makefile b/cddl/usr.sbin/dtrace/tests/common/oformat/Makefile
new file mode 100644
--- /dev/null
+++ b/cddl/usr.sbin/dtrace/tests/common/oformat/Makefile
@@ -0,0 +1,42 @@
+#
+# This Makefile was generated by $srcdir/cddl/usr.sbin/dtrace/tests/tools/genmakefiles.sh.
+#
+
+PACKAGE= tests
+
+${PACKAGE}FILES= \
+ tst.agg.avg.ksh \
+ tst.agg.count.ksh \
+ tst.agg.llquantize.ksh \
+ tst.agg.lquantize.ksh \
+ tst.agg.max.ksh \
+ tst.agg.min.ksh \
+ tst.agg.quantize.ksh \
+ tst.agg.stddev.ksh \
+ tst.agg.sum.ksh \
+ tst.aggmod.ksh \
+ tst.aggstack.ksh \
+ tst.aggsym.ksh \
+ tst.aggustack.ksh \
+ tst.aggusym.ksh \
+ tst.drop.ksh \
+ tst.mod.ksh \
+ tst.print.ksh \
+ tst.printf.ksh \
+ tst.printm.ksh \
+ tst.stack.ksh \
+ tst.sym.ksh \
+ tst.trace.ksh \
+ tst.tracemem.ksh \
+ tst.umod.ksh \
+ tst.ustack.ksh \
+ tst.usym.ksh \
+
+TESTEXES= \
+
+
+CFILES= \
+
+
+
+.include "../../dtrace.test.mk"
diff --git a/cddl/usr.sbin/dtrace/tests/dtrace.test.mk b/cddl/usr.sbin/dtrace/tests/dtrace.test.mk
--- a/cddl/usr.sbin/dtrace/tests/dtrace.test.mk
+++ b/cddl/usr.sbin/dtrace/tests/dtrace.test.mk
@@ -12,7 +12,7 @@
TESTWRAPPER= t_dtrace_contrib
ATF_TESTS_SH+= ${TESTWRAPPER}
-TEST_METADATA.t_dtrace_contrib+= required_files="/usr/local/bin/ksh"
+TEST_METADATA.t_dtrace_contrib+= required_files="/usr/local/bin/ksh /usr/local/bin/jq /usr/local/bin/xmllint"
TEST_METADATA.t_dtrace_contrib+= required_user="root"
GENTEST?= ${.CURDIR:H:H}/tools/gentest.sh
diff --git a/etc/mtree/BSD.tests.dist b/etc/mtree/BSD.tests.dist
--- a/etc/mtree/BSD.tests.dist
+++ b/etc/mtree/BSD.tests.dist
@@ -162,6 +162,8 @@
..
offsetof
..
+ oformat
+ ..
operators
..
pid
diff --git a/share/mk/src.libnames.mk b/share/mk/src.libnames.mk
--- a/share/mk/src.libnames.mk
+++ b/share/mk/src.libnames.mk
@@ -387,7 +387,7 @@
_DP_vmmapi= util
_DP_opencsd= cxxrt
_DP_ctf= spl z
-_DP_dtrace= ctf elf proc pthread rtld_db
+_DP_dtrace= ctf elf proc pthread rtld_db xo
_DP_xo= util
_DP_ztest= geom m nvpair umem zpool pthread avl zfs_core spl zutil zfs uutil icp
# The libc dependencies are not strictly needed but are defined to make the
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Jan 27, 12:37 PM (4 h, 16 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16196488
Default Alt Text
D41745.diff (131 KB)
Attached To
Mode
D41745: dtrace: Add the 'oformat' libdtrace option.
Attached
Detach File
Event Timeline
Log In to Comment