[DTrace-devel] [PATCH 09/12] Add support for the ustack() action

eugene.loh at oracle.com eugene.loh at oracle.com
Fri May 28 11:35:13 PDT 2021


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

Stack unwind is very difficult.  Therefore, adapt testing to the safest of
conditions:  probe firing in a stack that we compiled with no optimization,
-fno-omit-frame-pointer, no tail call optimizations, and no leaf function
optimizations.  Further, adapt the test to take better advantage of test
suite infrastructure for triggers and results checking.

The "strsize" argument has no effect.  Its value is silently ignored, and
strsize==0 is assumed.

When a pid entry probe fires, the stack frame is not yet set up.  Therefore,
the immediate caller will be missing from the call stack.

Signed-off-by: Eugene Loh <eugene.loh at oracle.com>
---
 libdtrace/dt_cg.c                             |  77 +++--
 libdtrace/dt_consume.c                        |  11 +-
 test/triggers/Build                           |   7 +-
 test/triggers/ustack-tst-basic.c              |  90 ++++++
 test/unittest/ustack/tst.frames.sh            | 271 ------------------
 test/unittest/ustack/tst.ustack25_pid.d       |  16 ++
 test/unittest/ustack/tst.ustack25_pid.r       |  27 ++
 test/unittest/ustack/tst.ustack25_profile.d   |  17 ++
 test/unittest/ustack/tst.ustack25_profile.r   |  27 ++
 test/unittest/ustack/tst.ustack95_profile.d   |  17 ++
 test/unittest/ustack/tst.ustack95_profile.r   |   1 +
 test/unittest/ustack/tst.ustack95_profile.r.p |   1 +
 test/unittest/ustack/tst.ustack_profile.d     |  17 ++
 test/unittest/ustack/tst.ustack_profile.r     |  65 +++++
 test/unittest/ustack/tst.ustack_profile.r.p   |  11 +
 15 files changed, 363 insertions(+), 292 deletions(-)
 create mode 100644 test/triggers/ustack-tst-basic.c
 delete mode 100755 test/unittest/ustack/tst.frames.sh
 create mode 100644 test/unittest/ustack/tst.ustack25_pid.d
 create mode 100644 test/unittest/ustack/tst.ustack25_pid.r
 create mode 100644 test/unittest/ustack/tst.ustack25_profile.d
 create mode 100644 test/unittest/ustack/tst.ustack25_profile.r
 create mode 100644 test/unittest/ustack/tst.ustack95_profile.d
 create mode 120000 test/unittest/ustack/tst.ustack95_profile.r
 create mode 120000 test/unittest/ustack/tst.ustack95_profile.r.p
 create mode 100644 test/unittest/ustack/tst.ustack_profile.d
 create mode 100644 test/unittest/ustack/tst.ustack_profile.r
 create mode 100755 test/unittest/ustack/tst.ustack_profile.r.p

diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
index c111e06a..1a88ef35 100644
--- a/libdtrace/dt_cg.c
+++ b/libdtrace/dt_cg.c
@@ -1503,37 +1503,82 @@ dt_cg_act_trunc(dt_pcb_t *pcb, dt_node_t *dnp, dtrace_actkind_t kind)
 static void
 dt_cg_act_ustack(dt_pcb_t *pcb, dt_node_t *dnp, dtrace_actkind_t kind)
 {
-	dt_node_t *arg0 = dnp->dn_args;
-	dt_node_t *arg1 = arg0 != NULL ? arg0->dn_list : NULL;
-#ifdef FIXME
-	uint32_t nframes = 0;
-	uint32_t strsize = 0;
-#endif
+	dt_irlist_t	*dlp = &pcb->pcb_ir;
+	dt_regset_t	*drp = pcb->pcb_regs;
+	dtrace_hdl_t	*dtp = pcb->pcb_hdl;
+	int		nframes = dtp->dt_options[DTRACEOPT_USTACKFRAMES];
+	int		strsize = 0;
+	dt_node_t	*arg0 = dnp->dn_args;
+	dt_node_t	*arg1 = arg0 != NULL ? arg0->dn_list : NULL;
+	int		skip = 0;
+	uint_t		off;
+	dt_ident_t	*idp;
+	uint_t		lbl_valid = dt_irlist_label(dlp);
+
+	/*
+	 * Legacy default was dtrace_ustackframes_default,
+	 * in kernel file dtrace/dtrace_state.c.
+	 */
+	if (nframes == DTRACEOPT_UNSET)
+		nframes = 100;
 
 	if (arg0 != NULL) {
-		if (!dt_node_is_posconst(arg0)) {
+		if (!dt_node_is_posconst(arg0))
 			dnerror(arg0, D_USTACK_FRAMES, "ustack( ) argument #1 "
 				"must be a non-zero positive integer "
 				"constant\n");
-		}
 
-#ifdef FIXME
-		nframes = (uint32_t)arg0->dn_value;
-#endif
+		nframes = arg0->dn_value;
 	}
 
+	/* FIXME: how shall we handle this?  See dt_cg_act_stack(). */
+	if (nframes > dtp->dt_maxframes)
+		nframes = dtp->dt_maxframes;
+
+	/* FIXME: for now, accept non-zero strsize, but it does nothing */
 	if (arg1 != NULL) {
 		if (arg1->dn_kind != DT_NODE_INT ||
 		    ((arg1->dn_flags & DT_NF_SIGNED) &&
-		    (int64_t)arg1->dn_value < 0)) {
+		    (int64_t)arg1->dn_value < 0))
 			dnerror(arg1, D_USTACK_STRSIZE, "ustack( ) argument #2 "
 				"must be a positive integer constant\n");
-		}
 
