Checking for Stack Overflow

From Texas Instruments Wiki
Jump to: navigation, search

Introduction

A common issue causing software instability is a stack overflow.  There is hardware on both the c6000 and the c5500 that can assist in catching these overflows as they happen.  This can be particularly important in cases where the stack overflow causes the DSP to go "into the weeds" and causes the emulator to crash. The Unified Breakpoint Manager (UBM) integrated into Code Composer Studio makes it easy to utilize this hardware in order to trap stack overflows as they happen.


Details about the stack

Stack Details Across Architectures
Stack Pointer Register Stack Pointer points to... Grows from... Recommended Watchpoint Location
c6000 B15 next available unused location high addr to low addr __stack
c55xx XSP/SP/SSP last data written on stack high addr to low addr __stack, __sysstack
F28x SP next available unused location low addr to high addr __STACK_END - 2
Stellaris
Cortex M3
R13 next available unused location high addr to low addr __stack

c6000 stack operation

On c6000 devices the register B15 is used as the stack pointer. The stack grows from high addresses to low addresses. The stack pointer (B15) always points to the next unused location. The stack pointer must always be double-word aligned (least significant 3 bits must be 0). The C compiler and BIOS automatically maintain the proper alignment. Only in the case of hand-written assembly does the programmer have to take special care that the stack pointer never be mis-aligned, even for one cycle (unless interrupts are disabled at that instant).

For more details on the c6000 stack please read the chapter "C/C++ System Stack" in the C6000 Compiler User's Guide.

c5500 stack operation

On c5500 devices there are actually two stack pointers. One is called simply "stack pointer" (SP) and the other is called "system stack pointer" (SSP). Like c6000, the stacks grows from high addresses to low addresses. The stack pointers on c5500, however, always point to the last piece of data on the stack. Therefore when doing a "push" the stack pointer is first decremented and then data is written. The stack pointers are both 16-bit. They share a common register called SPH which contains the upper 7 bits of the address being used for stack. Therefore SP and SSP be allocated in the same 64KB page of memory.

For more details on the 55x stack please read the "Stack" chapter of the 55x CPU Reference Guide.

F28x stack operation

On the F28x the stack pointer (SP) is a 16-bit pointer. Therefore it must point to the lower 64k words of memory. The stack on F28x grows from low addresses to high addresses. SP always points to the next free location, i.e. when doing a "push" the CPU first writes the data and then post-increments SP.

There is an excellent app note which also provides a means for configuring the watchpoints at run-time, i.e. without the need for an emulator. There is code provided in the index but you can also download it as a zip file.

stack definition in the code generation tools

When building a project the stack will be reserved at link time. In the project options (or in the configuration file for DSP/BIOS projects) one would specify the size of the stack(s). That corresponding size will be allocated for the stack by the linker. The linker will generate a symbol called __stack (two preceding underscores) that corresponds to the lowest address of the stack. If you want to use a hardware watchpoint to monitor a location in memory then __stack is the symbolic name you should enter in the Unified Breakpoint Manager (similarly there is also a symbol called __sysstack for c5500). To specify the stack size for a project that does not use DSP/BIOS one would go to Project -> Build Options -> Linker -> Stack Size (and System Stack for 55x), or use the -stack (and -sysstack) for command line builds.

DSP/BIOS details

If you utilize the task thread type (TSK) in DSP/BIOS then BIOS will create an additional stack for each task the user creates (plus one for the idle task). For 55x users, each task will have TWO stacks, one for SP and one for SSP. A symbol will be created for each of these stacks. If your task was called TSK0 in the BIOS config tool then you would end up with a symbol called TSK0$stack (and TSK0$sysstack on 55x). The size of the task stacks are specified in the task properties inside the config tool.

Configuring the Unified Breakpoint Manager (UBM)

UBM Setup Instructions

  1. Open UBM.
    • CCS 3.3: Go to Debug -> Breakpoints
    • CCS 4.0: Go to View -> Breakpoints
  2. Inside UBM, click the selection arrow to the right of "New" and choose "Watchpoint". (In CCS 4.0 it's an icon with 3 breakpoints arranged as a triangle.)
  3. For the Location, enter the symbol corresponding to the stack you want to monitor, e.g. __stack, TSK0$stack, TSK_idle$stack, etc.
    • For devices such as F28x where the stack grows from low addresses to high addresses you would set the watch point symbol at __STACK_END-2 (monitor a 2-word boundary since 32-bit accesses will only present the 2-word address on the bus).
  4. For the Access Type, select Memory Write.
  5. Click OK and you're set!

Now any time the CPU writes to that address then it will halt. If you're monitoring a DSP/BIOS task stack this will happen before you even get to main because the code that does the watermark will trigger the watchpoint. When reloading code you can either uncheck that watchpoint until you get to main() or else you can just hit run after you hit that watchpoint due to the watermarking.

Demonstration Video

Click here to see a Flash video demonstrating setup and usage of UBM on a 55x device to detect overflow of a task stack. There is audio commentary as well.

See also

DSP BIOS Debugging Tips: Stack Overflow
Advanced Event Triggering