summaryrefslogtreecommitdiffstats
path: root/cpukit/libmisc/stackchk
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/libmisc/stackchk')
-rw-r--r--cpukit/libmisc/stackchk/README53
-rw-r--r--cpukit/libmisc/stackchk/check.c515
-rw-r--r--cpukit/libmisc/stackchk/internal.h95
-rw-r--r--cpukit/libmisc/stackchk/stackchk.h135
4 files changed, 798 insertions, 0 deletions
diff --git a/cpukit/libmisc/stackchk/README b/cpukit/libmisc/stackchk/README
new file mode 100644
index 0000000000..5421a77434
--- /dev/null
+++ b/cpukit/libmisc/stackchk/README
@@ -0,0 +1,53 @@
+#
+# $Id$
+#
+
+Introduction
+============
+
+This directory contains a stack bounds checker. It provides two
+primary features:
+
+ + check for stack overflow at each context switch
+ + provides an educated guess at each task's stack usage
+
+Enabling
+========
+
+Add the stack checker extension to the initial user extension set.
+If using confdefs.h to build your configuration table, this is
+as simple as adding -DSTACK_CHECK_ON to the gcc command line which
+compiles the file defining the configuration table. In the RTEMS
+test suites and samples, this is always init.c
+
+Background
+==========
+
+The stack overflow check at context switch works by looking for
+a 16 byte pattern at the logical end of the stack to be corrupted.
+The "guesser" assumes that the entire stack was prefilled with a known
+pattern and assumes that the pattern is still in place if the memory
+has not been used as a stack.
+
+Both of these can be fooled by pushing large holes onto the stack
+and not writing to them... or (much more unlikely) writing the
+magic patterns into memory.
+
+This code has not been extensively tested. It is provided as a tool
+for RTEMS users to catch the most common mistake in multitasking
+systems ... too little stack space. Suggestions and comments are appreciated.
+
+NOTES:
+
+1. Stack usage information is questionable on CPUs which push
+ large holes on stack.
+
+2. The stack checker has a tendency to generate a fault when
+ trying to print the helpful diagnostic message. If it comes
+ out, congratulations. If not, then the variable Stack_check_Blown_task
+ contains a pointer to the TCB of the offending task. This
+ is usually enough to go on.
+
+FUTURE:
+
+1. Determine how/if gcc will generate stack probe calls and support that.
diff --git a/cpukit/libmisc/stackchk/check.c b/cpukit/libmisc/stackchk/check.c
new file mode 100644
index 0000000000..d2c0b1001b
--- /dev/null
+++ b/cpukit/libmisc/stackchk/check.c
@@ -0,0 +1,515 @@
+/*
+ * Stack Overflow Check User Extension Set
+ *
+ * NOTE: This extension set automatically determines at
+ * initialization time whether the stack for this
+ * CPU grows up or down and installs the correct
+ * extension routines for that direction.
+ *
+ * COPYRIGHT (c) 1989-2010.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems.h>
+#include <inttypes.h>
+
+/*
+ * The stack dump information may be printed by a "fatal" extension.
+ * Fatal extensions only get called via rtems_fatal_error_occurred()
+ * and not when rtems_shutdown_executive() is called.
+ * When that happens, this #define should be deleted and all the code
+ * it marks.
+ */
+#define DONT_USE_FATAL_EXTENSION
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <rtems/bspIo.h>
+#include <rtems/stackchk.h>
+#include "internal.h"
+
+/*
+ * Variable to indicate when the stack checker has been initialized.
+ */
+static int Stack_check_Initialized = 0;
+
+/*
+ * The "magic pattern" used to mark the end of the stack.
+ */
+Stack_check_Control Stack_check_Pattern;
+
+/*
+ * Helper function to report if the actual stack pointer is in range.
+ *
+ * NOTE: This uses a GCC specific method.
+ */
+static inline bool Stack_check_Frame_pointer_in_range(
+ Stack_Control *the_stack
+)
+{
+ #if defined(__GNUC__)
+ void *sp = __builtin_frame_address(0);
+
+ if ( sp < the_stack->area ) {
+ return false;
+ }
+ if ( sp > (the_stack->area + the_stack->size) ) {
+ return false;
+ }
+ #else
+ #error "How do I check stack bounds on a non-GNU compiler?"
+ #endif
+ return true;
+}
+
+/*
+ * Where the pattern goes in the stack area is dependent upon
+ * whether the stack grow to the high or low area of the memory.
+ */
+#if (CPU_STACK_GROWS_UP == TRUE)
+ #define Stack_check_Get_pattern( _the_stack ) \
+ ((char *)(_the_stack)->area + \
+ (_the_stack)->size - sizeof( Stack_check_Control ) )
+
+ #define Stack_check_Calculate_used( _low, _size, _high_water ) \
+ ((char *)(_high_water) - (char *)(_low))
+
+ #define Stack_check_usable_stack_start(_the_stack) \
+ ((_the_stack)->area)
+
+#else
+ /*
+ * We need this magic offset because during a task delete the task stack will
+ * be freed before we enter the task switch extension which checks the stack.
+ * The task stack free operation will write the next and previous pointers
+ * for the free list into this area.
+ */
+ #define Stack_check_Get_pattern( _the_stack ) \
+ ((char *)(_the_stack)->area + sizeof(Heap_Block) - HEAP_BLOCK_HEADER_SIZE)
+
+ #define Stack_check_Calculate_used( _low, _size, _high_water) \
+ ( ((char *)(_low) + (_size)) - (char *)(_high_water) )
+
+ #define Stack_check_usable_stack_start(_the_stack) \
+ ((char *)(_the_stack)->area + sizeof(Stack_check_Control))
+
+#endif
+
+/*
+ * Obtain a properly typed pointer to the area to check.
+ */
+#define Stack_check_Get_pattern_area( _the_stack ) \
+ (Stack_check_Control *) Stack_check_Get_pattern( _the_stack )
+
+/*
+ * The assumption is that if the pattern gets overwritten, the task
+ * is too close. This defines the usable stack memory.
+ */
+#define Stack_check_usable_stack_size(_the_stack) \
+ ((_the_stack)->size - sizeof(Stack_check_Control))
+
+#if (CPU_ALLOCATE_INTERRUPT_STACK == TRUE)
+ /*
+ * Did RTEMS allocate the interrupt stack? If so, put it in
+ * Stack_Control format.
+ */
+ Stack_Control Stack_check_Interrupt_stack;
+#endif
+
+/*
+ * Fill an entire stack area with BYTE_PATTERN. This will be used
+ * to check for amount of actual stack used.
+ */
+#define Stack_check_Dope_stack(_stack) \
+ memset((_stack)->area, BYTE_PATTERN, (_stack)->size)
+
+/*
+ * Stack_check_Initialize
+ */
+void Stack_check_Initialize( void )
+{
+ int i;
+ uint32_t *p;
+ static uint32_t pattern[ 4 ] = {
+ 0xFEEDF00D, 0x0BAD0D06, /* FEED FOOD to BAD DOG */
+ 0xDEADF00D, 0x600D0D06 /* DEAD FOOD but GOOD DOG */
+ };
+
+ if ( Stack_check_Initialized )
+ return;
+
+ /*
+ * Dope the pattern and fill areas
+ */
+ p = Stack_check_Pattern.pattern;
+ for ( i = 0; i < PATTERN_SIZE_WORDS; i++ ) {
+ p[i] = pattern[ i%4 ];
+ }
+
+ /*
+ * If appropriate, setup the interrupt stack for high water testing
+ * also.
+ */
+ #if (CPU_ALLOCATE_INTERRUPT_STACK == TRUE)
+ if (_CPU_Interrupt_stack_low && _CPU_Interrupt_stack_high) {
+ Stack_check_Interrupt_stack.area = _CPU_Interrupt_stack_low;
+ Stack_check_Interrupt_stack.size = (char *) _CPU_Interrupt_stack_high -
+ (char *) _CPU_Interrupt_stack_low;
+ Stack_check_Dope_stack(&Stack_check_Interrupt_stack);
+ }
+ #endif
+
+ Stack_check_Initialized = 1;
+}
+
+/*
+ * rtems_stack_checker_create_extension
+ */
+bool rtems_stack_checker_create_extension(
+ Thread_Control *running __attribute__((unused)),
+ Thread_Control *the_thread
+)
+{
+ Stack_check_Initialize();
+
+ if (the_thread)
+ Stack_check_Dope_stack(&the_thread->Start.Initial_stack);
+
+ return true;
+}
+
+/*
+ * rtems_stack_checker_Begin_extension
+ */
+void rtems_stack_checker_begin_extension(
+ Thread_Control *the_thread
+)
+{
+ Stack_check_Control *the_pattern;
+
+ if ( the_thread->Object.id == 0 ) /* skip system tasks */
+ return;
+
+ the_pattern = Stack_check_Get_pattern_area(&the_thread->Start.Initial_stack);
+
+ *the_pattern = Stack_check_Pattern;
+}
+
+/*
+ * Stack_check_report_blown_task
+ *
+ * Report a blown stack. Needs to be a separate routine
+ * so that interrupt handlers can use this too.
+ *
+ * NOTE: The system is in a questionable state... we may not get
+ * the following message out.
+ */
+void Stack_check_report_blown_task(
+ Thread_Control *running,
+ bool pattern_ok
+) RTEMS_COMPILER_NO_RETURN_ATTRIBUTE;
+
+void Stack_check_report_blown_task(Thread_Control *running, bool pattern_ok)
+{
+ Stack_Control *stack = &running->Start.Initial_stack;
+ void *pattern_area = Stack_check_Get_pattern(stack);
+ char name[32];
+
+ printk("BLOWN STACK!!!\n");
+ printk("task control block: 0x%08" PRIxPTR "\n", running);
+ printk("task ID: 0x%08lx\n", (unsigned long) running->Object.id);
+ printk(
+ "task name: 0x%08" PRIx32 "\n",
+ running->Object.name.name_u32
+ );
+ printk(
+ "task name string: %s\n",
+ rtems_object_get_name(running->Object.id, sizeof(name), name)
+ );
+ printk(
+ "task stack area (%lu Bytes): 0x%08" PRIxPTR " .. 0x%08" PRIxPTR "\n",
+ (unsigned long) stack->size,
+ stack->area,
+ ((char *) stack->area + stack->size)
+ );
+ if (!pattern_ok) {
+ printk(
+ "damaged pattern area (%lu Bytes): 0x%08" PRIxPTR " .. 0x%08" PRIxPTR "\n",
+ (unsigned long) PATTERN_SIZE_BYTES,
+ pattern_area,
+ (pattern_area + PATTERN_SIZE_BYTES)
+ );
+ }
+
+ #if defined(RTEMS_MULTIPROCESSING)
+ if (rtems_configuration_get_user_multiprocessing_table()) {
+ printk(
+ "node: 0x%08" PRIxPTR "\n",
+ rtems_configuration_get_user_multiprocessing_table()->node
+ );
+ }
+ #endif
+
+ rtems_fatal_error_occurred(0x81);
+}
+
+/*
+ * rtems_stack_checker_switch_extension
+ */
+void rtems_stack_checker_switch_extension(
+ Thread_Control *running __attribute__((unused)),
+ Thread_Control *heir __attribute__((unused))
+)
+{
+ Stack_Control *the_stack = &running->Start.Initial_stack;
+ void *pattern;
+ bool sp_ok;
+ bool pattern_ok = true;
+
+ pattern = Stack_check_Get_pattern_area(the_stack);
+
+ /*
+ * Check for an out of bounds stack pointer or an overwrite
+ */
+ sp_ok = Stack_check_Frame_pointer_in_range( the_stack );
+
+ pattern_ok = (!memcmp( pattern,
+ (void *) Stack_check_Pattern.pattern, PATTERN_SIZE_BYTES));
+
+ if ( !sp_ok || !pattern_ok ) {
+ Stack_check_report_blown_task( running, pattern_ok );
+ }
+}
+
+/*
+ * Check if blown
+ */
+bool rtems_stack_checker_is_blown( void )
+{
+ Stack_Control *the_stack = &_Thread_Executing->Start.Initial_stack;
+ bool sp_ok;
+ bool pattern_ok = true;
+
+ /*
+ * Check for an out of bounds stack pointer
+ */
+
+ sp_ok = Stack_check_Frame_pointer_in_range( the_stack );
+
+ /*
+ * The stack checker must be initialized before the pattern is there
+ * to check.
+ */
+ if ( Stack_check_Initialized ) {
+ pattern_ok = (!memcmp(
+ Stack_check_Get_pattern(the_stack),
+ (void *) Stack_check_Pattern.pattern,
+ PATTERN_SIZE_BYTES
+ ));
+ }
+
+
+ /*
+ * Let's report as much as we can.
+ */
+ if ( !sp_ok || !pattern_ok ) {
+ Stack_check_report_blown_task( _Thread_Executing, pattern_ok );
+ /* DOES NOT RETURN */
+ }
+
+ /*
+ * The Stack Pointer and the Pattern Area are OK so return false.
+ */
+ return false;
+}
+
+/*
+ * Stack_check_find_high_water_mark
+ */
+static inline void *Stack_check_find_high_water_mark(
+ const void *s,
+ size_t n
+)
+{
+ const uint32_t *base, *ebase;
+ uint32_t length;
+
+ base = s;
+ length = n/4;
+
+ #if ( CPU_STACK_GROWS_UP == TRUE )
+ /*
+ * start at higher memory and find first word that does not
+ * match pattern
+ */
+
+ base += length - 1;
+ for (ebase = s; base > ebase; base--)
+ if (*base != U32_PATTERN)
+ return (void *) base;
+ #else
+ /*
+ * start at lower memory and find first word that does not
+ * match pattern
+ */
+
+ base += PATTERN_SIZE_WORDS;
+ for (ebase = base + length; base < ebase; base++)
+ if (*base != U32_PATTERN)
+ return (void *) base;
+ #endif
+
+ return (void *)0;
+}
+
+/*
+ * Stack_check_Dump_threads_usage
+ *
+ * Try to print out how much stack was actually used by the task.
+ */
+static void *print_context;
+static rtems_printk_plugin_t print_handler;
+
+void Stack_check_Dump_threads_usage(
+ Thread_Control *the_thread
+)
+{
+ uint32_t size, used;
+ void *low;
+ void *high_water_mark;
+ void *current;
+ Stack_Control *stack;
+ char name[5];
+
+ /*
+ * The pointer passed in for the_thread is guaranteed to be non-NULL from
+ * rtems_iterate_over_all_threads() so no need to check it here.
+ */
+
+ /*
+ * Obtain interrupt stack information
+ */
+ #if (CPU_ALLOCATE_INTERRUPT_STACK == TRUE)
+ if (the_thread == (Thread_Control *) -1) {
+ if (!Stack_check_Interrupt_stack.area)
+ return;
+ stack = &Stack_check_Interrupt_stack;
+ the_thread = 0;
+ current = 0;
+ } else
+ #endif
+ {
+ stack = &the_thread->Start.Initial_stack;
+ current = (void *)_CPU_Context_Get_SP( &the_thread->Registers );
+ }
+
+ low = Stack_check_usable_stack_start(stack);
+ size = Stack_check_usable_stack_size(stack);
+
+ high_water_mark = Stack_check_find_high_water_mark(low, size);
+
+ if ( high_water_mark )
+ used = Stack_check_Calculate_used( low, size, high_water_mark );
+ else
+ used = 0;
+
+
+ #if (CPU_ALLOCATE_INTERRUPT_STACK == TRUE)
+ if ( the_thread )
+ #endif
+ {
+ (*print_handler)(
+ print_context,
+ "0x%08" PRIx32 " %4s",
+ the_thread->Object.id,
+ rtems_object_get_name( the_thread->Object.id, sizeof(name), name )
+ );
+ }
+ #if (CPU_ALLOCATE_INTERRUPT_STACK == TRUE)
+ else {
+ (*print_handler)( print_context, "0x%08" PRIx32 " INTR", ~0 );
+ }
+ #endif
+
+ (*print_handler)(
+ print_context,
+ " %010p - %010p %010p %8" PRId32 " ",
+ stack->area,
+ stack->area + stack->size - 1,
+ current,
+ size
+ );
+
+ if (Stack_check_Initialized == 0) {
+ (*print_handler)( print_context, "Unavailable\n" );
+ } else {
+ (*print_handler)( print_context, "%8" PRId32 "\n", used );
+ }
+
+
+}
+
+/*
+ * rtems_stack_checker_fatal_extension
+ */
+#ifndef DONT_USE_FATAL_EXTENSION
+ void rtems_stack_checker_fatal_extension(
+ Internal_errors_Source source,
+ bool is_internal,
+ uint32_t status
+ )
+ {
+ if (status == 0)
+ rtems_stack_checker_report_usage();
+ }
+#endif
+
+/*PAGE
+ *
+ * rtems_stack_checker_report_usage
+ */
+
+void rtems_stack_checker_report_usage_with_plugin(
+ void *context,
+ rtems_printk_plugin_t print
+)
+{
+ if ( !print )
+ return;
+
+ print_context = context;
+ print_handler = print;
+
+ (*print)( context, "Stack usage by thread\n");
+ (*print)( context,
+" ID NAME LOW HIGH CURRENT AVAILABLE USED\n"
+ );
+
+ /* iterate over all threads and dump the usage */
+ rtems_iterate_over_all_threads( Stack_check_Dump_threads_usage );
+
+ #if (CPU_ALLOCATE_INTERRUPT_STACK == TRUE)
+ /* dump interrupt stack info if any */
+ Stack_check_Dump_threads_usage((Thread_Control *) -1);
+ #endif
+
+ print_context = NULL;
+ print_handler = NULL;
+}
+
+void rtems_stack_checker_report_usage( void )
+{
+ rtems_stack_checker_report_usage_with_plugin( NULL, printk_plugin );
+}
diff --git a/cpukit/libmisc/stackchk/internal.h b/cpukit/libmisc/stackchk/internal.h
new file mode 100644
index 0000000000..a16a61e30e
--- /dev/null
+++ b/cpukit/libmisc/stackchk/internal.h
@@ -0,0 +1,95 @@
+/* internal.h
+ *
+ * This include file contains internal information
+ * for the RTEMS stack checker.
+ *
+ * COPYRIGHT (c) 1989-2006.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+
+#ifndef __INTERNAL_STACK_CHECK_h
+#define __INTERNAL_STACK_CHECK_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This structure is used to fill in and compare the "end of stack"
+ * marker pattern.
+ * pattern area must be a multiple of 4 words.
+ */
+
+#ifdef CPU_STACK_CHECK_SIZE
+#define PATTERN_SIZE_WORDS (((CPU_STACK_CHECK_SIZE / 4) + 3) & ~0x3)
+#else
+#define PATTERN_SIZE_WORDS (4)
+#endif
+
+#define PATTERN_SIZE_BYTES (PATTERN_SIZE_WORDS * sizeof(uint32_t))
+
+typedef struct {
+ uint32_t pattern[ PATTERN_SIZE_WORDS ];
+} Stack_check_Control;
+
+/*
+ * The pattern used to fill the entire stack.
+ */
+
+#define BYTE_PATTERN 0xA5
+#define U32_PATTERN 0xA5A5A5A5
+
+/*
+ * rtems_stack_checker_create_extension
+ */
+
+bool rtems_stack_checker_create_extension(
+ Thread_Control *running,
+ Thread_Control *the_thread
+);
+
+/*
+ * rtems_stack_checker_begin_extension
+ */
+
+void rtems_stack_checker_begin_extension(
+ Thread_Control *the_thread
+);
+
+/*
+ * rtems_stack_checker_switch_extension
+ */
+
+void rtems_stack_checker_switch_extension(
+ Thread_Control *running,
+ Thread_Control *heir
+);
+
+/*
+ * rtems_stack_checker_fatal_extension
+ */
+
+void rtems_stack_checker_fatal_extension(
+ Internal_errors_Source source,
+ bool is_internal,
+ uint32_t status
+);
+
+/*
+ * rtems_stack_checker_report_usage
+ */
+
+void rtems_stack_checker_report_usage( void );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+/* end of include file */
diff --git a/cpukit/libmisc/stackchk/stackchk.h b/cpukit/libmisc/stackchk/stackchk.h
new file mode 100644
index 0000000000..02bbac3a45
--- /dev/null
+++ b/cpukit/libmisc/stackchk/stackchk.h
@@ -0,0 +1,135 @@
+/** @file rtems/stackchk.h
+ *
+ * This include file contains information necessary to utilize
+ * and install the stack checker mechanism.
+ */
+
+/*
+ * COPYRIGHT (c) 1989-2007.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+
+#ifndef _RTEMS_STACKCHK_H
+#define _RTEMS_STACKCHK_H
+
+#include <stdbool.h> /* bool */
+
+#include <rtems/score/percpu.h> /* Thread_Control */
+#include <rtems/bspIo.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @brief Has Current Task Blown Its Stack
+ *
+ * This method is used to determine if the current stack pointer
+ * of the currently executing task is within bounds.
+ *
+ * @return This method returns true if the currently executing task
+ * has blown its stack.
+ *
+ */
+bool rtems_stack_checker_is_blown( void );
+
+/** @brief Print Stack Usage Report
+ *
+ * This method prints a stack usage report for the curently executing
+ * task.
+ *
+ * @note It uses printk to print the report.
+ */
+void rtems_stack_checker_report_usage( void );
+
+/** @brief Print Stack Usage Report
+ *
+ * This method prints a stack usage report for the curently executing
+ * task.
+ *
+ * @param[in] context is the context to pass to the print handler
+ * @param[in] print is the print handler
+ *
+ * @note It uses the caller's routine to print the report.
+ */
+void rtems_stack_checker_report_usage_with_plugin(
+ void *context,
+ rtems_printk_plugin_t print
+);
+
+/*************************************************************
+ *************************************************************
+ ** Prototyped only so the user extension can be installed **
+ *************************************************************
+ *************************************************************/
+
+/** @brief Stack Checker Task Create Extension
+ *
+ * This method is the task create extension for the stack checker.
+ *
+ * @param[in] running points to the currently executing task
+ * @param[in] the_thread points to the newly created task
+ *
+ * @note If this this the first task created, the stack checker
+ * will automatically intialize itself.
+ */
+bool rtems_stack_checker_create_extension(
+ Thread_Control *running,
+ Thread_Control *the_thread
+);
+
+/** @brief Stack Checker Task Begin Extension
+ *
+ * This method is the task begin extension for the stack checker.
+ *
+ * @param[in] the_thread points to task starting to execute
+ *
+ * @note This is called from the internal method _Thread_Handler.
+ */
+void rtems_stack_checker_begin_extension(
+ Thread_Control *the_thread
+);
+
+/** @brief Stack Checker Task Context Switch Extension
+ *
+ * This method is the task context switch extension for the stack checker.
+ *
+ * @param[in] running points to the currently executing task which
+ * is being context switched out
+ * @param[in] running points to the heir task which we are switching to
+ *
+ * @note This is called from the internal method _Thread_Dispatch.
+ */
+void rtems_stack_checker_switch_extension(
+ Thread_Control *running,
+ Thread_Control *heir
+);
+
+/** @brief Stack Checker Extension Set Definition
+ *
+ * This macro defines the user extension handler set for the stack
+ * checker. This macro is normally only used by confdefs.h.
+ */
+#define RTEMS_STACK_CHECKER_EXTENSION \
+{ \
+ rtems_stack_checker_create_extension, /* rtems_task_create */ \
+ 0, /* rtems_task_start */ \
+ 0, /* rtems_task_restart */ \
+ 0, /* rtems_task_delete */ \
+ rtems_stack_checker_switch_extension, /* task_switch */ \
+ rtems_stack_checker_begin_extension, /* task_begin */ \
+ 0, /* task_exitted */ \
+ 0 /* rtems_stack_checker_fatal_extension */, /* fatal */ \
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+/* end of include file */