Basic ASM Code Debugging and Analysis for the Beginner Coder
#1
Basic ASM Code Debugging and Analysis for the Beginner Coder

Chapter 1: Intro

After learning how to make very basic ASM Codes, the beginner coder may have trouble progressing to a higher skill level. Analyzing other already made ASM codes is one of the best ways to improve your ASM coding skills. Dolphin comes with many features to assist you.



Chapter 2: Setting up Hot Keys & Info About Other Features

Hotkeys (keyboard button shortcuts) are very useful for quick debugging. Open up your Dolphin Emulator. Under Options, select Hotkey Settings.

[Image: options.png]

There's basically only 2 hotkeys that are useful for debugging. In the General tab, there is a Hotkey setting for 'Toggle Pause'.

[Image: togglepause.png]

Right click on the button for Toggle Pause to bring up the window to change its Hotkey configuration.

[Image: confighotkey.png]

Whenever you bring up the Configure Input window for a Hotkey, you can select from a list or just type it in the lower larger box. Click Apply, then OK to save changes.

For the next hotkey, go to the Debugging tab.

[Image: debugtabclick.png]

There is a hotkey setting for 'Step-In'. This is by far the most important feature of debugging anything in Dolphin, and you will be using this Hotkey a ton.

[Image: stepinto.png]

What is Step-In?

Step-In will force Dolphin to execute the next ASM Instruction and that's it, noting else. Step-In is usually called 'stepping' by coders. When a coder says 'step by step' the code, they want you to debug the code utilizing the Step-In feature of Dolphin. Stepping codes is very helpful, as it allows you to execute a code one instruction at a time at whatever pace you want.



Chapter 3: Understanding How the Gecko Code Handler implements ASM Codes into Memory

According to the Gecko Documentation HERE, ASM Codes (C2 type) have the name of 'Insert ASM'. This name is sort of misleading as it's impossible to insert within memory itself. What actually happens is this...

  1. At the code's address, a branch instruction (replacing the default instruction) is placed in by the code handler (a backwards branch). View the picture below...
  2. The backwards branch instruction jumps to the first instruction of the ASM code where the code's instructions are placed into memory by the code handler (codes are placed in memory usually around 0x800022xx thru 0x800023xx)
  3. The amount to jump for the backwards branch instruction itself is auto calculated by the code handler
  4. The code instructions are thus executed. After the last instruction of the code, a forward branch instruction (also auto added by the code handler) will automatically jump back to the address directly below/after the code's address, thus continuing the game's instructions. The amount of jump for the forward branch instruction is auto calculated by the code handler

For example let's take a look at the old historical version of the shared item code (PAL version, with 00 for the WW value) - https://mariokartwii.com/showthread.php?tid=111


Code:
C27BA164 00000002
38600000 90770020
60000000 00000000


At the address 807BA164 is a backwards branch instruction that will jump to where the code's contents reside in memory (where the code contents were dumped by the code handler). A C2 Insert ASM Code's Address (where this backwards branch instruction resides at) is called the Hook Address. So when another coder/dev mentions the term Hook Address, you now understand what they are referring to.

[Image: shareditemcodeview2.png]

To follow where any branch-type instruction leads to, right click on the instruction and choose Follow Branch.

The backwards branch leads to the ASM code's contents (first instruction of the code highlighted in blue).

[Image: lir3zero.png]

The following is the code's contents plus the forward branch instruction that will jump back to where the CPU execution came from to continue running the game.

Code:
Address    Instruction
80002348  li r3, 0
8000234C  stw r3, 0x0020 (r23)
80002350  nop
80002354  b => 0x807BA168

