source: rtems/c/src/libmisc/stackchk/check.c @ 5a36154a

4.104.114.84.95
Last change on this file since 5a36154a was 8bde6ea9, checked in by Joel Sherrill <joel.sherrill@…>, on 02/13/96 at 22:16:36

removed post switch extension

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