GDB debugging and FreeRTOS

What sorts of things would make it so that FreeRTOS runs stand-alone just fine but it gets aborts when you run it with the debugger?  For example, I wrote a small app with one task (plus of course the idle task) that blinks a few LEDs.  If I run it without the debugger (i.e. just turn it on or push the reset button) it works fine, but if I run it through gdb it does nothing.  When I eventually abort it I get: Program received signal SIGINT, Interrupt. data_abort () at src/startup.S:83 83              b data_abort 1: /x $pc = 0x8b0 (gdb) print/x $lr $1 = 0xc0c It’s fairly consistent about stopping in that same spot, which is in the middle of vPreemptiveTick() as it calls the macro portRESTORE_CONTEXT():      /* The critical nesting depth is the first item on the stack. */      /* Load it into the ulCriticalNesting variable. */      "LDR        R0, =ulCriticalNesting -->  "LDMFD      LR!, {R1}    BLOWS UP HERE      "STR        R1, [R0] (this is based on the LPC2106 GCC port, though mine is an LPC2129).

GDB debugging and FreeRTOS

Hmm.  Don’t know.  Are you using exactly the same build for the debug and non debug versions?  I presume you set the linker script to be correct when converting the LPC2106 demo to run on the LPC2129? Regards.

GDB debugging and FreeRTOS

>I presume you set the linker script to be correct when converting the LPC2106 demo to run on the LPC2129? Yep. >Are you using exactly the same build for the debug and non debug versions? Yes. Maybe what I will do is examine vPreemptiveTick on some other ports and see if that helps me figure out what is happening with this one.

GDB debugging and FreeRTOS

My GDB still bombs out in vPreemptiveTick.  I am trying to trace through it …when I enter vPreemptiveTick the CPU is in IRQ mode (which makes sense, as it was called from the timer). portSAVE_CONTEXT() is executed. vTaskIncrementTick() is executed. vTaskSwitchContext() is executed, after which pxCurrentTCB is set to the IDLE task: (gdb) print *pxCurrentTCB $4 = {pxTopOfStack = 0x400005d8, xGenericListItem = {xItemValue = 0, pxNext = 0x40002244, pxPrevious = 0x40000214,     pvOwner = 0x400003ec, pvContainer = 0x4000223c}, xEventListItem = {xItemValue = 5, pxNext = 0x0, pxPrevious = 0x0,     pvOwner = 0x400003ec, pvContainer = 0x0}, uxPriority = 0, pxStack = 0x40000438, uxTCBNumber = 1,   pcTaskName = "IDLE", ‘’ <repeats 11 times>, usStackDepth = 128} Next it begins portRESTORE_CONTEXT().     LDR        R0, =pxCurrentTCB     LDR        R0, [R0]     LDR        LR, [R0] LR now contains 0x40003bf8     LDR        R0, =ulCriticalNesting     LDMFD  LR!, {R1}     STR        R1, [R0] After this, r1 contains 0x00000000, which seems right, and LR is 0x40003fbc, which means the stack pointer is going up, consistent with things being popped.  Good so far.     /* Get the SPSR from the stack. */     LDMFD  LR!, {R0} LR is now 0x40003fc0 and r0 is now 0x60000013.  This would correspond to mode b10111 which is ABORT.  Why is that?     MSR        SPSR, R0 It does what it was supposed to do; $spsr_irq is now 0x60000013.     LDMFD  LR, {R0-R14}^     NOP After the registers are restored, things generally look to me like they make sense.     /* Restore the return address. */     LDR        LR, [LR, #+60] lr now contains 0x944 … oops that’s bad.  That’s in _start, i.e. the startup routine (pre-main).     SUBS   PC, LR, #4 Indeed, it jumps to clear_bss (in the middle of _start) and $cpsr is 0x60000013 i.e. it is in abort mode. What’s happening here?

GDB debugging and FreeRTOS

You said previously that it was ok when not running the debugger.  In the past I have experienced two problems when stepping through this part of the code, neither time with GDB though so I don’t know if it is relevant.  The first was where stepping the debugger temporarily allowed interrupts to execute even when interrupts were globally disabled.  This can corrupt your data structures.  The second was where the timer that generated the interrupt was not halted when the debugger hit a break point, but kept running. If neither of these are the problem then I would suggest a simple test.  Write a task that sets all the registers to a known value, then calls yield, then checks to ensure the registers still contain the same values.  Create two of these tasks, with each task setting the registers to a different known value.  Then run the scheduler is cooperative mode.  This way you know which value should be in each register of both of the two tasks and can step through the saving and restoring of each when yield is called, to see where the problem occurs. There are some examples of this technique in the FreeRTOS download, but I cannot find one for the ARM7.  Take a look at the function prvSetAndCheckRegisters() in DemoCORTEX_LM3S102_GCCDemo1main.c, or vRegisterTest() in the PIC24 or microblaze main() files.

GDB debugging and FreeRTOS

>The first was where stepping the debugger temporarily allowed interrupts to execute even when interrupts were globally disabled. This can corrupt your data structures. The second was where the timer that generated the interrupt was not halted when the debugger hit a break point, but kept running. I read a note about this in the source for the 2106 port and was worried about it.  Check my logic here, but the reason I don’t think that is happening here is that the problem occurs without single stepping.     (gdb) break maintask     Breakpoint 1 at 0x728: file src/led.c, line 47.     (gdb) go where "go" is a macro defined as:      set $pc = 0      continue The program starts running but never hits the breakpoint, i.e. my main (first) task never gets called.  Eventually, I get bored and hit ^C to see what it is doing:     Program received signal SIGINT, Interrupt.     data_abort () at src/startup.S:83     83              b data_abort     1: /x $pc = 0x964     (gdb) print/x $lr     $1 = 0xcc0 This makes me wonder … maybe this gets all screwed up because just setting the pc to the reset vector then "continuing."  The gdb "run" command doesn’t seem to work:     (gdb) run     The program being debugged has been started already.     Start it from the beginning? (y or n) y     Starting program: /home/chrisp/work/arm/led/led.elf     Don’t know how to run. but, just executing from 0x00000000 is not quite the same as a reset, even considering that I put all of the registers I think I care about in a state I want regardless of their reset default. Does that make sense? I will try your suggestions now and see what happens.

GDB debugging and FreeRTOS

You know what part of it is … setting the $pc to 0 isn’t enough, because depending on where you were when you last stopped you might not even be in supervisor mode. I tried this: define go     set $cpsr = 0x13     set $pc = 0     continue end and it behaves DIFFERENTLY.  Not correctly, but differently.  (At least so far).  I will pursue this a little, because there may be more that I have to do.

GDB debugging and FreeRTOS

I don’t think setting the program counter to 0 without first a reset is guaranteed to work.  The VIS will still be configured, as will all the peripherals.  This means interrupts firing during the C startup code execution are likely to cause data aborts.