WiiRd forum

Wii & Gamecube Hacking => Wii Game hacking help => Topic started by: live2play on April 29, 2010, 12:29:12 AM

Title: LR=BP Address
Post by: live2play on April 29, 2010, 12:29:12 AM
I have, on several occassions, tracked a function back through all of the functions that call it and finally ended up at the bctrl that triggers the entire chain.  However, the bctrl is in the "main loop" and a breakpoint at its address will trigger immediately.  To get it to only trigger when the CTR address is the one I want, I set a condition of, for instance, r12=<address>.  This is great, but the problem is that after the BP triggers, I need to find out what in the main loop caused r12 to be the address that triggers the BP.  I know how to backtrack r12, but, eventually, I run into a dead end in the "main loop" as I am not able to determine who's calling me at that point because LR=the exact address on which I've set my current BP.  So, for instance, let's say that I backtracked to an mr r12, r3 in the main loop.  I know what r3 needs to be at that point so I can set a conditional r3=<address>.  However, once the BP triggers, LR equals the address of the mr r12, r3 on which I placed my BP.  Any ideas on how to keep backtracking to find the "decision" code that determines when the CTR (e.g. r3/r12) is going to be the address that triggers the chain that leads to the very first function from which I backtracked in the first place?  I hope this all makes sense.  :)
Title: Re: LR=BP Address
Post by: dcx2 on April 29, 2010, 05:09:07 AM
I have seen this bctrl that you're talking about.  I think it's kinda like a Windows message pump.

As far as I know, there's only two ways to write to the LR.  Either a branch that links (bl, bctrl, beql, etc), or a mtlr.  Branch-and-Link always load LR with the address of the *next* instruction, so look at the instruction immediately before mr r12,r3 for some type of linking branch.  This is consistent with the function call specification for the PowerPC, which uses r3 and r4 to get values back from a function call (also used to pass parameters into functions).

You can't just look at the LR where your breakpoint hits, because there may have been other linking branches inbetween the prologue and your breakpoint, and those other linking branches will overwrite the LR you want.  In order to walk the call stack, you should find the function prologue (stwu/mflr) or epilogue (lwz/mtlr/blr).  The prologue and epilogue are responsible for pushing and popping the LR so that its value is not lost.

I generally prefer to find the prologue, but for a function with multiple callers this might not work so well.  In that case, the epilogue might be easier to find.  After hitting your breakpoint at the right time, Step until you hit the blr for the current function you're in (or, if you're using Gecko.NET you can just press Step Out and it will go in search of the blr for you).  Alternatively you could parse the stack frames to find where the prologue/epilogue stored the LR, but that might be a little bit too much black magic for right now.

EDIT: I had mtlr and mflr backwards.
Title: Re: LR=BP Address
Post by: live2play on April 29, 2010, 05:20:09 PM
Thanks for the suggestions.  It really does get difficult to swalk the stack once you're in the main loop and your BP has to have some kind of additional condition in order to get the values you're looking for.

Aslo, does Gecko.NET have the same game freeze when selecting Memory Viewer issue that WiiRD does sometimes?
Title: Re: LR=BP Address
Post by: dcx2 on April 29, 2010, 05:41:01 PM
I would guess that if you've walked all the way back to the main loop, you've probably walked past the asm you're looking for.

I don't understand what Memory Viewer freezing issue you're talking about.  The major freezes I ever saw in WiiRDGUI involved setting breakpoints too fast, or switching tabs after a breakpoint too fast, or re-applying C2 codes.  Gecko.NET solves those issues, but there appear to be a few oddities where it doesn't work, but WiiRDGUI does (Gecko.NET appears to have a problem applying codes which write to the 81XXXXXX range), and vice versa (sometimes Gecko.NET can connect when WiiRDGUI won't).  I don't have much time to chase down the bugs right now, but in a month or so I probably will pick up development again.
Title: Re: LR=BP Address
Post by: live2play on April 29, 2010, 05:46:31 PM
Actually, if I write ASM that looks for r12, which is being used to populate CTR, being equal to the address that starts the chain of function calls I backtracked and change it to the address that the main loop normally uses when r12 isn't that address, I get the desired effect in the game.  The issue is that another event in the game, loading a level, also uses the same r12 value that I'm trying to change and that causes the game to freeze.  So, once I'm in a level, I can button activate the r12 change, but I would have to remember to deactivate the hack whenever I enter a new level.  So, it's kind of a "dirty" code at this point.
Title: Re: LR=BP Address
Post by: dcx2 on April 29, 2010, 06:14:42 PM
Uh...I'm not quite sure I follow.  r12 should be many different values, depending on what the game is doing right now, which is why I liken it to a message pump.  I hypothesize that other code will "queue up" a series of function calls during a frame, and the main loop then digests this queue in the next frame. 

