Dolphin, the GameCube and Wii emulator - Forums

Full Version: Setting a breakpoint BEFORE launching game?
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Pages: 1 2 3
I'd like to define a breakpoint in Dolphin before launching a game -- is it possible?

I'm writing a Gecko ASM code to hook on Waverace Blue Storm's VIConfigure function, which sets the video format before its splash screen appears.

My problem is the game appears to be taking a different code path depending on whether Dolphin launches the game for the very first time, vs using the "Emulation > Reset" function.

For some reason my Gecko code only works after I perform an "Emulation > Reset".   So I need to step through on the very first launch to see what's happening without using the "Emulation > Reset" function.   And the only way I can do that is if I can somehow tell Dolphin what breakpoint I want BEFORE hitting the Play button.

I've noticed when I save my breakpoint in Dolphin it adds "[BreakPoints] 80115afc nb" to the GameINI, but it still requires me to start the game, click "Breakpoints > Load" and then "Emulation > Reset". 

Is there something else I can add to the GameINI to get it to actually instantiate the breakpoint automatically on the very first game launch?  I've checked the GameINI wiki and couldn't find anything.

Here is the code, it's for patching viWidth inside the GXRenderModeObj passed to VIConfigure:

Code:
C2115afc 00000003    ; insert ASM at 0x80115AFC (VIConfigure's address)
38C00000 60C602C0    ; put 0x000002c0 (viWidth 704) in r6
B0C3000E 7C0802A6    ; put r6's low order bits (0x2c0) at 14 byte offset from addr in r3 (GXRenderModeObj); reinstate overridden 7C0802A6 instruction
60000000 00000000    ; no-op ; return
 

I've also tried just doing a plain write to the address in r3 where the GXRenderModeObj is stored and that also doesn't work either unless I do "Emulation > Reset".  The code for that one is:

Code:
2834142e 00000280    ; if 0x8034142e contains 0x0280
0634142e 00000002    ; write to 0x8034142e the following 2 bytes:
02c00000 00000000    ; 0x02c0
e0000000 80008000    ; end code


Another way I can get it to work is if I set the game to "[Core] ProgressiveScan = True", in which case the "Enable Progressive?" prompt is shown at the game's splash screen, which triggers VIConfigure when "Yes" is selected, and both codes work.  But I want this code to work without the user having to do that.   Heck, I can't even get that prompt screen to appear on one of my PC's without holding B button even though I've got "[Core] ProgressiveScan = True" so I wouldn't want to rely on it.     Codes are for the NTSC-U version.

Thanks
What about Options -> Boot to Pause? Doesn't that give enough time to set breakpoints before the game actually boots?
Or does this not work with resetting?
(03-04-2022, 06:54 PM)Leseratte10 Wrote: [ -> ]What about Options -> Boot to Pause? Doesn't that give enough time to set breakpoints before the game actually boots?
Or does this not work with resetting?

Thank you, can't believe I missed that Rolleyes 

And yes it appears to work properly as it pauses on the "entry point" instruction (in the case of Wave Race, 0x80003100 according to Readdol app).
So looking at the memory contents using "boot to pause" for both codes, it appears Gecko code handler isn't getting a chance to do anything before the splash screen appears on the very first boot of the game, as the memory contents are unchanged.

After the splash screen, or after an Emulation > Reset, Gecko code works and memory contents are changed.  However by then it is too late as I already missed the opportunity to patch VIConfigure.

I thought maybe it was a Gecko issue but I ported the second code to Action Replay and it has the same issue -- memory contents are patched only after the splash screen -- too late.

Code:
; Action Replay
0C34142E 028001E0    ; if addr 8034142e contains 028001e0
0434142E 02C001E0    ; write 02c001e0 to addr 8034142e
Even using Dolphin's own "Patches" tab in the GameINI, it still patches it too late.
Trying to think of a solution to work around the problem.  It seems I need to force another call to VIConfigure, something like:


1. Modify GXRenderModeObj->viWidth by changing 0280 to 02C0 at address 8034142e.

2. Set register 3 to the starting address of modified GXRenderModeObj (80341420).  This is VIConfigure's one and only function parameter.

3. Call VIConfigure at 80115afc.


I can do 1 and 2, but I don't know how to do 3.

It seems I would want to use a branch instruction, but that is relative to the current address, and I don't know what that is when Gecko finishes doing 2.

I tried pasting the entire VIConfigure function as Gecko assembly, but it didn't work.  I'm guessing VIConfigure itself contains some relative branches outside of itself which would be wrong destinations if they're not being executed from the same location as the original?
If you know where in the code a VI call would work, inject PPC code using gecko to route it to VIConfigure. You may need to make a variable to only route it once.

https://github.com/TheGag96/CodeWrite
(03-05-2022, 03:14 AM)Modception Wrote: [ -> ]If you know where in the code a VI call would work, inject PPC code using gecko to route it to VIConfigure. You may need to make a variable to only route it once.

https://github.com/TheGag96/CodeWrite

Thanks, I just got CodeWrite the other day -- very helpful.

After spending some time on this, I'm not sure it's possible to arbitrarily jump to other functions without preserving the call stack and link register, and possibly other registers too.   Otherwise it seems I just end up in an infinite loop or in wrong memory area due to code executing in the wrong order which the compiler didn't design it to do.

eg. I modified another unnecessary GX function's prologue to bl (branch and link) to VIConfigure.  Stepping through shows this happens, but then at the end of VIConfigure there is a blr instruction which returns to the function which called my modified function and the whole thing repeats for infinity.    I was expecting it to return to the next instruction after the bl in my modified function.   I guess the link register is still pointing to the start of my modified function?   I'm not sure how to solve that; Gecko seems to have set pointer address  but I've no idea how it works.

Also tried in GameINI:



Code:
[OnLoad]
$AspectFix
0x8034142E:word:0x000002C0
[OnLoad_Enabled]
$AspectFix

[OnFrame]
$AspectFix
0x8034142E:word:0x000002C0
[OnFrame_Enabled]
$AspectFix

The [OnLoad] one doesn't work at all -- memory contents unchanged.

The [OnFrame] one does work, but again does it too late after VIConfigure has already been called.

In the end I'll just patch the dol inside the ISO which works.
Even if I restore the call stack and my two modified registers to their original state before branching back to where my modified function normally returns to, the game still ends up branching to an area it shouldn't be and crashes (goes into an infinite nop loop).

So I think the whole system state needs to be immaculately preserved in order to do this kind of arbitrary branching to other functions.

This leaves me confused about how the compiler even knows how to put everything together in such a way that the game can call functions arbitrarily at any point in the game.  I guess it's all deterministic but I still can't get my head around it.   

Tried the C0 code as well:

https://mariokartwii.com/showthread.php?tid=434&pid=1287#pid1287' Wrote: [ -> ]C0 codes are executed before the game's RAM


But Gecko still doesn't get its foot in the door until after the game has already called VIConfigure.

Well, at least the code works for the 480p mode.  Alternatively, user can patch the iso with something like GCR or WIT.   So it's still possible to fix, just would have been nice to do it in a code.   Or in Dolphin directly ¹

Another possibility might be simply forcing a game reset with a code, since that works if issued by Dolphin.  Is it possible?
I'm fairly certain gecko runs inline with the game's code, so the game code has to be running before gecko can do stuff. How soon gecko can do stuff might depend on the hook method, which can't be set. I've never actually jumped around code blocks, so my advice may have been bad.

I feel like the people who do aspect ratio fixes should know how to do this.

This is a crazy question, but what happens if you branch back to the first instruction the game is at when it loads (pause on start). Also, I think the correct way to do a code branch (if there even is one) is to do a normal branch over a blr command, then the next blr should send you to the location the replaced blr pointed to.
Pages: 1 2 3