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 | } |