Saturday, January 1, 2011

How I Debug Wii Homebrew Crashes

I get a lot of e-mails from people asking me how I debug Wii crashes in my Wii homebrew. After just responding to yet another one I figured it was time for a brief writeup. Before beginning though I want to make it clear that there are many methods that can be used to debug your Wii homebrew. Depending on the situation mine may not be the best for you. Mine is only useful for finding the cause of a crash.

I have a really poor TV that I can't clearly read crashes off of. In order to counter this I use a USB Gecko device which outputs crash information to a serial connection I form with it. This way I'm not doing any guesswork and I know my results will be accurate. However, if you have a TV which you can read text clearly off of, a USB Gecko is not required to debug homebrew using my methodology.


When I debug my Wii homrbrew the first step is getting a crash to occur which I can see. It will usually look something like this:

        Exception (DSI) occurred!
        GPR00 0000000D GPR08 00000000 GPR16 800F67CC GPR24 80140520
        GPR01 804E0980 GPR09 0025AB84 GPR17 80147C64 GPR25 804E09C8
        GPR02 8011F320 GPR10 00000000 GPR18 8014005C GPR26 80140000
        GPR03 00000000 GPR11 80140000 GPR19 80140610 GPR27 80147C58
        GPR04 80415744 GPR12 44202028 GPR20 80485B80 GPR28 00000000
        GPR05 00000001 GPR13 8013FA80 GPR21 8014035C GPR29 00000000
        GPR06 8013DB14 GPR14 00000000 GPR22 80140368 GPR30 80140000
        GPR07 00000003 GPR15 80147C54 GPR23 80140520 GPR31 8011A664
        LR 8002D964 SRR0 8002d9e8 SRR1 0000b032 MSR 00001000
        DAR 0025AB85 DSISR 04000000


        STACK DUMP:
        8002d9e8 --> 8002d964 --> 800238d0 --> 8000cc08 -->
        80011878 --> 800154cc --> 80022824 --> 800851bc -->
        80004348


        CODE DUMP:
        8002d9e8:  88090001 540007BE 2F800002 419E07D4
        8002d9f8:  3817FFE0 3BA00001 2B80005F 419D0014
        8002da08:  3F608014 839B0768 2F9C0016 409D07BC

Not that, for your convenience, you can press RESET or A on gamecube controller you have plugged in on your Wii to return to your loader (which is probably the Homebrew Channel).

Next I initiate the devkitPPC tool addr2line. It only works with .elf files so for the sake of your own sanity the crash you use should have come from an .elf file. In my personal experience I've ran crashes from .dols against their .elf counterpart as well as crashes from .elfs and gotten the exact same results in some cases while in other cases the results couldn't be any more different. I lack the knowledge to articulate a technical explanation for this. So I'll just stick to strongly recommending you get your crash from an .elfso that you don't risk being thrown off into the wrong direction.

To initiate the tool along with the .elf I intend to debug I input this command in the Windows command prompt:

C:\devkitpro\devkitppc\bin\eabi-powerpc-addr2line -e C:\projects\wii\myproject\boot.elf

The command used in Linux and Mac operating systems should be similar. If anyone has it, I'll gladly add it to this post.

Afterward, I take the stack trace from the crash and I enter it into addr2line in reverse. So for the crash above I'll enter it in like this. I'll use [ENTER] to denote when I hit the enter key to input the stack trace to ensure absolute clarity.

80004348 [ENTER]
Receive feedback from addr2line
800851bc --> 80004348 [ENTER]
Receive feedback from addr2line
80022824 --> 800851bc --> 80004348 [ENTER]
Receive feedback from addr2line
800154cc --> 80022824 --> 800851bc --> 80004348 [ENTER]
Receive feedback from addr2line
80011878 --> 800154cc --> 80022824 --> 800851bc --> 80004348 [ENTER]
Receive feedback from addr2line
8000cc08 --> 80011878 --> 800154cc --> 80022824 --> 800851bc --> 80004348 [ENTER]
Receive feedback from addr2line
800238d0 --> 8000cc08 --> 80011878 --> 800154cc --> 80022824 --> 800851bc --> 80004348 [ENTER]
Receive feedback from addr2line
8002d964 --> 800238d0 --> 8000cc08 --> 80011878 --> 800154cc --> 80022824 --> 800851bc --> 80004348 [ENTER]
Receive feedback from addr2line
8002d9e8 --> 8002d964 --> 800238d0 --> 8000cc08 --> 80011878 --> 800154cc --> 80022824 --> 800851bc --> 80004348 [ENTER]
Receive feedback from addr2line

The feedback I receive from addr2line each time will either be a specific line in my source code which was last executed or it will be nothing at all. Generally I'll get about 3 to 5 lines of source code back from this. I've never been unsuccessful using this method and it's saved me countless hours trying to debug with printf().

Hopefully this post will help a fellow developer out. Thanks for reading.

2 comments:

  1. Is there something wrong with linking the debug stub and using GDB for interactive debugging?

    ReplyDelete
  2. Nope. This for finding the last lines ran which caused a crash, not step-by-step debugging. Personally I think this is faster but I have still broken down and used GDB many times. Note that I'm also not an avid Linux user so it might be why my first instinct is to avoid GDB.

    ReplyDelete