summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan McDonald <danmcd@mnx.io>2022-11-10 11:06:38 -0500
committerDan McDonald <danmcd@mnx.io>2022-11-10 11:06:38 -0500
commitfe2789d05c8a7f2b216028f4b925f14ad6490f7e (patch)
tree2f6170d853de053c2c872d435b6496719a99b2d5
parent758597efca5a7022fe4ed7c3b6653ed0068e795e (diff)
parent6eeafb34dceabceff80ed689002b6dc3e060f498 (diff)
downloadillumos-joyent-fe2789d05c8a7f2b216028f4b925f14ad6490f7e.tar.gz
[illumos-gate merge]
commit 6eeafb34dceabceff80ed689002b6dc3e060f498 15109 dtrace replicated mdb's bitfield mistakes 15111 dtrace -xtree doesn't always escape strings commit 603778843038dfbc5672c2565d9ce3dac034609d 15110 mdb ::printf replicated mdb ::print bitfield mistakes commit f651720770e11ade275c4fc451e6b00c9e5d3068 15126 ipv4info_t translator produces bad flags value 15113 dtrace ICMPv4 tests fail due to flags mismatch commit 17425aa5357a01155862de9af35ff553bab2bb86 15121 tst.temporal.ksh has PATH dependencies
-rw-r--r--exception_lists/wscheck2
-rw-r--r--usr/src/cmd/dtrace/test/tst/common/Makefile10
-rw-r--r--usr/src/cmd/dtrace/test/tst/common/bitfields/tst.bitfields.c92
-rw-r--r--usr/src/cmd/dtrace/test/tst/common/bitfields/tst.bitfields.ksh63
-rw-r--r--usr/src/cmd/dtrace/test/tst/common/bitfields/tst.bitfields.ksh.out28
-rwxr-xr-xusr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4localicmp.ksh3
-rw-r--r--usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4localicmp.ksh.out8
-rwxr-xr-xusr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteicmp.ksh3
-rw-r--r--usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteicmp.ksh.out4
-rw-r--r--usr/src/cmd/dtrace/test/tst/common/pragma/tst.temporal.ksh8
-rw-r--r--usr/src/cmd/mdb/common/mdb/mdb_print.c90
-rw-r--r--usr/src/lib/libdtrace/common/dt_cg.c15
-rw-r--r--usr/src/lib/libdtrace/common/dt_ident.c2
-rw-r--r--usr/src/lib/libdtrace/common/dt_impl.h5
-rw-r--r--usr/src/lib/libdtrace/common/dt_parser.c36
-rw-r--r--usr/src/lib/libdtrace/common/dt_parser.h4
-rw-r--r--usr/src/lib/libdtrace/common/dt_print.c43
-rw-r--r--usr/src/lib/libdtrace/common/dt_subr.c23
-rw-r--r--usr/src/lib/libdtrace/common/ip.d.in4
-rw-r--r--usr/src/pkg/manifests/system-dtrace-tests.p5m3
-rw-r--r--usr/src/test/util-tests/tests/mdb/numbers/tst.bitfields.ksh78
-rw-r--r--usr/src/test/util-tests/tests/mdb/numbers/tst.bitfields.ksh.out57
22 files changed, 504 insertions, 77 deletions
diff --git a/exception_lists/wscheck b/exception_lists/wscheck
index 4b4465646c..638acb3f52 100644
--- a/exception_lists/wscheck
+++ b/exception_lists/wscheck
@@ -193,4 +193,4 @@ usr/src/lib/lib9p/common/*
# These bits form the mdb test suite are all literal output from mdb and
# therefore trailing spaces may be part of what mdb does today.
#
-usr/src/test/util-tests/tests/mdb/*/*.mdb.out
+usr/src/test/util-tests/tests/mdb/*/*.*.out
diff --git a/usr/src/cmd/dtrace/test/tst/common/Makefile b/usr/src/cmd/dtrace/test/tst/common/Makefile
index 9ec706565a..14ba3acd19 100644
--- a/usr/src/cmd/dtrace/test/tst/common/Makefile
+++ b/usr/src/cmd/dtrace/test/tst/common/Makefile
@@ -28,6 +28,7 @@
# Copyright (c) 2012 by Delphix. All rights reserved.
# Copyright 2015 Nexenta Systems, Inc. All rights reserved.
# Copyright 2018 Joyent, Inc.
+# Copyright 2022 Oxide Computer Company
#
#
@@ -90,9 +91,16 @@ json/tst.usdt.exe: json/tst.usdt.o json/usdt.o
$(POST_PROCESS) ; $(STRIP_STABS)
#
-# Tests that use the next three programs rely on the binaries having
+# Tests that use the next four programs rely on the binaries having
# valid CTF data.
#
+bitfields/tst.bitfields.exe: bitfields/tst.bitfields.c
+ $(COMPILE.c) $(CTF_FLAGS) -o bitfields/tst.bitfields.o bitfields/tst.bitfields.c
+ $(CTFCONVERT) -i -L VERSION bitfields/tst.bitfields.o
+ $(LINK.c) -o bitfields/tst.bitfields.exe bitfields/tst.bitfields.o $(LDLIBS)
+ $(CTFMERGE) -L VERSION -o $@ bitfields/tst.bitfields.o
+ $(POST_PROCESS) ; $(STRIP_STABS)
+
uctf/tst.aouttype.exe: uctf/tst.aouttype.c
$(COMPILE.c) $(CTF_FLAGS) -o uctf/tst.aouttype.o uctf/tst.aouttype.c
$(CTFCONVERT) -i -L VERSION uctf/tst.aouttype.o
diff --git a/usr/src/cmd/dtrace/test/tst/common/bitfields/tst.bitfields.c b/usr/src/cmd/dtrace/test/tst/common/bitfields/tst.bitfields.c
new file mode 100644
index 0000000000..180127191a
--- /dev/null
+++ b/usr/src/cmd/dtrace/test/tst/common/bitfields/tst.bitfields.c
@@ -0,0 +1,92 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2022 Oxide Computer Company
+ */
+
+/*
+ * This is designed to allow us to execute print() and various dereferencing
+ * operations with bitfields. It reads the values from argc and passes them to
+ * functions that we can then take apart. Crtitically this uses bitfields
+ * constructed via CTF and not the D compiler.
+ */
+
+#include <err.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <errno.h>
+
+typedef struct bit0 {
+ uint32_t a:3;
+ uint32_t b:2;
+ uint32_t c:1;
+ uint32_t d:1;
+ uint32_t e:1;
+ uint32_t f:1;
+ uint32_t g:3;
+ uint32_t h:3;
+ uint32_t i:5;
+ uint32_t j:4;
+ uint32_t k:6;
+ uint32_t l:1;
+ uint32_t m:1;
+} bit0_t;
+
+typedef struct bit1 {
+ uint16_t a:1;
+ uint16_t b:8;
+ uint16_t c:3;
+ uint16_t d:2;
+ uint16_t e:1;
+ uint16_t f:1;
+} bit1_t;
+
+void
+mumble(FILE *f, bit0_t *zero, bit1_t *one)
+{
+ (void) fprintf(f, "%u\n%u\n", zero->k, one->d);
+}
+
+int
+main(int argc, char *argv[])
+{
+ unsigned long l;
+ uint16_t u16;
+ uint32_t u32;
+ FILE *f;
+
+ if (argc != 3) {
+ errx(EXIT_FAILURE, "Need two ints");
+ }
+
+ f = fopen("/dev/null", "rw+");
+ if (f == NULL) {
+ err(EXIT_FAILURE, "failed to open /dev/null");
+ }
+
+ errno = 0;
+ l = strtoul(argv[1], NULL, 0);
+ if (errno != 0 || l == 0 || l > UINT16_MAX) {
+ errx(EXIT_FAILURE, "invalid u16 value: %s", argv[1]);
+ }
+ u16 = (uint16_t)l;
+
+ l = strtoul(argv[2], NULL, 0);
+ if (errno != 0 || l == 0 || l > UINT32_MAX) {
+ errx(EXIT_FAILURE, "invalid u32 value: %s", argv[1]);
+ }
+ u32 = (uint32_t)l;
+ mumble(f, (bit0_t *)&u32, (bit1_t *)&u16);
+
+ return (0);
+}
diff --git a/usr/src/cmd/dtrace/test/tst/common/bitfields/tst.bitfields.ksh b/usr/src/cmd/dtrace/test/tst/common/bitfields/tst.bitfields.ksh
new file mode 100644
index 0000000000..b79046ba62
--- /dev/null
+++ b/usr/src/cmd/dtrace/test/tst/common/bitfields/tst.bitfields.ksh
@@ -0,0 +1,63 @@
+#!/usr/bin/ksh
+#
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2022 Oxide Computer Company
+#
+
+#
+# This test acts as a series of regression tests in DTrace around
+# printing bitfields that are byte sized at non-byte aligned offsets and
+# around printing fields that are less than a byte in size, but due to their
+# offset, cross a byte boundary (e.g. a 5-bit bitfield that starts at
+# bit 6).
+#
+# The DTrace implementation has two different general paths for this:
+#
+# o The D compiler compiling a dereference into DIF code to be executed
+# in probe context to extract a bitfield value.
+# o The print() action which grabs the larger chunk of memory and then
+# processes it all in userland.
+#
+
+if [ $# != 1 ]; then
+ echo expected one argument: '<'dtrace-path'>'
+ exit 2
+fi
+
+dtrace=$1
+exe="tst.bitfields.exe"
+
+elfdump "./$exe" | grep -q '.SUNW_ctf'
+if (( $? != 0 )); then
+ echo "CTF does not exist in $exe, that's a bug" >&2
+ exit 1
+fi
+
+$dtrace -qs /dev/stdin -c "./$exe 0xe417 0x9391d7db" <<EOF
+pid\$target::mumble:entry
+{
+ print(*args[1]);
+ printf("\n");
+ print(*args[2]);
+ printf("\n");
+ trace(args[2]->b);
+ printf("\n0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", args[2]->a, args[2]->b,
+ args[2]->c, args[2]->d, args[2]->e, args[2]->f);
+ trace(args[1]->i);
+ printf("\n0x%x 0x%x 0x%x 0x%x\n", args[1]->g, args[1]->h, args[1]->i,
+ args[1]->j);
+}
+EOF
+
+exit $rc
diff --git a/usr/src/cmd/dtrace/test/tst/common/bitfields/tst.bitfields.ksh.out b/usr/src/cmd/dtrace/test/tst/common/bitfields/tst.bitfields.ksh.out
new file mode 100644
index 0000000000..8db1736859
--- /dev/null
+++ b/usr/src/cmd/dtrace/test/tst/common/bitfields/tst.bitfields.ksh.out
@@ -0,0 +1,28 @@
+bit0_t {
+ unsigned int:3 a :3 = 0x3
+ unsigned int:2 b :2 = 0x3
+ unsigned int:1 c :1 = 0
+ unsigned int:1 d :1 = 0x1
+ unsigned int:1 e :1 = 0x1
+ unsigned int:1 f :1 = 0x1
+ unsigned int:3 g :3 = 0x3
+ unsigned int:3 h :3 = 0x5
+ unsigned int:5 i :5 = 0x3
+ unsigned int:4 j :4 = 0x9
+ unsigned int:6 k :6 = 0x13
+ unsigned int:1 l :1 = 0
+ unsigned int:1 m :1 = 0x1
+}
+bit1_t {
+ unsigned short:1 a :1 = 0x1
+ unsigned short:8 b :8 = 0xb
+ unsigned short:3 c :3 = 0x2
+ unsigned short:2 d :2 = 0x2
+ unsigned short:1 e :1 = 0x1
+ unsigned short:1 f :1 = 0x1
+}
+11
+0x1 0xb 0x2 0x2 0x1 0x1
+3
+0x3 0x5 0x3 0x9
+
diff --git a/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4localicmp.ksh b/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4localicmp.ksh
index 0965040e62..d95a00c48a 100755
--- a/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4localicmp.ksh
+++ b/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4localicmp.ksh
@@ -24,7 +24,6 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-#pragma ident "%Z%%M% %I% %E% SMI"
#
# Test ip:::{send,receive} of IPv4 ICMP to a local address.
@@ -45,7 +44,7 @@ fi
dtrace=$1
local=127.0.0.1
-$dtrace -c "/usr/sbin/ping $local 3" -qs /dev/stdin <<EOF | sort -n
+$dtrace -c "/usr/sbin/ping -D $local 3" -qs /dev/stdin <<EOF | sort -n
ip:::send
/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" &&
args[4]->ipv4_protocol == IPPROTO_ICMP/
diff --git a/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4localicmp.ksh.out b/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4localicmp.ksh.out
index 41d6e0c8ad..ce028a4c86 100644
--- a/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4localicmp.ksh.out
+++ b/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4localicmp.ksh.out
@@ -1,6 +1,6 @@
-1 ip:::send (args[2]: 4 64, args[4]: 4 84 0 0 255)
-1 ip:::send (args[2]: 4 64, args[4]: 4 84 0 0 255)
-2 ip:::receive (args[2]: 4 64, args[4]: 4 84 0 0 255)
-2 ip:::receive (args[2]: 4 64, args[4]: 4 84 0 0 255)
+1 ip:::send (args[2]: 4 64, args[4]: 4 84 2 0 255)
+1 ip:::send (args[2]: 4 64, args[4]: 4 84 2 0 255)
+2 ip:::receive (args[2]: 4 64, args[4]: 4 84 2 0 255)
+2 ip:::receive (args[2]: 4 64, args[4]: 4 84 2 0 255)
127.0.0.1 is alive
diff --git a/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteicmp.ksh b/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteicmp.ksh
index efe0d30fa9..b2aa601ad2 100755
--- a/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteicmp.ksh
+++ b/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteicmp.ksh
@@ -24,7 +24,6 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-#pragma ident "%Z%%M% %I% %E% SMI"
#
# Test ip:::{send,receive} of IPv4 ICMP to a remote host.
@@ -55,7 +54,7 @@ if (( $? != 0 )); then
exit 4
fi
-$dtrace -c "/usr/sbin/ping $dest 3" -qs /dev/stdin <<EOF | \
+$dtrace -c "/usr/sbin/ping -D $dest 3" -qs /dev/stdin <<EOF | \
grep -v 'is alive' | sort -n
ip:::send
/args[2]->ip_saddr == "$source" && args[2]->ip_daddr == "$dest" &&
diff --git a/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteicmp.ksh.out b/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteicmp.ksh.out
index b5915f8db4..a330569d62 100644
--- a/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteicmp.ksh.out
+++ b/usr/src/cmd/dtrace/test/tst/common/ip/tst.ipv4remoteicmp.ksh.out
@@ -1,3 +1,3 @@
-1 ip:::send (args[2]: 4 64, args[4]: 4 84 0 0 255)
-2 ip:::receive (args[2]: 4 64, args[4]: 4 84 4 0 255)
+1 ip:::send (args[2]: 4 64, args[4]: 4 84 2 0 255)
+2 ip:::receive (args[2]: 4 64, args[4]: 4 84 2 0 255)
diff --git a/usr/src/cmd/dtrace/test/tst/common/pragma/tst.temporal.ksh b/usr/src/cmd/dtrace/test/tst/common/pragma/tst.temporal.ksh
index 9a0aed0678..eb8397478a 100644
--- a/usr/src/cmd/dtrace/test/tst/common/pragma/tst.temporal.ksh
+++ b/usr/src/cmd/dtrace/test/tst/common/pragma/tst.temporal.ksh
@@ -1,7 +1,5 @@
#!/bin/ksh -p
#
-# CDDL HEADER START
-#
# This file and its contents are supplied under the terms of the
# Common Development and Distribution License ("CDDL"), version 1.0.
# You may only use this file in accordance with the terms of version
@@ -11,11 +9,10 @@
# source. A copy of the CDDL is also available via the Internet at
# http://www.illumos.org/license/CDDL.
#
-# CDDL HEADER END
-#
#
# Copyright (c) 2012 by Delphix. All rights reserved.
+# Copyright 2022 Oxide Computer Company
#
############################################################################
@@ -74,7 +71,8 @@ fi
# dtrace outputs a blank line at the end, which will sort to the beginning,
# so use head to remove the blank line.
-head -n -1 $file > $file.2
+nlines=$(wc -l $file | awk '{ print $1 - 1}')
+head -n $nlines $file > $file.2
sort -n $file.2 | diff $file.2 -
status=$?
diff --git a/usr/src/cmd/mdb/common/mdb/mdb_print.c b/usr/src/cmd/mdb/common/mdb/mdb_print.c
index a7c806ad29..9bd5028b08 100644
--- a/usr/src/cmd/mdb/common/mdb/mdb_print.c
+++ b/usr/src/cmd/mdb/common/mdb/mdb_print.c
@@ -27,7 +27,7 @@
* Copyright (c) 2012, 2014 by Delphix. All rights reserved.
* Copyright 2020 Joyent, Inc.
* Copyright (c) 2014 Nexenta Systems, Inc. All rights reserved.
- * Copyright 2021 Oxide Computer Company
+ * Copyright 2022 Oxide Computer Company
*/
#include <mdb/mdb_modapi.h>
@@ -855,6 +855,28 @@ cmd_array(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
}
/*
+ * This is a shared implementation to determine if we should treat a type as a
+ * bitfield. The parameters are the CTF encoding and the bit offset of the
+ * integer. This also exists in mdb_print.c. We consider something a bitfield
+ * if:
+ *
+ * o The type is more than 8 bytes. This is a bit of a historical choice from
+ * mdb and is a stranger one. The normal integer handling code generally
+ * doesn't handle integers more than 64-bits in size. Of course neither does
+ * the bitfield code...
+ * o The bit count is not a multiple of 8.
+ * o The size in bytes is not a power of 2.
+ * o The offset is not a multiple of 8.
+ */
+boolean_t
+is_bitfield(const ctf_encoding_t *ep, ulong_t off)
+{
+ size_t bsize = ep->cte_bits / NBBY;
+ return (bsize > 8 || (ep->cte_bits % NBBY) != 0 ||
+ (bsize & (bsize - 1)) != 0 || (off % NBBY) != 0);
+}
+
+/*
* Print an integer bitfield in hexadecimal by reading the enclosing byte(s)
* and then shifting and masking the data in the lower bits of a uint64_t.
*/
@@ -862,14 +884,21 @@ static int
print_bitfield(ulong_t off, printarg_t *pap, ctf_encoding_t *ep)
{
mdb_tgt_addr_t addr = pap->pa_addr + off / NBBY;
- size_t size = (ep->cte_bits + (NBBY - 1)) / NBBY;
uint64_t mask = (1ULL << ep->cte_bits) - 1;
uint64_t value = 0;
uint8_t *buf = (uint8_t *)&value;
uint8_t shift;
-
const char *format;
+ /*
+ * Our bitfield may straddle a byte boundary. We explicitly take the
+ * offset of the bitfield within its byte into account when determining
+ * the overall amount of data to copy and mask off from the underlying
+ * data.
+ */
+ uint_t nbits = ep->cte_bits + (off % NBBY);
+ size_t size = P2ROUNDUP(nbits, NBBY) / NBBY;
+
if (!(pap->pa_flags & PA_SHOWVAL))
return (0);
@@ -878,17 +907,9 @@ print_bitfield(ulong_t off, printarg_t *pap, ctf_encoding_t *ep)
return (0);
}
- /*
- * Our bitfield may stradle a byte boundary, if so, the calculation of
- * size may not correctly capture that. However, off is relative to the
- * entire bitfield, so we first have to make that relative to the byte.
- */
- if ((off % 8) + ep->cte_bits > NBBY * size) {
- size++;
- }
-
if (size > sizeof (value)) {
mdb_printf("??? (total bitfield too large after alignment");
+ return (0);
}
/*
@@ -1002,14 +1023,8 @@ print_int_val(const char *type, ctf_encoding_t *ep, ulong_t off,
return (0);
}
- /*
- * If the size is not a power-of-two number of bytes in the range 1-8 or
- * power-of-two number starts in the middle of a byte then we assume it
- * is a bitfield and print it as such.
- */
size = ep->cte_bits / NBBY;
- if (size > 8 || (ep->cte_bits % NBBY) != 0 || (size & (size - 1) ||
- (off % NBBY) != 0) != 0) {
+ if (is_bitfield(ep, off)) {
return (print_bitfield(off, pap, ep));
}
@@ -1811,7 +1826,7 @@ static int
pipe_print(mdb_ctf_id_t id, ulong_t off, void *data)
{
printarg_t *pap = data;
- ssize_t size;
+ size_t size;
static const char *const fsp[] = { "%#r", "%#r", "%#r", "%#llr" };
uintptr_t value;
uintptr_t addr = pap->pa_addr + off / NBBY;
@@ -1870,13 +1885,12 @@ again:
* For immediate values, we just print out the value.
*/
size = e.cte_bits / NBBY;
- if (size > 8 || (e.cte_bits % NBBY) != 0 ||
- (size & (size - 1)) != 0) {
+ if (is_bitfield(&e, off)) {
return (print_bitfield(off, pap, &e));
}
if (mdb_tgt_aread(pap->pa_tgt, pap->pa_as, &u.i8, size,
- addr) != size) {
+ addr) != (size_t)size) {
mdb_warn("failed to read %lu bytes at %p",
(ulong_t)size, pap->pa_addr);
return (-1);
@@ -2627,7 +2641,7 @@ print_help(void)
static int
printf_signed(mdb_ctf_id_t id, uintptr_t addr, ulong_t off, char *fmt, int sign)
{
- ssize_t size;
+ size_t size;
mdb_ctf_id_t base;
ctf_encoding_t e;
@@ -2676,23 +2690,43 @@ printf_signed(mdb_ctf_id_t id, uintptr_t addr, ulong_t off, char *fmt, int sign)
* particular, see the comments there for an explanation of the
* endianness differences in this code.)
*/
- if (size > 8 || (e.cte_bits % NBBY) != 0 ||
- (size & (size - 1)) != 0) {
+ if (is_bitfield(&e, off)) {
uint64_t mask = (1ULL << e.cte_bits) - 1;
uint64_t value = 0;
uint8_t *buf = (uint8_t *)&value;
uint8_t shift;
+ uint_t nbits;
/*
- * Round our size up one byte.
+ * Our bitfield may straddle a byte boundary. We explicitly take
+ * the offset of the bitfield within its byte into account when
+ * determining the overall amount of data to copy and mask off
+ * from the underlying data.
*/
- size = (e.cte_bits + (NBBY - 1)) / NBBY;
+ nbits = e.cte_bits + (off % NBBY);
+ size = P2ROUNDUP(nbits, NBBY) / NBBY;
if (e.cte_bits > sizeof (value) * NBBY - 1) {
mdb_printf("invalid bitfield size %u", e.cte_bits);
return (DCMD_ABORT);
}
+ /*
+ * Our bitfield may straddle a byte boundary, if so, the
+ * calculation of size may not correctly capture that. However,
+ * off is relative to the entire bitfield, so we first have to
+ * make that relative to the byte.
+ */
+ if ((off % NBBY) + e.cte_bits > NBBY * size) {
+ size++;
+ }
+
+ if (size > sizeof (value)) {
+ mdb_warn("??? (total bitfield too large after "
+ "alignment\n");
+ return (DCMD_ABORT);
+ }
+
#ifdef _BIG_ENDIAN
buf += sizeof (value) - size;
off += e.cte_bits;
diff --git a/usr/src/lib/libdtrace/common/dt_cg.c b/usr/src/lib/libdtrace/common/dt_cg.c
index 9f3625e6ee..816b31daf7 100644
--- a/usr/src/lib/libdtrace/common/dt_cg.c
+++ b/usr/src/lib/libdtrace/common/dt_cg.c
@@ -28,6 +28,7 @@
/*
* Copyright (c) 2012 by Delphix. All rights reserved.
* Copyright 2017 Joyent, Inc.
+ * Copyright 2022 Oxide Computer Company
*/
#include <sys/types.h>
@@ -160,15 +161,17 @@ dt_cg_load(dt_node_t *dnp, ctf_file_t *ctfp, ctf_id_t type)
ssize_t size;
/*
- * If we're loading a bit-field, the size of our load is found by
- * rounding cte_bits up to a byte boundary and then finding the
- * nearest power of two to this value (see clp2(), above).
+ * If we're loading a bit-field, we find the power-of-two that spans the
+ * full value. To do this we count the number of bytes that contain a
+ * portion of the bit-field.
*/
if ((dnp->dn_flags & DT_NF_BITFIELD) &&
- ctf_type_encoding(ctfp, type, &e) != CTF_ERR)
- size = clp2(P2ROUNDUP(e.cte_bits, NBBY) / NBBY);
- else
+ ctf_type_encoding(ctfp, type, &e) != CTF_ERR) {
+ uint_t nbits = e.cte_bits + (dnp->dn_bitoff % NBBY);
+ size = clp2(P2ROUNDUP(nbits, NBBY) / NBBY);
+ } else {
size = ctf_type_size(ctfp, type);
+ }
if (size < 1 || size > 8 || (size & (size - 1)) != 0) {
xyerror(D_UNKNOWN, "internal error -- cg cannot load "
diff --git a/usr/src/lib/libdtrace/common/dt_ident.c b/usr/src/lib/libdtrace/common/dt_ident.c
index 33f94eb9fd..6927132ada 100644
--- a/usr/src/lib/libdtrace/common/dt_ident.c
+++ b/usr/src/lib/libdtrace/common/dt_ident.c
@@ -23,6 +23,7 @@
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013 by Delphix. All rights reserved.
* Copyright (c) 2013 Joyent, Inc. All rights reserved.
+ * Copyright 2022 Oxide Computer Company
*/
#include <sys/sysmacros.h>
@@ -266,6 +267,7 @@ dt_idcook_func(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args)
if (strcmp(p1, "@") == 0 || strcmp(p1, "...") == 0) {
isp->dis_args[i].dn_ctfp = NULL;
isp->dis_args[i].dn_type = CTF_ERR;
+ isp->dis_args[i].dn_bitoff = 0;
if (*p1 == '.')
isp->dis_varargs = i;
continue;
diff --git a/usr/src/lib/libdtrace/common/dt_impl.h b/usr/src/lib/libdtrace/common/dt_impl.h
index 988b7f6fb7..cdf70586b0 100644
--- a/usr/src/lib/libdtrace/common/dt_impl.h
+++ b/usr/src/lib/libdtrace/common/dt_impl.h
@@ -27,6 +27,7 @@
/*
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
* Copyright (c) 2011, 2016 by Delphix. All rights reserved.
+ * Copyright 2022 Oxide Computer Company
*/
#ifndef _DT_IMPL_H
@@ -166,7 +167,7 @@ typedef struct dt_ahash {
} dt_ahash_t;
typedef struct dt_aggregate {
- dtrace_bufdesc_t dtat_buf; /* buf aggregation snapshot */
+ dtrace_bufdesc_t dtat_buf; /* buf aggregation snapshot */
int dtat_flags; /* aggregate flags */
processorid_t dtat_ncpus; /* number of CPUs in aggregate */
processorid_t *dtat_cpus; /* CPUs in aggregate */
@@ -653,6 +654,8 @@ extern int dt_handle_setopt(dtrace_hdl_t *, dtrace_setoptdata_t *);
extern int dt_lib_depend_add(dtrace_hdl_t *, dt_list_t *, const char *);
extern dt_lib_depend_t *dt_lib_depend_lookup(dt_list_t *, const char *);
+extern boolean_t dt_is_bitfield(const ctf_encoding_t *, ulong_t);
+
extern dt_pcb_t *yypcb; /* pointer to current parser control block */
extern char yyintprefix; /* int token prefix for macros (+/-) */
extern char yyintsuffix[4]; /* int token suffix ([uUlL]*) */
diff --git a/usr/src/lib/libdtrace/common/dt_parser.c b/usr/src/lib/libdtrace/common/dt_parser.c
index 176d9b7d48..9cd9520f0f 100644
--- a/usr/src/lib/libdtrace/common/dt_parser.c
+++ b/usr/src/lib/libdtrace/common/dt_parser.c
@@ -23,6 +23,7 @@
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, Joyent Inc. All rights reserved.
* Copyright (c) 2012, 2016 by Delphix. All rights reserved.
+ * Copyright 2022 Oxide Computer Company
*/
/*
@@ -517,6 +518,7 @@ dt_node_xalloc(dtrace_hdl_t *dtp, int kind)
dnp->dn_ctfp = NULL;
dnp->dn_type = CTF_ERR;
+ dnp->dn_bitoff = 0;
dnp->dn_kind = (uchar_t)kind;
dnp->dn_flags = 0;
dnp->dn_op = 0;
@@ -671,8 +673,8 @@ dt_node_attr_assign(dt_node_t *dnp, dtrace_attribute_t attr)
}
void
-dt_node_type_assign(dt_node_t *dnp, ctf_file_t *fp, ctf_id_t type,
- boolean_t user)
+dt_node_type_assign_member(dt_node_t *dnp, ctf_file_t *fp, ctf_id_t type,
+ boolean_t user, ulong_t bitoff)
{
ctf_id_t base = ctf_type_resolve(fp, type);
uint_t kind = ctf_type_kind(fp, base);
@@ -682,9 +684,7 @@ dt_node_type_assign(dt_node_t *dnp, ctf_file_t *fp, ctf_id_t type,
~(DT_NF_SIGNED | DT_NF_REF | DT_NF_BITFIELD | DT_NF_USERLAND);
if (kind == CTF_K_INTEGER && ctf_type_encoding(fp, base, &e) == 0) {
- size_t size = e.cte_bits / NBBY;
-
- if (size > 8 || (e.cte_bits % NBBY) != 0 || (size & (size - 1)))
+ if (dt_is_bitfield(&e, bitoff))
dnp->dn_flags |= DT_NF_BITFIELD;
if (e.cte_format & CTF_INT_SIGNED)
@@ -710,6 +710,15 @@ dt_node_type_assign(dt_node_t *dnp, ctf_file_t *fp, ctf_id_t type,
dnp->dn_flags |= DT_NF_COOKED;
dnp->dn_ctfp = fp;
dnp->dn_type = type;
+ dnp->dn_bitoff = bitoff;
+}
+
+
+void
+dt_node_type_assign(dt_node_t *dnp, ctf_file_t *fp, ctf_id_t type,
+ boolean_t user)
+{
+ return (dt_node_type_assign_member(dnp, fp, type, user, 0));
}
void
@@ -719,6 +728,7 @@ dt_node_type_propagate(const dt_node_t *src, dt_node_t *dst)
dst->dn_flags = src->dn_flags & ~DT_NF_LVALUE;
dst->dn_ctfp = src->dn_ctfp;
dst->dn_type = src->dn_type;
+ dst->dn_bitoff = src->dn_bitoff;
}
const char *
@@ -1369,7 +1379,8 @@ dt_node_type(dt_decl_t *ddp)
dnp->dn_op = DT_TOK_IDENT;
dnp->dn_string = name;
- dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type, dtt.dtt_flags);
+ dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type,
+ (dtt.dtt_flags & DTT_FL_USER) != 0);
if (dtt.dtt_ctfp == dtp->dt_cdefs->dm_ctfp ||
dtt.dtt_ctfp == dtp->dt_ddefs->dm_ctfp)
@@ -1392,6 +1403,7 @@ dt_node_vatype(void)
dnp->dn_op = DT_TOK_IDENT;
dnp->dn_ctfp = yypcb->pcb_hdl->dt_cdefs->dm_ctfp;
dnp->dn_type = CTF_ERR;
+ dnp->dn_bitoff = 0;
dnp->dn_attr = _dtrace_defattr;
return (dnp);
@@ -3767,7 +3779,8 @@ asgn_common:
type = ctf_type_resolve(ctfp, m.ctm_type);
kind = ctf_type_kind(ctfp, type);
- dt_node_type_assign(dnp, ctfp, m.ctm_type, B_FALSE);
+ dt_node_type_assign_member(dnp, ctfp, m.ctm_type, B_FALSE,
+ m.ctm_offset);
dt_node_attr_assign(dnp, lp->dn_attr);
if (op == DT_TOK_PTR && (kind != CTF_K_ARRAY ||
@@ -4137,7 +4150,7 @@ dt_cook_aggregation(dt_node_t *dnp, uint_t idflags)
* probe-description-list
* /x++ && y == 0/
* {
- * trace(x + y++);
+ * trace(x + y++);
* }
*
* but it doesn't seem worth the complexity to handle such rare cases. The
@@ -4842,9 +4855,12 @@ dt_node_printr(dt_node_t *dnp, FILE *fp, int depth)
(u_longlong_t)dnp->dn_value, buf);
break;
- case DT_NODE_STRING:
- (void) fprintf(fp, "STRING \"%s\" (%s)\n", dnp->dn_string, buf);
+ case DT_NODE_STRING: {
+ char *escd = strchr2esc(dnp->dn_string, strlen(dnp->dn_string));
+ (void) fprintf(fp, "STRING \"%s\" (%s)\n", escd, buf);
+ free(escd);
break;
+ }
case DT_NODE_IDENT:
(void) fprintf(fp, "IDENT %s (%s)\n", dnp->dn_string, buf);
diff --git a/usr/src/lib/libdtrace/common/dt_parser.h b/usr/src/lib/libdtrace/common/dt_parser.h
index f5f60a518e..96022ac5c1 100644
--- a/usr/src/lib/libdtrace/common/dt_parser.h
+++ b/usr/src/lib/libdtrace/common/dt_parser.h
@@ -25,6 +25,7 @@
/*
* Copyright (c) 2013, 2016 by Delphix. All rights reserved.
* Copyright (c) 2013 Joyent, Inc. All rights reserved.
+ * Copyright 2022 Oxide Computer Company
*/
#ifndef _DT_PARSER_H
@@ -50,6 +51,7 @@ extern "C" {
typedef struct dt_node {
ctf_file_t *dn_ctfp; /* CTF type container for node's type */
ctf_id_t dn_type; /* CTF type reference for node's type */
+ ulong_t dn_bitoff; /* Offset to the start of the CTF type */
uchar_t dn_kind; /* node kind (DT_NODE_*, defined below) */
uchar_t dn_flags; /* node flags (DT_NF_*, defined below) */
ushort_t dn_op; /* operator (DT_TOK_*, defined by lex) */
@@ -239,6 +241,8 @@ extern void dt_node_link_free(dt_node_t **);
extern void dt_node_attr_assign(dt_node_t *, dtrace_attribute_t);
extern void dt_node_type_assign(dt_node_t *, ctf_file_t *, ctf_id_t, boolean_t);
+extern void dt_node_type_assign_bitfield(dt_node_t *, ctf_file_t *, ctf_id_t,
+ boolean_t, ulong_t);
extern void dt_node_type_propagate(const dt_node_t *, dt_node_t *);
extern const char *dt_node_type_name(const dt_node_t *, char *, size_t);
extern size_t dt_node_type_size(const dt_node_t *);
diff --git a/usr/src/lib/libdtrace/common/dt_print.c b/usr/src/lib/libdtrace/common/dt_print.c
index b71eddbf9d..4b4a23b199 100644
--- a/usr/src/lib/libdtrace/common/dt_print.c
+++ b/usr/src/lib/libdtrace/common/dt_print.c
@@ -27,6 +27,7 @@
*/
/*
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright 2022 Oxide Computer Company
*/
/*
@@ -41,13 +42,13 @@
*
* This implementation differs from MDB's in the following ways:
*
- * - We do not expose any options or flags. The behavior of print() is
+ * - We do not expose any options or flags. The behavior of print() is
* equivalent to "::print -tn".
*
- * - MDB will display "holes" in structures (unused padding between
+ * - MDB will display "holes" in structures (unused padding between
* members).
*
- * - When printing arrays of structures, MDB will leave a trailing ','
+ * - When printing arrays of structures, MDB will leave a trailing ','
* after the last element.
*
* - MDB will print time_t types as date and time.
@@ -149,7 +150,8 @@ dt_print_indent(dt_printarg_t *pap)
* Print a bitfield. It's worth noting that the D compiler support for
* bitfields is currently broken; printing "D`user_desc_t" (pulled in by the
* various D provider files) will produce incorrect results compared to
- * "genunix`user_desc_t".
+ * "genunix`user_desc_t". However, bitfields that are built via CTF will be
+ * fine. Note, this is derived from mdb's print_bifield in mdb_print.c.
*/
static void
print_bitfield(dt_printarg_t *pap, ulong_t off, ctf_encoding_t *ep)
@@ -158,11 +160,32 @@ print_bitfield(dt_printarg_t *pap, ulong_t off, ctf_encoding_t *ep)
caddr_t addr = pap->pa_addr + off / NBBY;
uint64_t mask = (1ULL << ep->cte_bits) - 1;
uint64_t value = 0;
- size_t size = (ep->cte_bits + (NBBY - 1)) / NBBY;
uint8_t *buf = (uint8_t *)&value;
uint8_t shift;
/*
+ * Our bitfield may straddle a byte boundary. We explicitly take the
+ * offset of the bitfield within its byte into account when determining
+ * the overall amount of data to copy and mask off from the underlying
+ * data.
+ */
+ uint_t nbits = ep->cte_bits + (off % NBBY);
+ size_t size = P2ROUNDUP(nbits, NBBY) / NBBY;
+
+ /*
+ * The resulting size must fit within the 64-bit value that we're using
+ * to store the value, otherwise the bcopy below could destroy our
+ * stack. This could be handled, but is not practically worth
+ * addressing. This choice apes mdb, so if you're considering fixing
+ * this, fix mdb as well.
+ */
+ if (size > sizeof (value)) {
+ (void) fprintf(fp, "??? (total bitfield too large after "
+ "alignment");
+ return;
+ }
+
+ /*
* On big-endian machines, we need to adjust the buf pointer to refer
* to the lowest 'size' bytes in 'value', and we need to shift based on
* the offset from the end of the data, not the offset of the start.
@@ -248,12 +271,8 @@ dt_print_int(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
return;
}
- /*
- * We print this as a bitfield if the bit encoding indicates it's not
- * an even power of two byte size, or is larger than 8 bytes.
- */
size = e.cte_bits / NBBY;
- if (size > 8 || (e.cte_bits % NBBY) != 0 || (size & (size - 1)) != 0) {
+ if (dt_is_bitfield(&e, off)) {
print_bitfield(pap, off, &e);
return;
}
@@ -341,7 +360,7 @@ dt_print_ptr(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
* each member, and recursively invoke ctf_type_visit() for each member. If
* the members are non-structs, then we print them out directly:
*
- * [ 0x14, 0x2e, 0 ]
+ * [ 0x14, 0x2e, 0 ]
*
* If they are structs, then we print out the necessary leading and trailing
* braces, to end up with:
@@ -408,7 +427,7 @@ dt_print_array(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
* don't bother printing out the brackets. This lets print("foo") look
* like:
*
- * string "foo"
+ * string "foo"
*
* As D will internally represent this as a char[256] array.
*/
diff --git a/usr/src/lib/libdtrace/common/dt_subr.c b/usr/src/lib/libdtrace/common/dt_subr.c
index e93617ef59..1958e62f82 100644
--- a/usr/src/lib/libdtrace/common/dt_subr.c
+++ b/usr/src/lib/libdtrace/common/dt_subr.c
@@ -22,6 +22,7 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright 2022 Oxide Computer Company
*/
#include <sys/sysmacros.h>
@@ -909,3 +910,25 @@ dtrace_uaddr2str(dtrace_hdl_t *dtp, pid_t pid,
return (dt_string2str(c, str, nbytes));
}
+
+/*
+ * This is a shared implementation to determine if we should treat a type as a
+ * bitfield. The parameters are the CTF encoding and the bit offset of the
+ * integer. This also exists in mdb_print.c. We consider something a bitfield
+ * if:
+ *
+ * o The type is more than 8 bytes. This is a bit of a historical choice from
+ * mdb and is a stranger one. The normal integer handling code generally
+ * doesn't handle integers more than 64-bits in size. Of course neither does
+ * the bitfield code...
+ * o The bit count is not a multiple of 8.
+ * o The size in bytes is not a power of 2.
+ * o The offset is not a multiple of 8.
+ */
+boolean_t
+dt_is_bitfield(const ctf_encoding_t *ep, ulong_t off)
+{
+ size_t bsize = ep->cte_bits / NBBY;
+ return (bsize > 8 || (ep->cte_bits % NBBY) != 0 ||
+ (bsize & (bsize - 1)) != 0 || (off % NBBY) != 0);
+}
diff --git a/usr/src/lib/libdtrace/common/ip.d.in b/usr/src/lib/libdtrace/common/ip.d.in
index f1e6332529..7dd4d2a314 100644
--- a/usr/src/lib/libdtrace/common/ip.d.in
+++ b/usr/src/lib/libdtrace/common/ip.d.in
@@ -311,9 +311,9 @@ translator ipv4info_t < ipha_t *I > {
ipv4_length = I != NULL ? ntohs(I->ipha_length) : 0;
ipv4_ident = I != NULL ? ntohs(I->ipha_ident) : 0;
ipv4_flags = I != NULL ? ntohs(I->ipha_fragment_offset_and_flags) >>
- 12 : 0;
+ 13 : 0;
ipv4_offset = I != NULL ? ntohs(I->ipha_fragment_offset_and_flags) &
- 0x0fff : 0;
+ 0x1fff : 0;
ipv4_ttl = I != NULL ? I->ipha_ttl : 0;
ipv4_protocol = I != NULL ? I->ipha_protocol : 0;
ipv4_protostr = I == NULL ? "<null>" :
diff --git a/usr/src/pkg/manifests/system-dtrace-tests.p5m b/usr/src/pkg/manifests/system-dtrace-tests.p5m
index 10e3ab672c..3edfb242dc 100644
--- a/usr/src/pkg/manifests/system-dtrace-tests.p5m
+++ b/usr/src/pkg/manifests/system-dtrace-tests.p5m
@@ -352,6 +352,9 @@ file \
mode=0444
file path=opt/SUNWdtrt/tst/common/bitfields/tst.BitFieldPromotion.d mode=0444
file path=opt/SUNWdtrt/tst/common/bitfields/tst.SizeofBitField.d mode=0444
+file path=opt/SUNWdtrt/tst/common/bitfields/tst.bitfields.exe mode=0555
+file path=opt/SUNWdtrt/tst/common/bitfields/tst.bitfields.ksh mode=0444
+file path=opt/SUNWdtrt/tst/common/bitfields/tst.bitfields.ksh.out mode=0444
dir path=opt/SUNWdtrt/tst/common/buffering
file path=opt/SUNWdtrt/tst/common/buffering/err.end.d mode=0444
file path=opt/SUNWdtrt/tst/common/buffering/err.resize1.d mode=0444
diff --git a/usr/src/test/util-tests/tests/mdb/numbers/tst.bitfields.ksh b/usr/src/test/util-tests/tests/mdb/numbers/tst.bitfields.ksh
index 3f39acae92..971c798053 100644
--- a/usr/src/test/util-tests/tests/mdb/numbers/tst.bitfields.ksh
+++ b/usr/src/test/util-tests/tests/mdb/numbers/tst.bitfields.ksh
@@ -12,7 +12,7 @@
#
#
-# Copyright 2021 Oxide Computer Company
+# Copyright 2022 Oxide Computer Company
#
#
@@ -26,5 +26,81 @@ tst_prog="$tst_root/progs/bitfields"
tst_outfile="/tmp/mdb.bitfield.out.$$"
tst_exp="$0.out"
+#
+# Top level ::print
+#
$MDB -e "first::print -t broken_t" $tst_prog > $ODIR/stdout
$MDB -e "second::print -t broken6491_t" $tst_prog >> $ODIR/stdout
+
+#
+# ::print of specific members
+#
+$MDB -e "first::print broken_t brk_a" $tst_prog >> $ODIR/stdout
+$MDB -e "first::print broken_t brk_b" $tst_prog >> $ODIR/stdout
+$MDB -e "first::print broken_t brk_c" $tst_prog >> $ODIR/stdout
+$MDB -e "first::print broken_t brk_d" $tst_prog >> $ODIR/stdout
+$MDB -e "first::print broken_t brk_e" $tst_prog >> $ODIR/stdout
+$MDB -e "first::print broken_t brk_f" $tst_prog >> $ODIR/stdout
+$MDB -e "first::print broken_t brk_g" $tst_prog >> $ODIR/stdout
+$MDB -e "first::print broken_t brk_h" $tst_prog >> $ODIR/stdout
+$MDB -e "first::print broken_t brk_i" $tst_prog >> $ODIR/stdout
+$MDB -e "first::print broken_t brk_j" $tst_prog >> $ODIR/stdout
+$MDB -e "first::print broken_t brk_k" $tst_prog >> $ODIR/stdout
+$MDB -e "first::print broken_t brk_l" $tst_prog >> $ODIR/stdout
+$MDB -e "first::print broken_t brk_m" $tst_prog >> $ODIR/stdout
+$MDB -e "second::print broken6491_t a" $tst_prog >> $ODIR/stdout
+$MDB -e "second::print broken6491_t b" $tst_prog >> $ODIR/stdout
+$MDB -e "second::print broken6491_t c" $tst_prog >> $ODIR/stdout
+$MDB -e "second::print broken6491_t d" $tst_prog >> $ODIR/stdout
+$MDB -e "second::print broken6491_t e" $tst_prog >> $ODIR/stdout
+$MDB -e "second::print broken6491_t f" $tst_prog >> $ODIR/stdout
+
+#
+# ::printf of members. Note, if ::printf said '%x\n' below then we would
+# include the string "\n" (not a newline) in the output. Instead we rely
+# upon the implicit newline from mdb -e.
+#
+$MDB -e "first::printf '%x' broken_t brk_a" $tst_prog >> $ODIR/stdout
+$MDB -e "first::printf '%x' broken_t brk_b" $tst_prog >> $ODIR/stdout
+$MDB -e "first::printf '%x' broken_t brk_c" $tst_prog >> $ODIR/stdout
+$MDB -e "first::printf '%x' broken_t brk_d" $tst_prog >> $ODIR/stdout
+$MDB -e "first::printf '%x' broken_t brk_e" $tst_prog >> $ODIR/stdout
+$MDB -e "first::printf '%x' broken_t brk_f" $tst_prog >> $ODIR/stdout
+$MDB -e "first::printf '%x' broken_t brk_g" $tst_prog >> $ODIR/stdout
+$MDB -e "first::printf '%x' broken_t brk_h" $tst_prog >> $ODIR/stdout
+$MDB -e "first::printf '%x' broken_t brk_i" $tst_prog >> $ODIR/stdout
+$MDB -e "first::printf '%x' broken_t brk_j" $tst_prog >> $ODIR/stdout
+$MDB -e "first::printf '%x' broken_t brk_k" $tst_prog >> $ODIR/stdout
+$MDB -e "first::printf '%x' broken_t brk_l" $tst_prog >> $ODIR/stdout
+$MDB -e "first::printf '%x' broken_t brk_m" $tst_prog >> $ODIR/stdout
+$MDB -e "second::printf '%x' broken6491_t a" $tst_prog >> $ODIR/stdout
+$MDB -e "second::printf '%x' broken6491_t b" $tst_prog >> $ODIR/stdout
+$MDB -e "second::printf '%x' broken6491_t c" $tst_prog >> $ODIR/stdout
+$MDB -e "second::printf '%x' broken6491_t d" $tst_prog >> $ODIR/stdout
+$MDB -e "second::printf '%x' broken6491_t e" $tst_prog >> $ODIR/stdout
+$MDB -e "second::printf '%x' broken6491_t f" $tst_prog >> $ODIR/stdout
+
+#
+# If we pipe the output of ::print that is a different bitfield logic
+# path. So we take that all to a `::eval '.=K'` as a basic way to get it
+# out.
+#
+$MDB -e "first::print broken_t brk_a | ::eval '.=K'" $tst_prog >> $ODIR/stdout
+$MDB -e "first::print broken_t brk_b | ::eval '.=K'" $tst_prog >> $ODIR/stdout
+$MDB -e "first::print broken_t brk_c | ::eval '.=K'" $tst_prog >> $ODIR/stdout
+$MDB -e "first::print broken_t brk_d | ::eval '.=K'" $tst_prog >> $ODIR/stdout
+$MDB -e "first::print broken_t brk_e | ::eval '.=K'" $tst_prog >> $ODIR/stdout
+$MDB -e "first::print broken_t brk_f | ::eval '.=K'" $tst_prog >> $ODIR/stdout
+$MDB -e "first::print broken_t brk_g | ::eval '.=K'" $tst_prog >> $ODIR/stdout
+$MDB -e "first::print broken_t brk_h | ::eval '.=K'" $tst_prog >> $ODIR/stdout
+$MDB -e "first::print broken_t brk_i | ::eval '.=K'" $tst_prog >> $ODIR/stdout
+$MDB -e "first::print broken_t brk_j | ::eval '.=K'" $tst_prog >> $ODIR/stdout
+$MDB -e "first::print broken_t brk_k | ::eval '.=K'" $tst_prog >> $ODIR/stdout
+$MDB -e "first::print broken_t brk_l | ::eval '.=K'" $tst_prog >> $ODIR/stdout
+$MDB -e "first::print broken_t brk_m | ::eval '.=K'" $tst_prog >> $ODIR/stdout
+$MDB -e "second::print broken6491_t a | ::eval '.=K'" $tst_prog >> $ODIR/stdout
+$MDB -e "second::print broken6491_t b | ::eval '.=K'" $tst_prog >> $ODIR/stdout
+$MDB -e "second::print broken6491_t c | ::eval '.=K'" $tst_prog >> $ODIR/stdout
+$MDB -e "second::print broken6491_t d | ::eval '.=K'" $tst_prog >> $ODIR/stdout
+$MDB -e "second::print broken6491_t e | ::eval '.=K'" $tst_prog >> $ODIR/stdout
+$MDB -e "second::print broken6491_t f | ::eval '.=K'" $tst_prog >> $ODIR/stdout
diff --git a/usr/src/test/util-tests/tests/mdb/numbers/tst.bitfields.ksh.out b/usr/src/test/util-tests/tests/mdb/numbers/tst.bitfields.ksh.out
index 347415a638..b71fd45c60 100644
--- a/usr/src/test/util-tests/tests/mdb/numbers/tst.bitfields.ksh.out
+++ b/usr/src/test/util-tests/tests/mdb/numbers/tst.bitfields.ksh.out
@@ -21,3 +21,60 @@ broken6491_t {
unsigned short:1 e :1 = 0x1
unsigned short:1 f :1 = 0
}
+brk_a = 0x3
+brk_b = 0x3
+brk_c = 0
+brk_d = 0x1
+brk_e = 0x1
+brk_f = 0x1
+brk_g = 0x3
+brk_h = 0x5
+brk_i = 0x3
+brk_j = 0x9
+brk_k = 0x13
+brk_l = 0
+brk_m = 0x1
+a = 0x1
+b = 0x2
+c = 0
+d = 0
+e = 0x1
+f = 0
+3
+3
+0
+1
+1
+1
+3
+5
+3
+9
+13
+0
+1
+1
+2
+0
+0
+1
+0
+ 3
+ 3
+ 0
+ 1
+ 1
+ 1
+ 3
+ 5
+ 3
+ 9
+ 13
+ 0
+ 1
+ 1
+ 2
+ 0
+ 0
+ 1
+ 0