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