[DTrace-devel] [PATCH 06/15 v2] First implementation of the printf action

Kris Van Hees kris.van.hees at oracle.com
Fri May 29 10:59:31 PDT 2020


The legacy implementation was a close interaction between the userspace
and kernel components of DTrace.  Now that everything is in userspace
significant portions of the printf-style actions are updated.

Format strings used to be converted into a data structure that describes
the format and its conversions.  This representation was used during the
compilation of clauses to validate arguments.  Then, the string was
passed to the kernel component of DTrace, to be retrieved when buffer
processing needed to format data.  It would request the format string
based on a numeric id, and then process the returned string into a data
structure (almsot identical to the one used during compilation).

In the new version, we can simply convert the format string into the
final data structure and store that in dtrace_recdesc_t.  A reference
to the data structure (dt_pfargv_t *) is passed to dt_cg_store_val()
which in turn passes it to dt_rec_add() as format.  This ensures that
when output records are processed, we know that there data items belong
to a printf-style action.

A bug existed in the error reporting for multiple '*' specifiers in
the field width.  It mistakenly reported it as "more than one '*'
specified for the output precision" whereas it should refer to the
"output width".

Note that only numeric data is supported at this point due to fact that
string support is still missing in DTrace v2.

A series of unittests are included in test/unittest/actions/printf to
ensure the correct operation of the printf-style actions.

Orabug: 31236012
Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
---
 include/dtrace/metadesc.h                     |  2 +-
 libdtrace/dt_cg.c                             | 73 +++++++++++++++++--
 libdtrace/dt_consume.c                        | 15 ++++
 libdtrace/dt_impl.h                           |  3 +-
 libdtrace/dt_map.c                            |  4 +-
 libdtrace/dt_printf.c                         |  9 ++-
 .../actions/printf/err.D_PRINTF_AGG_CONV.d    | 21 ++++++
 .../actions/printf/err.D_PRINTF_AGG_CONV.r    |  2 +
 .../err.D_PRINTF_ARG_EXTRA.addr_width.d       | 22 ++++++
 .../err.D_PRINTF_ARG_EXTRA.addr_width.r       |  2 +
 .../err.D_PRINTF_ARG_EXTRA.too_many_vals.d    | 20 +++++
 .../err.D_PRINTF_ARG_EXTRA.too_many_vals.r    |  2 +
 .../actions/printf/err.D_PRINTF_ARG_FMT.d     | 20 +++++
 .../actions/printf/err.D_PRINTF_ARG_FMT.r     |  4 +
 .../err.D_PRINTF_ARG_PROTO.missing_val.d      | 20 +++++
 .../err.D_PRINTF_ARG_PROTO.missing_val.r      |  2 +
 .../printf/err.D_PRINTF_ARG_PROTO.prec.d      | 20 +++++
 .../printf/err.D_PRINTF_ARG_PROTO.prec.r      |  2 +
 .../err.D_PRINTF_ARG_PROTO.too_few_vals.d     | 20 +++++
 .../err.D_PRINTF_ARG_PROTO.too_few_vals.r     |  2 +
 .../err.D_PRINTF_ARG_PROTO.width-prec.d       | 20 +++++
 .../err.D_PRINTF_ARG_PROTO.width-prec.r       |  2 +
 .../printf/err.D_PRINTF_ARG_PROTO.width.d     | 20 +++++
 .../printf/err.D_PRINTF_ARG_PROTO.width.r     |  2 +
 .../printf/err.D_PRINTF_ARG_TYPE.agg.d        | 22 ++++++
 .../printf/err.D_PRINTF_ARG_TYPE.agg.r        |  5 ++
 .../printf/err.D_PRINTF_ARG_TYPE.mismatch.d   | 20 +++++
 .../printf/err.D_PRINTF_ARG_TYPE.mismatch.r   |  5 ++
 .../printf/err.D_PRINTF_ARG_TYPE.void.d       | 20 +++++
 .../printf/err.D_PRINTF_ARG_TYPE.void.r       |  5 ++
 .../printf/err.D_PRINTF_ARG_TYPE.width-prec.d | 20 +++++
 .../printf/err.D_PRINTF_ARG_TYPE.width-prec.r |  5 ++
 .../err.D_PRINTF_DYN_PROTO.missing_prec-2.d   | 21 ++++++
 .../err.D_PRINTF_DYN_PROTO.missing_prec-2.r   |  2 +
 .../err.D_PRINTF_DYN_PROTO.missing_prec.d     | 21 ++++++
 .../err.D_PRINTF_DYN_PROTO.missing_prec.r     |  2 +
 .../err.D_PRINTF_DYN_PROTO.missing_width-2.d  | 21 ++++++
 .../err.D_PRINTF_DYN_PROTO.missing_width-2.r  |  2 +
 .../err.D_PRINTF_DYN_PROTO.missing_width.d    | 21 ++++++
 .../err.D_PRINTF_DYN_PROTO.missing_width.r    |  2 +
 .../printf/err.D_PRINTF_DYN_TYPE.prec.d       | 21 ++++++
 .../printf/err.D_PRINTF_DYN_TYPE.prec.r       |  5 ++
 .../printf/err.D_PRINTF_DYN_TYPE.width-prec.d | 21 ++++++
 .../printf/err.D_PRINTF_DYN_TYPE.width-prec.r |  5 ++
 .../printf/err.D_PRINTF_DYN_TYPE.width.d      | 21 ++++++
 .../printf/err.D_PRINTF_DYN_TYPE.width.r      |  5 ++
 .../actions/printf/err.D_PRINTF_FMT_EMPTY.d   | 20 +++++
 .../actions/printf/err.D_PRINTF_FMT_EMPTY.r   |  2 +
 .../unittest/actions/printf/err.D_PROTO_ARG.d | 20 +++++
 .../unittest/actions/printf/err.D_PROTO_ARG.r |  4 +
 .../unittest/actions/printf/err.D_PROTO_LEN.d | 20 +++++
 .../unittest/actions/printf/err.D_PROTO_LEN.r |  2 +
 .../actions/printf/err.D_SYNTAX.double_prec.d | 20 +++++
 .../actions/printf/err.D_SYNTAX.double_prec.r |  2 +
 .../printf/err.D_SYNTAX.double_width.d        | 20 +++++
 .../printf/err.D_SYNTAX.double_width.r        |  2 +
 .../printf/err.D_SYNTAX.explicit_arg-2.d      | 21 ++++++
 .../printf/err.D_SYNTAX.explicit_arg-2.r      |  2 +
 .../printf/err.D_SYNTAX.explicit_arg-3.d      | 21 ++++++
 .../printf/err.D_SYNTAX.explicit_arg-3.r      |  2 +
 .../printf/err.D_SYNTAX.explicit_arg.d        | 21 ++++++
 .../printf/err.D_SYNTAX.explicit_arg.r        |  2 +
 .../printf/err.D_SYNTAX.missing_fmt-2.d       | 21 ++++++
 .../printf/err.D_SYNTAX.missing_fmt-2.r       |  2 +
 .../printf/err.D_SYNTAX.missing_fmt-3.d       | 21 ++++++
 .../printf/err.D_SYNTAX.missing_fmt-3.r       |  2 +
 .../actions/printf/err.D_SYNTAX.missing_fmt.d | 21 ++++++
 .../actions/printf/err.D_SYNTAX.missing_fmt.r |  2 +
 .../actions/printf/err.D_SYNTAX.pct_flags.d   | 21 ++++++
 .../actions/printf/err.D_SYNTAX.pct_flags.r   |  2 +
 .../actions/printf/err.D_SYNTAX.prec-width.d  | 20 +++++
 .../actions/printf/err.D_SYNTAX.prec-width.r  |  2 +
 .../printf/err.D_SYNTAX.unknown_conv.d        | 21 ++++++
 .../printf/err.D_SYNTAX.unknown_conv.r        |  2 +
 test/unittest/actions/printf/tst.conv_A.d     | 21 ++++++
 .../actions/printf/tst.conv_E_double.d        | 22 ++++++
 .../actions/printf/tst.conv_E_double.r        |  1 +
 .../actions/printf/tst.conv_E_float.d         | 22 ++++++
 .../actions/printf/tst.conv_E_float.r         |  1 +
 .../actions/printf/tst.conv_G_double.d        | 22 ++++++
 .../actions/printf/tst.conv_G_double.r        |  1 +
 .../actions/printf/tst.conv_G_float.d         | 22 ++++++
 .../actions/printf/tst.conv_G_float.r         |  1 +
 .../printf/tst.conv_T.r}                      |  0
 .../printf/tst.conv_T.sh}                     |  1 -
 .../printf/tst.conv_Y.r}                      |  0
 .../printf/tst.conv_Y.sh}                     |  1 -
 test/unittest/actions/printf/tst.conv_a.d     | 20 +++++
 test/unittest/actions/printf/tst.conv_a.r     |  1 +
 test/unittest/actions/printf/tst.conv_c.d     | 20 +++++
 .../actions/printf/tst.conv_d_signed.d        | 20 +++++
 .../actions/printf/tst.conv_d_unsigned.d      | 20 +++++
 .../actions/printf/tst.conv_e_double.d        | 22 ++++++
 .../actions/printf/tst.conv_e_double.r        |  1 +
 .../actions/printf/tst.conv_e_float.d         | 22 ++++++
 .../actions/printf/tst.conv_e_float.r         |  1 +
 .../actions/printf/tst.conv_f_double.d        | 22 ++++++
 .../actions/printf/tst.conv_f_double.r        |  1 +
 .../actions/printf/tst.conv_f_float.d         | 22 ++++++
 .../actions/printf/tst.conv_f_float.r         |  1 +
 .../actions/printf/tst.conv_g_double.d        | 22 ++++++
 .../actions/printf/tst.conv_g_double.r        |  1 +
 .../actions/printf/tst.conv_g_float.d         | 22 ++++++
 .../actions/printf/tst.conv_g_float.r         |  1 +
 .../printf/err.D_PRINTF_AGG_CONV.aggfmt.d     |  1 -
 .../printf/err.D_PRINTF_ARG_EXTRA.toomany.d   |  1 -
 .../printf/err.D_PRINTF_ARG_EXTRA.widths.d    |  1 -
 .../printf/err.D_PRINTF_ARG_PROTO.novalue.d   |  1 -
 .../printf/err.D_PRINTF_ARG_TYPE.recursive.d  |  1 -
 .../printf/err.D_PRINTF_DYN_PROTO.noprec.d    |  1 -
 .../printf/err.D_PRINTF_DYN_PROTO.nowidth.d   |  1 -
 .../printf/err.D_PRINTF_DYN_TYPE.badprec.d    |  1 -
 .../printf/err.D_PRINTF_DYN_TYPE.badwidth.d   |  1 -
 test/unittest/printf/err.D_SYNTAX.badconv1.d  |  1 -
 test/unittest/printf/err.D_SYNTAX.badconv2.d  |  1 -
 test/unittest/printf/err.D_SYNTAX.badconv3.d  |  1 -
 test/unittest/printf/tst.print-f.d            | 31 --------
 test/unittest/printf/tst.print-f.r            |  4 -
 test/unittest/printf/tst.printeE.d            | 34 ---------
 test/unittest/printf/tst.printeE.r            |  6 --
 test/unittest/printf/tst.printgG.d            | 34 ---------
 test/unittest/printf/tst.printgG.r            |  6 --
 122 files changed, 1218 insertions(+), 142 deletions(-)
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_AGG_CONV.d
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_AGG_CONV.r
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_ARG_EXTRA.addr_width.d
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_ARG_EXTRA.addr_width.r
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_ARG_EXTRA.too_many_vals.d
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_ARG_EXTRA.too_many_vals.r
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_ARG_FMT.d
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_ARG_FMT.r
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.missing_val.d
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.missing_val.r
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.prec.d
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.prec.r
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.too_few_vals.d
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.too_few_vals.r
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.width-prec.d
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.width-prec.r
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.width.d
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.width.r
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_ARG_TYPE.agg.d
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_ARG_TYPE.agg.r
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_ARG_TYPE.mismatch.d
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_ARG_TYPE.mismatch.r
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_ARG_TYPE.void.d
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_ARG_TYPE.void.r
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_ARG_TYPE.width-prec.d
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_ARG_TYPE.width-prec.r
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_DYN_PROTO.missing_prec-2.d
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_DYN_PROTO.missing_prec-2.r
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_DYN_PROTO.missing_prec.d
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_DYN_PROTO.missing_prec.r
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_DYN_PROTO.missing_width-2.d
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_DYN_PROTO.missing_width-2.r
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_DYN_PROTO.missing_width.d
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_DYN_PROTO.missing_width.r
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_DYN_TYPE.prec.d
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_DYN_TYPE.prec.r
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_DYN_TYPE.width-prec.d
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_DYN_TYPE.width-prec.r
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_DYN_TYPE.width.d
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_DYN_TYPE.width.r
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_FMT_EMPTY.d
 create mode 100644 test/unittest/actions/printf/err.D_PRINTF_FMT_EMPTY.r
 create mode 100644 test/unittest/actions/printf/err.D_PROTO_ARG.d
 create mode 100644 test/unittest/actions/printf/err.D_PROTO_ARG.r
 create mode 100644 test/unittest/actions/printf/err.D_PROTO_LEN.d
 create mode 100644 test/unittest/actions/printf/err.D_PROTO_LEN.r
 create mode 100644 test/unittest/actions/printf/err.D_SYNTAX.double_prec.d
 create mode 100644 test/unittest/actions/printf/err.D_SYNTAX.double_prec.r
 create mode 100644 test/unittest/actions/printf/err.D_SYNTAX.double_width.d
 create mode 100644 test/unittest/actions/printf/err.D_SYNTAX.double_width.r
 create mode 100644 test/unittest/actions/printf/err.D_SYNTAX.explicit_arg-2.d
 create mode 100644 test/unittest/actions/printf/err.D_SYNTAX.explicit_arg-2.r
 create mode 100644 test/unittest/actions/printf/err.D_SYNTAX.explicit_arg-3.d
 create mode 100644 test/unittest/actions/printf/err.D_SYNTAX.explicit_arg-3.r
 create mode 100644 test/unittest/actions/printf/err.D_SYNTAX.explicit_arg.d
 create mode 100644 test/unittest/actions/printf/err.D_SYNTAX.explicit_arg.r
 create mode 100644 test/unittest/actions/printf/err.D_SYNTAX.missing_fmt-2.d
 create mode 100644 test/unittest/actions/printf/err.D_SYNTAX.missing_fmt-2.r
 create mode 100644 test/unittest/actions/printf/err.D_SYNTAX.missing_fmt-3.d
 create mode 100644 test/unittest/actions/printf/err.D_SYNTAX.missing_fmt-3.r
 create mode 100644 test/unittest/actions/printf/err.D_SYNTAX.missing_fmt.d
 create mode 100644 test/unittest/actions/printf/err.D_SYNTAX.missing_fmt.r
 create mode 100644 test/unittest/actions/printf/err.D_SYNTAX.pct_flags.d
 create mode 100644 test/unittest/actions/printf/err.D_SYNTAX.pct_flags.r
 create mode 100644 test/unittest/actions/printf/err.D_SYNTAX.prec-width.d
 create mode 100644 test/unittest/actions/printf/err.D_SYNTAX.prec-width.r
 create mode 100644 test/unittest/actions/printf/err.D_SYNTAX.unknown_conv.d
 create mode 100644 test/unittest/actions/printf/err.D_SYNTAX.unknown_conv.r
 create mode 100644 test/unittest/actions/printf/tst.conv_A.d
 create mode 100644 test/unittest/actions/printf/tst.conv_E_double.d
 create mode 100644 test/unittest/actions/printf/tst.conv_E_double.r
 create mode 100644 test/unittest/actions/printf/tst.conv_E_float.d
 create mode 100644 test/unittest/actions/printf/tst.conv_E_float.r
 create mode 100644 test/unittest/actions/printf/tst.conv_G_double.d
 create mode 100644 test/unittest/actions/printf/tst.conv_G_double.r
 create mode 100644 test/unittest/actions/printf/tst.conv_G_float.d
 create mode 100644 test/unittest/actions/printf/tst.conv_G_float.r
 rename test/unittest/{printf/tst.printT.r => actions/printf/tst.conv_T.r} (100%)
 rename test/unittest/{printf/tst.printT.sh => actions/printf/tst.conv_T.sh} (97%)
 rename test/unittest/{printf/tst.printY.r => actions/printf/tst.conv_Y.r} (100%)
 rename test/unittest/{printf/tst.printY.sh => actions/printf/tst.conv_Y.sh} (97%)
 create mode 100644 test/unittest/actions/printf/tst.conv_a.d
 create mode 100644 test/unittest/actions/printf/tst.conv_a.r
 create mode 100644 test/unittest/actions/printf/tst.conv_c.d
 create mode 100644 test/unittest/actions/printf/tst.conv_d_signed.d
 create mode 100644 test/unittest/actions/printf/tst.conv_d_unsigned.d
 create mode 100644 test/unittest/actions/printf/tst.conv_e_double.d
 create mode 100644 test/unittest/actions/printf/tst.conv_e_double.r
 create mode 100644 test/unittest/actions/printf/tst.conv_e_float.d
 create mode 100644 test/unittest/actions/printf/tst.conv_e_float.r
 create mode 100644 test/unittest/actions/printf/tst.conv_f_double.d
 create mode 100644 test/unittest/actions/printf/tst.conv_f_double.r
 create mode 100644 test/unittest/actions/printf/tst.conv_f_float.d
 create mode 100644 test/unittest/actions/printf/tst.conv_f_float.r
 create mode 100644 test/unittest/actions/printf/tst.conv_g_double.d
 create mode 100644 test/unittest/actions/printf/tst.conv_g_double.r
 create mode 100644 test/unittest/actions/printf/tst.conv_g_float.d
 create mode 100644 test/unittest/actions/printf/tst.conv_g_float.r
 delete mode 100644 test/unittest/printf/tst.print-f.d
 delete mode 100644 test/unittest/printf/tst.print-f.r
 delete mode 100644 test/unittest/printf/tst.printeE.d
 delete mode 100644 test/unittest/printf/tst.printeE.r
 delete mode 100644 test/unittest/printf/tst.printgG.d
 delete mode 100644 test/unittest/printf/tst.printgG.r

