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

4.104.114.84.95
Last change on this file since 11290355 was 11290355, checked in by Joel Sherrill <joel.sherrill@…>, on Sep 29, 1995 at 5:19:16 PM

all targets compile .. tony's patches in place

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