forked from Imagelibrary/rtems
2007-04-02 Joel Sherrill <joel@OARcorp.com>
* libmisc/stackchk/check.c: Add code to check validity of frame pointer in addition to the pattern area being overwritten. Also do some cleanup.
This commit is contained in:
@@ -1,3 +1,9 @@
|
|||||||
|
2007-04-02 Joel Sherrill <joel@OARcorp.com>
|
||||||
|
|
||||||
|
* libmisc/stackchk/check.c: Add code to check validity of frame pointer
|
||||||
|
in addition to the pattern area being overwritten. Also do some
|
||||||
|
cleanup.
|
||||||
|
|
||||||
2007-03-28 Joel Sherrill <joel@OARcorp.com>
|
2007-03-28 Joel Sherrill <joel@OARcorp.com>
|
||||||
|
|
||||||
PR 1234/cpukit
|
PR 1234/cpukit
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
* CPU grows up or down and installs the correct
|
* CPU grows up or down and installs the correct
|
||||||
* extension routines for that direction.
|
* extension routines for that direction.
|
||||||
*
|
*
|
||||||
* COPYRIGHT (c) 1989-1999.
|
* COPYRIGHT (c) 1989-2007.
|
||||||
* On-Line Applications Research Corporation (OAR).
|
* On-Line Applications Research Corporation (OAR).
|
||||||
*
|
*
|
||||||
* The license and distribution terms for this file may be
|
* The license and distribution terms for this file may be
|
||||||
@@ -37,20 +37,13 @@
|
|||||||
#define DONT_USE_FATAL_EXTENSION
|
#define DONT_USE_FATAL_EXTENSION
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <rtems/bspIo.h>
|
||||||
#include <rtems/stackchk.h>
|
#include <rtems/stackchk.h>
|
||||||
#include "internal.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.
|
* The extension table for the stack checker.
|
||||||
*/
|
*/
|
||||||
@@ -76,6 +69,31 @@ rtems_extensions_table Stack_check_Extension_table = {
|
|||||||
|
|
||||||
Stack_check_Control Stack_check_Pattern;
|
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 boolean Stack_check_Frame_pointer_in_range(
|
||||||
|
Stack_Control *the_stack
|
||||||
|
)
|
||||||
|
{
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
void *sp = __builtin_frame_address(0);
|
||||||
|
|
||||||
|
if ( sp < the_stack->area ) {
|
||||||
|
printk( "Stack Pointer Too Low!\n" );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if ( sp > (the_stack->area + the_stack->size) ) {
|
||||||
|
printk( "Stack Pointer Too High!\n" );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Where the pattern goes in the stack area is dependent upon
|
* Where the pattern goes in the stack area is dependent upon
|
||||||
* whether the stack grow to the high or low area of the memory.
|
* whether the stack grow to the high or low area of the memory.
|
||||||
@@ -96,6 +114,7 @@ Stack_check_Control Stack_check_Pattern;
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
|
||||||
#define Stack_check_Get_pattern_area( _the_stack ) \
|
#define Stack_check_Get_pattern_area( _the_stack ) \
|
||||||
((Stack_check_Control *) ((char *)(_the_stack)->area + HEAP_OVERHEAD))
|
((Stack_check_Control *) ((char *)(_the_stack)->area + HEAP_OVERHEAD))
|
||||||
|
|
||||||
@@ -148,17 +167,7 @@ static int stack_check_initialized = 0;
|
|||||||
|
|
||||||
void Stack_check_Initialize( void )
|
void Stack_check_Initialize( void )
|
||||||
{
|
{
|
||||||
#if 0
|
|
||||||
rtems_status_code status;
|
|
||||||
Objects_Id id_ignored;
|
|
||||||
#endif
|
|
||||||
uint32_t *p;
|
uint32_t *p;
|
||||||
#if 0
|
|
||||||
uint32_t i;
|
|
||||||
uint32_t api_index;
|
|
||||||
Thread_Control *the_thread;
|
|
||||||
Objects_Information *information;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (stack_check_initialized)
|
if (stack_check_initialized)
|
||||||
return;
|
return;
|
||||||
@@ -178,52 +187,6 @@ void Stack_check_Initialize( void )
|
|||||||
p[3] = 0x600D0D06;
|
p[3] = 0x600D0D06;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if 0
|
|
||||||
status = rtems_extension_create(
|
|
||||||
rtems_build_name( 'S', 'T', 'C', 'K' ),
|
|
||||||
&Stack_check_Extension_table,
|
|
||||||
&id_ignored
|
|
||||||
);
|
|
||||||
assert ( status == RTEMS_SUCCESSFUL );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* XXX
|
|
||||||
*
|
|
||||||
* Technically this has not been done for any task created before this
|
|
||||||
* happened. So just run through them and fix the situation.
|
|
||||||
*/
|
|
||||||
#if 0
|
|
||||||
if (_Thread_Executing)
|
|
||||||
{
|
|
||||||
Stack_check_Create_extension(_Thread_Executing, _Thread_Executing);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
for ( api_index = 1;
|
|
||||||
api_index <= OBJECTS_APIS_LAST ;
|
|
||||||
api_index++ ) {
|
|
||||||
if ( !_Objects_Information_table[ api_index ] )
|
|
||||||
continue;
|
|
||||||
information = _Objects_Information_table[ api_index ][ 1 ];
|
|
||||||
if ( information ) {
|
|
||||||
for ( i=1 ; i <= information->maximum ; i++ ) {
|
|
||||||
the_thread = (Thread_Control *)information->local_table[ i ];
|
|
||||||
Stack_check_Create_extension( the_thread, the_thread );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If appropriate, setup the interrupt stack for high water testing
|
* If appropriate, setup the interrupt stack for high water testing
|
||||||
* also.
|
* also.
|
||||||
@@ -300,56 +263,47 @@ void Stack_check_Begin_extension(
|
|||||||
* Report a blown stack. Needs to be a separate routine
|
* Report a blown stack. Needs to be a separate routine
|
||||||
* so that interrupt handlers can use this too.
|
* 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
|
* NOTE: The system is in a questionable state... we may not get
|
||||||
* the following message out.
|
* the following message out.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void Stack_check_report_blown_task(void)
|
void Stack_check_report_blown_task(
|
||||||
|
Thread_Control *running,
|
||||||
|
boolean pattern_ok
|
||||||
|
)
|
||||||
{
|
{
|
||||||
Stack_Control *stack;
|
Stack_Control *stack = &running->Start.Initial_stack;
|
||||||
Thread_Control *running;
|
|
||||||
|
|
||||||
running = Stack_check_Blown_task;
|
printk(
|
||||||
stack = &running->Start.Initial_stack;
|
|
||||||
|
|
||||||
fprintf(
|
|
||||||
stderr,
|
|
||||||
"BLOWN STACK!!! Offending task(%p): id=0x%08" PRIx32
|
"BLOWN STACK!!! Offending task(%p): id=0x%08" PRIx32
|
||||||
"; name=0x%08" PRIx32,
|
"; name=0x%08" PRIx32,
|
||||||
running,
|
running,
|
||||||
running->Object.id,
|
running->Object.id,
|
||||||
(uint32_t) running->Object.name
|
(uint32_t) running->Object.name
|
||||||
);
|
);
|
||||||
fflush(stderr);
|
|
||||||
|
|
||||||
if (rtems_configuration_get_user_multiprocessing_table())
|
if (rtems_configuration_get_user_multiprocessing_table())
|
||||||
fprintf(
|
printk(
|
||||||
stderr,
|
"; node=%d\n",
|
||||||
"; node=%" PRId32 "\n",
|
|
||||||
rtems_configuration_get_user_multiprocessing_table()->node
|
rtems_configuration_get_user_multiprocessing_table()->node
|
||||||
);
|
);
|
||||||
else
|
else
|
||||||
fprintf(stderr, "\n");
|
printk( "\n");
|
||||||
fflush(stderr);
|
|
||||||
|
|
||||||
fprintf(
|
printk(
|
||||||
stderr,
|
" stack covers range %p - %p (%d bytes)\n",
|
||||||
" stack covers range %p - %p" PRIx32 " (%" PRId32 " bytes)\n",
|
|
||||||
stack->area,
|
stack->area,
|
||||||
stack->area + stack->size - 1,
|
stack->area + stack->size - 1,
|
||||||
stack->size);
|
stack->size);
|
||||||
fflush(stderr);
|
|
||||||
|
|
||||||
fprintf(
|
if ( !pattern_ok ) {
|
||||||
stderr,
|
printk(
|
||||||
" Damaged pattern begins at 0x%08lx and is %ld bytes long\n",
|
" Damaged pattern begins at 0x%08lx and is %ld bytes long\n",
|
||||||
(unsigned long) Stack_check_Get_pattern_area(stack),
|
(unsigned long) Stack_check_Get_pattern_area(stack),
|
||||||
(long) PATTERN_SIZE_BYTES);
|
(long) PATTERN_SIZE_BYTES);
|
||||||
fflush(stderr);
|
}
|
||||||
|
|
||||||
rtems_fatal_error_occurred( (uint32_t ) "STACK BLOWN" );
|
rtems_fatal_error_occurred( (uint32_t) "STACK BLOWN" );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*PAGE
|
/*PAGE
|
||||||
@@ -362,15 +316,24 @@ void Stack_check_Switch_extension(
|
|||||||
Thread_Control *heir
|
Thread_Control *heir
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if ( running->Object.id == 0 ) /* skip system tasks */
|
Stack_Control *the_stack = &running->Start.Initial_stack;
|
||||||
return;
|
void *pattern;
|
||||||
|
boolean sp_ok;
|
||||||
|
boolean pattern_ok;
|
||||||
|
|
||||||
if (0 != memcmp( (void *) Stack_check_Get_pattern_area( &running->Start.Initial_stack)->pattern,
|
pattern = (void *) Stack_check_Get_pattern_area(the_stack)->pattern;
|
||||||
(void *) Stack_check_Pattern.pattern,
|
|
||||||
PATTERN_SIZE_BYTES))
|
|
||||||
{
|
/*
|
||||||
Stack_check_Blown_task = running;
|
* Check for an out of bounds stack pointer and then an overwrite
|
||||||
Stack_check_report_blown_task();
|
*/
|
||||||
|
|
||||||
|
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 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -466,7 +429,7 @@ void Stack_check_Dump_threads_usage(
|
|||||||
if ( info->is_string ) {
|
if ( info->is_string ) {
|
||||||
name = (char *) the_thread->Object.name;
|
name = (char *) the_thread->Object.name;
|
||||||
} else {
|
} else {
|
||||||
u32_name = (uint32_t )the_thread->Object.name;
|
u32_name = (uint32_t) the_thread->Object.name;
|
||||||
name[ 0 ] = (u32_name >> 24) & 0xff;
|
name[ 0 ] = (u32_name >> 24) & 0xff;
|
||||||
name[ 1 ] = (u32_name >> 16) & 0xff;
|
name[ 1 ] = (u32_name >> 16) & 0xff;
|
||||||
name[ 2 ] = (u32_name >> 8) & 0xff;
|
name[ 2 ] = (u32_name >> 8) & 0xff;
|
||||||
@@ -482,8 +445,7 @@ void Stack_check_Dump_threads_usage(
|
|||||||
name[ 4 ] = '\0';
|
name[ 4 ] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stdout, "0x%08" PRIx32 " %4s %p - %p"
|
printk("0x%08" PRIx32 " %4s %p - %p %8" PRId32 " %8" PRId32 "\n",
|
||||||
" %8" PRId32 " %8" PRId32 "\n",
|
|
||||||
the_thread ? the_thread->Object.id : ~0,
|
the_thread ? the_thread->Object.id : ~0,
|
||||||
name,
|
name,
|
||||||
stack->area,
|
stack->area,
|
||||||
@@ -518,38 +480,16 @@ void Stack_check_Fatal_extension(
|
|||||||
|
|
||||||
void Stack_check_Dump_usage( void )
|
void Stack_check_Dump_usage( void )
|
||||||
{
|
{
|
||||||
uint32_t i;
|
|
||||||
uint32_t api_index;
|
|
||||||
Thread_Control *the_thread;
|
|
||||||
uint32_t hit_running = 0;
|
|
||||||
Objects_Information *information;
|
|
||||||
|
|
||||||
if (stack_check_initialized == 0)
|
if (stack_check_initialized == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
fprintf(stdout,"Stack usage by thread\n");
|
printk("Stack usage by thread\n");
|
||||||
fprintf(stdout,
|
printk(
|
||||||
" ID NAME LOW HIGH AVAILABLE USED\n"
|
" ID NAME LOW HIGH AVAILABLE USED\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
for ( api_index = 1 ;
|
/* iterate over all threads and dump the usage */
|
||||||
api_index <= OBJECTS_APIS_LAST ;
|
rtems_iterate_over_all_threads( Stack_check_Dump_threads_usage );
|
||||||
api_index++ ) {
|
|
||||||
if ( !_Objects_Information_table[ api_index ] )
|
|
||||||
continue;
|
|
||||||
information = _Objects_Information_table[ api_index ][ 1 ];
|
|
||||||
if ( information ) {
|
|
||||||
for ( i=1 ; i <= information->maximum ; i++ ) {
|
|
||||||
the_thread = (Thread_Control *)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 */
|
/* dump interrupt stack info if any */
|
||||||
Stack_check_Dump_threads_usage((Thread_Control *) -1);
|
Stack_check_Dump_threads_usage((Thread_Control *) -1);
|
||||||
|
|||||||
Reference in New Issue
Block a user