diff --git a/include/dtrace/metadesc.h b/include/dtrace/metadesc.h
index a4961b08..7f530ba2 100644
--- a/include/dtrace/metadesc.h
+++ b/include/dtrace/metadesc.h
@@ -37,7 +37,7 @@ typedef struct dtrace_recdesc {
 	uint32_t dtrd_size;			/* size of record */
 	uint32_t dtrd_offset;			/* offset in ECB's data */
 	uint16_t dtrd_alignment;		/* required alignment */
-	uint16_t dtrd_format;			/* format, if any */
+	void *dtrd_format;			/* format, if any */
 	uint64_t dtrd_arg;			/* action argument */
 	uint64_t dtrd_uarg;			/* user argument */
 } dtrace_recdesc_t;
diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
index 28f9bb3a..7a88654d 100644
--- a/libdtrace/dt_cg.c
+++ b/libdtrace/dt_cg.c
@@ -15,6 +15,7 @@
 #include <dt_impl.h>
 #include <dt_grammar.h>
 #include <dt_parser.h>
+#include <dt_printf.h>
 #include <dt_provider.h>
 #include <dt_probe.h>
 #include <dt_bpf_builtins.h>
@@ -243,7 +244,8 @@ dt_cg_spill_load(int reg)
 }
 
 static int
