[PATCH 2/2] cg: transition [u]stack() from action to subroutine

Kris Van Hees <[email protected]>
Newsgroups dev.linux.lists.dtrace
Message-ID <SJ0PR10MB567238538078DC5066122BECC21DA@SJ0PR10MB5672.namprd10.prod.outlook.com>
In order to allow [u]stack() to be used in expressions, they must be
subroutines.  An exception is added to allow them to retain their
original behaviour as data recording actions as well.

The implementation change requires a new internal type to be defined
(dt_stack) to hold stack trace data.

This patch does not allow [u]stack() to be used in assignments to
variables just yet, but it supports all previous uses of [u]stack().
Additional functionality will be added on top of this.

Signed-off-by: Kris Van Hees <[email protected]>
---
 include/dtrace/dif_defines.h                  |   4 +-
 libdtrace/dt_cg.c                             | 343 ++++++++++++------
 libdtrace/dt_open.c                           |  21 +-
 libdtrace/dt_options.c                        |  42 ++-
 libdtrace/dt_printf.c                         |   3 +-
 test/unittest/funcs/tst.subr.d                |  11 +
 .../printa/err.D_PRINTF_ARG_TYPE.stack.r      |   2 +-
 .../printa/err.D_PRINTF_ARG_TYPE.ustack.r     |   2 +-
 8 files changed, 313 insertions(+), 115 deletions(-)

diff --git a/include/dtrace/dif_defines.h b/include/dtrace/dif_defines.h
index 9f6e3b55..6e412247 100644
--- a/include/dtrace/dif_defines.h
+++ b/include/dtrace/dif_defines.h
@@ -210,8 +210,10 @@
 #define DIF_SUBR_INET_NTOA6		43
 #define DIF_SUBR_D_PATH			44
 #define DIF_SUBR_LINK_NTOP		45
+#define DIF_SUBR_STACK			46
+#define DIF_SUBR_USTACK			47
 
-#define DIF_SUBR_MAX			45
+#define DIF_SUBR_MAX			47
 
 typedef uint32_t	dif_instr_t;
 
diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
index 2b81f2e0..3eda5873 100644
--- a/libdtrace/dt_cg.c
+++ b/libdtrace/dt_cg.c
@@ -3907,33 +3907,42 @@ dt_cg_arglist(dt_ident_t *idp, dt_node_t *args, dt_irlist_t *dlp,
 			longjmp(yypcb->pcb_jmpbuf, EDT_NOTUPREG);
 
 		/*
-		 * Handle actions that can be used as agg keys.
-		 * If we are not an aggregation, dt_cg_node(dnp, ...)
-		 * will alert us there is a problem.
+		 * Some function calls (actions or subroutines) need special
+		 * handling.
 		 */
-		if (idp->di_kind == DT_IDENT_AGG &&
-		    dnp->dn_kind == DT_NODE_FUNC &&
-		    dnp->dn_ident != NULL)
-			switch (dnp->dn_ident->di_id) {
-			case DT_ACT_STACK:
-			case DT_ACT_USTACK:
-				/* If this is a stack()-like function, we can handle it later. */
-				dt_cg_push_stack(BPF_REG_FP, dlp, drp);
-				continue;
-			case DT_ACT_JSTACK:
-				dnerror(dnp, D_UNKNOWN, "jstack() is not implemented (yet)\n");
-				/* FIXME: Needs implementation */
-			case DT_ACT_SYM:
-			case DT_ACT_MOD:
-			case DT_ACT_UADDR:
-			case DT_ACT_UMOD:
-			case DT_ACT_USYM:
-				/* Otherwise, use the action's arg, not its "return value". */
-				dt_cg_node(dnp->dn_args, dlp, drp);
-				dt_cg_push_stack(dnp->dn_args->dn_reg, dlp, drp);
-				dt_regset_free(drp, dnp->dn_args->dn_reg);
-				continue;
+		if (dnp->dn_kind == DT_NODE_FUNC) {
+			dt_ident_t	*fidp = dnp->dn_ident;
+
+			assert(fidp != NULL);
+
+			/*
+			 * For subroutines, stack() and ustack() don't need to
+			 * be evaluated until we fill in the data of the tuple.
+			 */
+			if (fidp->di_kind == DT_IDENT_FUNC) {
+				if (fidp->di_id == DIF_SUBR_STACK ||
+				    fidp->di_id == DIF_SUBR_USTACK) {
+					dt_cg_push_stack(BPF_REG_FP, dlp, drp);
+					continue;
+				}
+			} else if (fidp->di_kind == DT_IDENT_ACTFUNC) {
+				switch (fidp->di_id) {
+				case DT_ACT_JSTACK:
+					dnerror(dnp, D_UNKNOWN, "jstack() is not implemented (yet)\n");
+					/* FIXME: Needs implementation */
+				case DT_ACT_SYM:
+				case DT_ACT_MOD:
+				case DT_ACT_UADDR:
+				case DT_ACT_UMOD:
+				case DT_ACT_USYM:
+					/* Otherwise, use the action's arg, not its "return value". */
+					dt_cg_node(dnp->dn_args, dlp, drp);
+					dt_cg_push_stack(dnp->dn_args->dn_reg, dlp, drp);
+					dt_regset_free(drp, dnp->dn_args->dn_reg);
+					continue;
+				}
 			}
+		}
 
 		/* Push the component (pointer or value) onto the tuple stack. */
 		dt_cg_node(dnp, dlp, drp);
@@ -3987,50 +3996,63 @@ empty_args:
 		uint_t			nextoff;
 		int			is_symmod = 0;
 
-		if (dnp->dn_kind == DT_NODE_FUNC &&
-		    dnp->dn_ident != NULL)
-			switch (dnp->dn_ident->di_id) {
-			case DT_ACT_STACK:
-				tuplesize = dt_cg_act_stack_sub(yypcb, dnp, treg, tuplesize, DTRACEACT_STACK);
-				continue;
-			case DT_ACT_USTACK:
-				tuplesize = dt_cg_act_stack_sub(yypcb, dnp, treg, tuplesize, DTRACEACT_USTACK);
-				continue;
-			case DT_ACT_UADDR:
-			case DT_ACT_USYM:
-			case DT_ACT_UMOD:
-				nextoff = (tuplesize + (8 - 1)) & ~(8 - 1);
-				if (tuplesize < nextoff)
-					emit(dlp,  BPF_ALU64_IMM(BPF_ADD, treg, nextoff - tuplesize));
-
-				/* Preface the value with the user process pid. */
-				if (dt_regset_xalloc_args(drp) == -1)
-					longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
-				dt_regset_xalloc(drp, BPF_REG_0);
-				emit(dlp, BPF_CALL_HELPER(BPF_FUNC_get_current_pid_tgid));
-				dt_regset_free_args(drp);
-				emit(dlp, BPF_ALU64_IMM(BPF_RSH, BPF_REG_0, 32));
-				emit(dlp, BPF_STORE(BPF_DW, treg, 0, BPF_REG_0));
-				dt_regset_free(drp, BPF_REG_0);
-
-				/* Then store the value. */
-				dt_regset_xalloc(drp, BPF_REG_0);
-				emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, areg, -i * DT_STK_SLOT_SZ));
-				emit(dlp,  BPF_STORE(BPF_DW, treg, 8, BPF_REG_0));
-				dt_regset_free(drp, BPF_REG_0);
-
-				emit(dlp,  BPF_ALU64_IMM(BPF_ADD, treg, 16));
-				tuplesize = nextoff + 16;
-
-				continue;
-			case DT_ACT_SYM:
-			case DT_ACT_MOD:
-				is_symmod = 1;
-				size = 8;
-				dt_regset_xalloc(drp, BPF_REG_0);
-				emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, areg, -i * DT_STK_SLOT_SZ));
-				break;
+		if (dnp->dn_kind == DT_NODE_FUNC) {
+			dt_ident_t	*fidp = dnp->dn_ident;
+
+			if (fidp->di_kind == DT_IDENT_FUNC) {
+				switch (fidp->di_id) {
+				case DIF_SUBR_STACK:
+					tuplesize = dt_cg_act_stack_sub(
+							yypcb, dnp, treg,
+							tuplesize,
+							DTRACEACT_STACK);
+					continue;
+				case DIF_SUBR_USTACK:
+					tuplesize = dt_cg_act_stack_sub(
+							yypcb, dnp, treg,
+							tuplesize,
+							DTRACEACT_USTACK);
+					continue;
+				}
+			} else if (fidp->di_kind == DT_IDENT_ACTFUNC) {
+				switch (dnp->dn_ident->di_id) {
+				case DT_ACT_UADDR:
+				case DT_ACT_USYM:
+				case DT_ACT_UMOD:
+					nextoff = ALIGN(tuplesize, 8);
+					if (tuplesize < nextoff)
+						emit(dlp,  BPF_ALU64_IMM(BPF_ADD, treg, nextoff - tuplesize));
+
+					/* Preface the value with the user process pid. */
+					if (dt_regset_xalloc_args(drp) == -1)
+						longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
+					dt_regset_xalloc(drp, BPF_REG_0);
+					emit(dlp, BPF_CALL_HELPER(BPF_FUNC_get_current_pid_tgid));
+					dt_regset_free_args(drp);
+					emit(dlp, BPF_ALU64_IMM(BPF_RSH, BPF_REG_0, 32));
+					emit(dlp, BPF_STORE(BPF_DW, treg, 0, BPF_REG_0));
+					dt_regset_free(drp, BPF_REG_0);
+
+					/* Then store the value. */
+					dt_regset_xalloc(drp, BPF_REG_0);
+					emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, areg, -i * DT_STK_SLOT_SZ));
+					emit(dlp,  BPF_STORE(BPF_DW, treg, 8, BPF_REG_0));
+					dt_regset_free(drp, BPF_REG_0);
+
+					emit(dlp,  BPF_ALU64_IMM(BPF_ADD, treg, 16));
+					tuplesize = nextoff + 16;
+
+					continue;
+				case DT_ACT_SYM:
+				case DT_ACT_MOD:
+					is_symmod = 1;
+					size = 8;
+					dt_regset_xalloc(drp, BPF_REG_0);
+					emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, areg, -i * DT_STK_SLOT_SZ));
+					break;
+				}
 			}
