File indexing completed on 2025-05-11 08:24:19
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041 #ifdef HAVE_CONFIG_H
0042 #include "config.h"
0043 #endif
0044
0045 #include <rtems.h>
0046 #include <inttypes.h>
0047
0048 #include <string.h>
0049 #include <stdlib.h>
0050
0051 #include <rtems/bspIo.h>
0052 #include <rtems/printer.h>
0053 #include <rtems/stackchk.h>
0054 #include <rtems/sysinit.h>
0055 #include <rtems/score/address.h>
0056 #include <rtems/score/percpu.h>
0057 #include <rtems/score/smp.h>
0058 #include <rtems/score/threadimpl.h>
0059
0060
0061
0062
0063
0064
0065
0066 #if !defined(CPU_STACK_CHECK_PATTERN_INITIALIZER)
0067 #define CPU_STACK_CHECK_PATTERN_INITIALIZER \
0068 { \
0069 0xFEEDF00D, 0x0BAD0D06, \
0070 0xDEADF00D, 0x600D0D06 \
0071 }
0072 #endif
0073
0074
0075
0076
0077
0078 #define BYTE_PATTERN 0xA5
0079 #define U32_PATTERN 0xA5A5A5A5
0080
0081
0082
0083
0084 static bool Stack_check_Initialized;
0085
0086
0087
0088
0089 static const uint32_t Stack_check_Sanity_pattern[] =
0090 CPU_STACK_CHECK_PATTERN_INITIALIZER;
0091
0092 #define SANITY_PATTERN_SIZE_BYTES sizeof(Stack_check_Sanity_pattern)
0093
0094 #define SANITY_PATTERN_SIZE_WORDS RTEMS_ARRAY_SIZE(Stack_check_Sanity_pattern)
0095
0096
0097
0098
0099
0100
0101 static inline bool Stack_check_Frame_pointer_in_range(
0102 const Thread_Control *the_thread
0103 )
0104 {
0105 #if defined(__GNUC__)
0106 void *sp = __builtin_frame_address(0);
0107 const Stack_Control *the_stack = &the_thread->Start.Initial_stack;
0108
0109 if ( sp < the_stack->area ) {
0110 return false;
0111 }
0112 if ( sp > (the_stack->area + the_stack->size) ) {
0113 return false;
0114 }
0115 #else
0116 #error "How do I check stack bounds on a non-GNU compiler?"
0117 #endif
0118 return true;
0119 }
0120
0121
0122
0123
0124
0125 #if (CPU_STACK_GROWS_UP == TRUE)
0126 #define Stack_check_Get_pattern( _the_stack ) \
0127 ((char *)(_the_stack)->area + \
0128 (_the_stack)->size - SANITY_PATTERN_SIZE_BYTES )
0129
0130 #define Stack_check_Calculate_used( _low, _size, _high_water ) \
0131 ((char *)(_high_water) - (char *)(_low))
0132
0133 #define Stack_check_Usable_stack_start(_the_stack) \
0134 ((_the_stack)->area)
0135
0136 #else
0137 #define Stack_check_Get_pattern( _the_stack ) \
0138 ((char *)(_the_stack)->area)
0139
0140 #define Stack_check_Calculate_used( _low, _size, _high_water) \
0141 ( ((char *)(_low) + (_size)) - (char *)(_high_water) )
0142
0143 #define Stack_check_Usable_stack_start(_the_stack) \
0144 ((char *)(_the_stack)->area + SANITY_PATTERN_SIZE_BYTES)
0145
0146 #endif
0147
0148
0149
0150
0151
0152 #define Stack_check_Usable_stack_size(_the_stack) \
0153 ((_the_stack)->size - SANITY_PATTERN_SIZE_BYTES)
0154
0155 #if defined(RTEMS_SMP)
0156 static Stack_Control Stack_check_Interrupt_stack[ CPU_MAXIMUM_PROCESSORS ];
0157 #else
0158 static Stack_Control Stack_check_Interrupt_stack[ 1 ];
0159 #endif
0160
0161
0162
0163
0164
0165 static void Stack_check_Dope_stack( Stack_Control *stack )
0166 {
0167 memset(
0168 Stack_check_Usable_stack_start( stack ),
0169 BYTE_PATTERN,
0170 Stack_check_Usable_stack_size( stack )
0171 );
0172 }
0173
0174 static void Stack_check_Add_sanity_pattern( Stack_Control *stack )
0175 {
0176 memcpy(
0177 Stack_check_Get_pattern( stack ),
0178 Stack_check_Sanity_pattern,
0179 SANITY_PATTERN_SIZE_BYTES
0180 );
0181 }
0182
0183 static bool Stack_check_Is_sanity_pattern_valid( const Stack_Control *stack )
0184 {
0185 return memcmp(
0186 Stack_check_Get_pattern( stack ),
0187 Stack_check_Sanity_pattern,
0188 SANITY_PATTERN_SIZE_BYTES
0189 ) == 0;
0190 }
0191
0192
0193
0194
0195 bool rtems_stack_checker_create_extension(
0196 Thread_Control *running RTEMS_UNUSED,
0197 Thread_Control *the_thread
0198 )
0199 {
0200 Stack_check_Initialized = true;
0201
0202 Stack_check_Dope_stack( &the_thread->Start.Initial_stack );
0203 Stack_check_Add_sanity_pattern( &the_thread->Start.Initial_stack );
0204
0205 return true;
0206 }
0207
0208 void rtems_stack_checker_begin_extension( Thread_Control *executing )
0209 {
0210 Per_CPU_Control *cpu_self;
0211 uint32_t cpu_self_index;
0212 Stack_Control *stack;
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223 #if defined(RTEMS_SMP)
0224 cpu_self = _Thread_Dispatch_disable();
0225 #else
0226 cpu_self = _Per_CPU_Get();
0227 #endif
0228
0229 cpu_self_index = _Per_CPU_Get_index( cpu_self );
0230 stack = &Stack_check_Interrupt_stack[ cpu_self_index ];
0231
0232 if ( stack->area == NULL ) {
0233 stack->area = cpu_self->interrupt_stack_low;
0234 stack->size = (size_t) ( (char *) cpu_self->interrupt_stack_high -
0235 (char *) cpu_self->interrupt_stack_low );
0236
0237
0238
0239
0240 if ( !Stack_check_Is_sanity_pattern_valid( stack ) ) {
0241 rtems_fatal(
0242 RTEMS_FATAL_SOURCE_STACK_CHECKER,
0243 rtems_build_name( 'I', 'N', 'T', 'R' )
0244 );
0245 }
0246
0247 Stack_check_Dope_stack( stack );
0248 }
0249
0250 #if defined(RTEMS_SMP)
0251 _Thread_Dispatch_enable( cpu_self );
0252 #endif
0253 }
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263
0264 void rtems_stack_checker_reporter_print_details(
0265 const Thread_Control *running,
0266 bool pattern_ok
0267 )
0268 {
0269 const Stack_Control *stack = &running->Start.Initial_stack;
0270 void *pattern_area = Stack_check_Get_pattern(stack);
0271 char name[2 * THREAD_DEFAULT_MAXIMUM_NAME_SIZE];
0272
0273 printk("BLOWN STACK!!!\n");
0274 printk("task control block: 0x%08" PRIxPTR "\n", (intptr_t) running);
0275 printk("task ID: 0x%08lx\n", (unsigned long) running->Object.id);
0276 printk(
0277 "task name: 0x%08" PRIx32 "\n",
0278 running->Object.name.name_u32
0279 );
0280 _Thread_Get_name(running, name, sizeof(name));
0281 printk("task name string: %s\n", name);
0282 printk(
0283 "task stack area (%lu Bytes): 0x%08" PRIxPTR " .. 0x%08" PRIxPTR "\n",
0284 (unsigned long) stack->size,
0285 (intptr_t) stack->area,
0286 (intptr_t) ((char *) stack->area + stack->size)
0287 );
0288 if (!pattern_ok) {
0289 printk(
0290 "damaged pattern area (%lu Bytes): 0x%08" PRIxPTR " .. 0x%08" PRIxPTR "\n",
0291 (unsigned long) SANITY_PATTERN_SIZE_BYTES,
0292 (intptr_t) pattern_area,
0293 (intptr_t) (pattern_area + SANITY_PATTERN_SIZE_BYTES)
0294 );
0295 }
0296
0297 #if defined(RTEMS_MULTIPROCESSING)
0298 if (rtems_configuration_get_user_multiprocessing_table()) {
0299 printk(
0300 "node: 0x%08" PRIxPTR "\n",
0301 (intptr_t) rtems_configuration_get_user_multiprocessing_table()->node
0302 );
0303 }
0304 #endif
0305
0306 rtems_fatal(
0307 RTEMS_FATAL_SOURCE_STACK_CHECKER,
0308 running->Object.name.name_u32
0309 );
0310 }
0311
0312 void rtems_stack_checker_reporter_quiet(
0313 const Thread_Control *running,
0314 bool pattern_ok
0315 )
0316 {
0317 rtems_fatal(
0318 RTEMS_FATAL_SOURCE_STACK_CHECKER,
0319 running->Object.name.name_u32
0320 );
0321 }
0322
0323
0324
0325
0326 void rtems_stack_checker_switch_extension(
0327 Thread_Control *running,
0328 Thread_Control *heir
0329 )
0330 {
0331 bool sp_ok;
0332 bool pattern_ok;
0333 const Stack_Control *stack;
0334
0335
0336
0337
0338 #if defined(RTEMS_SMP)
0339 sp_ok = Stack_check_Frame_pointer_in_range( heir );
0340
0341 if ( !sp_ok ) {
0342 pattern_ok = Stack_check_Is_sanity_pattern_valid(
0343 &heir->Start.Initial_stack
0344 );
0345 Stack_checker_Reporter( heir, pattern_ok );
0346 }
0347
0348 pattern_ok = Stack_check_Is_sanity_pattern_valid( &running->Start.Initial_stack );
0349
0350 if ( !pattern_ok ) {
0351 Stack_checker_Reporter( running, pattern_ok );
0352 }
0353 #else
0354 sp_ok = Stack_check_Frame_pointer_in_range( running );
0355
0356 pattern_ok = Stack_check_Is_sanity_pattern_valid( &running->Start.Initial_stack );
0357
0358 if ( !sp_ok || !pattern_ok ) {
0359 Stack_checker_Reporter( running, pattern_ok );
0360 }
0361 #endif
0362
0363 stack = &Stack_check_Interrupt_stack[ _SMP_Get_current_processor() ];
0364
0365 if ( stack->area != NULL && !Stack_check_Is_sanity_pattern_valid( stack ) ) {
0366 rtems_fatal(
0367 RTEMS_FATAL_SOURCE_STACK_CHECKER,
0368 rtems_build_name( 'I', 'N', 'T', 'R' )
0369 );
0370 }
0371 }
0372
0373
0374
0375
0376 bool rtems_stack_checker_is_blown( void )
0377 {
0378 Thread_Control *executing;
0379
0380 executing = _Thread_Get_executing();
0381 rtems_stack_checker_switch_extension( executing, executing );
0382
0383
0384
0385
0386 return false;
0387 }
0388
0389
0390
0391
0392 static inline void *Stack_check_Find_high_water_mark(
0393 const void *s,
0394 size_t n
0395 )
0396 {
0397 const uint32_t *base, *ebase;
0398 uint32_t length;
0399
0400 base = s;
0401 length = n/4;
0402
0403 #if ( CPU_STACK_GROWS_UP == TRUE )
0404
0405
0406
0407
0408
0409 base += length - 1;
0410 for (ebase = s; base > ebase; base--)
0411 if (*base != U32_PATTERN)
0412 return (void *) base;
0413 #else
0414
0415
0416
0417
0418
0419 for (ebase = base + length; base < ebase; base++)
0420 if (*base != U32_PATTERN)
0421 return (void *) base;
0422 #endif
0423
0424 return NULL;
0425 }
0426
0427 static void Stack_check_Visit_stack(
0428 const Stack_Control *stack,
0429 const void *current,
0430 const char *name,
0431 rtems_id id,
0432 rtems_stack_checker_visitor visit,
0433 void *arg
0434 )
0435 {
0436 rtems_stack_checker_info info;
0437
0438
0439 if ( stack->area == NULL ) {
0440 return;
0441 }
0442
0443 info.id = id;
0444 info.name = name;
0445 info.current = current;
0446 info.begin = Stack_check_Usable_stack_start( stack );
0447 info.size = Stack_check_Usable_stack_size( stack );
0448
0449 if ( Stack_check_Initialized ) {
0450 void *high_water_mark;
0451
0452 high_water_mark =
0453 Stack_check_Find_high_water_mark( info.begin, info.size );
0454
0455 if ( high_water_mark != NULL ) {
0456 info.used =
0457 Stack_check_Calculate_used( info.begin, info.size, high_water_mark );
0458 } else {
0459 info.used = 0;
0460 }
0461 } else {
0462 info.used = UINTPTR_MAX;
0463 }
0464
0465 ( *visit )( &info, arg );
0466 }
0467
0468 typedef struct {
0469 rtems_stack_checker_visitor visit;
0470 void *arg;
0471 } Stack_check_Visitor;
0472
0473 static bool Stack_check_Visit_thread(
0474 Thread_Control *the_thread,
0475 void *arg
0476 )
0477 {
0478 Stack_check_Visitor *visitor;
0479 char name[ 22 ];
0480 uintptr_t sp = (uintptr_t) _CPU_Context_Get_SP( &the_thread->Registers );
0481
0482 visitor = arg;
0483 _Thread_Get_name( the_thread, name, sizeof( name ) );
0484 Stack_check_Visit_stack(
0485 &the_thread->Start.Initial_stack,
0486 (void *) sp,
0487 name,
0488 the_thread->Object.id,
0489 visitor->visit,
0490 visitor->arg
0491 );
0492 return false;
0493 }
0494
0495 static void Stack_check_Visit_interrupt_stack(
0496 const Stack_Control *stack,
0497 uint32_t id,
0498 rtems_stack_checker_visitor visit,
0499 void *arg
0500 )
0501 {
0502 Stack_check_Visit_stack(
0503 stack,
0504 NULL,
0505 "Interrupt Stack",
0506 id,
0507 visit,
0508 arg
0509 );
0510 }
0511
0512 static void Stack_check_Print_info(
0513 const rtems_stack_checker_info *info,
0514 void *arg
0515 )
0516 {
0517 const rtems_printer *printer;
0518
0519 printer = arg;
0520
0521 rtems_printf(
0522 printer,
0523 "0x%08" PRIx32 " %-21s 0x%08" PRIxPTR " 0x%08" PRIxPTR " 0x%08" PRIxPTR " %6" PRIuPTR " ",
0524 info->id,
0525 info->name,
0526 (uintptr_t) info->begin,
0527 (uintptr_t) info->begin + info->size - 1,
0528 (uintptr_t) info->current,
0529 info->size
0530 );
0531
0532 if ( info->used != UINTPTR_MAX ) {
0533 rtems_printf( printer, "%6" PRIuPTR "\n", info->used );
0534 } else {
0535 rtems_printf( printer, "N/A\n" );
0536 }
0537 }
0538
0539 void rtems_stack_checker_report_usage_with_plugin(
0540 const rtems_printer* printer
0541 )
0542 {
0543 rtems_printf(
0544 printer,
0545 " STACK USAGE BY THREAD\n"
0546 "ID NAME LOW HIGH CURRENT AVAIL USED\n"
0547 );
0548
0549 rtems_stack_checker_iterate(
0550 Stack_check_Print_info,
0551 RTEMS_DECONST( rtems_printer *, printer )
0552 );
0553 }
0554
0555 void rtems_stack_checker_report_usage( void )
0556 {
0557 rtems_printer printer;
0558 rtems_print_printer_printk(&printer);
0559 rtems_stack_checker_report_usage_with_plugin( &printer );
0560 }
0561
0562 void rtems_stack_checker_iterate( rtems_stack_checker_visitor visit, void *arg )
0563 {
0564 Stack_check_Visitor visitor;
0565 uint32_t cpu_max;
0566 uint32_t cpu_index;
0567
0568 visitor.visit = visit;
0569 visitor.arg = arg;
0570 rtems_task_iterate( Stack_check_Visit_thread, &visitor );
0571
0572 cpu_max = rtems_scheduler_get_processor_maximum();
0573
0574 for ( cpu_index = 0; cpu_index < cpu_max; ++cpu_index ) {
0575 Stack_check_Visit_interrupt_stack(
0576 &Stack_check_Interrupt_stack[ cpu_index ],
0577 cpu_index,
0578 visit,
0579 arg
0580 );
0581 }
0582 }
0583
0584 static void Stack_check_Prepare_interrupt_stacks( void )
0585 {
0586 Stack_Control stack;
0587 uint32_t cpu_index;
0588 uint32_t cpu_max;
0589
0590 stack.size = rtems_configuration_get_interrupt_stack_size();
0591 stack.area = _ISR_Stack_area_begin;
0592 cpu_max = rtems_configuration_get_maximum_processors();
0593
0594 for ( cpu_index = 0; cpu_index < cpu_max; ++cpu_index ) {
0595 Stack_check_Add_sanity_pattern( &stack );
0596 stack.area = _Addresses_Add_offset( stack.area, stack.size );
0597 }
0598 }
0599
0600 RTEMS_SYSINIT_ITEM(
0601 Stack_check_Prepare_interrupt_stacks,
0602 RTEMS_SYSINIT_ISR_STACK,
0603 RTEMS_SYSINIT_ORDER_MIDDLE
0604 );