USB Debugging Gamecube/Wii Code with devkitPro on Mac OS

January 31, 2021 —

In an effort to find things to do to take my mind off of the current state of the world and my bouts of depression, I recently re-visited Gamecube/Wii development stuff for a small-ish project that had been brewing in the back of my mind over the past months.

The excellent devkitPro "homebrew" SDK is the go-to for doing this kind of thing. I've been using devkitPro since 2006 or 2007, first starting with Nintendo DS development. I toyed around with the Gamecube/Wii side of it also, but never dug too deep into it. I'm very thankful that I did at least dig into it a bit back then, as that led me to buying a USB Gecko at the time, which is an incredibly valuable piece of hardware for anyone interested in Gamecube/Wii development.

As I said, I'm really glad that past-me picked one of these up in 2007, as they are basically impossible to find now. There was a recent effort by someone who built some more and sold a few more a couple years ago, but that isn't happening anymore from the looks of it.

To make use of this you simply plug the USB Gecko into one of the memory card slots in your Gamecube or Wii (usually, you use the second slot, most homebrew that is USB Gecko-aware assumes the second slot is being used), and connect to your computer via USB. The USB Gecko uses an FTDI FT245RL chip, which provides pretty standard USB-to-serial support and is well supported these days (a lot of Arduino stuff uses very similar, if not identical, hardware for example).

The USB Gecko has two primary developer features:

  • Load code from your computer to the console via USB. Stuff like the Homebrew Channel for the Wii has support for this, as well as some Gamecube mod chips and other homebrew software.
  • Debug code running on your Gamecube/Wii through a remote GDB connection.

Conveniently, devkitPro ships with a tool called wiiload which handles uploading binaries to your Gamecube/Wii via the USB Gecko. It also supports sending code via network, so it's still a very useful tool to any developers who do not own a USB Gecko.

As far as debugging code with a USB Gecko goes, on the software side, libogc has a GDB stub included, which you can include in your code and then, somewhere during your program startup, run:

DEBUG_Init(GDBSTUB_DEVICE_USB, 1);

Afterwards you need to add _break() calls in your code, which will trigger a breakpoint. Execution will halt at a _break() if GDB has not been connected remotely yet, so this gives you time to set up the connection after deploying a new build.

More information about remote debugging with devkitPro can be found in this wiki article.

This process all worked pretty wonderfully back in 2007/2008 for me (on Linux), as well as back in 2016 (on Mac OS and Linux) when I was working on a port of Chocolate Doom to the Wii.

However, at some point over the past few years the situation changed.

Problem #1: FTDI Driver on Mac OS

The FTDI VCP (Virtual COM Port) drivers for Mac OS have some problems with Catalina and Big Sur.

Mac OS has, for a long while now (I think?), provided Apple's own "AppleUSBFTDI" driver which does seem to work out-of-the-box for FTDI devices, but FTDI also provides its own "FTDIUSBSerialDriver" which usually provides better support. However, with Catalina, Apple changed the way that kernel extensions work apparently, and there are now issues installing the FTDI VCP driver.

FTDI seems to be really dragging their feet on providing a resolution for this, so in the meantime, my not-perfect solution was to disable SIP (yes, yes, this is bad, I hear you) which allows the FTDI VCP driver that needs to be re-signed to be installed and useable with SIP disabled. This is obviously not ideal, and I am eagerly awaiting the day FTDI provides an updated driver.

Problem #2: GDB's Remote Debugging via Serial Support Is Broken?

This is the bigger problem, and hard for me to pin down exactly. I've come across a couple very vague references to this (for example), usually in relation to devkitPro specifically and never with any resolution or explanation of what is causing the problem. So, I am unsure what is actually causing the problem ... could be an issue in the libogc GDB stub, or it could be a problem in GDB itself.

My own investigation has revealed that remote debugging with GDB via a USB Gecko specifically (I do not have anything else that I can test remote debugging via serial connection with) is broken after GDB version 7.7.1. I tested other later versions of 7.x (7.8, 7.10, 7.12), as well as a couple 8.x versions and of course, 9.x versions which devkitPro currently includes, and they all fail to establish a remote connection.

From my testing, this also is the case on Linux, so it is not just a Mac OS issue.

With GDB 9.2:

