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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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