console-dev.de

Home of VsTortoise, VisualHAM, N3D and HEL Library

The processors built-in the Nintendo DS, an ARM946E-S and ARM7TDMI, support hardware exceptions such as “Data Abort – accessing invalid memory addresses” and “Undefined Instruction”. The Nintendo DS homebrew library libnds includes exception handling and comes with a default handler that displays the exception type, at which address in the instruction sequence the exception occured and a dump of all registers.

In this article I show what you can do with this information and why it is useful during development.

libnds exceptionTest example

If you installed the libnds examples, you should find the exeptionTest example in devkitPro\examples\nds\debugging\exceptionTest.

Copy&Paste from exceptionTest.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <nds.h>
 
/*---------------------------------------------------------------------------------
 
 The default exception handler displays the exception type - data abort or undefined
 instruction you can relate the exception to your code using
 
    arm-eabi-addr2line -e <elf file> <address>
 
 assuming you built with debug info this will display a source file and a line number
 The address of the instruction is shown as pc, beside the address which faulted
 the rest of the screen is a dump of the registers.
 
---------------------------------------------------------------------------------*/
 
//---------------------------------------------------------------------------------
int main(void)
{
  // install the default exception handler
  defaultExceptionHandler();
 
  // generate an exception
  *(unsigned int*)0xFA = 0x64;
 
  // never comes here
  while(1)
    swiWaitForVBlank();
 
  return 0;
}

When you build and run the example project, it displays:

Guru Meditation Error! - Data Abort

This is actually a fake screenshot. I rebuilt the Guru Meditation Error with printf, because the example didn’t behave in any emulator as on actual hardware. I tested no$gba 2.6a, iDeaS 1.0.3.3 beta and DeSmeME 0.9.5, none of them displayed the error report as on the real Nintendo DS hardware.

guru meditation origin

Guru Meditation is the name of the error that occurred on early versions of the Commodore Amiga computer when they crashed. It is analogous to the “Blue Screen Of Death” in Microsoft Windows operating systems.

The Guru Meditation error message was a black screen with the following animation at the top:

Commodore Amiga - Guru Meditation error message

decode nds guru meditation data abort message

One of the Nintendo DS variants of the Guru Meditation error message is the data abort, which includes the following information:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
     Guru Meditation Error!    
          data abort!          
 
  pc: 02000386 addr: 000000FA  
 
  r0: 020005BD   r8 : 00000000 
  r1: 00000000   r9 : 00000000 
  r2: 00000064   r10: 00000000 
  r3: 000000FA   r11: 00000000 
  r4: 0B000000   r12: 02000000 
  r5: 00000000   sp : 0B003CF8 
  r6: 00000000   lr : 020005B5 
  r7: 00000000   pc : 0200038E 
 
  0B003CF8: 0B000000 02000180  
  0B003D00: 00000000 00000000  
  0B003D08: 00000000 00000000  
  0B003D10: 00000000 00000000  
  0B003D18: 00000000 00000000  
  0B003D20: 00000000 00000000  
  0B003D28: 00000000 00000000  
  0B003D30: 00000000 00000000  
  0B003D38: 00000000 00000000  
  0B003D40: 00000000 00000000

The first line is always “Guru Meditation Error!”, followed by the type of the exception:

1
2
     Guru Meditation Error!    
          data abort!

The libnds default exception handler displays “Data Abort” and “Undefined Instructions” exceptions.

Below the exception type is pc and addr displayed, which I guess is not very obvious for many novice programmers:

1
  pc: 02000386 addr: 000000FA

pc is short for Program Counter. The Program Counter register indicates where the processor is in its instruction sequence. In this case, it’s the address of the instruction that caused the exception.

addr represents the exception address. In this case, writing to the memory address 0xFA:

1
2
  // generate an data abort exception
  *(unsigned int*)0xFA = 0x64;

This again is followed by a register dump:

