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

4.104.114.84.95
Last change on this file since 0f592fba was 0f592fba, checked in by Joel Sherrill <joel.sherrill@…>, on 08/18/95 at 21:43:40

Modified references to task name.

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