[DTrace-devel] [PATCH] Add annotations for dctx->X and mst->X members

Kris Van Hees kris.van.hees at oracle.com
Wed Mar 30 17:11:59 UTC 2022


Let's hold off on this entire annotation thing for dctx and mst members for
now.  I agree we can do better in general with providing annotations and not
require strict instruction sequence matching.

Something to tackle in the near future hopefully.

On Tue, Mar 29, 2022 at 06:24:02PM -0400, eugene.loh--- via DTrace-devel wrote:
> From: Eugene Loh <eugene.loh at oracle.com>
> 
> WIP
> 
> This is a version of Kris's recent patch but it allows certain
> intervening instructions to appear in the expected instruction
> stream in order to capture the bulk of the mst->X cases we will
> see once the alloca() patch series has been applied.
> 
> I can clean this patch up if there is general buy-in to the idea.
> ---
>  libdtrace/dt_dis.c                       | 198 ++++++++++++++++++++++-
>  test/unittest/disasm/tst.ann-dctx-mst.r  |  11 ++
>  test/unittest/disasm/tst.ann-dctx-mst.sh |  33 ++++
>  3 files changed, 237 insertions(+), 5 deletions(-)
>  create mode 100644 test/unittest/disasm/tst.ann-dctx-mst.r
>  create mode 100755 test/unittest/disasm/tst.ann-dctx-mst.sh
> 
> diff --git a/libdtrace/dt_dis.c b/libdtrace/dt_dis.c
> index 792cc99e..1871d421 100644
> --- a/libdtrace/dt_dis.c
> +++ b/libdtrace/dt_dis.c
> @@ -82,7 +82,185 @@ dt_dis_varname_off(const dtrace_difo_t *dp, uint_t off, uint_t scope, uint_t add
>  }
>  
>  /*
> - * Check if we are loading from the gvar, lvar, or strtab BPF map.
> + * Check if we are accessing the DTrace context.
> + *
> + * The sequence of instructions we are looking for is:
> + *
> + *         insn   code  dst  src    offset        imm
> + *          -1:    ld   reg  %fp  DT_STK_DCTX  00000000
> + *           0:    ld   dst  reg  DCTX_*VARS   00000000
> + *
> + * where reg can be the same or different as dst.
> + */
> +static int
> +dt_dis_refname_dctx(const dtrace_difo_t *dp, const struct bpf_insn *in,
> +		    uint_t addr, int n, FILE *fp)
> +{
> +	static const char	*dctx_member[DCTX_SIZE] = {
> +		[0 ... DCTX_SIZE - 1] 	= NULL,
> +		[DCTX_CTX]		= "ctx",
> +		[DCTX_ACT]		= "act",
> +		[DCTX_MST]		= "mst",
> +		[DCTX_BUF]		= "buf",
> +		[DCTX_MEM]		= "mem",
> +		[DCTX_STRTAB]		= "strtab",
> +		[DCTX_AGG]		= "agg",
> +		[DCTX_GVARS]		= "gvars",
> +		[DCTX_LVARS]		= "lvars",
> +	};
> +	const char	*s = dctx_member[in->off];
> +
> +	if (in[0].code != (BPF_LDX | BPF_MEM | BPF_DW) ||
> +	    in[0].imm != 0 ||
> +	    addr < 1 ||
> +	    in[-1].code != (BPF_LDX | BPF_MEM | BPF_DW) ||
> +	    in[-1].src_reg != BPF_REG_FP ||
> +	    in[-1].dst_reg != in->src_reg ||
> +	    in[-1].off != DT_STK_DCTX ||
> +	    in[-1].imm != 0 ||
> +	    in[0].off < 0 || in[0].off >= DCTX_SIZE ||
> +	    s == NULL)
> +		return 0;
> +
> +	fprintf(fp, "%*s! dctx->%s\n", DT_DIS_PAD(n), "", s);
> +	return 1;
> +}
> +
> +/*
> + * Check if we are accessing the DTrace machine state.
> + *
> + * The sequence of instructions we are looking for is:
> + *        code  dst  src    offset        imm
> + *
> + *         ld   mst  %fp  DT_STK_DCTX  00000000
> + *
> + *         ld   mst  mst  DCTX_MST     00000000
> + *
> + *         ld   reg  mst  DMST_*       00000000  -or-
> + *         st   mst  reg  DMST_*       00000000  -or-
> + *         st   mst   0   DMST_*           imm
> + * where reg can be the same or different as mst.
> + *
> + * This sequence of instructions can be interrupted by
> + * any number of
> + *         ld   reg  xxx  xxxxxx       00000000
> + *         st   xxx  xxx  xxxxxx       xxxxxxxx
> + * so long as reg!=mst.
> + */
> +static int
> +dt_dis_refname_mst(const dtrace_difo_t *dp, const struct bpf_insn *in,
> +		   uint_t addr, int n, FILE *fp)
> +{
> +	static const char *mst_members[sizeof(dt_mstate_t)] =
> +	{
> +		[0 ... sizeof(dt_mstate_t) - 1]	= NULL,
> +		[DMST_EPID]			= "epid",
> +		[DMST_PRID]			= "prid",
> +		[DMST_CLID]			= "clid",
> +		[DMST_TAG]			= "tag",
> +		[DMST_ERRNO]			= "syscall_errno",
> +		[DMST_SCRATCH_TOP]		= "scratch_top",
> +		[DMST_SCRATCH_NEXT]		= "scratch_next",
> +		[DMST_ERRNO]			= "syscall_errno",
> +		[DMST_SCALARIZER]		= "scalarizer",
> +		[DMST_FAULT]			= "fault",
> +		[DMST_TSTAMP]			= "tstamp",
> +		[DMST_REGS]			= "regs",
> +		[DMST_ARG(0)]			= "arg0",
> +		[DMST_ARG(1)]			= "arg1",
> +		[DMST_ARG(2)]			= "arg2",
> +		[DMST_ARG(3)]			= "arg3",
> +		[DMST_ARG(4)]			= "arg4",
> +		[DMST_ARG(5)]			= "arg5",
> +		[DMST_ARG(6)]			= "arg6",
> +		[DMST_ARG(7)]			= "arg7",
> +		[DMST_ARG(8)]			= "arg8",
> +		[DMST_ARG(9)]			= "arg9",
> +	};
> +	int i, j, mst, off;
> +
> +	/* examine the current instruction and get mst and off */
> +	if (BPF_CLASS(in[0].code) == BPF_LDX &&
> +	    BPF_MODE(in[0].code) == BPF_MEM &&
> +	    in[0].imm == 0) {
> +		mst = in[0].src_reg;
> +		off = in[0].off;
> +	}
> +	else if (BPF_CLASS(in[0].code) == BPF_STX &&
> +	    BPF_MODE(in[0].code) == BPF_MEM &&
> +	    in[0].imm == 0) {
> +		mst = in[0].dst_reg;
> +		off = in[0].off;
> +	}
> +	else if (BPF_CLASS(in[0].code) == BPF_ST &&
> +	    BPF_MODE(in[0].code) == BPF_MEM &&
> +	    in[0].src_reg == 0) {
> +		mst = in[0].dst_reg;
> +		off = in[0].off;
> +	}
> +	else
> +		return 0;
> +
> +	/*
> +	 * Walk backwards through recent instructions.
> +	 * Naively, we are checking in[-1] and in[-2].  In practice,
> +	 * there may be some intervening instructions we can ignore.
> +	 * in[-i] is the actual instruction we are checking and in[-j]
> +	 * is the "ideal" index.
> +	 */
> +	j = 1;
> +	for (i = 1; i <= addr; i++) {
> +		const char *str;
> +
> +		/* skip any stores */
> +		if (BPF_CLASS(in[-i].code) == BPF_ST ||
> +		    BPF_CLASS(in[-i].code) == BPF_STX)
> +			continue;
> +
> +		/* skip any loads to regs other than mst */
> +		if (BPF_CLASS(in[-i].code) == BPF_LD ||
> +		    BPF_CLASS(in[-i].code) == BPF_LDX)
> +			if (in[-i].dst_reg != mst)
> +				continue;
> +
> +		/* look for the expected instruction */
> +		if (j == 1) {
> +			if (in[-i].code != (BPF_LDX | BPF_MEM | BPF_DW) ||
> +			    in[-i].dst_reg != mst ||
> +			    in[-i].src_reg != mst ||
> +			    in[-i].off != DCTX_MST ||
> +			    in[-i].imm != 0)
> +				return 0;
> +			/* advance to the next expected instruction */
> +			j = 2;
> +			continue;
> +		}
> +		if (j == 2) {
> +			if (in[-i].code != (BPF_LDX | BPF_MEM | BPF_DW) ||
> +			    in[-i].dst_reg != mst ||
> +			    in[-i].src_reg != BPF_REG_FP ||
> +			    in[-i].off != DT_STK_DCTX ||
> +			    in[-i].imm != 0)
> +				return 0;
> +
> +			if (off < 0 || off >= sizeof(dt_mstate_t))
> +				return 0;
> +
> +			str = mst_members[off];
> +			if (str != NULL)
> +				fprintf(fp, "%*s! mst->%s", DT_DIS_PAD(n), "", str);
> +
> +			return 1;
> +		}
> +
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * Check if we are accessing the gvars, lvars, or strtab BPF map, or the DTrace
> + * machine state.
>   *
>   * If we are loading a gvar or lvar, we want to report the variable name.
>   * If we are loading a string constant, we want to report its value.
> @@ -116,6 +294,10 @@ dt_dis_refname(const dtrace_difo_t *dp, const struct bpf_insn *in, uint_t addr,
>  	int		dst, scope = -1, var_offset = -1;
>  	const char	*str;
>  
> +	/* check if this is a machine state (mst) field */
> +	if (dt_dis_refname_mst(dp, in, addr, n, fp))
> +		goto out;
> +
>  	/* make sure in[-2] and in[-1] exist */
>  	if (addr < 2)
>  		goto out;
> @@ -259,9 +441,13 @@ dt_dis_load(const dtrace_difo_t *dp, const char *name, uint_t addr,
>  	    in->dst_reg == -(in->off - DT_STK_SPILL_BASE) / DT_STK_SLOT_SZ) {
>  		fprintf(fp, "%*s! restore %s\n", DT_DIS_PAD(n), "",
>  			reg(in->dst_reg));
> -	} else
> -		dt_dis_refname(dp, in, addr, n, fp);
> +		return 0;
> +	}
> +
> +	if (dt_dis_refname_dctx(dp, in, addr, n, fp))
> +		return 0;
>  
> +	dt_dis_refname(dp, in, addr, n, fp);
>  	return 0;
>  }
>  
> @@ -303,9 +489,10 @@ dt_dis_store(const dtrace_difo_t *dp, const char *name, uint_t addr,
>  	    in->src_reg == -(in->off - DT_STK_SPILL_BASE) / DT_STK_SLOT_SZ) {
>  		fprintf(fp, "%*s! spill %s\n", DT_DIS_PAD(n), "",
>  			reg(in->src_reg));
> -	} else
> -		dt_dis_refname(dp, in, addr, n, fp);
> +		return 0;
> +	}
>  
> +	dt_dis_refname(dp, in, addr, n, fp);
>  	return 0;
>  }
>  
> @@ -319,6 +506,7 @@ dt_dis_store_imm(const dtrace_difo_t *dp, const char *name, uint_t addr,
>  	n = fprintf(fp, "%-4s [%s%+d], %d", name, reg(in->dst_reg), in->off,
>  		    in->imm);
>  
> +	dt_dis_refname_mst(dp, in, addr, n, fp);
>  	if (rname)
>  		fprintf(fp, "%*s! = %s\n", DT_DIS_PAD(n), "", rname);
>  	else
> diff --git a/test/unittest/disasm/tst.ann-dctx-mst.r b/test/unittest/disasm/tst.ann-dctx-mst.r
> new file mode 100644
> index 00000000..da19f010
> --- /dev/null
> +++ b/test/unittest/disasm/tst.ann-dctx-mst.r
> @@ -0,0 +1,11 @@
> +79 X X 0018 00000000    lddw %rX, [%rX+24]            ! dctx->buf
> +79 X X 0000 00000000    lddw %rX, [%rX+0]             ! dctx->ctx
> +79 X X 0040 00000000    lddw %rX, [%rX+64]            ! dctx->gvars
> +79 X X 0048 00000000    lddw %rX, [%rX+72]            ! dctx->lvars
> +79 X X 0010 00000000    lddw %rX, [%rX+16]            ! dctx->mst
> +62 X X 0008 00000001    stw  [%rX+8], 1               ! mst->clid               ! = CLID
> +62 X X 0000 00000003    stw  [%rX+0], 3               ! mst->epid               ! = EPID
> +7a X X 0028 00000000    stdw [%rX+40], 0              ! mst->fault
> +7b X X 0020 00000000    stdw [%rX+32], %rX            ! mst->scalarizer
> +79 X X 0014 00000000    lddw %rX, [%rX+20]            ! mst->scratch_next
> +7a X X 0030 00000000    stdw [%rX+48], 0              ! mst->tstamp
> diff --git a/test/unittest/disasm/tst.ann-dctx-mst.sh b/test/unittest/disasm/tst.ann-dctx-mst.sh
> new file mode 100755
> index 00000000..e1c5214a
> --- /dev/null
> +++ b/test/unittest/disasm/tst.ann-dctx-mst.sh
> @@ -0,0 +1,33 @@
> +#!/bin/bash
> +#
> +# Oracle Linux DTrace.
> +# Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
> +# Licensed under the Universal Permissive License v 1.0 as shown at
> +# http://oss.oracle.com/licenses/upl.
> +#/
> +
> +dtrace=$1
> +
> +$dtrace $dt_flags -xdisasm=8 -qSn '
> +BEGIN
> +{
> +	gvar = arg0;
> +	self->tvar = 22;
> +	this->lvar = 333;
> +	x = alloca(8);
> +	exit(0);
> +}
> +
> +ERROR
> +{
> +	exit(1);
> +}' 2>&1 | awk '/^NAME/ {
> +		exit(0);
> +	       }
> +
> +	       /! (dctx|mst)->/ {
> +		sub(/^[^:]+: /, "");
> +                sub(/ [0-9a] [0-9a] /, " X X ");
> +                gsub(/%r[0-9]/, "%rX");
> +                print;
> +	       }' | sort -u -k10
> -- 
> 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