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