$ ./powerpc-eabi-gdb
GNU gdb (GDB) 9.2
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "--host=x86_64-apple-darwin15 --target=powerpc-eabi".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word".
(gdb) target remote /dev/cu.usbserial-GECKUSB0
Remote debugging using /dev/cu.usbserial-GECKUSB0
../../gdb/inferior.c:283: internal-error: struct inferior *find_inferior_pid(int): Assertion `pid != 0' failed.
A problem internal to GDB has been detected,
further debugging may prove unreliable.
Quit this debugging session? (y or n) 

For me, using /dev/tty.usbserial-GECKUSB0 instead either just results in no output and eventually the connection times out, or I get a /dev/tty.usbserial-GECKUSB0: Resource busy. message (which, is why using /dev/cu.usbserial-GECKUSB0 is probably better if my poor understanding of the differences between those two device types is correct). Either way, it doesn't ever work.

With GDB 7.7.1 however:

$ ./powerpc-eabi-gdb
GNU gdb (GDB) 7.7.1
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=x86_64-apple-darwin18.7.0 --target=powerpc-eabi".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word".
(gdb) target remote /dev/cu.usbserial-GECKUSB0
Remote debugging using /dev/cu.usbserial-GECKUSB0
0x800069c4 in ?? ()
(gdb) 

And then basically everything works from that point.

So, ideally, we should all be striving to use up to date tools whenever we can. However, this issue currently doesn't seem to have any resolution and has been known for at least a few years at this point. As a result, since this older version of GDB still works well enough and isn't that old (despite the copyright notice above, version 7.7.1 was released in January 2017, so it's not "ancient" yet), my not-perfect solution here is just to use the old version until some sort of better fix for this problem is available.

However! Back in 2017 or 2018, devkitPro annoyingly switched to using a package manager to distribute their SDKs, tools, libraries, etc as well as provided a more streamlined process of providing updates (once you have the package manager installed and configured that is). Even before this, when downloads were being provided via their Sourceforce project page, they didn't really keep old versions around. So switching to an older version is difficult at best.

Someone took it upon themselves to provide older versions of devkitPro stuff, but not everything is there as the actual downloads available on that site are being provided by anyone in the community who happens to have not deleted their original downloaded zips/tarballs. Most annoyingly for me, there were no 64-bit Mac OS GDB 7.7 (or earlier) packages available for download anywhere on that archive. Ugh.

For the record, I do understand why the devkitPro maintainers would not want to continue to provide older versions for download, as it increases the support burden for them. That said, sometimes it is absolutely legitimately useful to have access to older versions of software. As this whole post I am writing here should help to demonstrate.

You can still build your own from source though, and thankfully it's not too difficult.

curl -O http://ftp.gnu.org/gnu/gdb/gdb-7.7.1.tar.gz
tar -xvf gdb-7.7.1.tar.gz
cd gdb-7.7.1

At this point, you will need to apply a quick patch to fix a build issue that will occur midway into the build.

diff -ur gdb-7.7.1/sim/ppc/Makefile.in gdb-7.7.1-ppc/sim/ppc/Makefile.in
--- gdb-7.7.1/sim/ppc/Makefile.in	2014-05-05 17:51:24.000000000 -0400
+++ gdb-7.7.1-ppc/sim/ppc/Makefile.in	2021-01-31 14:34:59.549793292 -0500
@@ -552,7 +552,7 @@
 PACKAGE_OBJ = @sim_pk_obj@
 
 
-psim: $(TARGETLIB) main.o $(LIBIBERTY_LIB) $(BFD_LIB) $(LIBS) $(LIBINTL_DEP)
+psim: $(TARGETLIB) main.o $(LIBIBERTY_LIB) $(BFD_LIB) $(LIBINTL_DEP)
 	$(CC) $(CFLAGS) $(SIM_CFLAGS) $(LDFLAGS) -o psim$(EXEEXT) main.o $(TARGETLIB) $(BFD_LIB) $(LIBINTL) $(LIBIBERTY_LIB) $(LIBS)
 
 run: psim

Now we can get to actually building GDB. Unfortunately, I already have a ton of developer tools and libraries and such things installed on my system, so I cannot say with 100% certainty exactly what dependency pre-requisites are required to build GDB successfully, other than that you absolutely will need to install the Xcode Command Line Tools.

Now, if you have Xcode 12 (and the Command Line Tools, of course) installed, you will need to run configure this way:

CFLAGS="-Wno-error=implicit-function-declaration" ./configure \
    --prefix=/opt/devkitPro/devkitPPC \
    --target=powerpc-eabi \
    --program-prefix=powerpc-eabi- \
    --disable-werror \
    --disable-nls

The CFLAGS setting works around the fact that a bunch of the GDB code, intentionally or not, uses implicit declarations, and as I understand it, Apple switched the option to flag this as an error (instead of just a warning) on by default with Xcode 12.

If you are using a version prior to 12, you can just do:

./configure \
    --prefix=/opt/devkitPro/devkitPPC \
    --target=powerpc-eabi \
    --program-prefix=powerpc-eabi- \
    --disable-werror \
    --disable-nls

And then finally, build and install it:

make
sudo make install

If you are like me, and have your devkitPro installation somewhere non-standard, you can easily adjust the --prefix option in the configure invocation above and also specify an alternate destination to the make install like the following:

make DESTDIR=${HOME}/some/where/else install

At the end of this, you will have your freshly built powerpc-eabi-gdb binary that should once again work with remote debugging with a USB Gecko.

(no, that's not how I normally work, it was just something I set up so I could get it all in one picture)

For your convenience, I have a pre-built PowerPC GDB 7.7.1 package for 64-bit Mac OS available for download here.

I hope all this information is helpful to someone!

Neither myself, 'nor the devkitPro team can or will provide support for this! If you intend on using this, you do so at your own risk! I do not at all claim that this is a perfect solution that will work for everyone. Be ready for some tinkering and investigation if you encounter any trouble with this. Remote debugging with a USB Gecko was NEVER perfect in the first place, so be warned and tread carefully!