+		}
 
 		if (!is_symmod) {
 			dt_node_diftype(dtp, dnp, &t);
@@ -6322,6 +6344,84 @@ dt_cg_subr_strchr(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
 	TRACE_REGSET("    subr-strchr:End  ");
 }
 
+static void
+dt_cg_subr_stack(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
+{
+	dtrace_hdl_t	*dtp = yypcb->pcb_hdl;
+	dt_node_t	*size = dnp->dn_args;
+	dt_node_t	asize;
+	int		nframes = dtp->dt_options[DTRACEOPT_MAXFRAMES];
+
+	TRACE_REGSET("    subr-stack:Begin");
+
+	if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1)
+		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
+
+	/*
+	 * Allocate enough scratch space to hold the maximum stacktrace size.
+	 * Since dt_cg_subr_alloca_impl() requires a node to be passed for the
+	 * allocation size, one is created here based on the stacktrace size.
+	 */
+	asize.dn_op = DT_TOK_INT;
+	asize.dn_kind = DT_NODE_INT;
+	asize.dn_value = (size ? size->dn_value : nframes) * sizeof(uint64_t);
+	dt_cg_node(&asize, dlp, drp);
+	dt_cg_subr_alloca_impl(dnp, &asize, dlp, drp);
+	dt_regset_free(drp, asize.dn_reg);
+	asize.dn_reg = -1;
+	/* Push the native alloca value to be used as return value. */
+	dt_cg_push_stack(dnp->dn_reg, dlp, drp);
+	/* Turn it into a proper alloca pointer. */
+	dt_cg_alloca_ptr(dlp, drp, dnp->dn_reg, dnp->dn_reg);
+
+	/* Call the stack helper function to collect the stack. */
+	dt_cg_act_stack_sub(yypcb, dnp, dnp->dn_reg, 0, DTRACEACT_STACK);
+
+	/* Pop the native alloca value as return value. */
+	dt_cg_pop_stack(dnp->dn_reg, dlp, drp);
+
+	TRACE_REGSET("    subr-stack:End  ");
+}
+
+static void
+dt_cg_subr_ustack(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
+{
+	dtrace_hdl_t	*dtp = yypcb->pcb_hdl;
+	dt_node_t	*size = dnp->dn_args;
+	dt_node_t	asize;
+	int		nframes = dtp->dt_options[DTRACEOPT_MAXFRAMES];
+
+	TRACE_REGSET("    subr-ustack:Begin");
+
+	if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1)
+		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
+
+	/*
+	 * Allocate enough scratch space to hold the maximum stacktrace size.
+	 * Since dt_cg_subr_alloca_impl() requires a node to be passed for the
+	 * allocation size, one is created here based on the stacktrace size.
+	 */
+	asize.dn_op = DT_TOK_INT;
+	asize.dn_kind = DT_NODE_INT;
+	asize.dn_value = (size ? size->dn_value : nframes) * sizeof(uint64_t);
+	dt_cg_node(&asize, dlp, drp);
+	dt_cg_subr_alloca_impl(dnp, &asize, dlp, drp);
+	dt_regset_free(drp, asize.dn_reg);
+	asize.dn_reg = -1;
+	/* Push the native alloca value to be used as return value. */
+	dt_cg_push_stack(dnp->dn_reg, dlp, drp);
+	/* Turn it into a proper alloca pointer. */
+	dt_cg_alloca_ptr(dlp, drp, dnp->dn_reg, dnp->dn_reg);
+
+	/* Call the stack helper function to collect the stack. */
+	dt_cg_act_stack_sub(yypcb, dnp, dnp->dn_reg, 0, DTRACEACT_USTACK);
+
+	/* Pop the native alloca value as return value. */
+	dt_cg_pop_stack(dnp->dn_reg, dlp, drp);
+
+	TRACE_REGSET("    subr-ustack:End  ");
+}
+
 static void
 dt_cg_subr_strrchr(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
 {
@@ -6951,6 +7051,8 @@ static dt_cg_subr_f *_dt_cg_subr[DIF_SUBR_MAX + 1] = {
 	[DIF_SUBR_INET_NTOA6]		= &dt_cg_subr_inet_ntoa6,
 	[DIF_SUBR_D_PATH]		= &dt_cg_subr_d_path,
 	[DIF_SUBR_LINK_NTOP]		= &dt_cg_subr_link_ntop,
+	[DIF_SUBR_STACK]		= &dt_cg_subr_stack,
+	[DIF_SUBR_USTACK]		= &dt_cg_subr_ustack,
 };
 
 static void
@@ -6968,6 +7070,7 @@ dt_cg_call_subr(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
 	assert(idp->di_id <= DIF_SUBR_MAX);
 
 	fun = _dt_cg_subr[idp->di_id];
+assert(fun != NULL);
 	if (fun == NULL)
 		dnerror(dnp, D_FUNC_UNDEF, "unimplemented subroutine: %s\n",
 			idp->di_name);
@@ -8690,43 +8793,50 @@ dt_cg_agg(dt_pcb_t *pcb, dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
 			uint64_t arg = 0;
 			dt_ident_t *idp = knp->dn_ident;
 
-			if (knp->dn_kind == DT_NODE_FUNC && idp != NULL &&
-			    idp->di_kind == DT_IDENT_ACTFUNC) {
-				size = 16;
+			if (knp->dn_kind == DT_NODE_FUNC && idp != NULL) {
 				alignment = 8;
-				switch (idp->di_id) {
-				case DT_ACT_USTACK:
-					arg = dt_cg_stack_arg(dtp, knp, DTRACEACT_USTACK);
-					kind = DTRACEACT_USTACK;
-					size = 8 + 8 * DTRACE_STACK_NFRAMES(arg);
-					break;
-				case DT_ACT_JSTACK:
-					kind = DTRACEACT_JSTACK;
-					break;
-				case DT_ACT_USYM:
-					kind = DTRACEACT_USYM;
-					break;
-				case DT_ACT_UMOD:
-					kind = DTRACEACT_UMOD;
-					break;
-				case DT_ACT_UADDR:
-					kind = DTRACEACT_UADDR;
-					break;
-				case DT_ACT_STACK:
-					arg = dt_cg_stack_arg(dtp, knp, DTRACEACT_STACK);
-					kind = DTRACEACT_STACK;
-					size = 8 * arg;
-					break;
-				case DT_ACT_SYM:
-					kind = DTRACEACT_SYM;
-					size = 8;
-					break;
-				case DT_ACT_MOD:
-					kind = DTRACEACT_MOD;
-					size = 8;
-					break;
+
+				if (idp->di_kind == DT_IDENT_FUNC) {
+					switch (idp->di_id) {
+					case DIF_SUBR_USTACK:
+						arg = dt_cg_stack_arg(dtp, knp, DTRACEACT_USTACK);
+						kind = DTRACEACT_USTACK;
+						size = 8 + 8 * DTRACE_STACK_NFRAMES(arg);
+						goto add_rec;
+					case DIF_SUBR_STACK:
+						arg = dt_cg_stack_arg(dtp, knp, DTRACEACT_STACK);
+						kind = DTRACEACT_STACK;
+						size = 8 * arg;
+						goto add_rec;
+					}
+				} else if (idp->di_kind == DT_IDENT_ACTFUNC) {
+					size = 16;
+					switch (idp->di_id) {
+					case DT_ACT_JSTACK:
+						kind = DTRACEACT_JSTACK;
+						goto add_rec;
+					case DT_ACT_USYM:
+						kind = DTRACEACT_USYM;
+						goto add_rec;
+					case DT_ACT_UMOD:
+						kind = DTRACEACT_UMOD;
+						goto add_rec;
+					case DT_ACT_UADDR:
+						kind = DTRACEACT_UADDR;
+						goto add_rec;
+					case DT_ACT_SYM:
+						kind = DTRACEACT_SYM;
+						size = 8;
+						goto add_rec;
+					case DT_ACT_MOD:
+						kind = DTRACEACT_MOD;
+						size = 8;
+						goto add_rec;
+					}
 				}
-			} else if (dt_node_is_string(knp)) {
+			}
+
+			if (dt_node_is_string(knp)) {
 				size = dtp->dt_options[DTRACEOPT_STRSIZE] + 1;
 				alignment = 1;
 			} else {
@@ -8737,6 +8847,7 @@ dt_cg_agg(dt_pcb_t *pcb, dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
 				alignment = size;
 			}
 
+add_rec:
 			dt_aggid_rec_add(dtp, aid->di_id, kind, size, alignment, arg);
 		}
 	}
@@ -8820,10 +8931,34 @@ dt_cg(dt_pcb_t *pcb, dt_node_t *dnp)
 				if (enp->dn_kind == DT_NODE_AGG)
 					dt_cg_agg(pcb, enp, &pcb->pcb_ir,
 						  pcb->pcb_regs);
-				else
+				else {
+					/*
+					 * Special case: [u]stack() in statement
+					 * context is treated as data generating
+					 * action.
+					 */
+					if (enp->dn_kind == DT_NODE_FUNC) {
+						uint_t	id;
+
+						id = enp->dn_ident->di_id;
+						if (id == DIF_SUBR_STACK)
+							id = DTRACEACT_STACK;
+						else if (id == DIF_SUBR_USTACK)
+							id = DTRACEACT_USTACK;
+						else
+							id = 0;
+
+						if (id) {
+							dt_cg_act_stack(pcb, enp, id);
+							pcb->pcb_stmt->dtsd_clauseflags |= DT_CLSFLAG_DATAREC;
+							goto done;
+						}
+					}
 					dt_cg_node(enp, &pcb->pcb_ir,
 						   pcb->pcb_regs);
+				}
 
+done:
 				if (enp->dn_reg != -1) {
 					dt_regset_free(pcb->pcb_regs,
 						       enp->dn_reg);
diff --git a/libdtrace/dt_open.c b/libdtrace/dt_open.c
index 509f263d..9dd8956d 100644
--- a/libdtrace/dt_open.c
+++ b/libdtrace/dt_open.c
@@ -175,7 +175,7 @@ static const dt_ident_t _dtrace_globals[] = {
 { "ipl", DT_IDENT_SCALAR, 0, DIF_VAR_IPL, DT_ATTR_STABCMN, DT_VERS_1_0,
 	&dt_idops_type, "uint_t" },
 { "jstack", DT_IDENT_ACTFUNC, 0, DT_ACT_JSTACK, DT_ATTR_STABCMN, DT_VERS_1_0,
-	&dt_idops_func, "stack([uint32_t], [uint32_t])" },
+	&dt_idops_func, "dt_stack([uint32_t], [uint32_t])" },
 { "link_ntop", DT_IDENT_FUNC, 0, DIF_SUBR_LINK_NTOP, DT_ATTR_STABCMN,
 	DT_VERS_1_5, &dt_idops_func, "string(int, void *)" },
 { "llquantize", DT_IDENT_AGGFUNC, 0, DT_AGG_LLQUANTIZE,
@@ -273,8 +273,8 @@ static const dt_ident_t _dtrace_globals[] = {
 { "speculation", DT_IDENT_FUNC, 0, DIF_SUBR_SPECULATION,
 	DT_ATTR_STABCMN, DT_VERS_1_0,
 	&dt_idops_func, "int()" },
-{ "stack", DT_IDENT_ACTFUNC, 0, DT_ACT_STACK, DT_ATTR_STABCMN, DT_VERS_1_0,
-	&dt_idops_func, "stack([uint32_t])" },
+{ "stack", DT_IDENT_FUNC, DT_IDFLG_ALLOCA, DIF_SUBR_STACK, DT_ATTR_STABCMN,
+	DT_VERS_1_0, &dt_idops_func, "dt_stack([uint32_t])" },
 { "stackdepth", DT_IDENT_SCALAR, 0, DIF_VAR_STACKDEPTH,
 	DT_ATTR_STABCMN, DT_VERS_1_0,
 	&dt_idops_type, "uint32_t" },
@@ -328,8 +328,8 @@ static const dt_ident_t _dtrace_globals[] = {
 	DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" },
 { "uregs", DT_IDENT_ARRAY, 0, DIF_VAR_UREGS, DT_ATTR_STABCMN, DT_VERS_1_0,
 	&dt_idops_regs, NULL },
-{ "ustack", DT_IDENT_ACTFUNC, 0, DT_ACT_USTACK, DT_ATTR_STABCMN, DT_VERS_1_0,
-	&dt_idops_func, "stack([uint32_t], [uint32_t])" },
+{ "ustack", DT_IDENT_FUNC, DT_IDFLG_ALLOCA, DIF_SUBR_USTACK, DT_ATTR_STABCMN,
+	DT_VERS_1_0, &dt_idops_func, "dt_stack([uint32_t], [uint32_t])" },
 { "ustackdepth", DT_IDENT_SCALAR, 0, DIF_VAR_USTACKDEPTH,
 	DT_ATTR_STABCMN, DT_VERS_1_2,
 	&dt_idops_type, "uint32_t" },
@@ -1054,8 +1054,17 @@ dt_vopen(int version, int flags, int *errp,
 	dtp->dt_type_dyn = ctf_add_typedef(dmp->dm_ctfp, CTF_ADD_ROOT,
 	    "<DYN>", ctf_lookup_by_name(dmp->dm_ctfp, "void"));
 
+	/*
+	 * The stack type is added as a typedef of uint64_t[MAXFRAMES].  The
+	 * final value of MAXFRAMES may be adjusted with the "stackframes"
+	 * option.
+	 */
+	ctr.ctr_contents = ctf_lookup_by_name(dmp->dm_ctfp, "uint64_t");
+	ctr.ctr_index = ctf_lookup_by_name(dmp->dm_ctfp, "long");
+	ctr.ctr_nelems = _dtrace_stackframes;
+
 	dtp->dt_type_stack = ctf_add_typedef(dmp->dm_ctfp, CTF_ADD_ROOT,
-	    "stack", ctf_lookup_by_name(dmp->dm_ctfp, "void"));
+		"dt_stack", ctf_add_array(dmp->dm_ctfp, CTF_ADD_ROOT, &ctr));
 
 	dtp->dt_type_symaddr = ctf_add_typedef(dmp->dm_ctfp, CTF_ADD_ROOT,
 	    "_symaddr", ctf_lookup_by_name(dmp->dm_ctfp, "void"));
diff --git a/libdtrace/dt_options.c b/libdtrace/dt_options.c
index 25e79979..69667f5b 100644
--- a/libdtrace/dt_options.c
+++ b/libdtrace/dt_options.c
@@ -912,6 +912,46 @@ dt_opt_rate(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
 	return 0;
 }
 
+/*
+ * When setting the maxframes option, set the option in the dt_options array
+ * using dt_opt_runtime() as usual, and then update the definition of the CTF
+ * type for "_stack" to be an array of the corresponding size.
+ * If any errors occur, reset dt_options[option] to its previous value.
+ */
+static int
+dt_opt_maxframes(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
+{
+	dtrace_optval_t val = dtp->dt_options[option];
+	ctf_file_t *fp = DT_STACK_CTFP(dtp);
+	ctf_id_t type = ctf_type_resolve(fp, DT_STACK_TYPE(dtp));
+	ctf_arinfo_t r;
+
+	if (dt_opt_runtime(dtp, arg, option) != 0)
+		return -1; /* dt_errno is set for us */
+
+	if (dtp->dt_options[option] > UINT_MAX) {
+		dtp->dt_options[option] = val;
+		return dt_set_errno(dtp, EOVERFLOW);
+	}
+
+	if (ctf_array_info(fp, type, &r) == CTF_ERR) {
+		dtp->dt_options[option] = val;
+		dtp->dt_ctferr = ctf_errno(fp);
+		return dt_set_errno(dtp, EDT_CTF);
+	}
+
+	r.ctr_nelems = (uint_t)dtp->dt_options[option];
+
+	if (ctf_set_array(fp, type, &r) == CTF_ERR ||
+	    ctf_update(fp) == CTF_ERR) {
+		dtp->dt_options[option] = val;
+		dtp->dt_ctferr = ctf_errno(fp);
+		return dt_set_errno(dtp, EDT_CTF);
+	}
+
+	return 0;
+}
+
 /*
  * When setting the strsize option, set the option in the dt_options array
  * using dt_opt_size() as usual, and then update the definition of the CTF
@@ -1157,7 +1197,7 @@ static const dt_option_t _dtrace_rtoptions[] = {
 	{ "jstackframes", dt_opt_runtime, DTRACEOPT_JSTACKFRAMES },
 	{ "jstackstrsize", dt_opt_size, DTRACEOPT_JSTACKSTRSIZE },
 	{ "lockmem", dt_opt_lockmem, DTRACEOPT_LOCKMEM },
-	{ "maxframes", dt_opt_runtime, DTRACEOPT_MAXFRAMES },
+	{ "maxframes", dt_opt_maxframes, DTRACEOPT_MAXFRAMES },
 	{ "nusdtprobes", dt_opt_runtime, DTRACEOPT_NUSDTPROBES },
 	{ "nspec", dt_opt_runtime, DTRACEOPT_NSPEC },
 	{ "pcapsize", dt_opt_pcapsize, DTRACEOPT_PCAPSIZE },
diff --git a/libdtrace/dt_printf.c b/libdtrace/dt_printf.c
index 4c276c26..06c86a37 100644
--- a/libdtrace/dt_printf.c
+++ b/libdtrace/dt_printf.c
@@ -24,7 +24,8 @@
 static int
 pfcheck_addr(dt_pfargv_t *pfv, dt_pfargd_t *pfd, dt_node_t *dnp)
 {
-	return dt_node_is_pointer(dnp) || dt_node_is_integer(dnp);
+	return (dt_node_is_pointer(dnp) && !dt_node_is_stack(dnp)) ||
+	       dt_node_is_integer(dnp);
 }
 
 /*ARGSUSED*/
diff --git a/test/unittest/funcs/tst.subr.d b/test/unittest/funcs/tst.subr.d
index 9f7203c0..20e38341 100644
--- a/test/unittest/funcs/tst.subr.d
+++ b/test/unittest/funcs/tst.subr.d
@@ -36,6 +36,15 @@
 	/*DSTYLED*/			\
 	}
 
+#define STKFUNC(x)			\
+	BEGIN				\
+	/*DSTYLED*/			\
+	{				\
+		subr++;			\
+		@stk[x] = sum(1);	\
+	/*DSTYLED*/			\
+	}
+
 #define NUM_UNIMPLEMENTED 7
 
 INTFUNC(rand())
@@ -89,6 +98,8 @@ STRFUNC(inet_ntoa6((in6_addr_t *)alloca(sizeof(in6_addr_t))))
 /* Not implemented yet.
    STRFUNC(d_path(&(curthread->fs->root)))
    STRFUNC(link_ntop(ARPHRD_ETHER, (void *)alloca(sizeof(ipaddr_t)))) */
+STKFUNC(stack(5))
+STKFUNC(ustack(5))
 
 BEGIN
 /subr == DIF_SUBR_MAX + 1 - NUM_UNIMPLEMENTED/
diff --git a/test/unittest/printa/err.D_PRINTF_ARG_TYPE.stack.r b/test/unittest/printa/err.D_PRINTF_ARG_TYPE.stack.r
index 50e884a0..95ac80da 100644
--- a/test/unittest/printa/err.D_PRINTF_ARG_TYPE.stack.r
+++ b/test/unittest/printa/err.D_PRINTF_ARG_TYPE.stack.r
@@ -2,4 +2,4 @@
 dtrace: failed to compile script test/unittest/printa/err.D_PRINTF_ARG_TYPE.stack.d: [D_PRINTF_ARG_TYPE] line 12: printa( ) argument #2 is incompatible with conversion #1 prototype:
 	conversion: %p
 	 prototype: pointer or integer
-	  argument: stack
+	  argument: dt_stack
diff --git a/test/unittest/printa/err.D_PRINTF_ARG_TYPE.ustack.r b/test/unittest/printa/err.D_PRINTF_ARG_TYPE.ustack.r
index fc9e1512..5df10376 100644
--- a/test/unittest/printa/err.D_PRINTF_ARG_TYPE.ustack.r
+++ b/test/unittest/printa/err.D_PRINTF_ARG_TYPE.ustack.r
@@ -2,4 +2,4 @@
 dtrace: failed to compile script test/unittest/printa/err.D_PRINTF_ARG_TYPE.ustack.d: [D_PRINTF_ARG_TYPE] line 12: printa( ) argument #2 is incompatible with conversion #1 prototype:
 	conversion: %p
 	 prototype: pointer or integer
-	  argument: stack
+	  argument: dt_stack
-- 
2.43.5
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.