| File: | /home/joel/rtems-4.11-work/build/rtems/c/src/../../cpukit/libmisc/stackchk/check.c |
| Location: | line 312, column 16 |
| Description: | Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption |
| 1 | /* | ||||
| 2 | * Stack Overflow Check User Extension Set | ||||
| 3 | * | ||||
| 4 | * NOTE: This extension set automatically determines at | ||||
| 5 | * initialization time whether the stack for this | ||||
| 6 | * CPU grows up or down and installs the correct | ||||
| 7 | * extension routines for that direction. | ||||
| 8 | * | ||||
| 9 | * COPYRIGHT (c) 1989-2010. | ||||
| 10 | * On-Line Applications Research Corporation (OAR). | ||||
| 11 | * | ||||
| 12 | * The license and distribution terms for this file may be | ||||
| 13 | * found in the file LICENSE in this distribution or at | ||||
| 14 | * http://www.rtems.com/license/LICENSE. | ||||
| 15 | * | ||||
| 16 | * $Id: check.c,v 1.72 2010/08/25 20:29:41 joel Exp $ | ||||
| 17 | * | ||||
| 18 | */ | ||||
| 19 | |||||
| 20 | #ifdef HAVE_CONFIG_H1 | ||||
| 21 | #include "config.h" | ||||
| 22 | #endif | ||||
| 23 | |||||
| 24 | #include <rtems.h> | ||||
| 25 | #include <inttypes.h> | ||||
| 26 | |||||
| 27 | /* | ||||
| 28 | * The stack dump information may be printed by a "fatal" extension. | ||||
| 29 | * Fatal extensions only get called via rtems_fatal_error_occurred() | ||||
| 30 | * and not when rtems_shutdown_executive() is called. | ||||
| 31 | * When that happens, this #define should be deleted and all the code | ||||
| 32 | * it marks. | ||||
| 33 | */ | ||||
| 34 | #define DONT_USE_FATAL_EXTENSION | ||||
| 35 | |||||
| 36 | #include <string.h> | ||||
| 37 | #include <stdlib.h> | ||||
| 38 | |||||
| 39 | #include <rtems/bspIo.h> | ||||
| 40 | #include <rtems/stackchk.h> | ||||
| 41 | #include "internal.h" | ||||
| 42 | |||||
| 43 | /* | ||||
| 44 | * Variable to indicate when the stack checker has been initialized. | ||||
| 45 | */ | ||||
| 46 | static int Stack_check_Initialized = 0; | ||||
| 47 | |||||
| 48 | /* | ||||
| 49 | * The "magic pattern" used to mark the end of the stack. | ||||
| 50 | */ | ||||
| 51 | Stack_check_Control Stack_check_Pattern; | ||||
| 52 | |||||
| 53 | /* | ||||
| 54 | * Helper function to report if the actual stack pointer is in range. | ||||
| 55 | * | ||||
| 56 | * NOTE: This uses a GCC specific method. | ||||
| 57 | */ | ||||
| 58 | static inline bool_Bool Stack_check_Frame_pointer_in_range( | ||||
| 59 | Stack_Control *the_stack | ||||
| 60 | ) | ||||
| 61 | { | ||||
| 62 | #if defined(__GNUC__4) | ||||
| 63 | void *sp = __builtin_frame_address(0); | ||||
| 64 | |||||
| 65 | if ( sp < the_stack->area ) { | ||||
| 66 | return false0; | ||||
| 67 | } | ||||
| 68 | if ( sp > (the_stack->area + the_stack->size) ) { | ||||
| 69 | return false0; | ||||
| 70 | } | ||||
| 71 | #else | ||||
| 72 | #error "How do I check stack bounds on a non-GNU compiler?" | ||||
| 73 | #endif | ||||
| 74 | return true1; | ||||
| 75 | } | ||||
| 76 | |||||
| 77 | /* | ||||
| 78 | * Where the pattern goes in the stack area is dependent upon | ||||
| 79 | * whether the stack grow to the high or low area of the memory. | ||||
| 80 | */ | ||||
| 81 | #if (CPU_STACK_GROWS_UP0 == TRUE1) | ||||
| 82 | #define Stack_check_Get_pattern_area( _the_stack )((Stack_check_Control *) ((char *)(_the_stack)->area + sizeof (Heap_Block) - (2 * sizeof(uintptr_t) + 0))) \ | ||||
| 83 | ((Stack_check_Control *) ((char *)(_the_stack)->area + \ | ||||
| 84 | (_the_stack)->size - sizeof( Stack_check_Control ) )) | ||||
| 85 | |||||
| 86 | #define Stack_check_Calculate_used( _low, _size, _high_water )( ((char *)(_low) + (_size)) - (char *)(_high_water) ) \ | ||||
| 87 | ((char *)(_high_water) - (char *)(_low)) | ||||
| 88 | |||||
| 89 | #define Stack_check_usable_stack_start(_the_stack)((char *)(_the_stack)->area + sizeof(Stack_check_Control)) \ | ||||
| 90 | ((_the_stack)->area) | ||||
| 91 | |||||
| 92 | #else | ||||
| 93 | /* | ||||
| 94 | * We need this magic offset because during a task delete the task stack will | ||||
| 95 | * be freed before we enter the task switch extension which checks the stack. | ||||
| 96 | * The task stack free operation will write the next and previous pointers | ||||
| 97 | * for the free list into this area. | ||||
| 98 | */ | ||||
| 99 | #define Stack_check_Get_pattern_area( _the_stack )((Stack_check_Control *) ((char *)(_the_stack)->area + sizeof (Heap_Block) - (2 * sizeof(uintptr_t) + 0))) \ | ||||
| 100 | ((Stack_check_Control *) ((char *)(_the_stack)->area \ | ||||
| 101 | + sizeof(Heap_Block) - HEAP_BLOCK_HEADER_SIZE(2 * sizeof(uintptr_t) + 0))) | ||||
| 102 | |||||
| 103 | #define Stack_check_Calculate_used( _low, _size, _high_water)( ((char *)(_low) + (_size)) - (char *)(_high_water) ) \ | ||||
| 104 | ( ((char *)(_low) + (_size)) - (char *)(_high_water) ) | ||||
| 105 | |||||
| 106 | #define Stack_check_usable_stack_start(_the_stack)((char *)(_the_stack)->area + sizeof(Stack_check_Control)) \ | ||||
| 107 | ((char *)(_the_stack)->area + sizeof(Stack_check_Control)) | ||||
| 108 | |||||
| 109 | #endif | ||||
| 110 | |||||
| 111 | /* | ||||
| 112 | * The assumption is that if the pattern gets overwritten, the task | ||||
| 113 | * is too close. This defines the usable stack memory. | ||||
| 114 | */ | ||||
| 115 | #define Stack_check_usable_stack_size(_the_stack)((_the_stack)->size - sizeof(Stack_check_Control)) \ | ||||
| 116 | ((_the_stack)->size - sizeof(Stack_check_Control)) | ||||
| 117 | |||||
| 118 | #if (CPU_ALLOCATE_INTERRUPT_STACK1 == TRUE1) | ||||
| 119 | /* | ||||
| 120 | * Did RTEMS allocate the interrupt stack? If so, put it in | ||||
| 121 | * Stack_Control format. | ||||
| 122 | */ | ||||
| 123 | Stack_Control Stack_check_Interrupt_stack; | ||||
| 124 | #endif | ||||
| 125 | |||||
| 126 | /* | ||||
| 127 | * Fill an entire stack area with BYTE_PATTERN. This will be used | ||||
| 128 | * to check for amount of actual stack used. | ||||
| 129 | */ | ||||
| 130 | #define Stack_check_Dope_stack(_stack)memset((_stack)->area, 0xA5, (_stack)->size) \ | ||||
| 131 | memset((_stack)->area, BYTE_PATTERN0xA5, (_stack)->size) | ||||
| 132 | |||||
| 133 | /* | ||||
| 134 | * Stack_check_Initialize | ||||
| 135 | */ | ||||
| 136 | void Stack_check_Initialize( void ) | ||||
| 137 | { | ||||
| 138 | int i; | ||||
| 139 | uint32_t *p; | ||||
| 140 | static uint32_t pattern[ 4 ] = { | ||||
| 141 | 0xFEEDF00D, 0x0BAD0D06, /* FEED FOOD to BAD DOG */ | ||||
| 142 | 0xDEADF00D, 0x600D0D06 /* DEAD FOOD but GOOD DOG */ | ||||
| 143 | }; | ||||
| 144 | |||||
| 145 | if ( Stack_check_Initialized ) | ||||
| 146 | return; | ||||
| 147 | |||||
| 148 | /* | ||||
| 149 | * Dope the pattern and fill areas | ||||
| 150 | */ | ||||
| 151 | p = Stack_check_Pattern.pattern; | ||||
| 152 | for ( i = 0; i < PATTERN_SIZE_WORDS(4); i++ ) { | ||||
| 153 | p[i] = pattern[ i%4 ]; | ||||
| 154 | } | ||||
| 155 | |||||
| 156 | /* | ||||
| 157 | * If appropriate, setup the interrupt stack for high water testing | ||||
| 158 | * also. | ||||
| 159 | */ | ||||
| 160 | #if (CPU_ALLOCATE_INTERRUPT_STACK1 == TRUE1) | ||||
| 161 | if (_CPU_Interrupt_stack_low_Per_CPU_Information.interrupt_stack_low && _CPU_Interrupt_stack_high_Per_CPU_Information.interrupt_stack_high) { | ||||
| 162 | Stack_check_Interrupt_stack.area = _CPU_Interrupt_stack_low_Per_CPU_Information.interrupt_stack_low; | ||||
| 163 | Stack_check_Interrupt_stack.size = (char *) _CPU_Interrupt_stack_high_Per_CPU_Information.interrupt_stack_high - | ||||
| 164 | (char *) _CPU_Interrupt_stack_low_Per_CPU_Information.interrupt_stack_low; | ||||
| 165 | Stack_check_Dope_stack(&Stack_check_Interrupt_stack)memset((&Stack_check_Interrupt_stack)->area, 0xA5, (& Stack_check_Interrupt_stack)->size); | ||||
| 166 | } | ||||
| 167 | #endif | ||||
| 168 | |||||
| 169 | Stack_check_Initialized = 1; | ||||
| 170 | } | ||||
| 171 | |||||
| 172 | /* | ||||
| 173 | * rtems_stack_checker_create_extension | ||||
| 174 | */ | ||||
| 175 | bool_Bool rtems_stack_checker_create_extension( | ||||
| 176 | Thread_Control *running __attribute__((unused)), | ||||
| 177 | Thread_Control *the_thread | ||||
| 178 | ) | ||||
| 179 | { | ||||
| 180 | Stack_check_Initialize(); | ||||
| 181 | |||||
| 182 | if (the_thread) | ||||
| 183 | Stack_check_Dope_stack(&the_thread->Start.Initial_stack)memset((&the_thread->Start.Initial_stack)->area, 0xA5 , (&the_thread->Start.Initial_stack)->size); | ||||
| 184 | |||||
| 185 | return true1; | ||||
| 186 | } | ||||
| 187 | |||||
| 188 | /* | ||||
| 189 | * rtems_stack_checker_Begin_extension | ||||
| 190 | */ | ||||
| 191 | void rtems_stack_checker_begin_extension( | ||||
| 192 | Thread_Control *the_thread | ||||
| 193 | ) | ||||
| 194 | { | ||||
| 195 | Stack_check_Control *the_pattern; | ||||
| 196 | |||||
| 197 | if ( the_thread->Object.id == 0 ) /* skip system tasks */ | ||||
| 198 | return; | ||||
| 199 | |||||
| 200 | the_pattern = Stack_check_Get_pattern_area(&the_thread->Start.Initial_stack)((Stack_check_Control *) ((char *)(&the_thread->Start. Initial_stack)->area + sizeof(Heap_Block) - (2 * sizeof(uintptr_t ) + 0))); | ||||
| 201 | |||||
| 202 | *the_pattern = Stack_check_Pattern; | ||||
| 203 | } | ||||
| 204 | |||||
| 205 | /* | ||||
| 206 | * Stack_check_report_blown_task | ||||
| 207 | * | ||||
| 208 | * Report a blown stack. Needs to be a separate routine | ||||
| 209 | * so that interrupt handlers can use this too. | ||||
| 210 | * | ||||
| 211 | * NOTE: The system is in a questionable state... we may not get | ||||
| 212 | * the following message out. | ||||
| 213 | */ | ||||
| 214 | void Stack_check_report_blown_task( | ||||
| 215 | Thread_Control *running, | ||||
| 216 | bool_Bool pattern_ok | ||||
| 217 | ) RTEMS_COMPILER_NO_RETURN_ATTRIBUTE__attribute__ ((noreturn)); | ||||
| 218 | |||||
| 219 | void Stack_check_report_blown_task(Thread_Control *running, bool_Bool pattern_ok) | ||||
| 220 | { | ||||
| 221 | Stack_Control *stack = &running->Start.Initial_stack; | ||||
| 222 | void *pattern_area = Stack_check_Get_pattern_area(stack)((Stack_check_Control *) ((char *)(stack)->area + sizeof(Heap_Block ) - (2 * sizeof(uintptr_t) + 0))); | ||||
| 223 | char name [32]; | ||||
| 224 | |||||
| 225 | printk("BLOWN STACK!!!\n"); | ||||
| 226 | printk("task control block: 0x%08" PRIxPTR"x" "\n", running); | ||||
| 227 | printk("task ID: 0x%08lx\n", (unsigned long) running->Object.id); | ||||
| 228 | printk( | ||||
| 229 | "task name: 0x%08" PRIx32"x" "\n", | ||||
| 230 | running->Object.name.name_u32 | ||||
| 231 | ); | ||||
| 232 | printk( | ||||
| 233 | "task name string: %s\n", | ||||
| 234 | rtems_object_get_name(running->Object.id, sizeof(name), name) | ||||
| 235 | ); | ||||
| 236 | printk( | ||||
| 237 | "task stack area (%lu Bytes): 0x%08" PRIxPTR"x" " .. 0x%08" PRIxPTR"x" "\n", | ||||
| 238 | (unsigned long) stack->size, | ||||
| 239 | stack->area, | ||||
| 240 | ((char *) stack->area + stack->size) | ||||
| 241 | ); | ||||
| 242 | if (!pattern_ok) { | ||||
| 243 | printk( | ||||
| 244 | "damaged pattern area (%lu Bytes): 0x%08" PRIxPTR"x" " .. 0x%08" PRIxPTR"x" "\n", | ||||
| 245 | (unsigned long) PATTERN_SIZE_BYTES((4) * sizeof(uint32_t)), | ||||
| 246 | pattern_area, | ||||
| 247 | (pattern_area + PATTERN_SIZE_BYTES((4) * sizeof(uint32_t))) | ||||
| 248 | ); | ||||
| 249 | } | ||||
| 250 | |||||
| 251 | #if defined(RTEMS_MULTIPROCESSING) | ||||
| 252 | if (rtems_configuration_get_user_multiprocessing_table()((void*)0)) { | ||||
| 253 | printk( | ||||
| 254 | "node: 0x%08" PRIxPTR"x" "\n", | ||||
| 255 | rtems_configuration_get_user_multiprocessing_table()((void*)0)->node | ||||
| 256 | ); | ||||
| 257 | } | ||||
| 258 | #endif | ||||
| 259 | |||||
| 260 | rtems_fatal_error_occurred(0x81); | ||||
| 261 | } | ||||
| 262 | |||||
| 263 | /* | ||||
| 264 | * rtems_stack_checker_switch_extension | ||||
| 265 | */ | ||||
| 266 | void rtems_stack_checker_switch_extension( | ||||
| 267 | Thread_Control *running __attribute__((unused)), | ||||
| 268 | Thread_Control *heir __attribute__((unused)) | ||||
| 269 | ) | ||||
| 270 | { | ||||
| 271 | Stack_Control *the_stack = &running->Start.Initial_stack; | ||||
| 272 | void *pattern; | ||||
| 273 | bool_Bool sp_ok; | ||||
| 274 | bool_Bool pattern_ok = true1; | ||||
| 275 | |||||
| 276 | pattern = (void *) Stack_check_Get_pattern_area(the_stack)((Stack_check_Control *) ((char *)(the_stack)->area + sizeof (Heap_Block) - (2 * sizeof(uintptr_t) + 0)))->pattern; | ||||
| 277 | |||||
| 278 | /* | ||||
| 279 | * Check for an out of bounds stack pointer or an overwrite | ||||
| 280 | */ | ||||
| 281 | sp_ok = Stack_check_Frame_pointer_in_range( the_stack ); | ||||
| 282 | |||||
| 283 | pattern_ok = (!memcmp( pattern, | ||||
| 284 | (void *) Stack_check_Pattern.pattern, PATTERN_SIZE_BYTES((4) * sizeof(uint32_t)))); | ||||
| 285 | |||||
| 286 | if ( !sp_ok || !pattern_ok ) { | ||||
| 287 | Stack_check_report_blown_task( running, pattern_ok ); | ||||
| 288 | } | ||||
| 289 | } | ||||
| 290 | |||||
| 291 | /* | ||||
| 292 | * Check if blown | ||||
| 293 | */ | ||||
| 294 | bool_Bool rtems_stack_checker_is_blown( void ) | ||||
| 295 | { | ||||
| 296 | Stack_Control *the_stack = &_Thread_Executing_Per_CPU_Information.executing->Start.Initial_stack; | ||||
| 297 | bool_Bool sp_ok; | ||||
| 298 | bool_Bool pattern_ok = true1; | ||||
| 299 | |||||
| 300 | /* | ||||
| 301 | * Check for an out of bounds stack pointer | ||||
| 302 | */ | ||||
| 303 | |||||
| 304 | sp_ok = Stack_check_Frame_pointer_in_range( the_stack ); | ||||
| 305 | |||||
| 306 | /* | ||||
| 307 | * The stack checker must be initialized before the pattern is there | ||||
| 308 | * to check. | ||||
| 309 | */ | ||||
| 310 | if ( Stack_check_Initialized ) { | ||||
| |||||
| 311 | pattern_ok = (!memcmp( | ||||
| 312 | (void *) Stack_check_Get_pattern_area(the_stack)((Stack_check_Control *) ((char *)(the_stack)->area + sizeof (Heap_Block) - (2 * sizeof(uintptr_t) + 0)))->pattern, | ||||
| |||||
| 313 | (void *) Stack_check_Pattern.pattern, | ||||
| 314 | PATTERN_SIZE_BYTES((4) * sizeof(uint32_t)) | ||||
| 315 | )); | ||||
| 316 | } | ||||
| 317 | |||||
| 318 | |||||
| 319 | /* | ||||
| 320 | * Let's report as much as we can. | ||||
| 321 | */ | ||||
| 322 | if ( !sp_ok || !pattern_ok ) { | ||||
| 323 | Stack_check_report_blown_task( _Thread_Executing_Per_CPU_Information.executing, pattern_ok ); | ||||
| 324 | /* DOES NOT RETURN */ | ||||
| 325 | } | ||||
| 326 | |||||
| 327 | /* | ||||
| 328 | * The Stack Pointer and the Pattern Area are OK so return false. | ||||
| 329 | */ | ||||
| 330 | return false0; | ||||
| 331 | } | ||||
| 332 | |||||
| 333 | /* | ||||
| 334 | * Stack_check_find_high_water_mark | ||||
| 335 | */ | ||||
| 336 | static inline void *Stack_check_find_high_water_mark( | ||||
| 337 | const void *s, | ||||
| 338 | size_t n | ||||
| 339 | ) | ||||
| 340 | { | ||||
| 341 | const uint32_t *base, *ebase; | ||||
| 342 | uint32_t length; | ||||
| 343 | |||||
| 344 | base = s; | ||||
| 345 | length = n/4; | ||||
| 346 | |||||
| 347 | #if ( CPU_STACK_GROWS_UP0 == TRUE1 ) | ||||
| 348 | /* | ||||
| 349 | * start at higher memory and find first word that does not | ||||
| 350 | * match pattern | ||||
| 351 | */ | ||||
| 352 | |||||
| 353 | base += length - 1; | ||||
| 354 | for (ebase = s; base > ebase; base--) | ||||
| 355 | if (*base != U32_PATTERN0xA5A5A5A5) | ||||
| 356 | return (void *) base; | ||||
| 357 | #else | ||||
| 358 | /* | ||||
| 359 | * start at lower memory and find first word that does not | ||||
| 360 | * match pattern | ||||
| 361 | */ | ||||
| 362 | |||||
| 363 | base += PATTERN_SIZE_WORDS(4); | ||||
| 364 | for (ebase = base + length; base < ebase; base++) | ||||
| 365 | if (*base != U32_PATTERN0xA5A5A5A5) | ||||
| 366 | return (void *) base; | ||||
| 367 | #endif | ||||
| 368 | |||||
| 369 | return (void *)0; | ||||
| 370 | } | ||||
| 371 | |||||
| 372 | /* | ||||
| 373 | * Stack_check_Dump_threads_usage | ||||
| 374 | * | ||||
| 375 | * Try to print out how much stack was actually used by the task. | ||||
| 376 | */ | ||||
| 377 | static void *print_context; | ||||
| 378 | static rtems_printk_plugin_t print_handler; | ||||
| 379 | |||||
| 380 | void Stack_check_Dump_threads_usage( | ||||
| 381 | Thread_Control *the_thread | ||||
| 382 | ) | ||||
| 383 | { | ||||
| 384 | uint32_t size, used; | ||||
| 385 | void *low; | ||||
| 386 | void *high_water_mark; | ||||
| 387 | void *current; | ||||
| 388 | Stack_Control *stack; | ||||
| 389 | char name[5]; | ||||
| 390 | |||||
| 391 | /* | ||||
| 392 | * The pointer passed in for the_thread is guaranteed to be non-NULL from | ||||
| 393 | * rtems_iterate_over_all_threads() so no need to check it here. | ||||
| 394 | */ | ||||
| 395 | |||||
| 396 | /* | ||||
| 397 | * Obtain interrupt stack information | ||||
| 398 | */ | ||||
| 399 | #if (CPU_ALLOCATE_INTERRUPT_STACK1 == TRUE1) | ||||
| 400 | if (the_thread == (Thread_Control *) -1) { | ||||
| 401 | if (!Stack_check_Interrupt_stack.area) | ||||
| 402 | return; | ||||
| 403 | stack = &Stack_check_Interrupt_stack; | ||||
| 404 | the_thread = 0; | ||||
| 405 | current = 0; | ||||
| 406 | } else | ||||
| 407 | #endif | ||||
| 408 | { | ||||
| 409 | stack = &the_thread->Start.Initial_stack; | ||||
| 410 | current = (void *)_CPU_Context_Get_SP( &the_thread->Registers )(&the_thread->Registers)->o6_sp; | ||||
| 411 | } | ||||
| 412 | |||||
| 413 | low = Stack_check_usable_stack_start(stack)((char *)(stack)->area + sizeof(Stack_check_Control)); | ||||
| 414 | size = Stack_check_usable_stack_size(stack)((stack)->size - sizeof(Stack_check_Control)); | ||||
| 415 | |||||
| 416 | high_water_mark = Stack_check_find_high_water_mark(low, size); | ||||
| 417 | |||||
| 418 | if ( high_water_mark ) | ||||
| 419 | used = Stack_check_Calculate_used( low, size, high_water_mark )( ((char *)(low) + (size)) - (char *)(high_water_mark) ); | ||||
| 420 | else | ||||
| 421 | used = 0; | ||||
| 422 | |||||
| 423 | |||||
| 424 | #if (CPU_ALLOCATE_INTERRUPT_STACK1 == TRUE1) | ||||
| 425 | if ( the_thread ) | ||||
| 426 | #endif | ||||
| 427 | { | ||||
| 428 | (*print_handler)( | ||||
| 429 | print_context, | ||||
| 430 | "0x%08" PRIx32"x" " %4s", | ||||
| 431 | the_thread->Object.id, | ||||
| 432 | rtems_object_get_name( the_thread->Object.id, sizeof(name), name ) | ||||
| 433 | ); | ||||
| 434 | } | ||||
| 435 | #if (CPU_ALLOCATE_INTERRUPT_STACK1 == TRUE1) | ||||
| 436 | else { | ||||
| 437 | (*print_handler)( print_context, "0x%08" PRIx32"x" " INTR", ~0 ); | ||||
| 438 | } | ||||
| 439 | #endif | ||||
| 440 | |||||
| 441 | (*print_handler)( | ||||
| 442 | print_context, | ||||
| 443 | " %010p - %010p %010p %8" PRId32"d" " ", | ||||
| 444 | stack->area, | ||||
| 445 | stack->area + stack->size - 1, | ||||
| 446 | current, | ||||
| 447 | size | ||||
| 448 | ); | ||||
| 449 | |||||
| 450 | if (Stack_check_Initialized == 0) { | ||||
| 451 | (*print_handler)( print_context, "Unavailable\n" ); | ||||
| 452 | } else { | ||||
| 453 | (*print_handler)( print_context, "%8" PRId32"d" "\n", used ); | ||||
| 454 | } | ||||
| 455 | |||||
| 456 | |||||
| 457 | } | ||||
| 458 | |||||
| 459 | /* | ||||
| 460 | * rtems_stack_checker_fatal_extension | ||||
| 461 | */ | ||||
| 462 | #ifndef DONT_USE_FATAL_EXTENSION | ||||
| 463 | void rtems_stack_checker_fatal_extension( | ||||
| 464 | Internal_errors_Source source, | ||||
| 465 | bool_Bool is_internal, | ||||
| 466 | uint32_t status | ||||
| 467 | ) | ||||
| 468 | { | ||||
| 469 | if (status == 0) | ||||
| 470 | rtems_stack_checker_report_usage(); | ||||
| 471 | } | ||||
| 472 | #endif | ||||
| 473 | |||||
| 474 | /*PAGE | ||||
| 475 | * | ||||
| 476 | * rtems_stack_checker_report_usage | ||||
| 477 | */ | ||||
| 478 | |||||
| 479 | void rtems_stack_checker_report_usage_with_plugin( | ||||
| 480 | void *context, | ||||
| 481 | rtems_printk_plugin_t print | ||||
| 482 | ) | ||||
| 483 | { | ||||
| 484 | if ( !print ) | ||||
| 485 | return; | ||||
| 486 | |||||
| 487 | print_context = context; | ||||
| 488 | print_handler = print; | ||||
| 489 | |||||
| 490 | (*print)( context, "Stack usage by thread\n"); | ||||
| 491 | (*print)( context, | ||||
| 492 | " ID NAME LOW HIGH CURRENT AVAILABLE USED\n" | ||||
| 493 | ); | ||||
| 494 | |||||
| 495 | /* iterate over all threads and dump the usage */ | ||||
| 496 | rtems_iterate_over_all_threads( Stack_check_Dump_threads_usage ); | ||||
| 497 | |||||
| 498 | #if (CPU_ALLOCATE_INTERRUPT_STACK1 == TRUE1) | ||||
| 499 | /* dump interrupt stack info if any */ | ||||
| 500 | Stack_check_Dump_threads_usage((Thread_Control *) -1); | ||||
| 501 | #endif | ||||
| 502 | |||||
| 503 | print_context = NULL((void*)0); | ||||
| 504 | print_handler = NULL((void*)0); | ||||
| 505 | } | ||||
| 506 | |||||
| 507 | void rtems_stack_checker_report_usage( void ) | ||||
| 508 | { | ||||
| 509 | rtems_stack_checker_report_usage_with_plugin( NULL((void*)0), printk_plugin ); | ||||
| 510 | } |