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

Kris Van Hees kris.van.hees at oracle.com
Wed Jun 9 14:50:59 PDT 2021


On Fri, May 28, 2021 at 02:35:13PM -0400, eugene.loh at oracle.com wrote:
> 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;

See comment on stack() with a similar use of a constant.

>  	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;

No need for the FIXME.  As expressed in the case for stack(), the option you
took here is the correct one in my opinion.
> +
> +	/* 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,

8 + nframes * sizeof(uint64_t), since it makes sense to express the sizes in
the order that they will be used (tgid first, then the stack trace).

You might as well declare a variable stacksize and assign
nframes * sizeof(uint64_t to it, so you can use it here and also in setting up
the arguments to the bpf_get_stack() helper.

> +			 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));

No need to make a call to get_bvar() for this.  Just retrieve the value from
the BPF helper just like the get_bvar() function does.  Going thrugh get_bvar()
is overkill.

Also, the tgid is a 32-bit value, so the store should be for size BPF_W
instead of BPF_DW.

> +
> +	/* 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? */

I believe illval is undefined in the case of a BADSTACK fault, so I would go
with 0 indeed.

> +	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
> 
> 
> _______________________________________________
> DTrace-devel mailing list
> DTrace-devel at oss.oracle.com
> https://oss.oracle.com/mailman/listinfo/dtrace-devel



More information about the DTrace-devel mailing list