Experimenting with the Shared Source DeviceEmulator's JIT compiler - tracing and debugging

There are some mechanisms built into the DeviceEmulator's JIT which can make debugging and tracing both the JIT and guest code fairly straightfoward.

 1)  Define LOGGING_ENABLED to 1 in include\emulator.h, to compile in debug logging in the JIT.  Several variables control logging:

- LogInstructionStart - begin logging once 'n' guest instructions have been executed

- the LogIf() macro specifies the conditions under which logging happens.  The expression "(Cpu.CPSR.Bits.Mode == UserModeValue && InstructionCount >= LogInstructionStart)" logs only instructions executed in usermode, and only after LogInstructionStart instructions have executed.  This is a handy trigger, as it filters out interrupt handlers.  JIT logging will dump the disassembled ARM opcodes and register state, showing you a single-step trace of your code as it runs.


2)  In cpus\arm\armcpu.cpp, edit g_fOptimizeCode to be 0/false instead of 1/true.  This disables cross-instruction optimizations such as the code that recognizes ARMFlushICacheLines and converts it to a no-op.  It also inserts a call to SingleStepHelper() between guest instructions, to poll for single-step requests from the hardware debugger interface.


3)  Write your own low-level debugger - create an instance of IDeviceEmulatorDebugger from another process, and you can read/write memory, read/write registers, break in, single-step, set breakpoints, etc.  This is the interface that the Platform Builder eXDI hardware debugger connects to.  See cpus\arm\debugger.cpp for the implementation of this interface - it's quite straightforward.


4)  If you are changing the JIT for some reason, and it stops working, open cpus\arm\armcpu.cpp and check out the comment block above "//#define GOOD_EMULATOR 1" - this feature allows you to run a known-good DeviceEmulator.exe and a known-bad DeviceEmulator.exe in lock-step with each other.  Each one steps forward by one guest instruction, then they compare results and if there is a difference, assert.  Please note that the two emulators quickly diverge if you enable guest hardware interrupts, as interrupt delivery is not slaved between the two emulators - timer interrupts will arrive at different times.