-#ifdef FIXME
-		strsize = (uint32_t)arg1->dn_value;
-#endif
+		strsize = arg1->dn_value;
 	}
+
+	/* Figure out where we want to be in the output buffer. */
+	off = dt_rec_add(pcb->pcb_hdl, dt_cg_fill_gap, DTRACEACT_USTACK,
+			 8 * nframes + 8, 8, NULL,
+			 DTRACE_USTACK_ARG(nframes, strsize));
+
+	if (dt_regset_xalloc_args(drp) == -1)
+		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
+	dt_regset_xalloc(drp, BPF_REG_0);
+
+	/* Write the tgid. */
+	emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_1, BPF_REG_FP, DT_STK_DCTX));
+	emit(dlp, BPF_MOV_IMM(BPF_REG_2, DIF_VAR_TID));
+	idp = dt_dlib_get_func(dtp, "dt_get_bvar");
+	assert(idp != NULL);
+	emite(dlp, BPF_CALL_FUNC(idp->di_id), idp);
+	dt_cg_check_fault(yypcb);
+	emit(dlp,  BPF_STORE(BPF_DW, BPF_REG_9, off, BPF_REG_0));
+
+	/* Now call bpf_get_stack(ctx, buf, size, flags). */
+	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, BPF_REG_9));
+	emit(dlp,  BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, off + 8));
+	emit(dlp,  BPF_MOV_IMM(BPF_REG_3, 8 * nframes));
+	emit(dlp,  BPF_MOV_IMM(BPF_REG_4, (skip & BPF_F_SKIP_FIELD_MASK) | BPF_F_USER_STACK));
+	emit(dlp,  BPF_CALL_HELPER(BPF_FUNC_get_stack));
+	dt_regset_free_args(drp);
+	emit(dlp,  BPF_BRANCH_IMM(BPF_JSGE, BPF_REG_0, 0, lbl_valid));
+	/* FIXME: what should the illval be? */
+	dt_cg_probe_error(pcb, -1, DTRACEFLT_BADSTACK, 0);
+	emitl(dlp, lbl_valid,
+		   BPF_NOP());
+	dt_regset_free(drp, BPF_REG_0);
 }
 
 typedef void dt_cg_action_f(dt_pcb_t *, dt_node_t *, dtrace_actkind_t);
