source: rtems/cpukit/libmisc/stackchk/check.c @ 98e4ebf5

4.104.114.84.95
Last change on this file since 98e4ebf5 was 98e4ebf5, checked in by Joel Sherrill <joel.sherrill@…>, on 10/08/97 at 15:45:54

Fixed typo in the pointer to the license terms.

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