-dt_cg_store_val(dt_pcb_t *pcb, dt_node_t *dnp, dtrace_actkind_t kind, int arg)
+dt_cg_store_val(dt_pcb_t *pcb, dt_node_t *dnp, dtrace_actkind_t kind,
+		dt_pfargv_t *pfp, int arg)
 {
 	dtrace_diftype_t	vtype;
 	struct bpf_insn		instr;
@@ -257,7 +259,7 @@ dt_cg_store_val(dt_pcb_t *pcb, dt_node_t *dnp, dtrace_actkind_t kind, int arg)
 		int	sz = 8;
 
 		off = dt_rec_add(pcb->pcb_hdl, dt_cg_fill_gap, kind,
-				 vtype.dtdt_size, vtype.dtdt_size, NULL,
+				 vtype.dtdt_size, vtype.dtdt_size, pfp,
 				 arg);
 
 		switch (vtype.dtdt_size) {
@@ -498,6 +500,67 @@ dt_cg_act_printa(dt_pcb_t *pcb, dt_node_t *dnp, dtrace_actkind_t kind)
 static void
 dt_cg_act_printf(dt_pcb_t *pcb, dt_node_t *dnp, dtrace_actkind_t kind)
 {
+	dt_node_t	*arg1, *anp;
+	dt_pfargv_t	*pfp;
+	char		n[DT_TYPE_NAMELEN];
+	char		*str;
+
+	/*
+	 * Ensure that the format string is a string constant.
+	 */
+	if (dnp->dn_args->dn_kind != DT_NODE_STRING) {
+		dnerror(dnp, D_PRINTF_ARG_FMT,
+			"%s( ) argument #1 is incompatible with prototype:\n"
+			"\tprototype: string constant\n\t argument: %s\n",
+			dnp->dn_ident->di_name,
+			dt_node_type_name(dnp->dn_args, n, sizeof(n)));
+	}
+
+	arg1 = dnp->dn_args->dn_list;
+	yylineno = dnp->dn_line;
+	str = dnp->dn_args->dn_string;
+
+	/*
+	 * If this is an freopen(), we use an empty string to denote that
+	 * stdout should be restored.  For other printf()-like actions, an
+	 * empty format string is illegal:  an empty format string would
+	 * result in malformed DOF, and the compiler thus flags an empty
+	 * format string as a compile-time error.  To avoid propagating the
+	 * freopen() special case throughout the system, we simply transpose
+	 * an empty string into a sentinel string (DT_FREOPEN_RESTORE) that
+	 * denotes that stdout should be restored.
+	 */
+	if (kind == DTRACEACT_FREOPEN) {
+		if (strcmp(str, DT_FREOPEN_RESTORE) == 0) {
+			/*
+			 * Our sentinel is always an invalid argument to
+			 * freopen(), but if it's been manually specified, we
+			 * must fail now instead of when the freopen() is
+			 * actually evaluated.
+			 */
+			dnerror(dnp, D_FREOPEN_INVALID,
+				"%s( ) argument #1 cannot be \"%s\"\n",
+				dnp->dn_ident->di_name, DT_FREOPEN_RESTORE);
+		}
+
+		if (str[0] == '\0')
+			str = DT_FREOPEN_RESTORE;
+	}
+
+	/*
+	 * Validate the format string and the datatypes of the arguments.
+	 */
+	pfp = dt_printf_create(pcb->pcb_hdl, str);
+	dt_printf_validate(pfp, DT_PRINTF_EXACTLEN, dnp->dn_ident, 1,
+			   DTRACEACT_AGGREGATION, arg1);
+
+	/*
+	 * Generate code to store the arguments.  If no arguments are provided,
+	 * we are printing a string constant, and no data needs to be written
+	 * to the output buffer.
+	 */
+	for (anp = arg1; anp != NULL; anp = anp->dn_list)
+		dt_cg_store_val(pcb, anp, kind, pfp, 0);
 }
 
 static void
@@ -593,7 +656,7 @@ dt_cg_act_trace(dt_pcb_t *pcb, dt_node_t *dnp, dtrace_actkind_t kind)
 	else if (arg->dn_flags & DT_NF_SIGNED)
 		type = DT_NF_SIGNED;
 
-	if (dt_cg_store_val(pcb, arg, DTRACEACT_DIFEXPR, type) == -1)
+	if (dt_cg_store_val(pcb, arg, DTRACEACT_DIFEXPR, NULL, type) == -1)
 		dnerror(arg, D_PROTO_ARG,
 			"trace( ) argument #1 is incompatible with prototype:\n"
 			"\tprototype: scalar or string\n\t argument: %s\n",
@@ -668,11 +731,11 @@ static const dt_cg_actdesc_t _dt_cg_actions[DT_ACT_MAX] = {
 	[DT_ACT_IDX(DT_ACT_NORMALIZE)]		= { &dt_cg_act_normalize, },
 	[DT_ACT_IDX(DT_ACT_DENORMALIZE)]	= { &dt_cg_act_denormalize, },
 	[DT_ACT_IDX(DT_ACT_TRUNC)]		= { &dt_cg_act_trunc, },
-	[DT_ACT_IDX(DT_ACT_SYSTEM)]		= { &dt_cg_act_system,
+	[DT_ACT_IDX(DT_ACT_SYSTEM)]		= { &dt_cg_act_printf,
 						    DTRACEACT_SYSTEM },
 	[DT_ACT_IDX(DT_ACT_JSTACK)]		= { &dt_cg_act_jstack, },
 	[DT_ACT_IDX(DT_ACT_FTRUNCATE)]		= { &dt_cg_act_ftruncate, },
-	[DT_ACT_IDX(DT_ACT_FREOPEN)]		= { &dt_cg_act_freopen,
+	[DT_ACT_IDX(DT_ACT_FREOPEN)]		= { &dt_cg_act_printf,
 						    DTRACEACT_FREOPEN },
 	[DT_ACT_IDX(DT_ACT_SYM)]		= { &dt_cg_act_symmod,
 						    DTRACEACT_SYM },
diff --git a/libdtrace/dt_consume.c b/libdtrace/dt_consume.c
index 6c15b4a5..5a5eb3bb 100644
--- a/libdtrace/dt_consume.c
+++ b/libdtrace/dt_consume.c
@@ -2414,6 +2414,21 @@ dt_consume_one(dtrace_hdl_t *dtp, FILE *fp, int cpu, char *buf,
 			if (rval != DTRACE_CONSUME_THIS)
 				return dt_set_errno(dtp, EDT_BADRVAL);
 
+			if (rec->dtrd_action == DTRACEACT_PRINTF) {
+				int	nrecs;
+
+				nrecs = pdat->dtpda_ddesc->dtdd_nrecs - i;
+				n = dtrace_fprintf(dtp, fp, rec->dtrd_format,
+						   pdat, rec, nrecs, data,
+						   size);
+				if (n < 0)
+					return -1;
+				if (n > 0)
+					i += n - 1;
+
+				continue;
+			}
+
 			n = dt_print_trace(dtp, fp, rec, pdat->dtpda_data,
 					   quiet);
 
diff --git a/libdtrace/dt_impl.h b/libdtrace/dt_impl.h
index 8f360047..fde084c4 100644
--- a/libdtrace/dt_impl.h
+++ b/libdtrace/dt_impl.h
@@ -48,6 +48,7 @@ extern "C" {
 #include <dt_dof.h>
 #include <dt_pcb.h>
 #include <dt_pt_regs.h>
+#include <dt_printf.h>
 #include <dt_bpf_ctx.h>
 #include <dt_debug.h>
 #include <dt_version.h>
@@ -792,7 +793,7 @@ extern int dt_epid_lookup(dtrace_hdl_t *, dtrace_epid_t, dtrace_datadesc_t **,
 extern void dt_epid_destroy(dtrace_hdl_t *);
 typedef void (*dt_cg_gap_f)(dt_pcb_t *, int);
 extern uint32_t dt_rec_add(dtrace_hdl_t *, dt_cg_gap_f, dtrace_actkind_t,
-			   uint32_t, uint16_t, const char *, uint64_t);
+			   uint32_t, uint16_t, dt_pfargv_t *, uint64_t);
 extern int dt_aggid_lookup(dtrace_hdl_t *, dtrace_aggid_t, dtrace_aggdesc_t **);
 extern void dt_aggid_destroy(dtrace_hdl_t *);
 
diff --git a/libdtrace/dt_map.c b/libdtrace/dt_map.c
index 00668c70..ce11f7c9 100644
--- a/libdtrace/dt_map.c
+++ b/libdtrace/dt_map.c
@@ -349,7 +349,7 @@ dt_epid_destroy(dtrace_hdl_t *dtp)
 
 uint32_t
 dt_rec_add(dtrace_hdl_t *dtp, dt_cg_gap_f gapf, dtrace_actkind_t kind,
-	   uint32_t size, uint16_t alignment, const char *fmt, uint64_t arg)
+	   uint32_t size, uint16_t alignment, dt_pfargv_t *pfp, uint64_t arg)
 {
 	dt_pcb_t		*pcb = dtp->dt_pcb;
 	uint32_t		off;
@@ -387,7 +387,7 @@ dt_rec_add(dtrace_hdl_t *dtp, dt_cg_gap_f gapf, dtrace_actkind_t kind,
 	rec->dtrd_size = size;
 	rec->dtrd_offset = off;
 	rec->dtrd_alignment = alignment;
-	rec->dtrd_format = 0;	/* FIXME */
+	rec->dtrd_format = pfp;
 	rec->dtrd_arg = arg;
 
 	gap = off - pcb->pcb_bufoff;
diff --git a/libdtrace/dt_printf.c b/libdtrace/dt_printf.c
index e567c6f9..03ffa8bd 100644
--- a/libdtrace/dt_printf.c
+++ b/libdtrace/dt_printf.c
@@ -812,11 +812,12 @@ dt_printf_create(dtrace_hdl_t *dtp, const char *s)
 
 			if (pfd->pfd_flags & n) {
 				yywarn("format conversion #%u has more than "
-				    "one '*' specified for the output %s\n",
-				    pfv->pfv_argc, n ? "precision" : "width");
+				       "one '*' specified for the output %s\n",
+				       pfv->pfv_argc,
+				       dot ? "precision" : "width");
 
 				dt_printf_destroy(pfv);
-				return (dt_printf_error(dtp, EDT_COMPILER));
+				return dt_printf_error(dtp, EDT_COMPILER);
 			}
 
 			pfd->pfd_flags |= n;
@@ -1162,7 +1163,7 @@ dt_printf_getint(dtrace_hdl_t *dtp, const dtrace_recdesc_t *recp,
 
 	addr = (uintptr_t)buf + recp->dtrd_offset;
 
-	if (addr + sizeof (int) > (uintptr_t)buf + len)
+	if (addr + recp->dtrd_size > (uintptr_t)buf + len)
 		return (dt_set_errno(dtp, EDT_DOFFSET));
 
 	if (addr & (recp->dtrd_alignment - 1))
diff --git a/test/unittest/actions/printf/err.D_PRINTF_AGG_CONV.d b/test/unittest/actions/printf/err.D_PRINTF_AGG_CONV.d
new file mode 100644
index 00000000..df24f0c9
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_AGG_CONV.d
@@ -0,0 +1,21 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf() action requires an aggregation value for conversions
+ *	      with the '@' specifier.
+ *
+ * SECTION: Actions and Subroutines/printf()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	printf("%@d", 1);
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/err.D_PRINTF_AGG_CONV.r b/test/unittest/actions/printf/err.D_PRINTF_AGG_CONV.r
new file mode 100644
index 00000000..28a613b4
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_AGG_CONV.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/actions/printf/err.D_PRINTF_AGG_CONV.d: [D_PRINTF_AGG_CONV] line 19: %@ conversion requires an aggregation and is not for use with printf( )
diff --git a/test/unittest/actions/printf/err.D_PRINTF_ARG_EXTRA.addr_width.d b/test/unittest/actions/printf/err.D_PRINTF_ARG_EXTRA.addr_width.d
new file mode 100644
index 00000000..d336c95d
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_ARG_EXTRA.addr_width.d
@@ -0,0 +1,22 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf() action provides a fixed field width for formatting
+ *	      addresses in hexadecimal format, so providing a field width with
+ *	      the '?' size specifier is not allowed.
+ *
+ * SECTION: Actions and Subroutines/printf()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	printf("%?d\n", 1, 2);
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/err.D_PRINTF_ARG_EXTRA.addr_width.r b/test/unittest/actions/printf/err.D_PRINTF_ARG_EXTRA.addr_width.r
new file mode 100644
index 00000000..f8647642
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_ARG_EXTRA.addr_width.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/actions/printf/err.D_PRINTF_ARG_EXTRA.addr_width.d: [D_PRINTF_ARG_EXTRA] line 20: printf( ) prototype mismatch: only 1 arguments required by this format string
diff --git a/test/unittest/actions/printf/err.D_PRINTF_ARG_EXTRA.too_many_vals.d b/test/unittest/actions/printf/err.D_PRINTF_ARG_EXTRA.too_many_vals.d
new file mode 100644
index 00000000..a973025e
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_ARG_EXTRA.too_many_vals.d
@@ -0,0 +1,20 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf() action requires values for all conversions.
+ *
+ * SECTION: Actions and Subroutines/printf()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	printf("%d", 1, 2, 3);
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/err.D_PRINTF_ARG_EXTRA.too_many_vals.r b/test/unittest/actions/printf/err.D_PRINTF_ARG_EXTRA.too_many_vals.r
new file mode 100644
index 00000000..8d388e34
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_ARG_EXTRA.too_many_vals.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/actions/printf/err.D_PRINTF_ARG_EXTRA.too_many_vals.d: [D_PRINTF_ARG_EXTRA] line 18: printf( ) prototype mismatch: only 1 arguments required by this format string
diff --git a/test/unittest/actions/printf/err.D_PRINTF_ARG_FMT.d b/test/unittest/actions/printf/err.D_PRINTF_ARG_FMT.d
new file mode 100644
index 00000000..837778e4
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_ARG_FMT.d
@@ -0,0 +1,20 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf() action requires a string constant as first argument.
+ *
+ * SECTION: Actions and Subroutines/printf()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	printf(probename);
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/err.D_PRINTF_ARG_FMT.r b/test/unittest/actions/printf/err.D_PRINTF_ARG_FMT.r
new file mode 100644
index 00000000..172e49dc
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_ARG_FMT.r
@@ -0,0 +1,4 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/actions/printf/err.D_PRINTF_ARG_FMT.d: [D_PRINTF_ARG_FMT] line 18: printf( ) argument #1 is incompatible with prototype:
+	prototype: string constant
+	 argument: string
diff --git a/test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.missing_val.d b/test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.missing_val.d
new file mode 100644
index 00000000..2ac28478
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.missing_val.d
@@ -0,0 +1,20 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf() action requires a value for a conversion.
+ *
+ * SECTION: Actions and Subroutines/printf()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	printf("%d");
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.missing_val.r b/test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.missing_val.r
new file mode 100644
index 00000000..d1cca78f
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.missing_val.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.missing_val.d: [D_PRINTF_ARG_PROTO] line 18: printf( ) prototype mismatch: conversion #1 (%d) is missing a corresponding value argument
diff --git a/test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.prec.d b/test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.prec.d
new file mode 100644
index 00000000..bc6c8f23
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.prec.d
@@ -0,0 +1,20 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf() action requires a value for a conversion.
+ *
+ * SECTION: Actions and Subroutines/printf()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	printf("%.*d", 1);
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.prec.r b/test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.prec.r
new file mode 100644
index 00000000..5765ab90
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.prec.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.prec.d: [D_PRINTF_ARG_PROTO] line 18: printf( ) prototype mismatch: conversion #1 (%d) is missing a corresponding value argument
diff --git a/test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.too_few_vals.d b/test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.too_few_vals.d
new file mode 100644
index 00000000..87879a11
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.too_few_vals.d
@@ -0,0 +1,20 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf() action requires values for all conversions.
+ *
+ * SECTION: Actions and Subroutines/printf()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	printf("%d %d %d %d %d", 1, 2, 3);
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.too_few_vals.r b/test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.too_few_vals.r
new file mode 100644
index 00000000..d606a166
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.too_few_vals.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.too_few_vals.d: [D_PRINTF_ARG_PROTO] line 18: printf( ) prototype mismatch: conversion #4 (%d) is missing a corresponding value argument
diff --git a/test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.width-prec.d b/test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.width-prec.d
new file mode 100644
index 00000000..94161432
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.width-prec.d
@@ -0,0 +1,20 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf() action requires a value for a conversion.
+ *
+ * SECTION: Actions and Subroutines/printf()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	printf("%*.*d", 1, 2);
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.width-prec.r b/test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.width-prec.r
new file mode 100644
index 00000000..b77107b5
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.width-prec.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.width-prec.d: [D_PRINTF_ARG_PROTO] line 18: printf( ) prototype mismatch: conversion #1 (%d) is missing a corresponding value argument
diff --git a/test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.width.d b/test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.width.d
new file mode 100644
index 00000000..02cda3d5
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.width.d
@@ -0,0 +1,20 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf() action requires a value for a conversion.
+ *
+ * SECTION: Actions and Subroutines/printf()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	printf("%*d", 1);
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.width.r b/test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.width.r
new file mode 100644
index 00000000..62553f63
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.width.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/actions/printf/err.D_PRINTF_ARG_PROTO.width.d: [D_PRINTF_ARG_PROTO] line 18: printf( ) prototype mismatch: conversion #1 (%d) is missing a corresponding value argument
diff --git a/test/unittest/actions/printf/err.D_PRINTF_ARG_TYPE.agg.d b/test/unittest/actions/printf/err.D_PRINTF_ARG_TYPE.agg.d
new file mode 100644
index 00000000..da1481aa
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_ARG_TYPE.agg.d
@@ -0,0 +1,22 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+/* @@xfail: dtv2 */
+
+/*
+ * ASSERTION: The printf() action requires a value that matches the conversion.
+ *
+ * SECTION: Actions and Subroutines/printf()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	@a = count();
+	printf("%d", @a);
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/err.D_PRINTF_ARG_TYPE.agg.r b/test/unittest/actions/printf/err.D_PRINTF_ARG_TYPE.agg.r
new file mode 100644
index 00000000..183f40ff
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_ARG_TYPE.agg.r
@@ -0,0 +1,5 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/actions/printf/err.D_PRINTF_ARG_TYPE.agg.d: [D_PRINTF_ARG_TYPE] line 18: printf( ) argument #2 is incompatible with conversion #1 prototype:
+	conversion: %d
+	 prototype: char, short, int, long, or long long
+	  argument: aggregation
diff --git a/test/unittest/actions/printf/err.D_PRINTF_ARG_TYPE.mismatch.d b/test/unittest/actions/printf/err.D_PRINTF_ARG_TYPE.mismatch.d
new file mode 100644
index 00000000..fa53d6f9
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_ARG_TYPE.mismatch.d
@@ -0,0 +1,20 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf() action requires a value that matches the conversion.
+ *
+ * SECTION: Actions and Subroutines/printf()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	printf("%d", "");
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/err.D_PRINTF_ARG_TYPE.mismatch.r b/test/unittest/actions/printf/err.D_PRINTF_ARG_TYPE.mismatch.r
new file mode 100644
index 00000000..4e7368db
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_ARG_TYPE.mismatch.r
@@ -0,0 +1,5 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/actions/printf/err.D_PRINTF_ARG_TYPE.mismatch.d: [D_PRINTF_ARG_TYPE] line 18: printf( ) argument #2 is incompatible with conversion #1 prototype:
+	conversion: %d
+	 prototype: char, short, int, long, or long long
+	  argument: string
diff --git a/test/unittest/actions/printf/err.D_PRINTF_ARG_TYPE.void.d b/test/unittest/actions/printf/err.D_PRINTF_ARG_TYPE.void.d
new file mode 100644
index 00000000..c12e8014
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_ARG_TYPE.void.d
@@ -0,0 +1,20 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf() action does not accept void as a value.
+ *
+ * SECTION: Actions and Subroutines/printf()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	printf("%d", printf(""));
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/err.D_PRINTF_ARG_TYPE.void.r b/test/unittest/actions/printf/err.D_PRINTF_ARG_TYPE.void.r
new file mode 100644
index 00000000..1c55bdae
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_ARG_TYPE.void.r
@@ -0,0 +1,5 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/actions/printf/err.D_PRINTF_ARG_TYPE.void.d: [D_PRINTF_ARG_TYPE] line 18: printf( ) argument #2 is incompatible with conversion #1 prototype:
+	conversion: %d
+	 prototype: char, short, int, long, or long long
+	  argument: void
diff --git a/test/unittest/actions/printf/err.D_PRINTF_ARG_TYPE.width-prec.d b/test/unittest/actions/printf/err.D_PRINTF_ARG_TYPE.width-prec.d
new file mode 100644
index 00000000..5f3f628b
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_ARG_TYPE.width-prec.d
@@ -0,0 +1,20 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf() action requires a value that matches the conversion.
+ *
+ * SECTION: Actions and Subroutines/printf()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	printf("%*.*d", 1, 2, "");
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/err.D_PRINTF_ARG_TYPE.width-prec.r b/test/unittest/actions/printf/err.D_PRINTF_ARG_TYPE.width-prec.r
new file mode 100644
index 00000000..750cc998
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_ARG_TYPE.width-prec.r
@@ -0,0 +1,5 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/actions/printf/err.D_PRINTF_ARG_TYPE.width-prec.d: [D_PRINTF_ARG_TYPE] line 18: printf( ) argument #4 is incompatible with conversion #1 prototype:
+	conversion: %d
+	 prototype: char, short, int, long, or long long
+	  argument: string
diff --git a/test/unittest/actions/printf/err.D_PRINTF_DYN_PROTO.missing_prec-2.d b/test/unittest/actions/printf/err.D_PRINTF_DYN_PROTO.missing_prec-2.d
new file mode 100644
index 00000000..3cd1be33
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_DYN_PROTO.missing_prec-2.d
@@ -0,0 +1,21 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf() action verifies that a precision is provided if the
+ *	      conversion includes a precision specifier.
+ *
+ * SECTION: Actions and Subroutines/printf()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	printf("%*.*d", 1);
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/err.D_PRINTF_DYN_PROTO.missing_prec-2.r b/test/unittest/actions/printf/err.D_PRINTF_DYN_PROTO.missing_prec-2.r
new file mode 100644
index 00000000..830bf022
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_DYN_PROTO.missing_prec-2.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/actions/printf/err.D_PRINTF_DYN_PROTO.missing_prec-2.d: [D_PRINTF_DYN_PROTO] line 19: printf( ) prototype mismatch: conversion #1 (%d) is missing a corresponding ".*" argument
diff --git a/test/unittest/actions/printf/err.D_PRINTF_DYN_PROTO.missing_prec.d b/test/unittest/actions/printf/err.D_PRINTF_DYN_PROTO.missing_prec.d
new file mode 100644
index 00000000..fef5b4c8
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_DYN_PROTO.missing_prec.d
@@ -0,0 +1,21 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf() action verifies that a precision is provided if the
+ *	      conversion includes a precision specifier.
+ *
+ * SECTION: Actions and Subroutines/printf()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	printf("%.*d");
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/err.D_PRINTF_DYN_PROTO.missing_prec.r b/test/unittest/actions/printf/err.D_PRINTF_DYN_PROTO.missing_prec.r
new file mode 100644
index 00000000..a793df36
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_DYN_PROTO.missing_prec.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/actions/printf/err.D_PRINTF_DYN_PROTO.missing_prec.d: [D_PRINTF_DYN_PROTO] line 19: printf( ) prototype mismatch: conversion #1 (%d) is missing a corresponding ".*" argument
diff --git a/test/unittest/actions/printf/err.D_PRINTF_DYN_PROTO.missing_width-2.d b/test/unittest/actions/printf/err.D_PRINTF_DYN_PROTO.missing_width-2.d
new file mode 100644
index 00000000..2082d7f8
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_DYN_PROTO.missing_width-2.d
@@ -0,0 +1,21 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf() action verifies that a width is provided if the
+ *	      conversion includes a width specifier.
+ *
+ * SECTION: Actions and Subroutines/printf()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	printf("%*.*d");
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/err.D_PRINTF_DYN_PROTO.missing_width-2.r b/test/unittest/actions/printf/err.D_PRINTF_DYN_PROTO.missing_width-2.r
new file mode 100644
index 00000000..e3297f38
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_DYN_PROTO.missing_width-2.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/actions/printf/err.D_PRINTF_DYN_PROTO.missing_width-2.d: [D_PRINTF_DYN_PROTO] line 19: printf( ) prototype mismatch: conversion #1 (%d) is missing a corresponding "*" argument
diff --git a/test/unittest/actions/printf/err.D_PRINTF_DYN_PROTO.missing_width.d b/test/unittest/actions/printf/err.D_PRINTF_DYN_PROTO.missing_width.d
new file mode 100644
index 00000000..d81b11b3
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_DYN_PROTO.missing_width.d
@@ -0,0 +1,21 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf() action verifies that a width is provided if the
+ *	      conversion includes a width specifier.
+ *
+ * SECTION: Actions and Subroutines/printf()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	printf("%*d");
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/err.D_PRINTF_DYN_PROTO.missing_width.r b/test/unittest/actions/printf/err.D_PRINTF_DYN_PROTO.missing_width.r
new file mode 100644
index 00000000..3a6223d4
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_DYN_PROTO.missing_width.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/actions/printf/err.D_PRINTF_DYN_PROTO.missing_width.d: [D_PRINTF_DYN_PROTO] line 19: printf( ) prototype mismatch: conversion #1 (%d) is missing a corresponding "*" argument
diff --git a/test/unittest/actions/printf/err.D_PRINTF_DYN_TYPE.prec.d b/test/unittest/actions/printf/err.D_PRINTF_DYN_TYPE.prec.d
new file mode 100644
index 00000000..f8cf0240
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_DYN_TYPE.prec.d
@@ -0,0 +1,21 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf() action requires an integer value for the precision
+ *	      specifier.
+ *
+ * SECTION: Actions and Subroutines/printf()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	printf("%.*d", "", 1);
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/err.D_PRINTF_DYN_TYPE.prec.r b/test/unittest/actions/printf/err.D_PRINTF_DYN_TYPE.prec.r
new file mode 100644
index 00000000..eb8bf0eb
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_DYN_TYPE.prec.r
@@ -0,0 +1,5 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/actions/printf/err.D_PRINTF_DYN_TYPE.prec.d: [D_PRINTF_DYN_TYPE] line 19: printf( ) argument #2 is incompatible with conversion #1 prototype:
+	conversion: % .* d
+	 prototype: int
+	  argument: string
diff --git a/test/unittest/actions/printf/err.D_PRINTF_DYN_TYPE.width-prec.d b/test/unittest/actions/printf/err.D_PRINTF_DYN_TYPE.width-prec.d
new file mode 100644
index 00000000..cdff86e1
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_DYN_TYPE.width-prec.d
@@ -0,0 +1,21 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf() action requires an integer value for the width and
+ *	      precision specifiers.  The width specifier is checked first.
+ *
+ * SECTION: Actions and Subroutines/printf()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	printf("%*.*d", "", "", 1);
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/err.D_PRINTF_DYN_TYPE.width-prec.r b/test/unittest/actions/printf/err.D_PRINTF_DYN_TYPE.width-prec.r
new file mode 100644
index 00000000..4dd0c194
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_DYN_TYPE.width-prec.r
@@ -0,0 +1,5 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/actions/printf/err.D_PRINTF_DYN_TYPE.width-prec.d: [D_PRINTF_DYN_TYPE] line 19: printf( ) argument #2 is incompatible with conversion #1 prototype:
+	conversion: % * d
+	 prototype: int
+	  argument: string
diff --git a/test/unittest/actions/printf/err.D_PRINTF_DYN_TYPE.width.d b/test/unittest/actions/printf/err.D_PRINTF_DYN_TYPE.width.d
new file mode 100644
index 00000000..0e0ff102
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_DYN_TYPE.width.d
@@ -0,0 +1,21 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf() action requires an integer value for the width
+ *	      specifier.
+ *
+ * SECTION: Actions and Subroutines/printf()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	printf("%*d", "", 1);
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/err.D_PRINTF_DYN_TYPE.width.r b/test/unittest/actions/printf/err.D_PRINTF_DYN_TYPE.width.r
new file mode 100644
index 00000000..af1f8da7
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_DYN_TYPE.width.r
@@ -0,0 +1,5 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/actions/printf/err.D_PRINTF_DYN_TYPE.width.d: [D_PRINTF_DYN_TYPE] line 19: printf( ) argument #2 is incompatible with conversion #1 prototype:
+	conversion: % * d
+	 prototype: int
+	  argument: string
diff --git a/test/unittest/actions/printf/err.D_PRINTF_FMT_EMPTY.d b/test/unittest/actions/printf/err.D_PRINTF_FMT_EMPTY.d
new file mode 100644
index 00000000..63898e52
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_FMT_EMPTY.d
@@ -0,0 +1,20 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf() action format string cannot be empty.
+ *
+ * SECTION: Actions and Subroutines/printf()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	printf("");
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/err.D_PRINTF_FMT_EMPTY.r b/test/unittest/actions/printf/err.D_PRINTF_FMT_EMPTY.r
new file mode 100644
index 00000000..e379bd2c
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PRINTF_FMT_EMPTY.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/actions/printf/err.D_PRINTF_FMT_EMPTY.d: [D_PRINTF_FMT_EMPTY] line 18: printf( ) format string is empty
diff --git a/test/unittest/actions/printf/err.D_PROTO_ARG.d b/test/unittest/actions/printf/err.D_PROTO_ARG.d
new file mode 100644
index 00000000..f514ee3b
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PROTO_ARG.d
@@ -0,0 +1,20 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf() action requires a string as first argument.
+ *
+ * SECTION: Actions and Subroutines/printf()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	printf(1);
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/err.D_PROTO_ARG.r b/test/unittest/actions/printf/err.D_PROTO_ARG.r
new file mode 100644
index 00000000..0fef262f
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PROTO_ARG.r
@@ -0,0 +1,4 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/actions/printf/err.D_PROTO_ARG.d: [D_PROTO_ARG] line 18: printf( ) argument #1 is incompatible with prototype:
+	prototype: string
+	 argument: int
diff --git a/test/unittest/actions/printf/err.D_PROTO_LEN.d b/test/unittest/actions/printf/err.D_PROTO_LEN.d
new file mode 100644
index 00000000..a4b80046
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PROTO_LEN.d
@@ -0,0 +1,20 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf() action requires at least one argument.
+ *
+ * SECTION: Actions and Subroutines/printf()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	printf();
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/err.D_PROTO_LEN.r b/test/unittest/actions/printf/err.D_PROTO_LEN.r
new file mode 100644
index 00000000..c8e8b347
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_PROTO_LEN.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/actions/printf/err.D_PROTO_LEN.d: [D_PROTO_LEN] line 18: printf( ) prototype mismatch: 0 args passed, at least 1 expected
diff --git a/test/unittest/actions/printf/err.D_SYNTAX.double_prec.d b/test/unittest/actions/printf/err.D_SYNTAX.double_prec.d
new file mode 100644
index 00000000..81862265
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_SYNTAX.double_prec.d
@@ -0,0 +1,20 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf() action accepts only one precision per conversion.
+ *
+ * SECTION: Actions and Subroutines/printf()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	printf("%.*.*d");
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/err.D_SYNTAX.double_prec.r b/test/unittest/actions/printf/err.D_SYNTAX.double_prec.r
new file mode 100644
index 00000000..14bc1405
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_SYNTAX.double_prec.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/actions/printf/err.D_SYNTAX.double_prec.d: [D_SYNTAX] line 18: format conversion #1 has more than one '.' specified
diff --git a/test/unittest/actions/printf/err.D_SYNTAX.double_width.d b/test/unittest/actions/printf/err.D_SYNTAX.double_width.d
new file mode 100644
index 00000000..7e8a9d9c
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_SYNTAX.double_width.d
@@ -0,0 +1,20 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf() action accepts only one width per conversion.
+ *
+ * SECTION: Actions and Subroutines/printf()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	printf("%**d");
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/err.D_SYNTAX.double_width.r b/test/unittest/actions/printf/err.D_SYNTAX.double_width.r
new file mode 100644
index 00000000..47aae46a
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_SYNTAX.double_width.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/actions/printf/err.D_SYNTAX.double_width.d: [D_SYNTAX] line 18: format conversion #1 has more than one '*' specified for the output width
diff --git a/test/unittest/actions/printf/err.D_SYNTAX.explicit_arg-2.d b/test/unittest/actions/printf/err.D_SYNTAX.explicit_arg-2.d
new file mode 100644
index 00000000..19755813
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_SYNTAX.explicit_arg-2.d
@@ -0,0 +1,21 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf() action does not allow explicit argument specifiers.
+ *
+ * SECTION: Actions and Subroutines/printf()
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	printf("%*1$d");
+	exit(-1);
+}
diff --git a/test/unittest/actions/printf/err.D_SYNTAX.explicit_arg-2.r b/test/unittest/actions/printf/err.D_SYNTAX.explicit_arg-2.r
new file mode 100644
index 00000000..4c72b01a
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_SYNTAX.explicit_arg-2.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/actions/printf/err.D_SYNTAX.explicit_arg-2.d: [D_SYNTAX] line 19: format conversion #1 uses unsupported positional format (%n$)
diff --git a/test/unittest/actions/printf/err.D_SYNTAX.explicit_arg-3.d b/test/unittest/actions/printf/err.D_SYNTAX.explicit_arg-3.d
new file mode 100644
index 00000000..cd798b98
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_SYNTAX.explicit_arg-3.d
@@ -0,0 +1,21 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf() action does not allow explicit argument specifiers.
+ *
+ * SECTION: Actions and Subroutines/printf()
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	printf("%.*1$d");
+	exit(-1);
+}
diff --git a/test/unittest/actions/printf/err.D_SYNTAX.explicit_arg-3.r b/test/unittest/actions/printf/err.D_SYNTAX.explicit_arg-3.r
new file mode 100644
index 00000000..3395f5b6
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_SYNTAX.explicit_arg-3.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/actions/printf/err.D_SYNTAX.explicit_arg-3.d: [D_SYNTAX] line 19: format conversion #1 uses unsupported positional format (%n$)
diff --git a/test/unittest/actions/printf/err.D_SYNTAX.explicit_arg.d b/test/unittest/actions/printf/err.D_SYNTAX.explicit_arg.d
new file mode 100644
index 00000000..7c6ef8a8
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_SYNTAX.explicit_arg.d
@@ -0,0 +1,21 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf() action does not allow explicit argument specifiers.
+ *
+ * SECTION: Actions and Subroutines/printf()
+ *
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	printf("%1$d");
+	exit(-1);
+}
diff --git a/test/unittest/actions/printf/err.D_SYNTAX.explicit_arg.r b/test/unittest/actions/printf/err.D_SYNTAX.explicit_arg.r
new file mode 100644
index 00000000..0292c7c4
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_SYNTAX.explicit_arg.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/actions/printf/err.D_SYNTAX.explicit_arg.d: [D_SYNTAX] line 19: format conversion #1 uses unsupported positional format (%n$)
diff --git a/test/unittest/actions/printf/err.D_SYNTAX.missing_fmt-2.d b/test/unittest/actions/printf/err.D_SYNTAX.missing_fmt-2.d
new file mode 100644
index 00000000..b0a94be6
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_SYNTAX.missing_fmt-2.d
@@ -0,0 +1,21 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf() action requires a conversion format symbol in a
+ *	      conversion specification.
+ *
+ * SECTION: Actions and Subroutines/printf()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	printf("%*");
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/err.D_SYNTAX.missing_fmt-2.r b/test/unittest/actions/printf/err.D_SYNTAX.missing_fmt-2.r
new file mode 100644
index 00000000..5bbcde487
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_SYNTAX.missing_fmt-2.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/actions/printf/err.D_SYNTAX.missing_fmt-2.d: [D_SYNTAX] line 19: format conversion #1 name expected before end of format string
diff --git a/test/unittest/actions/printf/err.D_SYNTAX.missing_fmt-3.d b/test/unittest/actions/printf/err.D_SYNTAX.missing_fmt-3.d
new file mode 100644
index 00000000..a8436b9e
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_SYNTAX.missing_fmt-3.d
@@ -0,0 +1,21 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf() action requires a conversion format symbol in a
+ *	      conversion specification.
+ *
+ * SECTION: Actions and Subroutines/printf()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	printf("%.*");
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/err.D_SYNTAX.missing_fmt-3.r b/test/unittest/actions/printf/err.D_SYNTAX.missing_fmt-3.r
new file mode 100644
index 00000000..c423bf1b
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_SYNTAX.missing_fmt-3.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/actions/printf/err.D_SYNTAX.missing_fmt-3.d: [D_SYNTAX] line 19: format conversion #1 name expected before end of format string
diff --git a/test/unittest/actions/printf/err.D_SYNTAX.missing_fmt.d b/test/unittest/actions/printf/err.D_SYNTAX.missing_fmt.d
new file mode 100644
index 00000000..846dbf8a
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_SYNTAX.missing_fmt.d
@@ -0,0 +1,21 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf() action requires a conversion format symbol in a
+ *	      conversion specification.
+ *
+ * SECTION: Actions and Subroutines/printf()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	printf("%");
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/err.D_SYNTAX.missing_fmt.r b/test/unittest/actions/printf/err.D_SYNTAX.missing_fmt.r
new file mode 100644
index 00000000..819c5f37
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_SYNTAX.missing_fmt.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/actions/printf/err.D_SYNTAX.missing_fmt.d: [D_SYNTAX] line 19: format conversion #1 name expected before end of format string
diff --git a/test/unittest/actions/printf/err.D_SYNTAX.pct_flags.d b/test/unittest/actions/printf/err.D_SYNTAX.pct_flags.d
new file mode 100644
index 00000000..2f3c459d
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_SYNTAX.pct_flags.d
@@ -0,0 +1,21 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf() action "%%" conversion does not accept other format
+ *	      flags.
+ *
+ * SECTION: Actions and Subroutines/printf()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	printf("%-%");
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/err.D_SYNTAX.pct_flags.r b/test/unittest/actions/printf/err.D_SYNTAX.pct_flags.r
new file mode 100644
index 00000000..b33b0996
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_SYNTAX.pct_flags.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/actions/printf/err.D_SYNTAX.pct_flags.d: [D_SYNTAX] line 19: format conversion #1 cannot be combined with other format flags: %%
diff --git a/test/unittest/actions/printf/err.D_SYNTAX.prec-width.d b/test/unittest/actions/printf/err.D_SYNTAX.prec-width.d
new file mode 100644
index 00000000..318aae1e
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_SYNTAX.prec-width.d
@@ -0,0 +1,20 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf() action does not allow precision before width.
+ *
+ * SECTION: Actions and Subroutines/printf()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	printf("%.**d");
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/err.D_SYNTAX.prec-width.r b/test/unittest/actions/printf/err.D_SYNTAX.prec-width.r
new file mode 100644
index 00000000..c6e35f98
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_SYNTAX.prec-width.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/actions/printf/err.D_SYNTAX.prec-width.d: [D_SYNTAX] line 18: format conversion #1 has more than one '*' specified for the output precision
diff --git a/test/unittest/actions/printf/err.D_SYNTAX.unknown_conv.d b/test/unittest/actions/printf/err.D_SYNTAX.unknown_conv.d
new file mode 100644
index 00000000..fe705c2d
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_SYNTAX.unknown_conv.d
@@ -0,0 +1,21 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf() action verifies that the conversion format symbol is
+ *	      valid.
+ *
+ * SECTION: Actions and Subroutines/printf()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	printf("%z");
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/err.D_SYNTAX.unknown_conv.r b/test/unittest/actions/printf/err.D_SYNTAX.unknown_conv.r
new file mode 100644
index 00000000..8b610590
--- /dev/null
+++ b/test/unittest/actions/printf/err.D_SYNTAX.unknown_conv.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/actions/printf/err.D_SYNTAX.unknown_conv.d: [D_SYNTAX] line 19: format conversion #1 is undefined: %z
diff --git a/test/unittest/actions/printf/tst.conv_A.d b/test/unittest/actions/printf/tst.conv_A.d
new file mode 100644
index 00000000..79c07c7f
--- /dev/null
+++ b/test/unittest/actions/printf/tst.conv_A.d
@@ -0,0 +1,21 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+/* @@xfail: dtv2 */
+
+/*
+ * ASSERTION: The printf action supports '%a' for userspace addresses.
+ *
+ * SECTION: Actions/printf()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	printf("%A", &``main);
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/tst.conv_E_double.d b/test/unittest/actions/printf/tst.conv_E_double.d
new file mode 100644
index 00000000..71901789
--- /dev/null
+++ b/test/unittest/actions/printf/tst.conv_E_double.d
@@ -0,0 +1,22 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf action supports '%E' for double floating point values.
+ *
+ * SECTION: Actions/printf()
+ */
+
+#pragma D option quiet
+
+double d;
+
+BEGIN
+{
+	printf("%E", d);
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/tst.conv_E_double.r b/test/unittest/actions/printf/tst.conv_E_double.r
new file mode 100644
index 00000000..09943084
--- /dev/null
+++ b/test/unittest/actions/printf/tst.conv_E_double.r
@@ -0,0 +1 @@
+0.000000E+00
diff --git a/test/unittest/actions/printf/tst.conv_E_float.d b/test/unittest/actions/printf/tst.conv_E_float.d
new file mode 100644
index 00000000..8075fc3a
--- /dev/null
+++ b/test/unittest/actions/printf/tst.conv_E_float.d
@@ -0,0 +1,22 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf action supports '%E' for floating point values.
+ *
+ * SECTION: Actions/printf()
+ */
+
+#pragma D option quiet
+
+float f;
+
+BEGIN
+{
+	printf("%E", f);
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/tst.conv_E_float.r b/test/unittest/actions/printf/tst.conv_E_float.r
new file mode 100644
index 00000000..09943084
--- /dev/null
+++ b/test/unittest/actions/printf/tst.conv_E_float.r
@@ -0,0 +1 @@
+0.000000E+00
diff --git a/test/unittest/actions/printf/tst.conv_G_double.d b/test/unittest/actions/printf/tst.conv_G_double.d
new file mode 100644
index 00000000..1e605f47
--- /dev/null
+++ b/test/unittest/actions/printf/tst.conv_G_double.d
@@ -0,0 +1,22 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf action supports '%G' for double floating point values.
+ *
+ * SECTION: Actions/printf()
+ */
+
+#pragma D option quiet
+
+double d;
+
+BEGIN
+{
+	printf("%G", d);
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/tst.conv_G_double.r b/test/unittest/actions/printf/tst.conv_G_double.r
new file mode 100644
index 00000000..573541ac
--- /dev/null
+++ b/test/unittest/actions/printf/tst.conv_G_double.r
@@ -0,0 +1 @@
+0
diff --git a/test/unittest/actions/printf/tst.conv_G_float.d b/test/unittest/actions/printf/tst.conv_G_float.d
new file mode 100644
index 00000000..59f1b2c2
--- /dev/null
+++ b/test/unittest/actions/printf/tst.conv_G_float.d
@@ -0,0 +1,22 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf action supports '%G' for floating point values.
+ *
+ * SECTION: Actions/printf()
+ */
+
+#pragma D option quiet
+
+float f;
+
+BEGIN
+{
+	printf("%G", f);
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/tst.conv_G_float.r b/test/unittest/actions/printf/tst.conv_G_float.r
new file mode 100644
index 00000000..573541ac
--- /dev/null
+++ b/test/unittest/actions/printf/tst.conv_G_float.r
@@ -0,0 +1 @@
+0
diff --git a/test/unittest/printf/tst.printT.r b/test/unittest/actions/printf/tst.conv_T.r
similarity index 100%
rename from test/unittest/printf/tst.printT.r
rename to test/unittest/actions/printf/tst.conv_T.r
diff --git a/test/unittest/printf/tst.printT.sh b/test/unittest/actions/printf/tst.conv_T.sh
similarity index 97%
rename from test/unittest/printf/tst.printT.sh
rename to test/unittest/actions/printf/tst.conv_T.sh
index f5ec47e4..36ee32e4 100755
--- a/test/unittest/printf/tst.printT.sh
+++ b/test/unittest/actions/printf/tst.conv_T.sh
@@ -9,7 +9,6 @@ if [ $# != 1 ]; then
 	echo expected one argument: '<'dtrace-path'>'
 	exit 2
 fi
-# @@xfail: dtv2
 
 dtrace=$1
 
diff --git a/test/unittest/printf/tst.printY.r b/test/unittest/actions/printf/tst.conv_Y.r
similarity index 100%
rename from test/unittest/printf/tst.printY.r
rename to test/unittest/actions/printf/tst.conv_Y.r
diff --git a/test/unittest/printf/tst.printY.sh b/test/unittest/actions/printf/tst.conv_Y.sh
similarity index 97%
rename from test/unittest/printf/tst.printY.sh
rename to test/unittest/actions/printf/tst.conv_Y.sh
index 64b65ec9..18fe56ee 100755
--- a/test/unittest/printf/tst.printY.sh
+++ b/test/unittest/actions/printf/tst.conv_Y.sh
@@ -9,7 +9,6 @@ if [ $# != 1 ]; then
 	echo expected one argument: '<'dtrace-path'>'
 	exit 2
 fi
-# @@xfail: dtv2
 
 dtrace=$1
 
diff --git a/test/unittest/actions/printf/tst.conv_a.d b/test/unittest/actions/printf/tst.conv_a.d
new file mode 100644
index 00000000..a5640301
--- /dev/null
+++ b/test/unittest/actions/printf/tst.conv_a.d
@@ -0,0 +1,20 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf action supports '%a' for kernel addresses.
+ *
+ * SECTION: Actions/printf()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	printf("%a", &`max_pfn);
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/tst.conv_a.r b/test/unittest/actions/printf/tst.conv_a.r
new file mode 100644
index 00000000..335cdd50
--- /dev/null
+++ b/test/unittest/actions/printf/tst.conv_a.r
@@ -0,0 +1 @@
+{ptr}
diff --git a/test/unittest/actions/printf/tst.conv_c.d b/test/unittest/actions/printf/tst.conv_c.d
new file mode 100644
index 00000000..2ac1a13b
--- /dev/null
+++ b/test/unittest/actions/printf/tst.conv_c.d
@@ -0,0 +1,20 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf action supports '%c' for 8-bit character values.
+ *
+ * SECTION: Actions/printf()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	printf("%c", 0x41);
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/tst.conv_d_signed.d b/test/unittest/actions/printf/tst.conv_d_signed.d
new file mode 100644
index 00000000..6774b97e
--- /dev/null
+++ b/test/unittest/actions/printf/tst.conv_d_signed.d
@@ -0,0 +1,20 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf action supports '%d' for signed integers.
+ *
+ * SECTION: Actions/printf()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	printf("%d", (int)-12345);
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/tst.conv_d_unsigned.d b/test/unittest/actions/printf/tst.conv_d_unsigned.d
new file mode 100644
index 00000000..1f5307e3
--- /dev/null
+++ b/test/unittest/actions/printf/tst.conv_d_unsigned.d
@@ -0,0 +1,20 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf action supports '%d' for unsigned integers.
+ *
+ * SECTION: Actions/printf()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+	printf("%d", (uint)-12345);
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/tst.conv_e_double.d b/test/unittest/actions/printf/tst.conv_e_double.d
new file mode 100644
index 00000000..0ce27e03
--- /dev/null
+++ b/test/unittest/actions/printf/tst.conv_e_double.d
@@ -0,0 +1,22 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf action supports '%e' for double floating point values.
+ *
+ * SECTION: Actions/printf()
+ */
+
+#pragma D option quiet
+
+double d;
+
+BEGIN
+{
+	printf("%e", d);
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/tst.conv_e_double.r b/test/unittest/actions/printf/tst.conv_e_double.r
new file mode 100644
index 00000000..36e4eab1
--- /dev/null
+++ b/test/unittest/actions/printf/tst.conv_e_double.r
@@ -0,0 +1 @@
+0.000000e+00
diff --git a/test/unittest/actions/printf/tst.conv_e_float.d b/test/unittest/actions/printf/tst.conv_e_float.d
new file mode 100644
index 00000000..f552757a
--- /dev/null
+++ b/test/unittest/actions/printf/tst.conv_e_float.d
@@ -0,0 +1,22 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf action supports '%e' for floating point values.
+ *
+ * SECTION: Actions/printf()
+ */
+
+#pragma D option quiet
+
+float f;
+
+BEGIN
+{
+	printf("%e", f);
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/tst.conv_e_float.r b/test/unittest/actions/printf/tst.conv_e_float.r
new file mode 100644
index 00000000..36e4eab1
--- /dev/null
+++ b/test/unittest/actions/printf/tst.conv_e_float.r
@@ -0,0 +1 @@
+0.000000e+00
diff --git a/test/unittest/actions/printf/tst.conv_f_double.d b/test/unittest/actions/printf/tst.conv_f_double.d
new file mode 100644
index 00000000..75e4811d
--- /dev/null
+++ b/test/unittest/actions/printf/tst.conv_f_double.d
@@ -0,0 +1,22 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf action supports '%f' for double floating point values.
+ *
+ * SECTION: Actions/printf()
+ */
+
+#pragma D option quiet
+
+double d;
+
+BEGIN
+{
+	printf("%f", d);
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/tst.conv_f_double.r b/test/unittest/actions/printf/tst.conv_f_double.r
new file mode 100644
index 00000000..945da8ff
--- /dev/null
+++ b/test/unittest/actions/printf/tst.conv_f_double.r
@@ -0,0 +1 @@
+0.000000
diff --git a/test/unittest/actions/printf/tst.conv_f_float.d b/test/unittest/actions/printf/tst.conv_f_float.d
new file mode 100644
index 00000000..0b0c3190
--- /dev/null
+++ b/test/unittest/actions/printf/tst.conv_f_float.d
@@ -0,0 +1,22 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf action supports '%f' for floating point values.
+ *
+ * SECTION: Actions/printf()
+ */
+
+#pragma D option quiet
+
+float f;
+
+BEGIN
+{
+	printf("%f", f);
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/tst.conv_f_float.r b/test/unittest/actions/printf/tst.conv_f_float.r
new file mode 100644
index 00000000..945da8ff
--- /dev/null
+++ b/test/unittest/actions/printf/tst.conv_f_float.r
@@ -0,0 +1 @@
+0.000000
diff --git a/test/unittest/actions/printf/tst.conv_g_double.d b/test/unittest/actions/printf/tst.conv_g_double.d
new file mode 100644
index 00000000..a8a063a0
--- /dev/null
+++ b/test/unittest/actions/printf/tst.conv_g_double.d
@@ -0,0 +1,22 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf action supports '%g' for double floating point values.
+ *
+ * SECTION: Actions/printf()
+ */
+
+#pragma D option quiet
+
+double d;
+
+BEGIN
+{
+	printf("%g", d);
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/tst.conv_g_double.r b/test/unittest/actions/printf/tst.conv_g_double.r
new file mode 100644
index 00000000..573541ac
--- /dev/null
+++ b/test/unittest/actions/printf/tst.conv_g_double.r
@@ -0,0 +1 @@
+0
diff --git a/test/unittest/actions/printf/tst.conv_g_float.d b/test/unittest/actions/printf/tst.conv_g_float.d
new file mode 100644
index 00000000..d5eea4e3
--- /dev/null
+++ b/test/unittest/actions/printf/tst.conv_g_float.d
@@ -0,0 +1,22 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: The printf action supports '%g' for floating point values.
+ *
+ * SECTION: Actions/printf()
+ */
+
+#pragma D option quiet
+
+float f;
+
+BEGIN
+{
+	printf("%g", f);
+	exit(0);
+}
diff --git a/test/unittest/actions/printf/tst.conv_g_float.r b/test/unittest/actions/printf/tst.conv_g_float.r
new file mode 100644
index 00000000..573541ac
--- /dev/null
+++ b/test/unittest/actions/printf/tst.conv_g_float.r
@@ -0,0 +1 @@
+0
diff --git a/test/unittest/printf/err.D_PRINTF_AGG_CONV.aggfmt.d b/test/unittest/printf/err.D_PRINTF_AGG_CONV.aggfmt.d
index c803bbf5..0df5614a 100644
--- a/test/unittest/printf/err.D_PRINTF_AGG_CONV.aggfmt.d
+++ b/test/unittest/printf/err.D_PRINTF_AGG_CONV.aggfmt.d
@@ -4,7 +4,6 @@
  * Licensed under the Universal Permissive License v 1.0 as shown at
  * http://oss.oracle.com/licenses/upl.
  */
-/* @@xfail: dtv2 */
 
 /*
  * ASSERTION:
diff --git a/test/unittest/printf/err.D_PRINTF_ARG_EXTRA.toomany.d b/test/unittest/printf/err.D_PRINTF_ARG_EXTRA.toomany.d
index b8958d18..c26a8991 100644
--- a/test/unittest/printf/err.D_PRINTF_ARG_EXTRA.toomany.d
+++ b/test/unittest/printf/err.D_PRINTF_ARG_EXTRA.toomany.d
@@ -4,7 +4,6 @@
  * Licensed under the Universal Permissive License v 1.0 as shown at
  * http://oss.oracle.com/licenses/upl.
  */
-/* @@xfail: dtv2 */
 
 /*
  * ASSERTION:
diff --git a/test/unittest/printf/err.D_PRINTF_ARG_EXTRA.widths.d b/test/unittest/printf/err.D_PRINTF_ARG_EXTRA.widths.d
index 6c885858..d6a1bd32 100644
--- a/test/unittest/printf/err.D_PRINTF_ARG_EXTRA.widths.d
+++ b/test/unittest/printf/err.D_PRINTF_ARG_EXTRA.widths.d
@@ -4,7 +4,6 @@
  * Licensed under the Universal Permissive License v 1.0 as shown at
  * http://oss.oracle.com/licenses/upl.
  */
-/* @@xfail: dtv2 */
 
 /*
  * ASSERTION:
diff --git a/test/unittest/printf/err.D_PRINTF_ARG_PROTO.novalue.d b/test/unittest/printf/err.D_PRINTF_ARG_PROTO.novalue.d
index 264f30a7..394fa3fd 100644
--- a/test/unittest/printf/err.D_PRINTF_ARG_PROTO.novalue.d
+++ b/test/unittest/printf/err.D_PRINTF_ARG_PROTO.novalue.d
@@ -4,7 +4,6 @@
  * Licensed under the Universal Permissive License v 1.0 as shown at
  * http://oss.oracle.com/licenses/upl.
  */
-/* @@xfail: dtv2 */
 
 /*
  * ASSERTION:
diff --git a/test/unittest/printf/err.D_PRINTF_ARG_TYPE.recursive.d b/test/unittest/printf/err.D_PRINTF_ARG_TYPE.recursive.d
index 6688401b..22274202 100644
--- a/test/unittest/printf/err.D_PRINTF_ARG_TYPE.recursive.d
+++ b/test/unittest/printf/err.D_PRINTF_ARG_TYPE.recursive.d
@@ -4,7 +4,6 @@
  * Licensed under the Universal Permissive License v 1.0 as shown at
  * http://oss.oracle.com/licenses/upl.
  */
-/* @@xfail: dtv2 */
 
 /*
  * ASSERTION:
diff --git a/test/unittest/printf/err.D_PRINTF_DYN_PROTO.noprec.d b/test/unittest/printf/err.D_PRINTF_DYN_PROTO.noprec.d
index bcadbd58..9ab1f24e 100644
--- a/test/unittest/printf/err.D_PRINTF_DYN_PROTO.noprec.d
+++ b/test/unittest/printf/err.D_PRINTF_DYN_PROTO.noprec.d
@@ -4,7 +4,6 @@
  * Licensed under the Universal Permissive License v 1.0 as shown at
  * http://oss.oracle.com/licenses/upl.
  */
-/* @@xfail: dtv2 */
 
 /*
  * ASSERTION:
diff --git a/test/unittest/printf/err.D_PRINTF_DYN_PROTO.nowidth.d b/test/unittest/printf/err.D_PRINTF_DYN_PROTO.nowidth.d
index 79070317..6b45f82e 100644
--- a/test/unittest/printf/err.D_PRINTF_DYN_PROTO.nowidth.d
+++ b/test/unittest/printf/err.D_PRINTF_DYN_PROTO.nowidth.d
@@ -4,7 +4,6 @@
  * Licensed under the Universal Permissive License v 1.0 as shown at
  * http://oss.oracle.com/licenses/upl.
  */
-/* @@xfail: dtv2 */
 
 /*
  * ASSERTION:
diff --git a/test/unittest/printf/err.D_PRINTF_DYN_TYPE.badprec.d b/test/unittest/printf/err.D_PRINTF_DYN_TYPE.badprec.d
index 9d3a8e87..8681aa4a 100644
--- a/test/unittest/printf/err.D_PRINTF_DYN_TYPE.badprec.d
+++ b/test/unittest/printf/err.D_PRINTF_DYN_TYPE.badprec.d
@@ -4,7 +4,6 @@
  * Licensed under the Universal Permissive License v 1.0 as shown at
  * http://oss.oracle.com/licenses/upl.
  */
-/* @@xfail: dtv2 */
 
 /*
  * ASSERTION:
diff --git a/test/unittest/printf/err.D_PRINTF_DYN_TYPE.badwidth.d b/test/unittest/printf/err.D_PRINTF_DYN_TYPE.badwidth.d
index dc70454f..a3dd62a3 100644
--- a/test/unittest/printf/err.D_PRINTF_DYN_TYPE.badwidth.d
+++ b/test/unittest/printf/err.D_PRINTF_DYN_TYPE.badwidth.d
@@ -4,7 +4,6 @@
  * Licensed under the Universal Permissive License v 1.0 as shown at
  * http://oss.oracle.com/licenses/upl.
  */
-/* @@xfail: dtv2 */
 
 /*
  * ASSERTION:
diff --git a/test/unittest/printf/err.D_SYNTAX.badconv1.d b/test/unittest/printf/err.D_SYNTAX.badconv1.d
index 98eb22cd..8992112e 100644
--- a/test/unittest/printf/err.D_SYNTAX.badconv1.d
+++ b/test/unittest/printf/err.D_SYNTAX.badconv1.d
@@ -4,7 +4,6 @@
  * Licensed under the Universal Permissive License v 1.0 as shown at
  * http://oss.oracle.com/licenses/upl.
  */
-/* @@xfail: dtv2 */
 
 /*
  * ASSERTION:
diff --git a/test/unittest/printf/err.D_SYNTAX.badconv2.d b/test/unittest/printf/err.D_SYNTAX.badconv2.d
index 19728b14..a2fcc0de 100644
--- a/test/unittest/printf/err.D_SYNTAX.badconv2.d
+++ b/test/unittest/printf/err.D_SYNTAX.badconv2.d
@@ -4,7 +4,6 @@
  * Licensed under the Universal Permissive License v 1.0 as shown at
  * http://oss.oracle.com/licenses/upl.
  */
-/* @@xfail: dtv2 */
 
 /*
  * ASSERTION:
diff --git a/test/unittest/printf/err.D_SYNTAX.badconv3.d b/test/unittest/printf/err.D_SYNTAX.badconv3.d
index 6728e172..61016f22 100644
--- a/test/unittest/printf/err.D_SYNTAX.badconv3.d
+++ b/test/unittest/printf/err.D_SYNTAX.badconv3.d
@@ -4,7 +4,6 @@
  * Licensed under the Universal Permissive License v 1.0 as shown at
  * http://oss.oracle.com/licenses/upl.
  */
-/* @@xfail: dtv2 */
 
 /*
  * ASSERTION:
diff --git a/test/unittest/printf/tst.print-f.d b/test/unittest/printf/tst.print-f.d
deleted file mode 100644
index 37b9cbe3..00000000
--- a/test/unittest/printf/tst.print-f.d
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Oracle Linux DTrace.
- * Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved.
- * Licensed under the Universal Permissive License v 1.0 as shown at
- * http://oss.oracle.com/licenses/upl.
- */
-/* @@xfail: dtv2 */
-
-/*
- * ASSERTION:
- *  Test %f format printing.
- *
- * SECTION: Output Formatting/printf()
- *
- */
-
-#pragma D option quiet
-
-float f;
-double d;
-
-BEGIN
-{
-	printf("\n");
-
-	printf("%%f = %f\n", f);
-	printf("%%f = %f\n", d);
-
-
-	exit(0);
-}
diff --git a/test/unittest/printf/tst.print-f.r b/test/unittest/printf/tst.print-f.r
deleted file mode 100644
index 4d4b8641..00000000
--- a/test/unittest/printf/tst.print-f.r
+++ /dev/null
@@ -1,4 +0,0 @@
-
-%f = 0.000000
-%f = 0.000000
-
diff --git a/test/unittest/printf/tst.printeE.d b/test/unittest/printf/tst.printeE.d
deleted file mode 100644
index 0127350f..00000000
--- a/test/unittest/printf/tst.printeE.d
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Oracle Linux DTrace.
- * Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved.
- * Licensed under the Universal Permissive License v 1.0 as shown at
- * http://oss.oracle.com/licenses/upl.
- */
-/* @@xfail: dtv2 */
-
-/*
- * ASSERTION:
- *  Test %e, %E format printing.
- *
- * SECTION: Output Formatting/printf()
- *
- */
-
-#pragma D option quiet
-
-float f;
-double d;
-
-BEGIN
-{
-	printf("\n");
-
-	printf("%%e = %e\n", f);
-	printf("%%E = %E\n", f);
-
-	printf("%%e = %e\n", d);
-	printf("%%E = %E\n", d);
-
-
-	exit(0);
-}
diff --git a/test/unittest/printf/tst.printeE.r b/test/unittest/printf/tst.printeE.r
deleted file mode 100644
index 3fa96bc2..00000000
--- a/test/unittest/printf/tst.printeE.r
+++ /dev/null
@@ -1,6 +0,0 @@
-
-%e = 0.000000e+00
-%E = 0.000000E+00
-%e = 0.000000e+00
-%E = 0.000000E+00
-
diff --git a/test/unittest/printf/tst.printgG.d b/test/unittest/printf/tst.printgG.d
deleted file mode 100644
index 6f4c29c2..00000000
--- a/test/unittest/printf/tst.printgG.d
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Oracle Linux DTrace.
- * Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved.
- * Licensed under the Universal Permissive License v 1.0 as shown at
- * http://oss.oracle.com/licenses/upl.
- */
-/* @@xfail: dtv2 */
-
-/*
- * ASSERTION:
- *  Test %g, %G format printing.
- *
- * SECTION: Output Formatting/printf()
- *
- */
-
-#pragma D option quiet
-
-float f;
-double d;
-
-BEGIN
-{
-	printf("\n");
-
-	printf("%%g = %g\n", f);
-	printf("%%g = %g\n", d);
-
-	printf("%%G = %G\n", f);
-	printf("%%G = %G\n", d);
-
-
-	exit(0);
-}
diff --git a/test/unittest/printf/tst.printgG.r b/test/unittest/printf/tst.printgG.r
deleted file mode 100644
index e4175e64..00000000
--- a/test/unittest/printf/tst.printgG.r
+++ /dev/null
@@ -1,6 +0,0 @@
-
-%g = 0
-%g = 0
-%G = 0
-%G = 0
-
-- 
2.26.0




More information about the DTrace-devel mailing list