From 8d052926671eb0e8c83ffab6d15a98790c215a36 Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Fri, 14 Mar 2014 15:21:23 +0000 Subject: [PATCH] Add support for instruction level tracing to the ARM simulator. * wrapper.c (op_print): New function. (sim_dis_read): New function. (print_insn): New function - disassembles the given instruction. (sim_trace): Note that tracing is now allowed. (sim_create_inferior): Default to emulating v6. Initialise the disassembler machinery. (sim_target_parse_command_line): Add support for -t -d and -z options. (sim_target_display_usage): Note existence of -d and -z options. (sim_open): Parse -t -d and -z options. * armemu.h: Add exports of trace, disas and trace_funcs. Add prototype for print_insn. * armemu.c (ARMul_Emulate26): Add tracing code. Delete unused variables. * thumbemu (handle_v6_thumb_insn): Delete unused variable Rd. Move Rm variable into switch cases. Add tracing code. * armcopro.c (XScale_cp15_init): Add a return value. (XScale_cp13_init): Likewise. (XScale_cp14_init): Likewise. (XScale_cp15_LDC): Delete unused function. (XScale_cp15_STC): Likewise. * maverick.c: Delete comment inside comment. (DSPInit): Delete unused function. (DSPMCR4): Fix compile time warning about missing parenthesis. (DSPMCR5): Likewise. (DSPCDP6): Delete unused variable opcode2. --- sim/arm/ChangeLog | 31 ++++++++++++++ sim/arm/armcopro.c | 34 +++------------ sim/arm/armemu.c | 53 ++++++++++++++++------- sim/arm/armemu.h | 8 ++++ sim/arm/maverick.c | 23 ++++------ sim/arm/thumbemu.c | 70 ++++++++++++++++++++----------- sim/arm/wrapper.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++++----- 7 files changed, 245 insertions(+), 94 deletions(-) diff --git a/sim/arm/ChangeLog b/sim/arm/ChangeLog index fe236cb..89f0531 100644 --- a/sim/arm/ChangeLog +++ b/sim/arm/ChangeLog @@ -1,3 +1,34 @@ +2014-03-14 Nick Clifton + + * wrapper.c (op_print): New function. + (sim_dis_read): New function. + (print_insn): New function - disassembles the given instruction. + (sim_trace): Note that tracing is now allowed. + (sim_create_inferior): Default to emulating v6. + Initialise the disassembler machinery. + (sim_target_parse_command_line): Add support for -t -d and -z + options. + (sim_target_display_usage): Note existence of -d and -z options. + (sim_open): Parse -t -d and -z options. + * armemu.h: Add exports of trace, disas and trace_funcs. + Add prototype for print_insn. + * armemu.c (ARMul_Emulate26): Add tracing code. + Delete unused variables. + * thumbemu (handle_v6_thumb_insn): Delete unused variable Rd. + Move Rm variable into switch cases. + Add tracing code. + + * armcopro.c (XScale_cp15_init): Add a return value. + (XScale_cp13_init): Likewise. + (XScale_cp14_init): Likewise. + (XScale_cp15_LDC): Delete unused function. + (XScale_cp15_STC): Likewise. + * maverick.c: Delete comment inside comment. + (DSPInit): Delete unused function. + (DSPMCR4): Fix compile time warning about missing parenthesis. + (DSPMCR5): Likewise. + (DSPCDP6): Delete unused variable opcode2. + 2014-03-14 David McQuillan PR sim/8388 diff --git a/sim/arm/armcopro.c b/sim/arm/armcopro.c index 8194b31..4c5da24 100644 --- a/sim/arm/armcopro.c +++ b/sim/arm/armcopro.c @@ -85,6 +85,8 @@ XScale_cp15_init (ARMul_State * state ATTRIBUTE_UNUSED) /* Initialise the ARM Control Register. */ XScale_cp15_opcode_2_is_0_Regs[1] = 0x00000078; + + return TRUE; } /* Check an access to a register. */ @@ -371,34 +373,6 @@ read_cp15_reg (unsigned reg, unsigned opcode_2, unsigned CRm) } static unsigned -XScale_cp15_LDC (ARMul_State * state, unsigned type, ARMword instr, ARMword data) -{ - unsigned reg = BITS (12, 15); - unsigned result; - - result = check_cp15_access (state, reg, 0, 0, 0); - - if (result == ARMul_DONE && type == ARMul_DATA) - write_cp15_reg (state, reg, 0, 0, data); - - return result; -} - -static unsigned -XScale_cp15_STC (ARMul_State * state, unsigned type, ARMword instr, ARMword * data) -{ - unsigned reg = BITS (12, 15); - unsigned result; - - result = check_cp15_access (state, reg, 0, 0, 0); - - if (result == ARMul_DONE && type == ARMul_DATA) - * data = read_cp15_reg (reg, 0, 0); - - return result; -} - -static unsigned XScale_cp15_MRC (ARMul_State * state, unsigned type ATTRIBUTE_UNUSED, ARMword instr, @@ -582,6 +556,8 @@ XScale_cp13_init (ARMul_State * state ATTRIBUTE_UNUSED) XScale_cp13_CR0_Regs[i] = 0; XScale_cp13_CR1_Regs[i] = 0; } + + return TRUE; } /* Check an access to a register. */ @@ -812,6 +788,8 @@ XScale_cp14_init (ARMul_State * state ATTRIBUTE_UNUSED) for (i = 16; i--;) XScale_cp14_Regs[i] = 0; + + return TRUE; } /* Check an access to a register. */ diff --git a/sim/arm/armemu.c b/sim/arm/armemu.c index 64c0146..d535a4e 100644 --- a/sim/arm/armemu.c +++ b/sim/arm/armemu.c @@ -1,7 +1,7 @@ /* armemu.c -- Main instruction emulation: ARM7 Instruction Emulator. Copyright (C) 1994 Advanced RISC Machines Ltd. Modifications to add arch. v4 support by . - + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or @@ -314,7 +314,7 @@ handle_v6_insn (ARMul_State * state, ARMword instr) { ARMword Rm; int ror = -1; - + switch (BITS (4, 11)) { case 0x07: ror = 0; break; @@ -580,11 +580,20 @@ ARMul_Emulate26 (ARMul_State * state) if (state->EventSet) ARMul_EnvokeEvent (state); -#if 0 /* Enable this for a helpful bit of debugging when tracing is needed. */ - fprintf (stderr, "pc: %x, instr: %x\n", pc & ~1, instr); - if (instr == 0) - abort (); -#endif + + if (! TFLAG && trace) + { + fprintf (stderr, "pc: %x, ", pc & ~1); + if (! disas) + fprintf (stderr, "instr: %x\n", instr); + } + + if (instr == 0 || pc < 0x10) + { + ARMul_Abort (state, ARMUndefinedInstrV); + state->Emulate = FALSE; + } + #if 0 /* Enable this code to help track down stack alignment bugs. */ { static ARMword old_sp = -1; @@ -628,8 +637,8 @@ ARMul_Emulate26 (ARMul_State * state) } if (state->Debug) { - fprintf (stderr, "sim: At %08lx Instr %08lx Mode %02lx\n", pc, instr, - state->Mode); + fprintf (stderr, "sim: At %08lx Instr %08lx Mode %02lx\n", + (long) pc, (long) instr, (long) state->Mode); (void) fgetc (stdin); } } @@ -667,6 +676,14 @@ ARMul_Emulate26 (ARMul_State * state) case t_decoded: /* ARM instruction available. */ + if (disas || trace) + { + fprintf (stderr, " emulate as: "); + if (trace) + fprintf (stderr, "%08x ", new); + if (! disas) + fprintf (stderr, "\n"); + } instr = new; /* So continue instruction decoding. */ break; @@ -675,6 +692,8 @@ ARMul_Emulate26 (ARMul_State * state) } } #endif + if (disas) + print_insn (instr); /* Check the condition codes. */ if ((temp = TOPBITS (28)) == AL) @@ -1654,7 +1673,6 @@ check_PMUintr: { if (BITS (4, 7) == 0x7) { - ARMword value; extern int SWI_vector_installed; /* Hardware is allowed to optionally override this @@ -1736,7 +1754,6 @@ check_PMUintr: ARMdword op1 = state->Reg[BITS (0, 3)]; ARMdword op2 = state->Reg[BITS (8, 11)]; ARMdword dest; - ARMdword result; if (BIT (5)) op1 >>= 16; @@ -1877,7 +1894,6 @@ check_PMUintr: /* ElSegundo SMULxy insn. */ ARMword op1 = state->Reg[BITS (0, 3)]; ARMword op2 = state->Reg[BITS (8, 11)]; - ARMword Rn = state->Reg[BITS (12, 15)]; if (BIT (5)) op1 >>= 16; @@ -3459,7 +3475,6 @@ check_PMUintr: FLUSHPIPE; break; - /* Branch and Link forward. */ case 0xb0: case 0xb1: @@ -3477,9 +3492,10 @@ check_PMUintr: #endif state->Reg[15] = pc + 8 + POSBRANCH; FLUSHPIPE; + if (trace_funcs) + fprintf (stderr, " pc changed to %x\n", state->Reg[15]); break; - /* Branch and Link backward. */ case 0xb8: case 0xb9: @@ -3497,9 +3513,10 @@ check_PMUintr: #endif state->Reg[15] = pc + 8 + NEGBRANCH; FLUSHPIPE; + if (trace_funcs) + fprintf (stderr, " pc changed to %x\n", state->Reg[15]); break; - /* Co-Processor Data Transfers. */ case 0xc4: if (state->is_v5) @@ -4150,6 +4167,8 @@ WriteR15 (ARMul_State * state, ARMword src) #endif FLUSHPIPE; + if (trace_funcs) + fprintf (stderr, " pc changed to %x\n", state->Reg[15]); } /* This routine handles writes to register 15 when the S bit is set. */ @@ -4187,6 +4206,8 @@ WriteSR15 (ARMul_State * state, ARMword src) ARMul_R15Altered (state); #endif FLUSHPIPE; + if (trace_funcs) + fprintf (stderr, " pc changed to %x\n", state->Reg[15]); } /* In machines capable of running in Thumb mode, BX, BLX, LDR and LDM @@ -4208,6 +4229,8 @@ WriteR15Branch (ARMul_State * state, ARMword src) state->Reg[15] = src & 0xfffffffc; } FLUSHPIPE; + if (trace_funcs) + fprintf (stderr, " pc changed to %x\n", state->Reg[15]); #else WriteR15 (state, src); #endif diff --git a/sim/arm/armemu.h b/sim/arm/armemu.h index d61c85a..419f799 100644 --- a/sim/arm/armemu.h +++ b/sim/arm/armemu.h @@ -15,6 +15,10 @@ along with this program; if not, see . */ extern ARMword isize; +extern int trace; +extern int disas; +extern int trace_funcs; +extern void print_insn (ARMword); /* Condition code values. */ #define EQ 0 @@ -46,6 +50,10 @@ extern ARMword isize; #define CBIT (1L << 29) #define VBIT (1L << 28) #define SBIT (1L << 27) +#define GE0 (1L << 16) +#define GE1 (1L << 17) +#define GE2 (1L << 18) +#define GE3 (1L << 19) #define IBIT (1L << 7) #define FBIT (1L << 6) #define IFBITS (3L << 6) diff --git a/sim/arm/maverick.c b/sim/arm/maverick.c index 2acf2b6..b9a6517 100644 --- a/sim/arm/maverick.c +++ b/sim/arm/maverick.c @@ -20,7 +20,7 @@ #include "ansidecl.h" #include "armemu.h" -/*#define CIRRUS_DEBUG 1 /**/ +/*#define CIRRUS_DEBUG 1 */ #if CIRRUS_DEBUG # define printfdbg printf #else @@ -97,13 +97,6 @@ cirrus_not_implemented (char * insn) exit (1); } -static unsigned -DSPInit (ARMul_State * state) -{ - ARMul_ConsolePrint (state, ", DSP present"); - return TRUE; -} - unsigned DSPMRC4 (ARMul_State * state ATTRIBUTE_UNUSED, unsigned type ATTRIBUTE_UNUSED, @@ -270,8 +263,9 @@ DSPMRC5 (ARMul_State * state ATTRIBUTE_UNUSED, v = SubOverflow (DSPregs[SRC1_REG].lower.i, DSPregs[SRC2_REG].lower.i, res); /* carry */ - c = (NEG (a) && POS (b) || - (NEG (a) && POS (res)) || (POS (b) && POS (res))); + c = (NEG (a) && POS (b)) + || (NEG (a) && POS (res)) + || (POS (b) && POS (res)); *value = (n << 31) | (z << 30) | (c << 29) | (v << 28); break; @@ -301,8 +295,9 @@ DSPMRC5 (ARMul_State * state ATTRIBUTE_UNUSED, v = ((NEG64 (a) && POS64 (b) && POS64 (res)) || (POS64 (a) && NEG64 (b) && NEG64 (res))); /* carry */ - c = (NEG64 (a) && POS64 (b) || - (NEG64 (a) && POS64 (res)) || (POS64 (b) && POS64 (res))); + c = (NEG64 (a) && POS64 (b)) + || (NEG64 (a) && POS64 (res)) + || (POS64 (b) && POS64 (res)); *value = (n << 31) | (z << 30) | (c << 29) | (v << 28); break; @@ -1167,10 +1162,6 @@ DSPCDP6 (ARMul_State * state, unsigned type, ARMword instr) { - int opcode2; - - opcode2 = BITS (5,7); - switch (BITS (20,21)) { case 0: diff --git a/sim/arm/thumbemu.c b/sim/arm/thumbemu.c index b8ef7df..e4c91f6 100644 --- a/sim/arm/thumbemu.c +++ b/sim/arm/thumbemu.c @@ -5,12 +5,12 @@ it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program; if not, see . */ @@ -38,9 +38,6 @@ handle_v6_thumb_insn (ARMul_State * state, ARMword tinstr, tdstate * pvalid) { - ARMword Rd; - ARMword Rm; - if (! state->is_v6) { * pvalid = t_undefined; @@ -56,33 +53,48 @@ handle_v6_thumb_insn (ARMul_State * state, case 0xba40: /* rev16 */ case 0xbac0: /* revsh */ case 0xb650: /* setend */ - default: + default: printf ("Unhandled v6 thumb insn: %04x\n", tinstr); * pvalid = t_undefined; return; case 0xb200: /* sxth */ - Rm = state->Reg [(tinstr & 0x38) >> 3]; - if (Rm & 0x8000) - state->Reg [(tinstr & 0x7)] = (Rm & 0xffff) | 0xffff0000; - else - state->Reg [(tinstr & 0x7)] = Rm & 0xffff; - break; + { + ARMword Rm = state->Reg [(tinstr & 0x38) >> 3]; + + if (Rm & 0x8000) + state->Reg [(tinstr & 0x7)] = (Rm & 0xffff) | 0xffff0000; + else + state->Reg [(tinstr & 0x7)] = Rm & 0xffff; + break; + } + case 0xb240: /* sxtb */ - Rm = state->Reg [(tinstr & 0x38) >> 3]; - if (Rm & 0x80) - state->Reg [(tinstr & 0x7)] = (Rm & 0xff) | 0xffffff00; - else - state->Reg [(tinstr & 0x7)] = Rm & 0xff; - break; + { + ARMword Rm = state->Reg [(tinstr & 0x38) >> 3]; + + if (Rm & 0x80) + state->Reg [(tinstr & 0x7)] = (Rm & 0xff) | 0xffffff00; + else + state->Reg [(tinstr & 0x7)] = Rm & 0xff; + break; + } + case 0xb280: /* uxth */ - Rm = state->Reg [(tinstr & 0x38) >> 3]; - state->Reg [(tinstr & 0x7)] = Rm & 0xffff; - break; + { + ARMword Rm = state->Reg [(tinstr & 0x38) >> 3]; + + state->Reg [(tinstr & 0x7)] = Rm & 0xffff; + break; + } + case 0xb2c0: /* uxtb */ - Rm = state->Reg [(tinstr & 0x38) >> 3]; - state->Reg [(tinstr & 0x7)] = Rm & 0xff; - break; + { + ARMword Rm = state->Reg [(tinstr & 0x38) >> 3]; + + state->Reg [(tinstr & 0x7)] = Rm & 0xff; + break; + } } /* Indicate that the instruction has been processed. */ * pvalid = t_branch; @@ -113,6 +125,9 @@ ARMul_ThumbDecode (ARMul_State * state, tinstr &= 0xFFFF; } + if (trace) + fprintf (stderr, "pc: %x, Thumb instr: %x", pc & ~1, tinstr); + #if 1 /* debugging to catch non updates */ *ainstr = 0xDEADC0DE; #endif @@ -413,7 +428,7 @@ ARMul_ThumbDecode (ARMul_State * state, case 0x0e00: if (state->is_v5) { - /* This is normally an undefined instruction. The v5t architecture + /* This is normally an undefined instruction. The v5t architecture defines this particular pattern as a BKPT instruction, for hardware assisted debugging. We map onto the arm BKPT instruction. */ @@ -550,6 +565,8 @@ ARMul_ThumbDecode (ARMul_State * state, state->Reg[14] = (tmp | 1); valid = t_branch; FLUSHPIPE; + if (trace_funcs) + fprintf (stderr, " pc changed to %x\n", state->Reg[15]); break; } } @@ -610,5 +627,8 @@ ARMul_ThumbDecode (ARMul_State * state, break; } + if (trace && valid != t_decoded) + fprintf (stderr, "\n"); + return valid; } diff --git a/sim/arm/wrapper.c b/sim/arm/wrapper.c index 064962b..228cbc8 100644 --- a/sim/arm/wrapper.c +++ b/sim/arm/wrapper.c @@ -37,6 +37,7 @@ #include "gdb/sim-arm.h" #include "gdb/signals.h" #include "libiberty.h" +#include "iwmmxt.h" host_callback *sim_callback; @@ -59,6 +60,54 @@ static int big_endian; int stop_simulator; +#include "dis-asm.h" + +int trace = 0; +int disas = 0; +int trace_funcs = 0; + +static struct disassemble_info info; +static char opbuf[1000]; + +static int +op_printf (char *buf, char *fmt, ...) +{ + int ret; + va_list ap; + + va_start (ap, fmt); + ret = vsprintf (opbuf + strlen (opbuf), fmt, ap); + va_end (ap); + return ret; +} + +static int +sim_dis_read (bfd_vma memaddr ATTRIBUTE_UNUSED, + bfd_byte * ptr, + unsigned int length, + struct disassemble_info * info) +{ + ARMword val = (ARMword) *((ARMword *) info->application_data); + + while (length--) + { + * ptr ++ = val & 0xFF; + val >>= 8; + } + return 0; +} + +void +print_insn (ARMword instr) +{ + int size; + + opbuf[0] = 0; + info.application_data = & instr; + size = print_insn_little_arm (0, & info); + fprintf (stderr, " %*s\n", size, opbuf); +} + /* Cirrus DSP registers. We need to define these registers outside of maverick.c because @@ -192,10 +241,9 @@ sim_read (sd, addr, buffer, size) int sim_trace (sd) SIM_DESC sd ATTRIBUTE_UNUSED; -{ - (*sim_callback->printf_filtered) - (sim_callback, - "This simulator does not support tracing\n"); +{ + trace = 1; + sim_resume (sd, 0, 0); return 1; } @@ -269,9 +317,9 @@ sim_create_inferior (sd, abfd, argv, env) /* We wouldn't set the machine type with earlier toolchains, so we explicitly select a processor capable of supporting all ARMs in 32bit mode. */ - /* We choose the XScale rather than the iWMMXt, because the iWMMXt - removes the FPE emulator, since it conflicts with its coprocessors. - For the most generic ARM support, we want the FPE emulator in place. */ + ARMul_SelectProcessor (state, ARM_v5_Prop | ARM_v5e_Prop | ARM_v6_Prop); + break; + case bfd_mach_arm_XScale: ARMul_SelectProcessor (state, ARM_v5_Prop | ARM_v5e_Prop | ARM_XScale_Prop | ARM_v6_Prop); break; @@ -351,6 +399,16 @@ sim_create_inferior (sd, abfd, argv, env) ARMul_SetCPSR (state, SVC32MODE); } + memset (& info, 0, sizeof (info)); + INIT_DISASSEMBLE_INFO (info, stdout, op_printf); + info.read_memory_func = sim_dis_read; + info.arch = bfd_get_arch (abfd); + info.mach = bfd_get_mach (abfd); + info.endian_code = BFD_ENDIAN_LITTLE; + if (info.mach == 0) + info.arch = bfd_arch_arm; + disassemble_init_for_target (& info); + if (argv != NULL) { /* Set up the command line by laboriously stringing together @@ -676,8 +734,6 @@ sim_fetch_register (sd, rn, memory, length) return length; } -#ifdef SIM_TARGET_SWITCHES - static void sim_target_parse_arg_array (char **); typedef struct @@ -718,6 +774,34 @@ sim_target_parse_command_line (argc, argv) if ((ptr == NULL) || (* ptr != '-')) break; + if (strcmp (ptr, "-t") == 0) + { + trace = 1; + continue; + } + + if (strcmp (ptr, "-z") == 0) + { + /* Remove this option from the argv array. */ + for (arg = i; arg < argc; arg ++) + argv[arg] = argv[arg + 1]; + argc --; + i --; + trace_funcs = 1; + continue; + } + + if (strcmp (ptr, "-d") == 0) + { + /* Remove this option from the argv array. */ + for (arg = i; arg < argc; arg ++) + argv[arg] = argv[arg + 1]; + argc --; + i --; + disas = 1; + continue; + } + if (strncmp (ptr, SWI_SWITCH, sizeof SWI_SWITCH - 1) != 0) continue; @@ -789,8 +873,9 @@ sim_target_display_usage (help) fprintf (stream, "%s= Comma seperated list of SWI protocols to supoport.\n\ This list can contain: NONE, DEMON, ANGEL, REDBOOT and/or ALL.\n", SWI_SWITCH); + fprintf (stream, "-d\t\tEnable disassembly of instructions during tracing.\n"); + fprintf (stream, "-z\t\tTrace entering and leaving functions.\n\n"); } -#endif SIM_DESC sim_open (kind, ptr, abfd, argv) @@ -853,6 +938,21 @@ sim_open (kind, ptr, abfd, argv) break; } } + else if (argv[i][0] == '-' && argv[i][1] == 't') + { + trace = 1; + break; + } + else if (argv[i][0] == '-' && argv[i][1] == 'z') + { + trace_funcs = 1; + break; + } + else if (argv[i][0] == '-' && argv[i][1] == 'd') + { + disas = 1; + break; + } else if (argv[i][0] == '-' && argv[i][1] == 'm') { if (argv[i][2] != '\0') -- 2.7.4