[DTrace-devel] [PATCH v2 4/6] procfs: implement d_execargs() for pr_psargs translator support

Kris Van Hees kris.van.hees at oracle.com
Wed Jan 29 07:00:20 UTC 2025


Implement d_execargs() to provide task argument string (pr_psargs)
for the psinfo translator.  It takes a task (struct task_struct) as
argument and returns a string.

psinfo->pr_psargs now simply calls d_execargs(T).

Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
---
 bpf/Build                                     |  1 +
 bpf/d_execargs.S                              | 91 +++++++++++++++++++
 dlibs/aarch64/5.11/procfs.d                   |  4 +-
 dlibs/aarch64/5.12/procfs.d                   |  4 +-
 dlibs/aarch64/5.14/procfs.d                   |  4 +-
 dlibs/aarch64/5.16/procfs.d                   |  4 +-
 dlibs/aarch64/5.2/procfs.d                    |  4 +-
 dlibs/aarch64/5.6/procfs.d                    |  4 +-
 dlibs/aarch64/6.1/procfs.d                    |  4 +-
 dlibs/aarch64/6.10/procfs.d                   |  4 +-
 dlibs/x86_64/5.11/procfs.d                    |  4 +-
 dlibs/x86_64/5.12/procfs.d                    |  4 +-
 dlibs/x86_64/5.14/procfs.d                    |  4 +-
 dlibs/x86_64/5.16/procfs.d                    |  4 +-
 dlibs/x86_64/5.2/procfs.d                     |  4 +-
 dlibs/x86_64/5.6/procfs.d                     |  4 +-
 dlibs/x86_64/6.1/procfs.d                     |  4 +-
 dlibs/x86_64/6.10/procfs.d                    |  4 +-
 include/dtrace/dif_defines.h                  |  7 +-
 libdtrace/dt_bpf.h                            | 21 +++--
 libdtrace/dt_cc.c                             | 33 ++++++-
 libdtrace/dt_cg.c                             |  9 +-
 libdtrace/dt_dlibs.c                          |  3 +
 libdtrace/dt_open.c                           |  2 +
 libdtrace/procfs.d.in                         |  4 +-
 .../d_execargs/err.D_PROTO_ARG.scalar_arg.d   | 16 ++++
 .../d_execargs/err.D_PROTO_ARG.scalar_arg.r   |  4 +
 .../d_execargs/err.D_PROTO_ARG.string_arg.d   | 16 ++++
 .../d_execargs/err.D_PROTO_ARG.string_arg.r   |  4 +
 .../d_execargs/err.D_PROTO_ARG.wrong_ptr.d    | 16 ++++
 .../d_execargs/err.D_PROTO_ARG.wrong_ptr.r    |  4 +
 .../d_execargs/err.D_PROTO_LEN.missing_arg.d  | 16 ++++
 .../d_execargs/err.D_PROTO_LEN.missing_arg.r  |  2 +
 .../err.D_PROTO_LEN.too_many_args.d           | 16 ++++
 .../err.D_PROTO_LEN.too_many_args.r           |  2 +
 .../funcs/d_execargs/tst.d_execargs.d         | 31 +++++++
 .../funcs/d_execargs/tst.d_execargs.r         |  2 +
 test/unittest/proc/tst.pr_psargs.d            | 31 +++++++
 test/unittest/proc/tst.pr_psargs.r            |  9 ++
 39 files changed, 339 insertions(+), 65 deletions(-)
 create mode 100644 bpf/d_execargs.S
 create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.d
 create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.r
 create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.d
 create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.r
 create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.d
 create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.r
 create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.d
 create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.r
 create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.d
 create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.r
 create mode 100644 test/unittest/funcs/d_execargs/tst.d_execargs.d
 create mode 100644 test/unittest/funcs/d_execargs/tst.d_execargs.r
 create mode 100644 test/unittest/proc/tst.pr_psargs.d
 create mode 100644 test/unittest/proc/tst.pr_psargs.r

diff --git a/bpf/Build b/bpf/Build
index 3e43f4b6..9355326c 100644
--- a/bpf/Build
+++ b/bpf/Build
@@ -24,6 +24,7 @@ bpf_dlib_SOURCES = \
 	agg_lqbin.c agg_qbin.c \
 	basename.S \
 	cleanpath.S \
