source: rtems/cpukit/libmisc/stackchk/check.c @ c3330a8

4.104.114.84.95
Last change on this file since c3330a8 was c3330a8, checked in by Joel Sherrill <joel.sherrill@…>, on 05/17/07 at 22:46:45

2007-05-17 Joel Sherrill <joel.sherrill@…>

  • ChangeLog?, configure.ac, libcsupport/src/times.c, libmisc/cpuuse/cpuuse.c, libmisc/stackchk/check.c, rtems/include/rtems/rtems/ratemon.h, rtems/src/ratemongetstatus.c, rtems/src/ratemonperiod.c, rtems/src/ratemonreportstatistics.c, rtems/src/ratemonresetall.c, rtems/src/ratemontimeout.c, score/Makefile.am, score/include/rtems/score/thread.h, score/include/rtems/score/timespec.h, score/src/threaddispatch.c, score/src/threadinitialize.c, score/src/threadtickletimeslice.c, score/src/timespecdivide.c: Add nanoseconds granularity to the rate monotonic period statistics and CPU usage statistics. This capability is enabled by default although may be conditionally disabled by the user. It could be too much overhead on small targets but it does not appear to be bad in early testing. Its impact on code size has not been evaluated either. It is possible that both forms of statistics gathering could be disabled with further tweaking of the conditional compilation.
  • score/src/timespecdividebyinteger.c: New file.
  • Property mode set to 100644
File size: 10.4 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  /*
269   *  Check for an out of bounds stack pointer and then an overwrite
270   */
[ac7d5ef0]271
[d8ec87b4]272  sp_ok = Stack_check_Frame_pointer_in_range( the_stack );
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  void          *pattern;
288  boolean        sp_ok;
289  boolean        pattern_ok = TRUE;
290
291  pattern = (void *) Stack_check_Get_pattern_area(the_stack)->pattern;
292
293  /*
294   *  Check for an out of bounds stack pointer and then an overwrite
295   */
296
297  sp_ok = Stack_check_Frame_pointer_in_range( the_stack );
298  pattern_ok = (!memcmp( pattern,
299            (void *) Stack_check_Pattern.pattern, PATTERN_SIZE_BYTES));
300
301  if ( !sp_ok || !pattern_ok ) {
302    return TRUE;
303  }
304  return FALSE;
305}
306
307/*
308 * Stack_check_find_high_water_mark
309 */
[ac7d5ef0]310void *Stack_check_find_high_water_mark(
311  const void *s,
[4da36c1a]312  size_t      n
[ac7d5ef0]313)
314{
[3e08d4e]315  const uint32_t   *base, *ebase;
316  uint32_t   length;
[ac7d5ef0]317
318  base = s;
319  length = n/4;
320
[4da36c1a]321  #if ( CPU_STACK_GROWS_UP == TRUE )
322    /*
323     * start at higher memory and find first word that does not
324     * match pattern
325     */
[ac7d5ef0]326
[4da36c1a]327    base += length - 1;
328    for (ebase = s; base > ebase; base--)
[c3330a8]329      if (*base != U32_PATTERN)
330        return (void *) base;
[4da36c1a]331  #else
332    /*
333     * start at lower memory and find first word that does not
334     * match pattern
335     */
[ac7d5ef0]336
[4da36c1a]337    base += PATTERN_SIZE_WORDS;
338    for (ebase = base + length; base < ebase; base++)
[c3330a8]339      if (*base != U32_PATTERN)
340        return (void *) base;
[4da36c1a]341  #endif
[ac7d5ef0]342
343  return (void *)0;
344}
345
[4da36c1a]346/*
[7ac4ae9]347 *  Stack_check_Dump_threads_usage(
[ac7d5ef0]348 *
[4da36c1a]349 *  Try to print out how much stack was actually used by the task.
[ac7d5ef0]350 */
351void Stack_check_Dump_threads_usage(
352  Thread_Control *the_thread
353)
354{
[3e08d4e]355  uint32_t        size, used;
[ac7d5ef0]356  void           *low;
357  void           *high_water_mark;
358  Stack_Control  *stack;
[c3330a8]359  char            name[5];
[ac7d5ef0]360
361  if ( !the_thread )
362    return;
363
364  /*
365   * XXX HACK to get to interrupt stack
366   */
367
[4da36c1a]368  if (the_thread == (Thread_Control *) -1) {
369    if (Stack_check_Interrupt_stack.area) {
370      stack = &Stack_check_Interrupt_stack;
371      the_thread = 0;
372    }
373    else
374      return;
375  } else
376    stack = &the_thread->Start.Initial_stack;
[ac7d5ef0]377
378  low  = Stack_check_usable_stack_start(stack);
379  size = Stack_check_usable_stack_size(stack);
380
381  high_water_mark = Stack_check_find_high_water_mark(low, size);
382
383  if ( high_water_mark )
384    used = Stack_check_Calculate_used( low, size, high_water_mark );
385  else
386    used = 0;
387
[e819fefc]388  if ( the_thread ) {
[c3330a8]389    rtems_object_get_name( the_thread->Object.id, sizeof(name), name );
[e819fefc]390  } else {
[c3330a8]391    name[ 0 ] = 'I';
392    name[ 1 ] = 'N';
393    name[ 2 ] = 'T';
394    name[ 3 ] = 'R';
[e819fefc]395    name[ 4 ] = '\0';
396  }
[c46ce854]397
[c3330a8]398  printk("0x%08" PRIx32 "  %4s  0x%p - 0x%p   %8" PRId32 "   %8" PRId32 "\n",
[4da36c1a]399    the_thread ? the_thread->Object.id : ~0,
400    name,
401    stack->area,
402    stack->area + stack->size - 1,
403    size,
404    used
[ac7d5ef0]405  );
406}
407
[4da36c1a]408/*
[7ac4ae9]409 *  rtems_stack_checker_fatal_extension
[ac7d5ef0]410 */
[4da36c1a]411#ifndef DONT_USE_FATAL_EXTENSION
412  void rtems_stack_checker_fatal_extension(
[11290355]413    Internal_errors_Source  source,
414    boolean                 is_internal,
[3e08d4e]415    uint32_t                status
[4da36c1a]416  )
417  {
[ac7d5ef0]418    if (status == 0)
[4da36c1a]419      rtems_stack_checker_report_usage();
420  }
[8389628]421#endif
[ac7d5ef0]422
423/*PAGE
424 *
[8583f82]425 *  rtems_stack_checker_report_usage
[ac7d5ef0]426 */
427
[8583f82]428void rtems_stack_checker_report_usage( void )
[ac7d5ef0]429{
[4da36c1a]430  if (Stack_check_Initialized == 0)
[ac7d5ef0]431      return;
432
[d8ec87b4]433  printk("Stack usage by thread\n");
434  printk(
[baa876a4]435    "    ID      NAME       LOW        HIGH     AVAILABLE      USED\n"
[ac7d5ef0]436  );
[5250ff39]437
[d8ec87b4]438  /* iterate over all threads and dump the usage */
439  rtems_iterate_over_all_threads( Stack_check_Dump_threads_usage );
[ac7d5ef0]440
441  /* dump interrupt stack info if any */
442  Stack_check_Dump_threads_usage((Thread_Control *) -1);
443}
Note: See TracBrowser for help on using the repository browser.