source: rtems/cpukit/libmisc/stackchk/check.c @ 9b4422a2

4.11
Last change on this file since 9b4422a2 was 9b4422a2, checked in by Joel Sherrill <joel.sherrill@…>, on May 3, 2012 at 3:09:24 PM

Remove All CVS Id Strings Possible Using a Script

Script does what is expected and tries to do it as
smartly as possible.

+ remove occurrences of two blank comment lines

next to each other after Id string line removed.

+ remove entire comment blocks which only exited to

contain CVS Ids

+ If the processing left a blank line at the top of

a file, it was removed.

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