stackchk: Add rtems_stack_checker_iterate()

This commit is contained in:
Sebastian Huber
2022-09-29 15:35:37 +02:00
parent 03ddd89459
commit 829e489230
2 changed files with 171 additions and 64 deletions

View File

@@ -90,6 +90,81 @@ void rtems_stack_checker_report_usage_with_plugin(
const rtems_printer *printer
);
/**
* @brief This structure contains the stack information provided by the stack
* checker for a stack.
*/
typedef struct {
/**
* @brief This member contains the object identifier associated with the
* object using the stack.
*
* For interrupt stacks, the object identifier is the processor index.
*/
rtems_id id;
/**
* @brief This member provides the object name associated with the
* object using the stack.
*
* For interrupt stacks, the object name is "Interrupt Stack".
*/
const char *name;
/**
* @brief This member provides the begin address of the stack area.
*/
const void *begin;
/**
* @brief This member contains the size in byes of the stack area.
*/
uintptr_t size;
/**
* @brief This member provides the current stack pointer of the stack.
*
* If the current stack pointer is not available, then the value is set to
* NULL.
*/
const void *current;
/**
* @brief This member contains the size in byes of the used stack area.
*
* If the stack checker is not initialized, then the value is set to
* UINTPTR_MAX.
*/
uintptr_t used;
} rtems_stack_checker_info;
/**
* @brief Visitor routines invoked by rtems_stack_checker_iterate() shall have
* this type.
*
* @param info is the stack information.
*
* @param arg is the argument passed to rtems_stack_checker_iterate().
*/
typedef void ( *rtems_stack_checker_visitor )(
const rtems_stack_checker_info *info,
void *arg
);
/**
* @brief Iterates over all stacks used by the system and invokes the visitor
* routine for each stack.
*
* This method prints a stack usage report for the curently executing
* task.
*
* @param visitor is the visitor routine invoked for each stack.
*
* @param arg is the argument passed to each visitor routine invocation during
* the iteration.
*/
void rtems_stack_checker_iterate( rtems_stack_checker_visitor visit, void *arg );
/*************************************************************
*************************************************************
** Prototyped only so the user extension can be installed **

View File

@@ -413,125 +413,135 @@ static inline void *Stack_check_Find_high_water_mark(
return (void *) base;
#endif
return (void *)0;
return NULL;
}
static bool Stack_check_Dump_stack_usage(
const Stack_Control *stack,
const void *current,
const char *name,
uint32_t id,
const rtems_printer *printer
static void Stack_check_Visit_stack(
const Stack_Control *stack,
const void *current,
const char *name,
rtems_id id,
rtems_stack_checker_visitor visit,
void *arg
)
{
uint32_t size;
uint32_t used;
void *low;
void *high_water_mark;
rtems_stack_checker_info info;
/* This is likely to occur if the stack checker is not actually enabled */
if ( stack->area == NULL ) {
return false;
return;
}
low = Stack_check_Usable_stack_start(stack);
size = Stack_check_Usable_stack_size(stack);
info.id = id;
info.name = name;
info.current = current;
info.begin = Stack_check_Usable_stack_start( stack );
info.size = Stack_check_Usable_stack_size( stack );
high_water_mark = Stack_check_Find_high_water_mark(low, size);
if ( Stack_check_Initialized ) {
void *high_water_mark;
if ( high_water_mark )
used = Stack_check_Calculate_used( low, size, high_water_mark );
else
used = 0;
high_water_mark =
Stack_check_Find_high_water_mark( info.begin, info.size );
rtems_printf(
printer,
"0x%08" PRIx32 " %-21s 0x%08" PRIxPTR " 0x%08" PRIxPTR " 0x%08" PRIxPTR " %6" PRId32 " ",
id,
name,
(uintptr_t) stack->area,
(uintptr_t) stack->area + (uintptr_t) stack->size - 1,
(uintptr_t) current,
size
);
if (Stack_check_Initialized) {
rtems_printf( printer, "%6" PRId32 "\n", used );
if ( high_water_mark != NULL ) {
info.used =
Stack_check_Calculate_used( info.begin, info.size, high_water_mark );
} else {
info.used = 0;
}
} else {
rtems_printf( printer, "N/A\n" );
info.used = UINTPTR_MAX;
}
return false;
( *visit )( &info, arg );
}
static bool Stack_check_Dump_threads_usage(
typedef struct {
rtems_stack_checker_visitor visit;
void *arg;
} Stack_check_Visitor;
static bool Stack_check_Visit_thread(
Thread_Control *the_thread,
void *arg
)
{
Stack_check_Visitor *visitor;
char name[ 22 ];
const rtems_printer *printer;
uintptr_t sp = _CPU_Context_Get_SP( &the_thread->Registers );
printer = arg;
visitor = arg;
_Thread_Get_name( the_thread, name, sizeof( name ) );
Stack_check_Dump_stack_usage(
Stack_check_Visit_stack(
&the_thread->Start.Initial_stack,
(void *) sp,
name,
the_thread->Object.id,
printer
visitor->visit,
visitor->arg
);
return false;
}
static void Stack_check_Dump_interrupt_stack_usage(
const Stack_Control *stack,
uint32_t id,
const rtems_printer *printer
static void Stack_check_Visit_interrupt_stack(
const Stack_Control *stack,
uint32_t id,
rtems_stack_checker_visitor visit,
void *arg
)
{
Stack_check_Dump_stack_usage(
Stack_check_Visit_stack(
stack,
NULL,
"Interrupt Stack",
id,
printer
visit,
arg
);
}
/*
* rtems_stack_checker_report_usage
*/
static void Stack_check_Print_info(
const rtems_stack_checker_info *info,
void *arg
)
{
const rtems_printer *printer;
printer = arg;
rtems_printf(
printer,
"0x%08" PRIx32 " %-21s 0x%08" PRIxPTR " 0x%08" PRIxPTR " 0x%08" PRIxPTR " %6" PRIuPTR " ",
info->id,
info->name,
(uintptr_t) info->begin,
(uintptr_t) info->begin + info->size - 1,
(uintptr_t) info->current,
info->size
);
if ( info->used != UINTPTR_MAX ) {
rtems_printf( printer, "%6" PRIuPTR "\n", info->used );
} else {
rtems_printf( printer, "N/A\n" );
}
}
void rtems_stack_checker_report_usage_with_plugin(
const rtems_printer* printer
)
{
uint32_t cpu_max;
uint32_t cpu_index;
rtems_printf(
printer,
" STACK USAGE BY THREAD\n"
"ID NAME LOW HIGH CURRENT AVAIL USED\n"
);
/* iterate over all threads and dump the usage */
rtems_task_iterate(
Stack_check_Dump_threads_usage,
rtems_stack_checker_iterate(
Stack_check_Print_info,
RTEMS_DECONST( rtems_printer *, printer )
);
cpu_max = rtems_scheduler_get_processor_maximum();
for ( cpu_index = 0; cpu_index < cpu_max; ++cpu_index ) {
Stack_check_Dump_interrupt_stack_usage(
&Stack_check_Interrupt_stack[ cpu_index ],
cpu_index,
printer
);
}
}
void rtems_stack_checker_report_usage( void )
@@ -541,6 +551,28 @@ void rtems_stack_checker_report_usage( void )
rtems_stack_checker_report_usage_with_plugin( &printer );
}
void rtems_stack_checker_iterate( rtems_stack_checker_visitor visit, void *arg )
{
Stack_check_Visitor visitor;
uint32_t cpu_max;
uint32_t cpu_index;
visitor.visit = visit;
visitor.arg = arg;
rtems_task_iterate( Stack_check_Visit_thread, &visitor );
cpu_max = rtems_scheduler_get_processor_maximum();
for ( cpu_index = 0; cpu_index < cpu_max; ++cpu_index ) {
Stack_check_Visit_interrupt_stack(
&Stack_check_Interrupt_stack[ cpu_index ],
cpu_index,
visit,
arg
);
}
}
static void Stack_check_Prepare_interrupt_stacks( void )
{
Stack_Control stack;