From bfb2629c162c05dac30fc16180953efb671c4227 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 30 Dec 2015 23:17:58 -0500 Subject: [PATCH] sim: trace: add support for disassembling Some targets have started to add support for calling the disassembler automatically when executing code. Add support for that directly into the trace core. --- sim/common/ChangeLog | 20 ++++++++++++++ sim/common/sim-trace.c | 62 ++++++++++++++++++++++++++++++++++++++++++ sim/common/sim-trace.h | 38 +++++++++++++++++++++++++- 3 files changed, 119 insertions(+), 1 deletion(-) diff --git a/sim/common/ChangeLog b/sim/common/ChangeLog index 8ad6a417351..6dc76f5de3f 100644 --- a/sim/common/ChangeLog +++ b/sim/common/ChangeLog @@ -1,3 +1,23 @@ +2016-01-05 Mike Frysinger + + * sim-trace.c: Include dis-asm.h. + (OPTION_TRACE_DISASM): New enum. + (trace_options): Add trace-disasm flag. + (trace_option_handler): Handle OPTION_TRACE_DISASM. + (trace_idx_to_str): Handle TRACE_DISASM_IDX. + (dis_read, dis_printf, trace_disasm): New functions. + * sim-trace.h: Include dis-asm.h. + (TRACE_INSN_IDX): Clarify comment. + (TRACE_DISASM_IDX): New enum. + (TRACE_disasm): New define. + (WITH_TRACE_DISASM_P): New define. + (struct _trace_data): Add dis_bfd, disassembler, and dis_info. + (STRACE_DISASM_P): New define. + (TRACE_DISASM_P): Likewise. + (TRACE_DISASM_P): Likewise. + (TRACE_DISASM): Likewise. + (trace_disasm): New function. + 2016-01-04 Mike Frysinger * sim-utils.c (sim_state_free): Change to STATE_MAGIC. diff --git a/sim/common/sim-trace.c b/sim/common/sim-trace.c index 6c01e15e106..e299cf857d0 100644 --- a/sim/common/sim-trace.c +++ b/sim/common/sim-trace.c @@ -25,6 +25,8 @@ along with this program. If not, see . */ #include "bfd.h" #include "libiberty.h" +#include "dis-asm.h" + #include "sim-assert.h" #ifdef HAVE_STRING_H @@ -61,6 +63,7 @@ static DECLARE_OPTION_HANDLER (trace_option_handler); enum { OPTION_TRACE_INSN = OPTION_START, + OPTION_TRACE_DISASM, OPTION_TRACE_DECODE, OPTION_TRACE_EXTRACT, OPTION_TRACE_LINENUM, @@ -90,6 +93,9 @@ static const OPTION trace_options[] = { {"trace-insn", optional_argument, NULL, OPTION_TRACE_INSN}, '\0', "on|off", "Perform instruction tracing", trace_option_handler, NULL }, + { {"trace-disasm", optional_argument, NULL, OPTION_TRACE_DISASM}, + '\0', "on|off", "Disassemble instructions (slower, but more accurate)", + trace_option_handler, NULL }, { {"trace-decode", optional_argument, NULL, OPTION_TRACE_DECODE}, '\0', "on|off", "Trace instruction decoding", trace_option_handler, NULL }, @@ -249,6 +255,13 @@ trace_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt, sim_io_eprintf (sd, "Instruction tracing not compiled in, `--trace-insn' ignored\n"); break; + case OPTION_TRACE_DISASM : + if (WITH_TRACE_DISASM_P) + return set_trace_option (sd, "-disasm", TRACE_DISASM_IDX, arg); + else + sim_io_eprintf (sd, "Instruction tracing not compiled in, `--trace-disasm' ignored\n"); + break; + case OPTION_TRACE_DECODE : if (WITH_TRACE_DECODE_P) return set_trace_option (sd, "-decode", TRACE_DECODE_IDX, arg); @@ -616,6 +629,7 @@ trace_idx_to_str (int trace_idx) { case TRACE_ALU_IDX: return "alu: "; case TRACE_INSN_IDX: return "insn: "; + case TRACE_DISASM_IDX: return "disasm: "; case TRACE_DECODE_IDX: return "decode: "; case TRACE_EXTRACT_IDX: return "extract: "; case TRACE_MEMORY_IDX: return "memory: "; @@ -837,6 +851,54 @@ trace_generic (SIM_DESC sd, trace_printf (sd, cpu, "\n"); } +static int +dis_read (bfd_vma memaddr, bfd_byte *myaddr, unsigned int length, + struct disassemble_info *dinfo) +{ + SIM_CPU *cpu = dinfo->application_data; + sim_core_read_buffer (CPU_STATE (cpu), cpu, NULL_CIA, myaddr, memaddr, length); + return 0; +} + +static int +dis_printf (SIM_CPU *cpu, const char *fmt, ...) +{ + SIM_DESC sd = CPU_STATE (cpu); + va_list ap; + va_start (ap, fmt); + trace_vprintf (sd, cpu, fmt, ap); + va_end (ap); + return 0; +} + +void +trace_disasm (SIM_DESC sd, sim_cpu *cpu, address_word addr) +{ + struct bfd *bfd = STATE_PROG_BFD (sd); + TRACE_DATA *trace_data = CPU_TRACE_DATA (cpu); + disassemble_info *info = &trace_data->dis_info; + + /* See if we need to set up the disassembly func. */ + if (trace_data->dis_bfd != bfd) + { + trace_data->dis_bfd = bfd; + trace_data->disassembler = disassembler (trace_data->dis_bfd); + INIT_DISASSEMBLE_INFO (*info, cpu, dis_printf); + info->read_memory_func = dis_read; + info->arch = bfd_get_arch (bfd); + info->mach = bfd_get_mach (bfd); + disassemble_init_for_target (info); + } + + info->application_data = cpu; + + trace_printf (sd, cpu, "%s %s", + trace_idx_to_str (TRACE_DISASM_IDX), + TRACE_PREFIX (trace_data)); + trace_data->disassembler (addr, info); + trace_printf (sd, cpu, "\n"); +} + void trace_input0 (SIM_DESC sd, sim_cpu *cpu, diff --git a/sim/common/sim-trace.h b/sim/common/sim-trace.h index 6d62c5ab0a7..40de5bf5a21 100644 --- a/sim/common/sim-trace.h +++ b/sim/common/sim-trace.h @@ -22,12 +22,20 @@ along with this program. If not, see . */ #ifndef SIM_TRACE_H #define SIM_TRACE_H +#include "dis-asm.h" + /* Standard traceable entities. */ enum { - /* Trace insn execution. */ + /* Trace insn execution. The port itself is responsible for displaying what + it thinks it is decoding. */ TRACE_INSN_IDX = 1, + /* Disassemble code addresses. Like insn tracing, but relies on the opcode + framework for displaying code. Can be slower, more accurate as to what + the binary code actually is, but not how the sim is decoding it. */ + TRACE_DISASM_IDX, + /* Trace insn decoding. ??? This is more of a simulator debugging operation and might best be moved to --debug-decode. */ @@ -97,6 +105,7 @@ enum { The case choice here is on purpose. The lowercase parts are args to --with-trace. */ #define TRACE_insn (1 << TRACE_INSN_IDX) +#define TRACE_disasm (1 << TRACE_DISASM_IDX) #define TRACE_decode (1 << TRACE_DECODE_IDX) #define TRACE_extract (1 << TRACE_EXTRACT_IDX) #define TRACE_linenum (1 << TRACE_LINENUM_IDX) @@ -118,6 +127,7 @@ enum { /* Preprocessor macros to simplify tests of WITH_TRACE. */ #define WITH_TRACE_ANY_P (WITH_TRACE) #define WITH_TRACE_INSN_P WITH_TRACE_P (TRACE_INSN_IDX) +#define WITH_TRACE_DISASM_P WITH_TRACE_P (TRACE_DISASM_IDX) #define WITH_TRACE_DECODE_P WITH_TRACE_P (TRACE_DECODE_IDX) #define WITH_TRACE_EXTRACT_P WITH_TRACE_P (TRACE_EXTRACT_IDX) #define WITH_TRACE_LINENUM_P WITH_TRACE_P (TRACE_LINENUM_IDX) @@ -190,6 +200,19 @@ typedef struct _trace_data { ??? Not all cpu's support this. */ ADDR_RANGE range; #define TRACE_RANGE(t) (& (t)->range) + + /* The bfd used to disassemble code. Should compare against STATE_PROG_BFD + before using the disassembler helper. + Meant for use by the internal trace module only. */ + struct bfd *dis_bfd; + + /* The function used to actually disassemble code. + Meant for use by the internal trace module only. */ + disassembler_ftype disassembler; + + /* State used with the disassemble function. + Meant for use by the internal trace module only. */ + disassemble_info dis_info; } TRACE_DATA; /* System tracing support. */ @@ -204,6 +227,7 @@ typedef struct _trace_data { /* Non-zero if --trace- was specified for SD. */ #define STRACE_ANY_P(sd) (WITH_TRACE_ANY_P && (STATE_TRACE_DATA (sd)->trace_any_p)) #define STRACE_INSN_P(sd) STRACE_P (sd, TRACE_INSN_IDX) +#define STRACE_DISASM_P(sd) STRACE_P (sd, TRACE_DISASM_IDX) #define STRACE_DECODE_P(sd) STRACE_P (sd, TRACE_DECODE_IDX) #define STRACE_EXTRACT_P(sd) STRACE_P (sd, TRACE_EXTRACT_IDX) #define STRACE_LINENUM_P(sd) STRACE_P (sd, TRACE_LINENUM_IDX) @@ -226,6 +250,7 @@ typedef struct _trace_data { trace_generic (sd, NULL, idx, fmt, ## args); \ } while (0) #define STRACE_INSN(sd, fmt, args...) STRACE (sd, TRACE_INSN_IDX, fmt, ## args) +#define STRACE_DISASM(sd, fmt, args...) STRACE (sd, TRACE_DISASM_IDX, fmt, ## args) #define STRACE_DECODE(sd, fmt, args...) STRACE (sd, TRACE_DECODE_IDX, fmt, ## args) #define STRACE_EXTRACT(sd, fmt, args...) STRACE (sd, TRACE_EXTRACT_IDX, fmt, ## args) #define STRACE_LINENUM(sd, fmt, args...) STRACE (sd, TRACE_LINENUM_IDX, fmt, ## args) @@ -252,6 +277,7 @@ typedef struct _trace_data { /* Non-zero if --trace- was specified for CPU. */ #define TRACE_ANY_P(cpu) (WITH_TRACE_ANY_P && (CPU_TRACE_DATA (cpu)->trace_any_p)) #define TRACE_INSN_P(cpu) TRACE_P (cpu, TRACE_INSN_IDX) +#define TRACE_DISASM_P(cpu) TRACE_P (cpu, TRACE_DISASM_IDX) #define TRACE_DECODE_P(cpu) TRACE_P (cpu, TRACE_DECODE_IDX) #define TRACE_EXTRACT_P(cpu) TRACE_P (cpu, TRACE_EXTRACT_IDX) #define TRACE_LINENUM_P(cpu) TRACE_P (cpu, TRACE_LINENUM_IDX) @@ -266,6 +292,7 @@ typedef struct _trace_data { #define TRACE_SYSCALL_P(cpu) TRACE_P (cpu, TRACE_SYSCALL_IDX) #define TRACE_REGISTER_P(cpu) TRACE_P (cpu, TRACE_REGISTER_IDX) #define TRACE_DEBUG_P(cpu) TRACE_P (cpu, TRACE_DEBUG_IDX) +#define TRACE_DISASM_P(cpu) TRACE_P (cpu, TRACE_DISASM_IDX) /* Helper functions for printing messages. */ #define TRACE(cpu, idx, fmt, args...) \ @@ -288,6 +315,11 @@ typedef struct _trace_data { #define TRACE_SYSCALL(cpu, fmt, args...) TRACE (cpu, TRACE_SYSCALL_IDX, fmt, ## args) #define TRACE_REGISTER(cpu, fmt, args...) TRACE (cpu, TRACE_REGISTER_IDX, fmt, ## args) #define TRACE_DEBUG(cpu, fmt, args...) TRACE (cpu, TRACE_DEBUG_IDX, fmt, ## args) +#define TRACE_DISASM(cpu, addr) \ + do { \ + if (TRACE_DISASM_P (cpu)) \ + trace_disasm (CPU_STATE (cpu), cpu, addr); \ + } while (0) /* Tracing functions. */ @@ -313,6 +345,10 @@ extern void trace_generic (SIM_DESC sd, ...) __attribute__((format (printf, 4, 5))); +/* Disassemble the specified address. */ + +extern void trace_disasm (SIM_DESC sd, sim_cpu *cpu, address_word addr); + typedef enum { trace_fmt_invalid, trace_fmt_word, -- 2.30.2