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

eugene.loh at oracle.com eugene.loh at oracle.com
Wed Apr 14 09:50:20 PDT 2021


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




More information about the DTrace-devel mailing list