If you set an execute breakpoint on the mr r12, r3 with no conditions, r12 should be a wide variety of values.  So I don't think there's a "normal" r12 value.

So...you're looking for, say, r12==80123450.  That address marks the first call in a series of function calls.  You want to...prevent this series of calls from happening?  Or you want something different to happen when 80123450 should have been executed?  And when changing levels, r12 is also 80123450?

If you just want to prevent it from happening, instead of calling something else I would use a cmp/bne that replaces r12 with a pointer that goes directly to a blr.
Title: Re: LR=BP Address
Post by: live2play on April 29, 2010, 06:59:44 PM
I set the BP on the bctrl command.  Just before that command is a mtctr r12 command.  Because a BP on the bctrl instruction happended to be in the main loop, the BP would trigger immediately.  However, because I backtracked to that bctrl, I knew exactly what the CTR had to be in order for the program to branch to the long chain that eventually leads to my function from which I performed the backtrack.  Given this, I set the condition of r12=<chain_address>.  I then performed the action in the game that would lead to r12 eventually being equal to the address of the function that starts the chain.  While instructions were being skipped, I watched the value of CTR in the BP dialog.  I noticed that it remained at a particular address all the time until my condition hit.  So, in this specific portion of the main loop, CTR is always one value until the event occurs that causes it to change to the address of the function that begins the long chain.  My C2 code basically checks if r12 equals the address that starts the chain I backtracked (<chain_address>), and, if so, sets it to the address that is always in the CTR when I do not perform the action in the game that causes the branching to occur.  This works just fine as long as it is only activated once the level has already loaded.  If it is activated before, then the level load, which also causes r12 to be equal to <chain_address>, is not able to go down the chain I backtracked and, in turn, is not able to set up whatever is needed to load the level.
Title: Re: LR=BP Address
Post by: live2play on April 29, 2010, 09:23:04 PM
When you say the following, I'm assuming that the address of the blr should be the one for the function that the bctrl is in, right?  Also, given that r12 equals the same address when a level is entered as it is when I perform the specific action in the game, changing r12 to be the address of the blr probably won't fix the level load problem, right?

Quote from: dcx2 on April 29, 2010, 06:14:42 PM
If you just want to prevent it from happening, instead of calling something else I would use a cmp/bne that replaces r12 with a pointer that goes directly to a blr.
Title: Re: LR=BP Address
Post by: dcx2 on April 29, 2010, 09:30:21 PM
Any old blr will do, it doesn't matter which one.  A linking branch that goes directly to a blr might as well be a nop.

Also, it *might* not cause the freezing issue that you're seeing.  You were forcing the code to take a path that it might not be supposed to take when changing levels, instead of cutting the path short.
Title: Re: LR=BP Address
Post by: live2play on April 29, 2010, 10:41:44 PM
Would I set r12 to the address of the actual blr opcode or does it have to be set to the actual address that that blr references via the LR register?
Title: Re: LR=BP Address
Post by: dcx2 on April 29, 2010, 11:18:27 PM
You want to branch to the actual blr.  The address that the blr will branch to is the address immediately after the bctrl.  You most certainly do not want to bctrl to that instruction, because there will be no matching blr there.

However, you *could* use a non-linking branch to jump just after the bctrl, instead of rewriting r12 to point at a blr.
Title: Re: LR=BP Address
Post by: live2play on April 30, 2010, 12:35:21 AM
Makes sense.  Thanks!