source: rtems/cpukit/libmisc/stackchk/check.c @ 7ced9d9b

5
Last change on this file since 7ced9d9b was 7ced9d9b, checked in by Sebastian Huber <sebastian.huber@…>, on 01/12/17 at 08:25:56

score: Add and use _Thread_Get_name()

Update #2858.

  • Property mode set to 100644
File size: 11.8 KB
RevLine 
[f5f2676]1/**
2 * @file
3 *
4 * @brief Stack Overflow Check User Extension Set
5 * @ingroup libmisc_stackchk Stack Checker Mechanism
[ac7d5ef0]6 *
[f5f2676]7 * NOTE:  This extension set automatically determines at
[ac7d5ef0]8 *         initialization time whether the stack for this
9 *         CPU grows up or down and installs the correct
10 *         extension routines for that direction.
[f5f2676]11 */
12
13/*
[d22cd4a]14 *  COPYRIGHT (c) 1989-2010.
[ac7d5ef0]15 *  On-Line Applications Research Corporation (OAR).
16 *
[98e4ebf5]17 *  The license and distribution terms for this file may be
18 *  found in the file LICENSE in this distribution or at
[c499856]19 *  http://www.rtems.org/license/LICENSE.
[ac7d5ef0]20 *
21 */
22
[550c3df7]23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
26
[3a4ae6c]27#include <rtems.h>
[3523321]28#include <inttypes.h>
[3a4ae6c]29
[8389628]30/*
[4da36c1a]31 * The stack dump information may be printed by a "fatal" extension.
[8389628]32 * Fatal extensions only get called via rtems_fatal_error_occurred()
33 * and not when rtems_shutdown_executive() is called.
34 * When that happens, this #define should be deleted and all the code
35 * it marks.
36 */
37#define DONT_USE_FATAL_EXTENSION
38
[ac7d5ef0]39#include <string.h>
40#include <stdlib.h>
41
[d8ec87b4]42#include <rtems/bspIo.h>
[506bfc8]43#include <rtems/printer.h>
[bfc3533]44#include <rtems/stackchk.h>
[5f31bbe]45#include <rtems/score/percpu.h>
[7ced9d9b]46#include <rtems/score/threadimpl.h>
[bba988d]47
48/*
49 *  This structure is used to fill in and compare the "end of stack"
50 *  marker pattern.
51 *  pattern area must be a multiple of 4 words.
52 */
53
[8bb9d41]54#if !defined(CPU_STACK_CHECK_PATTERN_INITIALIZER)
55#define CPU_STACK_CHECK_PATTERN_INITIALIZER \
56  { \
57    0xFEEDF00D, 0x0BAD0D06, /* FEED FOOD to  BAD DOG */ \
58    0xDEADF00D, 0x600D0D06  /* DEAD FOOD but GOOD DOG */ \
59  }
[bba988d]60#endif
61
62/*
63 *  The pattern used to fill the entire stack.
64 */
65
66#define BYTE_PATTERN 0xA5
67#define U32_PATTERN 0xA5A5A5A5
68
[ac7d5ef0]69/*
[4da36c1a]70 *  Variable to indicate when the stack checker has been initialized.
[ac7d5ef0]71 */
[4da36c1a]72static int   Stack_check_Initialized = 0;
[ac7d5ef0]73
74/*
75 *  The "magic pattern" used to mark the end of the stack.
76 */
[8bb9d41]77static const uint32_t Stack_check_Pattern[] =
78  CPU_STACK_CHECK_PATTERN_INITIALIZER;
79
80#define PATTERN_SIZE_BYTES sizeof(Stack_check_Pattern)
81
82#define PATTERN_SIZE_WORDS RTEMS_ARRAY_SIZE(Stack_check_Pattern)
[ac7d5ef0]83
[d8ec87b4]84/*
85 * Helper function to report if the actual stack pointer is in range.
86 *
87 * NOTE: This uses a GCC specific method.
88 */
[937ec60]89static inline bool Stack_check_Frame_pointer_in_range(
[8bb9d41]90  const Thread_Control *the_thread
[d8ec87b4]91)
92{
93  #if defined(__GNUC__)
[b99a35a]94    void *sp = __builtin_frame_address(0);
[8bb9d41]95    const Stack_Control *the_stack = &the_thread->Start.Initial_stack;
[b99a35a]96
[d8ec87b4]97    if ( sp < the_stack->area ) {
[937ec60]98      return false;
[d8ec87b4]99    }
100    if ( sp > (the_stack->area + the_stack->size) ) {
[937ec60]101      return false;
[d8ec87b4]102    }
[4da36c1a]103  #else
104    #error "How do I check stack bounds on a non-GNU compiler?"
[d8ec87b4]105  #endif
[937ec60]106  return true;
[d8ec87b4]107}
108
[ac7d5ef0]109/*
110 *  Where the pattern goes in the stack area is dependent upon
111 *  whether the stack grow to the high or low area of the memory.
112 */
[4da36c1a]113#if (CPU_STACK_GROWS_UP == TRUE)
[16b1546e]114  #define Stack_check_Get_pattern( _the_stack ) \
115    ((char *)(_the_stack)->area + \
[8bb9d41]116         (_the_stack)->size - PATTERN_SIZE_BYTES )
[ac7d5ef0]117
[4da36c1a]118  #define Stack_check_Calculate_used( _low, _size, _high_water ) \
119      ((char *)(_high_water) - (char *)(_low))
[ac7d5ef0]120
[4da36c1a]121  #define Stack_check_usable_stack_start(_the_stack) \
[ac7d5ef0]122    ((_the_stack)->area)
123
124#else
[518c2aeb]125  /*
126   * We need this magic offset because during a task delete the task stack will
127   * be freed before we enter the task switch extension which checks the stack.
128   * The task stack free operation will write the next and previous pointers
129   * for the free list into this area.
130   */
[16b1546e]131  #define Stack_check_Get_pattern( _the_stack ) \
[11236580]132    ((char *)(_the_stack)->area + sizeof(Heap_Block) - HEAP_BLOCK_HEADER_SIZE)
[ac7d5ef0]133
[4da36c1a]134  #define Stack_check_Calculate_used( _low, _size, _high_water) \
135      ( ((char *)(_low) + (_size)) - (char *)(_high_water) )
[d8ec87b4]136
[4da36c1a]137  #define Stack_check_usable_stack_start(_the_stack) \
[8bb9d41]138      ((char *)(_the_stack)->area + PATTERN_SIZE_BYTES)
[ac7d5ef0]139
140#endif
141
[4da36c1a]142/*
143 *  The assumption is that if the pattern gets overwritten, the task
144 *  is too close.  This defines the usable stack memory.
145 */
[ac7d5ef0]146#define Stack_check_usable_stack_size(_the_stack) \
[8bb9d41]147    ((_the_stack)->size - PATTERN_SIZE_BYTES)
[ac7d5ef0]148
[2d637b2]149#if (CPU_ALLOCATE_INTERRUPT_STACK == TRUE)
150  /*
151   *  Did RTEMS allocate the interrupt stack? If so, put it in
152   *  Stack_Control format.
153   */
154  Stack_Control Stack_check_Interrupt_stack;
155#endif
[ac7d5ef0]156
157/*
[4da36c1a]158 *  Fill an entire stack area with BYTE_PATTERN.  This will be used
159 *  to check for amount of actual stack used.
[ac7d5ef0]160 */
[4da36c1a]161#define Stack_check_Dope_stack(_stack) \
162  memset((_stack)->area, BYTE_PATTERN, (_stack)->size)
[ac7d5ef0]163
[4da36c1a]164/*
165 *  Stack_check_Initialize
[ac7d5ef0]166 */
[13a69b9]167static void Stack_check_Initialize( void )
[ac7d5ef0]168{
[21e3de1]169  if ( Stack_check_Initialized )
[d8ec87b4]170    return;
[ac7d5ef0]171
172  /*
173   * If appropriate, setup the interrupt stack for high water testing
174   * also.
175   */
[4da36c1a]176  #if (CPU_ALLOCATE_INTERRUPT_STACK == TRUE)
177    if (_CPU_Interrupt_stack_low && _CPU_Interrupt_stack_high) {
178      Stack_check_Interrupt_stack.area = _CPU_Interrupt_stack_low;
179      Stack_check_Interrupt_stack.size = (char *) _CPU_Interrupt_stack_high -
180                                  (char *) _CPU_Interrupt_stack_low;
181      Stack_check_Dope_stack(&Stack_check_Interrupt_stack);
[da9b538]182   }
[4da36c1a]183  #endif
[8389628]184
[4da36c1a]185  Stack_check_Initialized = 1;
[ac7d5ef0]186}
187
[8bb9d41]188static bool Stack_check_Is_pattern_valid(const Thread_Control *the_thread)
189{
190  return memcmp(
191    Stack_check_Get_pattern(&the_thread->Start.Initial_stack),
192    Stack_check_Pattern,
193    PATTERN_SIZE_BYTES
194  ) == 0;
195}
196
[4da36c1a]197/*
[7ac4ae9]198 *  rtems_stack_checker_create_extension
[ac7d5ef0]199 */
[937ec60]200bool rtems_stack_checker_create_extension(
[f97536d]201  Thread_Control *running RTEMS_UNUSED,
[ac7d5ef0]202  Thread_Control *the_thread
203)
204{
[4da36c1a]205  Stack_check_Initialize();
[84e960e]206  Stack_check_Dope_stack(&the_thread->Start.Initial_stack);
[ac7d5ef0]207
[8bb9d41]208  memcpy(
209    Stack_check_Get_pattern(&the_thread->Start.Initial_stack),
210    Stack_check_Pattern,
211    PATTERN_SIZE_BYTES
212  );
[84e960e]213
214  return true;
[ac7d5ef0]215}
216
[4da36c1a]217/*
[ac7d5ef0]218 *  Stack_check_report_blown_task
[4da36c1a]219 *
[ac7d5ef0]220 *  Report a blown stack.  Needs to be a separate routine
221 *  so that interrupt handlers can use this too.
222 *
223 *  NOTE: The system is in a questionable state... we may not get
224 *        the following message out.
225 */
[8bb9d41]226static void Stack_check_report_blown_task(
227  const Thread_Control *running,
[da9b538]228  bool pattern_ok
[8bb9d41]229)
[ac7d5ef0]230{
[8bb9d41]231  const Stack_Control *stack = &running->Start.Initial_stack;
232  void                *pattern_area = Stack_check_Get_pattern(stack);
233  char                 name[32];
[ac7d5ef0]234
[8a775c27]235  printk("BLOWN STACK!!!\n");
[560db810]236  printk("task control block: 0x%08" PRIxPTR "\n", (intptr_t) running);
[8a775c27]237  printk("task ID: 0x%08lx\n", (unsigned long) running->Object.id);
238  printk(
[a89c963]239    "task name: 0x%08" PRIx32 "\n",
240    running->Object.name.name_u32
[8a775c27]241  );
[7ced9d9b]242  _Thread_Get_name(running, name, sizeof(name));
243  printk("task name string: %s\n", name);
[8a775c27]244  printk(
[a89c963]245    "task stack area (%lu Bytes): 0x%08" PRIxPTR " .. 0x%08" PRIxPTR "\n",
[8a775c27]246    (unsigned long) stack->size,
[560db810]247    (intptr_t) stack->area,
248    (intptr_t) ((char *) stack->area + stack->size)
[8a775c27]249  );
250  if (!pattern_ok) {
251    printk(
[a89c963]252      "damaged pattern area (%lu Bytes): 0x%08" PRIxPTR " .. 0x%08" PRIxPTR "\n",
[8a775c27]253      (unsigned long) PATTERN_SIZE_BYTES,
[560db810]254      (intptr_t) pattern_area,
255      (intptr_t) (pattern_area + PATTERN_SIZE_BYTES)
[8a775c27]256    );
257  }
[ac7d5ef0]258
[4da36c1a]259  #if defined(RTEMS_MULTIPROCESSING)
260    if (rtems_configuration_get_user_multiprocessing_table()) {
[d8ec87b4]261      printk(
[a89c963]262        "node: 0x%08" PRIxPTR "\n",
[560db810]263          (intptr_t) rtems_configuration_get_user_multiprocessing_table()->node
[4da36c1a]264      );
[d8ec87b4]265    }
[4da36c1a]266  #endif
267
[a12f7e9]268  rtems_fatal(
269    RTEMS_FATAL_SOURCE_STACK_CHECKER,
270    running->Object.name.name_u32
271  );
[ac7d5ef0]272}
273
[4da36c1a]274/*
[7ac4ae9]275 *  rtems_stack_checker_switch_extension
[ac7d5ef0]276 */
[7ac4ae9]277void rtems_stack_checker_switch_extension(
[f97536d]278  Thread_Control *running RTEMS_UNUSED,
279  Thread_Control *heir RTEMS_UNUSED
[ac7d5ef0]280)
281{
[8bb9d41]282  bool sp_ok;
283  bool pattern_ok;
[d8ec87b4]284
285  /*
[2b596c69]286   *  Check for an out of bounds stack pointer or an overwrite
[d8ec87b4]287   */
[8bb9d41]288  sp_ok = Stack_check_Frame_pointer_in_range( running );
[2b596c69]289
[8bb9d41]290  pattern_ok = Stack_check_Is_pattern_valid( running );
[d8ec87b4]291
292  if ( !sp_ok || !pattern_ok ) {
293    Stack_check_report_blown_task( running, pattern_ok );
[ac7d5ef0]294  }
295}
296
[4da36c1a]297/*
298 *  Check if blown
299 */
[937ec60]300bool rtems_stack_checker_is_blown( void )
[4da36c1a]301{
[8bb9d41]302  rtems_stack_checker_switch_extension( _Thread_Get_executing(), NULL );
[0faa8b11]303
304  /*
[da9b538]305   * The Stack Pointer and the Pattern Area are OK so return false.
[0faa8b11]306   */
[da9b538]307  return false;
[4da36c1a]308}
309
310/*
311 * Stack_check_find_high_water_mark
312 */
[da9b538]313static inline void *Stack_check_find_high_water_mark(
[ac7d5ef0]314  const void *s,
[4da36c1a]315  size_t      n
[ac7d5ef0]316)
317{
[3e08d4e]318  const uint32_t   *base, *ebase;
319  uint32_t   length;
[ac7d5ef0]320
321  base = s;
322  length = n/4;
323
[4da36c1a]324  #if ( CPU_STACK_GROWS_UP == TRUE )
325    /*
326     * start at higher memory and find first word that does not
327     * match pattern
328     */
[ac7d5ef0]329
[4da36c1a]330    base += length - 1;
331    for (ebase = s; base > ebase; base--)
[c3330a8]332      if (*base != U32_PATTERN)
333        return (void *) base;
[4da36c1a]334  #else
335    /*
336     * start at lower memory and find first word that does not
337     * match pattern
338     */
[ac7d5ef0]339
[4da36c1a]340    base += PATTERN_SIZE_WORDS;
341    for (ebase = base + length; base < ebase; base++)
[c3330a8]342      if (*base != U32_PATTERN)
343        return (void *) base;
[4da36c1a]344  #endif
[ac7d5ef0]345
346  return (void *)0;
347}
348
[4da36c1a]349/*
[90a5d194]350 *  Stack_check_Dump_threads_usage
[ac7d5ef0]351 *
[4da36c1a]352 *  Try to print out how much stack was actually used by the task.
[ac7d5ef0]353 */
[d271c3bb]354static bool Stack_check_Dump_threads_usage(
355  Thread_Control *the_thread,
356  void           *arg
[ac7d5ef0]357)
358{
[d271c3bb]359  uint32_t             size, used;
360  void                *low;
361  void                *high_water_mark;
362  void                *current;
363  Stack_Control       *stack;
[7ced9d9b]364  char                 name[ 22 ];
[d271c3bb]365  const rtems_printer *printer;
[7ced9d9b]366  uint32_t             id;
[ac7d5ef0]367
[d271c3bb]368  printer = arg;
[90a5d194]369
[ac7d5ef0]370  /*
[dbfc895e]371   *  Obtain interrupt stack information
[ac7d5ef0]372   */
[2d637b2]373  #if (CPU_ALLOCATE_INTERRUPT_STACK == TRUE)
374    if (the_thread == (Thread_Control *) -1) {
375      if (!Stack_check_Interrupt_stack.area)
[d271c3bb]376        return false;
[4da36c1a]377      stack = &Stack_check_Interrupt_stack;
378      the_thread = 0;
[dbfc895e]379      current = 0;
[f5f2676]380    } else
[d4a97df3]381  #endif
[2d637b2]382    {
383      stack  = &the_thread->Start.Initial_stack;
384      current = (void *)_CPU_Context_Get_SP( &the_thread->Registers );
[4da36c1a]385    }
[ac7d5ef0]386
387  low  = Stack_check_usable_stack_start(stack);
388  size = Stack_check_usable_stack_size(stack);
389
390  high_water_mark = Stack_check_find_high_water_mark(low, size);
391
392  if ( high_water_mark )
393    used = Stack_check_Calculate_used( low, size, high_water_mark );
394  else
395    used = 0;
396
[7ced9d9b]397#if (CPU_ALLOCATE_INTERRUPT_STACK == TRUE)
398  if ( the_thread == NULL ) {
399    id = 0xffffffff;
400    strlcpy( name, "INTR", sizeof( name ) );
401  } else
402#endif
403  {
404    id = the_thread->Object.id;
405    _Thread_Get_name( the_thread, name, sizeof( name ) );
406  }
[c46ce854]407
[24d0ee57]408  rtems_printf(
409    printer,
[7ced9d9b]410    "0x%08" PRIx32 " %-21s 0x%08" PRIuPTR " 0x%08" PRIuPTR " 0x%08" PRIuPTR " %6" PRId32 " ",
411    id,
412    name,
413    (uintptr_t) stack->area,
414    (uintptr_t) stack->area + (uintptr_t) stack->size - 1,
415    (uintptr_t) current,
[dbfc895e]416    size
[ac7d5ef0]417  );
[dbfc895e]418
419  if (Stack_check_Initialized == 0) {
[7ced9d9b]420    rtems_printf( printer, "N/A\n" );
[dbfc895e]421  } else {
[7ced9d9b]422    rtems_printf( printer, "%6" PRId32 "\n", used );
[dbfc895e]423  }
[0893220]424
[d271c3bb]425  return false;
[ac7d5ef0]426}
427
[4da36c1a]428/*
[7ac4ae9]429 *  rtems_stack_checker_fatal_extension
[ac7d5ef0]430 */
[4da36c1a]431#ifndef DONT_USE_FATAL_EXTENSION
432  void rtems_stack_checker_fatal_extension(
[11290355]433    Internal_errors_Source  source,
[6a9282d]434    bool                    always_set_to_false,
[3e08d4e]435    uint32_t                status
[4da36c1a]436  )
437  {
[ac7d5ef0]438    if (status == 0)
[4da36c1a]439      rtems_stack_checker_report_usage();
440  }
[8389628]441#endif
[ac7d5ef0]442
[64adc13]443/*
[8583f82]444 *  rtems_stack_checker_report_usage
[ac7d5ef0]445 */
446
[90a5d194]447void rtems_stack_checker_report_usage_with_plugin(
[d271c3bb]448  const rtems_printer* printer
[90a5d194]449)
[ac7d5ef0]450{
[7ced9d9b]451  rtems_printf(
452     printer,
453     "                             STACK USAGE BY THREAD\n"
454     "ID         NAME                  LOW        HIGH       CURRENT    AVAIL  USED\n"
[ac7d5ef0]455  );
[5250ff39]456
[d8ec87b4]457  /* iterate over all threads and dump the usage */
[d271c3bb]458  rtems_task_iterate(
459    Stack_check_Dump_threads_usage,
460    RTEMS_DECONST( rtems_printer *, printer )
461  );
[ac7d5ef0]462
[2d637b2]463  #if (CPU_ALLOCATE_INTERRUPT_STACK == TRUE)
464    /* dump interrupt stack info if any */
[d271c3bb]465    Stack_check_Dump_threads_usage(
466      (Thread_Control *) -1,
467      RTEMS_DECONST( rtems_printer *, printer )
468    );
[2d637b2]469  #endif
[90a5d194]470}
471
472void rtems_stack_checker_report_usage( void )
473{
[24d0ee57]474  rtems_printer printer;
475  rtems_print_printer_printk(&printer);
476  rtems_stack_checker_report_usage_with_plugin( &printer );
[ac7d5ef0]477}
Note: See TracBrowser for help on using the repository browser.