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

4.104.114.84.9
Last change on this file since 3523321 was 3523321, checked in by Joel Sherrill <joel.sherrill@…>, on Aug 30, 2006 at 1:53:02 PM

2006-08-30 Joel Sherrill <joel@…>

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