[DTrace-devel] [PATCH] Add support for built-in variable errno
eugene.loh at oracle.com
eugene.loh at oracle.com
Fri Apr 23 09:50:12 PDT 2021
From: Eugene Loh <eugene.loh at oracle.com>
The built-in variable errno should be:
*) the errno for failed system calls for syscall:::return probes
*) 0 otherwise
This behavior is slightly different from the errno in C library functions
(where errno is not reset by successful system calls) and from the
behavior described in the DTrace Guide (which allows errno to be non-0
for non-syscall probes).
Introduce an mst->syserrno, and have the provider trampolines set it to 0.
Then have syscall:::return probes check arg0, setting mst->syserrno=-arg0
if the value would be within bounds. Finally, have dt_get_bvar() retrieve
errno from mst->syserrno.
Update tests. The only particularly meaningful test for errno is
tst.errno2.d, which will not yet work since it still needs, for example,
string support. Add a tst.errno3.sh test for the new errno support.
Signed-off-by: Eugene Loh <eugene.loh at oracle.com>
---
bpf/get_bvar.c | 2 +
libdtrace/dt_cg.c | 2 +
libdtrace/dt_dctx.h | 2 +
libdtrace/dt_prov_syscall.c | 17 +++++++
test/unittest/builtinvar/tst.errno.d | 1 -
test/unittest/builtinvar/tst.errno1.d | 1 -
test/unittest/builtinvar/tst.errno3.r | 1 +
test/unittest/builtinvar/tst.errno3.sh | 56 ++++++++++++++++++++++++
test/unittest/variables/bvar/tst.errno.d | 3 +-
9 files changed, 81 insertions(+), 4 deletions(-)
create mode 100644 test/unittest/builtinvar/tst.errno3.r
create mode 100755 test/unittest/builtinvar/tst.errno3.sh
diff --git a/bpf/get_bvar.c b/bpf/get_bvar.c
index 7e7b25a3..971209ab 100644
--- a/bpf/get_bvar.c
+++ b/bpf/get_bvar.c
@@ -106,6 +106,8 @@ noinline uint64_t dt_get_bvar(dt_dctx_t *dctx, uint32_t id)
return val >> 32;
}
+ case DIF_VAR_ERRNO:
+ return mst->syserrno;
case DIF_VAR_CURCPU: {
uint32_t key = 0;
void *val = bpf_map_lookup_elem(&cpuinfo, &key);
diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
index 047cb7ba..54c50d01 100644
--- a/libdtrace/dt_cg.c
+++ b/libdtrace/dt_cg.c
@@ -114,6 +114,7 @@ dt_cg_tramp_prologue_act(dt_pcb_t *pcb, dt_activity_t act)
* // mov %r7, %r0
* dctx.mst = rc; // stdw [%fp + DCTX_FP(DCTX_MST)], %r7
* dctx.mst->prid = PRID; // stw [%r7 + DMST_PRID], PRID
+ * dctx.mst->syserrno = 0; // stw [%r7 + DMST_ERRNO], 0
*/
emit(dlp, BPF_STORE_IMM(BPF_W, BPF_REG_FP, DCTX_FP(DCTX_MST), 0));
dt_cg_xsetx(dlp, mem, DT_LBL_NONE, BPF_REG_1, mem->di_id);
@@ -124,6 +125,7 @@ dt_cg_tramp_prologue_act(dt_pcb_t *pcb, dt_activity_t act)
emit(dlp, BPF_MOV_REG(BPF_REG_7, BPF_REG_0));
emit(dlp, BPF_STORE(BPF_DW, BPF_REG_FP, DCTX_FP(DCTX_MST), BPF_REG_7));
emite(dlp, BPF_STORE_IMM(BPF_W, BPF_REG_7, DMST_PRID, -1), prid);
+ emit(dlp, BPF_STORE_IMM(BPF_W, BPF_REG_7, DMST_ERRNO, 0));
/*
* buf = rc + roundup(sizeof(dt_mstate_t), 8);
diff --git a/libdtrace/dt_dctx.h b/libdtrace/dt_dctx.h
index 0873602c..8318ea00 100644
--- a/libdtrace/dt_dctx.h
+++ b/libdtrace/dt_dctx.h
@@ -22,6 +22,7 @@ typedef struct dt_mstate {
uint32_t prid; /* Probe ID */
uint32_t clid; /* Clause ID (unique per probe) */
uint32_t tag; /* Tag (for future use) */
+ int32_t syserrno; /* syscall errno */
uint64_t fault; /* DTrace fault flags */
uint64_t tstamp; /* cached timestamp value */
#if 0
@@ -62,6 +63,7 @@ typedef struct dt_dctx {
#define DMST_PRID offsetof(dt_mstate_t, prid)
#define DMST_CLID offsetof(dt_mstate_t, clid)
#define DMST_TAG offsetof(dt_mstate_t, tag)
+#define DMST_ERRNO offsetof(dt_mstate_t, syserrno)
#define DMST_FAULT offsetof(dt_mstate_t, fault)
#define DMST_TSTAMP offsetof(dt_mstate_t, tstamp)
#define DMST_REGS offsetof(dt_mstate_t, regs)
diff --git a/libdtrace/dt_prov_syscall.c b/libdtrace/dt_prov_syscall.c
index 65b624a9..43fe44c0 100644
--- a/libdtrace/dt_prov_syscall.c
+++ b/libdtrace/dt_prov_syscall.c
@@ -188,6 +188,23 @@ static void trampoline(dt_pcb_t *pcb)
for ( ; i < ARRAY_SIZE(((dt_mstate_t *)0)->argv); i++)
emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_7, DMST_ARG(i), 0));
+ /*
+ * For return probes, store the errno. That is, examine arg0.
+ * If it is >=0 or <=-2048, ignore it. Otherwise, store -arg0
+ * in dctx->mst->syserrno.
+ */
+ if (strcmp(pcb->pcb_probe->desc->prb, "return") == 0) {
+ uint_t lbl_errno_done = dt_irlist_label(dlp);
+
+ emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, BPF_REG_7, DMST_ARG(0)));
+ emit(dlp, BPF_BRANCH_IMM(BPF_JSGE, BPF_REG_0, 0, lbl_errno_done));
+ emit(dlp, BPF_BRANCH_IMM(BPF_JSLE, BPF_REG_0, -2048, lbl_errno_done));
+ emit(dlp, BPF_NEG_REG(BPF_REG_0));
+ emit(dlp, BPF_STORE(BPF_W, BPF_REG_7, DMST_ERRNO, BPF_REG_0));
+ emitl(dlp, lbl_errno_done,
+ BPF_NOP());
+ }
+
dt_cg_tramp_epilogue(pcb);
}
diff --git a/test/unittest/builtinvar/tst.errno.d b/test/unittest/builtinvar/tst.errno.d
index 58b71bc3..877b8f84 100644
--- a/test/unittest/builtinvar/tst.errno.d
+++ b/test/unittest/builtinvar/tst.errno.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/builtinvar/tst.errno1.d b/test/unittest/builtinvar/tst.errno1.d
index dcac23ae..c9bd35c2 100644
--- a/test/unittest/builtinvar/tst.errno1.d
+++ b/test/unittest/builtinvar/tst.errno1.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/builtinvar/tst.errno3.r b/test/unittest/builtinvar/tst.errno3.r
new file mode 100644
index 00000000..708ecc26
--- /dev/null
+++ b/test/unittest/builtinvar/tst.errno3.r
@@ -0,0 +1 @@
+ 0 0 0 0 0 0 0 0 0 2 0 9 0 2 0 9 0 0 0 0 0 0 0 0
diff --git a/test/unittest/builtinvar/tst.errno3.sh b/test/unittest/builtinvar/tst.errno3.sh
new file mode 100755
index 00000000..40215f31
--- /dev/null
+++ b/test/unittest/builtinvar/tst.errno3.sh
@@ -0,0 +1,56 @@
+#!/bin/bash
+#
+# Oracle Linux DTrace.
+# Copyright (c) 2021, 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.
+#
+
+dtrace=$1
+CC=/usr/bin/gcc
+
+DIRNAME="$tmpdir/builtinvar-errno3.$$.$RANDOM"
+mkdir -p $DIRNAME
+cd $DIRNAME
+
+cat << EOF > main.c
+#include <stdio.h>
+#include <errno.h>
+#include <sys/types.h> /* open() */
+#include <sys/stat.h> /* open() */
+#include <fcntl.h> /* open() */
+#include <unistd.h> /* close() */
+void foo(char *s) {
+ int fd = open(s, O_WRONLY);
+ close(fd);
+}
+int main(int c, char **v) {
+ foo("/dev/null");
+ foo("/dev/null");
+ foo("/no/such/path/exists");
+ foo("/no/such/path/exists");
+ foo("/dev/null");
+ foo("/dev/null");
+ return 0;
+}
+EOF
+
+$CC main.c
+if [ $? -ne 0 ]; then
+ echo compilation failed
+ exit 1
+fi
+
+$dtrace $dt_flags -qn '
+ syscall::open:,
+ syscall::openat:,
+ syscall::close:
+ /pid == $target/
+ { printf(" %d", errno); }
+' -c ./a.out
+if [ $? -ne 0 ]; then
+ echo DTrace failed
+ exit 1
+fi
+
+exit 0
diff --git a/test/unittest/variables/bvar/tst.errno.d b/test/unittest/variables/bvar/tst.errno.d
index f7a08071..4a866dff 100644
--- a/test/unittest/variables/bvar/tst.errno.d
+++ b/test/unittest/variables/bvar/tst.errno.d
@@ -1,10 +1,9 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 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 'errno' variable can be accessed and is not -1.
--
2.18.4
More information about the DTrace-devel
mailing list