[DTrace-devel] [PATCH] WIP Implement the printf action (and related actions)

Kris Van Hees kris.van.hees at oracle.com
Mon May 18 10:44:10 PDT 2020


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".

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

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 +
 .../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 -
 86 files changed, 886 insertions(+), 25 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

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 e5d3ac73..f5d96652 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 act)
+dt_cg_store_val(dt_pcb_t *pcb, dt_node_t *dnp, dtrace_actkind_t kind,
+		dt_pfargv_t *pfp, int act)
 {
 	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 act)
 		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,
 				 act);
 
 		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..7934f626
--- /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..518d063e
--- /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..990b067b
--- /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/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:
-- 
2.26.0




More information about the DTrace-devel mailing list