source: rtems/cpukit/libmisc/stackchk/check.c @ e819fefc

4.104.114.84.95
Last change on this file since e819fefc was e819fefc, checked in by Joel Sherrill <joel.sherrill@…>, on 12/03/02 at 00:47:10

2002-12-02 Joel Sherrill <joel@…>

  • stackchk/check.c: Better handling of task name.
  • Property mode set to 100644
File size: 13.0 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           api_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 ( api_index = 1;
208        api_index <= OBJECTS_APIS_LAST ;
209        api_index++ ) {
210    if ( !_Objects_Information_table[ api_index ] )
211      continue;
212    information = _Objects_Information_table[ api_index ][ 1 ];
213    if ( information ) {
214      for ( i=1 ; i <= information->maximum ; i++ ) {
215        the_thread = (Thread_Control *)information->local_table[ i ];
216        Stack_check_Create_extension( the_thread, the_thread );
217      }
218    }
219  }
220#endif
221
222  /*
223   * If appropriate, setup the interrupt stack for high water testing
224   * also.
225   */
226#if (CPU_ALLOCATE_INTERRUPT_STACK == TRUE)
227  if (_CPU_Interrupt_stack_low && _CPU_Interrupt_stack_high)
228  {
229      stack_check_interrupt_stack.area = _CPU_Interrupt_stack_low;
230      stack_check_interrupt_stack.size = (char *) _CPU_Interrupt_stack_high -
231                                              (char *) _CPU_Interrupt_stack_low;
232
233      stack_check_dope_stack(&stack_check_interrupt_stack);
234  }
235#endif
236
237#ifdef DONT_USE_FATAL_EXTENSION
238#ifdef RTEMS_DEBUG
239    /*
240     * this would normally be called by a fatal extension
241     * handler, but we don't run fatal extensions unless
242     * we fatal error.
243     */
244  atexit(Stack_check_Dump_usage);
245#endif
246#endif
247
248  stack_check_initialized = 1;
249}
250
251/*PAGE
252 *
253 *  Stack_check_Create_extension
254 */
255
256boolean Stack_check_Create_extension(
257  Thread_Control *running,
258  Thread_Control *the_thread
259)
260{
261    if (!stack_check_initialized)
262      Stack_check_Initialize();
263
264    if (the_thread /* XXX && (the_thread != _Thread_Executing) */ )
265        stack_check_dope_stack(&the_thread->Start.Initial_stack);
266
267    return TRUE;
268}
269
270/*PAGE
271 *
272 *  Stack_check_Begin_extension
273 */
274
275void Stack_check_Begin_extension(
276  Thread_Control *the_thread
277)
278{
279  Stack_check_Control  *the_pattern;
280
281  if (!stack_check_initialized)
282    Stack_check_Initialize();
283
284  if ( the_thread->Object.id == 0 )        /* skip system tasks */
285    return;
286
287  the_pattern = Stack_check_Get_pattern_area(&the_thread->Start.Initial_stack);
288
289  *the_pattern = Stack_check_Pattern;
290}
291
292/*PAGE
293 *
294 *  Stack_check_report_blown_task
295 *  Report a blown stack.  Needs to be a separate routine
296 *  so that interrupt handlers can use this too.
297 *
298 *  Caller must have set the Stack_check_Blown_task.
299 *
300 *  NOTE: The system is in a questionable state... we may not get
301 *        the following message out.
302 */
303
304void Stack_check_report_blown_task(void)
305{
306    Stack_Control *stack;
307    Thread_Control *running;
308
309    running = Stack_check_Blown_task;
310    stack = &running->Start.Initial_stack;
311
312    fprintf(
313        stderr,
314        "BLOWN STACK!!! Offending task(%p): id=0x%08x; name=0x%08x",
315        running,
316        running->Object.id,
317        (unsigned32)running->Object.name
318    );
319    fflush(stderr);
320
321    if (rtems_configuration_get_user_multiprocessing_table())
322        fprintf(
323          stderr,
324          "; node=%d\n",
325          rtems_configuration_get_user_multiprocessing_table()->node
326       );
327    else
328        fprintf(stderr, "\n");
329    fflush(stderr);
330
331    fprintf(
332        stderr,
333        "  stack covers range 0x%08x - 0x%08x (%d bytes)\n",
334        (unsigned32) stack->area,
335        (unsigned32) stack->area + stack->size - 1,
336        (unsigned32) stack->size);
337    fflush(stderr);
338
339    fprintf(
340        stderr,
341        "  Damaged pattern begins at 0x%08lx and is %ld bytes long\n",
342        (unsigned long) Stack_check_Get_pattern_area(stack),
343        (long) PATTERN_SIZE_BYTES);
344    fflush(stderr);
345
346    rtems_fatal_error_occurred( (unsigned32) "STACK BLOWN" );
347}
348
349/*PAGE
350 *
351 *  Stack_check_Switch_extension
352 */
353
354void Stack_check_Switch_extension(
355  Thread_Control *running,
356  Thread_Control *heir
357)
358{
359  if ( running->Object.id == 0 )        /* skip system tasks */
360    return;
361
362  if (0 != memcmp( (void *) Stack_check_Get_pattern_area( &running->Start.Initial_stack)->pattern,
363                  (void *) Stack_check_Pattern.pattern,
364                  PATTERN_SIZE_BYTES))
365  {
366      Stack_check_Blown_task = running;
367      Stack_check_report_blown_task();
368  }
369}
370
371void *Stack_check_find_high_water_mark(
372  const void *s,
373  size_t n
374)
375{
376  const unsigned32 *base, *ebase;
377  unsigned32 length;
378
379  base = s;
380  length = n/4;
381
382#if ( CPU_STACK_GROWS_UP == TRUE )
383  /*
384   * start at higher memory and find first word that does not
385   * match pattern
386   */
387
388  base += length - 1;
389  for (ebase = s; base > ebase; base--)
390      if (*base != U32_PATTERN)
391          return (void *) base;
392#else
393  /*
394   * start at lower memory and find first word that does not
395   * match pattern
396   */
397
398  base += PATTERN_SIZE_WORDS;
399  for (ebase = base + length; base < ebase; base++)
400      if (*base != U32_PATTERN)
401          return (void *) base;
402#endif
403
404  return (void *)0;
405}
406
407/*PAGE
408 *
409 *  Stack_check_Dump_threads_usage
410 *  Try to print out how much stack was actually used by the task.
411 *
412 */
413
414void Stack_check_Dump_threads_usage(
415  Thread_Control *the_thread
416)
417{
418  unsigned32      size, used;
419  void           *low;
420  void           *high_water_mark;
421  Stack_Control  *stack;
422  unsigned32      u32_name;
423  char            name_str[5];
424  char            *name;
425  Objects_Information *info;
426
427  if ( !the_thread )
428    return;
429
430  /*
431   * XXX HACK to get to interrupt stack
432   */
433
434  if (the_thread == (Thread_Control *) -1)
435  {
436      if (stack_check_interrupt_stack.area)
437      {
438          stack = &stack_check_interrupt_stack;
439          the_thread = 0;
440      }
441      else
442          return;
443  }
444  else
445      stack = &the_thread->Start.Initial_stack;
446
447  low  = Stack_check_usable_stack_start(stack);
448  size = Stack_check_usable_stack_size(stack);
449
450  high_water_mark = Stack_check_find_high_water_mark(low, size);
451
452  if ( high_water_mark )
453    used = Stack_check_Calculate_used( low, size, high_water_mark );
454  else
455    used = 0;
456
457  info = _Objects_Get_information(the_thread->Object.id);
458  name = name_str;
459  if ( the_thread ) {
460    if ( info->is_string ) {
461      name = (char *) the_thread->Object.name;
462    } else {
463      u32_name = (unsigned32 *)the_thread->Object.name;
464      name[ 0 ] = (u32_name >> 24) & 0xff;
465      name[ 1 ] = (u32_name >> 16) & 0xff;
466      name[ 2 ] = (u32_name >>  8) & 0xff;
467      name[ 3 ] = (u32_name >>  0) & 0xff;
468      name[ 4 ] = '\0';
469    }
470  } else {
471    u32_name = rtems_build_name('I', 'N', 'T', 'R');
472    name[ 0 ] = (u32_name >> 24) & 0xff;
473    name[ 1 ] = (u32_name >> 16) & 0xff;
474    name[ 2 ] = (u32_name >>  8) & 0xff;
475    name[ 3 ] = (u32_name >>  0) & 0xff;
476    name[ 4 ] = '\0';
477  }
478
479  printf( "0x%08x  %4s  0x%08x  0x%08x   %8d   %8d\n",
480          the_thread ? the_thread->Object.id : ~0,
481          name,
482          (unsigned32) stack->area,
483          (unsigned32) stack->area + (unsigned32) stack->size - 1,
484          size,
485          used
486  );
487}
488
489/*PAGE
490 *
491 *  Stack_check_Fatal_extension
492 */
493
494void Stack_check_Fatal_extension(
495    Internal_errors_Source  source,
496    boolean                 is_internal,
497    unsigned32              status
498)
499{
500#ifndef DONT_USE_FATAL_EXTENSION
501    if (status == 0)
502        Stack_check_Dump_usage();
503#endif
504}
505
506
507/*PAGE
508 *
509 *  Stack_check_Dump_usage
510 */
511
512void Stack_check_Dump_usage( void )
513{
514  unsigned32           i;
515  unsigned32           api_index;
516  Thread_Control      *the_thread;
517  unsigned32           hit_running = 0;
518  Objects_Information *information;
519
520  if (stack_check_initialized == 0)
521      return;
522
523  printf("Stack usage by thread\n");
524  printf(
525    "    ID      NAME       LOW        HIGH     AVAILABLE      USED\n"
526  );
527
528  for ( api_index = 1 ;
529        api_index <= OBJECTS_APIS_LAST ;
530        api_index++ ) {
531    if ( !_Objects_Information_table[ api_index ] )
532      continue;
533    information = _Objects_Information_table[ api_index ][ 1 ];
534    if ( information ) {
535      for ( i=1 ; i <= information->maximum ; i++ ) {
536        the_thread = (Thread_Control *)information->local_table[ i ];
537        Stack_check_Dump_threads_usage( the_thread );
538        if ( the_thread == _Thread_Executing )
539          hit_running = 1;
540      }
541    }
542  }
543
544  if ( !hit_running )
545    Stack_check_Dump_threads_usage( _Thread_Executing );
546
547  /* dump interrupt stack info if any */
548  Stack_check_Dump_threads_usage((Thread_Control *) -1);
549}
550
Note: See TracBrowser for help on using the repository browser.