[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