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 May 17, 2007 at 10:46:45 PM

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
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-2007.
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$
17 *
18 */
19
20#ifdef HAVE_CONFIG_H
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 <assert.h>
37#include <string.h>
38#include <stdlib.h>
39
40#include <rtems/bspIo.h>
41#include <rtems/stackchk.h>
42#include "internal.h"
43
44/*
45 *  Variable to indicate when the stack checker has been initialized.
46 */
47static int   Stack_check_Initialized = 0;
48
49/*
50 *  The "magic pattern" used to mark the end of the stack.
51 */
52Stack_check_Control Stack_check_Pattern;
53
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    }
74  #else
75    #error "How do I check stack bounds on a non-GNU compiler?"
76  #endif
77  return TRUE;
78}
79
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 */
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 ) ))
88
89  #define Stack_check_Calculate_used( _low, _size, _high_water ) \
90      ((char *)(_high_water) - (char *)(_low))
91
92  #define Stack_check_usable_stack_start(_the_stack) \
93    ((_the_stack)->area)
94
95#else
96  #define Stack_check_Get_pattern_area( _the_stack ) \
97    ((Stack_check_Control *) ((char *)(_the_stack)->area + HEAP_OVERHEAD))
98
99  #define Stack_check_Calculate_used( _low, _size, _high_water) \
100      ( ((char *)(_low) + (_size)) - (char *)(_high_water) )
101
102  #define Stack_check_usable_stack_start(_the_stack) \
103      ((char *)(_the_stack)->area + sizeof(Stack_check_Control))
104
105#endif
106
107/*
108 *  The assumption is that if the pattern gets overwritten, the task
109 *  is too close.  This defines the usable stack memory.
110 */
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 */
119Stack_Control Stack_check_Interrupt_stack;
120
121/*
122 *  Fill an entire stack area with BYTE_PATTERN.  This will be used
123 *  to check for amount of actual stack used.
124 */
125#define Stack_check_Dope_stack(_stack) \
126  memset((_stack)->area, BYTE_PATTERN, (_stack)->size)
127
128/*
129 *  Stack_check_Initialize
130 */
131void Stack_check_Initialize( void )
132{
133  uint32_t *p;
134
135  if (Stack_check_Initialized)
136    return;
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
145      ) {
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;
150  }
151 
152  /*
153   * If appropriate, setup the interrupt stack for high water testing
154   * also.
155   */
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);
162  }
163  #endif
164
165  Stack_check_Initialized = 1;
166}
167
168/*
169 *  rtems_stack_checker_create_extension
170 */
171boolean rtems_stack_checker_create_extension(
172  Thread_Control *running,
173  Thread_Control *the_thread
174)
175{
176  Stack_check_Initialize();
177
178  if (the_thread)
179    Stack_check_Dope_stack(&the_thread->Start.Initial_stack);
180
181  return TRUE;
182}
183
184/*
185 *  rtems_stack_checker_Begin_extension
186 */
187void rtems_stack_checker_begin_extension(
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
201/*
202 *  Stack_check_report_blown_task
203 *
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 */
210void Stack_check_report_blown_task(
211  Thread_Control *running,
212  boolean         pattern_ok
213)
214{
215  Stack_Control *stack = &running->Start.Initial_stack;
216
217  printk(
218    "BLOWN STACK!!! Offending task(0x%p): "
219        "id=0x%08" PRIx32 "; name=0x%08" PRIx32,
220    running,
221    running->Object.id,
222    (uint32_t) running->Object.name
223  );
224
225  #if defined(RTEMS_MULTIPROCESSING)
226    if (rtems_configuration_get_user_multiprocessing_table()) {
227      printk(
228        "; node=%d\n",
229        rtems_configuration_get_user_multiprocessing_table()->node
230      );
231    }
232  #else
233      printk( "\n" );
234  #endif
235
236  printk(
237    "  stack covers range 0x%p - 0x%p (%d bytes)\n",
238    stack->area,
239    stack->area + stack->size - 1,
240    stack->size
241  );
242
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 );
251}
252
253/*
254 *  rtems_stack_checker_switch_extension
255 */
256void rtems_stack_checker_switch_extension(
257  Thread_Control *running,
258  Thread_Control *heir
259)
260{
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   */
271
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 );
278  }
279}
280
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 */
310void *Stack_check_find_high_water_mark(
311  const void *s,
312  size_t      n
313)
314{
315  const uint32_t   *base, *ebase;
316  uint32_t   length;
317
318  base = s;
319  length = n/4;
320
321  #if ( CPU_STACK_GROWS_UP == TRUE )
322    /*
323     * start at higher memory and find first word that does not
324     * match pattern
325     */
326
327    base += length - 1;
328    for (ebase = s; base > ebase; base--)
329      if (*base != U32_PATTERN)
330        return (void *) base;
331  #else
332    /*
333     * start at lower memory and find first word that does not
334     * match pattern
335     */
336
337    base += PATTERN_SIZE_WORDS;
338    for (ebase = base + length; base < ebase; base++)
339      if (*base != U32_PATTERN)
340        return (void *) base;
341  #endif
342
343  return (void *)0;
344}
345
346/*
347 *  Stack_check_Dump_threads_usage(
348 *
349 *  Try to print out how much stack was actually used by the task.
350 */
351void Stack_check_Dump_threads_usage(
352  Thread_Control *the_thread
353)
354{
355  uint32_t        size, used;
356  void           *low;
357  void           *high_water_mark;
358  Stack_Control  *stack;
359  char            name[5];
360
361  if ( !the_thread )
362    return;
363
364  /*
365   * XXX HACK to get to interrupt stack
366   */
367
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;
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
388  if ( the_thread ) {
389    rtems_object_get_name( the_thread->Object.id, sizeof(name), name );
390  } else {
391    name[ 0 ] = 'I';
392    name[ 1 ] = 'N';
393    name[ 2 ] = 'T';
394    name[ 3 ] = 'R';
395    name[ 4 ] = '\0';
396  }
397
398  printk("0x%08" PRIx32 "  %4s  0x%p - 0x%p   %8" PRId32 "   %8" PRId32 "\n",
399    the_thread ? the_thread->Object.id : ~0,
400    name,
401    stack->area,
402    stack->area + stack->size - 1,
403    size,
404    used
405  );
406}
407
408/*
409 *  rtems_stack_checker_fatal_extension
410 */
411#ifndef DONT_USE_FATAL_EXTENSION
412  void rtems_stack_checker_fatal_extension(
413    Internal_errors_Source  source,
414    boolean                 is_internal,
415    uint32_t                status
416  )
417  {
418    if (status == 0)
419      rtems_stack_checker_report_usage();
420  }
421#endif
422
423/*PAGE
424 *
425 *  rtems_stack_checker_report_usage
426 */
427
428void rtems_stack_checker_report_usage( void )
429{
430  if (Stack_check_Initialized == 0)
431      return;
432
433  printk("Stack usage by thread\n");
434  printk(
435    "    ID      NAME       LOW        HIGH     AVAILABLE      USED\n"
436  );
437
438  /* iterate over all threads and dump the usage */
439  rtems_iterate_over_all_threads( Stack_check_Dump_threads_usage );
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.