Skip to content

Commit

Permalink
Add support for built-in variable errno
Browse files Browse the repository at this point in the history
The built-in variable errno should be:

  *)  the errno for failed system calls for syscall:::return probes

  *)  0 otherwise

The D errno variable is different from the C library errno variable.
Also, the behavior differs from that described in the DTrace Guide,
which allows errno to be non-0 for non-syscall probes.

Introduce an mst->syscall_errno, and have the provider trampolines set
it to 0.  Then have syscall:::return probes check arg0, setting
mst->syscall_errno=-arg0 if the value would be within bounds.  Finally,
have dt_get_bvar() retrieve errno from mst->syscall_errno.

Update tests.  The only particularly meaningful test for errno is
tst.errno2.d, which will not yet work since it still needs other as yet
unsupported features.  Add a tst.errno3.sh test for the new errno support.

Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
Reviewed-by: Kris Van Hees <kris.van.hees@oracle.com>
  • Loading branch information
euloh authored and kvanhees committed Jun 18, 2021
1 parent e48bf6a commit 26724bc
Show file tree
Hide file tree
Showing 9 changed files with 81 additions and 3 deletions.
2 changes: 2 additions & 0 deletions bpf/get_bvar.c
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@ noinline uint64_t dt_get_bvar(dt_dctx_t *dctx, uint32_t id)

return val >> 32;
}
case DIF_VAR_ERRNO:
return mst->syscall_errno;
case DIF_VAR_CURCPU: {
uint32_t key = 0;
void *val = bpf_map_lookup_elem(&cpuinfo, &key);
Expand Down
3 changes: 3 additions & 0 deletions libdtrace/dt_cg.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ 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->syscall_errno = 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);
Expand All @@ -127,6 +129,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);
Expand Down
2 changes: 2 additions & 0 deletions libdtrace/dt_dctx.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 syscall_errno; /* syscall errno */
uint64_t fault; /* DTrace fault flags */
uint64_t tstamp; /* cached timestamp value */
#if 0
Expand Down Expand Up @@ -64,6 +65,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, syscall_errno)
#define DMST_FAULT offsetof(dt_mstate_t, fault)
#define DMST_TSTAMP offsetof(dt_mstate_t, tstamp)
#define DMST_REGS offsetof(dt_mstate_t, regs)
Expand Down
17 changes: 17 additions & 0 deletions libdtrace/dt_prov_syscall.c
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,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->syscall_errno.
*/
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);
}

Expand Down
1 change: 0 additions & 1 deletion test/unittest/builtinvar/tst.errno.d
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
1 change: 0 additions & 1 deletion test/unittest/builtinvar/tst.errno1.d
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
1 change: 1 addition & 0 deletions test/unittest/builtinvar/tst.errno3.r
Original file line number Diff line number Diff line change
@@ -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
56 changes: 56 additions & 0 deletions test/unittest/builtinvar/tst.errno3.sh
Original file line number Diff line number Diff line change
@@ -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 -Zqn '
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
1 change: 0 additions & 1 deletion test/unittest/variables/bvar/tst.errno.d
Original file line number Diff line number Diff line change
Expand Up @@ -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: The 'errno' variable can be accessed and is not -1.
Expand Down

0 comments on commit 26724bc

Please sign in to comment.