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:
Joel Sherrill
2007-04-02 14:34:39 +00:00
parent 625ef85d6a
commit 29fd387849
2 changed files with 76 additions and 130 deletions

View File

@@ -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

View File

@@ -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);