pspemu (annex I) : dynarec debugging

21 Apr 2010

Since I started with dynamic recompilation, a couple of persons have asked me “how can I debug that”.

To debug it I’m using a disassembler, as expected. I recommend you IDA’s demo, even if it is limited, it is enough to do this.

The idea is simple: stop the execution once you reach a dynamically generated block of code, and go step by step checking out if everything works as expected. To stop at that point, yo can do it manually, or do it as I’m doing right now for this case: I’m detecting if there is an attached debugger to the debugger, and if it is, I’m emitting interruption 3 just before starting the code block. Interruption 3 is a software breakpoint. The debugger stops there automatically, so we don’t need to know the address beforehand.

IsDebuggerPresent

if (addBreakPointWhenStart && (PC == StartPC)) {  
    if (IsDebuggerPresent()) emiter.INT3(); // Debugger  
    emiter.MOV(Register32.EDX, PC); // Just for debugging.  
}  

This allows me to use the same executable (without the need of recompiling) to be able to debug. The bad part is that the interruption happens on all the native blocks. At this point is what I want, but eventually I will want only to place breakpoints with the debugger I want to do. Once the debugger is ready, in order to stop the execution in a specific place, it would be enough to replace the instruction where we want to stop the code. But before we should store the bytes we are replacing, so we can restore them once the execution is resumed.

.text  

;loop_test:  
;j loop_test  

li t0, 128  

loop_color:  
    li a0, 0x04000000  
    li a1, 0x88000  
    loop_write:  
        addiu a0, a0, 1  
        addiu a1, a1, -1  
        sb t0, 0(a0)  
    bne a1, zr, loop_write  
    nop  
    addi t0, t0, 1  
    syscall 0x2147 ; sceDisplay.sceDisplayWaitVblankStart  
j loop_color  
nop