[f5f2676] | 1 | /** |
---|
| 2 | * @file |
---|
| 3 | * |
---|
| 4 | * @brief Stack Overflow Check User Extension Set |
---|
| 5 | * @ingroup libmisc_stackchk Stack Checker Mechanism |
---|
[ac7d5ef0] | 6 | * |
---|
[f5f2676] | 7 | * NOTE: This extension set automatically determines at |
---|
[ac7d5ef0] | 8 | * initialization time whether the stack for this |
---|
| 9 | * CPU grows up or down and installs the correct |
---|
| 10 | * extension routines for that direction. |
---|
[f5f2676] | 11 | */ |
---|
| 12 | |
---|
| 13 | /* |
---|
[d22cd4a] | 14 | * COPYRIGHT (c) 1989-2010. |
---|
[ac7d5ef0] | 15 | * On-Line Applications Research Corporation (OAR). |
---|
| 16 | * |
---|
[98e4ebf5] | 17 | * The license and distribution terms for this file may be |
---|
| 18 | * found in the file LICENSE in this distribution or at |
---|
[c499856] | 19 | * http://www.rtems.org/license/LICENSE. |
---|
[ac7d5ef0] | 20 | * |
---|
| 21 | */ |
---|
| 22 | |
---|
[550c3df7] | 23 | #ifdef HAVE_CONFIG_H |
---|
| 24 | #include "config.h" |
---|
| 25 | #endif |
---|
| 26 | |
---|
[3a4ae6c] | 27 | #include <rtems.h> |
---|
[3523321] | 28 | #include <inttypes.h> |
---|
[3a4ae6c] | 29 | |
---|
[8389628] | 30 | /* |
---|
[4da36c1a] | 31 | * The stack dump information may be printed by a "fatal" extension. |
---|
[8389628] | 32 | * Fatal extensions only get called via rtems_fatal_error_occurred() |
---|
| 33 | * and not when rtems_shutdown_executive() is called. |
---|
| 34 | * When that happens, this #define should be deleted and all the code |
---|
| 35 | * it marks. |
---|
| 36 | */ |
---|
| 37 | #define DONT_USE_FATAL_EXTENSION |
---|
| 38 | |
---|
[ac7d5ef0] | 39 | #include <string.h> |
---|
| 40 | #include <stdlib.h> |
---|
| 41 | |
---|
[d8ec87b4] | 42 | #include <rtems/bspIo.h> |
---|
[506bfc8] | 43 | #include <rtems/printer.h> |
---|
[bfc3533] | 44 | #include <rtems/stackchk.h> |
---|
[5f31bbe] | 45 | #include <rtems/score/percpu.h> |
---|
[7ced9d9b] | 46 | #include <rtems/score/threadimpl.h> |
---|
[bba988d] | 47 | |
---|
| 48 | /* |
---|
| 49 | * This structure is used to fill in and compare the "end of stack" |
---|
| 50 | * marker pattern. |
---|
| 51 | * pattern area must be a multiple of 4 words. |
---|
| 52 | */ |
---|
| 53 | |
---|
[8bb9d41] | 54 | #if !defined(CPU_STACK_CHECK_PATTERN_INITIALIZER) |
---|
| 55 | #define CPU_STACK_CHECK_PATTERN_INITIALIZER \ |
---|
| 56 | { \ |
---|
| 57 | 0xFEEDF00D, 0x0BAD0D06, /* FEED FOOD to BAD DOG */ \ |
---|
| 58 | 0xDEADF00D, 0x600D0D06 /* DEAD FOOD but GOOD DOG */ \ |
---|
| 59 | } |
---|
[bba988d] | 60 | #endif |
---|
| 61 | |
---|
| 62 | /* |
---|
| 63 | * The pattern used to fill the entire stack. |
---|
| 64 | */ |
---|
| 65 | |
---|
| 66 | #define BYTE_PATTERN 0xA5 |
---|
| 67 | #define U32_PATTERN 0xA5A5A5A5 |
---|
| 68 | |
---|
[ac7d5ef0] | 69 | /* |
---|
[4da36c1a] | 70 | * Variable to indicate when the stack checker has been initialized. |
---|
[ac7d5ef0] | 71 | */ |
---|
[4da36c1a] | 72 | static int Stack_check_Initialized = 0; |
---|
[ac7d5ef0] | 73 | |
---|
| 74 | /* |
---|
| 75 | * The "magic pattern" used to mark the end of the stack. |
---|
| 76 | */ |
---|
[8bb9d41] | 77 | static const uint32_t Stack_check_Pattern[] = |
---|
| 78 | CPU_STACK_CHECK_PATTERN_INITIALIZER; |
---|
| 79 | |
---|
| 80 | #define PATTERN_SIZE_BYTES sizeof(Stack_check_Pattern) |
---|
| 81 | |
---|
| 82 | #define PATTERN_SIZE_WORDS RTEMS_ARRAY_SIZE(Stack_check_Pattern) |
---|
[ac7d5ef0] | 83 | |
---|
[d8ec87b4] | 84 | /* |
---|
| 85 | * Helper function to report if the actual stack pointer is in range. |
---|
| 86 | * |
---|
| 87 | * NOTE: This uses a GCC specific method. |
---|
| 88 | */ |
---|
[937ec60] | 89 | static inline bool Stack_check_Frame_pointer_in_range( |
---|
[8bb9d41] | 90 | const Thread_Control *the_thread |
---|
[d8ec87b4] | 91 | ) |
---|
| 92 | { |
---|
| 93 | #if defined(__GNUC__) |
---|
[b99a35a] | 94 | void *sp = __builtin_frame_address(0); |
---|
[8bb9d41] | 95 | const Stack_Control *the_stack = &the_thread->Start.Initial_stack; |
---|
[b99a35a] | 96 | |
---|
[d8ec87b4] | 97 | if ( sp < the_stack->area ) { |
---|
[937ec60] | 98 | return false; |
---|
[d8ec87b4] | 99 | } |
---|
| 100 | if ( sp > (the_stack->area + the_stack->size) ) { |
---|
[937ec60] | 101 | return false; |
---|
[d8ec87b4] | 102 | } |
---|
[4da36c1a] | 103 | #else |
---|
| 104 | #error "How do I check stack bounds on a non-GNU compiler?" |
---|
[d8ec87b4] | 105 | #endif |
---|
[937ec60] | 106 | return true; |
---|
[d8ec87b4] | 107 | } |
---|
| 108 | |
---|
[ac7d5ef0] | 109 | /* |
---|
| 110 | * Where the pattern goes in the stack area is dependent upon |
---|
| 111 | * whether the stack grow to the high or low area of the memory. |
---|
| 112 | */ |
---|
[4da36c1a] | 113 | #if (CPU_STACK_GROWS_UP == TRUE) |
---|
[16b1546e] | 114 | #define Stack_check_Get_pattern( _the_stack ) \ |
---|
| 115 | ((char *)(_the_stack)->area + \ |
---|
[8bb9d41] | 116 | (_the_stack)->size - PATTERN_SIZE_BYTES ) |
---|
[ac7d5ef0] | 117 | |
---|
[4da36c1a] | 118 | #define Stack_check_Calculate_used( _low, _size, _high_water ) \ |
---|
| 119 | ((char *)(_high_water) - (char *)(_low)) |
---|
[ac7d5ef0] | 120 | |
---|
[4da36c1a] | 121 | #define Stack_check_usable_stack_start(_the_stack) \ |
---|
[ac7d5ef0] | 122 | ((_the_stack)->area) |
---|
| 123 | |
---|
| 124 | #else |
---|
[518c2aeb] | 125 | /* |
---|
| 126 | * We need this magic offset because during a task delete the task stack will |
---|
| 127 | * be freed before we enter the task switch extension which checks the stack. |
---|
| 128 | * The task stack free operation will write the next and previous pointers |
---|
| 129 | * for the free list into this area. |
---|
| 130 | */ |
---|
[16b1546e] | 131 | #define Stack_check_Get_pattern( _the_stack ) \ |
---|
[11236580] | 132 | ((char *)(_the_stack)->area + sizeof(Heap_Block) - HEAP_BLOCK_HEADER_SIZE) |
---|
[ac7d5ef0] | 133 | |
---|
[4da36c1a] | 134 | #define Stack_check_Calculate_used( _low, _size, _high_water) \ |
---|
| 135 | ( ((char *)(_low) + (_size)) - (char *)(_high_water) ) |
---|
[d8ec87b4] | 136 | |
---|
[4da36c1a] | 137 | #define Stack_check_usable_stack_start(_the_stack) \ |
---|
[8bb9d41] | 138 | ((char *)(_the_stack)->area + PATTERN_SIZE_BYTES) |
---|
[ac7d5ef0] | 139 | |
---|
| 140 | #endif |
---|
| 141 | |
---|
[4da36c1a] | 142 | /* |
---|
| 143 | * The assumption is that if the pattern gets overwritten, the task |
---|
| 144 | * is too close. This defines the usable stack memory. |
---|
| 145 | */ |
---|
[ac7d5ef0] | 146 | #define Stack_check_usable_stack_size(_the_stack) \ |
---|
[8bb9d41] | 147 | ((_the_stack)->size - PATTERN_SIZE_BYTES) |
---|
[ac7d5ef0] | 148 | |
---|
[2d637b2] | 149 | #if (CPU_ALLOCATE_INTERRUPT_STACK == TRUE) |
---|
| 150 | /* |
---|
| 151 | * Did RTEMS allocate the interrupt stack? If so, put it in |
---|
| 152 | * Stack_Control format. |
---|
| 153 | */ |
---|
| 154 | Stack_Control Stack_check_Interrupt_stack; |
---|
| 155 | #endif |
---|
[ac7d5ef0] | 156 | |
---|
| 157 | /* |
---|
[4da36c1a] | 158 | * Fill an entire stack area with BYTE_PATTERN. This will be used |
---|
| 159 | * to check for amount of actual stack used. |
---|
[ac7d5ef0] | 160 | */ |
---|
[4da36c1a] | 161 | #define Stack_check_Dope_stack(_stack) \ |
---|
| 162 | memset((_stack)->area, BYTE_PATTERN, (_stack)->size) |
---|
[ac7d5ef0] | 163 | |
---|
[4da36c1a] | 164 | /* |
---|
| 165 | * Stack_check_Initialize |
---|
[ac7d5ef0] | 166 | */ |
---|
[13a69b9] | 167 | static void Stack_check_Initialize( void ) |
---|
[ac7d5ef0] | 168 | { |
---|
[21e3de1] | 169 | if ( Stack_check_Initialized ) |
---|
[d8ec87b4] | 170 | return; |
---|
[ac7d5ef0] | 171 | |
---|
| 172 | /* |
---|
| 173 | * If appropriate, setup the interrupt stack for high water testing |
---|
| 174 | * also. |
---|
| 175 | */ |
---|
[4da36c1a] | 176 | #if (CPU_ALLOCATE_INTERRUPT_STACK == TRUE) |
---|
| 177 | if (_CPU_Interrupt_stack_low && _CPU_Interrupt_stack_high) { |
---|
| 178 | Stack_check_Interrupt_stack.area = _CPU_Interrupt_stack_low; |
---|
| 179 | Stack_check_Interrupt_stack.size = (char *) _CPU_Interrupt_stack_high - |
---|
| 180 | (char *) _CPU_Interrupt_stack_low; |
---|
| 181 | Stack_check_Dope_stack(&Stack_check_Interrupt_stack); |
---|
[da9b538] | 182 | } |
---|
[4da36c1a] | 183 | #endif |
---|
[8389628] | 184 | |
---|
[4da36c1a] | 185 | Stack_check_Initialized = 1; |
---|
[ac7d5ef0] | 186 | } |
---|
| 187 | |
---|
[8bb9d41] | 188 | static bool Stack_check_Is_pattern_valid(const Thread_Control *the_thread) |
---|
| 189 | { |
---|
| 190 | return memcmp( |
---|
| 191 | Stack_check_Get_pattern(&the_thread->Start.Initial_stack), |
---|
| 192 | Stack_check_Pattern, |
---|
| 193 | PATTERN_SIZE_BYTES |
---|
| 194 | ) == 0; |
---|
| 195 | } |
---|
| 196 | |
---|
[4da36c1a] | 197 | /* |
---|
[7ac4ae9] | 198 | * rtems_stack_checker_create_extension |
---|
[ac7d5ef0] | 199 | */ |
---|
[937ec60] | 200 | bool rtems_stack_checker_create_extension( |
---|
[f97536d] | 201 | Thread_Control *running RTEMS_UNUSED, |
---|
[ac7d5ef0] | 202 | Thread_Control *the_thread |
---|
| 203 | ) |
---|
| 204 | { |
---|
[4da36c1a] | 205 | Stack_check_Initialize(); |
---|
[84e960e] | 206 | Stack_check_Dope_stack(&the_thread->Start.Initial_stack); |
---|
[ac7d5ef0] | 207 | |
---|
[8bb9d41] | 208 | memcpy( |
---|
| 209 | Stack_check_Get_pattern(&the_thread->Start.Initial_stack), |
---|
| 210 | Stack_check_Pattern, |
---|
| 211 | PATTERN_SIZE_BYTES |
---|
| 212 | ); |
---|
[84e960e] | 213 | |
---|
| 214 | return true; |
---|
[ac7d5ef0] | 215 | } |
---|
| 216 | |
---|
[4da36c1a] | 217 | /* |
---|
[ac7d5ef0] | 218 | * Stack_check_report_blown_task |
---|
[4da36c1a] | 219 | * |
---|
[ac7d5ef0] | 220 | * Report a blown stack. Needs to be a separate routine |
---|
| 221 | * so that interrupt handlers can use this too. |
---|
| 222 | * |
---|
| 223 | * NOTE: The system is in a questionable state... we may not get |
---|
| 224 | * the following message out. |
---|
| 225 | */ |
---|
[8bb9d41] | 226 | static void Stack_check_report_blown_task( |
---|
| 227 | const Thread_Control *running, |
---|
[da9b538] | 228 | bool pattern_ok |
---|
[8bb9d41] | 229 | ) |
---|
[ac7d5ef0] | 230 | { |
---|
[8bb9d41] | 231 | const Stack_Control *stack = &running->Start.Initial_stack; |
---|
| 232 | void *pattern_area = Stack_check_Get_pattern(stack); |
---|
| 233 | char name[32]; |
---|
[ac7d5ef0] | 234 | |
---|
[8a775c27] | 235 | printk("BLOWN STACK!!!\n"); |
---|
[560db810] | 236 | printk("task control block: 0x%08" PRIxPTR "\n", (intptr_t) running); |
---|
[8a775c27] | 237 | printk("task ID: 0x%08lx\n", (unsigned long) running->Object.id); |
---|
| 238 | printk( |
---|
[a89c963] | 239 | "task name: 0x%08" PRIx32 "\n", |
---|
| 240 | running->Object.name.name_u32 |
---|
[8a775c27] | 241 | ); |
---|
[7ced9d9b] | 242 | _Thread_Get_name(running, name, sizeof(name)); |
---|
| 243 | printk("task name string: %s\n", name); |
---|
[8a775c27] | 244 | printk( |
---|
[a89c963] | 245 | "task stack area (%lu Bytes): 0x%08" PRIxPTR " .. 0x%08" PRIxPTR "\n", |
---|
[8a775c27] | 246 | (unsigned long) stack->size, |
---|
[560db810] | 247 | (intptr_t) stack->area, |
---|
| 248 | (intptr_t) ((char *) stack->area + stack->size) |
---|
[8a775c27] | 249 | ); |
---|
| 250 | if (!pattern_ok) { |
---|
| 251 | printk( |
---|
[a89c963] | 252 | "damaged pattern area (%lu Bytes): 0x%08" PRIxPTR " .. 0x%08" PRIxPTR "\n", |
---|
[8a775c27] | 253 | (unsigned long) PATTERN_SIZE_BYTES, |
---|
[560db810] | 254 | (intptr_t) pattern_area, |
---|
| 255 | (intptr_t) (pattern_area + PATTERN_SIZE_BYTES) |
---|
[8a775c27] | 256 | ); |
---|
| 257 | } |
---|
[ac7d5ef0] | 258 | |
---|
[4da36c1a] | 259 | #if defined(RTEMS_MULTIPROCESSING) |
---|
| 260 | if (rtems_configuration_get_user_multiprocessing_table()) { |
---|
[d8ec87b4] | 261 | printk( |
---|
[a89c963] | 262 | "node: 0x%08" PRIxPTR "\n", |
---|
[560db810] | 263 | (intptr_t) rtems_configuration_get_user_multiprocessing_table()->node |
---|
[4da36c1a] | 264 | ); |
---|
[d8ec87b4] | 265 | } |
---|
[4da36c1a] | 266 | #endif |
---|
| 267 | |
---|
[a12f7e9] | 268 | rtems_fatal( |
---|
| 269 | RTEMS_FATAL_SOURCE_STACK_CHECKER, |
---|
| 270 | running->Object.name.name_u32 |
---|
| 271 | ); |
---|
[ac7d5ef0] | 272 | } |
---|
| 273 | |
---|
[4da36c1a] | 274 | /* |
---|
[7ac4ae9] | 275 | * rtems_stack_checker_switch_extension |
---|
[ac7d5ef0] | 276 | */ |
---|
[7ac4ae9] | 277 | void rtems_stack_checker_switch_extension( |
---|
[f97536d] | 278 | Thread_Control *running RTEMS_UNUSED, |
---|
| 279 | Thread_Control *heir RTEMS_UNUSED |
---|
[ac7d5ef0] | 280 | ) |
---|
| 281 | { |
---|
[8bb9d41] | 282 | bool sp_ok; |
---|
| 283 | bool pattern_ok; |
---|
[d8ec87b4] | 284 | |
---|
| 285 | /* |
---|
[2b596c69] | 286 | * Check for an out of bounds stack pointer or an overwrite |
---|
[d8ec87b4] | 287 | */ |
---|
[8bb9d41] | 288 | sp_ok = Stack_check_Frame_pointer_in_range( running ); |
---|
[2b596c69] | 289 | |
---|
[8bb9d41] | 290 | pattern_ok = Stack_check_Is_pattern_valid( running ); |
---|
[d8ec87b4] | 291 | |
---|
| 292 | if ( !sp_ok || !pattern_ok ) { |
---|
| 293 | Stack_check_report_blown_task( running, pattern_ok ); |
---|
[ac7d5ef0] | 294 | } |
---|
| 295 | } |
---|
| 296 | |
---|
[4da36c1a] | 297 | /* |
---|
| 298 | * Check if blown |
---|
| 299 | */ |
---|
[937ec60] | 300 | bool rtems_stack_checker_is_blown( void ) |
---|
[4da36c1a] | 301 | { |
---|
[8bb9d41] | 302 | rtems_stack_checker_switch_extension( _Thread_Get_executing(), NULL ); |
---|
[0faa8b11] | 303 | |
---|
| 304 | /* |
---|
[da9b538] | 305 | * The Stack Pointer and the Pattern Area are OK so return false. |
---|
[0faa8b11] | 306 | */ |
---|
[da9b538] | 307 | return false; |
---|
[4da36c1a] | 308 | } |
---|
| 309 | |
---|
| 310 | /* |
---|
| 311 | * Stack_check_find_high_water_mark |
---|
| 312 | */ |
---|
[da9b538] | 313 | static inline void *Stack_check_find_high_water_mark( |
---|
[ac7d5ef0] | 314 | const void *s, |
---|
[4da36c1a] | 315 | size_t n |
---|
[ac7d5ef0] | 316 | ) |
---|
| 317 | { |
---|
[3e08d4e] | 318 | const uint32_t *base, *ebase; |
---|
| 319 | uint32_t length; |
---|
[ac7d5ef0] | 320 | |
---|
| 321 | base = s; |
---|
| 322 | length = n/4; |
---|
| 323 | |
---|
[4da36c1a] | 324 | #if ( CPU_STACK_GROWS_UP == TRUE ) |
---|
| 325 | /* |
---|
| 326 | * start at higher memory and find first word that does not |
---|
| 327 | * match pattern |
---|
| 328 | */ |
---|
[ac7d5ef0] | 329 | |
---|
[4da36c1a] | 330 | base += length - 1; |
---|
| 331 | for (ebase = s; base > ebase; base--) |
---|
[c3330a8] | 332 | if (*base != U32_PATTERN) |
---|
| 333 | return (void *) base; |
---|
[4da36c1a] | 334 | #else |
---|
| 335 | /* |
---|
| 336 | * start at lower memory and find first word that does not |
---|
| 337 | * match pattern |
---|
| 338 | */ |
---|
[ac7d5ef0] | 339 | |
---|
[4da36c1a] | 340 | base += PATTERN_SIZE_WORDS; |
---|
| 341 | for (ebase = base + length; base < ebase; base++) |
---|
[c3330a8] | 342 | if (*base != U32_PATTERN) |
---|
| 343 | return (void *) base; |
---|
[4da36c1a] | 344 | #endif |
---|
[ac7d5ef0] | 345 | |
---|
| 346 | return (void *)0; |
---|
| 347 | } |
---|
| 348 | |
---|
[4da36c1a] | 349 | /* |
---|
[90a5d194] | 350 | * Stack_check_Dump_threads_usage |
---|
[ac7d5ef0] | 351 | * |
---|
[4da36c1a] | 352 | * Try to print out how much stack was actually used by the task. |
---|
[ac7d5ef0] | 353 | */ |
---|
[d271c3bb] | 354 | static bool Stack_check_Dump_threads_usage( |
---|
| 355 | Thread_Control *the_thread, |
---|
| 356 | void *arg |
---|
[ac7d5ef0] | 357 | ) |
---|
| 358 | { |
---|
[d271c3bb] | 359 | uint32_t size, used; |
---|
| 360 | void *low; |
---|
| 361 | void *high_water_mark; |
---|
| 362 | void *current; |
---|
| 363 | Stack_Control *stack; |
---|
[7ced9d9b] | 364 | char name[ 22 ]; |
---|
[d271c3bb] | 365 | const rtems_printer *printer; |
---|
[7ced9d9b] | 366 | uint32_t id; |
---|
[ac7d5ef0] | 367 | |
---|
[d271c3bb] | 368 | printer = arg; |
---|
[90a5d194] | 369 | |
---|
[ac7d5ef0] | 370 | /* |
---|
[dbfc895e] | 371 | * Obtain interrupt stack information |
---|
[ac7d5ef0] | 372 | */ |
---|
[2d637b2] | 373 | #if (CPU_ALLOCATE_INTERRUPT_STACK == TRUE) |
---|
| 374 | if (the_thread == (Thread_Control *) -1) { |
---|
| 375 | if (!Stack_check_Interrupt_stack.area) |
---|
[d271c3bb] | 376 | return false; |
---|
[4da36c1a] | 377 | stack = &Stack_check_Interrupt_stack; |
---|
| 378 | the_thread = 0; |
---|
[dbfc895e] | 379 | current = 0; |
---|
[f5f2676] | 380 | } else |
---|
[d4a97df3] | 381 | #endif |
---|
[2d637b2] | 382 | { |
---|
| 383 | stack = &the_thread->Start.Initial_stack; |
---|
| 384 | current = (void *)_CPU_Context_Get_SP( &the_thread->Registers ); |
---|
[4da36c1a] | 385 | } |
---|
[ac7d5ef0] | 386 | |
---|
| 387 | low = Stack_check_usable_stack_start(stack); |
---|
| 388 | size = Stack_check_usable_stack_size(stack); |
---|
| 389 | |
---|
| 390 | high_water_mark = Stack_check_find_high_water_mark(low, size); |
---|
| 391 | |
---|
| 392 | if ( high_water_mark ) |
---|
| 393 | used = Stack_check_Calculate_used( low, size, high_water_mark ); |
---|
| 394 | else |
---|
| 395 | used = 0; |
---|
| 396 | |
---|
[7ced9d9b] | 397 | #if (CPU_ALLOCATE_INTERRUPT_STACK == TRUE) |
---|
| 398 | if ( the_thread == NULL ) { |
---|
| 399 | id = 0xffffffff; |
---|
| 400 | strlcpy( name, "INTR", sizeof( name ) ); |
---|
| 401 | } else |
---|
| 402 | #endif |
---|
| 403 | { |
---|
| 404 | id = the_thread->Object.id; |
---|
| 405 | _Thread_Get_name( the_thread, name, sizeof( name ) ); |
---|
| 406 | } |
---|
[c46ce854] | 407 | |
---|
[24d0ee57] | 408 | rtems_printf( |
---|
| 409 | printer, |
---|
[7ced9d9b] | 410 | "0x%08" PRIx32 " %-21s 0x%08" PRIuPTR " 0x%08" PRIuPTR " 0x%08" PRIuPTR " %6" PRId32 " ", |
---|
| 411 | id, |
---|
| 412 | name, |
---|
| 413 | (uintptr_t) stack->area, |
---|
| 414 | (uintptr_t) stack->area + (uintptr_t) stack->size - 1, |
---|
| 415 | (uintptr_t) current, |
---|
[dbfc895e] | 416 | size |
---|
[ac7d5ef0] | 417 | ); |
---|
[dbfc895e] | 418 | |
---|
| 419 | if (Stack_check_Initialized == 0) { |
---|
[7ced9d9b] | 420 | rtems_printf( printer, "N/A\n" ); |
---|
[dbfc895e] | 421 | } else { |
---|
[7ced9d9b] | 422 | rtems_printf( printer, "%6" PRId32 "\n", used ); |
---|
[dbfc895e] | 423 | } |
---|
[0893220] | 424 | |
---|
[d271c3bb] | 425 | return false; |
---|
[ac7d5ef0] | 426 | } |
---|
| 427 | |
---|
[4da36c1a] | 428 | /* |
---|
[7ac4ae9] | 429 | * rtems_stack_checker_fatal_extension |
---|
[ac7d5ef0] | 430 | */ |
---|
[4da36c1a] | 431 | #ifndef DONT_USE_FATAL_EXTENSION |
---|
| 432 | void rtems_stack_checker_fatal_extension( |
---|
[11290355] | 433 | Internal_errors_Source source, |
---|
[6a9282d] | 434 | bool always_set_to_false, |
---|
[3e08d4e] | 435 | uint32_t status |
---|
[4da36c1a] | 436 | ) |
---|
| 437 | { |
---|
[ac7d5ef0] | 438 | if (status == 0) |
---|
[4da36c1a] | 439 | rtems_stack_checker_report_usage(); |
---|
| 440 | } |
---|
[8389628] | 441 | #endif |
---|
[ac7d5ef0] | 442 | |
---|
[64adc13] | 443 | /* |
---|
[8583f82] | 444 | * rtems_stack_checker_report_usage |
---|
[ac7d5ef0] | 445 | */ |
---|
| 446 | |
---|
[90a5d194] | 447 | void rtems_stack_checker_report_usage_with_plugin( |
---|
[d271c3bb] | 448 | const rtems_printer* printer |
---|
[90a5d194] | 449 | ) |
---|
[ac7d5ef0] | 450 | { |
---|
[7ced9d9b] | 451 | rtems_printf( |
---|
| 452 | printer, |
---|
| 453 | " STACK USAGE BY THREAD\n" |
---|
| 454 | "ID NAME LOW HIGH CURRENT AVAIL USED\n" |
---|
[ac7d5ef0] | 455 | ); |
---|
[5250ff39] | 456 | |
---|
[d8ec87b4] | 457 | /* iterate over all threads and dump the usage */ |
---|
[d271c3bb] | 458 | rtems_task_iterate( |
---|
| 459 | Stack_check_Dump_threads_usage, |
---|
| 460 | RTEMS_DECONST( rtems_printer *, printer ) |
---|
| 461 | ); |
---|
[ac7d5ef0] | 462 | |
---|
[2d637b2] | 463 | #if (CPU_ALLOCATE_INTERRUPT_STACK == TRUE) |
---|
| 464 | /* dump interrupt stack info if any */ |
---|
[d271c3bb] | 465 | Stack_check_Dump_threads_usage( |
---|
| 466 | (Thread_Control *) -1, |
---|
| 467 | RTEMS_DECONST( rtems_printer *, printer ) |
---|
| 468 | ); |
---|
[2d637b2] | 469 | #endif |
---|
[90a5d194] | 470 | } |
---|
| 471 | |
---|
| 472 | void rtems_stack_checker_report_usage( void ) |
---|
| 473 | { |
---|
[24d0ee57] | 474 | rtems_printer printer; |
---|
| 475 | rtems_print_printer_printk(&printer); |
---|
| 476 | rtems_stack_checker_report_usage_with_plugin( &printer ); |
---|
[ac7d5ef0] | 477 | } |
---|