12

Update 2016-12 There is now also a minimal example for this behavior: https://community.nxp.com/message/862676


I'm using a ARM Cortex M4 with freertos using freescales freedom Kinetis IDE (gnu arm toolchain). Problem is that

try {
    throw 4; // old scenario also not working: throw std::runtime_error("wut");
} catch (...) {
}

results in a halted CPU and code after the try or (when some is added) in the catch handler is not executed.

And assembly can be found here: https://gist.github.com/Superlokkus/3c4201893b4c51e154e2a0afdf78fef0

I ASSUMED that this results in an SVC interrupt, I'm sorry I got that wrong, Freertos tricked me into this, because when I throw something it halts in DefaultISR.

The throw indeeds jump to __cxa_throw then from there to ___Unwind_RaiseException __gnu_Unwind_RaiseException __cxa_begin_catch> <_ZSt9terminatev> So it looks like std::terminate is called, but the catch all block should not allow this. Or is my assumption wrong and this behavior is because the gcc C++ runtime exception support is a stub which always calls terminate?!

Update 2016-09: Because I saw that rand() tries to use malloc(), I also defined a working malloc()/freeRTOS function and et voilà: __cxa_allocate_exception uses malloc (I wonder how the toolchain expects me to handle a bad_alloc case). So now, it still crashes, but after exception allocation (I think): The excecution path is :

(throwing function after exception allocation)
__cxa_throw
   ...                        //(some intructions in __cxa_throw)
   __cxa_begin_catch  //I guess something went wrong here
    _ZSt9terminatev // Immediately after __cxa_begin_catch
        _ZN10__cxxabiv111__terminateEPFvvE:
         00016dfc: push {r3, lr}
         00016dfe: blx r0  //Goes directly to WDOG_EWM_IRQHandler or hard fault handler
         00016e00: bl 0x194ac <abort>

If you wonder or it might help: My debuggers say its the WDOG_EWM_IRQHandler I crash into, if I not define the hard_fault handler and an own default handler.

So I guess something went wrong in the stack unwinding, because I go thru some symbols with "finished stack unwinding" in the name in _throw, but I didn't catched the break point I set in a destructor of an object which should have been cleaned up. And that seems to motivate __cxa_begin_catch to call abort or something.

( Kinetis Design Studio 3.2.0. with the GNU ARM C/C++ Cross Compiler Version: 1.12.1.201502281154 for our FRDM-KV31F)

