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

4.104.114.84.95
Last change on this file since f26145b was cbd849c, checked in by Ralf Corsepius <ralf.corsepius@…>, on 11/01/04 at 13:14:33

2004-11-01 Ralf Corsepius <ralf_corsepius@…>

  • monitor/monitor.h: Let rtems_monitor_config_dump return int.
  • monitor/mon-config.c: Ditto. Use PRI*N macros.
  • monitor/mon-itask.c, monitor/mon-prmisc.c: Use PRI*N macros.
  • Property mode set to 100644
File size: 13.1 KB
RevLine 
[ac7d5ef0]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 *
[08311cc3]9 *  COPYRIGHT (c) 1989-1999.
[ac7d5ef0]10 *  On-Line Applications Research Corporation (OAR).
11 *
[98e4ebf5]12 *  The license and distribution terms for this file may be
13 *  found in the file LICENSE in this distribution or at
[3160ff6]14 *  http://www.rtems.com/license/LICENSE.
[ac7d5ef0]15 *
16 *  $Id$
17 *
18 */
19
[550c3df7]20#ifdef HAVE_CONFIG_H
21#include "config.h"
22#endif
23
[3a4ae6c]24#include <rtems.h>
25
[8389628]26/*
27 * HACK
28 * the stack dump information should be printed by a "fatal" extension.
29 * Fatal extensions only get called via rtems_fatal_error_occurred()
30 * and not when rtems_shutdown_executive() is called.
31 * I hope/think this is changing so that fatal extensions are renamed
32 * to "shutdown" extensions.
33 * When that happens, this #define should be deleted and all the code
34 * it marks.
35 */
36#define DONT_USE_FATAL_EXTENSION
37
[ac7d5ef0]38#include <assert.h>
39#include <stdio.h>
40#include <string.h>
41#include <stdlib.h>
42
[bfc3533]43#include <rtems/stackchk.h>
[ac7d5ef0]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 */
[8389628]65#ifdef DONT_USE_FATAL_EXTENSION
66  0,                                /* fatal        */
67#else
[ac7d5ef0]68  Stack_check_Fatal_extension,      /* fatal        */
[8389628]69#endif
[ac7d5ef0]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 ) \
[5697c28]87  ((Stack_check_Control *) ((char *)(_the_stack)->area + \
88       (_the_stack)->size - sizeof( Stack_check_Control ) ))
[ac7d5ef0]89
90#define Stack_check_Calculate_used( _low, _size, _high_water ) \
[5697c28]91    ((char *)(_high_water) - (char *)(_low))
[ac7d5ef0]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 ) \
[5697c28]99  ((Stack_check_Control *) ((char *)(_the_stack)->area + HEAP_OVERHEAD))
[ac7d5ef0]100
101#define Stack_check_Calculate_used( _low, _size, _high_water) \
[5697c28]102    ( ((char *)(_low) + (_size)) - (char *)(_high_water) )
[ac7d5ef0]103
104#define Stack_check_usable_stack_start(_the_stack) \
[5697c28]105    ((char *)(_the_stack)->area + sizeof(Stack_check_Control))
[ac7d5ef0]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
[29310016]122/*
123 * Prototypes necessary for forward references
124 */
125
126void Stack_check_Dump_usage( void );
127
[ac7d5ef0]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
[cbd849c]146static int   stack_check_initialized = 0;
[ac7d5ef0]147
148void Stack_check_Initialize( void )
149{
[edffc054]150#if 0
[3a4ae6c]151  rtems_status_code    status;
152  Objects_Id           id_ignored;
[edffc054]153#endif
[3e08d4e]154  uint32_t            *p;
[11290355]155#if 0
[3e08d4e]156  uint32_t             i;
157  uint32_t             api_index;
[3a4ae6c]158  Thread_Control      *the_thread;
159  Objects_Information *information;
[11290355]160#endif
[ac7d5ef0]161
162  if (stack_check_initialized)
163      return;
164
165  /*
166   * Dope the pattern and fill areas
167   */
168
169  for ( p = Stack_check_Pattern.pattern;
170        p < &Stack_check_Pattern.pattern[PATTERN_SIZE_WORDS];
171        p += 4
172      )
173  {
174      p[0] = 0xFEEDF00D;          /* FEED FOOD to BAD DOG */
175      p[1] = 0x0BAD0D06;
176      p[2] = 0xDEADF00D;          /* DEAD FOOD GOOD DOG */
177      p[3] = 0x600D0D06;
178  };
179
[71f4beb]180#if 0
[ac7d5ef0]181  status = rtems_extension_create(
182    rtems_build_name( 'S', 'T', 'C', 'K' ),
183    &Stack_check_Extension_table,
184    &id_ignored
185  );
186  assert ( status == RTEMS_SUCCESSFUL );
[71f4beb]187#endif
[ac7d5ef0]188
189  Stack_check_Blown_task = 0;
190
191  /*
192   * If installed by a task, that task will not get setup properly
193   * since it missed out on the create hook.  This will cause a
194   * failure on first switch out of that task.
195   * So pretend here that we actually ran create and begin extensions.
196   */
197
[3a4ae6c]198  /* XXX
199   *
200   *  Technically this has not been done for any task created before this
201   *  happened.  So just run through them and fix the situation.
202   */
203#if 0
[ac7d5ef0]204  if (_Thread_Executing)
205  {
206      Stack_check_Create_extension(_Thread_Executing, _Thread_Executing);
207  }
[3a4ae6c]208#endif
209
210#if 0
[ee13a74]211  for ( api_index = 1;
212        api_index <= OBJECTS_APIS_LAST ;
213        api_index++ ) {
214    if ( !_Objects_Information_table[ api_index ] )
215      continue;
216    information = _Objects_Information_table[ api_index ][ 1 ];
217    if ( information ) {
[3a4ae6c]218      for ( i=1 ; i <= information->maximum ; i++ ) {
219        the_thread = (Thread_Control *)information->local_table[ i ];
220        Stack_check_Create_extension( the_thread, the_thread );
221      }
222    }
223  }
224#endif
[ac7d5ef0]225
226  /*
227   * If appropriate, setup the interrupt stack for high water testing
228   * also.
229   */
[57c67302]230#if (CPU_ALLOCATE_INTERRUPT_STACK == TRUE)
[ac7d5ef0]231  if (_CPU_Interrupt_stack_low && _CPU_Interrupt_stack_high)
232  {
233      stack_check_interrupt_stack.area = _CPU_Interrupt_stack_low;
[5697c28]234      stack_check_interrupt_stack.size = (char *) _CPU_Interrupt_stack_high -
235                                              (char *) _CPU_Interrupt_stack_low;
[ac7d5ef0]236
237      stack_check_dope_stack(&stack_check_interrupt_stack);
238  }
[57c67302]239#endif
[ac7d5ef0]240
[8389628]241#ifdef DONT_USE_FATAL_EXTENSION
242#ifdef RTEMS_DEBUG
243    /*
244     * this would normally be called by a fatal extension
245     * handler, but we don't run fatal extensions unless
246     * we fatal error.
247     */
248  atexit(Stack_check_Dump_usage);
249#endif
250#endif
251
[ac7d5ef0]252  stack_check_initialized = 1;
253}
254
255/*PAGE
256 *
257 *  Stack_check_Create_extension
258 */
259
[3a4ae6c]260boolean Stack_check_Create_extension(
[ac7d5ef0]261  Thread_Control *running,
262  Thread_Control *the_thread
263)
264{
[71f4beb]265    if (!stack_check_initialized)
266      Stack_check_Initialize();
267
[3a4ae6c]268    if (the_thread /* XXX && (the_thread != _Thread_Executing) */ )
[ac7d5ef0]269        stack_check_dope_stack(&the_thread->Start.Initial_stack);
[3a4ae6c]270
271    return TRUE;
[ac7d5ef0]272}
273
274/*PAGE
275 *
276 *  Stack_check_Begin_extension
277 */
278
279void Stack_check_Begin_extension(
280  Thread_Control *the_thread
281)
282{
283  Stack_check_Control  *the_pattern;
284
[71f4beb]285  if (!stack_check_initialized)
286    Stack_check_Initialize();
287
[ac7d5ef0]288  if ( the_thread->Object.id == 0 )        /* skip system tasks */
289    return;
290
291  the_pattern = Stack_check_Get_pattern_area(&the_thread->Start.Initial_stack);
292
293  *the_pattern = Stack_check_Pattern;
294}
295
296/*PAGE
297 *
298 *  Stack_check_report_blown_task
299 *  Report a blown stack.  Needs to be a separate routine
300 *  so that interrupt handlers can use this too.
301 *
302 *  Caller must have set the Stack_check_Blown_task.
303 *
304 *  NOTE: The system is in a questionable state... we may not get
305 *        the following message out.
306 */
307
308void Stack_check_report_blown_task(void)
309{
310    Stack_Control *stack;
311    Thread_Control *running;
312
313    running = Stack_check_Blown_task;
314    stack = &running->Start.Initial_stack;
315
316    fprintf(
317        stderr,
318        "BLOWN STACK!!! Offending task(%p): id=0x%08x; name=0x%08x",
319        running,
320        running->Object.id,
[3e08d4e]321        (uint32_t  )running->Object.name
[0f592fba]322    );
[ac7d5ef0]323    fflush(stderr);
324
[458bd34]325    if (rtems_configuration_get_user_multiprocessing_table())
[ac7d5ef0]326        fprintf(
327          stderr,
328          "; node=%d\n",
[458bd34]329          rtems_configuration_get_user_multiprocessing_table()->node
[ac7d5ef0]330       );
331    else
332        fprintf(stderr, "\n");
333    fflush(stderr);
334
335    fprintf(
336        stderr,
337        "  stack covers range 0x%08x - 0x%08x (%d bytes)\n",
[3e08d4e]338        (uint32_t  ) stack->area,
339        (uint32_t  ) stack->area + stack->size - 1,
340        (uint32_t  ) stack->size);
[ac7d5ef0]341    fflush(stderr);
342
343    fprintf(
344        stderr,
[a761f565]345        "  Damaged pattern begins at 0x%08lx and is %ld bytes long\n",
346        (unsigned long) Stack_check_Get_pattern_area(stack),
[1889c7f]347        (long) PATTERN_SIZE_BYTES);
[ac7d5ef0]348    fflush(stderr);
349
[3e08d4e]350    rtems_fatal_error_occurred( (uint32_t  ) "STACK BLOWN" );
[ac7d5ef0]351}
352
353/*PAGE
354 *
355 *  Stack_check_Switch_extension
356 */
357
358void Stack_check_Switch_extension(
359  Thread_Control *running,
360  Thread_Control *heir
361)
362{
363  if ( running->Object.id == 0 )        /* skip system tasks */
364    return;
365
366  if (0 != memcmp( (void *) Stack_check_Get_pattern_area( &running->Start.Initial_stack)->pattern,
367                  (void *) Stack_check_Pattern.pattern,
368                  PATTERN_SIZE_BYTES))
369  {
370      Stack_check_Blown_task = running;
371      Stack_check_report_blown_task();
372  }
373}
374
375void *Stack_check_find_high_water_mark(
376  const void *s,
377  size_t n
378)
379{
[3e08d4e]380  const uint32_t   *base, *ebase;
381  uint32_t   length;
[ac7d5ef0]382
383  base = s;
384  length = n/4;
385
386#if ( CPU_STACK_GROWS_UP == TRUE )
387  /*
388   * start at higher memory and find first word that does not
389   * match pattern
390   */
391
392  base += length - 1;
393  for (ebase = s; base > ebase; base--)
394      if (*base != U32_PATTERN)
395          return (void *) base;
396#else
397  /*
398   * start at lower memory and find first word that does not
399   * match pattern
400   */
401
[9e86dd7d]402  base += PATTERN_SIZE_WORDS;
[ac7d5ef0]403  for (ebase = base + length; base < ebase; base++)
404      if (*base != U32_PATTERN)
405          return (void *) base;
406#endif
407
408  return (void *)0;
409}
410
411/*PAGE
412 *
413 *  Stack_check_Dump_threads_usage
414 *  Try to print out how much stack was actually used by the task.
415 *
416 */
417
418void Stack_check_Dump_threads_usage(
419  Thread_Control *the_thread
420)
421{
[3e08d4e]422  uint32_t        size, used;
[ac7d5ef0]423  void           *low;
424  void           *high_water_mark;
425  Stack_Control  *stack;
[3e08d4e]426  uint32_t        u32_name;
[e819fefc]427  char            name_str[5];
428  char            *name;
429  Objects_Information *info;
[ac7d5ef0]430
431  if ( !the_thread )
432    return;
433
434  /*
435   * XXX HACK to get to interrupt stack
436   */
437
438  if (the_thread == (Thread_Control *) -1)
439  {
440      if (stack_check_interrupt_stack.area)
441      {
442          stack = &stack_check_interrupt_stack;
443          the_thread = 0;
444      }
445      else
446          return;
447  }
448  else
449      stack = &the_thread->Start.Initial_stack;
450
451  low  = Stack_check_usable_stack_start(stack);
452  size = Stack_check_usable_stack_size(stack);
453
454  high_water_mark = Stack_check_find_high_water_mark(low, size);
455
456  if ( high_water_mark )
457    used = Stack_check_Calculate_used( low, size, high_water_mark );
458  else
459    used = 0;
460
[e819fefc]461  name = name_str;
462  if ( the_thread ) {
[f6c2c30]463    info = _Objects_Get_information(the_thread->Object.id);
[e819fefc]464    if ( info->is_string ) {
465      name = (char *) the_thread->Object.name;
466    } else {
[7a965bc]467      u32_name = (uint32_t )the_thread->Object.name;
[e819fefc]468      name[ 0 ] = (u32_name >> 24) & 0xff;
469      name[ 1 ] = (u32_name >> 16) & 0xff;
470      name[ 2 ] = (u32_name >>  8) & 0xff;
471      name[ 3 ] = (u32_name >>  0) & 0xff;
472      name[ 4 ] = '\0';
473    }
474  } else {
[c46ce854]475    u32_name = rtems_build_name('I', 'N', 'T', 'R');
[e819fefc]476    name[ 0 ] = (u32_name >> 24) & 0xff;
477    name[ 1 ] = (u32_name >> 16) & 0xff;
478    name[ 2 ] = (u32_name >>  8) & 0xff;
479    name[ 3 ] = (u32_name >>  0) & 0xff;
480    name[ 4 ] = '\0';
481  }
[c46ce854]482
[714f06c]483  fprintf(stdout, "0x%08x  %4s  0x%08x  0x%08x   %8d   %8d\n",
[ac7d5ef0]484          the_thread ? the_thread->Object.id : ~0,
[c46ce854]485          name,
[3e08d4e]486          (uint32_t  ) stack->area,
487          (uint32_t  ) stack->area + (uint32_t  ) stack->size - 1,
[ac7d5ef0]488          size,
489          used
490  );
491}
492
493/*PAGE
494 *
495 *  Stack_check_Fatal_extension
496 */
497
[8389628]498void Stack_check_Fatal_extension(
[11290355]499    Internal_errors_Source  source,
500    boolean                 is_internal,
[3e08d4e]501    uint32_t                status
[11290355]502)
[ac7d5ef0]503{
[8389628]504#ifndef DONT_USE_FATAL_EXTENSION
[ac7d5ef0]505    if (status == 0)
506        Stack_check_Dump_usage();
[8389628]507#endif
[ac7d5ef0]508}
509
510
511/*PAGE
512 *
513 *  Stack_check_Dump_usage
514 */
515
516void Stack_check_Dump_usage( void )
517{
[3e08d4e]518  uint32_t             i;
519  uint32_t             api_index;
[5250ff39]520  Thread_Control      *the_thread;
[3e08d4e]521  uint32_t             hit_running = 0;
[5250ff39]522  Objects_Information *information;
[ac7d5ef0]523
524  if (stack_check_initialized == 0)
525      return;
526
[714f06c]527  fprintf(stdout,"Stack usage by thread\n");
528  fprintf(stdout,
[baa876a4]529    "    ID      NAME       LOW        HIGH     AVAILABLE      USED\n"
[ac7d5ef0]530  );
[5250ff39]531
[aed742c]532  for ( api_index = 1 ;
533        api_index <= OBJECTS_APIS_LAST ;
[ee13a74]534        api_index++ ) {
535    if ( !_Objects_Information_table[ api_index ] )
536      continue;
537    information = _Objects_Information_table[ api_index ][ 1 ];
538    if ( information ) {
[7f6a24ab]539      for ( i=1 ; i <= information->maximum ; i++ ) {
[5250ff39]540        the_thread = (Thread_Control *)information->local_table[ i ];
541        Stack_check_Dump_threads_usage( the_thread );
542        if ( the_thread == _Thread_Executing )
543          hit_running = 1;
544      }
545    }
[ac7d5ef0]546  }
547
548  if ( !hit_running )
549    Stack_check_Dump_threads_usage( _Thread_Executing );
550
551  /* dump interrupt stack info if any */
552  Stack_check_Dump_threads_usage((Thread_Control *) -1);
553}
Note: See TracBrowser for help on using the repository browser.