+	d_execargs.S \
 	dirname.S \
 	get_agg.c \
 	get_bvar.c \
diff --git a/bpf/d_execargs.S b/bpf/d_execargs.S
new file mode 100644
index 00000000..3a5b1270
--- /dev/null
+++ b/bpf/d_execargs.S
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025, Oracle and/or its affiliates.
+ */
+
+#include <bpf_asm_helpers.h>
+#include <dtrace/faults_defines.h>
+
+	.text
+	.align	4
+	.global	dt_d_execargs
+dt_d_execargs:
+	stxdw	[%fp+-8], %r1			/* save dctx to stack */
+	mov	%r9, %r3			/* %r9 = args */
+
+	mov	%r6, %r2			/* set %r6 in case of error */
+	jeq	%r6, 0, .Lerror
+
+	add	%r6, TASK_MM			/* ptr = &(T->mm) */
+
+	mov	%r1, %r9
+	mov	%r2, 8
+	mov	%r3, %r6
+	call	BPF_FUNC_probe_read
+	jne	%r0, 0, .Lerror
+
+	ldxdw	%r8, [%r9+0]			/* %r8 = T->mm */
+	jeq	%r8, 0, .Lempty
+	mov	%r6, %r8
+	add	%r6, TASK_MM_ARG_START		/* ptr = &(T->mm->arg_start) */
+
+	mov	%r1, %r9
+	mov	%r2, 8
+	mov	%r3, %r6
+	call	BPF_FUNC_probe_read
+	jne	%r0, 0, .Lerror
+
+	ldxdw	%r7, [%r9+0]			/* %r7 = T->mm->arg_start */
+	mov	%r6, %r8
+	add	%r6, TASK_MM_ARG_END		/* ptr = &(T->mm->arg_end) */
+
+	mov	%r1, %r9
+	mov	%r2, 8
+	mov	%r3, %r6
+	call	BPF_FUNC_probe_read
+	jne	%r0, 0, .Lerror
+
+	ldxdw	%r6, [%r9+0]			/* %r6 = T->mm->arg_end */
+
+	mov	%r8, %r6
+	sub	%r8, %r7			/* %r8 = len = arg_end - arg_start */
+	jslt	%r8, 2, .Lempty
+	mov	%r0, STRSZ
+	jslt	%r8, %r0, .Llen_ok
+	mov	%r8, %r0
+.Llen_ok:
+
+	/* read data from arg_start to arg_end */
+	mov	%r1, %r9
+	mov	%r2, %r8
+	mov	%r3, %r7
+	call	BPF_FUNC_probe_read		/* bpf_probe_read(&args, len + 1, arg_start) */
+	jne	%r0, 0, .Lerror
+
+	/* loop over args and replace '\0' with ' ' */
+	mov	%r1, %r8
+	sub	%r1, 2
+.Lloop:
+	mov	%r2, %r9
+	add	%r2, %r1
+	ldxb	%r0, [%r2+0]
+	jne	%r0, 0, .Lnot_nil
+	stb	[%r2+0], 32
+.Lnot_nil:
+	sub	%r1, 1
+	jsge	%r1, 0, .Lloop
+
+.Ldone:
+	mov	%r0, %r9
+	exit					/* return args */
+.Lerror:
+	ldxdw	%r1, [%fp+-8]
+	mov	%r2, PC
+	mov	%r3, DTRACEFLT_BADADDR
+	mov	%r4, %r6
+	call	dt_probe_error
+.Lempty:
+	mov	%r0, %r9
+	stb	[%r9+0], 0			/* args[0] = 0 */
+	exit					/* return args */
+	.size	dt_d_execargs, .-dt_d_execargs
diff --git a/dlibs/aarch64/5.11/procfs.d b/dlibs/aarch64/5.11/procfs.d
index 44ec4280..70a43ddf 100644
--- a/dlibs/aarch64/5.11/procfs.d
+++ b/dlibs/aarch64/5.11/procfs.d
@@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > {
 				   : (struct tty_struct *)-1;
 
 	pr_fname = T->comm;
-/*
-	pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs));
- */
+	pr_psargs = d_execargs(T);
 	pr_wstat = 0;
 /*
 	pr_argc = get_psinfo(T)->__psinfo(argc);
diff --git a/dlibs/aarch64/5.12/procfs.d b/dlibs/aarch64/5.12/procfs.d
index 44ec4280..70a43ddf 100644
--- a/dlibs/aarch64/5.12/procfs.d
+++ b/dlibs/aarch64/5.12/procfs.d
@@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > {
 				   : (struct tty_struct *)-1;
 
 	pr_fname = T->comm;
-/*
-	pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs));
- */
+	pr_psargs = d_execargs(T);
 	pr_wstat = 0;
 /*
 	pr_argc = get_psinfo(T)->__psinfo(argc);
diff --git a/dlibs/aarch64/5.14/procfs.d b/dlibs/aarch64/5.14/procfs.d
index 584ac325..ef27bb70 100644
--- a/dlibs/aarch64/5.14/procfs.d
+++ b/dlibs/aarch64/5.14/procfs.d
@@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > {
 				   : (struct tty_struct *)-1;
 
 	pr_fname = T->comm;
-/*
-	pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs));
- */
+	pr_psargs = d_execargs(T);
 	pr_wstat = 0;
 /*
 	pr_argc = get_psinfo(T)->__psinfo(argc);
diff --git a/dlibs/aarch64/5.16/procfs.d b/dlibs/aarch64/5.16/procfs.d
index 5aabc6f1..cad2d2c5 100644
--- a/dlibs/aarch64/5.16/procfs.d
+++ b/dlibs/aarch64/5.16/procfs.d
@@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > {
 				   : (struct tty_struct *)-1;
 
 	pr_fname = T->comm;
-/*
-	pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs));
- */
+	pr_psargs = d_execargs(T);
 	pr_wstat = 0;
 /*
 	pr_argc = get_psinfo(T)->__psinfo(argc);
diff --git a/dlibs/aarch64/5.2/procfs.d b/dlibs/aarch64/5.2/procfs.d
index 683ff5a8..6b1b1b9c 100644
--- a/dlibs/aarch64/5.2/procfs.d
+++ b/dlibs/aarch64/5.2/procfs.d
@@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > {
 				   : (struct tty_struct *)-1;
 
 	pr_fname = T->comm;
-/*
-	pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs));
- */
+	pr_psargs = d_execargs(T);
 	pr_wstat = 0;
 /*
 	pr_argc = get_psinfo(T)->__psinfo(argc);
diff --git a/dlibs/aarch64/5.6/procfs.d b/dlibs/aarch64/5.6/procfs.d
index 44ec4280..70a43ddf 100644
--- a/dlibs/aarch64/5.6/procfs.d
+++ b/dlibs/aarch64/5.6/procfs.d
@@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > {
 				   : (struct tty_struct *)-1;
 
 	pr_fname = T->comm;
-/*
-	pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs));
- */
+	pr_psargs = d_execargs(T);
 	pr_wstat = 0;
 /*
 	pr_argc = get_psinfo(T)->__psinfo(argc);
diff --git a/dlibs/aarch64/6.1/procfs.d b/dlibs/aarch64/6.1/procfs.d
index 5d7873b5..4cb7b77c 100644
--- a/dlibs/aarch64/6.1/procfs.d
+++ b/dlibs/aarch64/6.1/procfs.d
@@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > {
 				   : (struct tty_struct *)-1;
 
 	pr_fname = T->comm;
-/*
-	pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs));
- */
+	pr_psargs = d_execargs(T);
 	pr_wstat = 0;
 /*
 	pr_argc = get_psinfo(T)->__psinfo(argc);
diff --git a/dlibs/aarch64/6.10/procfs.d b/dlibs/aarch64/6.10/procfs.d
index 5d7873b5..4cb7b77c 100644
--- a/dlibs/aarch64/6.10/procfs.d
+++ b/dlibs/aarch64/6.10/procfs.d
@@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > {
 				   : (struct tty_struct *)-1;
 
 	pr_fname = T->comm;
-/*
-	pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs));
- */
+	pr_psargs = d_execargs(T);
 	pr_wstat = 0;
 /*
 	pr_argc = get_psinfo(T)->__psinfo(argc);
diff --git a/dlibs/x86_64/5.11/procfs.d b/dlibs/x86_64/5.11/procfs.d
index 7274554e..c2be76d8 100644
--- a/dlibs/x86_64/5.11/procfs.d
+++ b/dlibs/x86_64/5.11/procfs.d
@@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > {
 				   : (struct tty_struct *)-1;
 
 	pr_fname = T->comm;
-/*
-	pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs));
- */
+	pr_psargs = d_execargs(T);
 	pr_wstat = 0;
 /*
 	pr_argc = get_psinfo(T)->__psinfo(argc);
diff --git a/dlibs/x86_64/5.12/procfs.d b/dlibs/x86_64/5.12/procfs.d
index 7274554e..c2be76d8 100644
--- a/dlibs/x86_64/5.12/procfs.d
+++ b/dlibs/x86_64/5.12/procfs.d
@@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > {
 				   : (struct tty_struct *)-1;
 
 	pr_fname = T->comm;
-/*
-	pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs));
- */
+	pr_psargs = d_execargs(T);
 	pr_wstat = 0;
 /*
 	pr_argc = get_psinfo(T)->__psinfo(argc);
diff --git a/dlibs/x86_64/5.14/procfs.d b/dlibs/x86_64/5.14/procfs.d
index d1cf90d3..28fada6d 100644
--- a/dlibs/x86_64/5.14/procfs.d
+++ b/dlibs/x86_64/5.14/procfs.d
@@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > {
 				   : (struct tty_struct *)-1;
 
 	pr_fname = T->comm;
-/*
-	pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs));
- */
+	pr_psargs = d_execargs(T);
 	pr_wstat = 0;
 /*
 	pr_argc = get_psinfo(T)->__psinfo(argc);
diff --git a/dlibs/x86_64/5.16/procfs.d b/dlibs/x86_64/5.16/procfs.d
index 5aabc6f1..cad2d2c5 100644
--- a/dlibs/x86_64/5.16/procfs.d
+++ b/dlibs/x86_64/5.16/procfs.d
@@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > {
 				   : (struct tty_struct *)-1;
 
 	pr_fname = T->comm;
-/*
-	pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs));
- */
+	pr_psargs = d_execargs(T);
 	pr_wstat = 0;
 /*
 	pr_argc = get_psinfo(T)->__psinfo(argc);
diff --git a/dlibs/x86_64/5.2/procfs.d b/dlibs/x86_64/5.2/procfs.d
index 35538862..08696cf7 100644
--- a/dlibs/x86_64/5.2/procfs.d
+++ b/dlibs/x86_64/5.2/procfs.d
@@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > {
 				   : (struct tty_struct *)-1;
 
 	pr_fname = T->comm;
-/*
-	pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs));
- */
+	pr_psargs = d_execargs(T);
 	pr_wstat = 0;
 /*
 	pr_argc = get_psinfo(T)->__psinfo(argc);
diff --git a/dlibs/x86_64/5.6/procfs.d b/dlibs/x86_64/5.6/procfs.d
index 7274554e..c2be76d8 100644
--- a/dlibs/x86_64/5.6/procfs.d
+++ b/dlibs/x86_64/5.6/procfs.d
@@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > {
 				   : (struct tty_struct *)-1;
 
 	pr_fname = T->comm;
-/*
-	pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs));
- */
+	pr_psargs = d_execargs(T);
 	pr_wstat = 0;
 /*
 	pr_argc = get_psinfo(T)->__psinfo(argc);
diff --git a/dlibs/x86_64/6.1/procfs.d b/dlibs/x86_64/6.1/procfs.d
index 5d7873b5..4cb7b77c 100644
--- a/dlibs/x86_64/6.1/procfs.d
+++ b/dlibs/x86_64/6.1/procfs.d
@@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > {
 				   : (struct tty_struct *)-1;
 
 	pr_fname = T->comm;
-/*
-	pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs));
- */
+	pr_psargs = d_execargs(T);
 	pr_wstat = 0;
 /*
 	pr_argc = get_psinfo(T)->__psinfo(argc);
diff --git a/dlibs/x86_64/6.10/procfs.d b/dlibs/x86_64/6.10/procfs.d
index 5d7873b5..4cb7b77c 100644
--- a/dlibs/x86_64/6.10/procfs.d
+++ b/dlibs/x86_64/6.10/procfs.d
@@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > {
 				   : (struct tty_struct *)-1;
 
 	pr_fname = T->comm;
-/*
-	pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs));
- */
+	pr_psargs = d_execargs(T);
 	pr_wstat = 0;
 /*
 	pr_argc = get_psinfo(T)->__psinfo(argc);
diff --git a/include/dtrace/dif_defines.h b/include/dtrace/dif_defines.h
index c8c1d961..cd785723 100644
--- a/include/dtrace/dif_defines.h
+++ b/include/dtrace/dif_defines.h
@@ -207,10 +207,11 @@
 #define DIF_SUBR_INET_NTOP		41
 #define DIF_SUBR_INET_NTOA		42
 #define DIF_SUBR_INET_NTOA6		43
-#define DIF_SUBR_D_PATH			44
-#define DIF_SUBR_LINK_NTOP		45
+#define DIF_SUBR_LINK_NTOP		44
+#define DIF_SUBR_D_PATH			45
+#define DIF_SUBR_D_EXECARGS		46
 
-#define DIF_SUBR_MAX			45
+#define DIF_SUBR_MAX			46
 
 typedef uint32_t	dif_instr_t;
 
diff --git a/libdtrace/dt_bpf.h b/libdtrace/dt_bpf.h
index 6518de66..85934d2d 100644
--- a/libdtrace/dt_bpf.h
+++ b/libdtrace/dt_bpf.h
@@ -47,15 +47,18 @@ extern "C" {
 #define DT_CONST_TASK_TGID		12
 #define DT_CONST_TASK_REAL_PARENT	13
 #define DT_CONST_TASK_COMM		14
-#define DT_CONST_MUTEX_OWNER		15
-#define DT_CONST_RWLOCK_CNTS		16
-#define DT_CONST_DCTX_RODATA		17
-#define DT_CONST_RODATA_OFF		18
-#define DT_CONST_RODATA_SIZE		19
-#define DT_CONST_ZERO_OFF		20
-#define DT_CONST_STACK_OFF		21
-#define DT_CONST_STACK_SKIP		22
-#define DT_CONST_NPROBES		23
+#define DT_CONST_TASK_MM		15
+#define DT_CONST_TASK_MM_ARG_START	16
+#define DT_CONST_TASK_MM_ARG_END	17
+#define DT_CONST_MUTEX_OWNER		18
+#define DT_CONST_RWLOCK_CNTS		19
+#define DT_CONST_DCTX_RODATA		20
+#define DT_CONST_RODATA_OFF		21
+#define DT_CONST_RODATA_SIZE		22
+#define DT_CONST_ZERO_OFF		23
+#define DT_CONST_STACK_OFF		24
+#define DT_CONST_STACK_SKIP		25
+#define DT_CONST_NPROBES		26
 
 #define DT_BPF_LOG_SIZE_DEFAULT	(UINT32_MAX >> 8)
 #define DT_BPF_LOG_SIZE_SMALL	4096
diff --git a/libdtrace/dt_cc.c b/libdtrace/dt_cc.c
index 29cfbd84..1dc119ea 100644
--- a/libdtrace/dt_cc.c
+++ b/libdtrace/dt_cc.c
@@ -1082,7 +1082,8 @@ dt_link_construct(dtrace_hdl_t *dtp, const dt_probe_t *prp, dtrace_difo_t *dp,
 			case DT_CONST_TASK_PID:
 			case DT_CONST_TASK_TGID:
 			case DT_CONST_TASK_REAL_PARENT:
-			case DT_CONST_TASK_COMM: {
+			case DT_CONST_TASK_COMM:
+			case DT_CONST_TASK_MM: {
 				ctf_file_t *cfp = dtp->dt_shared_ctf;
 				ctf_id_t type;
 				ctf_membinfo_t ctm;
@@ -1108,6 +1109,36 @@ dt_link_construct(dtrace_hdl_t *dtp, const dt_probe_t *prp, dtrace_difo_t *dp,
 				case DT_CONST_TASK_COMM:
 					rc = ctf_member_info(cfp, type, "comm", &ctm);
 					break;
+				case DT_CONST_TASK_MM:
+					rc = ctf_member_info(cfp, type, "mm", &ctm);
+					break;
+				}
+				if (rc == CTF_ERR)
+					goto err_ctf;
+				nrp->dofr_data = ctm.ctm_offset / NBBY;
+				continue;
+			}
+			case DT_CONST_TASK_MM_ARG_START:
+			case DT_CONST_TASK_MM_ARG_END: {
+				ctf_file_t *cfp = dtp->dt_shared_ctf;
+				ctf_id_t type;
+				ctf_membinfo_t ctm;
+				int rc = 0;
+
+				if (!cfp)
+					return dt_set_errno(dtp, EDT_NOCTF);
+
+				type = ctf_lookup_by_name(cfp, "struct mm_struct");
+				if (type == CTF_ERR)
+					goto err_ctf;
+
+				switch (idp->di_id) {
+				case DT_CONST_TASK_MM_ARG_START:
+					rc = ctf_member_info(cfp, type, "arg_start", &ctm);
+					break;
+				case DT_CONST_TASK_MM_ARG_END:
+					rc = ctf_member_info(cfp, type, "arg_end", &ctm);
+					break;
 				}
 				if (rc == CTF_ERR)
 					goto err_ctf;
diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
index 6e74b4b0..a1a39f3f 100644
--- a/libdtrace/dt_cg.c
+++ b/libdtrace/dt_cg.c
@@ -3300,7 +3300,6 @@ dt_cg_load_var(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
 	}
 
 	/* built-in variables (note: args[] is handled in dt_cg_array_op) */
-	/* Special case for arg0 through arg9; encode as args[n] */
 	if (idp->di_id >= DIF_VAR_ARG0 && idp->di_id <= DIF_VAR_ARG9) {
 		fnp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_bvar_args");
 		idx = idp->di_id - DIF_VAR_ARG0;
@@ -6661,6 +6660,13 @@ dt_cg_subr_inet_ntop(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
 	tnp->dn_tstring = NULL;
 }
 
+static void
+dt_cg_subr_d_execargs(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
+{
+	dt_cg_subr_arg_to_tstring(dnp, dlp, drp, "dt_d_execargs", 0,
+				  DT_IGNOR, 0, DT_IGNOR, 0);
+}
+
 static void
 dt_cg_subr_d_path(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
 {
@@ -6758,6 +6764,7 @@ static dt_cg_subr_f *_dt_cg_subr[DIF_SUBR_MAX + 1] = {
 	[DIF_SUBR_INET_NTOP]		= &dt_cg_subr_inet_ntop,
 	[DIF_SUBR_INET_NTOA]		= &dt_cg_subr_inet_ntoa,
 	[DIF_SUBR_INET_NTOA6]		= &dt_cg_subr_inet_ntoa6,
+	[DIF_SUBR_D_EXECARGS]		= &dt_cg_subr_d_execargs,
 	[DIF_SUBR_D_PATH]		= &dt_cg_subr_d_path,
 	[DIF_SUBR_LINK_NTOP]		= &dt_cg_subr_link_ntop,
 };
diff --git a/libdtrace/dt_dlibs.c b/libdtrace/dt_dlibs.c
index 07d22afd..9ad4f5e7 100644
--- a/libdtrace/dt_dlibs.c
+++ b/libdtrace/dt_dlibs.c
@@ -89,6 +89,9 @@ static const dt_ident_t		dt_bpf_symbols[] = {
 	DT_BPF_SYMBOL_ID(TASK_TGID, DT_IDENT_SCALAR, DT_CONST_TASK_TGID),
 	DT_BPF_SYMBOL_ID(TASK_REAL_PARENT, DT_IDENT_SCALAR, DT_CONST_TASK_REAL_PARENT),
 	DT_BPF_SYMBOL_ID(TASK_COMM, DT_IDENT_SCALAR, DT_CONST_TASK_COMM),
+	DT_BPF_SYMBOL_ID(TASK_MM, DT_IDENT_SCALAR, DT_CONST_TASK_MM),
+	DT_BPF_SYMBOL_ID(TASK_MM_ARG_START, DT_IDENT_SCALAR, DT_CONST_TASK_MM_ARG_START),
+	DT_BPF_SYMBOL_ID(TASK_MM_ARG_END, DT_IDENT_SCALAR, DT_CONST_TASK_MM_ARG_END),
 	DT_BPF_SYMBOL_ID(MUTEX_OWNER, DT_IDENT_SCALAR, DT_CONST_MUTEX_OWNER),
 	DT_BPF_SYMBOL_ID(RWLOCK_CNTS, DT_IDENT_SCALAR, DT_CONST_RWLOCK_CNTS),
 	DT_BPF_SYMBOL_ID(DCTX_RODATA, DT_IDENT_SCALAR, DT_CONST_DCTX_RODATA),
diff --git a/libdtrace/dt_open.c b/libdtrace/dt_open.c
index a0205887..c8208de6 100644
--- a/libdtrace/dt_open.c
+++ b/libdtrace/dt_open.c
@@ -138,6 +138,8 @@ static const dt_ident_t _dtrace_globals[] = {
 	{ DTRACE_STABILITY_STABLE, DTRACE_STABILITY_PRIVATE,
 	DTRACE_CLASS_COMMON }, DT_VERS_1_0,
 	&dt_idops_type, "vmlinux`struct task_struct *" },
+{ "d_execargs", DT_IDENT_FUNC, 0, DIF_SUBR_D_EXECARGS, DT_ATTR_EVOLCMN,
+	DT_VERS_2_0, &dt_idops_func, "string(vmlinux`struct task_struct *)" },
 { "d_path", DT_IDENT_FUNC, DT_IDFLG_DPTR, DIF_SUBR_D_PATH, DT_ATTR_EVOLCMN,
 	DT_VERS_1_0, &dt_idops_func, "string(struct path *)" },
 { "ddi_pathname", DT_IDENT_FUNC, 0, DIF_SUBR_DDI_PATHNAME,
diff --git a/libdtrace/procfs.d.in b/libdtrace/procfs.d.in
index 038cf69b..e9d50349 100644
--- a/libdtrace/procfs.d.in
+++ b/libdtrace/procfs.d.in
@@ -179,9 +179,7 @@ translator psinfo_t < struct task_struct *T > {
 				   : (struct tty_struct *)-1;
 
 	pr_fname = T->comm;
-/*
-	pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs));
- */
+	pr_psargs = d_execargs(T);
 	pr_wstat = 0;
 /*
 	pr_argc = get_psinfo(T)->__psinfo(argc);
diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.d b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.d
new file mode 100644
index 00000000..c707184d
--- /dev/null
+++ b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.d
@@ -0,0 +1,16 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2025, 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 argument to d_execargs() should be a (struct task_struct *).
+ */
+
+BEGIN
+{
+	trace(d_execargs(1));
+	exit(0);
+}
diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.r b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.r
new file mode 100644
index 00000000..0e9cda07
--- /dev/null
+++ b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.r
@@ -0,0 +1,4 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.d: [D_PROTO_ARG] line 14: d_execargs( ) argument #1 is incompatible with prototype:
+	prototype: struct task_struct *
+	 argument: int
diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.d b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.d
new file mode 100644
index 00000000..ba419689
--- /dev/null
+++ b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.d
@@ -0,0 +1,16 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2025, 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 argument to d_execargs() should be (struct task_struct *).
+ */
+
+BEGIN
+{
+	trace(d_execargs("a"));
+	exit(0);
+}
diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.r b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.r
new file mode 100644
index 00000000..ac1c1401
--- /dev/null
+++ b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.r
@@ -0,0 +1,4 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.d: [D_PROTO_ARG] line 14: d_execargs( ) argument #1 is incompatible with prototype:
+	prototype: struct task_struct *
+	 argument: string
diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.d b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.d
new file mode 100644
index 00000000..473e35e4
--- /dev/null
+++ b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.d
@@ -0,0 +1,16 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2025, 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 argument to d_execargs() should be (struct task_struct *).
+ */
+
+BEGIN
+{
+	trace(d_execargs(curthread->mm));
+	exit(0);
+}
diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.r b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.r
new file mode 100644
index 00000000..842371a3
--- /dev/null
+++ b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.r
@@ -0,0 +1,4 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.d: [D_PROTO_ARG] line 14: d_execargs( ) argument #1 is incompatible with prototype:
+	prototype: struct task_struct *
+	 argument: struct mm_struct *
diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.d b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.d
new file mode 100644
index 00000000..86b1b237
--- /dev/null
+++ b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.d
@@ -0,0 +1,16 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2025, 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: d_execargs() requires an argument
+ */
+
+BEGIN
+{
+	trace(d_execargs());
+	exit(0);
+}
diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.r b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.r
new file mode 100644
index 00000000..a4fcd162
--- /dev/null
+++ b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.d: [D_PROTO_LEN] line 14: d_execargs( ) prototype mismatch: 0 args passed, 1 expected
diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.d b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.d
new file mode 100644
index 00000000..3add63f6
--- /dev/null
+++ b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.d
@@ -0,0 +1,16 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2025, 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 d_execargs() subroutine accepts no more than one argument.
+ */
+
+BEGIN
+{
+	trace(d_execargs(curthread, 1));
+	exit(0);
+}
diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.r b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.r
new file mode 100644
index 00000000..f5a982ff
--- /dev/null
+++ b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.d: [D_PROTO_LEN] line 14: d_execargs( ) prototype mismatch: 2 args passed, 1 expected
diff --git a/test/unittest/funcs/d_execargs/tst.d_execargs.d b/test/unittest/funcs/d_execargs/tst.d_execargs.d
new file mode 100644
index 00000000..b8b141aa
--- /dev/null
+++ b/test/unittest/funcs/d_execargs/tst.d_execargs.d
@@ -0,0 +1,31 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2025, 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: d_execargs() provides correct results.
+ */
+
+#pragma D option destructive
+#pragma D option quiet
+
+BEGIN
+{
+	mypid = pid;
+	system("/bin/echo TEST");
+}
+
+proc:::exec-success
+/progenyof(mypid) && d_execargs(curthread) == "/bin/echo TEST"/
+{
+	trace(d_execargs(curthread));
+	exit(0);
+}
+
+tick-1s
+{
+	exit(1);
+}
diff --git a/test/unittest/funcs/d_execargs/tst.d_execargs.r b/test/unittest/funcs/d_execargs/tst.d_execargs.r
new file mode 100644
index 00000000..d8ff6689
--- /dev/null
+++ b/test/unittest/funcs/d_execargs/tst.d_execargs.r
@@ -0,0 +1,2 @@
+TEST
+/bin/echo TEST
diff --git a/test/unittest/proc/tst.pr_psargs.d b/test/unittest/proc/tst.pr_psargs.d
new file mode 100644
index 00000000..902ac1a3
--- /dev/null
+++ b/test/unittest/proc/tst.pr_psargs.d
@@ -0,0 +1,31 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2025, 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: psinfo->pr_psargs provides correct results.
+ */
+
+#pragma D option destructive
+#pragma D option quiet
+
+BEGIN
+{
+	mypid = pid;
+	system("/bin/echo TEST");
+}
+
+proc:::exec-success
+/progenyof(mypid) && curpsinfo->pr_psargs == "/bin/echo TEST"/
+{
+	trace(curpsinfo->pr_psargs);
+	exit(0);
+}
+
+tick-1s
+{
+	exit(1);
+}
diff --git a/test/unittest/proc/tst.pr_psargs.r b/test/unittest/proc/tst.pr_psargs.r
new file mode 100644
index 00000000..397c8717
--- /dev/null
+++ b/test/unittest/proc/tst.pr_psargs.r
@@ -0,0 +1,9 @@
+TEST
+
+             0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f  0123456789abcdef
+         0: 2f 62 69 6e 2f 65 63 68 6f 20 54 45 53 54 00 00  /bin/echo TEST..
+        10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
+        20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
+        30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
+        40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
+
-- 
2.45.2




More information about the DTrace-devel mailing list