source: rtems/cpukit/libmisc/stackchk/check.c @ 20f54e9

4.104.114.84.95
Last change on this file since 20f54e9 was 458bd34, checked in by Joel Sherrill <joel.sherrill@…>, on 11/05/99 at 16:44:02

This is another pass at making sure that nothing outside the BSP
unnecessarily uses any variables defined by the BSP. On this
sweep, use of BSP_Configuration and Cpu_table was eliminated.

A significant part of this modification was the addition of
macros to access fields in the RTEMS configuration structures.

This is necessary to strengthen the division between the BSP independent
parts of RTEMS and the BSPs themselves. This started after
comments and analysis by Ralf Corsepius <corsepiu@…>.

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