Emulator Issues #10872
closedTwilight Princess weird reset crash
0%
Description
I talked a bit about this with JMC and booto, but forgot to make a proper issue report of it.
Game Name?
Wii versions of Twilight Princess.
What's the problem? Describe what went wrong.
A weird glitch was mentioned to me where if you soft reset the game from the home menu on a specific frame as you void out will crash the game after you try to load a save file. On Dolphin, the game will crash without even reaching the title screen.
What steps will reproduce the problem?
The glitch is a bit complicated to pull off from a fresh save file, so there's a save state for 5.0-6300 on the European version. Simply hit reset and the game will lock up.
Is there anything else that can help developers narrow down the issue?
https://drive.google.com/open?id=1jSEubUjoWoYEiBOE3p9-TBuS_DnIg5Jn
Contains ram dumps from Dolphin, a save state to recreate the issue on -6300 and a ram dump from where it crashes on console. This is probably too late to see what's going wrong on Dolphin's end, so I guess a ram dump would have to be done at the exact moment it would crash on Dolphin.
https://www.youtube.com/watch?v=GEy1g5G7Z9E
Here's a video of the crash on console.
I tried a variety of settings like toggling MMU among others, but nothing changes.
Files
Updated by sepalani about 6 years ago
- File NULL_i_data.png NULL_i_data.png added
- File stage_patch.png stage_patch.png added
- File RZDP01.zip.001 RZDP01.zip.001 added
- File RZDP01.zip.002 RZDP01.zip.002 added
- File RZDP01.zip.003 RZDP01.zip.003 added
- File RZDP01.zip.004 RZDP01.zip.004 added
- File RZDP01.zip.005 RZDP01.zip.005 added
- File RZDP01.zip.006 RZDP01.zip.006 added
I managed to trigger the issue using the provided savestate. When exiting the HOME menu it loads the stage properly. Otherwise, the game loads that same stage when pressing RESET as well (rather than loading the title screen) according the log.
To patch the stage, put a breakpoint where the PC is in the stage_patch.png screenshot (before the setStartStage call in the phase_1 function).
Then, go to the r4 address (available in the Register view, right click -> View Memory, then go) in the Memory view and patch:
- the stage name (@r4): Replace "F_SP121" with "F_SP102"
- the constants right after the stage name (@r4+0x8):
Constants (before)
0xFFFF01FF
0x0001001A
0x0000803E
0x953CFF00
Constants (after)
0x0064000A
0x0001001A
0x0000803E
0x953CFF00
Only the first line differs (@r4+0x8).
Regardless, the split zip archives contain the savestate after patching the game memory and reaching the title screen.
NULL_i_data.png is the call stack before the following error message which occurs while loading a save slot:
[ERROR]dStage_dt_c_decode: i_data is NULL
Updated by sepalani about 6 years ago
After diving into the code, this is what I found:
Starting the stage¶
The function responsible for starting a stage is dComIfG_play_c::setStartStage(dStage_startStage_c *)
, this one is called once when the phase_1
function is executed after pressing reset.
Setting the next stage¶
The function responsible for setting the next stage is dComIfGp_setNextStage(char const *, short, signed char, signed char, float, unsigned long, int, signed char, short, int, int)
and is called by dComIfG_changeOpeningScene(scene_class *, short)
.
Next stage setup after pressing RESET¶
In order to call dComIfG_changeOpeningScene
(which is called by dComIfG_resetToOpening(scene_class *)
), the following conditions have to be met:
In the dComIfG_resetToOpening(scene_class *)
function (dComIfG_changeOpeningScene
's caller)¶
r13 = 0x80525ea0
1. u32 ptr = *(r13-0x4E10) // @0x80521090 (value = 0x80537440)
u8 b = *(ptr + 0x10) // @0x80537440+0x10 (value = 0x00)
Condition: b == 0
2. u8 b = *(ptr + 0x11) // @0x80537440+0x11 (value = 0x00)
Condition: b == 0
3. u32 v = *(ptr) // @0x80537440+0x00 (value = 0x00000001)
// Set in mDoRst_resetCallBack(int, void *) m_Do_Reset.o
Condition: v != 0
4. u32 ptr2 = *(r13-0x4F00) // @0x80520FA0 (value = 0x805EE410)
u32 fadeout = *(ptr2+4) // @0x805EE410+4 (value = 0x00000001)
// Set in JUTFader::startFadeOut(int) JUtility.a JUTFader.o
Condition: fadeout != 2
In the dScnPly_Draw(dScnPly_c *) function (dComIfG_resetToOpening
's caller)¶
Condition: fopOvlpM_IsPeek() != true
When these 5 conditions are met, the dComIfG_changeOpeningScene
function is called. Regarding the normal behaviour, when RESET is pressed (either via the Wii button or the HOME menu) it sets the next stage to be "F_SP102", then calls dScnPly_Draw
a bunch of time to draw the fadeout animation and finally calls phase_1
. However, when the bug occurs, the next stage isn't set because those conditions aren't met, especially since fopOvlpM_IsPeek() == true
. Overwriting the return value allows to reach the title screen but won't produce the save slot loading glitch. Moreover, when the bug happens the next stage isn't set, so it reloads the previous one which is "F_SP121" and dScnPly_Draw
is never called again which is weird.
I'll investigate and try to find why. However, if it's a timing issue, the savestate might have saved the "bad" timing and might be useless to check if the issue has been fixed.
Updated by sepalani about 6 years ago
I tried to find a consistent setup to reproduce the glitch from the title screen savestate I provided and I realised that breakpoints or waiting too much won't trigger the glitch. The i_data = NULL mentioned in the debug message seems to be located on the heap, so I assume it's a memory corruption glitch. According to the memory breakpoints it could be either the DVD reading/writing to it or the game reloading a scene.
Either way, I don't know how accurate this is compared to the real console since it could behave differently. Could someone please reproduce the following steps when the glitch occurs on a real console (using the appropriate debugging tools):
Breakpoint setup¶
Put a breakpoint on 0x8001abf8 (mDoRst_resetCallBack)
When hit, put a breakpoint on:
- 0x802e637c (JUTReportConsole_f)
- 0x80009358 (OSReport_Error)
Then, resume the execution.
Debug messages¶
JUTReportConsole_f¶
When the JUTReportConsole_f's breakpoint is hit,
1. Extract the string located in memory based on r3 value
2. Count the number of "%" character in the string and extract the same number of register (starting at r4)
-> Example: if there are 2 "%" characters, write down the r4 and r5 values
-> (Optional) if the register value is an address, write down the string
r3 = 0x804076de ("Start StageName:RoomNo [%s:%d]")
r4 = 0x8047f628 ("F_SP121")
r5 = 0x00000001
3. Describe where and when the breakpoint is hit
Then, resume the execution.
OSReport_Error¶
Same as JUTReportConsole_f
Updated by PPLToast about 6 years ago
This can be closed, because I just got it to work on Dolphin the same as it does on console. Sepalani can confirm.
Sorry for wasting everyone's time.