OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rtems/] [c/] [src/] [libmisc/] [stackchk/] [check.c] - Blame information for rev 1779

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.