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

Kris Van Hees kris.van.hees at oracle.com
Tue Sep 23 16:01:32 UTC 2025


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 <kris.van.hees at oracle.com>
---
 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




More information about the DTrace-devel mailing list