Tips for debugging your games
Unfortunately, it's inevitable - bugs will find their way into your game. Never fear! Let's go over some of the strategies available for hunting them down.
The simplest form of debugging available is LOG() and its friends in the Macros module. This allows you to render values in your application according to a given format string, similar to printf().
In simulation, the output from LOG() is written directly to the console.
You can redirect the output to a file by invoking siftulator with the --stdout
option, as follows:
$ siftulator awesome-game.elf --stdout mylogfile.txt
On hardware, there's of course no console to write to. Instead, swiss listen
can capture console output from the Sifteo Base over a USB connection.
To be as efficient as possible, the Base sends only the bare minimum of log info over the USB connection, then swiss
is responsible for accessing your game's .elf and decoding the log info accordingly.
This means you must provide the same elf running on the Base to swiss listen
, as follows:
$ swiss listen awesome-game.elf
Your LOG() statements will be rendered to the console, and should look the same as when printed by siftulator.
See the Device Management guide for more details on how to use swiss
.
When a fault occurs while your app is running, the Sifteo Base stores an internal record describing details of the fault, and displays the dreaded Cat Monkey.
The Ref# in the fault display is not an error code, but an instance ID that allows you to distinguish a particular instance of an error from others that might be similar.
All the helpful details are stored internally in fault logs on the Base. Use the swiss savedata
command, specifying com.sifteo.syslfs
to retrieve the Base's internal savedata:
$ swiss savedata extract com.sifteo.syslfs my-fault-records.bin
Now, use the python script in the sdk/tools directory to interpret syslfs.bin:
$ python sdk/tools/savedata.py my-fault-records.bin
Sample output:
Fault Info for com.mycompany.mygame (0.3.0) uuid: f8531629-3539-42aa-8d54-b9b20e824292 Header Info reference: 2 recordType: 1 - SVM Fault Record runningVolume: 0xb fault code: 0xe - User call to _SYS_abort uptime (in sys ticks): 30627379585 CubeInfo num connected to the system (bitmap): 0xf0000000 num visible to user space (bitmap): 0xf0000000 cube range: 3 - 8 Registers PC: 0x8000030e SP: 0x2000fab8 FP: 0x2000fab8 r0: 0x20003f40 r1: 0x20002680 r2: 0x3d0e5532 r3: 0xffffffff r4: 0x00000000 r5: 0x00000007 r6: 0x21704fb2 r7: 0x00000003
This shows us that com.mycompany.mygame, version 0.3.0, was responsible for generating fault code 0xe, which indicates a call to _SYS_abort(). This fault was Ref #2, so if this same fault had happened several times, we'd have a way to determine which is which.
In the Registers section above, PC is short for program counter, which is the register that holds the address of the instruction being executed at any given moment. We can cross reference the PC from the fault log with your game's .elf to see what was executing when the fault was generated.
To do this, you'll need to install the ARM GCC toolchain available at https://launchpad.net/gcc-arm-embedded. Once this is installed, you can run a command like the following:
$ arm-none-eabi-objdump -d awesome-game.elf | arm-none-eabi-c++filt -n | less
You'll be presented with the disassembly of your game, with the addresses in the column on the left, and function names interleaved to indicate where they begin. Scroll through the output until you find the PC address, and you should have your culprit!
less
may not be available by default, but can be installed via http://www.mingw.org. Future SDKs will likely have a more streamlined approach for this process.We have plans to introduce GDB-compatible source level debugging in a future release, but this is not yet available. Stand by!
Sifteo SDK v1.1.0 (see all versions)
Last updated Tue Dec 23 2014, by Doxygen