[DTrace-devel] [PATCH] Add a disassembly listing mode 0 (-xdisasm=1) for code generation

Kris Van Hees kris.van.hees at oracle.com
Mon Jun 14 06:59:33 PDT 2021


I don't think we should add this to the overall code base because it is a
truly development-time only feature.  While it can be useful during dev work
for some, it can easily be done on a case-by-case basis or as a patch in a
development branch.  But it also invites adding debugging statements that are
under this mode 0 control that are really only of use to the developer who
added them, which is again not soemthing that belongs in the public tree.

I'd be open to a much more minimal patch that adds a dt_dis_insn() function
that is not used in the public tree, but that can easily be used in personal
dev branches.  That would make doing so a lot less invasive, and I do think
there is value in offering that.  Having to carry this more complex patch as
a personal one is more tricky, so if we can make that easier with low impact
changes in the public tree, I supprot that.

On Wed, Apr 14, 2021 at 12:50:20PM -0400, eugene.loh at oracle.com wrote:
> From: Eugene Loh <eugene.loh at oracle.com>
> 
> For debugging BPF instructions emitted during code generation, it
> is useful to print debugging messages that are interwoven with
> disassembled instructions.  Therefore, add disassembly support,
> including a listing mode 0:
> 
> x)  Move BPF ops out of dt_dis_difo(), so that they can
>     be used for other functions as well.
> 
> x)  Add a dt_dis_insn() to disassemble a single instruction.
> 
> x)  Add listing mode numbers to disassembly headers.  These
>     simple numbers help remind readers of the ordering of phases.
>     and improve the correspondence between printed headers and
>     the numerical values specified with -xdisasm.
> 
> x)  Add a listing mode 0 (-xdisasm=1) that disassembles instructions
>     one by one as they are produced by the code generator.
> 
> x)  Remove the long-orphaned DT_DISASM macro.
> 
> x)  Add a test of disassembly modes that checks that:
> 
>     x  disassembly of all modes in one run is the same
>        as what the various modes report individually
> 
>     x  the default mode is correct
> 
> Developers can add more -xdisasm=1 diagnostic messages to the code
> generator like this:
> 
> 	if (DT_DISASM_CODEGEN_COND(pcb))
> 		fprintf(stderr, "hello world\n");
> 
> Signed-off-by: Eugene Loh <eugene.loh at oracle.com>
> ---
>  libdtrace/dt_as.h                  |   2 +
>  libdtrace/dt_cg.c                  |  15 ++
>  libdtrace/dt_dis.c                 | 303 +++++++++++++++--------------
>  libdtrace/dt_dis.h                 |  42 ++--
>  libdtrace/dt_open.c                |   3 +-
>  libdtrace/dt_prov_dtrace.c         |   1 +
>  libdtrace/dt_prov_pid.c            |   1 +
>  libdtrace/dt_prov_profile.c        |   1 +
>  libdtrace/dt_prov_sdt.c            |   1 +
>  libdtrace/dt_prov_syscall.c        |   1 +
>  test/unittest/dif/tst.DisOption.sh | 126 ++++++++++++
>  11 files changed, 329 insertions(+), 167 deletions(-)
>  create mode 100755 test/unittest/dif/tst.DisOption.sh
> 
> diff --git a/libdtrace/dt_as.h b/libdtrace/dt_as.h
> index e35bd7be..fff2fe7a 100644
> --- a/libdtrace/dt_as.h
> +++ b/libdtrace/dt_as.h
> @@ -40,6 +40,8 @@ extern uint_t dt_irlist_label(dt_irlist_t *);
>  #define emitle(dlp, lbl, instr, idp) \
>  		({ \
>  			dt_irnode_t *dip = dt_cg_node_alloc((lbl), (instr)); \
> +			if (DT_DISASM_CODEGEN_COND(yypcb)) \
> +				dt_dis_insn(dlp->dl_len, &(instr), stderr); \
>  			dt_irlist_append((dlp), dip); \
>  			if (idp != NULL) \
>  				dip->di_extern = (idp); \
> diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
> index f111165a..55bf1449 100644
> --- a/libdtrace/dt_cg.c
> +++ b/libdtrace/dt_cg.c
> @@ -1543,10 +1543,13 @@ void
>  dt_cg_xsetx(dt_irlist_t *dlp, dt_ident_t *idp, uint_t lbl, int reg, uint64_t x)
>  {
>  	struct bpf_insn instr[2] = { BPF_LDDW(reg, x) };
> +	uint_t cflags = yypcb->pcb_cflags;
>  
>  	emitle(dlp, lbl,
>  		    instr[0], idp);
> +	yypcb->pcb_cflags &= ~DTRACE_C_DIFV;	/* turn disassembly off */
>  	emit(dlp,   instr[1]);
> +	yypcb->pcb_cflags = cflags;		/* restore disassembly */
>  }
>  
>  static void
> @@ -4610,6 +4613,18 @@ dt_cg(dt_pcb_t *pcb, dt_node_t *dnp)
>  		dnerror(dnp, D_CG_DYN, "expression cannot evaluate to result "
>  			"of dynamic type\n");
>  
> +	if (DT_DISASM_CODEGEN_COND(pcb)) {
> +		if (pcb->pcb_pdesc)
> +			fprintf(stderr,
> +			    "\nDisassembly (#0) code generation %s:%s:%s:%s:\n",
> +			    pcb->pcb_pdesc->prv ? pcb->pcb_pdesc->prv : "",
> +			    pcb->pcb_pdesc->mod ? pcb->pcb_pdesc->mod : "",
> +			    pcb->pcb_pdesc->fun ? pcb->pcb_pdesc->fun : "",
> +			    pcb->pcb_pdesc->prb ? pcb->pcb_pdesc->prb : "");
> +		else
> +			fprintf(stderr, "\nDisassembly (#0) code generation:\n");
> +	}
> +
>  	/*
>  	 * If we're generating code for a translator body, assign the input
>  	 * parameter to the first available register (i.e. caller passes %r1).
> diff --git a/libdtrace/dt_dis.c b/libdtrace/dt_dis.c
> index 7b7c39f9..84b9580d 100644
> --- a/libdtrace/dt_dis.c
> +++ b/libdtrace/dt_dis.c
> @@ -508,164 +508,179 @@ dt_dis_rtab(const char *rtag, const dtrace_difo_t *dp, FILE *fp,
>  	}
>  }
>  
> +static const struct opent {
> +	const char *op_name;
> +	uint_t (*op_func)(const dtrace_difo_t *, const char *, uint_t,
> +			  const struct bpf_insn *, const char *,
> +			  FILE *);
> +} optab[256] = {
> +	[0 ... 255] = { "(illegal opcode)", dt_dis_str },
> +#define INSN2(x, y)	[BPF_##x | BPF_##y]
> +#define INSN3(x, y, z)	[BPF_##x | BPF_##y | BPF_##z]
> +	/* 32-bit ALU ops, op(dst, src) */
> +	INSN3(ALU, ADD, X)	= { "add", dt_dis_op2 },
> +	INSN3(ALU, SUB, X)	= { "sub", dt_dis_op2 },
> +	INSN3(ALU, AND, X)	= { "and", dt_dis_op2 },
> +	INSN3(ALU, OR, X)	= { "or", dt_dis_op2 },
> +	INSN3(ALU, LSH, X)	= { "lsh", dt_dis_op2 },
> +	INSN3(ALU, RSH, X)	= { "rsh", dt_dis_op2 },
> +	INSN3(ALU, XOR, X)	= { "xor", dt_dis_op2 },
> +	INSN3(ALU, MUL, X)	= { "mul", dt_dis_op2 },
> +	INSN3(ALU, MOV, X)	= { "mov", dt_dis_op2 },
> +	INSN3(ALU, ARSH, X)	= { "arsh", dt_dis_op2 },
> +	INSN3(ALU, DIV, X)	= { "div", dt_dis_op2 },
> +	INSN3(ALU, MOD, X)	= { "mod", dt_dis_op2 },
> +	INSN2(ALU, NEG)		= { "neg", dt_dis_op1 },
> +	INSN3(ALU, END, TO_BE)	= { "tobe", dt_dis_op2 },
> +	INSN3(ALU, END, TO_LE)	= { "tole", dt_dis_op2 },
> +	/* 32-bit ALU ops, op(dst, imm) */
> +	INSN3(ALU, ADD, K)	= { "add", dt_dis_op2imm },
> +	INSN3(ALU, SUB, K)	= { "sub", dt_dis_op2imm },
> +	INSN3(ALU, AND, K)	= { "and", dt_dis_op2imm },
> +	INSN3(ALU, OR, K)	= { "or", dt_dis_op2imm },
> +	INSN3(ALU, LSH, K)	= { "lsh", dt_dis_op2imm },
> +	INSN3(ALU, RSH, K)	= { "rsh", dt_dis_op2imm },
> +	INSN3(ALU, XOR, K)	= { "xor", dt_dis_op2imm },
> +	INSN3(ALU, MUL, K)	= { "mul", dt_dis_op2imm },
> +	INSN3(ALU, MOV, K)	= { "mov", dt_dis_op2imm },
> +	INSN3(ALU, ARSH, K)	= { "arsh", dt_dis_op2imm },
> +	INSN3(ALU, DIV, K)	= { "div", dt_dis_op2imm },
> +	INSN3(ALU, MOD, K)	= { "mod", dt_dis_op2imm },
> +	/* 64-bit ALU ops, op(dst, src) */
> +	INSN3(ALU64, ADD, X)	= { "add", dt_dis_op2 },
> +	INSN3(ALU64, SUB, X)	= { "sub", dt_dis_op2 },
> +	INSN3(ALU64, AND, X)	= { "and", dt_dis_op2 },
> +	INSN3(ALU64, OR, X)	= { "or", dt_dis_op2 },
> +	INSN3(ALU64, LSH, X)	= { "lsh", dt_dis_op2 },
> +	INSN3(ALU64, RSH, X)	= { "rsh", dt_dis_op2 },
> +	INSN3(ALU64, XOR, X)	= { "xor", dt_dis_op2 },
> +	INSN3(ALU64, MUL, X)	= { "mul", dt_dis_op2 },
> +	INSN3(ALU64, MOV, X)	= { "mov", dt_dis_op2 },
> +	INSN3(ALU64, ARSH, X)	= { "arsh", dt_dis_op2 },
> +	INSN3(ALU64, DIV, X)	= { "div", dt_dis_op2 },
> +	INSN3(ALU64, MOD, X)	= { "mod", dt_dis_op2 },
> +	INSN2(ALU64, NEG)	= { "neg", dt_dis_op1 },
> +	/* 64-bit ALU ops, op(dst, imm) */
> +	INSN3(ALU64, ADD, K)	= { "add", dt_dis_op2imm },
> +	INSN3(ALU64, SUB, K)	= { "sub", dt_dis_op2imm },
> +	INSN3(ALU64, AND, K)	= { "and", dt_dis_op2imm },
> +	INSN3(ALU64, OR, K)	= { "or", dt_dis_op2imm },
> +	INSN3(ALU64, LSH, K)	= { "lsh", dt_dis_op2imm },
> +	INSN3(ALU64, RSH, K)	= { "rsh", dt_dis_op2imm },
> +	INSN3(ALU64, XOR, K)	= { "xor", dt_dis_op2imm },
> +	INSN3(ALU64, MUL, K)	= { "mul", dt_dis_op2imm },
> +	INSN3(ALU64, MOV, K)	= { "mov", dt_dis_op2imm },
> +	INSN3(ALU64, ARSH, K)	= { "arsh", dt_dis_op2imm },
> +	INSN3(ALU64, DIV, K)	= { "div", dt_dis_op2imm },
> +	INSN3(ALU64, MOD, K)	= { "mod", dt_dis_op2imm },
> +	/* Call instruction */
> +	INSN2(JMP, CALL)	= { "call", dt_dis_call },
> +	/* Return instruction */
> +	INSN2(JMP, EXIT)	= { "exit", dt_dis_str },
> +	/* 32-bit jump ops, op(dst, src) */
> +	INSN3(JMP32, JEQ, X)	= { "jeq", dt_dis_branch },
> +	INSN3(JMP32, JNE, X)	= { "jne", dt_dis_branch },
> +	INSN3(JMP32, JGT, X)	= { "jgt", dt_dis_branch },
> +	INSN3(JMP32, JLT, X)	= { "jlt", dt_dis_branch },
> +	INSN3(JMP32, JGE, X)	= { "jge", dt_dis_branch },
> +	INSN3(JMP32, JLE, X)	= { "jle", dt_dis_branch },
> +	INSN3(JMP32, JSGT, X)	= { "jsgt", dt_dis_branch },
> +	INSN3(JMP32, JSLT, X)	= { "jslt", dt_dis_branch },
> +	INSN3(JMP32, JSGE, X)	= { "jsge", dt_dis_branch },
> +	INSN3(JMP32, JSLE, X)	= { "jsle", dt_dis_branch },
> +	INSN3(JMP32, JSET, X)	= { "jset", dt_dis_branch },
> +	/* 32-bit jump ops, op(dst, imm) */
> +	INSN3(JMP32, JEQ, K)	= { "jeq", dt_dis_branch_imm },
> +	INSN3(JMP32, JNE, K)	= { "jne", dt_dis_branch_imm },
> +	INSN3(JMP32, JGT, K)	= { "jgt", dt_dis_branch_imm },
> +	INSN3(JMP32, JLT, K)	= { "jlt", dt_dis_branch_imm },
> +	INSN3(JMP32, JGE, K)	= { "jge", dt_dis_branch_imm },
> +	INSN3(JMP32, JLE, K)	= { "jle", dt_dis_branch_imm },
> +	INSN3(JMP32, JSGT, K)	= { "jsgt", dt_dis_branch_imm },
> +	INSN3(JMP32, JSLT, K)	= { "jslt", dt_dis_branch_imm },
> +	INSN3(JMP32, JSGE, K)	= { "jsge", dt_dis_branch_imm },
> +	INSN3(JMP32, JSLE, K)	= { "jsle", dt_dis_branch_imm },
> +	INSN3(JMP32, JSET, K)	= { "jset", dt_dis_branch_imm },
> +	/* 64-bit jump ops, op(dst, src) */
> +	INSN3(JMP, JEQ, X)	= { "jeq", dt_dis_branch },
> +	INSN3(JMP, JNE, X)	= { "jne", dt_dis_branch },
> +	INSN3(JMP, JGT, X)	= { "jgt", dt_dis_branch },
> +	INSN3(JMP, JLT, X)	= { "jlt", dt_dis_branch },
> +	INSN3(JMP, JGE, X)	= { "jge", dt_dis_branch },
> +	INSN3(JMP, JLE, X)	= { "jle", dt_dis_branch },
> +	INSN3(JMP, JSGT, X)	= { "jsgt", dt_dis_branch },
> +	INSN3(JMP, JSLT, X)	= { "jslt", dt_dis_branch },
> +	INSN3(JMP, JSGE, X)	= { "jsge", dt_dis_branch },
> +	INSN3(JMP, JSLE, X)	= { "jsle", dt_dis_branch },
> +	INSN3(JMP, JSET, X)	= { "jset", dt_dis_branch },
> +	/* 64-bit jump ops, op(dst, imm) */
> +	INSN3(JMP, JEQ, K)	= { "jeq", dt_dis_branch_imm },
> +	INSN3(JMP, JNE, K)	= { "jne", dt_dis_branch_imm },
> +	INSN3(JMP, JGT, K)	= { "jgt", dt_dis_branch_imm },
> +	INSN3(JMP, JLT, K)	= { "jlt", dt_dis_branch_imm },
> +	INSN3(JMP, JGE, K)	= { "jge", dt_dis_branch_imm },
> +	INSN3(JMP, JLE, K)	= { "jle", dt_dis_branch_imm },
> +	INSN3(JMP, JSGT, K)	= { "jsgt", dt_dis_branch_imm },
> +	INSN3(JMP, JSLT, K)	= { "jslt", dt_dis_branch_imm },
> +	INSN3(JMP, JSGE, K)	= { "jsge", dt_dis_branch_imm },
> +	INSN3(JMP, JSLE, K)	= { "jsle", dt_dis_branch_imm },
> +	INSN3(JMP, JSET, K)	= { "jset", dt_dis_branch_imm },
> +	INSN2(JMP, JA)		= { "ja", dt_dis_jump },
> +	/* Store instructions, [dst + off] = src */
> +	INSN3(STX, MEM, B)	= { "stb", dt_dis_store },
> +	INSN3(STX, MEM, H)	= { "sth", dt_dis_store },
> +	INSN3(STX, MEM, W)	= { "stw", dt_dis_store },
> +	INSN3(STX, MEM, DW)	= { "stdw", dt_dis_store },
> +	INSN3(STX, XADD, W)	= { "xadd", dt_dis_store },
> +	INSN3(STX, XADD, DW)	= { "xadd", dt_dis_store },
> +	/* Store instructions, [dst + off] = imm */
> +	INSN3(ST, MEM, B)	= { "stb", dt_dis_store_imm },
> +	INSN3(ST, MEM, H)	= { "sth", dt_dis_store_imm },
> +	INSN3(ST, MEM, W)	= { "stw", dt_dis_store_imm },
> +	INSN3(ST, MEM, DW)	= { "stdw", dt_dis_store_imm },
> +	/* Load instructions, dst = [src + off] */
> +	INSN3(LDX, MEM, B)	= { "ldb", dt_dis_load },
> +	INSN3(LDX, MEM, H)	= { "ldh", dt_dis_load },
> +	INSN3(LDX, MEM, W)	= { "ldw", dt_dis_load },
> +	INSN3(LDX, MEM, DW)	= { "lddw", dt_dis_load },
> +	/* Load instructions, dst = imm */
> +	INSN3(LD, IMM, DW)	= { "lddw", dt_dis_load_imm },
> +};
> +
> +void
> +dt_dis_insn(uint_t i, const struct bpf_insn *instr, FILE *fp)
> +{
> +	uint8_t			opcode = instr->code;
> +	const struct opent	*op;
> +
> +	if (opcode >= ARRAY_SIZE(optab))
> +		opcode = 0;	/* force invalid opcode message */
> +
> +	dt_dis_prefix(i, instr, fp);
> +
> +	op = &optab[opcode];
> +	op->op_func(NULL, op->op_name, i, instr, NULL, fp);
> +}
> +
>  void
>  dt_dis_difo(const dtrace_difo_t *dp, FILE *fp, const dt_ident_t *idp,
>  	    const dtrace_probedesc_t *pdp, const char *ltype)
>  {
> -	static const struct opent {
> -		const char *op_name;
> -		uint_t (*op_func)(const dtrace_difo_t *, const char *, uint_t,
> -				  const struct bpf_insn *, const char *,
> -				  FILE *);
> -	} optab[256] = {
> -		[0 ... 255] = { "(illegal opcode)", dt_dis_str },
> -#define INSN2(x, y)	[BPF_##x | BPF_##y]
> -#define INSN3(x, y, z)	[BPF_##x | BPF_##y | BPF_##z]
> -		/* 32-bit ALU ops, op(dst, src) */
> -		INSN3(ALU, ADD, X)	= { "add", dt_dis_op2 },
> -		INSN3(ALU, SUB, X)	= { "sub", dt_dis_op2 },
> -		INSN3(ALU, AND, X)	= { "and", dt_dis_op2 },
> -		INSN3(ALU, OR, X)	= { "or", dt_dis_op2 },
> -		INSN3(ALU, LSH, X)	= { "lsh", dt_dis_op2 },
> -		INSN3(ALU, RSH, X)	= { "rsh", dt_dis_op2 },
> -		INSN3(ALU, XOR, X)	= { "xor", dt_dis_op2 },
> -		INSN3(ALU, MUL, X)	= { "mul", dt_dis_op2 },
> -		INSN3(ALU, MOV, X)	= { "mov", dt_dis_op2 },
> -		INSN3(ALU, ARSH, X)	= { "arsh", dt_dis_op2 },
> -		INSN3(ALU, DIV, X)	= { "div", dt_dis_op2 },
> -		INSN3(ALU, MOD, X)	= { "mod", dt_dis_op2 },
> -		INSN2(ALU, NEG)		= { "neg", dt_dis_op1 },
> -		INSN3(ALU, END, TO_BE)	= { "tobe", dt_dis_op2 },
> -		INSN3(ALU, END, TO_LE)	= { "tole", dt_dis_op2 },
> -		/* 32-bit ALU ops, op(dst, imm) */
> -		INSN3(ALU, ADD, K)	= { "add", dt_dis_op2imm },
> -		INSN3(ALU, SUB, K)	= { "sub", dt_dis_op2imm },
> -		INSN3(ALU, AND, K)	= { "and", dt_dis_op2imm },
> -		INSN3(ALU, OR, K)	= { "or", dt_dis_op2imm },
> -		INSN3(ALU, LSH, K)	= { "lsh", dt_dis_op2imm },
> -		INSN3(ALU, RSH, K)	= { "rsh", dt_dis_op2imm },
> -		INSN3(ALU, XOR, K)	= { "xor", dt_dis_op2imm },
> -		INSN3(ALU, MUL, K)	= { "mul", dt_dis_op2imm },
> -		INSN3(ALU, MOV, K)	= { "mov", dt_dis_op2imm },
> -		INSN3(ALU, ARSH, K)	= { "arsh", dt_dis_op2imm },
> -		INSN3(ALU, DIV, K)	= { "div", dt_dis_op2imm },
> -		INSN3(ALU, MOD, K)	= { "mod", dt_dis_op2imm },
> -		/* 64-bit ALU ops, op(dst, src) */
> -		INSN3(ALU64, ADD, X)	= { "add", dt_dis_op2 },
> -		INSN3(ALU64, SUB, X)	= { "sub", dt_dis_op2 },
> -		INSN3(ALU64, AND, X)	= { "and", dt_dis_op2 },
> -		INSN3(ALU64, OR, X)	= { "or", dt_dis_op2 },
> -		INSN3(ALU64, LSH, X)	= { "lsh", dt_dis_op2 },
> -		INSN3(ALU64, RSH, X)	= { "rsh", dt_dis_op2 },
> -		INSN3(ALU64, XOR, X)	= { "xor", dt_dis_op2 },
> -		INSN3(ALU64, MUL, X)	= { "mul", dt_dis_op2 },
> -		INSN3(ALU64, MOV, X)	= { "mov", dt_dis_op2 },
> -		INSN3(ALU64, ARSH, X)	= { "arsh", dt_dis_op2 },
> -		INSN3(ALU64, DIV, X)	= { "div", dt_dis_op2 },
> -		INSN3(ALU64, MOD, X)	= { "mod", dt_dis_op2 },
> -		INSN2(ALU64, NEG)	= { "neg", dt_dis_op1 },
> -		/* 64-bit ALU ops, op(dst, imm) */
> -		INSN3(ALU64, ADD, K)	= { "add", dt_dis_op2imm },
> -		INSN3(ALU64, SUB, K)	= { "sub", dt_dis_op2imm },
> -		INSN3(ALU64, AND, K)	= { "and", dt_dis_op2imm },
> -		INSN3(ALU64, OR, K)	= { "or", dt_dis_op2imm },
> -		INSN3(ALU64, LSH, K)	= { "lsh", dt_dis_op2imm },
> -		INSN3(ALU64, RSH, K)	= { "rsh", dt_dis_op2imm },
> -		INSN3(ALU64, XOR, K)	= { "xor", dt_dis_op2imm },
> -		INSN3(ALU64, MUL, K)	= { "mul", dt_dis_op2imm },
> -		INSN3(ALU64, MOV, K)	= { "mov", dt_dis_op2imm },
> -		INSN3(ALU64, ARSH, K)	= { "arsh", dt_dis_op2imm },
> -		INSN3(ALU64, DIV, K)	= { "div", dt_dis_op2imm },
> -		INSN3(ALU64, MOD, K)	= { "mod", dt_dis_op2imm },
> -		/* Call instruction */
> -		INSN2(JMP, CALL)	= { "call", dt_dis_call },
> -		/* Return instruction */
> -		INSN2(JMP, EXIT)	= { "exit", dt_dis_str },
> -		/* 32-bit jump ops, op(dst, src) */
> -		INSN3(JMP32, JEQ, X)	= { "jeq", dt_dis_branch },
> -		INSN3(JMP32, JNE, X)	= { "jne", dt_dis_branch },
> -		INSN3(JMP32, JGT, X)	= { "jgt", dt_dis_branch },
> -		INSN3(JMP32, JLT, X)	= { "jlt", dt_dis_branch },
> -		INSN3(JMP32, JGE, X)	= { "jge", dt_dis_branch },
> -		INSN3(JMP32, JLE, X)	= { "jle", dt_dis_branch },
> -		INSN3(JMP32, JSGT, X)	= { "jsgt", dt_dis_branch },
> -		INSN3(JMP32, JSLT, X)	= { "jslt", dt_dis_branch },
> -		INSN3(JMP32, JSGE, X)	= { "jsge", dt_dis_branch },
> -		INSN3(JMP32, JSLE, X)	= { "jsle", dt_dis_branch },
> -		INSN3(JMP32, JSET, X)	= { "jset", dt_dis_branch },
> -		/* 32-bit jump ops, op(dst, imm) */
> -		INSN3(JMP32, JEQ, K)	= { "jeq", dt_dis_branch_imm },
> -		INSN3(JMP32, JNE, K)	= { "jne", dt_dis_branch_imm },
> -		INSN3(JMP32, JGT, K)	= { "jgt", dt_dis_branch_imm },
> -		INSN3(JMP32, JLT, K)	= { "jlt", dt_dis_branch_imm },
> -		INSN3(JMP32, JGE, K)	= { "jge", dt_dis_branch_imm },
> -		INSN3(JMP32, JLE, K)	= { "jle", dt_dis_branch_imm },
> -		INSN3(JMP32, JSGT, K)	= { "jsgt", dt_dis_branch_imm },
> -		INSN3(JMP32, JSLT, K)	= { "jslt", dt_dis_branch_imm },
> -		INSN3(JMP32, JSGE, K)	= { "jsge", dt_dis_branch_imm },
> -		INSN3(JMP32, JSLE, K)	= { "jsle", dt_dis_branch_imm },
> -		INSN3(JMP32, JSET, K)	= { "jset", dt_dis_branch_imm },
> -		/* 64-bit jump ops, op(dst, src) */
> -		INSN3(JMP, JEQ, X)	= { "jeq", dt_dis_branch },
> -		INSN3(JMP, JNE, X)	= { "jne", dt_dis_branch },
> -		INSN3(JMP, JGT, X)	= { "jgt", dt_dis_branch },
> -		INSN3(JMP, JLT, X)	= { "jlt", dt_dis_branch },
> -		INSN3(JMP, JGE, X)	= { "jge", dt_dis_branch },
> -		INSN3(JMP, JLE, X)	= { "jle", dt_dis_branch },
> -		INSN3(JMP, JSGT, X)	= { "jsgt", dt_dis_branch },
> -		INSN3(JMP, JSLT, X)	= { "jslt", dt_dis_branch },
> -		INSN3(JMP, JSGE, X)	= { "jsge", dt_dis_branch },
> -		INSN3(JMP, JSLE, X)	= { "jsle", dt_dis_branch },
> -		INSN3(JMP, JSET, X)	= { "jset", dt_dis_branch },
> -		/* 64-bit jump ops, op(dst, imm) */
> -		INSN3(JMP, JEQ, K)	= { "jeq", dt_dis_branch_imm },
> -		INSN3(JMP, JNE, K)	= { "jne", dt_dis_branch_imm },
> -		INSN3(JMP, JGT, K)	= { "jgt", dt_dis_branch_imm },
> -		INSN3(JMP, JLT, K)	= { "jlt", dt_dis_branch_imm },
> -		INSN3(JMP, JGE, K)	= { "jge", dt_dis_branch_imm },
> -		INSN3(JMP, JLE, K)	= { "jle", dt_dis_branch_imm },
> -		INSN3(JMP, JSGT, K)	= { "jsgt", dt_dis_branch_imm },
> -		INSN3(JMP, JSLT, K)	= { "jslt", dt_dis_branch_imm },
> -		INSN3(JMP, JSGE, K)	= { "jsge", dt_dis_branch_imm },
> -		INSN3(JMP, JSLE, K)	= { "jsle", dt_dis_branch_imm },
> -		INSN3(JMP, JSET, K)	= { "jset", dt_dis_branch_imm },
> -		INSN2(JMP, JA)		= { "ja", dt_dis_jump },
> -		/* Store instructions, [dst + off] = src */
> -		INSN3(STX, MEM, B)	= { "stb", dt_dis_store },
> -		INSN3(STX, MEM, H)	= { "sth", dt_dis_store },
> -		INSN3(STX, MEM, W)	= { "stw", dt_dis_store },
> -		INSN3(STX, MEM, DW)	= { "stdw", dt_dis_store },
> -		INSN3(STX, XADD, W)	= { "xadd", dt_dis_store },
> -		INSN3(STX, XADD, DW)	= { "xadd", dt_dis_store },
> -		/* Store instructions, [dst + off] = imm */
> -		INSN3(ST, MEM, B)	= { "stb", dt_dis_store_imm },
> -		INSN3(ST, MEM, H)	= { "sth", dt_dis_store_imm },
> -		INSN3(ST, MEM, W)	= { "stw", dt_dis_store_imm },
> -		INSN3(ST, MEM, DW)	= { "stdw", dt_dis_store_imm },
> -		/* Load instructions, dst = [src + off] */
> -		INSN3(LDX, MEM, B)	= { "ldb", dt_dis_load },
> -		INSN3(LDX, MEM, H)	= { "ldh", dt_dis_load },
> -		INSN3(LDX, MEM, W)	= { "ldw", dt_dis_load },
> -		INSN3(LDX, MEM, DW)	= { "lddw", dt_dis_load },
> -		/* Load instructions, dst = imm */
> -		INSN3(LD, IMM, DW)	= { "lddw", dt_dis_load_imm },
> -	};
> -
>  	uint_t		i = 0;
>  	dof_relodesc_t	*rp = dp->dtdo_breltab;
>  	int		cnt = dp->dtdo_brelen;
>  	char		type[DT_TYPE_NAMELEN];
>  
>  	if (pdp != NULL && idp != NULL)
> -		fprintf(fp, "\nDisassembly of %s %s:%s:%s:%s, <%s>:\n", ltype,
> +		fprintf(fp, "\nDisassembly %s %s:%s:%s:%s, <%s>:\n", ltype,
>  			pdp->prv, pdp->mod, pdp->fun, pdp->prb, idp->di_name);
>  	else if (pdp != NULL)
> -		fprintf(fp, "\nDisassembly of %s %s:%s:%s:%s:\n", ltype,
> +		fprintf(fp, "\nDisassembly %s %s:%s:%s:%s:\n", ltype,
>  			pdp->prv, pdp->mod, pdp->fun, pdp->prb);
>  	else if (idp != NULL)
> -		fprintf(fp, "\nDisassembly of %s <%s>:\n", ltype, idp->di_name);
> +		fprintf(fp, "\nDisassembly %s <%s>:\n", ltype, idp->di_name);
>  	else
> -		fprintf(fp, "\nDisassembly of %s:\n", ltype);
> +		fprintf(fp, "\nDisassembly %s:\n", ltype);
>  
>  	fprintf(fp, "%-3s %-5s %-20s    %s\n",
>  	    "INS", "OFF", "OPCODE", "INSTRUCTION");
> @@ -807,7 +822,7 @@ dt_dis_stmts(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, dtrace_stmtdesc_t *sdp,
>  	}
>  
>  	dt_dis_difo(dt_dlib_get_func_difo(dtp, sdp->dtsd_clause), d->fp,
> -		    sdp->dtsd_clause, pdp, "clause");
> +		    sdp->dtsd_clause, pdp, "(#1) clause");
>  
>  	return 0;
>  }
> diff --git a/libdtrace/dt_dis.h b/libdtrace/dt_dis.h
> index 36dac74c..2a68981e 100644
> --- a/libdtrace/dt_dis.h
> +++ b/libdtrace/dt_dis.h
> @@ -15,17 +15,27 @@ extern "C" {
>  #endif
>  
>  /*
> - * The following disassembler listings can be requested.  The values can be
> - * combined to select multiple listings.
> + * The following disassembler listings can be requested with -xdisasm=....
> + *    - As the code generator issues each instruction.
> + *    - After compilation and assembly of a clause function.
> + *    - After constructing a probe program.
> + *    - After linking in dependencies.
> + *    - After all processing, prior to loading the program.
> + * The values can be combined to select multiple listings.  The '-S' option
> + * must also be supplied in order for disassembler output to be generated.
>   */
> -#define DT_DISASM_OPT_CLAUSE		1	/* default */
> -#define DT_DISASM_OPT_PROG		2
> -#define DT_DISASM_OPT_PROG_LINKED	4
> -#define DT_DISASM_OPT_PROG_FINAL	8
> +#define DT_DISASM_OPT_CODEGEN		1
> +#define DT_DISASM_OPT_CLAUSE		2
> +#define DT_DISASM_OPT_PROG		4
> +#define DT_DISASM_OPT_PROG_LINKED	8
> +#define DT_DISASM_OPT_PROG_FINAL	16
>  
>  /*
>   * Macros to make a call to the disassembler for specific disassembler listings.
>   */
> +#define DT_DISASM_CODEGEN_COND(pcb) \
> +	((pcb)->pcb_cflags & DTRACE_C_DIFV && \
> +	    (pcb)->pcb_hdl->dt_disasm & DT_DISASM_OPT_CODEGEN)
>  #define DT_DISASM_CLAUSE(dtp, cflags, pp, fp) \
>  	do { \
>  		if (((cflags) & DTRACE_C_DIFV) && \
> @@ -36,36 +46,24 @@ extern "C" {
>  	do { \
>  		if (((cflags) & DTRACE_C_DIFV) && \
>  		    ((dtp)->dt_disasm & DT_DISASM_OPT_PROG)) \
> -			dt_dis_difo((dp), (fp), (idp), (pdp), "program"); \
> +			dt_dis_difo((dp), (fp), (idp), (pdp), "(#2) program"); \
>  	} while(0)
>  #define DT_DISASM_PROG_LINKED(dtp, cflags, dp, fp, idp, pdp) \
>  	do { \
>  		if (((cflags) & DTRACE_C_DIFV) && \
>  		    ((dtp)->dt_disasm & DT_DISASM_OPT_PROG_LINKED)) \
>  			dt_dis_difo((dp), (fp), (idp), (pdp), \
> -				    "linked program"); \
> +				    "(#3) linked program"); \
>  	} while(0)
>  #define DT_DISASM_PROG_FINAL(dtp, cflags, dp, fp, idp, pdp) \
>  	do { \
>  		if (((cflags) & DTRACE_C_DIFV) && \
>  		    ((dtp)->dt_disasm & DT_DISASM_OPT_PROG_FINAL)) \
>  			dt_dis_difo((dp), (fp), (idp), (pdp), \
> -				    "final program"); \
> +				    "(#4) final program"); \
>  	} while(0)
> -/*
> - * Macro to test whether a given disassembler bit is set in the dt_disasm
> - * bit-vector.  If the bit for listing 'l' is set, the D disassembler will be
> - * invoked for that specific listing.  The '-S' option must also be supplied in
> - * order for disassembler output to be generated.
> - *
> - * Supported listings are:
> - *	1	After compilation and assembly of a clause function.
> - *	2	After constructing a probe program.
> - *	3	After linking in dependencies.
> - *	4	After all processing, prior to loading the program.
> - */
> -#define	DT_DISASM(dtp, l)		((dtp)->dt_disasm & (1 << ((l) - 1)))
>  
> +extern void dt_dis_insn(uint_t i, const struct bpf_insn *instr, FILE *fp);
>  extern void dt_dis_program(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, FILE *fp);
>  extern void dt_dis_difo(const dtrace_difo_t *dp, FILE *fp,
>  			const dt_ident_t *idp, const dtrace_probedesc_t *pdp,
> diff --git a/libdtrace/dt_open.c b/libdtrace/dt_open.c
> index f2b86f7c..c912615c 100644
> --- a/libdtrace/dt_open.c
> +++ b/libdtrace/dt_open.c
> @@ -36,6 +36,7 @@
>  #include <dt_string.h>
>  #include <dt_provider.h>
>  #include <dt_probe.h>
> +#include <dt_dis.h>
>  #include <dt_peb.h>
>  
>  const dt_version_t _dtrace_versions[] = {
> @@ -725,7 +726,7 @@ dt_vopen(int version, int flags, int *errp,
>  	dtp->dt_linktype = DT_LTYP_ELF;
>  	dtp->dt_xlatemode = DT_XL_STATIC;
>  	dtp->dt_stdcmode = DT_STDC_XA;
> -	dtp->dt_disasm = 1;
> +	dtp->dt_disasm = DT_DISASM_OPT_CLAUSE;
>  	dtp->dt_version = version;
>  	dtp->dt_cdefs_fd = -1;
>  	dtp->dt_ddefs_fd = -1;
> diff --git a/libdtrace/dt_prov_dtrace.c b/libdtrace/dt_prov_dtrace.c
> index 3e0bb3f1..87b2d4bc 100644
> --- a/libdtrace/dt_prov_dtrace.c
> +++ b/libdtrace/dt_prov_dtrace.c
> @@ -16,6 +16,7 @@
>  #include "dt_cg.h"
>  #include "dt_provider.h"
>  #include "dt_probe.h"
> +#include "dt_dis.h"
>  
>  static const char		prvname[] = "dtrace";
>  static const char		modname[] = "";
> diff --git a/libdtrace/dt_prov_pid.c b/libdtrace/dt_prov_pid.c
> index 5c0345c3..e7d0b754 100644
> --- a/libdtrace/dt_prov_pid.c
> +++ b/libdtrace/dt_prov_pid.c
> @@ -18,6 +18,7 @@
>  #include "dt_provider.h"
>  #include "dt_probe.h"
>  #include "dt_pid.h"
> +#include "dt_dis.h"
>  
>  static const char		prvname[] = "pid";
>  
> diff --git a/libdtrace/dt_prov_profile.c b/libdtrace/dt_prov_profile.c
> index 313c8c9c..f4d9d676 100644
> --- a/libdtrace/dt_prov_profile.c
> +++ b/libdtrace/dt_prov_profile.c
> @@ -15,6 +15,7 @@
>  #include "dt_cg.h"
>  #include "dt_bpf.h"
>  #include "dt_probe.h"
> +#include "dt_dis.h"
>  
>  static const char		prvname[] = "profile";
>  static const char		modname[] = "";
> diff --git a/libdtrace/dt_prov_sdt.c b/libdtrace/dt_prov_sdt.c
> index 320edbd2..5a44d871 100644
> --- a/libdtrace/dt_prov_sdt.c
> +++ b/libdtrace/dt_prov_sdt.c
> @@ -32,6 +32,7 @@
>  #include "dt_bpf.h"
>  #include "dt_provider.h"
>  #include "dt_probe.h"
> +#include "dt_dis.h"
>  #include "dt_pt_regs.h"
>  
>  static const char		prvname[] = "sdt";
> diff --git a/libdtrace/dt_prov_syscall.c b/libdtrace/dt_prov_syscall.c
> index 6c61e16b..65b624a9 100644
> --- a/libdtrace/dt_prov_syscall.c
> +++ b/libdtrace/dt_prov_syscall.c
> @@ -33,6 +33,7 @@
>  #include "dt_cg.h"
>  #include "dt_provider.h"
>  #include "dt_probe.h"
> +#include "dt_dis.h"
>  #include "dt_pt_regs.h"
>  
>  static const char		prvname[] = "syscall";
> diff --git a/test/unittest/dif/tst.DisOption.sh b/test/unittest/dif/tst.DisOption.sh
> new file mode 100755
> index 00000000..ebbf332d
> --- /dev/null
> +++ b/test/unittest/dif/tst.DisOption.sh
> @@ -0,0 +1,126 @@
> +#!/bin/bash
> +#
> +# 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.
> +#
> +
> +# ASSERTION: That the dtrace -xdisasm option can control the listings.
> +
> +dtrace=$1
> +
> +DIRNAME="$tmpdir/DisOption.$$.$RANDOM"
> +mkdir -p $DIRNAME
> +cd $DIRNAME
> +
> +# create sample D scripts and expected D output
> +
> +cat << EOF > D1.d
> +int x;
> +BEGIN {
> +    x = 1234;
> +    y = x;
> +}
> +EOF
> +cat << EOF > D2.d
> +BEGIN {
> +    trace(y);
> +    exit(0);
> +}
> +EOF
> +cat << EOF > D.out
> +1234
> +EOF
> +
> +# run dtrace for various xdisasm settings
> +
> +function run_dtrace() {
> +    $dtrace $dt_flags $2 -Sq -s D1.d -s D2.d > $1.out 2> $1.err
> +    if [ $? -ne 0 ]; then
> +        echo DTrace failed $2
> +        cat $1.out $1.err
> +        exit 1
> +    fi
> +}
> +
> +run_dtrace def               # default
> +run_dtrace   0 -xdisasm=1    # listing mode 0
> +run_dtrace   1 -xdisasm=2    # listing mode 1
> +run_dtrace   2 -xdisasm=4    # listing mode 2
> +run_dtrace   3 -xdisasm=8    # listing mode 3
> +run_dtrace   4 -xdisasm=16   # listing mode 4
> +run_dtrace all -xdisasm=31   # all
> +
> +# check individual D stdout and stderr files
> +
> +for x in def 0 1 2 3 4 all; do
> +    if [ `cat $x.err | wc -l` -lt 10 ]; then
> +        echo $x.err is suspiciously small
> +        cat $x.err
> +        exit 1
> +    fi
> +    if ! diff -q $x.out D.out > /dev/null; then
> +        echo $x.out is not as expected
> +        cat $x.out
> +        exit 1
> +    fi
> +done
> +
> +# check default setting
> +
> +if ! diff -q 1.err def.err > /dev/null; then
> +    echo it appears that -xdisasm=2 is not the default
> +    cat 1.err def.err
> +    exit 1
> +fi
> +
> +# split all.err into *.chk files
> +
> +for x in 0 1 2 3 4; do
> +    rm -f $x.chk
> +    touch $x.chk
> +done
> +
> +awk '
> +BEGIN { f = "/dev/null"; lastlineblank = 0; }
> +lastlineblank == 1 {
> +    # if previous line was blank, see if we should change output file
> +    if (index($0, "Disassembly (#0) code generation") == 1) { f = "0.chk" } else
> +    if (index($0, "Disassembly (#1) clause "        ) == 1) { f = "1.chk" } else
> +    if (index($0, "Disassembly (#2) program "       ) == 1) { f = "2.chk" } else
> +    if (index($0, "Disassembly (#3) linked program ") == 1) { f = "3.chk" } else
> +    if (index($0, "Disassembly (#4) final program " ) == 1) { f = "4.chk" }
> +
> +    # in any case, print that previous (blank) line
> +    print "" >> f;
> +}
> +
> +# if this line is blank, do not print it yet;  wait to see the next line
> +NF == 0 {
> +    lastlineblank = 1;
> +}
> +NF != 0 {
> +    print $0 >> f;
> +    lastlineblank = 0;
> +}
> +' all.err
> +
> +echo >> 4.chk     # need an extra blank line at the end
> +
> +# check against *.chk files
> +
> +for x in 0 1 2 3 4; do
> +    if ! diff -q $x.chk $x.err > /dev/null; then
> +        echo $x.chk does not match $x.err
> +        diff $x.chk $x.err
> +        echo $x.chk
> +        cat  $x.chk
> +        echo $x.err
> +        cat  $x.err
> +        exit 1
> +    fi
> +done
> +
> +echo success
> +exit 0
> -- 
> 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