forked from Imagelibrary/rtems
2007-05-11 Joel Sherrill <joel.sherrill@OARcorp.com>
* libmisc/cpuuse/cpuuse.c, libmisc/stackchk/check.c, libmisc/stackchk/stackchk.h: Clean up as side-effect of making them suitable for inclusion in the Users Guide.
This commit is contained in:
@@ -25,12 +25,9 @@
|
||||
#include <inttypes.h>
|
||||
|
||||
/*
|
||||
* HACK
|
||||
* the stack dump information should be printed by a "fatal" extension.
|
||||
* 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.
|
||||
* I hope/think this is changing so that fatal extensions are renamed
|
||||
* to "shutdown" extensions.
|
||||
* When that happens, this #define should be deleted and all the code
|
||||
* it marks.
|
||||
*/
|
||||
@@ -45,27 +42,13 @@
|
||||
#include "internal.h"
|
||||
|
||||
/*
|
||||
* The extension table for the stack checker.
|
||||
* Variable to indicate when the stack checker has been initialized.
|
||||
*/
|
||||
|
||||
rtems_extensions_table rtems_stack_checker_extension_table = {
|
||||
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 */
|
||||
#ifdef DONT_USE_FATAL_EXTENSION
|
||||
0, /* fatal */
|
||||
#else
|
||||
rtems_stack_checker_fatal_extension, /* fatal */
|
||||
#endif
|
||||
};
|
||||
static int Stack_check_Initialized = 0;
|
||||
|
||||
/*
|
||||
* The "magic pattern" used to mark the end of the stack.
|
||||
*/
|
||||
|
||||
Stack_check_Control Stack_check_Pattern;
|
||||
|
||||
/*
|
||||
@@ -73,7 +56,6 @@ Stack_check_Control Stack_check_Pattern;
|
||||
*
|
||||
* NOTE: This uses a GCC specific method.
|
||||
*/
|
||||
|
||||
static inline boolean Stack_check_Frame_pointer_in_range(
|
||||
Stack_Control *the_stack
|
||||
)
|
||||
@@ -89,6 +71,8 @@ static inline boolean Stack_check_Frame_pointer_in_range(
|
||||
printk( "Stack Pointer Too High!\n" );
|
||||
return FALSE;
|
||||
}
|
||||
#else
|
||||
#error "How do I check stack bounds on a non-GNU compiler?"
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
@@ -96,72 +80,59 @@ static inline boolean Stack_check_Frame_pointer_in_range(
|
||||
/*
|
||||
* 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 )
|
||||
#if (CPU_STACK_GROWS_UP == TRUE)
|
||||
#define Stack_check_Get_pattern_area( _the_stack ) \
|
||||
((Stack_check_Control *) ((char *)(_the_stack)->area + \
|
||||
(_the_stack)->size - sizeof( Stack_check_Control ) ))
|
||||
|
||||
#define Stack_check_Get_pattern_area( _the_stack ) \
|
||||
((Stack_check_Control *) ((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_Calculate_used( _low, _size, _high_water ) \
|
||||
((char *)(_high_water) - (char *)(_low))
|
||||
|
||||
#define Stack_check_usable_stack_start(_the_stack) \
|
||||
#define Stack_check_usable_stack_start(_the_stack) \
|
||||
((_the_stack)->area)
|
||||
|
||||
#else
|
||||
#define Stack_check_Get_pattern_area( _the_stack ) \
|
||||
((Stack_check_Control *) ((char *)(_the_stack)->area + HEAP_OVERHEAD))
|
||||
|
||||
#define Stack_check_Calculate_used( _low, _size, _high_water) \
|
||||
( ((char *)(_low) + (_size)) - (char *)(_high_water) )
|
||||
|
||||
#define Stack_check_Get_pattern_area( _the_stack ) \
|
||||
((Stack_check_Control *) ((char *)(_the_stack)->area + HEAP_OVERHEAD))
|
||||
|
||||
#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))
|
||||
#define Stack_check_usable_stack_start(_the_stack) \
|
||||
((char *)(_the_stack)->area + sizeof(Stack_check_Control))
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 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))
|
||||
|
||||
|
||||
/*
|
||||
* 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;
|
||||
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
|
||||
* 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)
|
||||
|
||||
void
|
||||
stack_check_dope_stack(Stack_Control *stack)
|
||||
{
|
||||
memset(stack->area, BYTE_PATTERN, stack->size);
|
||||
}
|
||||
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
* rtems_stack_checker_initialize
|
||||
/*
|
||||
* Stack_check_Initialize
|
||||
*/
|
||||
|
||||
static int stack_check_initialized = 0;
|
||||
|
||||
void rtems_stack_checker_initialize( void )
|
||||
void Stack_check_Initialize( void )
|
||||
{
|
||||
uint32_t *p;
|
||||
uint32_t *p;
|
||||
|
||||
if (stack_check_initialized)
|
||||
if (Stack_check_Initialized)
|
||||
return;
|
||||
|
||||
/*
|
||||
@@ -171,83 +142,54 @@ void rtems_stack_checker_initialize( void )
|
||||
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;
|
||||
};
|
||||
|
||||
/*
|
||||
* 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 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);
|
||||
#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
|
||||
#endif
|
||||
|
||||
#ifdef DONT_USE_FATAL_EXTENSION
|
||||
#ifdef RTEMS_DEBUG
|
||||
/*
|
||||
* this would normally be called by a fatal extension
|
||||
* handler, but we don't run fatal extensions unless
|
||||
* we fatal error.
|
||||
*/
|
||||
atexit(rtems_stack_checker_report_usage);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
stack_check_initialized = 1;
|
||||
Stack_check_Initialized = 1;
|
||||
}
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
/*
|
||||
* rtems_stack_checker_create_extension
|
||||
*/
|
||||
|
||||
boolean rtems_stack_checker_create_extension(
|
||||
Thread_Control *running,
|
||||
Thread_Control *the_thread
|
||||
)
|
||||
{
|
||||
if (!stack_check_initialized)
|
||||
rtems_stack_checker_initialize();
|
||||
Stack_check_Initialize();
|
||||
|
||||
if (the_thread /* XXX && (the_thread != _Thread_Executing) */ )
|
||||
stack_check_dope_stack(&the_thread->Start.Initial_stack);
|
||||
if (the_thread)
|
||||
Stack_check_Dope_stack(&the_thread->Start.Initial_stack);
|
||||
|
||||
return TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
/*
|
||||
* rtems_stack_checker_Begin_extension
|
||||
*/
|
||||
|
||||
void rtems_stack_checker_begin_extension(
|
||||
Thread_Control *the_thread
|
||||
)
|
||||
{
|
||||
Stack_check_Control *the_pattern;
|
||||
|
||||
if (!stack_check_initialized)
|
||||
rtems_stack_checker_initialize();
|
||||
|
||||
if ( the_thread->Object.id == 0 ) /* skip system tasks */
|
||||
return;
|
||||
|
||||
@@ -256,60 +198,60 @@ void rtems_stack_checker_begin_extension(
|
||||
*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.
|
||||
*
|
||||
* 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,
|
||||
boolean pattern_ok
|
||||
)
|
||||
{
|
||||
Stack_Control *stack = &running->Start.Initial_stack;
|
||||
Stack_Control *stack = &running->Start.Initial_stack;
|
||||
|
||||
printk(
|
||||
"BLOWN STACK!!! Offending task(%p): id=0x%08" PRIx32
|
||||
"; name=0x%08" PRIx32,
|
||||
running,
|
||||
running->Object.id,
|
||||
(uint32_t) running->Object.name
|
||||
);
|
||||
printk(
|
||||
"BLOWN STACK!!! Offending task(%p): id=0x%08" PRIx32 "; name=0x%08" PRIx32,
|
||||
running,
|
||||
running->Object.id,
|
||||
(uint32_t) running->Object.name
|
||||
);
|
||||
|
||||
if (rtems_configuration_get_user_multiprocessing_table())
|
||||
printk(
|
||||
"; node=%d\n",
|
||||
rtems_configuration_get_user_multiprocessing_table()->node
|
||||
);
|
||||
else
|
||||
printk( "\n");
|
||||
|
||||
printk(
|
||||
" stack covers range %p - %p (%d bytes)\n",
|
||||
stack->area,
|
||||
stack->area + stack->size - 1,
|
||||
stack->size);
|
||||
|
||||
if ( !pattern_ok ) {
|
||||
#if defined(RTEMS_MULTIPROCESSING)
|
||||
if (rtems_configuration_get_user_multiprocessing_table()) {
|
||||
printk(
|
||||
" Damaged pattern begins at 0x%08lx and is %ld bytes long\n",
|
||||
(unsigned long) Stack_check_Get_pattern_area(stack),
|
||||
(long) PATTERN_SIZE_BYTES);
|
||||
"; node=%d\n",
|
||||
rtems_configuration_get_user_multiprocessing_table()->node
|
||||
);
|
||||
}
|
||||
#else
|
||||
printk( "\n" );
|
||||
#endif
|
||||
|
||||
rtems_fatal_error_occurred( (uint32_t) "STACK BLOWN" );
|
||||
printk(
|
||||
" stack covers range %p - %p (%d bytes)\n",
|
||||
stack->area,
|
||||
stack->area + stack->size - 1,
|
||||
stack->size
|
||||
);
|
||||
|
||||
if ( !pattern_ok ) {
|
||||
printk(
|
||||
" Damaged pattern begins at 0x%08lx and is %ld bytes long\n",
|
||||
(unsigned long) Stack_check_Get_pattern_area(stack),
|
||||
(long) PATTERN_SIZE_BYTES);
|
||||
}
|
||||
|
||||
rtems_fatal_error_occurred( 0x81 );
|
||||
}
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
/*
|
||||
* rtems_stack_checker_switch_extension
|
||||
*/
|
||||
|
||||
void rtems_stack_checker_switch_extension(
|
||||
Thread_Control *running,
|
||||
Thread_Control *heir
|
||||
@@ -322,7 +264,6 @@ void rtems_stack_checker_switch_extension(
|
||||
|
||||
pattern = (void *) Stack_check_Get_pattern_area(the_stack)->pattern;
|
||||
|
||||
|
||||
/*
|
||||
* Check for an out of bounds stack pointer and then an overwrite
|
||||
*/
|
||||
@@ -336,9 +277,38 @@ void rtems_stack_checker_switch_extension(
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if blown
|
||||
*/
|
||||
boolean rtems_stack_checker_is_blown( void )
|
||||
{
|
||||
Stack_Control *the_stack = &_Thread_Executing->Start.Initial_stack;
|
||||
void *pattern;
|
||||
boolean sp_ok;
|
||||
boolean pattern_ok = TRUE;
|
||||
|
||||
pattern = (void *) Stack_check_Get_pattern_area(the_stack)->pattern;
|
||||
|
||||
/*
|
||||
* Check for an out of bounds stack pointer and then 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 ) {
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Stack_check_find_high_water_mark
|
||||
*/
|
||||
void *Stack_check_find_high_water_mark(
|
||||
const void *s,
|
||||
size_t n
|
||||
size_t n
|
||||
)
|
||||
{
|
||||
const uint32_t *base, *ebase;
|
||||
@@ -347,38 +317,61 @@ void *Stack_check_find_high_water_mark(
|
||||
base = s;
|
||||
length = n/4;
|
||||
|
||||
#if ( CPU_STACK_GROWS_UP == TRUE )
|
||||
/*
|
||||
* start at higher memory and find first word that does not
|
||||
* match pattern
|
||||
*/
|
||||
#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 += 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
|
||||
base += PATTERN_SIZE_WORDS;
|
||||
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.
|
||||
*
|
||||
/*
|
||||
* Report Name
|
||||
*/
|
||||
|
||||
char *Stack_check_Get_object_name(
|
||||
Objects_Control *the_object,
|
||||
char **name
|
||||
)
|
||||
{
|
||||
Objects_Information *info;
|
||||
|
||||
info = _Objects_Get_information(the_object->id);
|
||||
if ( info->is_string ) {
|
||||
*name = (char *) the_object->name;
|
||||
} else {
|
||||
uint32_t u32_name = (uint32_t) the_object->name;
|
||||
(*name)[ 0 ] = (u32_name >> 24) & 0xff;
|
||||
(*name)[ 1 ] = (u32_name >> 16) & 0xff;
|
||||
(*name)[ 2 ] = (u32_name >> 8) & 0xff;
|
||||
(*name)[ 3 ] = (u32_name >> 0) & 0xff;
|
||||
(*name)[ 4 ] = '\0';
|
||||
}
|
||||
return *name;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
)
|
||||
@@ -389,8 +382,7 @@ void Stack_check_Dump_threads_usage(
|
||||
Stack_Control *stack;
|
||||
uint32_t u32_name;
|
||||
char name_str[5];
|
||||
char *name;
|
||||
Objects_Information *info;
|
||||
char *name;
|
||||
|
||||
if ( !the_thread )
|
||||
return;
|
||||
@@ -399,18 +391,15 @@ void Stack_check_Dump_threads_usage(
|
||||
* 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;
|
||||
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);
|
||||
@@ -424,17 +413,7 @@ void Stack_check_Dump_threads_usage(
|
||||
|
||||
name = name_str;
|
||||
if ( the_thread ) {
|
||||
info = _Objects_Get_information(the_thread->Object.id);
|
||||
if ( info->is_string ) {
|
||||
name = (char *) the_thread->Object.name;
|
||||
} else {
|
||||
u32_name = (uint32_t) the_thread->Object.name;
|
||||
name[ 0 ] = (u32_name >> 24) & 0xff;
|
||||
name[ 1 ] = (u32_name >> 16) & 0xff;
|
||||
name[ 2 ] = (u32_name >> 8) & 0xff;
|
||||
name[ 3 ] = (u32_name >> 0) & 0xff;
|
||||
name[ 4 ] = '\0';
|
||||
}
|
||||
name = Stack_check_Get_object_name( &the_thread->Object, &name );
|
||||
} else {
|
||||
u32_name = rtems_build_name('I', 'N', 'T', 'R');
|
||||
name[ 0 ] = (u32_name >> 24) & 0xff;
|
||||
@@ -445,32 +424,29 @@ void Stack_check_Dump_threads_usage(
|
||||
}
|
||||
|
||||
printk("0x%08" PRIx32 " %4s %p - %p %8" PRId32 " %8" PRId32 "\n",
|
||||
the_thread ? the_thread->Object.id : ~0,
|
||||
name,
|
||||
stack->area,
|
||||
stack->area + stack->size - 1,
|
||||
size,
|
||||
used
|
||||
the_thread ? the_thread->Object.id : ~0,
|
||||
name,
|
||||
stack->area,
|
||||
stack->area + stack->size - 1,
|
||||
size,
|
||||
used
|
||||
);
|
||||
}
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
/*
|
||||
* rtems_stack_checker_fatal_extension
|
||||
*/
|
||||
|
||||
void rtems_stack_checker_fatal_extension(
|
||||
#ifndef DONT_USE_FATAL_EXTENSION
|
||||
void rtems_stack_checker_fatal_extension(
|
||||
Internal_errors_Source source,
|
||||
boolean is_internal,
|
||||
uint32_t status
|
||||
)
|
||||
{
|
||||
#ifndef DONT_USE_FATAL_EXTENSION
|
||||
)
|
||||
{
|
||||
if (status == 0)
|
||||
rtems_stack_checker_report_usage();
|
||||
rtems_stack_checker_report_usage();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
@@ -479,7 +455,7 @@ void rtems_stack_checker_fatal_extension(
|
||||
|
||||
void rtems_stack_checker_report_usage( void )
|
||||
{
|
||||
if (stack_check_initialized == 0)
|
||||
if (Stack_check_Initialized == 0)
|
||||
return;
|
||||
|
||||
printk("Stack usage by thread\n");
|
||||
|
||||
Reference in New Issue
Block a user