source: rtems/cpukit/libmisc/stackchk/check.c @ 33eeeb2

4.104.114.84.95
Last change on this file since 33eeeb2 was 33eeeb2, checked in by Joel Sherrill <joel.sherrill@…>, on 09/14/07 at 22:53:39

2007-09-14 Joel Sherrill <joel.sherrill@…>

  • libmisc/stackchk/check.c: Fix alignment of output.
  • Property mode set to 100644
File size: 10.9 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 *
[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]47static int   Stack_check_Initialized = 0;
[ac7d5ef0]48
49/*
50 *  The "magic pattern" used to mark the end of the stack.
51 */
52Stack_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 */
59static inline boolean Stack_check_Frame_pointer_in_range(
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 ) {
67      printk( "Stack Pointer Too Low!\n" );
68      return FALSE;
69    }
70    if ( sp > (the_stack->area + the_stack->size) ) {
71      printk( "Stack Pointer Too High!\n" );
72      return FALSE;
73    }
[4da36c1a]74  #else
75    #error "How do I check stack bounds on a non-GNU compiler?"
[d8ec87b4]76  #endif
77  return TRUE;
78}
79
[ac7d5ef0]80/*
81 *  Where the pattern goes in the stack area is dependent upon
82 *  whether the stack grow to the high or low area of the memory.
83 */
[4da36c1a]84#if (CPU_STACK_GROWS_UP == TRUE)
85  #define Stack_check_Get_pattern_area( _the_stack ) \
86    ((Stack_check_Control *) ((char *)(_the_stack)->area + \
87         (_the_stack)->size - sizeof( Stack_check_Control ) ))
[ac7d5ef0]88
[4da36c1a]89  #define Stack_check_Calculate_used( _low, _size, _high_water ) \
90      ((char *)(_high_water) - (char *)(_low))
[ac7d5ef0]91
[4da36c1a]92  #define Stack_check_usable_stack_start(_the_stack) \
[ac7d5ef0]93    ((_the_stack)->area)
94
95#else
[4da36c1a]96  #define Stack_check_Get_pattern_area( _the_stack ) \
97    ((Stack_check_Control *) ((char *)(_the_stack)->area + HEAP_OVERHEAD))
[ac7d5ef0]98
[4da36c1a]99  #define Stack_check_Calculate_used( _low, _size, _high_water) \
100      ( ((char *)(_low) + (_size)) - (char *)(_high_water) )
[d8ec87b4]101
[4da36c1a]102  #define Stack_check_usable_stack_start(_the_stack) \
103      ((char *)(_the_stack)->area + sizeof(Stack_check_Control))
[ac7d5ef0]104
105#endif
106
[4da36c1a]107/*
108 *  The assumption is that if the pattern gets overwritten, the task
109 *  is too close.  This defines the usable stack memory.
110 */
[ac7d5ef0]111#define Stack_check_usable_stack_size(_the_stack) \
112    ((_the_stack)->size - sizeof(Stack_check_Control))
113
114/*
115 * Do we have an interrupt stack?
116 * XXX it would sure be nice if the interrupt stack were also
117 *     stored in a "stack" structure!
118 */
[4da36c1a]119Stack_Control Stack_check_Interrupt_stack;
[ac7d5ef0]120
121/*
[4da36c1a]122 *  Fill an entire stack area with BYTE_PATTERN.  This will be used
123 *  to check for amount of actual stack used.
[ac7d5ef0]124 */
[4da36c1a]125#define Stack_check_Dope_stack(_stack) \
126  memset((_stack)->area, BYTE_PATTERN, (_stack)->size)
[ac7d5ef0]127
[4da36c1a]128/*
129 *  Stack_check_Initialize
[ac7d5ef0]130 */
[4da36c1a]131void Stack_check_Initialize( void )
[ac7d5ef0]132{
[4da36c1a]133  uint32_t *p;
[ac7d5ef0]134
[4da36c1a]135  if (Stack_check_Initialized)
[d8ec87b4]136    return;
[ac7d5ef0]137
138  /*
139   * Dope the pattern and fill areas
140   */
141
142  for ( p = Stack_check_Pattern.pattern;
143        p < &Stack_check_Pattern.pattern[PATTERN_SIZE_WORDS];
144        p += 4
[4da36c1a]145      ) {
[ac7d5ef0]146      p[0] = 0xFEEDF00D;          /* FEED FOOD to BAD DOG */
147      p[1] = 0x0BAD0D06;
148      p[2] = 0xDEADF00D;          /* DEAD FOOD GOOD DOG */
149      p[3] = 0x600D0D06;
[4da36c1a]150  }
151 
[ac7d5ef0]152  /*
153   * If appropriate, setup the interrupt stack for high water testing
154   * also.
155   */
[4da36c1a]156  #if (CPU_ALLOCATE_INTERRUPT_STACK == TRUE)
157    if (_CPU_Interrupt_stack_low && _CPU_Interrupt_stack_high) {
158      Stack_check_Interrupt_stack.area = _CPU_Interrupt_stack_low;
159      Stack_check_Interrupt_stack.size = (char *) _CPU_Interrupt_stack_high -
160                                  (char *) _CPU_Interrupt_stack_low;
161      Stack_check_Dope_stack(&Stack_check_Interrupt_stack);
[ac7d5ef0]162  }
[4da36c1a]163  #endif
[8389628]164
[4da36c1a]165  Stack_check_Initialized = 1;
[ac7d5ef0]166}
167
[4da36c1a]168/*
[7ac4ae9]169 *  rtems_stack_checker_create_extension
[ac7d5ef0]170 */
[7ac4ae9]171boolean rtems_stack_checker_create_extension(
[ac7d5ef0]172  Thread_Control *running,
173  Thread_Control *the_thread
174)
175{
[4da36c1a]176  Stack_check_Initialize();
[71f4beb]177
[4da36c1a]178  if (the_thread)
179    Stack_check_Dope_stack(&the_thread->Start.Initial_stack);
[3a4ae6c]180
[4da36c1a]181  return TRUE;
[ac7d5ef0]182}
183
[4da36c1a]184/*
[7ac4ae9]185 *  rtems_stack_checker_Begin_extension
[ac7d5ef0]186 */
[7ac4ae9]187void rtems_stack_checker_begin_extension(
[ac7d5ef0]188  Thread_Control *the_thread
189)
190{
191  Stack_check_Control  *the_pattern;
192
193  if ( the_thread->Object.id == 0 )        /* skip system tasks */
194    return;
195
196  the_pattern = Stack_check_Get_pattern_area(&the_thread->Start.Initial_stack);
197
198  *the_pattern = Stack_check_Pattern;
199}
200
[4da36c1a]201/*
[ac7d5ef0]202 *  Stack_check_report_blown_task
[4da36c1a]203 *
[ac7d5ef0]204 *  Report a blown stack.  Needs to be a separate routine
205 *  so that interrupt handlers can use this too.
206 *
207 *  NOTE: The system is in a questionable state... we may not get
208 *        the following message out.
209 */
[d8ec87b4]210void Stack_check_report_blown_task(
211  Thread_Control *running,
212  boolean         pattern_ok
213)
[ac7d5ef0]214{
[4da36c1a]215  Stack_Control *stack = &running->Start.Initial_stack;
[ac7d5ef0]216
[4da36c1a]217  printk(
[c3330a8]218    "BLOWN STACK!!! Offending task(0x%p): "
219        "id=0x%08" PRIx32 "; name=0x%08" PRIx32,
[4da36c1a]220    running,
221    running->Object.id,
222    (uint32_t) running->Object.name
223  );
[ac7d5ef0]224
[4da36c1a]225  #if defined(RTEMS_MULTIPROCESSING)
226    if (rtems_configuration_get_user_multiprocessing_table()) {
[d8ec87b4]227      printk(
[4da36c1a]228        "; node=%d\n",
229        rtems_configuration_get_user_multiprocessing_table()->node
230      );
[d8ec87b4]231    }
[4da36c1a]232  #else
233      printk( "\n" );
234  #endif
235
236  printk(
[c3330a8]237    "  stack covers range 0x%p - 0x%p (%d bytes)\n",
[4da36c1a]238    stack->area,
239    stack->area + stack->size - 1,
240    stack->size
241  );
[ac7d5ef0]242
[4da36c1a]243  if ( !pattern_ok ) {
244    printk(
245      "  Damaged pattern begins at 0x%08lx and is %ld bytes long\n",
246      (unsigned long) Stack_check_Get_pattern_area(stack),
247      (long) PATTERN_SIZE_BYTES);
248  }
249
250  rtems_fatal_error_occurred( 0x81 );
[ac7d5ef0]251}
252
[4da36c1a]253/*
[7ac4ae9]254 *  rtems_stack_checker_switch_extension
[ac7d5ef0]255 */
[7ac4ae9]256void rtems_stack_checker_switch_extension(
[ac7d5ef0]257  Thread_Control *running,
258  Thread_Control *heir
259)
260{
[d8ec87b4]261  Stack_Control *the_stack = &running->Start.Initial_stack;
262  void          *pattern;
263  boolean        sp_ok;
264  boolean        pattern_ok = TRUE;
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 */
284boolean rtems_stack_checker_is_blown( void )
285{
286  Stack_Control *the_stack = &_Thread_Executing->Start.Initial_stack;
287  boolean        sp_ok;
288  boolean        pattern_ok = TRUE;
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
308  if ( !sp_ok || !pattern_ok ) {
309    return TRUE;
310  }
311  return FALSE;
312}
313
314/*
315 * Stack_check_find_high_water_mark
316 */
[ac7d5ef0]317void *Stack_check_find_high_water_mark(
318  const void *s,
[4da36c1a]319  size_t      n
[ac7d5ef0]320)
321{
[3e08d4e]322  const uint32_t   *base, *ebase;
323  uint32_t   length;
[ac7d5ef0]324
325  base = s;
326  length = n/4;
327
[4da36c1a]328  #if ( CPU_STACK_GROWS_UP == TRUE )
329    /*
330     * start at higher memory and find first word that does not
331     * match pattern
332     */
[ac7d5ef0]333
[4da36c1a]334    base += length - 1;
335    for (ebase = s; base > ebase; base--)
[c3330a8]336      if (*base != U32_PATTERN)
337        return (void *) base;
[4da36c1a]338  #else
339    /*
340     * start at lower memory and find first word that does not
341     * match pattern
342     */
[ac7d5ef0]343
[4da36c1a]344    base += PATTERN_SIZE_WORDS;
345    for (ebase = base + length; base < ebase; base++)
[c3330a8]346      if (*base != U32_PATTERN)
347        return (void *) base;
[4da36c1a]348  #endif
[ac7d5ef0]349
350  return (void *)0;
351}
352
[4da36c1a]353/*
[90a5d194]354 *  Stack_check_Dump_threads_usage
[ac7d5ef0]355 *
[4da36c1a]356 *  Try to print out how much stack was actually used by the task.
[ac7d5ef0]357 */
[90a5d194]358static void                   *print_context;
359static rtems_printk_plugin_t   print_handler;
360
[ac7d5ef0]361void Stack_check_Dump_threads_usage(
362  Thread_Control *the_thread
363)
364{
[3e08d4e]365  uint32_t        size, used;
[ac7d5ef0]366  void           *low;
367  void           *high_water_mark;
368  Stack_Control  *stack;
[c3330a8]369  char            name[5];
[ac7d5ef0]370
371  if ( !the_thread )
372    return;
373
[90a5d194]374  if ( !print_handler )
375    return;
376
[ac7d5ef0]377  /*
378   * XXX HACK to get to interrupt stack
379   */
380
[4da36c1a]381  if (the_thread == (Thread_Control *) -1) {
382    if (Stack_check_Interrupt_stack.area) {
383      stack = &Stack_check_Interrupt_stack;
384      the_thread = 0;
385    }
386    else
387      return;
388  } else
389    stack = &the_thread->Start.Initial_stack;
[ac7d5ef0]390
391  low  = Stack_check_usable_stack_start(stack);
392  size = Stack_check_usable_stack_size(stack);
393
394  high_water_mark = Stack_check_find_high_water_mark(low, size);
395
396  if ( high_water_mark )
397    used = Stack_check_Calculate_used( low, size, high_water_mark );
398  else
399    used = 0;
400
[e819fefc]401  if ( the_thread ) {
[c3330a8]402    rtems_object_get_name( the_thread->Object.id, sizeof(name), name );
[e819fefc]403  } else {
[c3330a8]404    name[ 0 ] = 'I';
405    name[ 1 ] = 'N';
406    name[ 2 ] = 'T';
407    name[ 3 ] = 'R';
[e819fefc]408    name[ 4 ] = '\0';
409  }
[c46ce854]410
[90a5d194]411  (*print_handler)(
412    print_context,
[33eeeb2]413    "0x%08" PRIx32 "  %4s  %08p - %08p   %8" PRId32 "   %8" PRId32 "\n",
[4da36c1a]414    the_thread ? the_thread->Object.id : ~0,
415    name,
416    stack->area,
417    stack->area + stack->size - 1,
418    size,
419    used
[ac7d5ef0]420  );
421}
422
[4da36c1a]423/*
[7ac4ae9]424 *  rtems_stack_checker_fatal_extension
[ac7d5ef0]425 */
[4da36c1a]426#ifndef DONT_USE_FATAL_EXTENSION
427  void rtems_stack_checker_fatal_extension(
[11290355]428    Internal_errors_Source  source,
429    boolean                 is_internal,
[3e08d4e]430    uint32_t                status
[4da36c1a]431  )
432  {
[ac7d5ef0]433    if (status == 0)
[4da36c1a]434      rtems_stack_checker_report_usage();
435  }
[8389628]436#endif
[ac7d5ef0]437
438/*PAGE
439 *
[8583f82]440 *  rtems_stack_checker_report_usage
[ac7d5ef0]441 */
442
[90a5d194]443void rtems_stack_checker_report_usage_with_plugin(
444  void                  *context,
445  rtems_printk_plugin_t  print
446)
[ac7d5ef0]447{
[4da36c1a]448  if (Stack_check_Initialized == 0)
[ac7d5ef0]449      return;
450
[90a5d194]451  print_context = context;
452  print_handler = print;
453
454  (*print)( context, "Stack usage by thread\n");
455  (*print)( context,
[33eeeb2]456    "    ID      NAME    LOW        HIGH     AVAILABLE      USED\n"
[ac7d5ef0]457  );
[5250ff39]458
[d8ec87b4]459  /* iterate over all threads and dump the usage */
460  rtems_iterate_over_all_threads( Stack_check_Dump_threads_usage );
[ac7d5ef0]461
462  /* dump interrupt stack info if any */
463  Stack_check_Dump_threads_usage((Thread_Control *) -1);
[90a5d194]464
465  print_context = NULL;
466  print_handler = NULL;
467
468}
469
470void rtems_stack_checker_report_usage( void )
471{
472  rtems_stack_checker_report_usage_with_plugin( NULL, printk_plugin );
[ac7d5ef0]473}
Note: See TracBrowser for help on using the repository browser.