source: rtems/cpukit/libmisc/stackchk/check.c @ 4e36a2f

4.104.114.84.95
Last change on this file since 4e36a2f was 08311cc3, checked in by Joel Sherrill <joel.sherrill@…>, on 11/17/99 at 17:51:34

Updated copyright notice.

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