[DTrace-devel] [PATCH 1/4] parser, cg: Implement the return() action
Kris Van Hees
kris.van.hees at oracle.com
Tue Jul 15 05:47:36 UTC 2025
The return(n) action can be used for error injection by forcing a
given return value for a kernel function.
Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
---
include/dtrace/actions_defines.h | 1 +
libdtrace/dt_cg.c | 21 +++++++++++++++
libdtrace/dt_grammar.y | 1 -
libdtrace/dt_impl.h | 3 ++-
libdtrace/dt_lex.l | 1 -
libdtrace/dt_open.c | 2 ++
test/modules | 1 +
.../actions/return/err.D_PROTO_ARG.str.d | 19 +++++++++++++
.../actions/return/err.D_PROTO_ARG.str.r | 4 +++
.../actions/return/err.D_PROTO_ARG.void.d | 19 +++++++++++++
.../actions/return/err.D_PROTO_ARG.void.r | 4 +++
.../return/err.D_PROTO_LEN.missing_arg.d | 20 ++++++++++++++
.../return/err.D_PROTO_LEN.missing_arg.r | 2 ++
.../return/err.D_PROTO_LEN.too_many_args.d | 20 ++++++++++++++
.../return/err.D_PROTO_LEN.too_many_args.r | 2 ++
.../unittest/actions/return/err.destructive.d | 26 ++++++++++++++++++
.../unittest/actions/return/err.destructive.r | 2 ++
.../unittest/actions/return/tst.destructive.d | 27 +++++++++++++++++++
.../unittest/actions/return/tst.destructive.r | 1 +
19 files changed, 173 insertions(+), 3 deletions(-)
create mode 100644 test/unittest/actions/return/err.D_PROTO_ARG.str.d
create mode 100644 test/unittest/actions/return/err.D_PROTO_ARG.str.r
create mode 100644 test/unittest/actions/return/err.D_PROTO_ARG.void.d
create mode 100644 test/unittest/actions/return/err.D_PROTO_ARG.void.r
create mode 100644 test/unittest/actions/return/err.D_PROTO_LEN.missing_arg.d
create mode 100644 test/unittest/actions/return/err.D_PROTO_LEN.missing_arg.r
create mode 100644 test/unittest/actions/return/err.D_PROTO_LEN.too_many_args.d
create mode 100644 test/unittest/actions/return/err.D_PROTO_LEN.too_many_args.r
create mode 100644 test/unittest/actions/return/err.destructive.d
create mode 100644 test/unittest/actions/return/err.destructive.r
create mode 100644 test/unittest/actions/return/tst.destructive.d
create mode 100644 test/unittest/actions/return/tst.destructive.r
diff --git a/include/dtrace/actions_defines.h b/include/dtrace/actions_defines.h
index 4ff4fb83..601328b8 100644
--- a/include/dtrace/actions_defines.h
+++ b/include/dtrace/actions_defines.h
@@ -51,6 +51,7 @@
#define DTRACEACT_RAISE (DTRACEACT_PROC_DESTRUCTIVE + 2)
#define DTRACEACT_SYSTEM (DTRACEACT_PROC_DESTRUCTIVE + 3)
#define DTRACEACT_FREOPEN (DTRACEACT_PROC_DESTRUCTIVE + 4)
+#define DTRACEACT_RETURN (DTRACEACT_PROC_DESTRUCTIVE + 5)
#define DTRACEACT_PROC_CONTROL 0x0300
diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
index bd0763d6..d80b0a55 100644
--- a/libdtrace/dt_cg.c
+++ b/libdtrace/dt_cg.c
@@ -2893,6 +2893,25 @@ dt_cg_act_print(dt_pcb_t *pcb, dt_node_t *dnp, dtrace_actkind_t kind)
dt_regset_free(drp, BPF_REG_0);
}
+static void
+dt_cg_act_return(dt_pcb_t *pcb, dt_node_t *dnp, dtrace_actkind_t kind)
+{
+ dt_irlist_t *dlp = &pcb->pcb_ir;
+ dt_regset_t *drp = pcb->pcb_regs;
+
+ dt_cg_node(dnp->dn_args, &pcb->pcb_ir, pcb->pcb_regs);
+
+ if (dt_regset_xalloc_args(drp) == -1)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
+ emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_1, BPF_REG_FP, DT_STK_DCTX));
+ emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_1, BPF_REG_1, DCTX_CTX));
+ emit(dlp, BPF_MOV_REG(BPF_REG_2, dnp->dn_args->dn_reg));
+ dt_regset_xalloc(drp, BPF_REG_0);
+ emit(dlp, BPF_CALL_HELPER(BPF_FUNC_override_return));
+ dt_regset_free_args(drp);
+ dt_regset_free(drp, BPF_REG_0);
+}
+
typedef void dt_cg_action_f(dt_pcb_t *, dt_node_t *, dtrace_actkind_t);
typedef struct dt_cg_actdesc {
@@ -2951,6 +2970,8 @@ static const dt_cg_actdesc_t _dt_cg_actions[DT_ACT_MAX] = {
[DT_ACT_IDX(DT_ACT_SETOPT)] = { &dt_cg_act_setopt, },
[DT_ACT_IDX(DT_ACT_PCAP)] = { &dt_cg_act_pcap, },
[DT_ACT_IDX(DT_ACT_PRINT)] = { &dt_cg_act_print, },
+ [DT_ACT_IDX(DT_ACT_RETURN)] = { &dt_cg_act_return,
+ DTRACEACT_RETURN },
};
dt_irnode_t *
diff --git a/libdtrace/dt_grammar.y b/libdtrace/dt_grammar.y
index 048a974d..a0911097 100644
--- a/libdtrace/dt_grammar.y
+++ b/libdtrace/dt_grammar.y
@@ -73,7 +73,6 @@ int yylex (void);
%token DT_KEY_PROVIDER
%token DT_KEY_REGISTER
%token DT_KEY_RESTRICT
-%token DT_KEY_RETURN
%token DT_KEY_SELF
%token DT_KEY_SHORT
%token DT_KEY_SIGNED
diff --git a/libdtrace/dt_impl.h b/libdtrace/dt_impl.h
index 2adc1252..e7192290 100644
--- a/libdtrace/dt_impl.h
+++ b/libdtrace/dt_impl.h
@@ -550,8 +550,9 @@ struct dtrace_hdl {
#define DT_ACT_SETOPT DT_ACT(28) /* setopt() action */
#define DT_ACT_PCAP DT_ACT(29) /* pcap() action */
#define DT_ACT_PRINT DT_ACT(30) /* print() action */
+#define DT_ACT_RETURN DT_ACT(31) /* return() action */
-#define DT_ACT_MAX 31
+#define DT_ACT_MAX 32
/*
* Sentinel to tell freopen() to restore the saved stdout. This must not
diff --git a/libdtrace/dt_lex.l b/libdtrace/dt_lex.l
index cc165c1e..bdcca415 100644
--- a/libdtrace/dt_lex.l
+++ b/libdtrace/dt_lex.l
@@ -104,7 +104,6 @@ if (yypcb->pcb_token != 0) {
<S0>provider return DT_KEY_PROVIDER;
<S0>register return DT_KEY_REGISTER;
<S0>restrict return DT_KEY_RESTRICT;
-<S0>return return DT_KEY_RETURN;
<S0>self return DT_KEY_SELF;
<S0>short return DT_KEY_SHORT;
<S0>signed return DT_KEY_SIGNED;
diff --git a/libdtrace/dt_open.c b/libdtrace/dt_open.c
index c67455e7..08394a11 100644
--- a/libdtrace/dt_open.c
+++ b/libdtrace/dt_open.c
@@ -269,6 +269,8 @@ static const dt_ident_t _dtrace_globals[] = {
&dt_idops_func, "void(int)" },
{ "rand", DT_IDENT_FUNC, 0, DIF_SUBR_RAND, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_func, "int()" },
+{ "return", DT_IDENT_ACTFUNC, 0, DT_ACT_RETURN, DT_ATTR_STABCMN, DT_VERS_2_0,
+ &dt_idops_func, "void(int)" },
{ "rindex", DT_IDENT_FUNC, 0, DIF_SUBR_RINDEX, DT_ATTR_STABCMN, DT_VERS_1_1,
&dt_idops_func, "int(const char *, const char *, [int])" },
{ "rw_iswriter", DT_IDENT_FUNC, 0, DIF_SUBR_RW_ISWRITER,
diff --git a/test/modules b/test/modules
index 0f01d6e0..7782540c 100644
--- a/test/modules
+++ b/test/modules
@@ -1,3 +1,4 @@
+btrfs
ext4
isofs
nfs
diff --git a/test/unittest/actions/return/err.D_PROTO_ARG.str.d b/test/unittest/actions/return/err.D_PROTO_ARG.str.d
new file mode 100644
index 00000000..d04836f3
--- /dev/null
+++ b/test/unittest/actions/return/err.D_PROTO_ARG.str.d
@@ -0,0 +1,19 @@
+/*
+ * 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 return() action cannot be passed a string argument.
+ *
+ * SECTION: Actions and Subroutines/return()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ return("");
+}
diff --git a/test/unittest/actions/return/err.D_PROTO_ARG.str.r b/test/unittest/actions/return/err.D_PROTO_ARG.str.r
new file mode 100644
index 00000000..46ca1828
--- /dev/null
+++ b/test/unittest/actions/return/err.D_PROTO_ARG.str.r
@@ -0,0 +1,4 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/actions/return/err.D_PROTO_ARG.str.d: [D_PROTO_ARG] line 18: return( ) argument #1 is incompatible with prototype:
+ prototype: int
+ argument: string
diff --git a/test/unittest/actions/return/err.D_PROTO_ARG.void.d b/test/unittest/actions/return/err.D_PROTO_ARG.void.d
new file mode 100644
index 00000000..dc3b15fa
--- /dev/null
+++ b/test/unittest/actions/return/err.D_PROTO_ARG.void.d
@@ -0,0 +1,19 @@
+/*
+ * 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 return() action cannot be passed a void argument.
+ *
+ * SECTION: Actions and Subroutines/return()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ return(return(0));
+}
diff --git a/test/unittest/actions/return/err.D_PROTO_ARG.void.r b/test/unittest/actions/return/err.D_PROTO_ARG.void.r
new file mode 100644
index 00000000..1573c557
--- /dev/null
+++ b/test/unittest/actions/return/err.D_PROTO_ARG.void.r
@@ -0,0 +1,4 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/actions/return/err.D_PROTO_ARG.void.d: [D_PROTO_ARG] line 18: return( ) argument #1 is incompatible with prototype:
+ prototype: int
+ argument: void
diff --git a/test/unittest/actions/return/err.D_PROTO_LEN.missing_arg.d b/test/unittest/actions/return/err.D_PROTO_LEN.missing_arg.d
new file mode 100644
index 00000000..97ed0762
--- /dev/null
+++ b/test/unittest/actions/return/err.D_PROTO_LEN.missing_arg.d
@@ -0,0 +1,20 @@
+/*
+ * 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 return() action takes exactly one argument.
+ *
+ * SECTION: Actions and Subroutines/return()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ return();
+ exit(0);
+}
diff --git a/test/unittest/actions/return/err.D_PROTO_LEN.missing_arg.r b/test/unittest/actions/return/err.D_PROTO_LEN.missing_arg.r
new file mode 100644
index 00000000..fd7c2512
--- /dev/null
+++ b/test/unittest/actions/return/err.D_PROTO_LEN.missing_arg.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/actions/return/err.D_PROTO_LEN.missing_arg.d: [D_PROTO_LEN] line 18: return( ) prototype mismatch: 0 args passed, 1 expected
diff --git a/test/unittest/actions/return/err.D_PROTO_LEN.too_many_args.d b/test/unittest/actions/return/err.D_PROTO_LEN.too_many_args.d
new file mode 100644
index 00000000..0776192b
--- /dev/null
+++ b/test/unittest/actions/return/err.D_PROTO_LEN.too_many_args.d
@@ -0,0 +1,20 @@
+/*
+ * 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 return() action takes exactly one argument.
+ *
+ * SECTION: Actions and Subroutines/return()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ return(1, 2);
+ exit(0);
+}
diff --git a/test/unittest/actions/return/err.D_PROTO_LEN.too_many_args.r b/test/unittest/actions/return/err.D_PROTO_LEN.too_many_args.r
new file mode 100644
index 00000000..37ff4d9d
--- /dev/null
+++ b/test/unittest/actions/return/err.D_PROTO_LEN.too_many_args.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: failed to compile script test/unittest/actions/return/err.D_PROTO_LEN.too_many_args.d: [D_PROTO_LEN] line 18: return( ) prototype mismatch: 2 args passed, 1 expected
diff --git a/test/unittest/actions/return/err.destructive.d b/test/unittest/actions/return/err.destructive.d
new file mode 100644
index 00000000..4c4a246a
--- /dev/null
+++ b/test/unittest/actions/return/err.destructive.d
@@ -0,0 +1,26 @@
+/*
+ * 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: return() is allowed when destructive execution is allowed
+ *
+ * SECTION: Actions and Subroutines/return()
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ ok = 0;
+ exit(0);
+}
+
+rawfbt:btrfs:open_ctree:entry
+/ok/
+{
+ return(0);
+}
diff --git a/test/unittest/actions/return/err.destructive.r b/test/unittest/actions/return/err.destructive.r
new file mode 100644
index 00000000..004c30a9
--- /dev/null
+++ b/test/unittest/actions/return/err.destructive.r
@@ -0,0 +1,2 @@
+-- @@stderr --
+dtrace: could not enable tracing: Destructive actions not allowed
diff --git a/test/unittest/actions/return/tst.destructive.d b/test/unittest/actions/return/tst.destructive.d
new file mode 100644
index 00000000..f1d9e4d3
--- /dev/null
+++ b/test/unittest/actions/return/tst.destructive.d
@@ -0,0 +1,27 @@
+/*
+ * 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: return() is allowed when destructive execution is allowed
+ *
+ * SECTION: Actions and Subroutines/return()
+ */
+
+#pragma D option quiet
+#pragma D option destructive
+
+BEGIN
+{
+ ok = 0;
+ exit(0);
+}
+
+rawfbt:btrfs:open_ctree:entry
+/ok/
+{
+ return(0);
+}
diff --git a/test/unittest/actions/return/tst.destructive.r b/test/unittest/actions/return/tst.destructive.r
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/test/unittest/actions/return/tst.destructive.r
@@ -0,0 +1 @@
+
--
2.43.5
More information about the DTrace-devel
mailing list