[DTrace-devel] [PATCH] Add support for getmajor() and getminor() subroutines

eugene.loh at oracle.com eugene.loh at oracle.com
Tue Feb 15 20:00:18 UTC 2022


From: Eugene Loh <eugene.loh at oracle.com>

The expected behavior is unclear.  E.g., with D script
    y = 0x1234567890abcdef;
    printf("%x\n", getmajor(y));
    printf("%x\n", getminor(y));
Solaris gives
    12345678
    90abcdef
while legacy DTrace (on Linux) gives
    90a
    bcdef
Further, there were no tests.

Implement the behavior that is in /usr/include/linux/kdev_t.h:
    #define MAJOR(dev)      ((dev)>>8)
    #define MINOR(dev)      ((dev) & 0xff)
and add tests.

Signed-off-by: Eugene Loh <eugene.loh at oracle.com>
---
 libdtrace/dt_cg.c                   | 27 +++++++++++-
 test/unittest/funcs/tst.getmajor.sh | 65 +++++++++++++++++++++++++++++
 test/unittest/funcs/tst.getminor.sh | 59 ++++++++++++++++++++++++++
 3 files changed, 149 insertions(+), 2 deletions(-)
 create mode 100755 test/unittest/funcs/tst.getmajor.sh
 create mode 100755 test/unittest/funcs/tst.getminor.sh

diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
index b6b39617..bd05bd32 100644
--- a/libdtrace/dt_cg.c
+++ b/libdtrace/dt_cg.c
@@ -3374,6 +3374,29 @@ dt_cg_subr_dirname(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
 	dt_cg_subr_path_helper(dnp, dlp, drp, "dt_dirname");
 }
 
+/*
+ * For getmajor and getminor, see /usr/include/linux/kdev_t.h.
+ */
+static void
+dt_cg_subr_getmajor(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
+{
+	dt_node_t	*arg = dnp->dn_args;
+
+	dt_cg_node(arg, dlp, drp);
+	dnp->dn_reg = arg->dn_reg;
+	emit(dlp, BPF_ALU64_IMM(BPF_RSH, dnp->dn_reg, 8));
+}
+
+static void
+dt_cg_subr_getminor(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
+{
+	dt_node_t	*arg = dnp->dn_args;
+
+	dt_cg_node(arg, dlp, drp);
+	dnp->dn_reg = arg->dn_reg;
+	emit(dlp, BPF_ALU64_IMM(BPF_AND, dnp->dn_reg, 0xff));
+}
+
 /*
  * Get and return a new speculation ID.  These are unallocated entries in the
  * specs map, obtained by calling dt_speculation().  Return zero if none is
@@ -4120,8 +4143,8 @@ static dt_cg_subr_f *_dt_cg_subr[DIF_SUBR_MAX + 1] = {
 	[DIF_SUBR_COPYINTO]		= NULL,
 	[DIF_SUBR_MSGDSIZE]		= NULL,
 	[DIF_SUBR_MSGSIZE]		= NULL,
-	[DIF_SUBR_GETMAJOR]		= NULL,
-	[DIF_SUBR_GETMINOR]		= NULL,
+	[DIF_SUBR_GETMAJOR]		= &dt_cg_subr_getmajor,
+	[DIF_SUBR_GETMINOR]		= &dt_cg_subr_getminor,
 	[DIF_SUBR_DDI_PATHNAME]		= NULL,
 	[DIF_SUBR_STRJOIN]		= dt_cg_subr_strjoin,
 	[DIF_SUBR_LLTOSTR]		= &dt_cg_subr_lltostr,
diff --git a/test/unittest/funcs/tst.getmajor.sh b/test/unittest/funcs/tst.getmajor.sh
new file mode 100755
index 00000000..65fb5036
--- /dev/null
+++ b/test/unittest/funcs/tst.getmajor.sh
@@ -0,0 +1,65 @@
+#!/bin/bash
+#
+# Oracle Linux DTrace.
+# Copyright (c) 2022, 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
+
+DIRNAME="$tmpdir/getmajor.$$.$RANDOM"
+mkdir -p $DIRNAME
+cd $DIRNAME
+
+cat << EOF > test.c
+#include <stdio.h>
+#include <sys/types.h>		/* for dev_t, or use <sys/stat.h> */
+#include <linux/kdev_t.h>	/* for MAJOR */
+
+int main(int c, char **v) {
+	long long y = 0x1234567890abcdefll;
+	dev_t x = y;
+
+	/*
+	 * sizeof(dev_t) is:
+	 *   8 bytes in  user  header /usr/include/sys/types.h
+	 *   4 bytes in kernel header include/linux/types.h
+	 * DTrace uses the kernel dev_t.  So truncate the result.
+	 */
+	printf("%x\n\n", (unsigned int) MAJOR(x));
+	return 0;
+}
+EOF
+
+gcc test.c
+if [ $? -ne 0 ]; then
+	echo ERROR: test.c did not compile
+	exit 1
+fi
+
+./a.out > test.out
+
+$dtrace -qn '
+BEGIN
+{
+	printf("%x\n", getmajor(0x1234567890abcdef));
+	exit(0)
+}' > dtrace.out
+if [ $? -ne 0 ]; then
+	echo ERROR: dtrace error
+	exit 1
+fi
+
+diff test.out dtrace.out
+if [ $? -ne 0 ]; then
+	echo ERROR: unexpected output
+	echo expect:
+	cat test.out
+	echo actual:
+	cat dtrace.out
+	exit 1
+fi
+
+echo success
+exit 0
diff --git a/test/unittest/funcs/tst.getminor.sh b/test/unittest/funcs/tst.getminor.sh
new file mode 100755
index 00000000..34b77e23
--- /dev/null
+++ b/test/unittest/funcs/tst.getminor.sh
@@ -0,0 +1,59 @@
+#!/bin/bash
+#
+# Oracle Linux DTrace.
+# Copyright (c) 2022, 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
+
+DIRNAME="$tmpdir/getminor.$$.$RANDOM"
+mkdir -p $DIRNAME
+cd $DIRNAME
+
+cat << EOF > test.c
+#include <stdio.h>
+#include <sys/types.h>		/* for dev_t, or use <sys/stat.h> */
+#include <linux/kdev_t.h>	/* for MINOR */
+
+int main(int c, char **v) {
+	long long y = 0x1234567890abcdefll;
+	dev_t x = y;
+
+	printf("%x\n\n", (unsigned int) MINOR(x));
+	return 0;
+}
+EOF
+
+gcc test.c
+if [ $? -ne 0 ]; then
+	echo ERROR: test.c did not compile
+	exit 1
+fi
+
+./a.out > test.out
+
+$dtrace -qn '
+BEGIN
+{
+	printf("%x\n", getminor(0x1234567890abcdef));
+	exit(0)
+}' > dtrace.out
+if [ $? -ne 0 ]; then
+	echo ERROR: dtrace error
+	exit 1
+fi
+
+diff test.out dtrace.out
+if [ $? -ne 0 ]; then
+	echo ERROR: unexpected output
+	echo expect:
+	cat test.out
+	echo actual:
+	cat dtrace.out
+	exit 1
+fi
+
+echo success
+exit 0
-- 
2.18.4




More information about the DTrace-devel mailing list