Superlokkus
  • 3,784
  • 1
  • 17
  • 49
  • IMHO, for embedded device, c++ exception mechanism is a little bit to complex. Also FreeRTOS use SVC interruption, so if you do that, you have to be aware of what you do to avoid breaking FreeRTOS – Garf365 Sep 13 '16 at 11:22
  • Isn't there any exception handling code in the gnu arm toolchain? – Superlokkus Sep 13 '16 at 11:30
  • 1
    Are you talking about C++ exceptions or ARM core exceptions? – rjp Sep 13 '16 at 13:42
  • It sounds like you're talking about ARM core exceptions, given the reference to SVC_Handler. Typically the microcontroller vendor will ship a file that includes a vector table and it may be populated with weakly linked vectors that you can override, or it is expected that you will modify the file to call what you need. NXP/Freescale uses weak linkage on their Kinetis parts. – rjp Sep 13 '16 at 13:45
  • @rjp No I'm talking about C++ exceptions, but it seems to me the arm gcc is just invoking the arm core svc exception, when a C++ exception is thrown, because the stack unwinding looks to be an OS task. – Superlokkus Sep 13 '16 at 13:56
  • 2
    I don't know what gcc is expecting to have called from there, but you're going to have to insert your own `SVC_Handler` above FreeRTOS' that can check why it got there. `SVC` takes a parameter that ends up in `R0` IIRC, and FreeRTOS by default calls `SVC #0`, so depending on what gcc is inserting for the `SVC` parameter you may be able to distinguish the source. It will block RTOS interrupts as you fear though. – rjp Sep 13 '16 at 14:38
  • 1
    All I can look at is how IAR EWARM handles it, and it handles it without using processor exceptions. Could you post the disassembly of an MCVE, please? – rjp Sep 13 '16 at 15:01
  • 1
    Do you have your watchdog setup and are you servicing it appropriately? I've also had an issue where I was dropping into the wrong vector, so if the vector you're dropping into doesn't make sense, double check that you have the alignment on your vector table correct. – rjp Sep 22 '16 at 13:35
  • @Superlokkus Might point at something. See [osdev.org](http://wiki.osdev.org/Libsupcxx) - The section: "Full C++ Runtime Support Using libgcc And libsupc++" – iolo Nov 02 '16 at 18:37

3 Answers3

9

By fault, most of your exceptions will execute the default handler, so the first thing you need to do is determine which exception is actually executing. You can see the "Determining Which Exception Handler is Executing" section on the following page: http://www.freertos.org/Debugging-Hard-Faults-On-Cortex-M-Microcontrollers.html

I would guess, since you are not using a peripheral in your code, that it will be a fault handler, probably the hard fault. The same page (see link above) gives instructions on debugging that too.

Other than that - ensure you do the normal FreeRTOS debug things, like ensure you have configASSERT() defined, and that you have stack overflow checking on. Info on those topics is found on this page: http://www.freertos.org/FAQHelp.html

Richard
  • 2,688
  • 7
  • 7
  • It's the hard fault, since it stops there after throwing after I define an own HardFault_Handler. My biggest question at the moment is: Is C++ exception handling supposed to work out of the box, with freeRTOS or without an OS?! I'm asking since this is a brown field project I have been thrown into, and if you say "Yeah it should work, so it looks like wrong interrupt management" I know where to look. – Superlokkus Sep 15 '16 at 13:31
  • 1
    @Superlokkus It should be work with or without freeRTOS. I think if you get a hard Fault it's probably because you don't catch a exception.... Or a bad pointer somewhere – Garf365 Sep 23 '16 at 07:40
  • Thx @Garf365 !! – Superlokkus Sep 23 '16 at 09:18
7

From the RTOS side of things, C++ exceptions are just a glorified jump. As long as they're jumping from one bit of your code to another, they don't interfere with the RTOS. So you can write a try { } catch(std::exception) { }.

When there is no C++ handler, the RTOS indeed will have to step in as your C++ code stops running.

MSalters
  • 159,923
  • 8
  • 140
  • 320
  • You will never get to the catch part, since at this moment, whenever an C++ exception gets thrown, regardless if it's catched or not, an arm hardware exception is invoked but looks to be handled by the default excpetion handler, which means the CPU just halts, which it does actually. – Superlokkus Sep 13 '16 at 14:19
  • @Superlokkus: Do you have a source for that claim? Because AFAICT, GCC follows the Itanium ABI on ARM and that does _not_ use hardware exceptions. – MSalters Sep 13 '16 at 14:29
  • http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0056d/Cihbbbcj.html ("ARM® Developer Suite Developer Guide Chapter 5. Handling Processor Exceptions") Even better: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0553a/Babefdjc.html ("Cortex-M4 Devices Generic User Guide Home > The Cortex-M4 Processor > Exception model") – Superlokkus Sep 13 '16 at 14:34
  • 2
    Processor exceptions != C++ Exceptions. This was why I asked earlier. – rjp Sep 13 '16 at 14:42
  • 1
    Here is a page that has some information about the Itanium ABI that @MSalters mentioned: http://wiki.osdev.org/C++_Exception_Support – rjp Sep 13 '16 at 14:47
  • @rjp Are you directing that to me?! I know they aren't the same, As it looks to me gcc is just invoking the SVC processor exception/interrupt which then should do the (language agnostic) stack unwinding (which I called ambiguously "(c++)exception handling") – Superlokkus Sep 13 '16 at 14:49
  • 1
    @Superlokkus the link you posted was just the processor exception model and not a source that gcc isn't using the Itanium ABI for exceptions. Post some disassembly that shows your throw statement resulting in an `svc` instruction, and if it's not that, show us what it does result in. – rjp Sep 13 '16 at 14:52
  • @rjp I just edited the question regarding to that. Looks like I asked a XY problem, so maybe I should not edit it but ask a new one – Superlokkus Sep 13 '16 at 15:39
  • The new info you have puts it completely out of my scope. I'd double check that KDS is actually running gcc with the correct options to have exceptions handled properly. – rjp Sep 13 '16 at 16:28
2

After successfully creating a blank project with default settings in freescales Kinetis, and asking the same problem on the nxp community, Alice_Yang , an NXP engineer (assuming by the NXP badge), told me the answer:

By default new projects link to newlib-nano which has it exception support disabled.

The libstdc++ built along with newlib-nano have exception handling disabled.

So the solution is to link simply to newlib. This can be done by simply removing the line "-specs=nano.specs" in "other linker flags" and also make sure the check box which adds the same option is also disabled. Then everything works as expected. Only the code increased by 27 kB in ROM/text size and 2kB in RAM/data. enter image description here

Superlokkus
  • 3,784
  • 1
  • 17
  • 49