The '00000000' word of the assembled Shared Item code is read by the code handler and the code handler will know to replace it with a branch (to address below/after code's address) instruction after the last instruction of the Code.

If you follow the 'b => 0x807BA168', it will lead to the instruction highlighted in blue in the following pic...

[Image: lisaftershared.png]

As you can see the instruction highlighted in blue is the very next instruction below/after the Code's Address. Let's go back to the Dolphin's Code View of the Code itself but zoomed out just a bit.

[Image: c2codeview.png]

You will see there are other instructions nearby the code. In this tutorial, I have simply applied only the Shared Item Code via Dolphin's Cheat Manager and nothing else. Dolphin simulates the code being contained in a GCT file (like how codes are normally loaded to a real Wii via an SD card).

The nop at 80002334 is placed by the Gecko Code Handler. I haven't gone over the entire source of the Gecko code handler personally, so I'm not sure what the purpose of this nop is.

The next two instructions after that are both '(ill) 00d0code'. (ill) stands for illegal instruction. The (ill) is given to any word value in memory that would not assemble to a valid PowerPC instruction. Dolphin will slap the (ill) tag and then display the hex contents of that particular word value.

'00d0code 00d0code' is the Header of the GCT file. Every GCT file has this Header. The lfs instruction at 80002340 is not an lfs instruction, it is actually the 'C27BA164' part of the Shared Item Code. Dolphin is attempting to disassemble that word as a PowerPC instruction. The '(ill) 00000002' is what you would expect, it's the '00000002' part of the Shared Item code. Next 4 lines are the code contents plus the branch instruction to branch forward to the Address that is right below/after the Code's Address.

The psq_st instruction at 80002358 is the 1st half of the Final Terminator of the GCT file. The final terminator of a GCT file is 'F0000000 00000000. Any time there is a word of null in memory, Dolphin's Code View will simply place ' --- '. Hence why you see ' --- ' at 8000235C.

Understanding how C2 Codes get executed:
This is important to know if you haven't figured this out by now. C2 ASM Codes only get executed whenever its Hook Address gets executed by the CPU. They are NOT constantly executing every time the Code Handler itself is being executed. The amount of times different C2 codes gets executed within a specific time period varies so much as it's based on so many factors. For example, the Shared Item Code. It's Hook Address only gets executed whenever a player picks up a box. Some C2 ASM Codes may execute every frame, some only once per race, some only once during the booting of the game, it all depends.



Chapter 4. Debugging/Analyzing ASM Codes

First apply whatever C2 ASM code that you want to debug/analyze. If the code's Hook Address gets executed during the early booting stages of the Game, or is executed every frame, we need to adjust a Dolphin setting. If not, go ahead and launch your Game, and skip over the next paragraph.

At the top of the Dolphin main menu, click Options. Select 'Boot to Pause'. Now launch your Game. This will cause the game to halt when it executes its very first instruction.

Okay at this point your Game should be booted up as paused or running. Open up your Breakpoint tab/window. Set an Instruction Breakpoint using the value for the code's address. Remember to covert it from a C2XXXXXX to 80XXXXXX for a valid Mem80 Address.

Once the Breakpoint has been set, un-pause the emulation if it was paused if you've applied 'Boot to Pause'. If you didn't use Boot-to-Pause, do whatever action you need to do to make your Code execute (i.e. Shared Item Code would be executed from picking up an Item Box). If you did in fact use the Boot-to-Pause, simply resume the Emulation.

The Breakpoint should be hit and Dolphin will pause itself. Once that has occurred, take a look at the Code View. You will be at the code's address and you will see the backwards branch instruction that was mentioned earlier.

Remember the Hotkey you configured for Stepping (Step-in)? Use that hotkey to make the code execute one instruction at a time at whatever pace you like. When you execute the first instruction, the backwards branch instruction will be executed, and you will be at the beginning of the ASM code's instructions.

Things to note during stepping:
Whatever instruction highlighted in Green in Code View is the instruction that is GOING to execute. However, this is NOT true for any Memory Breakpoint hits! This is because Dolphin has no idea that the Memory BP was hit until after the responsible store/load instruction gets executed.

You can also take a look at the PC register in the Registers Tab/Window, that will also tell you what instruction is GOING to execute, but once again this does NOT apply on any Memory Breakpoint hit. PC register will function correctly once you step just one time after a Memory Breakpoint hit.

When you perform a Step-In, if a register gets modified from the stepped instruction, that register will turn red in color on the Registers tab/window. That red register will go back to black if it's not modified if you decide to step again.

FYI, on your first emulation pause after launching a game on Dolphin, any registers not zero will start off as red color. This is on any first-time emulation pause, regardless of how the pause occurred.



Chapter 5: More Tips

To quickly set an Instruction Breakpoint on an address, simply left click to the immediate left of the Address value in Code View. A grey dot will appear signaling an Instruction Breakpoint has been set for that particular address.

Need to quickly copy an address value? Right click on the address in Code View, select Copy Address.

You can also use this right-click method to quickly replace instructions. Right click on an address, you will see shortcuts to quickly replace the address's instruction with a nop or a blr. The nop feature can be really handy for beginner coders. You may not know what a blr is. If not, don't worry about that til you get to the point of learning about function calls. Or even better, use this guide on a code that has a blr instruction and analyze it to understand what it does.

You can also edit in any custom valid PowerPC instruction you want with the 'Replace Instruction' feature, but you will need to enter in the assembled form of the instruction (its hexadecimal word value). If you set in a custom instruction of any kind, or a quick nop/blr, you can use the 'Restore Instruction' feature to recover the address's original instruction.

Need to edit register values by hand? Easy to to do. Simply double click within any register you need to edit, and type in the custom value then hit Enter on your keyboard.

By the way, on the left side of the Code View is the call stack. It's a trace back of function calls. Once again, if you are a beginner coder, you don't need to worry about this as this deals with function calls.



Chapter 6: Intro to Exceptions

While stepping through your code, you may have ran into an incident where you've jumped to a weird spot in memory, but you have noticed the memory addresses do not start with '8', but instead with '0'.

You are currently on one of Broadway's Exception Routines. Whenever your code crashes, you will hit one of these Exception Routines. The true technical term for any crash is called an Exception.

Exceptions can happen for a variety of reasons, and knowing which particular Exception Routine you have landed on, can tell you a lot about what is wrong with your code.

First thing's first,you need a quick lesson on Virtual Memory vs Physical Memory. The standard Memory that you are already familiar with is called Virtual Memory. It's a representation of Physical Memory but incorporates what is called Cache. Don't worry about what Cache is, beginner's don't need to know that for ASM Codes.

Exception routines always execute in Physical Memory.

To convert a mem80/81 address form Virtual to Physical, simply change the leading '8' to '0'.
To convert a mem9 address from Virtual to Physical, simply change the leading '9' to '1'.
  • Example: 0x80345AB0 ---> 0x00345AB0
  • Example: 0x921C0008 ---> 0x121C0008
  • Example: 0x817FFFFF ---> 0x017FFFFF

There are a total of 13 Exception Routines that Broadway has implemented for Wii games. However for beginner debugging, we only need to go over 6.

-

DSI (0x00000300)
Storing/loading to/from an invalid memory address

External Interrupt (0x00000500)
Some piece of external hardware needs to temporarily halt normal operation of Broadway.

Alignment (0x00000600)
Effective Address of a stmw, lmw, or any floating point load/store instruction was not word aligned (divisible by 4).

Floating Point Unavailable (0x00000800)
Broadway currently not configured to run floating point instructions.

Decrementer (0x00000900)
When the Decrementer Register has completed decrementing. Basically there is a Timer that is always decrementing, once it hits below 0, this Exception will occur.

System Call (0x00000C00)
Whenever a 'sc' (system call) instruction is executed, Broadway will jump to the System Call Exception Routine. This routine contains cache-related tasks.

---

External Interrupt, Floating Point Unavailable, Decrementer, and System Call happen periodically which is normal. You may encounter these when stepping thru your codes.



Chapter 7: Setting Breakpoints in Exception Routines & srr0

If you are in a hurry and do not want to step thru all of your code but still want to be notified of any Exceptions, set Instruction Breakpoints on the following addresses before test running your code
  • 0x00000300
  • 0x00000600

These are physical addresses and must be entered in as such

If one of these Instruction BPs get triggered, there is really only one register you need to examine. And that is srr0. srr0 contains the address of the instruction that caused the Exception.

At this point, you can copy the address that's in srr0 and paste it into Code View. But there's an issue... You won't see anything listed in Code View.

That is because you are paused while Broadway is executing in Physical Memory. Thus, take your address that's in srr0, and change the leading '8' to a '0'. Plug that new address into Code View, and you should now see the instruction that is causing you a lot of trouble.



Chapter 8: Trying to Solve the cause of your Exception

DSI's are the most common type of Exceptions. If a DSI exception occurred, then the instruction located at srr0's address will be a load or a store instruction. Said load/store instruction has loaded/stored via an invalid memory address. Be sure to check the earlier parts of your code to find out why the Source Register of the load/store instruction contains a invalid memory address.

The #1 mistake by beginners for ending up with an invalid memory address is using r0 as a source register in an instruction that treats r0 as literal zero (i.e. stw) The following will show how easy this mistake can be made...

Code:
#Set r0 to 0x80000000
lis r0, 0x8000

#Store contents of r12 to 0x80001640
stw r12, 0x1640 (r0)

And boom a DSI exception has now occurred.

If an Alignment exception occurred, check any present stmw and lmw instructions. As a Beginner, working on stmw and lmw instructions can cause some issues as it is easy to forget the rule that any Effective Address must be divisible by 0x4. This should be an easy fix if you run into this.

NOTE: There are other exceptions that could occur (such as ISI 0x400 & Program 0x700), but the reasons for these exceptions are usually NOT something that can be triggered accidentally from Beginner ASM Coders.



Chapter 9. Stepping Issues in regards to Exceptions

As mentioned earlier, External Interrupt, Floating Point Unavailable, Decrementer, and System Call Exceptions may occur "randomly", and they may occur while you are stepping through a code. If such an event occurs, take the address in srr0 (do NOT convert it to physical in this case), add 4 to it, and place an Instruction BP on it. Press play on Dolphin Emulator, and in a split second, you should now be at srr0+4, ready to continue stepping through the code.

Another note is that if you are at an Exception Routine, you cannot simply step thru the 'rest of it', and think you will simply jump back to your code. Your Wii game will go through a multitude of other processes after the Exception Routine before even getting close to coming back to your code. Thus, once you are something such as a DSI exception, take a look at srr0, notch down some notes, and then close the game. Trying to resume a DSI (or Alignment) exception will just result in the game halting/freezing.



Chapter 10. Conclusion

As I always tell person after person, the best way to get better at coding, is to take other people's codes (that are a little above your own skill level) and analyze them on Dolphin. Set the Breakpoints, step by step necessary instructions, and take plenty of notes. Happy coding!
Reply


Messages In This Thread
Basic ASM Code Debugging and Analysis for the Beginner Coder - by Vega - 12-15-2019, 04:37 AM

Forum Jump:


Users browsing this thread: 1 Guest(s)