source: rtems/c/src/lib/libmisc/stackchk/check.c @ 88d594a

4.104.114.84.95
Last change on this file since 88d594a was 88d594a, checked in by Joel Sherrill <joel.sherrill@…>, on May 24, 1995 at 9:39:42 PM

Fully tested on all in-house targets

  • Property mode set to 100644
File size: 10.2 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, 1990, 1991, 1992, 1993, 1994.
10 *  On-Line Applications Research Corporation (OAR).
11 *  All rights assigned to U.S. Government, 1994.
12 *
13 *  This material may be reproduced by or for the U.S. Government pursuant
14 *  to the copyright license under the clause at DFARS 252.227-7013.  This
15 *  notice must appear in all copies of this file and its derivatives.
16 *
17 *  $Id$
18 *
19 */
20
21#include <rtems/system.h>
22#include <rtems/extension.h>
23#include <rtems/fatal.h>
24#include <rtems/heap.h>
25#include <rtems/stack.h>
26#include <rtems/thread.h>
27#ifdef XXX_RTEMS_H_FIXED
28#include <bsp.h>
29#else
30#include <rtems/config.h>
31extern rtems_configuration_table BSP_Configuration;
32#endif
33
34#include <assert.h>
35#include <stdio.h>
36#include <string.h>
37#include <stdlib.h>
38
39#include "stackchk.h"
40#include "internal.h"
41
42/*
43 *  This variable contains the name of the task which "blew" the stack.
44 *  It is NULL if the system is all right.
45 */
46
47Thread_Control *Stack_check_Blown_task;
48
49/*
50 *  The extension table for the stack checker.
51 */
52
53rtems_extensions_table Stack_check_Extension_table = {
54  Stack_check_Create_extension,     /* rtems_task_create  */
55  0,                                /* rtems_task_start   */
56  0,                                /* rtems_task_restart */
57  0,                                /* rtems_task_delete  */
58  Stack_check_Switch_extension,     /* task_switch  */
59  Stack_check_Begin_extension,      /* task_begin   */
60  0,                                /* task_exitted */
61  Stack_check_Fatal_extension,      /* fatal        */
62};
63
64/*
65 *  The "magic pattern" used to mark the end of the stack.
66 */
67
68Stack_check_Control Stack_check_Pattern;
69
70/*
71 *  Where the pattern goes in the stack area is dependent upon
72 *  whether the stack grow to the high or low area of the memory.
73 *
74 */
75
76#if ( CPU_STACK_GROWS_UP == TRUE )
77
78#define Stack_check_Get_pattern_area( _the_stack ) \
79  ((Stack_check_Control *) \
80    ((_the_stack)->area + (_the_stack)->size - sizeof( Stack_check_Control ) ))
81
82#define Stack_check_Calculate_used( _low, _size, _high_water ) \
83    ((_high_water) - (_low))
84
85#define Stack_check_usable_stack_start(_the_stack) \
86    ((_the_stack)->area)
87
88#else
89
90#define Stack_check_Get_pattern_area( _the_stack ) \
91  ((Stack_check_Control *) ((_the_stack)->area + HEAP_OVERHEAD))
92
93#define Stack_check_Calculate_used( _low, _size, _high_water) \
94    ( ((_low) + (_size)) - (_high_water) )
95
96#define Stack_check_usable_stack_start(_the_stack) \
97    ((_the_stack)->area + sizeof(Stack_check_Control))
98
99#endif
100
101#define Stack_check_usable_stack_size(_the_stack) \
102    ((_the_stack)->size - sizeof(Stack_check_Control))
103
104
105/*
106 * Do we have an interrupt stack?
107 * XXX it would sure be nice if the interrupt stack were also
108 *     stored in a "stack" structure!
109 */
110
111
112Stack_Control stack_check_interrupt_stack;
113
114/*
115 * Fill an entire stack area with BYTE_PATTERN.
116 * This will be used by a Fatal extension to check for
117 * amount of actual stack used
118 */
119
120void
121stack_check_dope_stack(Stack_Control *stack)
122{
123    memset(stack->area, BYTE_PATTERN, stack->size);
124}
125
126
127/*PAGE
128 *
129 *  Stack_check_Initialize
130 */
131
132unsigned32 stack_check_initialized = 0;
133
134void Stack_check_Initialize( void )
135{
136  rtems_status_code status;
137  Objects_Id   id_ignored;
138  unsigned32  *p;
139
140  if (stack_check_initialized)
141      return;
142
143  /*
144   * Dope the pattern and fill areas
145   */
146
147  for ( p = Stack_check_Pattern.pattern;
148        p < &Stack_check_Pattern.pattern[PATTERN_SIZE_WORDS];
149        p += 4
150      )
151  {
152      p[0] = 0xFEEDF00D;          /* FEED FOOD to BAD DOG */
153      p[1] = 0x0BAD0D06;
154      p[2] = 0xDEADF00D;          /* DEAD FOOD GOOD DOG */
155      p[3] = 0x600D0D06;
156  };
157
158  status = rtems_extension_create(
159    rtems_build_name( 'S', 'T', 'C', 'K' ),
160    &Stack_check_Extension_table,
161    &id_ignored
162  );
163  assert ( status == RTEMS_SUCCESSFUL );
164
165  Stack_check_Blown_task = 0;
166
167  /*
168   * If installed by a task, that task will not get setup properly
169   * since it missed out on the create hook.  This will cause a
170   * failure on first switch out of that task.
171   * So pretend here that we actually ran create and begin extensions.
172   */
173
174  if (_Thread_Executing)
175  {
176      Stack_check_Create_extension(_Thread_Executing, _Thread_Executing);
177  }
178
179  /*
180   * If appropriate, setup the interrupt stack for high water testing
181   * also.
182   */
183  if (_CPU_Interrupt_stack_low && _CPU_Interrupt_stack_high)
184  {
185      stack_check_interrupt_stack.area = _CPU_Interrupt_stack_low;
186      stack_check_interrupt_stack.size = _CPU_Interrupt_stack_high -
187                                               _CPU_Interrupt_stack_low;
188
189      stack_check_dope_stack(&stack_check_interrupt_stack);
190  }
191
192  stack_check_initialized = 1;
193}
194
195/*PAGE
196 *
197 *  Stack_check_Create_extension
198 */
199
200void Stack_check_Create_extension(
201  Thread_Control *running,
202  Thread_Control *the_thread
203)
204{
205    if (the_thread && (the_thread != _Thread_Executing))
206        stack_check_dope_stack(&the_thread->Start.Initial_stack);
207}
208
209/*PAGE
210 *
211 *  Stack_check_Begin_extension
212 */
213
214void Stack_check_Begin_extension(
215  Thread_Control *the_thread
216)
217{
218  Stack_check_Control  *the_pattern;
219
220  if ( the_thread->Object.id == 0 )        /* skip system tasks */
221    return;
222
223  the_pattern = Stack_check_Get_pattern_area(&the_thread->Start.Initial_stack);
224
225  *the_pattern = Stack_check_Pattern;
226}
227
228/*PAGE
229 *
230 *  Stack_check_report_blown_task
231 *  Report a blown stack.  Needs to be a separate routine
232 *  so that interrupt handlers can use this too.
233 *
234 *  Caller must have set the Stack_check_Blown_task.
235 *
236 *  NOTE: The system is in a questionable state... we may not get
237 *        the following message out.
238 */
239
240void Stack_check_report_blown_task(void)
241{
242    Stack_Control *stack;
243    Thread_Control *running;
244
245    running = Stack_check_Blown_task;
246    stack = &running->Start.Initial_stack;
247
248    fprintf(
249        stderr,
250        "BLOWN STACK!!! Offending task(%p): id=0x%08x; name=0x%08x",
251        running,
252        running->Object.id,
253        running->name);
254    fflush(stderr);
255
256    if (BSP_Configuration.User_multiprocessing_table)
257        fprintf(
258          stderr,
259          "; node=%d\n",
260          BSP_Configuration.User_multiprocessing_table->node
261       );
262    else
263        fprintf(stderr, "\n");
264    fflush(stderr);
265
266    fprintf(
267        stderr,
268        "  stack covers range 0x%08x - 0x%08x (%d bytes)\n",
269        (unsigned32) stack->area,
270        (unsigned32) stack->area + stack->size - 1,
271        (unsigned32) stack->size);
272    fflush(stderr);
273
274    fprintf(
275        stderr,
276        "  Damaged pattern begins at 0x%08x and is %d bytes long\n",
277        (unsigned32) Stack_check_Get_pattern_area(stack), PATTERN_SIZE_BYTES);
278    fflush(stderr);
279
280    rtems_fatal_error_occurred( (unsigned32) "STACK BLOWN" );
281}
282
283/*PAGE
284 *
285 *  Stack_check_Switch_extension
286 */
287
288void Stack_check_Switch_extension(
289  Thread_Control *running,
290  Thread_Control *heir
291)
292{
293  if ( running->Object.id == 0 )        /* skip system tasks */
294    return;
295
296  if (0 != memcmp( (void *) Stack_check_Get_pattern_area( &running->Start.Initial_stack)->pattern,
297                  (void *) Stack_check_Pattern.pattern,
298                  PATTERN_SIZE_BYTES))
299  {
300      Stack_check_Blown_task = running;
301      Stack_check_report_blown_task();
302  }
303}
304
305void *Stack_check_find_high_water_mark(
306  const void *s,
307  size_t n
308)
309{
310  const unsigned32 *base, *ebase;
311  unsigned32 length;
312
313  base = s;
314  length = n/4;
315
316#if ( CPU_STACK_GROWS_UP == TRUE )
317  /*
318   * start at higher memory and find first word that does not
319   * match pattern
320   */
321
322  base += length - 1;
323  for (ebase = s; base > ebase; base--)
324      if (*base != U32_PATTERN)
325          return (void *) base;
326#else
327  /*
328   * start at lower memory and find first word that does not
329   * match pattern
330   */
331
332  base += 4;
333  for (ebase = base + length; base < ebase; base++)
334      if (*base != U32_PATTERN)
335          return (void *) base;
336#endif
337
338  return (void *)0;
339}
340
341/*PAGE
342 *
343 *  Stack_check_Dump_threads_usage
344 *  Try to print out how much stack was actually used by the task.
345 *
346 */
347
348void Stack_check_Dump_threads_usage(
349  Thread_Control *the_thread
350)
351{
352  unsigned32      size, used;
353  void           *low;
354  void           *high_water_mark;
355  Stack_Control  *stack;
356
357  if ( !the_thread )
358    return;
359
360  /*
361   * XXX HACK to get to interrupt stack
362   */
363
364  if (the_thread == (Thread_Control *) -1)
365  {
366      if (stack_check_interrupt_stack.area)
367      {
368          stack = &stack_check_interrupt_stack;
369          the_thread = 0;
370      }
371      else
372          return;
373  }
374  else
375      stack = &the_thread->Start.Initial_stack;
376
377  low  = Stack_check_usable_stack_start(stack);
378  size = Stack_check_usable_stack_size(stack);
379
380  high_water_mark = Stack_check_find_high_water_mark(low, size);
381
382  if ( high_water_mark )
383    used = Stack_check_Calculate_used( low, size, high_water_mark );
384  else
385    used = 0;
386
387  printf( "0x%08x  0x%08x  0x%08x  0x%08x   %8d   %8d\n",
388          the_thread ? the_thread->Object.id : ~0,
389          the_thread ? the_thread->name :
390                       rtems_build_name('I', 'N', 'T', 'R'),
391          (unsigned32) stack->area,
392          (unsigned32) stack->area + (unsigned32) stack->size - 1,
393          size,
394          used
395  );
396}
397
398/*PAGE
399 *
400 *  Stack_check_Fatal_extension
401 */
402
403void Stack_check_Fatal_extension( unsigned32 status )
404{
405    if (status == 0)
406        Stack_check_Dump_usage();
407}
408
409
410/*PAGE
411 *
412 *  Stack_check_Dump_usage
413 */
414
415void Stack_check_Dump_usage( void )
416{
417  unsigned32      i;
418  Thread_Control *the_thread;
419  unsigned32      hit_running = 0;
420
421  if (stack_check_initialized == 0)
422      return;
423
424  printf(
425    "   ID          NAME         LOW        HIGH      AVAILABLE     USED\n"
426  );
427  for ( i=1 ; i<_Thread_Information.maximum ; i++ ) {
428    the_thread = (Thread_Control *)_Thread_Information.local_table[ i ];
429    Stack_check_Dump_threads_usage( the_thread );
430    if ( the_thread == _Thread_Executing )
431      hit_running = 1;
432  }
433
434  if ( !hit_running )
435    Stack_check_Dump_threads_usage( _Thread_Executing );
436
437  /* dump interrupt stack info if any */
438  Stack_check_Dump_threads_usage((Thread_Control *) -1);
439}
440
Note: See TracBrowser for help on using the repository browser.