summaryrefslogtreecommitdiffstats
path: root/cpukit/libmisc
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@OARcorp.com>1995-05-11 17:39:37 +0000
committerJoel Sherrill <joel.sherrill@OARcorp.com>1995-05-11 17:39:37 +0000
commitac7d5ef06a6d6e8d84abbd1f0b82162725f98326 (patch)
tree9304cf759a73f2a1c6fd3191948f00e870af3787 /cpukit/libmisc
downloadrtems-ac7d5ef06a6d6e8d84abbd1f0b82162725f98326.tar.bz2
Initial revision
Diffstat (limited to 'cpukit/libmisc')
-rw-r--r--cpukit/libmisc/README16
-rw-r--r--cpukit/libmisc/monitor/README7
-rw-r--r--cpukit/libmisc/monitor/mon-monitor.c307
-rw-r--r--cpukit/libmisc/monitor/mon-symbols.c327
-rw-r--r--cpukit/libmisc/monitor/monitor.h38
-rw-r--r--cpukit/libmisc/monitor/symbols.h80
-rw-r--r--cpukit/libmisc/stackchk/README41
-rw-r--r--cpukit/libmisc/stackchk/check.c439
-rw-r--r--cpukit/libmisc/stackchk/internal.h94
-rw-r--r--cpukit/libmisc/stackchk/stackchk.h41
10 files changed, 1390 insertions, 0 deletions
diff --git a/cpukit/libmisc/README b/cpukit/libmisc/README
new file mode 100644
index 0000000000..6825898121
--- /dev/null
+++ b/cpukit/libmisc/README
@@ -0,0 +1,16 @@
+#
+# $Id$
+#
+
+This directory contains for the "miscellaneous" library. Currently
+the only item in this library is a user extension set which checks
+for a task "blowing" it's stack.
+
+The following ideas have been mentioned for items which could go
+in this library, but this list is not all inclusive:
+
+ + Workspace Consistency Checker
+ + Task Execution Time Monitor
+
+The intent of this library is to provide a home for useful utility routines
+which are dependent upon RTEMS.
diff --git a/cpukit/libmisc/monitor/README b/cpukit/libmisc/monitor/README
new file mode 100644
index 0000000000..cae39d593c
--- /dev/null
+++ b/cpukit/libmisc/monitor/README
@@ -0,0 +1,7 @@
+#
+# $Id$
+#
+
+This is a snapshot of a work in process. It is the beginnings of a
+debug monitor task and trap handler which is tasking aware.
+
diff --git a/cpukit/libmisc/monitor/mon-monitor.c b/cpukit/libmisc/monitor/mon-monitor.c
new file mode 100644
index 0000000000..aa466143f9
--- /dev/null
+++ b/cpukit/libmisc/monitor/mon-monitor.c
@@ -0,0 +1,307 @@
+/*
+ * @(#)monitor.c 1.6 - 95/04/24
+ *
+ */
+
+/*
+ * mon-task.c
+ *
+ * Description:
+ * RTEMS monitor task
+ *
+ *
+ *
+ * TODO:
+ * add pause command (monitor sleeps for 'n' ticks, then wakes up)
+ *
+ */
+
+#include <rtems.h>
+/* #include <bsp.h> */
+
+#include "symbols.h"
+#include "monitor.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define STREQ(a,b) (strcmp(a,b) == 0)
+
+/* set by trap handler */
+extern rtems_tcb *debugger_interrupted_task;
+extern rtems_context *debugger_interrupted_task_context;
+extern rtems_unsigned32 debugger_trap;
+
+/* our task id needs to be public so any debugger can resume us */
+rtems_unsigned32 rtems_monitor_task_id;
+
+
+rtems_symbol_table_t *rtems_monitor_symbols;
+
+
+#ifndef MONITOR_PROMPT
+#define MONITOR_PROMPT "rtems> "
+#endif
+
+#define MONITOR_WAKEUP_EVENT RTEMS_EVENT_0
+
+/*
+ * Function: rtems_monitor_init
+ *
+ * Description:
+ * Create the RTEMS monitor task
+ *
+ * Parameters:
+ * 'monitor_suspend' arg is passed as initial arg to monitor task
+ * If TRUE, monitor will suspend itself as it starts up. Otherwise
+ * it will begin its command loop.
+ *
+ * Returns:
+ *
+ *
+ * Side Effects:
+ *
+ *
+ * Notes:
+ *
+ *
+ * Deficiencies/ToDo:
+ *
+ *
+ */
+
+/*
+ * make_argv(cp): token-count
+ * Break up the command line in 'cp' into global argv[] and argc (return
+ * value).
+ */
+
+int
+rtems_monitor_make_argv(
+ char *cp,
+ int *argc_p,
+ char **argv)
+{
+ int argc = 0;
+
+ while ((cp = strtok(cp, " \t\n\r")))
+ {
+ argv[argc++] = cp;
+ cp = (char *) NULL;
+ }
+ argv[argc] = (char *) NULL; /* end of argv */
+
+ return *argc_p = argc;
+}
+
+void
+rtems_monitor_init(rtems_boolean monitor_suspend)
+{
+ rtems_status_code status;
+
+ status = rtems_task_create(rtems_build_name('R', 'M', 'O', 'N'),
+ 1, 0/*stack*/, RTEMS_NO_PREEMPT | RTEMS_INTERRUPT_LEVEL(0), RTEMS_DEFAULT_ATTRIBUTES, &rtems_monitor_task_id);
+ if (status != RTEMS_SUCCESSFUL)
+ {
+ printf("could not create monitor task\n");
+ goto done;
+ }
+
+ rtems_monitor_symbols_loadup();
+
+ status = rtems_task_start(rtems_monitor_task_id, rtems_monitor_task, monitor_suspend);
+ if (status != RTEMS_SUCCESSFUL)
+ {
+ printf("could not start monitor!\n");
+ goto done;
+ }
+
+done:
+}
+
+rtems_status_code
+rtems_monitor_suspend(rtems_interval timeout)
+{
+ rtems_event_set event_set;
+ rtems_status_code status;
+
+ status = rtems_event_receive(MONITOR_WAKEUP_EVENT, RTEMS_DEFAULT_OPTIONS, timeout, &event_set);
+ return status;
+}
+
+void
+rtems_monitor_wakeup(void)
+{
+ rtems_status_code status;
+
+ status = rtems_event_send(rtems_monitor_task_id, MONITOR_WAKEUP_EVENT);
+}
+
+
+/*
+ * Read and break up a monitor command
+ *
+ * We have to loop on the gets call, since it will return NULL under UNIX
+ * RTEMS when we get a signal (eg: SIGALRM).
+ */
+
+int
+rtems_monitor_read_command(char *command,
+ int *argc,
+ char **argv)
+{
+ printf("%s", MONITOR_PROMPT); fflush(stdout);
+ while (gets(command) == (char *) 0)
+ ;
+ return rtems_monitor_make_argv(command, argc, argv);
+}
+
+void
+rtems_monitor_task(rtems_task_argument monitor_suspend)
+{
+ rtems_tcb *debugee = 0;
+ char command[513];
+ rtems_context *rp;
+ rtems_context_fp *fp;
+ char *cp;
+ int argc;
+ char *argv[64];
+
+ if ((rtems_boolean) monitor_suspend)
+ (void) rtems_monitor_suspend(RTEMS_NO_TIMEOUT);
+
+ for (;;)
+ {
+ extern rtems_tcb * _Thread_Executing;
+ debugee = _Thread_Executing;
+ rp = &debugee->Registers;
+ fp = (rtems_context_fp *) debugee->fp_context; /* possibly 0 */
+
+ if (0 == rtems_monitor_read_command(command, &argc, argv))
+ continue;
+
+ if (STREQ(argv[0], "quit"))
+ rtems_monitor_suspend(RTEMS_NO_TIMEOUT);
+ else if (STREQ(argv[0], "pause"))
+ rtems_monitor_suspend(1);
+
+#ifdef CPU_INVOKE_DEBUGGER
+ else if (STREQ(argv[0], "debug"))
+ {
+ CPU_INVOKE_DEBUGGER;
+ }
+#endif
+ else if (STREQ(argv[0], "symbol"))
+ {
+ char *symbol;
+ char *value;
+
+ if (argc != 3)
+ {
+ printf("usage: symbol symname symvalue\n");
+ continue;
+ }
+
+ symbol = argv[1];
+ value = argv[2];
+ if (symbol && value)
+ {
+ rtems_symbol_t *sp;
+ sp = rtems_symbol_create(rtems_monitor_symbols,
+ symbol,
+ (rtems_unsigned32) strtoul(value, 0, 16));
+ if (sp)
+ printf("symbol defined is at %p\n", sp);
+ else
+ printf("could not define symbol\n");
+ }
+ else
+ printf("parsing error\n");
+ }
+ else
+ {
+ printf("Unrecognized command: '%s'\n", argv[0]);
+ }
+ }
+}
+
+/*
+ * Function: rtems_monitor_symbols_loadup
+ *
+ * Description:
+ * Create and load the monitor's symbol table.
+ * We are reading the output format of 'gnm' which looks like this:
+ *
+ * 400a7068 ? _Rate_monotonic_Information
+ * 400a708c ? _Thread_Dispatch_disable_level
+ * 400a7090 ? _Configuration_Table
+ *
+ *
+ * We ignore the type field.
+ *
+ * Parameters:
+ *
+ *
+ * Returns:
+ *
+ *
+ * Side Effects:
+ * Creates and fills in 'rtems_monitor_symbols' table
+ *
+ * Notes:
+ *
+ *
+ * Deficiencies/ToDo:
+ * Someday this should know BFD
+ * Maybe we could get objcopy to just copy the symbol areas
+ * and copy that down.
+ *
+ */
+
+void
+rtems_monitor_symbols_loadup(void)
+{
+ FILE *fp;
+ char buffer[128];
+
+ rtems_monitor_symbols = rtems_symbol_table_create(10);
+ if (rtems_monitor_symbols == 0)
+ return;
+
+ fp = fdopen(8, "r");
+ if (fp == 0)
+ return;
+
+ while (fgets(buffer, sizeof(buffer) - 1, fp))
+ {
+ char *symbol;
+ char *value;
+ char *ignored_type;
+
+ value = strtok(buffer, " \t\n");
+ ignored_type = strtok(0, " \t\n");
+ symbol = strtok(0, " \t\n");
+
+ if (symbol && ignored_type && value)
+ {
+ rtems_symbol_t *sp;
+ sp = rtems_symbol_create(rtems_monitor_symbols,
+ symbol,
+ (rtems_unsigned32) strtoul(value, 0, 16));
+ if (sp == 0)
+ {
+ printf("could not define symbol\n");
+ goto done;
+ }
+ }
+ else
+ {
+ printf("parsing error\n");
+ goto done;
+ }
+ }
+
+done:
+}
diff --git a/cpukit/libmisc/monitor/mon-symbols.c b/cpukit/libmisc/monitor/mon-symbols.c
new file mode 100644
index 0000000000..58d35befa1
--- /dev/null
+++ b/cpukit/libmisc/monitor/mon-symbols.c
@@ -0,0 +1,327 @@
+/*
+ * @(#)symbols.c 1.3 - 95/04/24
+ *
+ */
+
+/* #define qsort _quicksort */
+
+/*
+ * File: symbols.c
+ *
+ * Description:
+ * Symbol table manager for the RTEMS monitor.
+ * These routines may be used by other system resources also.
+ *
+ *
+ * TODO:
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <rtems.h>
+
+#include "symbols.h"
+
+extern rtems_symbol_table_t *rtems_monitor_symbols;
+
+#ifdef RTEMS_DEBUG
+#define CHK_ADR_PTR(p) \
+do { \
+ if (((p) < rtems_monitor_symbols->addresses) || \
+ ((p) >= (rtems_monitor_symbols->addresses + rtems_monitor_symbols->next))) \
+ { \
+ printf("bad address pointer %p\n", (p)); \
+ rtems_fatal_error_occurred(RTEMS_INVALID_ADDRESS); \
+ } \
+} while (0)
+
+#define CHK_NAME_PTR(p) \
+do { \
+ if (((p) < rtems_monitor_symbols->symbols) || \
+ ((p) >= (rtems_monitor_symbols->symbols + rtems_monitor_symbols->next))) \
+ { \
+ printf("bad symbol pointer %p\n", (p)); \
+ rtems_fatal_error_occurred(RTEMS_INVALID_ADDRESS); \
+ } \
+} while (0)
+#else
+#define CHK_ADR_PTR(p)
+#define CHK_NAME_PTR(p)
+#endif
+
+rtems_symbol_table_t *
+rtems_symbol_table_create()
+{
+ rtems_symbol_table_t *table;
+
+ table = (rtems_symbol_table_t *) malloc(sizeof(rtems_symbol_table_t));
+ memset((void *) table, 0, sizeof(*table));
+
+ table->growth_factor = 30; /* 30 percent */
+
+ return table;
+}
+
+void
+rtems_symbol_table_destroy(rtems_symbol_table_t *table)
+{
+ rtems_symbol_string_block_t *p, *pnext;
+
+ if (table)
+ {
+ if (table->addresses)
+ (void) free(table->addresses);
+ table->addresses = 0;
+
+ if (table->symbols)
+ (void) free(table->symbols);
+ table->symbols = 0;
+
+ p = table->string_buffer_head;
+ while (p)
+ {
+ pnext = p->next;
+ free(p);
+ p = pnext;
+ }
+ table->string_buffer_head = 0;
+ table->string_buffer_current = 0;
+
+ free(table);
+ }
+}
+
+rtems_symbol_t *
+rtems_symbol_create(
+ rtems_symbol_table_t *table,
+ char *name,
+ rtems_unsigned32 value
+ )
+{
+ int symbol_length;
+ size_t newsize;
+ rtems_symbol_t *sp;
+
+ symbol_length = strlen(name) + 1; /* include '\000' in length */
+
+ /* need to grow the table? */
+ if (table->next >= table->size)
+ {
+ if (table->size == 0)
+ newsize = 100;
+ else
+ newsize = table->size + (table->size / (100 / table->growth_factor));
+
+ table->addresses = (rtems_symbol_t *) realloc((void *) table->addresses, newsize * sizeof(rtems_symbol_t));
+ if (table->addresses == 0) /* blew it; lost orig */
+ goto failed;
+
+ table->symbols = (rtems_symbol_t *) realloc((void *) table->symbols, newsize * sizeof(rtems_symbol_t));
+ if (table->symbols == 0) /* blew it; lost orig */
+ goto failed;
+
+ table->size = newsize;
+ }
+
+ sp = &table->addresses[table->next];
+ sp->value = value;
+
+ /* Have to add it to string pool */
+ /* need to grow pool? */
+
+ if ((table->string_buffer_head == 0) ||
+ (table->strings_next + symbol_length) >= SYMBOL_STRING_BLOCK_SIZE)
+ {
+ rtems_symbol_string_block_t *p;
+
+ p = (rtems_symbol_string_block_t *) malloc(sizeof(rtems_symbol_string_block_t));
+ if (p == 0)
+ goto failed;
+ p->next = 0;
+ if (table->string_buffer_head == 0)
+ table->string_buffer_head = p;
+ else
+ table->string_buffer_current->next = p;
+ table->string_buffer_current = p;
+
+ table->strings_next = 0;
+ }
+
+ sp->name = table->string_buffer_current->buffer + table->strings_next;
+ (void) strcpy(sp->name, name);
+
+ table->strings_next += symbol_length;
+
+ table->symbols[table->next] = *sp;
+
+ table->sorted = 0;
+ table->next++;
+
+ return sp;
+
+/* XXX Not sure what to do here. We've possibly destroyed the initial
+ symbol table due to realloc failure */
+failed:
+ return 0;
+}
+
+/*
+ * Qsort entry point for compare by address
+ */
+
+int
+rtems_symbol_compare(const void *e1,
+ const void *e2)
+{
+ rtems_symbol_t *s1, *s2;
+ s1 = (rtems_symbol_t *) e1;
+ s2 = (rtems_symbol_t *) e2;
+
+ CHK_ADR_PTR(s1);
+ CHK_ADR_PTR(s2);
+
+ if (s1->value < s2->value)
+ return -1;
+ if (s1->value > s2->value)
+ return 1;
+ return 0;
+}
+
+/*
+ * Qsort entry point for compare by string name (case independent)
+ */
+
+int
+rtems_symbol_string_compare(const void *e1,
+ const void *e2)
+{
+ rtems_symbol_t *s1, *s2;
+ s1 = (rtems_symbol_t *) e1;
+ s2 = (rtems_symbol_t *) e2;
+
+ CHK_NAME_PTR(s1);
+ CHK_NAME_PTR(s2);
+
+ return strcasecmp(s1->name, s2->name);
+}
+
+
+/*
+ * Sort the symbol table using qsort
+ */
+
+void
+rtems_symbol_sort(rtems_symbol_table_t *table)
+{
+#ifdef simhppa
+ printf("Sorting symbols ... "); /* so slow we need a msg */
+ fflush(stdout);
+#endif
+
+ qsort((void *) table->addresses, (size_t) table->next,
+ sizeof(rtems_symbol_t), rtems_symbol_compare);
+
+ qsort((void *) table->symbols, (size_t) table->next,
+ sizeof(rtems_symbol_t), rtems_symbol_string_compare);
+
+#ifdef simhppa
+ /* so slow we need a msg */
+ printf("done\n");
+#endif
+
+ table->sorted = 1;
+}
+
+/*
+ * Search the symbol table by address
+ * This code based on CYGNUS newlib bsearch, but changed
+ * to allow for finding closest symbol <= key
+ */
+
+rtems_symbol_t *
+rtems_symbol_value_lookup(
+ rtems_symbol_table_t *table,
+ rtems_unsigned32 value
+ )
+{
+ rtems_symbol_t *sp;
+ rtems_symbol_t *base;
+ rtems_symbol_t *best = 0;
+ rtems_unsigned32 distance;
+ rtems_unsigned32 best_distance = ~0;
+ rtems_unsigned32 elements;
+
+ if ((table == 0) || (table->size == 0))
+ return 0;
+
+ if (table->sorted == 0)
+ rtems_symbol_sort(table);
+
+ base = table->addresses;
+ elements = table->next;
+
+ while (elements)
+ {
+ sp = base + (elements / 2);
+ if (value < sp->value)
+ elements /= 2;
+ else if (value > sp->value)
+ {
+ distance = value - sp->value;
+ if (distance < best_distance)
+ {
+ best_distance = distance;
+ best = sp;
+ }
+ base = sp + 1;
+ elements = (elements / 2) - (elements % 2 ? 0 : 1);
+ }
+ else
+ return sp;
+ }
+
+ if (value == base->value)
+ return base;
+
+ return best;
+}
+
+/*
+ * Search the symbol table by string name (case independent)
+ */
+
+rtems_symbol_t *
+rtems_symbol_name_lookup(
+ rtems_symbol_table_t *table,
+ char *name
+ )
+{
+ rtems_symbol_t *sp = 0;
+ rtems_symbol_t key;
+
+ if ((table == 0) || (name == 0))
+ goto done;
+
+ if (table->sorted == 0)
+ {
+ rtems_symbol_sort(table);
+ }
+
+ /*
+ * dummy up one for bsearch()
+ */
+
+ key.name = name;
+ key.value = 0;
+
+ sp = (rtems_symbol_t *) bsearch((const void *) &key,
+ (const void *) table->symbols,
+ (size_t) table->next,
+ sizeof(rtems_symbol_t),
+ rtems_symbol_string_compare);
+
+done:
+ return sp;
+}
+
diff --git a/cpukit/libmisc/monitor/monitor.h b/cpukit/libmisc/monitor/monitor.h
new file mode 100644
index 0000000000..195aa73695
--- /dev/null
+++ b/cpukit/libmisc/monitor/monitor.h
@@ -0,0 +1,38 @@
+/*
+ * @(#)monitor.h 1.2 - 95/04/24
+ *
+ */
+
+/*
+ * File: monitor.h
+ *
+ * Description:
+ * The RTEMS monitor task include file.
+ *
+ *
+ *
+ * TODO:
+ *
+ */
+
+#ifndef __MONITOR_H
+#define __MONITOR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void rtems_monitor_init(rtems_boolean monitor_suspend);
+void rtems_monitor_wakeup(void);
+void rtems_monitor_task(rtems_task_argument monitor_suspend);
+void rtems_monitor_symbols_loadup(void);
+
+extern rtems_unsigned32 rtems_monitor_task_id;
+
+extern rtems_symbol_table_t *rtems_monitor_symbols;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ! __MONITOR_H */
diff --git a/cpukit/libmisc/monitor/symbols.h b/cpukit/libmisc/monitor/symbols.h
new file mode 100644
index 0000000000..680ac6d2cf
--- /dev/null
+++ b/cpukit/libmisc/monitor/symbols.h
@@ -0,0 +1,80 @@
+/*
+ * File: symbols.h
+ *
+ * Description:
+ * Entry points for symbol table routines.
+ *
+ *
+ *
+ * TODO:
+ *
+ */
+
+#ifndef _INCLUDE_SYMBOLS_H
+#define _INCLUDE_SYMBOLS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+ rtems_unsigned32 value;
+ char *name;
+} rtems_symbol_t;
+
+#define SYMBOL_STRING_BLOCK_SIZE 4080
+typedef struct rtems_symbol_string_block_s {
+ struct rtems_symbol_string_block_s *next;
+ char buffer[SYMBOL_STRING_BLOCK_SIZE];
+} rtems_symbol_string_block_t;
+
+typedef struct {
+
+ rtems_unsigned32 sorted; /* are symbols sorted right now? */
+
+ rtems_unsigned32 growth_factor; /* % to grow by when needed */
+
+ rtems_unsigned32 next; /* next symbol slot to use when adding */
+ rtems_unsigned32 size; /* max # of symbols */
+
+ /*
+ * Symbol list -- sorted by address (when we do a lookup)
+ */
+
+ rtems_symbol_t *addresses; /* symbol array by address */
+
+ /*
+ * String list -- sorted by name (when we do a lookup)
+ * This is a duplicate of the info in table->addresses, but it's
+ * pretty small, so I don't worry about it.
+ */
+
+ rtems_symbol_t *symbols; /* symbol array */
+
+ /*
+ * String pool, unsorted, a list of blocks of string data
+ */
+
+ rtems_symbol_string_block_t *string_buffer_head;
+ rtems_symbol_string_block_t *string_buffer_current;
+ rtems_unsigned32 strings_next; /* next byte to use in this block */
+
+} rtems_symbol_table_t;
+
+void rtems_symbol_table_destroy(rtems_symbol_table_t *table);
+rtems_symbol_table_t *rtems_symbol_table_create();
+rtems_symbol_t *rtems_symbol_create(rtems_symbol_table_t *,
+ char *, rtems_unsigned32);
+rtems_symbol_t *rtems_symbol_value_lookup(rtems_symbol_table_t *,
+ rtems_unsigned32);
+rtems_symbol_t *rtems_symbol_name_lookup(rtems_symbol_table_t *,
+ char *);
+
+#define rtems_symbol_name(sp) ((sp)->name)
+#define rtems_symbol_value(sp) ((sp)->value)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ! _INCLUDE_SYMBOLS_H */
diff --git a/cpukit/libmisc/stackchk/README b/cpukit/libmisc/stackchk/README
new file mode 100644
index 0000000000..20e76f07bc
--- /dev/null
+++ b/cpukit/libmisc/stackchk/README
@@ -0,0 +1,41 @@
+#
+# $Id$
+#
+
+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
+
+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.
+
+2. Get accurate stack usage numbers on i960.. it pushes very large
+ holes on the stack.
diff --git a/cpukit/libmisc/stackchk/check.c b/cpukit/libmisc/stackchk/check.c
new file mode 100644
index 0000000000..8b923f5c02
--- /dev/null
+++ b/cpukit/libmisc/stackchk/check.c
@@ -0,0 +1,439 @@
+/*
+ * 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, 1990, 1991, 1992, 1993, 1994.
+ * On-Line Applications Research Corporation (OAR).
+ * All rights assigned to U.S. Government, 1994.
+ *
+ * This material may be reproduced by or for the U.S. Government pursuant
+ * to the copyright license under the clause at DFARS 252.227-7013. This
+ * notice must appear in all copies of this file and its derivatives.
+ *
+ * $Id$
+ *
+ */
+
+#include <rtems/system.h>
+#include <rtems/extension.h>
+#include <rtems/fatal.h>
+#include <rtems/heap.h>
+#include <rtems/stack.h>
+#include <rtems/thread.h>
+#ifdef XXX_RTEMS_H_FIXED
+#include <bsp.h>
+#else
+#include <rtems/config.h>
+extern rtems_configuration_table BSP_Configuration;
+#endif
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "stackchk.h"
+#include "internal.h"
+
+/*
+ * This variable contains the name of the task which "blew" the stack.
+ * It is NULL if the system is all right.
+ */
+
+Thread_Control *Stack_check_Blown_task;
+
+/*
+ * The extension table for the stack checker.
+ */
+
+rtems_extensions_table Stack_check_Extension_table = {
+ Stack_check_Create_extension, /* rtems_task_create */
+ 0, /* rtems_task_start */
+ 0, /* rtems_task_restart */
+ 0, /* rtems_task_delete */
+ Stack_check_Switch_extension, /* task_switch */
+ Stack_check_Begin_extension, /* task_begin */
+ 0, /* task_exitted */
+ Stack_check_Fatal_extension, /* fatal */
+};
+
+/*
+ * The "magic pattern" used to mark the end of the stack.
+ */
+
+Stack_check_Control Stack_check_Pattern;
+
+/*
+ * 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_area( _the_stack ) \
+ ((Stack_check_Control *) \
+ ((_the_stack)->area + (_the_stack)->size - sizeof( Stack_check_Control ) ))
+
+#define Stack_check_Calculate_used( _low, _size, _high_water ) \
+ ((_high_water) - (_low))
+
+#define Stack_check_usable_stack_start(_the_stack) \
+ ((_the_stack)->area)
+
+#else
+
+#define Stack_check_Get_pattern_area( _the_stack ) \
+ ((Stack_check_Control *) ((_the_stack)->area + HEAP_OVERHEAD))
+
+#define Stack_check_Calculate_used( _low, _size, _high_water) \
+ ( ((_low) + (_size)) - (_high_water) )
+
+#define Stack_check_usable_stack_start(_the_stack) \
+ ((_the_stack)->area + sizeof(Stack_check_Control))
+
+#endif
+
+#define Stack_check_usable_stack_size(_the_stack) \
+ ((_the_stack)->size - sizeof(Stack_check_Control))
+
+
+/*
+ * Do we have an interrupt stack?
+ * XXX it would sure be nice if the interrupt stack were also
+ * stored in a "stack" structure!
+ */
+
+
+Stack_Control stack_check_interrupt_stack;
+
+/*
+ * Fill an entire stack area with BYTE_PATTERN.
+ * This will be used by a Fatal extension to check for
+ * amount of actual stack used
+ */
+
+void
+stack_check_dope_stack(Stack_Control *stack)
+{
+ memset(stack->area, BYTE_PATTERN, stack->size);
+}
+
+
+/*PAGE
+ *
+ * Stack_check_Initialize
+ */
+
+unsigned32 stack_check_initialized = 0;
+
+void Stack_check_Initialize( void )
+{
+ rtems_status_code status;
+ Objects_Id id_ignored;
+ unsigned32 *p;
+
+ if (stack_check_initialized)
+ return;
+
+ /*
+ * Dope the pattern and fill areas
+ */
+
+ for ( p = Stack_check_Pattern.pattern;
+ p < &Stack_check_Pattern.pattern[PATTERN_SIZE_WORDS];
+ p += 4
+ )
+ {
+ p[0] = 0xFEEDF00D; /* FEED FOOD to BAD DOG */
+ p[1] = 0x0BAD0D06;
+ p[2] = 0xDEADF00D; /* DEAD FOOD GOOD DOG */
+ p[3] = 0x600D0D06;
+ };
+
+ status = rtems_extension_create(
+ rtems_build_name( 'S', 'T', 'C', 'K' ),
+ &Stack_check_Extension_table,
+ &id_ignored
+ );
+ assert ( status == RTEMS_SUCCESSFUL );
+
+ Stack_check_Blown_task = 0;
+
+ /*
+ * If installed by a task, that task will not get setup properly
+ * since it missed out on the create hook. This will cause a
+ * failure on first switch out of that task.
+ * So pretend here that we actually ran create and begin extensions.
+ */
+
+ if (_Thread_Executing)
+ {
+ Stack_check_Create_extension(_Thread_Executing, _Thread_Executing);
+ }
+
+ /*
+ * If appropriate, setup the interrupt stack for high water testing
+ * also.
+ */
+ if (_CPU_Interrupt_stack_low && _CPU_Interrupt_stack_high)
+ {
+ stack_check_interrupt_stack.area = _CPU_Interrupt_stack_low;
+ stack_check_interrupt_stack.size = _CPU_Interrupt_stack_high -
+ _CPU_Interrupt_stack_low;
+
+ stack_check_dope_stack(&stack_check_interrupt_stack);
+ }
+
+ stack_check_initialized = 1;
+}
+
+/*PAGE
+ *
+ * Stack_check_Create_extension
+ */
+
+void Stack_check_Create_extension(
+ Thread_Control *running,
+ Thread_Control *the_thread
+)
+{
+ if (the_thread && (the_thread != _Thread_Executing))
+ stack_check_dope_stack(&the_thread->Start.Initial_stack);
+}
+
+/*PAGE
+ *
+ * Stack_check_Begin_extension
+ */
+
+void Stack_check_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;
+}
+
+/*PAGE
+ *
+ * Stack_check_report_blown_task
+ * Report a blown stack. Needs to be a separate routine
+ * so that interrupt handlers can use this too.
+ *
+ * Caller must have set the Stack_check_Blown_task.
+ *
+ * NOTE: The system is in a questionable state... we may not get
+ * the following message out.
+ */
+
+void Stack_check_report_blown_task(void)
+{
+ Stack_Control *stack;
+ Thread_Control *running;
+
+ running = Stack_check_Blown_task;
+ stack = &running->Start.Initial_stack;
+
+ fprintf(
+ stderr,
+ "BLOWN STACK!!! Offending task(%p): id=0x%08x; name=0x%08x",
+ running,
+ running->Object.id,
+ running->name);
+ fflush(stderr);
+
+ if (BSP_Configuration.User_multiprocessing_table)
+ fprintf(
+ stderr,
+ "; node=%d\n",
+ BSP_Configuration.User_multiprocessing_table->node
+ );
+ else
+ fprintf(stderr, "\n");
+ fflush(stderr);
+
+ fprintf(
+ stderr,
+ " stack covers range 0x%08x - 0x%08x (%d bytes)\n",
+ (unsigned32) stack->area,
+ (unsigned32) stack->area + stack->size - 1,
+ (unsigned32) stack->size);
+ fflush(stderr);
+
+ fprintf(
+ stderr,
+ " Damaged pattern begins at 0x%08x and is %d bytes long\n",
+ (unsigned32) Stack_check_Get_pattern_area(stack), PATTERN_SIZE_BYTES);
+ fflush(stderr);
+
+ rtems_fatal_error_occurred( (unsigned32) "STACK BLOWN" );
+}
+
+/*PAGE
+ *
+ * Stack_check_Switch_extension
+ */
+
+void Stack_check_Switch_extension(
+ Thread_Control *running,
+ Thread_Control *heir
+)
+{
+ if ( running->Object.id == 0 ) /* skip system tasks */
+ return;
+
+ if (0 != memcmp( (void *) Stack_check_Get_pattern_area( &running->Start.Initial_stack)->pattern,
+ (void *) Stack_check_Pattern.pattern,
+ PATTERN_SIZE_BYTES))
+ {
+ Stack_check_Blown_task = running;
+ Stack_check_report_blown_task();
+ }
+}
+
+void *Stack_check_find_high_water_mark(
+ const void *s,
+ size_t n
+)
+{
+ const unsigned32 *base, *ebase;
+ unsigned32 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
+ */
+
+ for (ebase = base + length; base < ebase; base++)
+ if (*base != U32_PATTERN)
+ return (void *) base;
+#endif
+
+ return (void *)0;
+}
+
+/*PAGE
+ *
+ * Stack_check_Dump_threads_usage
+ * Try to print out how much stack was actually used by the task.
+ *
+ */
+
+void Stack_check_Dump_threads_usage(
+ Thread_Control *the_thread
+)
+{
+ unsigned32 size, used;
+ void *low;
+ void *high_water_mark;
+ Stack_Control *stack;
+
+ if ( !the_thread )
+ return;
+
+ /*
+ * XXX HACK to get to interrupt stack
+ */
+
+ if (the_thread == (Thread_Control *) -1)
+ {
+ if (stack_check_interrupt_stack.area)
+ {
+ stack = &stack_check_interrupt_stack;
+ the_thread = 0;
+ }
+ else
+ return;
+ }
+ else
+ stack = &the_thread->Start.Initial_stack;
+
+ 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;
+
+ printf( "0x%08x 0x%08x 0x%08x 0x%08x %8d %8d\n",
+ the_thread ? the_thread->Object.id : ~0,
+ the_thread ? the_thread->name :
+ rtems_build_name('I', 'N', 'T', 'R'),
+ (unsigned32) stack->area,
+ (unsigned32) stack->area + (unsigned32) stack->size - 1,
+ size,
+ used
+ );
+}
+
+/*PAGE
+ *
+ * Stack_check_Fatal_extension
+ */
+
+void Stack_check_Fatal_extension( unsigned32 status )
+{
+ if (status == 0)
+ Stack_check_Dump_usage();
+}
+
+
+/*PAGE
+ *
+ * Stack_check_Dump_usage
+ */
+
+void Stack_check_Dump_usage( void )
+{
+ unsigned32 i;
+ Thread_Control *the_thread;
+ unsigned32 hit_running = 0;
+
+ if (stack_check_initialized == 0)
+ return;
+
+ printf(
+ " ID NAME LOW HIGH AVAILABLE USED\n"
+ );
+ for ( i=1 ; i<_Thread_Information.maximum ; i++ ) {
+ the_thread = (Thread_Control *)_Thread_Information.local_table[ i ];
+ Stack_check_Dump_threads_usage( the_thread );
+ if ( the_thread == _Thread_Executing )
+ hit_running = 1;
+ }
+
+ if ( !hit_running )
+ Stack_check_Dump_threads_usage( _Thread_Executing );
+
+ /* dump interrupt stack info if any */
+ Stack_check_Dump_threads_usage((Thread_Control *) -1);
+}
+
diff --git a/cpukit/libmisc/stackchk/internal.h b/cpukit/libmisc/stackchk/internal.h
new file mode 100644
index 0000000000..19c9f5e267
--- /dev/null
+++ b/cpukit/libmisc/stackchk/internal.h
@@ -0,0 +1,94 @@
+/* internal.h
+ *
+ * This include file contains internal information
+ * for the RTEMS stack checker.
+ *
+ * COPYRIGHT (c) 1989, 1990, 1991, 1992, 1993, 1994.
+ * On-Line Applications Research Corporation (OAR).
+ * All rights assigned to U.S. Government, 1994.
+ *
+ * This material may be reproduced by or for the U.S. Government pursuant
+ * to the copyright license under the clause at DFARS 252.227-7013. This
+ * notice must appear in all copies of this file and its derivatives.
+ *
+ * $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 * 4)
+
+typedef struct {
+ unsigned32 pattern[ PATTERN_SIZE_WORDS ];
+} Stack_check_Control;
+
+/*
+ * The pattern used to fill the entire stack.
+ */
+
+#define BYTE_PATTERN 0xA5
+#define U32_PATTERN 0xA5A5A5A5
+
+/*
+ * Stack_check_Create_extension
+ */
+
+void Stack_check_Create_extension(
+ Thread_Control *running,
+ Thread_Control *the_thread
+);
+
+/*
+ * Stack_check_Begin_extension
+ */
+
+void Stack_check_Begin_extension(
+ Thread_Control *the_thread
+);
+
+/*
+ * Stack_check_Switch_extension
+ */
+
+void Stack_check_Switch_extension(
+ Thread_Control *running,
+ Thread_Control *heir
+);
+
+/*
+ * Stack_check_Fatal_extension
+ */
+
+void Stack_check_Fatal_extension(
+ unsigned32
+);
+
+/*
+ * Stack_check_Dump_usage
+ */
+
+void Stack_check_Dump_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..f3281c63fe
--- /dev/null
+++ b/cpukit/libmisc/stackchk/stackchk.h
@@ -0,0 +1,41 @@
+/* stackchk.h
+ *
+ * This include file contains information necessary to utilize
+ * and install the stack checker mechanism.
+ *
+ * COPYRIGHT (c) 1989, 1990, 1991, 1992, 1993, 1994.
+ * On-Line Applications Research Corporation (OAR).
+ * All rights assigned to U.S. Government, 1994.
+ *
+ * This material may be reproduced by or for the U.S. Government pursuant
+ * to the copyright license under the clause at DFARS 252.227-7013. This
+ * notice must appear in all copies of this file and its derivatives.
+ *
+ * $Id$
+ */
+
+#ifndef __STACK_CHECK_h
+#define __STACK_CHECK_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Stack_check_Initialize
+ */
+
+void Stack_check_Initialize( void );
+
+/*
+ * Stack_check_Dump_usage
+ */
+
+void Stack_check_Dump_usage( void );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+/* end of include file */