source: rtems/cpukit/libmisc/stackchk/check.c @ 13a69b9

4.115
Last change on this file since 13a69b9 was 13a69b9, checked in by Ralf Corsepius <ralf.corsepius@…>, on 12/06/11 at 15:22:13

2011-12-06 Ralf Corsépius <ralf.corsepius@…>

  • libmisc/stackchk/check.c: Make Stack_check_Initialize, Stack_check_Dump_threads_usage static.
  • Property mode set to 100644
File size: 12.5 KB
RevLine 
[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]46static int   Stack_check_Initialized = 0;
[ac7d5ef0]47
48/*
49 *  The "magic pattern" used to mark the end of the stack.
50 */
51Stack_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]58static 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]141static 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]180bool 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]196void 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]219void Stack_check_report_blown_task(
220  Thread_Control *running,
221  bool pattern_ok
222) RTEMS_COMPILER_NO_RETURN_ATTRIBUTE;
223
[8a775c27]224void 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]271void 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]299bool 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]341static 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]382static void                   *print_context;
383static rtems_printk_plugin_t   print_handler;
384
[13a69b9]385static 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]483void 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
511void rtems_stack_checker_report_usage( void )
512{
513  rtems_stack_checker_report_usage_with_plugin( NULL, printk_plugin );
[ac7d5ef0]514}
Note: See TracBrowser for help on using the repository browser.