1
2
3
4
5
6
7
8
  r0: 020005BD   r8 : 00000000 
  r1: 00000000   r9 : 00000000 
  r2: 00000064   r10: 00000000 
  r3: 000000FA   r11: 00000000 
  r4: 0B000000   r12: 02000000 
  r5: 00000000   sp : 0B003CF8 
  r6: 00000000   lr : 020005B5 
  r7: 00000000   pc : 0200038E
  • r0r12 are the so called General Purpose Registers.
  • sp (r13) is the Stack Pointer Register, which indicates the current top of stack memory.
  • lr (r14) represents the Link Register, which holds the return address when the current function completes (it’s the address of the caller).
  • pc (r15) is short for Program Counter. The Program Counter register indicates where the processor is in its instruction sequence.

The last information in the error report is a memory dump of the top 80 bytes of stack memory:

1
2
3
4
5
6
7
8
9
10
  0B003CF8: 0B000000 02000180  
  0B003D00: 00000000 00000000  
  0B003D08: 00000000 00000000  
  0B003D10: 00000000 00000000  
  0B003D18: 00000000 00000000  
  0B003D20: 00000000 00000000  
  0B003D28: 00000000 00000000  
  0B003D30: 00000000 00000000  
  0B003D38: 00000000 00000000  
  0B003D40: 00000000 00000000
  • First column specifies the stack address (0B003CF8)
  • Second column shows the 32bit value from the stack address (0B000000)
  • Third column shows the 32bit value from the stack address + 4 bytes (02000180)

how to make use of all this

This information is informative only when the output file was built with debug information. You can include debug information by adding the -g option (produce debugging information) to CFLAGS in the project makefile:

Copy&Paste from exceptionTest makefile:

1
2
3
4
5
CFLAGS	:= -g -Wall -O2\
		-march=armv5te -mtune=arm946e-s \
 		-fomit-frame-pointer\
		-ffast-math \
		$(ARCH)

devkitARM includes an application named “arm-eabi-addr2line.exe”, located in devkitPro\devkitARM\bin, that can be used to convert addresses into line number/file name pairs. It supports the following command line options:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Usage: arm-eabi-addr2line.exe [option(s)] [addr(s)]
 Convert addresses into line number/file name pairs.
 If no addresses are specified on the command line, they will be read from stdin
 
 The options are:
  @<file>                Read options from <file>
  -b --target=<bfdname>  Set the binary file format
  -e --exe=<executable>  Set the input file name (default is a.out)
  -i --inlines           Unwind inlined functions
  -j --section=<name>    Read section-relative offsets instead of addresses
  -s --basenames         Strip directory names
  -f --functions         Show function names
  -C --demangle[=style]  Demangle function names
  -h --help              Display this information
  -v --version           Display the program's version

We are interested in the address where the Data Abort exception occured, named pc here:

1
2
3
4
     Guru Meditation Error!    
          data abort!          
 
  pc: 02000386 addr: 000000FA

I used the following commandline for conversion:

1
arm-eabi-addr2line.exe -f -C -e  -s -i exceptionTest.elf 02000386

The output is:

1
2
main
exceptionTest.c:23

When you scroll at the beginning of this article, where I present the source code of the exceptionTest example, you see line 23 is inside main(), which is stored in exceptionTest.c and contains the code that writes to the address 0xFA.

conclusion

Make sure to install an exception handler in your projects. It’s very helpful to actually see that an error occured rather than a freeze. libnds makes it enormously easy, it’s just one line of code!

  1. sylvainulg Said,

    Nice post ^^, and nice blog altogether.

    I used to hack defaultHandler() from libnds to make sure it won’t reset too much when an exception occurs. The second screen usually proves a wonderful help to figure out the context of the crash, especially if it is showing a debug log.

    (that makes me think: the debug log could be revealed only in defaultHandler() and be a hidden tiled layer for the rest of the application’s life :P )

Add A Comment

This site uses a Hackadelic PlugIn, Hackadelic SEO Table Of Contents 1.6.0.