diff --git a/libdtrace/dt_consume.c b/libdtrace/dt_consume.c
index c0b74ce2..860f83d8 100644
--- a/libdtrace/dt_consume.c
+++ b/libdtrace/dt_consume.c
@@ -1088,10 +1088,10 @@ dt_print_ustack(dtrace_hdl_t *dtp, FILE *fp, const char *format,
     caddr_t addr, uint64_t arg)
 {
 	/* LINTED - alignment */
-	uint64_t *pc = ((uint64_t *)addr) + 1;
+	uint64_t *pc = ((uint64_t *)addr);
 	uint32_t depth = DTRACE_USTACK_NFRAMES(arg);
 	uint32_t strsize = DTRACE_USTACK_STRSIZE(arg);
-	const char *strbase = addr + (depth + 2) * sizeof(uint64_t);
+	const char *strbase = addr + (depth + 1) * sizeof(uint64_t);
 	const char *str = strsize ? strbase : NULL;
 	int err = 0;
 
@@ -2081,6 +2081,13 @@ dt_consume_one(dtrace_hdl_t *dtp, FILE *fp, char *buf,
 				continue;
 			}
 
+			if (act == DTRACEACT_USTACK) {
+				if (dt_print_ustack(dtp, fp, NULL,
+				    addr, rec->dtrd_arg) < 0)
+					return -1;
+				continue;
+			}
+
 			switch (act) {
 			case DTRACEACT_PRINTF:
 				func = dtrace_fprintf;
diff --git a/test/triggers/Build b/test/triggers/Build
index ef2115bd..071cf619 100644
--- a/test/triggers/Build
+++ b/test/triggers/Build
@@ -3,7 +3,7 @@
 # Licensed under the Universal Permissive License v 1.0 as shown at
 # http://oss.oracle.com/licenses/upl.
 
-EXTERNAL_64BIT_TRIGGERS = testprobe readwholedir mmap bogus-ioctl open delaydie pid-tst-args1 pid-tst-float pid-tst-fork pid-tst-gcc pid-tst-ret1 pid-tst-ret2 pid-tst-vfork pid-tst-weak1 pid-tst-weak2 proc-tst-sigwait proc-tst-omp proc-tst-pthread-exec profile-tst-ufuncsort raise-tst-raise1 raise-tst-raise2 raise-tst-raise3 syscall-tst-args ustack-tst-bigstack ustack-tst-spin ustack-tst-mtspin visible-constructor visible-constructor-static visible-constructor-static-unstripped
+EXTERNAL_64BIT_TRIGGERS = testprobe readwholedir mmap bogus-ioctl open delaydie pid-tst-args1 pid-tst-float pid-tst-fork pid-tst-gcc pid-tst-ret1 pid-tst-ret2 pid-tst-vfork pid-tst-weak1 pid-tst-weak2 proc-tst-sigwait proc-tst-omp proc-tst-pthread-exec profile-tst-ufuncsort raise-tst-raise1 raise-tst-raise2 raise-tst-raise3 syscall-tst-args ustack-tst-basic ustack-tst-bigstack ustack-tst-spin ustack-tst-mtspin visible-constructor visible-constructor-static visible-constructor-static-unstripped
 
 EXTERNAL_64BIT_SDT_TRIGGERS = usdt-tst-argmap usdt-tst-args usdt-tst-forker usdt-tst-special
 EXTERNAL_64BIT_TRIGGERS += $(EXTERNAL_64BIT_SDT_TRIGGERS)
@@ -196,9 +196,10 @@ usdt-tst-forker_PROV := usdt-tst-forker-prov.d
 usdt-tst-special_CFLAGS := -fno-inline -O2
 usdt-tst-special_PROV := usdt-tst-special-prov.d
 
-# ustack-tst-mtspin uses threads, and neither ustack-tst-spin nor
-# ustack-tst-mtspin want optimization.
+# ustack-tst-mtspin uses threads
+# ustack wants no optimization
 
+ustack-tst-basic_CFLAGS := -O0 -fno-inline -fno-omit-frame-pointer
 ustack-tst-spin_CFLAGS := -O0
 ustack-tst-mtspin_CFLAGS := -O0
 ustack-tst-mtspin_LIBS := -lpthread
diff --git a/test/triggers/ustack-tst-basic.c b/test/triggers/ustack-tst-basic.c
new file mode 100644
index 00000000..a7da618d
--- /dev/null
+++ b/test/triggers/ustack-tst-basic.c
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+
+int mycallee(int i) {
+	return i ^ 1;
+}
+
+int myfunc_z() {
+	int i = 1;
+
+	/* call another function to prevent leaf call optimizations */
+	i = mycallee(i);
+
+	/* endless loop, profile-n probe will fire here */
+	while (i < 3)
+		i = 2 * i - 1;
+
+	return i;
+}
+
+/* have a relatively deep stack; ^1 prevents tail calls */
+int myfunc_y() { return myfunc_z() ^ 1; }
+int myfunc_x() { return myfunc_y() ^ 1; }
+int myfunc_w() { return myfunc_x() ^ 1; }
+int myfunc_v() { return myfunc_w() ^ 1; }
+int myfunc_u() { return myfunc_v() ^ 1; }
+int myfunc_t() { return myfunc_u() ^ 1; }
+int myfunc_s() { return myfunc_t() ^ 1; }
+int myfunc_r() { return myfunc_s() ^ 1; }
+int myfunc_q() { return myfunc_r() ^ 1; }
+int myfunc_p() { return myfunc_q() ^ 1; }
+int myfunc_o() { return myfunc_p() ^ 1; }
+int myfunc_n() { return myfunc_o() ^ 1; }
+int myfunc_m() { return myfunc_n() ^ 1; }
+int myfunc_l() { return myfunc_m() ^ 1; }
+int myfunc_k() { return myfunc_l() ^ 1; }
+int myfunc_j() { return myfunc_k() ^ 1; }
+int myfunc_i() { return myfunc_j() ^ 1; }
+int myfunc_h() { return myfunc_i() ^ 1; }
+int myfunc_g() { return myfunc_h() ^ 1; }
+int myfunc_f() { return myfunc_g() ^ 1; }
+int myfunc_e() { return myfunc_f() ^ 1; }
+int myfunc_d() { return myfunc_e() ^ 1; }
+int myfunc_c() { return myfunc_d() ^ 1; }
+int myfunc_b() { return myfunc_c() ^ 1; }
+int myfunc_a() { return myfunc_b() ^ 1; }
+int myfunc_Z() { return myfunc_a() ^ 1; }
+int myfunc_Y() { return myfunc_Z() ^ 1; }
+int myfunc_X() { return myfunc_Y() ^ 1; }
+int myfunc_W() { return myfunc_X() ^ 1; }
+int myfunc_V() { return myfunc_W() ^ 1; }
+int myfunc_U() { return myfunc_V() ^ 1; }
+int myfunc_T() { return myfunc_U() ^ 1; }
+int myfunc_S() { return myfunc_T() ^ 1; }
+int myfunc_R() { return myfunc_S() ^ 1; }
+int myfunc_Q() { return myfunc_R() ^ 1; }
+int myfunc_P() { return myfunc_Q() ^ 1; }
+int myfunc_O() { return myfunc_P() ^ 1; }
+int myfunc_N() { return myfunc_O() ^ 1; }
+int myfunc_M() { return myfunc_N() ^ 1; }
+int myfunc_L() { return myfunc_M() ^ 1; }
+int myfunc_K() { return myfunc_L() ^ 1; }
+int myfunc_J() { return myfunc_K() ^ 1; }
+int myfunc_I() { return myfunc_J() ^ 1; }
+int myfunc_H() { return myfunc_I() ^ 1; }
+int myfunc_G() { return myfunc_H() ^ 1; }
+int myfunc_F() { return myfunc_G() ^ 1; }
+int myfunc_E() { return myfunc_F() ^ 1; }
+int myfunc_D() { return myfunc_E() ^ 1; }
+int myfunc_C() { return myfunc_D() ^ 1; }
+int myfunc_B() { return myfunc_C() ^ 1; }
+int myfunc_A() { return myfunc_B() ^ 1; }
+int myfunc_9() { return myfunc_A() ^ 1; }
+int myfunc_8() { return myfunc_9() ^ 1; }
+int myfunc_7() { return myfunc_8() ^ 1; }
+int myfunc_6() { return myfunc_7() ^ 1; }
+int myfunc_5() { return myfunc_6() ^ 1; }
+int myfunc_4() { return myfunc_5() ^ 1; }
+int myfunc_3() { return myfunc_4() ^ 1; }
+int myfunc_2() { return myfunc_3() ^ 1; }
+int myfunc_1() { return myfunc_2() ^ 1; }
+int myfunc_0() { return myfunc_1() ^ 1; }
+
+int main(int c, char **v) {
+	return myfunc_0() ^ 1;
+}
diff --git a/test/unittest/ustack/tst.frames.sh b/test/unittest/ustack/tst.frames.sh
deleted file mode 100755
index 968ab57d..00000000
--- a/test/unittest/ustack/tst.frames.sh
+++ /dev/null
@@ -1,271 +0,0 @@
-#!/bin/bash
-#
-# Oracle Linux DTrace.
-# Copyright (c) 2019, 2020, 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
-
-dtrace=$1
-CC=/usr/bin/gcc
-
-DIRNAME="$tmpdir/ustack-frames.$$.$RANDOM"
-mkdir -p $DIRNAME
-cd $DIRNAME
-
-###########
-# make test code
-###########
-
-cat > test.c <<EOF
-#include <stdio.h>
-#include <unistd.h>
-
-/* trigger a syscall in the leaf function */
-int fooz() {
-	printf("hello world\n");
-	fflush(stdout);
-	return 1;
-}
-
-/* have a relatively deep stack; prevent tail calls */
-int fooy() { return fooz() ^ 1; }
-int foox() { return fooy() ^ 1; }
-int foow() { return foox() ^ 1; }
-int foov() { return foow() ^ 1; }
-int foou() { return foov() ^ 1; }
-int foot() { return foou() ^ 1; }
-int foos() { return foot() ^ 1; }
-int foor() { return foos() ^ 1; }
-int fooq() { return foor() ^ 1; }
-int foop() { return fooq() ^ 1; }
-int fooo() { return foop() ^ 1; }
-int foon() { return fooo() ^ 1; }
-int foom() { return foon() ^ 1; }
-int fool() { return foom() ^ 1; }
-int fook() { return fool() ^ 1; }
-int fooj() { return fook() ^ 1; }
-int fooi() { return fooj() ^ 1; }
-int fooh() { return fooi() ^ 1; }
-int foog() { return fooh() ^ 1; }
-int foof() { return foog() ^ 1; }
-int fooe() { return foof() ^ 1; }
-int food() { return fooe() ^ 1; }
-int fooc() { return food() ^ 1; }
-int foob() { return fooc() ^ 1; }
-int fooa() { return foob() ^ 1; }
-int fooZ() { return fooa() ^ 1; }
-int fooY() { return fooZ() ^ 1; }
-int fooX() { return fooY() ^ 1; }
-int fooW() { return fooX() ^ 1; }
-int fooV() { return fooW() ^ 1; }
-int fooU() { return fooV() ^ 1; }
-int fooT() { return fooU() ^ 1; }
-int fooS() { return fooT() ^ 1; }
-int fooR() { return fooS() ^ 1; }
-int fooQ() { return fooR() ^ 1; }
-int fooP() { return fooQ() ^ 1; }
-int fooO() { return fooP() ^ 1; }
-int fooN() { return fooO() ^ 1; }
-int fooM() { return fooN() ^ 1; }
-int fooL() { return fooM() ^ 1; }
-int fooK() { return fooL() ^ 1; }
-int fooJ() { return fooK() ^ 1; }
-int fooI() { return fooJ() ^ 1; }
-int fooH() { return fooI() ^ 1; }
-int fooG() { return fooH() ^ 1; }
-int fooF() { return fooG() ^ 1; }
-int fooE() { return fooF() ^ 1; }
-int fooD() { return fooE() ^ 1; }
-int fooC() { return fooD() ^ 1; }
-int fooB() { return fooC() ^ 1; }
-int fooA() { return fooB() ^ 1; }
-int foo9() { return fooA() ^ 1; }
-int foo8() { return foo9() ^ 1; }
-int foo7() { return foo8() ^ 1; }
-int foo6() { return foo7() ^ 1; }
-int foo5() { return foo6() ^ 1; }
-int foo4() { return foo5() ^ 1; }
-int foo3() { return foo4() ^ 1; }
-int foo2() { return foo3() ^ 1; }
-int foo1() { return foo2() ^ 1; }
-int foo0() { return foo1() ^ 1; }
-
-/* sleep so frames can be resolved before process exits */
-int main(int c, char **v) {
-	int rc = foo0() ^ 1;
-	sleep(5);
-	return rc;
-}
-EOF
-
-###########
-# list expected stack
-###########
-
-cat > filtered-stack-expect.txt <<EOF
-              libc.so.6\`fflush
-              a.out\`fooz
-              a.out\`fooy
-              a.out\`foox
-              a.out\`foow
-              a.out\`foov
-              a.out\`foou
-              a.out\`foot
-              a.out\`foos
-              a.out\`foor
-              a.out\`fooq
-              a.out\`foop
-              a.out\`fooo
-              a.out\`foon
-              a.out\`foom
-              a.out\`fool
-              a.out\`fook
-              a.out\`fooj
-              a.out\`fooi
-              a.out\`fooh
-              a.out\`foog
-              a.out\`foof
-              a.out\`fooe
-              a.out\`food
-              a.out\`fooc
-              a.out\`foob
-              a.out\`fooa
-              a.out\`fooZ
-              a.out\`fooY
-              a.out\`fooX
-              a.out\`fooW
-              a.out\`fooV
-              a.out\`fooU
-              a.out\`fooT
-              a.out\`fooS
-              a.out\`fooR
-              a.out\`fooQ
-              a.out\`fooP
-              a.out\`fooO
-              a.out\`fooN
-              a.out\`fooM
-              a.out\`fooL
-              a.out\`fooK
-              a.out\`fooJ
-              a.out\`fooI
-              a.out\`fooH
-              a.out\`fooG
-              a.out\`fooF
-              a.out\`fooE
-              a.out\`fooD
-              a.out\`fooC
-              a.out\`fooB
-              a.out\`fooA
-              a.out\`foo9
-              a.out\`foo8
-              a.out\`foo7
-              a.out\`foo6
-              a.out\`foo5
-              a.out\`foo4
-              a.out\`foo3
-              a.out\`foo2
-              a.out\`foo1
-              a.out\`foo0
-              a.out\`main
-              libc.so.6\`__libc_start_main
-EOF
-
-###########
-# compile
-###########
-
-${CC} -O2 -fno-inline test.c
-if [ $? -ne 0 ]; then
-        echo "failed to compile test.c" >& 2
-        exit 1
-fi
-
-###########
-# run
-###########
-
-$dtrace $dt_flags -c ./a.out -qwn '
-    syscall::write:entry
-    /pid == $target/
-    {
-        freopen("ustack.txt");
-        ustack();
-        freopen("ustack95.txt");
-        ustack(95);
-        freopen("ustack25.txt");
-        ustack(25);
-        freopen("");
-    }'
-
-status=$?
-if [ "$status" -ne 0 ]; then
-	echo $tst: dtrace failed
-	rm -f $file
-	exit $status
-fi
-
-###########
-# check
-###########
-
-if [ ! -f ustack25.txt ]; then
-	echo "missing file ustack25.txt"
-	exit 1
-fi
-if [ ! -f ustack95.txt ]; then
-	echo "missing file ustack95.txt"
-	exit 1
-fi
-if [ ! -f ustack.txt ]; then
-	echo "missing file ustack.txt"
-	exit 1
-fi
-if ! diff ustack95.txt ustack.txt > /dev/null; then
-	echo "ustack(95) differs from ustack()"
-	echo "    ustack(95)"
-	cat ustack95.txt
-	echo "    ustack()"
-	cat ustack.txt
-	echo "    diff"
-	diff -u ustack95.txt ustack.txt
-	exit 1
-fi
-if ! head -26 ustack.txt | diff - ustack25.txt > /dev/null; then
-	echo "ustack(25) differs from head of ustack()"
-	echo "    ustack(25)"
-	cat ustack25.txt
-	echo "    ustack() (head)"
-	head -26 ustack.txt
-	echo "    diff"
-	head -26 ustack.txt | diff -u - ustack25.txt
-	exit 1
-fi
-
-# filter the stack (remove offsets and a few frames) and check
-
-awk '
-    /libc\.so\.6`fflush\+0x/ ||
-    /a\.out`foo[0-9a-zA-Z]\+0x/ ||
-    /a\.out`main\+0x/ ||
-    /libc\.so\.6`__libc_start_main\+0x/ {
-        sub("+0x.*$", "");
-        print;
-    }
-' ustack.txt > filtered-stack-actual.txt
-
-if ! diff filtered-stack-expect.txt filtered-stack-actual.txt > /dev/null; then
-	echo "filtered ustack() differs from expected"
-	echo "    ustack()"
-	cat ustack.txt
-	echo "    ustack() (filtered)"
-	cat filtered-stack-actual.txt
-	echo "    expected"
-	cat filtered-stack-expect.txt
-	echo "    diff"
-	diff -u filtered-stack-expect.txt filtered-stack-actual.txt
-	exit 1
-fi
-
-exit 0
-
diff --git a/test/unittest/ustack/tst.ustack25_pid.d b/test/unittest/ustack/tst.ustack25_pid.d
new file mode 100644
index 00000000..aa16940a
--- /dev/null
+++ b/test/unittest/ustack/tst.ustack25_pid.d
@@ -0,0 +1,16 @@
+/*
+ * 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.
+ */
+
+/* @@trigger: ustack-tst-basic */
+
+#pragma D option quiet
+
+pid$target:a.out:myfunc_z:entry
+{
+    ustack(25);
+    exit(0);
+}
diff --git a/test/unittest/ustack/tst.ustack25_pid.r b/test/unittest/ustack/tst.ustack25_pid.r
new file mode 100644
index 00000000..89b35c02
--- /dev/null
+++ b/test/unittest/ustack/tst.ustack25_pid.r
@@ -0,0 +1,27 @@
+
+              ustack-tst-basic`myfunc_z
+              ustack-tst-basic`myfunc_x+{ptr}
+              ustack-tst-basic`myfunc_w+{ptr}
+              ustack-tst-basic`myfunc_v+{ptr}
+              ustack-tst-basic`myfunc_u+{ptr}
+              ustack-tst-basic`myfunc_t+{ptr}
+              ustack-tst-basic`myfunc_s+{ptr}
+              ustack-tst-basic`myfunc_r+{ptr}
+              ustack-tst-basic`myfunc_q+{ptr}
+              ustack-tst-basic`myfunc_p+{ptr}
+              ustack-tst-basic`myfunc_o+{ptr}
+              ustack-tst-basic`myfunc_n+{ptr}
+              ustack-tst-basic`myfunc_m+{ptr}
+              ustack-tst-basic`myfunc_l+{ptr}
+              ustack-tst-basic`myfunc_k+{ptr}
+              ustack-tst-basic`myfunc_j+{ptr}
+              ustack-tst-basic`myfunc_i+{ptr}
+              ustack-tst-basic`myfunc_h+{ptr}
+              ustack-tst-basic`myfunc_g+{ptr}
+              ustack-tst-basic`myfunc_f+{ptr}
+              ustack-tst-basic`myfunc_e+{ptr}
+              ustack-tst-basic`myfunc_d+{ptr}
+              ustack-tst-basic`myfunc_c+{ptr}
+              ustack-tst-basic`myfunc_b+{ptr}
+              ustack-tst-basic`myfunc_a+{ptr}
+
diff --git a/test/unittest/ustack/tst.ustack25_profile.d b/test/unittest/ustack/tst.ustack25_profile.d
new file mode 100644
index 00000000..9b0ba9af
--- /dev/null
+++ b/test/unittest/ustack/tst.ustack25_profile.d
@@ -0,0 +1,17 @@
+/*
+ * 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.
+ */
+
+/* @@trigger: ustack-tst-basic */
+
+#pragma D option quiet
+
+profile-1
+/pid == $target/
+{
+    ustack(25);
+    exit(0);
+}
diff --git a/test/unittest/ustack/tst.ustack25_profile.r b/test/unittest/ustack/tst.ustack25_profile.r
new file mode 100644
index 00000000..6445fda8
--- /dev/null
+++ b/test/unittest/ustack/tst.ustack25_profile.r
@@ -0,0 +1,27 @@
+
+              ustack-tst-basic`myfunc_z+{ptr}
+              ustack-tst-basic`myfunc_y+{ptr}
+              ustack-tst-basic`myfunc_x+{ptr}
+              ustack-tst-basic`myfunc_w+{ptr}
+              ustack-tst-basic`myfunc_v+{ptr}
+              ustack-tst-basic`myfunc_u+{ptr}
+              ustack-tst-basic`myfunc_t+{ptr}
+              ustack-tst-basic`myfunc_s+{ptr}
+              ustack-tst-basic`myfunc_r+{ptr}
+              ustack-tst-basic`myfunc_q+{ptr}
+              ustack-tst-basic`myfunc_p+{ptr}
+              ustack-tst-basic`myfunc_o+{ptr}
+              ustack-tst-basic`myfunc_n+{ptr}
+              ustack-tst-basic`myfunc_m+{ptr}
+              ustack-tst-basic`myfunc_l+{ptr}
+              ustack-tst-basic`myfunc_k+{ptr}
+              ustack-tst-basic`myfunc_j+{ptr}
+              ustack-tst-basic`myfunc_i+{ptr}
+              ustack-tst-basic`myfunc_h+{ptr}
+              ustack-tst-basic`myfunc_g+{ptr}
+              ustack-tst-basic`myfunc_f+{ptr}
+              ustack-tst-basic`myfunc_e+{ptr}
+              ustack-tst-basic`myfunc_d+{ptr}
+              ustack-tst-basic`myfunc_c+{ptr}
+              ustack-tst-basic`myfunc_b+{ptr}
+
diff --git a/test/unittest/ustack/tst.ustack95_profile.d b/test/unittest/ustack/tst.ustack95_profile.d
new file mode 100644
index 00000000..e0c89443
--- /dev/null
+++ b/test/unittest/ustack/tst.ustack95_profile.d
@@ -0,0 +1,17 @@
+/*
+ * 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.
+ */
+
+/* @@trigger: ustack-tst-basic */
+
+#pragma D option quiet
+
+profile-1
+/pid == $target/
+{
+    ustack(95);
+    exit(0);
+}
diff --git a/test/unittest/ustack/tst.ustack95_profile.r b/test/unittest/ustack/tst.ustack95_profile.r
new file mode 120000
index 00000000..9b6b9cd7
--- /dev/null
+++ b/test/unittest/ustack/tst.ustack95_profile.r
@@ -0,0 +1 @@
+tst.ustack_profile.r
\ No newline at end of file
diff --git a/test/unittest/ustack/tst.ustack95_profile.r.p b/test/unittest/ustack/tst.ustack95_profile.r.p
new file mode 120000
index 00000000..4d31ad85
--- /dev/null
+++ b/test/unittest/ustack/tst.ustack95_profile.r.p
@@ -0,0 +1 @@
+tst.ustack_profile.r.p
\ No newline at end of file
diff --git a/test/unittest/ustack/tst.ustack_profile.d b/test/unittest/ustack/tst.ustack_profile.d
new file mode 100644
index 00000000..1589acc8
--- /dev/null
+++ b/test/unittest/ustack/tst.ustack_profile.d
@@ -0,0 +1,17 @@
+/*
+ * 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.
+ */
+
+/* @@trigger: ustack-tst-basic */
+
+#pragma D option quiet
+
+profile-1
+/pid == $target/
+{
+    ustack();
+    exit(0);
+}
diff --git a/test/unittest/ustack/tst.ustack_profile.r b/test/unittest/ustack/tst.ustack_profile.r
new file mode 100644
index 00000000..79b1cfbb
--- /dev/null
+++ b/test/unittest/ustack/tst.ustack_profile.r
@@ -0,0 +1,65 @@
+
+              ustack-tst-basic`myfunc_z+{ptr}
+              ustack-tst-basic`myfunc_y+{ptr}
+              ustack-tst-basic`myfunc_x+{ptr}
+              ustack-tst-basic`myfunc_w+{ptr}
+              ustack-tst-basic`myfunc_v+{ptr}
+              ustack-tst-basic`myfunc_u+{ptr}
+              ustack-tst-basic`myfunc_t+{ptr}
+              ustack-tst-basic`myfunc_s+{ptr}
+              ustack-tst-basic`myfunc_r+{ptr}
+              ustack-tst-basic`myfunc_q+{ptr}
+              ustack-tst-basic`myfunc_p+{ptr}
+              ustack-tst-basic`myfunc_o+{ptr}
+              ustack-tst-basic`myfunc_n+{ptr}
+              ustack-tst-basic`myfunc_m+{ptr}
+              ustack-tst-basic`myfunc_l+{ptr}
+              ustack-tst-basic`myfunc_k+{ptr}
+              ustack-tst-basic`myfunc_j+{ptr}
+              ustack-tst-basic`myfunc_i+{ptr}
+              ustack-tst-basic`myfunc_h+{ptr}
+              ustack-tst-basic`myfunc_g+{ptr}
+              ustack-tst-basic`myfunc_f+{ptr}
+              ustack-tst-basic`myfunc_e+{ptr}
+              ustack-tst-basic`myfunc_d+{ptr}
+              ustack-tst-basic`myfunc_c+{ptr}
+              ustack-tst-basic`myfunc_b+{ptr}
+              ustack-tst-basic`myfunc_a+{ptr}
+              ustack-tst-basic`myfunc_Z+{ptr}
+              ustack-tst-basic`myfunc_Y+{ptr}
+              ustack-tst-basic`myfunc_X+{ptr}
+              ustack-tst-basic`myfunc_W+{ptr}
+              ustack-tst-basic`myfunc_V+{ptr}
+              ustack-tst-basic`myfunc_U+{ptr}
+              ustack-tst-basic`myfunc_T+{ptr}
+              ustack-tst-basic`myfunc_S+{ptr}
+              ustack-tst-basic`myfunc_R+{ptr}
+              ustack-tst-basic`myfunc_Q+{ptr}
+              ustack-tst-basic`myfunc_P+{ptr}
+              ustack-tst-basic`myfunc_O+{ptr}
+              ustack-tst-basic`myfunc_N+{ptr}
+              ustack-tst-basic`myfunc_M+{ptr}
+              ustack-tst-basic`myfunc_L+{ptr}
+              ustack-tst-basic`myfunc_K+{ptr}
+              ustack-tst-basic`myfunc_J+{ptr}
+              ustack-tst-basic`myfunc_I+{ptr}
+              ustack-tst-basic`myfunc_H+{ptr}
+              ustack-tst-basic`myfunc_G+{ptr}
+              ustack-tst-basic`myfunc_F+{ptr}
+              ustack-tst-basic`myfunc_E+{ptr}
+              ustack-tst-basic`myfunc_D+{ptr}
+              ustack-tst-basic`myfunc_C+{ptr}
+              ustack-tst-basic`myfunc_B+{ptr}
+              ustack-tst-basic`myfunc_A+{ptr}
+              ustack-tst-basic`myfunc_9+{ptr}
+              ustack-tst-basic`myfunc_8+{ptr}
+              ustack-tst-basic`myfunc_7+{ptr}
+              ustack-tst-basic`myfunc_6+{ptr}
+              ustack-tst-basic`myfunc_5+{ptr}
+              ustack-tst-basic`myfunc_4+{ptr}
+              ustack-tst-basic`myfunc_3+{ptr}
+              ustack-tst-basic`myfunc_2+{ptr}
+              ustack-tst-basic`myfunc_1+{ptr}
+              ustack-tst-basic`myfunc_0+{ptr}
+              ustack-tst-basic`main+{ptr}
+              libc.so.6`__libc_start_main+{ptr}
diff --git a/test/unittest/ustack/tst.ustack_profile.r.p b/test/unittest/ustack/tst.ustack_profile.r.p
new file mode 100755
index 00000000..9c6a0dfb
--- /dev/null
+++ b/test/unittest/ustack/tst.ustack_profile.r.p
@@ -0,0 +1,11 @@
+#!/usr/bin/gawk -f
+# 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.
+
+# if we get to a frame we do not recognize, but we saw "main", exit
+BEGIN { saw_main = 0 }
+!/myfunc_/ && !/main/ && saw_main { exit(0) }
+{ print }
+/main/ { saw_main = 1 }
-- 
2.18.4




More information about the DTrace-devel mailing list