source: rtems/cpukit/libmisc/stackchk/check.c @ 8a775c27

4.104.115
Last change on this file since 8a775c27 was 8a775c27, checked in by Joel Sherrill <joel.sherrill@…>, on 03/27/09 at 13:45:31

2009-03-27 Sebastian Huber <sebastian.huber@…>

  • Makefile.am, preinstall.am, libmisc/Makefile.am, libmisc/shell/shell.c, libmisc/shell/shell.h, telnetd/check_passwd.c, telnetd/telnetd.c, telnetd/telnetd.h: Generalized login check.
  • libmisc/shell/login.h, libmisc/shell/login_check.c, libmisc/shell/login_prompt.c: New files.
  • libmisc/stackchk/check.c: Changed format for blown stack message.
  • libcsupport/src/libio_sockets.c: Removed superfluous cast.
  • libnetworking/rtems/ftpfs.h: Documentation.
  • Property mode set to 100644
File size: 11.7 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 *
[d8ec87b4]9 *  COPYRIGHT (c) 1989-2007.
[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>
[3523321]25#include <inttypes.h>
[3a4ae6c]26
[8389628]27/*
[4da36c1a]28 * The stack dump information may be printed by a "fatal" extension.
[8389628]29 * Fatal extensions only get called via rtems_fatal_error_occurred()
30 * and not when rtems_shutdown_executive() is called.
31 * When that happens, this #define should be deleted and all the code
32 * it marks.
33 */
34#define DONT_USE_FATAL_EXTENSION
35
[ac7d5ef0]36#include <assert.h>
37#include <string.h>
38#include <stdlib.h>
39
[d8ec87b4]40#include <rtems/bspIo.h>
[bfc3533]41#include <rtems/stackchk.h>
[ac7d5ef0]42#include "internal.h"
43
44/*
[4da36c1a]45 *  Variable to indicate when the stack checker has been initialized.
[ac7d5ef0]46 */
[4da36c1a]47static int   Stack_check_Initialized = 0;
[ac7d5ef0]48
49/*
50 *  The "magic pattern" used to mark the end of the stack.
51 */
52Stack_check_Control Stack_check_Pattern;
53
[d8ec87b4]54/*
55 * Helper function to report if the actual stack pointer is in range.
56 *
57 * NOTE: This uses a GCC specific method.
58 */
[937ec60]59static inline bool Stack_check_Frame_pointer_in_range(
[d8ec87b4]60  Stack_Control *the_stack
61)
62{
63  void *sp = __builtin_frame_address(0);
64
65  #if defined(__GNUC__)
66    if ( sp < the_stack->area ) {
[937ec60]67      return false;
[d8ec87b4]68    }
69    if ( sp > (the_stack->area + the_stack->size) ) {
[937ec60]70      return false;
[d8ec87b4]71    }
[4da36c1a]72  #else
73    #error "How do I check stack bounds on a non-GNU compiler?"
[d8ec87b4]74  #endif
[937ec60]75  return true;
[d8ec87b4]76}
77
[ac7d5ef0]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 */
[4da36c1a]82#if (CPU_STACK_GROWS_UP == TRUE)
83  #define Stack_check_Get_pattern_area( _the_stack ) \
84    ((Stack_check_Control *) ((char *)(_the_stack)->area + \
85         (_the_stack)->size - sizeof( Stack_check_Control ) ))
[ac7d5ef0]86
[4da36c1a]87  #define Stack_check_Calculate_used( _low, _size, _high_water ) \
88      ((char *)(_high_water) - (char *)(_low))
[ac7d5ef0]89
[4da36c1a]90  #define Stack_check_usable_stack_start(_the_stack) \
[ac7d5ef0]91    ((_the_stack)->area)
92
93#else
[4da36c1a]94  #define Stack_check_Get_pattern_area( _the_stack ) \
95    ((Stack_check_Control *) ((char *)(_the_stack)->area + HEAP_OVERHEAD))
[ac7d5ef0]96
[4da36c1a]97  #define Stack_check_Calculate_used( _low, _size, _high_water) \
98      ( ((char *)(_low) + (_size)) - (char *)(_high_water) )
[d8ec87b4]99
[4da36c1a]100  #define Stack_check_usable_stack_start(_the_stack) \
101      ((char *)(_the_stack)->area + sizeof(Stack_check_Control))
[ac7d5ef0]102
103#endif
104
[4da36c1a]105/*
106 *  The assumption is that if the pattern gets overwritten, the task
107 *  is too close.  This defines the usable stack memory.
108 */
[ac7d5ef0]109#define Stack_check_usable_stack_size(_the_stack) \
110    ((_the_stack)->size - sizeof(Stack_check_Control))
111
112/*
113 * Do we have an interrupt stack?
114 * XXX it would sure be nice if the interrupt stack were also
115 *     stored in a "stack" structure!
116 */
[4da36c1a]117Stack_Control Stack_check_Interrupt_stack;
[ac7d5ef0]118
119/*
[4da36c1a]120 *  Fill an entire stack area with BYTE_PATTERN.  This will be used
121 *  to check for amount of actual stack used.
[ac7d5ef0]122 */
[4da36c1a]123#define Stack_check_Dope_stack(_stack) \
124  memset((_stack)->area, BYTE_PATTERN, (_stack)->size)
[ac7d5ef0]125
[4da36c1a]126/*
127 *  Stack_check_Initialize
[ac7d5ef0]128 */
[4da36c1a]129void Stack_check_Initialize( void )
[ac7d5ef0]130{
[4da36c1a]131  uint32_t *p;
[ac7d5ef0]132
[4da36c1a]133  if (Stack_check_Initialized)
[d8ec87b4]134    return;
[ac7d5ef0]135
136  /*
137   * Dope the pattern and fill areas
138   */
139
140  for ( p = Stack_check_Pattern.pattern;
141        p < &Stack_check_Pattern.pattern[PATTERN_SIZE_WORDS];
142        p += 4
[4da36c1a]143      ) {
[ac7d5ef0]144      p[0] = 0xFEEDF00D;          /* FEED FOOD to BAD DOG */
145      p[1] = 0x0BAD0D06;
146      p[2] = 0xDEADF00D;          /* DEAD FOOD GOOD DOG */
147      p[3] = 0x600D0D06;
[4da36c1a]148  }
149 
[ac7d5ef0]150  /*
151   * If appropriate, setup the interrupt stack for high water testing
152   * also.
153   */
[4da36c1a]154  #if (CPU_ALLOCATE_INTERRUPT_STACK == TRUE)
155    if (_CPU_Interrupt_stack_low && _CPU_Interrupt_stack_high) {
156      Stack_check_Interrupt_stack.area = _CPU_Interrupt_stack_low;
157      Stack_check_Interrupt_stack.size = (char *) _CPU_Interrupt_stack_high -
158                                  (char *) _CPU_Interrupt_stack_low;
159      Stack_check_Dope_stack(&Stack_check_Interrupt_stack);
[ac7d5ef0]160  }
[4da36c1a]161  #endif
[8389628]162
[4da36c1a]163  Stack_check_Initialized = 1;
[ac7d5ef0]164}
165
[4da36c1a]166/*
[7ac4ae9]167 *  rtems_stack_checker_create_extension
[ac7d5ef0]168 */
[937ec60]169bool rtems_stack_checker_create_extension(
[031deada]170  Thread_Control *running __attribute__((unused)),
[ac7d5ef0]171  Thread_Control *the_thread
172)
173{
[4da36c1a]174  Stack_check_Initialize();
[71f4beb]175
[4da36c1a]176  if (the_thread)
177    Stack_check_Dope_stack(&the_thread->Start.Initial_stack);
[3a4ae6c]178
[937ec60]179  return true;
[ac7d5ef0]180}
181
[4da36c1a]182/*
[7ac4ae9]183 *  rtems_stack_checker_Begin_extension
[ac7d5ef0]184 */
[7ac4ae9]185void rtems_stack_checker_begin_extension(
[ac7d5ef0]186  Thread_Control *the_thread
187)
188{
189  Stack_check_Control  *the_pattern;
190
191  if ( the_thread->Object.id == 0 )        /* skip system tasks */
192    return;
193
194  the_pattern = Stack_check_Get_pattern_area(&the_thread->Start.Initial_stack);
195
196  *the_pattern = Stack_check_Pattern;
197}
198
[4da36c1a]199/*
[ac7d5ef0]200 *  Stack_check_report_blown_task
[4da36c1a]201 *
[ac7d5ef0]202 *  Report a blown stack.  Needs to be a separate routine
203 *  so that interrupt handlers can use this too.
204 *
205 *  NOTE: The system is in a questionable state... we may not get
206 *        the following message out.
207 */
[8a775c27]208void Stack_check_report_blown_task(Thread_Control *running, bool pattern_ok)
[ac7d5ef0]209{
[4da36c1a]210  Stack_Control *stack = &running->Start.Initial_stack;
[8a775c27]211  char *pattern_area = Stack_check_Get_pattern_area(stack);
212  char name [32];
[ac7d5ef0]213
[8a775c27]214  printk("BLOWN STACK!!!\n");
215  printk("task control block: 0x%08lx\n", (unsigned long) running);
216  printk("task ID: 0x%08lx\n", (unsigned long) running->Object.id);
217  printk(
218    "task name: 0x%08lx\n",
219    (unsigned long) running->Object.name.name_u32
220  );
[4da36c1a]221  printk(
[8a775c27]222    "task name string: %s\n",
223    rtems_object_get_name(running->Object.id, sizeof(name), name)
[4da36c1a]224  );
[8a775c27]225  printk(
226    "task stack area (%lu Bytes): 0x%08lx .. 0x%08lx\n",
227    (unsigned long) stack->size,
228    (unsigned long) stack->area,
229    (unsigned long) ((char *) stack->area + stack->size)
230  );
231  if (!pattern_ok) {
232    printk(
233      "damaged pattern area (%lu Bytes): 0x%08lx .. 0x%08lx\n",
234      (unsigned long) PATTERN_SIZE_BYTES,
235      (unsigned long) pattern_area,
236      (unsigned long) (pattern_area + PATTERN_SIZE_BYTES)
237    );
238  }
[ac7d5ef0]239
[4da36c1a]240  #if defined(RTEMS_MULTIPROCESSING)
241    if (rtems_configuration_get_user_multiprocessing_table()) {
[d8ec87b4]242      printk(
[8a775c27]243        "node: 0x%08lx\n",
244        (unsigned long)
245          rtems_configuration_get_user_multiprocessing_table()->node
[4da36c1a]246      );
[d8ec87b4]247    }
[4da36c1a]248  #endif
249
[8a775c27]250  rtems_fatal_error_occurred(0x81);
[ac7d5ef0]251}
252
[4da36c1a]253/*
[7ac4ae9]254 *  rtems_stack_checker_switch_extension
[ac7d5ef0]255 */
[7ac4ae9]256void rtems_stack_checker_switch_extension(
[031deada]257  Thread_Control *running __attribute__((unused)),
258  Thread_Control *heir __attribute__((unused))
[ac7d5ef0]259)
260{
[d8ec87b4]261  Stack_Control *the_stack = &running->Start.Initial_stack;
262  void          *pattern;
[937ec60]263  bool        sp_ok;
264  bool        pattern_ok = true;
[d8ec87b4]265
266  pattern = (void *) Stack_check_Get_pattern_area(the_stack)->pattern;
267
268  /*
[2b596c69]269   *  Check for an out of bounds stack pointer or an overwrite
[d8ec87b4]270   */
271  sp_ok = Stack_check_Frame_pointer_in_range( the_stack );
[2b596c69]272
[d8ec87b4]273  pattern_ok = (!memcmp( pattern,
274            (void *) Stack_check_Pattern.pattern, PATTERN_SIZE_BYTES));
275
276  if ( !sp_ok || !pattern_ok ) {
277    Stack_check_report_blown_task( running, pattern_ok );
[ac7d5ef0]278  }
279}
280
[4da36c1a]281/*
282 *  Check if blown
283 */
[937ec60]284bool rtems_stack_checker_is_blown( void )
[4da36c1a]285{
286  Stack_Control *the_stack = &_Thread_Executing->Start.Initial_stack;
[937ec60]287  bool           sp_ok;
288  bool           pattern_ok = true;
[4da36c1a]289
290  /*
[2b596c69]291   *  Check for an out of bounds stack pointer
[4da36c1a]292   */
293
294  sp_ok = Stack_check_Frame_pointer_in_range( the_stack );
[2b596c69]295
296  /*
297   * The stack checker must be initialized before the pattern is there
298   * to check.
299   */
300  if ( Stack_check_Initialized ) {
301    pattern_ok = (!memcmp(
302      (void *) Stack_check_Get_pattern_area(the_stack)->pattern,
303      (void *) Stack_check_Pattern.pattern,
304      PATTERN_SIZE_BYTES
305    ));
306  }
[4da36c1a]307
[0faa8b11]308  /*
[937ec60]309   * The Stack Pointer and the Pattern Area are OK so return false.
[0faa8b11]310   */
311  if ( sp_ok && pattern_ok )
[937ec60]312    return false;
[0faa8b11]313
314  /*
315   * Let's report as much as we can.
316   */
317  Stack_check_report_blown_task( _Thread_Executing, pattern_ok );
[937ec60]318  return true;
[4da36c1a]319}
320
321/*
322 * Stack_check_find_high_water_mark
323 */
[ac7d5ef0]324void *Stack_check_find_high_water_mark(
325  const void *s,
[4da36c1a]326  size_t      n
[ac7d5ef0]327)
328{
[3e08d4e]329  const uint32_t   *base, *ebase;
330  uint32_t   length;
[ac7d5ef0]331
332  base = s;
333  length = n/4;
334
[4da36c1a]335  #if ( CPU_STACK_GROWS_UP == TRUE )
336    /*
337     * start at higher memory and find first word that does not
338     * match pattern
339     */
[ac7d5ef0]340
[4da36c1a]341    base += length - 1;
342    for (ebase = s; base > ebase; base--)
[c3330a8]343      if (*base != U32_PATTERN)
344        return (void *) base;
[4da36c1a]345  #else
346    /*
347     * start at lower memory and find first word that does not
348     * match pattern
349     */
[ac7d5ef0]350
[4da36c1a]351    base += PATTERN_SIZE_WORDS;
352    for (ebase = base + length; base < ebase; base++)
[c3330a8]353      if (*base != U32_PATTERN)
354        return (void *) base;
[4da36c1a]355  #endif
[ac7d5ef0]356
357  return (void *)0;
358}
359
[4da36c1a]360/*
[90a5d194]361 *  Stack_check_Dump_threads_usage
[ac7d5ef0]362 *
[4da36c1a]363 *  Try to print out how much stack was actually used by the task.
[ac7d5ef0]364 */
[90a5d194]365static void                   *print_context;
366static rtems_printk_plugin_t   print_handler;
367
[ac7d5ef0]368void Stack_check_Dump_threads_usage(
369  Thread_Control *the_thread
370)
371{
[3e08d4e]372  uint32_t        size, used;
[ac7d5ef0]373  void           *low;
374  void           *high_water_mark;
[dbfc895e]375  void           *current;
[ac7d5ef0]376  Stack_Control  *stack;
[c3330a8]377  char            name[5];
[ac7d5ef0]378
379  if ( !the_thread )
380    return;
381
[90a5d194]382  if ( !print_handler )
383    return;
384
[ac7d5ef0]385  /*
[dbfc895e]386   *  Obtain interrupt stack information
[ac7d5ef0]387   */
388
[4da36c1a]389  if (the_thread == (Thread_Control *) -1) {
390    if (Stack_check_Interrupt_stack.area) {
391      stack = &Stack_check_Interrupt_stack;
392      the_thread = 0;
[dbfc895e]393      current = 0;
[4da36c1a]394    }
395    else
396      return;
[dbfc895e]397  } else {
398    stack  = &the_thread->Start.Initial_stack;
399    current = (void *)_CPU_Context_Get_SP( &the_thread->Registers );
400  }
[ac7d5ef0]401
402  low  = Stack_check_usable_stack_start(stack);
403  size = Stack_check_usable_stack_size(stack);
404
405  high_water_mark = Stack_check_find_high_water_mark(low, size);
406
407  if ( high_water_mark )
408    used = Stack_check_Calculate_used( low, size, high_water_mark );
409  else
410    used = 0;
411
[e819fefc]412  if ( the_thread ) {
[dbfc895e]413    (*print_handler)(
414      print_context,
415      "0x%08" PRIx32 "  %4s",
416      the_thread->Object.id,
417      rtems_object_get_name( the_thread->Object.id, sizeof(name), name )
418    );
[e819fefc]419  } else {
[dbfc895e]420    (*print_handler)( print_context, "0x%08" PRIx32 "  INTR", ~0 );
[e819fefc]421  }
[c46ce854]422
[90a5d194]423  (*print_handler)(
424    print_context,
[dbfc895e]425    " %010p - %010p %010p  %8" PRId32 "   ",
[4da36c1a]426    stack->area,
427    stack->area + stack->size - 1,
[dbfc895e]428    current,
429    size
[ac7d5ef0]430  );
[dbfc895e]431
432  if (Stack_check_Initialized == 0) {
433    (*print_handler)( print_context, "Unavailable\n" );
434  } else {
435    (*print_handler)( print_context, "%8" PRId32 "\n", used );
436  }
437   
438
[ac7d5ef0]439}
440
[4da36c1a]441/*
[7ac4ae9]442 *  rtems_stack_checker_fatal_extension
[ac7d5ef0]443 */
[4da36c1a]444#ifndef DONT_USE_FATAL_EXTENSION
445  void rtems_stack_checker_fatal_extension(
[11290355]446    Internal_errors_Source  source,
[937ec60]447    bool                    is_internal,
[3e08d4e]448    uint32_t                status
[4da36c1a]449  )
450  {
[ac7d5ef0]451    if (status == 0)
[4da36c1a]452      rtems_stack_checker_report_usage();
453  }
[8389628]454#endif
[ac7d5ef0]455
456/*PAGE
457 *
[8583f82]458 *  rtems_stack_checker_report_usage
[ac7d5ef0]459 */
460
[90a5d194]461void rtems_stack_checker_report_usage_with_plugin(
462  void                  *context,
463  rtems_printk_plugin_t  print
464)
[ac7d5ef0]465{
[90a5d194]466  print_context = context;
467  print_handler = print;
468
469  (*print)( context, "Stack usage by thread\n");
470  (*print)( context,
[dbfc895e]471"    ID      NAME    LOW          HIGH     CURRENT     AVAILABLE     USED\n"
[ac7d5ef0]472  );
[5250ff39]473
[d8ec87b4]474  /* iterate over all threads and dump the usage */
475  rtems_iterate_over_all_threads( Stack_check_Dump_threads_usage );
[ac7d5ef0]476
477  /* dump interrupt stack info if any */
478  Stack_check_Dump_threads_usage((Thread_Control *) -1);
[90a5d194]479
480  print_context = NULL;
481  print_handler = NULL;
482
483}
484
485void rtems_stack_checker_report_usage( void )
486{
487  rtems_stack_checker_report_usage_with_plugin( NULL, printk_plugin );
[ac7d5ef0]488}
Note: See TracBrowser for help on using the repository browser.