release
dev builds
extras
themes manual
wiki
device status forums
mailing lists
IRC bugs
patches
dev guide



Search | Go
Wiki > Main > UseMemoryGuard

How to use the memory guard ("Catch mem accesses") debugging feature

About

Rockbox is mainly written in C, with some assembler for time critical parts. Both languages lack one feature that would come in very handy for debugging - there is no range checking for array indices and pointers. Therefore it happens easily that you write some code that inadvertently accesses memory areas it shouldn't. One case are uninitialized pointers (pointing to NULL which is essentially address 0), another would be writing to write protected areas (const data). The latter case will usually be detected by the compiler, unless you do explicit casting.

While accessing those areas even for writing will usually not crash rockbox because there is nothing writable at those addresses (for writing to const data this is only true for RomBox), it is still an error one would like to find.

How? The SH1 CPU used in our boxes does not feature an MMU, which would allow fine-grained memory access control. However, it features the "user break controller" (UBC), which can be mis-used as a "poor man's MMU". While this is somewhat limited, it is still better than nothing.

How to use

This feature is of course only available on the real target. It does not work in the simulator.

Activation

You will find a new menu item in the debug menu: "Catch mem accesses". The default setting is "None". If you want to check some code for illegal memory accesses, set this to one of the following modes:

Mode Description
None This is the default. No check for illegal accesses is performed.
Flash ROM writes Select this if you want to check for write accesses to const data. This does only work when running RomBox, and for the main rockbox code only. It is mainly intended for debugging RomBox. This catches all write accesses to address 0x02?????? (area 02 for short)
Zero area (all) Select this if you want to check for any access to the zero area due to uninitialized pointers. This catches all accesses (read or write) to addresses 0x00?????? and 0x01?????? (areas 00 and 01 for short)

As this setting is not stored in a variable, but directly written to/ read from the UBC, it will survive RoLo, this enables testing the rockbox init as well. However, the setting will not survive poweroff, as it is not saved within the config block.

There are some (rare) places where the check will be temporarily disabled, due to deliberate access of the protected areas. These places are:

Function Reason
Debug->Dump ROM contents Accesses area 00 (boot ROM) for reading
Debug->View HW info Accesses area 00 (boot ROM) for reading (CRC check and comparing with flash ROM to detect ROM-less boxes) and area 02 (flash ROM) for writing (flash ID check)
firmware_flash.rock Accesses area 00 (boot ROM) for reading (CRC check and comparing with flash ROM to detect ROM-less boxes) and area 02 for writing (flashing)
rockbox_flash.rock Accesses area 02 for writing (flashing)

Performing your tests

Simply use the functions/ features of rockbox that use the code you want to test. It will work as usual as long as there is no illegal access detected. However, if an illegal access happens, you'll see a message like the following one on the screen:

I0C:UserBrk
at 09020114

The hexadecimal number following the at will vary, as this is the address of the PC at the moment the illegal access took place. (Yes, this is the output of the default handler for unexpected interrupts. I didn't bother to write my own handler, since this would not enable retrieving additional information, but only increase code size. Hey, this is a low-level debug feature anyway!)

Post-mortem analysis

In order to take full advantage of that feature, you'll need some understanding of SH1 assembler and architecture. I suggest reading both the SH1 programming manual and the SH1 hardware manual. The rockbox memory map is found on this page.

How do you interpret an actual UserBrk exception? You'll need the following additional info

  • The address of the UserBrk exception. This tells you the value of the program counter at the point the illegal access was detected. It is not possible to tell the address that was access, nor whether it was a read or write access (unless you catch write accesses only)
  • The linker map file (rockbox.map when debugging rockbox itself, [pluginname].map when debugging [plugin].rock. See later)
  • Possibly a disassembly of the binary

For the following table I assume your build directory is one level down from the rockbox source tree.

Task Typical UserBrk address How to create the disassembly
Debug ordinary rockbox 0x090????? ../tools/sh2d -sh1 -o 0x09000000 rockbox.bin >rockbox_dis.s
Debug RomBox (recorder V1) 0x020????? ../tools/sh2d -sh1 -o 0x02011010 rockbox.bin >rockbox_dis.s
Debug RomBox (recorder V2) 0x020????? ../tools/sh2d -sh1 -o 0x02012010 rockbox.bin >rockbox_dis.s
Debug [plugin] (2 MB boxes) 0x091F???? ../tools/sh2d -sh1 -o 0x091F8000 [plugin].rock >[plugin]_dis.s
Debug rockbox (all) 0x0F000??? Exceptions in this area are tricky to analyze with disassemblies, because code for this area (the SH1 internal RAM) gets moved by the rockbox init

  • open the .map file in an editor
  • search for the code fragment (marked with .text) that has the highest start address below the exception address
  • within that fragment, search for the function symbol with the highest start address below the exception address and that with the lowest start address above the exception address. Beware, the symbols are not sorted by address!
  • look into the source file of that fragment: if there are no static functions between the two functions you determined in the last step, you are lucky: you now know the function that caused the exception
  • if there are static functions in between, or you want to find the exact spot of the exception, you'll have to use the disassembly.

Rockbox memory map

Area Function normal access addresses
00 internal (boot) ROM read (1) 0x00000000..0x0000FFFF
02 flash ROM read (2) 0x02000000..0x0203FFFF
04 MAS PIO (3) read 0x04000000
05 on-chip modules read/write 0x05FFFE00..0x05FFFFFF
06 ATA read/write 0x06100100..0x06100107, 0x06104100, 0x06200206, 0x06200306
09 DRAM read/write 0x09000000..0x091FFFFF
0F internal RAM read/write 0x0F000000..0x0F000FFF

  1. debug functions only
  2. write for flash ID reading and flashing
  3. recorders only

r3 - 02 Apr 2021 - 20:46:07 - UnknownUser

Copyright © by the contributing authors.