--- crash/gdb-6.0/gdb/symtab.c.orig 2005-03-03 11:36:20.000000000 -0500 +++ crash/gdb-6.0/gdb/symtab.c 2005-03-02 16:19:09.000000000 -0500 @@ -889,7 +889,9 @@ doesn't affect these calls since they are looking for a known variable and thus can probably assume it will never hit the C++ code). */ - +#ifdef CRASH_MERGE +static void gdb_bait_and_switch(char *, struct symbol *); +#endif struct symbol * lookup_symbol (const char *name, const struct block *block, const domain_enum domain, int *is_a_field_of_this, @@ -936,7 +938,6 @@ #ifdef CRASH_MERGE if (returnval && (domain == VAR_DOMAIN)) { - static void gdb_bait_and_switch(char *, struct symbol *); gdb_bait_and_switch((char *)modified_name, returnval); } #endif --- crash/gdb-6.0/include/obstack.h.orig 2005-03-03 11:36:20.000000000 -0500 +++ crash/gdb-6.0/include/obstack.h 2005-03-02 16:39:05.000000000 -0500 @@ -0,0 +1,611 @@ +/* obstack.h - object stack macros + Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, + 1999, 2000 + Free Software Foundation, Inc. + + + NOTE: The canonical source of this file is maintained with the GNU C Library. + Bugs can be reported to bug-glibc@gnu.org. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +/* Summary: + +All the apparent functions defined here are macros. The idea +is that you would use these pre-tested macros to solve a +very specific set of problems, and they would run fast. +Caution: no side-effects in arguments please!! They may be +evaluated MANY times!! + +These macros operate a stack of objects. Each object starts life +small, and may grow to maturity. (Consider building a word syllable +by syllable.) An object can move while it is growing. Once it has +been "finished" it never changes address again. So the "top of the +stack" is typically an immature growing object, while the rest of the +stack is of mature, fixed size and fixed address objects. + +These routines grab large chunks of memory, using a function you +supply, called `obstack_chunk_alloc'. On occasion, they free chunks, +by calling `obstack_chunk_free'. You must define them and declare +them before using any obstack macros. + +Each independent stack is represented by a `struct obstack'. +Each of the obstack macros expects a pointer to such a structure +as the first argument. + +One motivation for this package is the problem of growing char strings +in symbol tables. Unless you are "fascist pig with a read-only mind" +--Gosper's immortal quote from HAKMEM item 154, out of context--you +would not like to put any arbitrary upper limit on the length of your +symbols. + +In practice this often means you will build many short symbols and a +few long symbols. At the time you are reading a symbol you don't know +how long it is. One traditional method is to read a symbol into a +buffer, realloc()ating the buffer every time you try to read a symbol +that is longer than the buffer. This is beaut, but you still will +want to copy the symbol from the buffer to a more permanent +symbol-table entry say about half the time. + +With obstacks, you can work differently. Use one obstack for all symbol +names. As you read a symbol, grow the name in the obstack gradually. +When the name is complete, finalize it. Then, if the symbol exists already, +free the newly read name. + +The way we do this is to take a large chunk, allocating memory from +low addresses. When you want to build a symbol in the chunk you just +add chars above the current "high water mark" in the chunk. When you +have finished adding chars, because you got to the end of the symbol, +you know how long the chars are, and you can create a new object. +Mostly the chars will not burst over the highest address of the chunk, +because you would typically expect a chunk to be (say) 100 times as +long as an average object. + +In case that isn't clear, when we have enough chars to make up +the object, THEY ARE ALREADY CONTIGUOUS IN THE CHUNK (guaranteed) +so we just point to it where it lies. No moving of chars is +needed and this is the second win: potentially long strings need +never be explicitly shuffled. Once an object is formed, it does not +change its address during its lifetime. + +When the chars burst over a chunk boundary, we allocate a larger +chunk, and then copy the partly formed object from the end of the old +chunk to the beginning of the new larger chunk. We then carry on +accreting characters to the end of the object as we normally would. + +A special macro is provided to add a single char at a time to a +growing object. This allows the use of register variables, which +break the ordinary 'growth' macro. + +Summary: + We allocate large chunks. + We carve out one object at a time from the current chunk. + Once carved, an object never moves. + We are free to append data of any size to the currently + growing object. + Exactly one object is growing in an obstack at any one time. + You can run one obstack per control block. + You may have as many control blocks as you dare. + Because of the way we do it, you can `unwind' an obstack + back to a previous state. (You may remove objects much + as you would with a stack.) +*/ + + +/* Don't do the contents of this file more than once. */ + +#ifndef _OBSTACK_H +#define _OBSTACK_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* We use subtraction of (char *) 0 instead of casting to int + because on word-addressable machines a simple cast to int + may ignore the byte-within-word field of the pointer. */ + +#ifndef __PTR_TO_INT +# define __PTR_TO_INT(P) ((P) - (char *) 0) +#endif + +#ifndef __INT_TO_PTR +# define __INT_TO_PTR(P) ((P) + (char *) 0) +#endif + +/* We need the type of the resulting object. If __PTRDIFF_TYPE__ is + defined, as with GNU C, use that; that way we don't pollute the + namespace with 's symbols. Otherwise, if is + available, include it and use ptrdiff_t. In traditional C, long is + the best that we can do. */ + +#ifdef __PTRDIFF_TYPE__ +# define PTR_INT_TYPE __PTRDIFF_TYPE__ +#else +# ifdef HAVE_STDDEF_H +# include +# define PTR_INT_TYPE ptrdiff_t +# else +# define PTR_INT_TYPE long +# endif +#endif + +#if defined _LIBC || defined HAVE_STRING_H +# include +# if defined __STDC__ && __STDC__ +# define _obstack_memcpy(To, From, N) memcpy ((To), (From), (N)) +# else +# define _obstack_memcpy(To, From, N) memcpy ((To), (char *)(From), (N)) +# endif +#else +# ifdef memcpy +# define _obstack_memcpy(To, From, N) memcpy ((To), (char *)(From), (N)) +# else +# define _obstack_memcpy(To, From, N) bcopy ((char *)(From), (To), (N)) +# endif +#endif + +struct _obstack_chunk /* Lives at front of each chunk. */ +{ + char *limit; /* 1 past end of this chunk */ + struct _obstack_chunk *prev; /* address of prior chunk or NULL */ + char contents[4]; /* objects begin here */ +}; + +struct obstack /* control current object in current chunk */ +{ + long chunk_size; /* preferred size to allocate chunks in */ + struct _obstack_chunk *chunk; /* address of current struct obstack_chunk */ + char *object_base; /* address of object we are building */ + char *next_free; /* where to add next char to current object */ + char *chunk_limit; /* address of char after current chunk */ + PTR_INT_TYPE temp; /* Temporary for some macros. */ + int alignment_mask; /* Mask of alignment for each object. */ +#if defined __STDC__ && __STDC__ + /* These prototypes vary based on `use_extra_arg', and we use + casts to the prototypeless function type in all assignments, + but having prototypes here quiets -Wstrict-prototypes. */ + struct _obstack_chunk *(*chunkfun) (void *, long); + void (*freefun) (void *, struct _obstack_chunk *); + void *extra_arg; /* first arg for chunk alloc/dealloc funcs */ +#else + struct _obstack_chunk *(*chunkfun) (); /* User's fcn to allocate a chunk. */ + void (*freefun) (); /* User's function to free a chunk. */ + char *extra_arg; /* first arg for chunk alloc/dealloc funcs */ +#endif + unsigned use_extra_arg:1; /* chunk alloc/dealloc funcs take extra arg */ + unsigned maybe_empty_object:1;/* There is a possibility that the current + chunk contains a zero-length object. This + prevents freeing the chunk if we allocate + a bigger chunk to replace it. */ + unsigned alloc_failed:1; /* No longer used, as we now call the failed + handler on error, but retained for binary + compatibility. */ +}; + +/* Declare the external functions we use; they are in obstack.c. */ + +#if defined __STDC__ && __STDC__ +extern void _obstack_newchunk (struct obstack *, int); +extern void _obstack_free (struct obstack *, void *); +extern int _obstack_begin (struct obstack *, int, int, + void *(*) (long), void (*) (void *)); +extern int _obstack_begin_1 (struct obstack *, int, int, + void *(*) (void *, long), + void (*) (void *, void *), void *); +extern int _obstack_memory_used (struct obstack *); +#else +extern void _obstack_newchunk (); +extern void _obstack_free (); +extern int _obstack_begin (); +extern int _obstack_begin_1 (); +extern int _obstack_memory_used (); +#endif + +#if defined __STDC__ && __STDC__ + +/* Do the function-declarations after the structs + but before defining the macros. */ + +void obstack_init (struct obstack *obstack); + +void * obstack_alloc (struct obstack *obstack, int size); + +void * obstack_copy (struct obstack *obstack, void *address, int size); +void * obstack_copy0 (struct obstack *obstack, void *address, int size); + +void obstack_free (struct obstack *obstack, void *block); + +void obstack_blank (struct obstack *obstack, int size); + +void obstack_grow (struct obstack *obstack, void *data, int size); +void obstack_grow0 (struct obstack *obstack, void *data, int size); + +void obstack_1grow (struct obstack *obstack, int data_char); +void obstack_ptr_grow (struct obstack *obstack, void *data); +void obstack_int_grow (struct obstack *obstack, int data); + +void * obstack_finish (struct obstack *obstack); + +int obstack_object_size (struct obstack *obstack); + +int obstack_room (struct obstack *obstack); +void obstack_make_room (struct obstack *obstack, int size); +void obstack_1grow_fast (struct obstack *obstack, int data_char); +void obstack_ptr_grow_fast (struct obstack *obstack, void *data); +void obstack_int_grow_fast (struct obstack *obstack, int data); +void obstack_blank_fast (struct obstack *obstack, int size); + +void * obstack_base (struct obstack *obstack); +void * obstack_next_free (struct obstack *obstack); +int obstack_alignment_mask (struct obstack *obstack); +int obstack_chunk_size (struct obstack *obstack); +int obstack_memory_used (struct obstack *obstack); + +#endif /* __STDC__ */ + +/* Non-ANSI C cannot really support alternative functions for these macros, + so we do not declare them. */ + +/* Error handler called when `obstack_chunk_alloc' failed to allocate + more memory. This can be set to a user defined function. The + default action is to print a message and abort. */ +#if defined __STDC__ && __STDC__ +extern void (*obstack_alloc_failed_handler) (void); +#else +extern void (*obstack_alloc_failed_handler) (); +#endif + +/* Exit value used when `print_and_abort' is used. */ +extern int obstack_exit_failure; + +/* Pointer to beginning of object being allocated or to be allocated next. + Note that this might not be the final address of the object + because a new chunk might be needed to hold the final size. */ + +#define obstack_base(h) ((h)->object_base) + +/* Size for allocating ordinary chunks. */ + +#define obstack_chunk_size(h) ((h)->chunk_size) + +/* Pointer to next byte not yet allocated in current chunk. */ + +#define obstack_next_free(h) ((h)->next_free) + +/* Mask specifying low bits that should be clear in address of an object. */ + +#define obstack_alignment_mask(h) ((h)->alignment_mask) + +/* To prevent prototype warnings provide complete argument list in + standard C version. */ +#if defined __STDC__ && __STDC__ + +# define obstack_init(h) \ + _obstack_begin ((h), 0, 0, \ + (void *(*) (long)) obstack_chunk_alloc, (void (*) (void *)) obstack_chunk_free) + +# define obstack_begin(h, size) \ + _obstack_begin ((h), (size), 0, \ + (void *(*) (long)) obstack_chunk_alloc, (void (*) (void *)) obstack_chunk_free) + +# define obstack_specify_allocation(h, size, alignment, chunkfun, freefun) \ + _obstack_begin ((h), (size), (alignment), \ + (void *(*) (long)) (chunkfun), (void (*) (void *)) (freefun)) + +# define obstack_specify_allocation_with_arg(h, size, alignment, chunkfun, freefun, arg) \ + _obstack_begin_1 ((h), (size), (alignment), \ + (void *(*) (void *, long)) (chunkfun), \ + (void (*) (void *, void *)) (freefun), (arg)) + +# define obstack_chunkfun(h, newchunkfun) \ + ((h) -> chunkfun = (struct _obstack_chunk *(*)(void *, long)) (newchunkfun)) + +# define obstack_freefun(h, newfreefun) \ + ((h) -> freefun = (void (*)(void *, struct _obstack_chunk *)) (newfreefun)) + +#else + +# define obstack_init(h) \ + _obstack_begin ((h), 0, 0, \ + (void *(*) ()) obstack_chunk_alloc, (void (*) ()) obstack_chunk_free) + +# define obstack_begin(h, size) \ + _obstack_begin ((h), (size), 0, \ + (void *(*) ()) obstack_chunk_alloc, (void (*) ()) obstack_chunk_free) + +# define obstack_specify_allocation(h, size, alignment, chunkfun, freefun) \ + _obstack_begin ((h), (size), (alignment), \ + (void *(*) ()) (chunkfun), (void (*) ()) (freefun)) + +# define obstack_specify_allocation_with_arg(h, size, alignment, chunkfun, freefun, arg) \ + _obstack_begin_1 ((h), (size), (alignment), \ + (void *(*) ()) (chunkfun), (void (*) ()) (freefun), (arg)) + +# define obstack_chunkfun(h, newchunkfun) \ + ((h) -> chunkfun = (struct _obstack_chunk *(*)()) (newchunkfun)) + +# define obstack_freefun(h, newfreefun) \ + ((h) -> freefun = (void (*)()) (newfreefun)) + +#endif + +#define obstack_1grow_fast(h,achar) (*((h)->next_free)++ = (achar)) + +#define obstack_blank_fast(h,n) ((h)->next_free += (n)) + +#define obstack_memory_used(h) _obstack_memory_used (h) + +#if defined __GNUC__ && defined __STDC__ && __STDC__ +/* NextStep 2.0 cc is really gcc 1.93 but it defines __GNUC__ = 2 and + does not implement __extension__. But that compiler doesn't define + __GNUC_MINOR__. */ +# if __GNUC__ < 2 || (__NeXT__ && !__GNUC_MINOR__) +# define __extension__ +# endif + +/* For GNU C, if not -traditional, + we can define these macros to compute all args only once + without using a global variable. + Also, we can avoid using the `temp' slot, to make faster code. */ + +# define obstack_object_size(OBSTACK) \ + __extension__ \ + ({ struct obstack *__o = (OBSTACK); \ + (unsigned) (__o->next_free - __o->object_base); }) + +# define obstack_room(OBSTACK) \ + __extension__ \ + ({ struct obstack *__o = (OBSTACK); \ + (unsigned) (__o->chunk_limit - __o->next_free); }) + +# define obstack_make_room(OBSTACK,length) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + int __len = (length); \ + if (__o->chunk_limit - __o->next_free < __len) \ + _obstack_newchunk (__o, __len); \ + (void) 0; }) + +# define obstack_empty_p(OBSTACK) \ + __extension__ \ + ({ struct obstack *__o = (OBSTACK); \ + (__o->chunk->prev == 0 && __o->next_free - __o->chunk->contents == 0); }) + +# define obstack_grow(OBSTACK,where,length) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + int __len = (length); \ + if (__o->next_free + __len > __o->chunk_limit) \ + _obstack_newchunk (__o, __len); \ + _obstack_memcpy (__o->next_free, (where), __len); \ + __o->next_free += __len; \ + (void) 0; }) + +# define obstack_grow0(OBSTACK,where,length) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + int __len = (length); \ + if (__o->next_free + __len + 1 > __o->chunk_limit) \ + _obstack_newchunk (__o, __len + 1); \ + _obstack_memcpy (__o->next_free, (where), __len); \ + __o->next_free += __len; \ + *(__o->next_free)++ = 0; \ + (void) 0; }) + +# define obstack_1grow(OBSTACK,datum) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + if (__o->next_free + 1 > __o->chunk_limit) \ + _obstack_newchunk (__o, 1); \ + obstack_1grow_fast (__o, datum); \ + (void) 0; }) + +/* These assume that the obstack alignment is good enough for pointers or ints, + and that the data added so far to the current object + shares that much alignment. */ + +# define obstack_ptr_grow(OBSTACK,datum) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + if (__o->next_free + sizeof (void *) > __o->chunk_limit) \ + _obstack_newchunk (__o, sizeof (void *)); \ + obstack_ptr_grow_fast (__o, datum); }) + +# define obstack_int_grow(OBSTACK,datum) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + if (__o->next_free + sizeof (int) > __o->chunk_limit) \ + _obstack_newchunk (__o, sizeof (int)); \ + obstack_int_grow_fast (__o, datum); }) + +# define obstack_ptr_grow_fast(OBSTACK,aptr) \ +__extension__ \ +({ struct obstack *__o1 = (OBSTACK); \ + *(const void **) __o1->next_free = (aptr); \ + __o1->next_free += sizeof (const void *); \ + (void) 0; }) + +# define obstack_int_grow_fast(OBSTACK,aint) \ +__extension__ \ +({ struct obstack *__o1 = (OBSTACK); \ + *(int *) __o1->next_free = (aint); \ + __o1->next_free += sizeof (int); \ + (void) 0; }) + +# define obstack_blank(OBSTACK,length) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + int __len = (length); \ + if (__o->chunk_limit - __o->next_free < __len) \ + _obstack_newchunk (__o, __len); \ + obstack_blank_fast (__o, __len); \ + (void) 0; }) + +# define obstack_alloc(OBSTACK,length) \ +__extension__ \ +({ struct obstack *__h = (OBSTACK); \ + obstack_blank (__h, (length)); \ + obstack_finish (__h); }) + +# define obstack_copy(OBSTACK,where,length) \ +__extension__ \ +({ struct obstack *__h = (OBSTACK); \ + obstack_grow (__h, (where), (length)); \ + obstack_finish (__h); }) + +# define obstack_copy0(OBSTACK,where,length) \ +__extension__ \ +({ struct obstack *__h = (OBSTACK); \ + obstack_grow0 (__h, (where), (length)); \ + obstack_finish (__h); }) + +/* The local variable is named __o1 to avoid a name conflict + when obstack_blank is called. */ +# define obstack_finish(OBSTACK) \ +__extension__ \ +({ struct obstack *__o1 = (OBSTACK); \ + void *value; \ + value = (void *) __o1->object_base; \ + if (__o1->next_free == value) \ + __o1->maybe_empty_object = 1; \ + __o1->next_free \ + = __INT_TO_PTR ((__PTR_TO_INT (__o1->next_free)+__o1->alignment_mask)\ + & ~ (__o1->alignment_mask)); \ + if (__o1->next_free - (char *)__o1->chunk \ + > __o1->chunk_limit - (char *)__o1->chunk) \ + __o1->next_free = __o1->chunk_limit; \ + __o1->object_base = __o1->next_free; \ + value; }) + +# define obstack_free(OBSTACK, OBJ) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + void *__obj = (void *) (OBJ); \ + if (__obj > (void *)__o->chunk && __obj < (void *)__o->chunk_limit) \ + __o->next_free = __o->object_base = (char *) __obj; \ + else (obstack_free) (__o, __obj); }) + +#else /* not __GNUC__ or not __STDC__ */ + +# define obstack_object_size(h) \ + (unsigned) ((h)->next_free - (h)->object_base) + +# define obstack_room(h) \ + (unsigned) ((h)->chunk_limit - (h)->next_free) + +# define obstack_empty_p(h) \ + ((h)->chunk->prev == 0 && (h)->next_free - (h)->chunk->contents == 0) + +/* Note that the call to _obstack_newchunk is enclosed in (..., 0) + so that we can avoid having void expressions + in the arms of the conditional expression. + Casting the third operand to void was tried before, + but some compilers won't accept it. */ + +# define obstack_make_room(h,length) \ +( (h)->temp = (length), \ + (((h)->next_free + (h)->temp > (h)->chunk_limit) \ + ? (_obstack_newchunk ((h), (h)->temp), 0) : 0)) + +# define obstack_grow(h,where,length) \ +( (h)->temp = (length), \ + (((h)->next_free + (h)->temp > (h)->chunk_limit) \ + ? (_obstack_newchunk ((h), (h)->temp), 0) : 0), \ + _obstack_memcpy ((h)->next_free, (where), (h)->temp), \ + (h)->next_free += (h)->temp) + +# define obstack_grow0(h,where,length) \ +( (h)->temp = (length), \ + (((h)->next_free + (h)->temp + 1 > (h)->chunk_limit) \ + ? (_obstack_newchunk ((h), (h)->temp + 1), 0) : 0), \ + _obstack_memcpy ((h)->next_free, (where), (h)->temp), \ + (h)->next_free += (h)->temp, \ + *((h)->next_free)++ = 0) + +# define obstack_1grow(h,datum) \ +( (((h)->next_free + 1 > (h)->chunk_limit) \ + ? (_obstack_newchunk ((h), 1), 0) : 0), \ + obstack_1grow_fast (h, datum)) + +# define obstack_ptr_grow(h,datum) \ +( (((h)->next_free + sizeof (char *) > (h)->chunk_limit) \ + ? (_obstack_newchunk ((h), sizeof (char *)), 0) : 0), \ + obstack_ptr_grow_fast (h, datum)) + +# define obstack_int_grow(h,datum) \ +( (((h)->next_free + sizeof (int) > (h)->chunk_limit) \ + ? (_obstack_newchunk ((h), sizeof (int)), 0) : 0), \ + obstack_int_grow_fast (h, datum)) + +# define obstack_ptr_grow_fast(h,aptr) \ + (((const void **) ((h)->next_free += sizeof (void *)))[-1] = (aptr)) + +# define obstack_int_grow_fast(h,aint) \ + (((int *) ((h)->next_free += sizeof (int)))[-1] = (aptr)) + +# define obstack_blank(h,length) \ +( (h)->temp = (length), \ + (((h)->chunk_limit - (h)->next_free < (h)->temp) \ + ? (_obstack_newchunk ((h), (h)->temp), 0) : 0), \ + obstack_blank_fast (h, (h)->temp)) + +# define obstack_alloc(h,length) \ + (obstack_blank ((h), (length)), obstack_finish ((h))) + +# define obstack_copy(h,where,length) \ + (obstack_grow ((h), (where), (length)), obstack_finish ((h))) + +# define obstack_copy0(h,where,length) \ + (obstack_grow0 ((h), (where), (length)), obstack_finish ((h))) + +# define obstack_finish(h) \ +( ((h)->next_free == (h)->object_base \ + ? (((h)->maybe_empty_object = 1), 0) \ + : 0), \ + (h)->temp = __PTR_TO_INT ((h)->object_base), \ + (h)->next_free \ + = __INT_TO_PTR ((__PTR_TO_INT ((h)->next_free)+(h)->alignment_mask) \ + & ~ ((h)->alignment_mask)), \ + (((h)->next_free - (char *) (h)->chunk \ + > (h)->chunk_limit - (char *) (h)->chunk) \ + ? ((h)->next_free = (h)->chunk_limit) : 0), \ + (h)->object_base = (h)->next_free, \ + __INT_TO_PTR ((h)->temp)) + +# if defined __STDC__ && __STDC__ +# define obstack_free(h,obj) \ +( (h)->temp = (char *) (obj) - (char *) (h)->chunk, \ + (((h)->temp > 0 && (h)->temp < (h)->chunk_limit - (char *) (h)->chunk)\ + ? (int) ((h)->next_free = (h)->object_base \ + = (h)->temp + (char *) (h)->chunk) \ + : (((obstack_free) ((h), (h)->temp + (char *) (h)->chunk), 0), 0))) +# else +# define obstack_free(h,obj) \ +( (h)->temp = (char *) (obj) - (char *) (h)->chunk, \ + (((h)->temp > 0 && (h)->temp < (h)->chunk_limit - (char *) (h)->chunk)\ + ? (int) ((h)->next_free = (h)->object_base \ + = (h)->temp + (char *) (h)->chunk) \ + : (_obstack_free ((h), (h)->temp + (char *) (h)->chunk), 0))) +# endif + +#endif /* not __GNUC__ or not __STDC__ */ + +#ifdef __cplusplus +} /* C++ */ +#endif + +#endif /* obstack.h */ --- crash/memory.c.orig 2005-03-03 11:36:20.000000000 -0500 +++ crash/memory.c 2005-01-06 14:56:46.000000000 -0500 @@ -88,7 +88,9 @@ static void kmem_search(struct meminfo *); static void kmem_cache_init(void); static ulong max_cpudata_limit(ulong, ulong *); +static int ignore_cache(struct meminfo *, char *); static char *is_kmem_cache_addr(ulong, char *); +static void kmem_cache_list(void); static void dump_kmem_cache(struct meminfo *); static void dump_kmem_cache_percpu_v1(struct meminfo *); static void dump_kmem_cache_percpu_v2(struct meminfo *); @@ -104,6 +106,8 @@ static void dump_slab(struct meminfo *); static void dump_slab_percpu_v1(struct meminfo *); static void dump_slab_percpu_v2(struct meminfo *); +static int verify_slab_v1(struct meminfo *, ulong, int); +static int verify_slab_v2(struct meminfo *, ulong, int); static void gather_slab_free_list(struct meminfo *); static void gather_slab_free_list_percpu(struct meminfo *); static void gather_cpudata_list_v1(struct meminfo *); @@ -3321,7 +3325,10 @@ if (vt->flags & KMEM_CACHE_UNAVAIL) error(FATAL, "kmem cache slab subsystem not available\n"); - vt->dump_kmem_cache(&meminfo); + if (STREQ(meminfo.reqname, "list")) + kmem_cache_list(); + else + vt->dump_kmem_cache(&meminfo); } if (Sflag == 1) { @@ -3329,7 +3336,10 @@ error(FATAL, "kmem cache slab subsystem not available\n"); meminfo.flags = VERBOSE; - vt->dump_kmem_cache(&meminfo); + if (STREQ(meminfo.reqname, "list")) + kmem_cache_list(); + else + vt->dump_kmem_cache(&meminfo); } if (vflag == 1) @@ -5967,6 +5977,66 @@ } /* + * Note same functionality as above, but instead it just + * dumps all slab cache names and their addresses. + */ +static void +kmem_cache_list(void) +{ + ulong cache, cache_cache, name; + long next_offset, name_offset; + char *cache_buf; + char buf[BUFSIZE]; + + if (vt->flags & KMEM_CACHE_UNAVAIL) { + error(INFO, "kmem cache slab subsystem not available\n"); + return; + } + + name_offset = vt->flags & (PERCPU_KMALLOC_V1|PERCPU_KMALLOC_V2) ? + OFFSET(kmem_cache_s_name) : OFFSET(kmem_cache_s_c_name); + next_offset = vt->flags & (PERCPU_KMALLOC_V1|PERCPU_KMALLOC_V2) ? + OFFSET(kmem_cache_s_next) : OFFSET(kmem_cache_s_c_nextp); + + cache = cache_cache = symbol_value("cache_cache"); + + cache_buf = GETBUF(SIZE(kmem_cache_s)); + + do { + readmem(cache, KVADDR, cache_buf, SIZE(kmem_cache_s), + "kmem_cache_s buffer", FAULT_ON_ERROR); + + if (vt->kmem_cache_namelen) { + BCOPY(cache_buf+name_offset, buf, + vt->kmem_cache_namelen); + } else { + name = ULONG(cache_buf + name_offset); + if (!read_string(name, buf, BUFSIZE-1)) { + if (vt->flags & + (PERCPU_KMALLOC_V1|PERCPU_KMALLOC_V2)) + error(FATAL, + "cannot read kmem_cache_s.name string at %lx\n", + name); + else + error(FATAL, + "cannot read kmem_cache_s.c_name string at %lx\n", + name); + } + } + + fprintf(fp, "%lx %s\n", cache, buf); + + cache = ULONG(cache_buf + next_offset); + + if (vt->flags & (PERCPU_KMALLOC_V1|PERCPU_KMALLOC_V2)) + cache -= next_offset; + + } while (cache != cache_cache); + + FREEBUF(cache_buf); +} + +/* * Translate an address to its physical page number, verify that the * page in fact belongs to the slab subsystem, and if so, return the * name of the cache to which it belongs. @@ -6040,11 +6110,14 @@ readmem(page+OFFSET(page_prev), KVADDR, &slab, sizeof(void *), "page.prev", FAULT_ON_ERROR); - else if (VALID_MEMBER(page_list_prev)) readmem(page+OFFSET(page_list_prev), KVADDR, &slab, sizeof(void *), "page.list.prev", FAULT_ON_ERROR); + else if (VALID_MEMBER(page_lru)) + readmem(page+OFFSET(page_lru)+OFFSET(list_head_prev), + KVADDR, &slab, sizeof(void *), + "page.lru.prev", FAULT_ON_ERROR); else error(FATAL, "unknown definition of struct page?\n"); @@ -6231,6 +6304,41 @@ return max_limit; } +/* + * Determine whether the current slab cache is contained in + * the comma-separated list from a "kmem -I list1,list2 ..." + * command entry. + */ +static int +ignore_cache(struct meminfo *si, char *name) +{ + int i, argc; + char *p1; + char *arglist[MAXARGS]; + char buf[BUFSIZE]; + + if (!si->ignore) + return FALSE; + + strcpy(buf, si->ignore); + + p1 = buf; + while (*p1) { + if (*p1 == ',') + *p1 = ' '; + p1++; + } + + argc = parse_line(buf, arglist); + + for (i = 0; i < argc; i++) { + if (STREQ(name, arglist[i])) + return TRUE; + } + + return FALSE; +} + /* * dump_kmem_cache() displays basic information about kmalloc() slabs. @@ -6390,8 +6498,8 @@ if (reqname && !STREQ(reqname, buf)) goto next_cache; - if (STREQ(si->ignore, buf)) { - fprintf(fp, "%lx %-19s [IGNORED]\n", si->cache, buf); + if (ignore_cache(si, buf)) { + fprintf(fp, "%lx %-18s [IGNORED]\n", si->cache, buf); goto next_cache; } @@ -6588,16 +6696,13 @@ if (reqname && !STREQ(reqname, buf)) goto next_cache; - if (STREQ(si->ignore, buf)) { - fprintf(fp, "%lx %-19s [IGNORED]\n", si->cache, buf); + if (ignore_cache(si, buf)) { + fprintf(fp, "%lx %-18s [IGNORED]\n", si->cache, buf); goto next_cache; } si->curname = buf; - if (CRASHDEBUG(1)) - fprintf(fp, "cache: %lx %s\n", si->cache, si->curname); - readmem(si->cache+OFFSET(kmem_cache_s_objsize), KVADDR, &tmp_val, sizeof(uint), "objsize", FAULT_ON_ERROR); @@ -6804,16 +6909,13 @@ if (reqname && !STREQ(reqname, buf)) goto next_cache; - if (STREQ(si->ignore, buf)) { - fprintf(fp, "%lx %-19s [IGNORED]\n", si->cache, buf); + if (ignore_cache(si, buf)) { + fprintf(fp, "%lx %-18s [IGNORED]\n", si->cache, buf); goto next_cache; } si->curname = buf; - if (CRASHDEBUG(3)) - fprintf(fp, "cache: %lx %s\n", si->cache, si->curname); - readmem(si->cache+OFFSET(kmem_cache_s_objsize), KVADDR, &tmp_val, sizeof(uint), "objsize", FAULT_ON_ERROR); @@ -6883,7 +6985,7 @@ case KMEM_SLAB_ADDR: fprintf(fp, " %lx ", (ulong)si->spec_addr); - fprintf(fp, "(slab_s)\n"); + fprintf(fp, "(slab)\n"); break; case KMEM_ON_SLAB: @@ -7073,6 +7175,8 @@ #define SLAB_CHAINS (3) +static char *slab_chain_name_v1[] = {"full", "partial", "free"}; + static void do_slab_chain_percpu_v1(long cmd, struct meminfo *si) { @@ -7080,6 +7184,7 @@ int list_borked; char *slab_s_buf; ulong specified_slab; + ulong last; ulong slab_chains[SLAB_CHAINS]; list_borked = 0; @@ -7096,6 +7201,12 @@ slab_chains[2] = si->cache + OFFSET(kmem_cache_s_slabs_free); } + if (CRASHDEBUG(1)) { + fprintf(fp, "[ %s: %lx ", si->curname, si->cache); + fprintf(fp, "full: %lx partial: %lx free: %lx ]\n", + slab_chains[0], slab_chains[1], slab_chains[2]); + } + switch (cmd) { case SLAB_GET_COUNTS: @@ -7112,9 +7223,16 @@ if (!slab_chains[s]) continue; - readmem(slab_chains[s], - KVADDR, &si->slab, sizeof(ulong), - "first slab", FAULT_ON_ERROR); + if (!readmem(slab_chains[s], + KVADDR, &si->slab, sizeof(ulong), + "first slab", QUIET|RETURN_ON_ERROR)) { + error(INFO, + "%s: %s list: bad slab pointer: %lx\n", + si->curname, slab_chain_name_v1[s], + slab_chains[s]); + list_borked = 1; + continue; + } if (slab_data_saved(si)) { FREEBUF(slab_s_buf); @@ -7124,11 +7242,19 @@ if (si->slab == slab_chains[s]) continue; + last = slab_chains[s]; + do { if (received_SIGINT()) { FREEBUF(slab_s_buf); restart(0); } + + if (!verify_slab_v1(si, last, s)) { + list_borked = 1; + continue; + } + last = si->slab - OFFSET(slab_s_list); readmem(si->slab, KVADDR, slab_s_buf, SIZE(slab_s), "slab_s buffer", @@ -7159,9 +7285,7 @@ error(NOTE, "%s: slab chain inconsistency: %s list\n", si->curname, - s == 0 ? "full" : - s == 1 ? "partial" : - "free"); + slab_chain_name_v1[s]); list_borked = 1; } } @@ -7170,7 +7294,8 @@ } FREEBUF(slab_s_buf); - save_slab_data(si); + if (!list_borked) + save_slab_data(si); break; case SLAB_WALKTHROUGH: @@ -7183,14 +7308,24 @@ continue; if (!specified_slab) { - readmem(slab_chains[s], - KVADDR, &si->slab, sizeof(ulong), - "slabs", FAULT_ON_ERROR); - } + if (!readmem(slab_chains[s], + KVADDR, &si->slab, sizeof(ulong), + "slabs", QUIET|RETURN_ON_ERROR)) { + error(INFO, + "%s: %s list: bad slab pointer: %lx\n", + si->curname, + slab_chain_name_v1[s], + slab_chains[s]); + list_borked = 1; + continue; + } + last = slab_chains[s]; + } else + last = 0; if (si->slab == slab_chains[s]) continue; - + if (CRASHDEBUG(1)) { fprintf(fp, "search cache: [%s] ", si->curname); if (si->flags & ADDRESS_SPECIFIED) @@ -7201,6 +7336,12 @@ do { if (received_SIGINT()) restart(0); + + if (!verify_slab_v1(si, last, s)) { + list_borked = 1; + continue; + } + last = si->slab - OFFSET(slab_s_list); dump_slab_percpu_v1(si); @@ -7214,7 +7355,7 @@ si->slab -= OFFSET(slab_s_list); - } while (si->slab != slab_chains[s]); + } while (si->slab != slab_chains[s] && !list_borked); } break; @@ -7222,8 +7363,94 @@ } /* + * Try to preclude any attempt to translate a bogus slab structure. + */ + +static int +verify_slab_v1(struct meminfo *si, ulong last, int s) +{ + char slab_s_buf[BUFSIZE]; + struct kernel_list_head *list_head; + unsigned int inuse; + ulong s_mem; + char *list; + int errcnt; + + list = slab_chain_name_v1[s]; + + errcnt = 0; + + if (!readmem(si->slab, KVADDR, slab_s_buf, + SIZE(slab_s), "slab_s buffer", QUIET|RETURN_ON_ERROR)) { + error(INFO, "%s: %s list: bad slab pointer: %lx\n", + si->curname, list, si->slab); + return FALSE; + } + + list_head = (struct kernel_list_head *) + (slab_s_buf + OFFSET(slab_s_list)); + + if (!IS_KVADDR((ulong)list_head->next) || + !accessible((ulong)list_head->next)) { + error(INFO, "%s: %s list: slab: %lx bad next pointer: %lx\n", + si->curname, list, si->slab, + (ulong)list_head->next); + errcnt++; + } + + if (last && (last != (ulong)list_head->prev)) { + error(INFO, "%s: %s list: slab: %lx bad prev pointer: %lx\n", + si->curname, list, si->slab, + (ulong)list_head->prev); + errcnt++; + } + + inuse = UINT(slab_s_buf + OFFSET(slab_s_inuse)); + if (inuse > si->c_num) { + error(INFO, "%s: %s list: slab: %lx bad inuse counter: %ld\n", + si->curname, list, si->slab, inuse); + errcnt++; + } + switch (s) + { + case 0: /* full -- or one singular list, so we can't test this */ + break; + + case 1: /* partial */ + if ((inuse == 0) || (inuse == si->c_num)) { + error(INFO, + "%s: %s list: slab: %lx bad inuse counter: %ld\n", + si->curname, list, si->slab, inuse); + errcnt++; + } + break; + + case 2: /* free */ + if (inuse > 0) { + error(INFO, + "%s: %s list: slab: %lx bad inuse counter: %ld\n", + si->curname, list, si->slab, inuse); + errcnt++; + } + break; + } + + s_mem = ULONG(slab_s_buf + OFFSET(slab_s_s_mem)); + if (!IS_KVADDR(s_mem) || !accessible(s_mem)) { + error(INFO, "%s: %s list: slab: %lx bad s_mem pointer: %lx\n", + si->curname, list, si->slab, s_mem); + errcnt++; + } + + return(errcnt ? FALSE : TRUE); +} + +/* * Updated for 2.6 slab substructure. */ + +static char *slab_chain_name_v2[] = {"partial", "full", "free"}; + static void do_slab_chain_percpu_v2(long cmd, struct meminfo *si) { @@ -7231,6 +7458,7 @@ int list_borked; char *slab_buf; ulong specified_slab; + ulong last; ulong slab_chains[SLAB_CHAINS]; list_borked = 0; @@ -7244,6 +7472,12 @@ slab_chains[2] = si->cache + OFFSET(kmem_cache_s_lists) + OFFSET(kmem_list3_slabs_free); + if (CRASHDEBUG(1)) { + fprintf(fp, "[ %s: %lx ", si->curname, si->cache); + fprintf(fp, "partial: %lx full: %lx free: %lx ]\n", + slab_chains[0], slab_chains[1], slab_chains[2]); + } + switch (cmd) { case SLAB_GET_COUNTS: @@ -7259,9 +7493,17 @@ if (!slab_chains[s]) continue; - readmem(slab_chains[s], - KVADDR, &si->slab, sizeof(ulong), - "first slab", FAULT_ON_ERROR); + if (!readmem(slab_chains[s], + KVADDR, &si->slab, sizeof(ulong), + "first slab", QUIET|RETURN_ON_ERROR)) { + error(INFO, + "%s: %s list: bad slab pointer: %lx\n", + si->curname, + slab_chain_name_v2[s], + slab_chains[s]); + list_borked = 1; + continue; + } if (slab_data_saved(si)) { FREEBUF(slab_buf); @@ -7271,11 +7513,19 @@ if (si->slab == slab_chains[s]) continue; + last = slab_chains[s]; + do { if (received_SIGINT()) { FREEBUF(slab_buf); restart(0); } + + if (!verify_slab_v2(si, last, s)) { + list_borked = 1; + continue; + } + last = si->slab - OFFSET(slab_list); readmem(si->slab, KVADDR, slab_buf, SIZE(slab), "slab buffer", @@ -7306,9 +7556,7 @@ error(NOTE, "%s: slab chain inconsistency: %s list\n", si->curname, - s == 0 ? "full" : - s == 1 ? "partial" : - "free"); + slab_chain_name_v2[s]); list_borked = 1; } } @@ -7317,7 +7565,8 @@ } FREEBUF(slab_buf); - save_slab_data(si); + if (!list_borked) + save_slab_data(si); break; case SLAB_WALKTHROUGH: @@ -7330,11 +7579,21 @@ continue; if (!specified_slab) { - readmem(slab_chains[s], - KVADDR, &si->slab, sizeof(ulong), - "slabs", FAULT_ON_ERROR); - } - + if (!readmem(slab_chains[s], + KVADDR, &si->slab, sizeof(ulong), + "slabs", QUIET|RETURN_ON_ERROR)) { + error(INFO, + "%s: %s list: bad slab pointer: %lx\n", + si->curname, + slab_chain_name_v2[s], + slab_chains[s]); + list_borked = 1; + continue; + } + last = slab_chains[s]; + } else + last = 0; + if (si->slab == slab_chains[s]) continue; @@ -7349,6 +7608,12 @@ if (received_SIGINT()) restart(0); + if (!verify_slab_v2(si, last, s)) { + list_borked = 1; + continue; + } + last = si->slab - OFFSET(slab_list); + dump_slab_percpu_v2(si); if (si->found) { @@ -7361,13 +7626,98 @@ si->slab -= OFFSET(slab_list); - } while (si->slab != slab_chains[s]); + } while (si->slab != slab_chains[s] && !list_borked); } break; } } +/* + * Try to preclude any attempt to translate a bogus slab structure. + */ +static int +verify_slab_v2(struct meminfo *si, ulong last, int s) +{ + char slab_buf[BUFSIZE]; + struct kernel_list_head *list_head; + unsigned int inuse; + ulong s_mem; + char *list; + int errcnt; + + list = slab_chain_name_v2[s]; + + errcnt = 0; + + if (!readmem(si->slab, KVADDR, slab_buf, + SIZE(slab), "slab buffer", QUIET|RETURN_ON_ERROR)) { + error(INFO, "%s: %s list: bad slab pointer: %lx\n", + si->curname, list, si->slab); + return FALSE; + } + + list_head = (struct kernel_list_head *)(slab_buf + OFFSET(slab_list)); + if (!IS_KVADDR((ulong)list_head->next) || + !accessible((ulong)list_head->next)) { + error(INFO, "%s: %s list: slab: %lx bad next pointer: %lx\n", + si->curname, list, si->slab, + (ulong)list_head->next); + errcnt++; + } + + if (last && (last != (ulong)list_head->prev)) { + error(INFO, "%s: %s list: slab: %lx bad prev pointer: %lx\n", + si->curname, list, si->slab, + (ulong)list_head->prev); + errcnt++; + } + + inuse = UINT(slab_buf + OFFSET(slab_inuse)); + if (inuse > si->c_num) { + error(INFO, "%s: %s list: slab: %lx bad inuse counter: %ld\n", + si->curname, list, si->slab, inuse); + errcnt++; + } + switch (s) + { + case 0: /* partial */ + if ((inuse == 0) || (inuse == si->c_num)) { + error(INFO, + "%s: %s list: slab: %lx bad inuse counter: %ld\n", + si->curname, list, si->slab, inuse); + errcnt++; + } + break; + + case 1: /* full */ + if (inuse != si->c_num) { + error(INFO, + "%s: %s list: slab: %lx bad inuse counter: %ld\n", + si->curname, list, si->slab, inuse); + errcnt++; + } + break; + + case 2: /* free */ + if (inuse > 0) { + error(INFO, + "%s: %s list: slab: %lx bad inuse counter: %ld\n", + si->curname, list, si->slab, inuse); + errcnt++; + } + break; + } + + s_mem = ULONG(slab_buf + OFFSET(slab_s_mem)); + if (!IS_KVADDR(s_mem) || !accessible(s_mem)) { + error(INFO, "%s: %s list: slab: %lx bad s_mem pointer: %lx\n", + si->curname, list, si->slab, s_mem); + errcnt++; + } + + return(errcnt ? FALSE : TRUE); +} /* * If it's a dumpfile, save the essential slab data to avoid re-reading @@ -7579,7 +7929,7 @@ if (INSLAB_PERCPU(si->slab, si) && (si->spec_addr >= si->slab) && (si->spec_addr < (si->slab+tmp))) { - if (si->spec_addr >= (si->slab + SIZE(slab_s))) + if (si->spec_addr >= (si->slab + SIZE(slab))) si->found = KMEM_BUFCTL_ADDR; else si->found = KMEM_SLAB_ADDR; --- crash/filesys.c.orig 2005-03-03 11:36:20.000000000 -0500 +++ crash/filesys.c 2005-03-02 16:19:05.000000000 -0500 @@ -3457,7 +3457,7 @@ "unexpected length of radix_tree_node structure\n"); ilen = ARRAY_LENGTH(height_to_maxindex); - height_to_maxindex = (ulong *)GETBUF(ilen * sizeof(long)); + height_to_maxindex = (long *)GETBUF(ilen * sizeof(long)); readmem(symbol_value("height_to_maxindex"), KVADDR, height_to_maxindex, ilen*sizeof(long), "height_to_maxindex array", FAULT_ON_ERROR); --- crash/help.c.orig 2005-03-03 11:36:20.000000000 -0500 +++ crash/help.c 2005-01-28 15:26:13.000000000 -0500 @@ -3578,8 +3578,9 @@ " -li walks through the inactive_list and verifies nr_inactive_pages.", " -La same as -la, but also dumps each page in the active_list.", " -Li same as -li, but also dumps each page in the inactive_list.", -" slab-name when used with -s or -S, limits the command to only the slab", -" of name \"slab-cache\".", +" slab-name when used with -s or -S, limits the command to only the slab cache", +" of name \"slab-name\". If the slab-name argument is \"list\", then", +" all slab cache names and addresses are listed.", " -P declares that the following address argument is a physical address.", " address when used without any flag, the address can be a kernel virtual,", " or physical address; a search is made through the symbol table,", @@ -5257,8 +5258,8 @@ " ", " These are the current prerequisites: ", "", -" o At this point, x86, ia64, x86_64, alpha and ppc-based kernels are ", -" supported. Other architectures will be addressed in the future.", +" o At this point, x86, ia64, x86_64, alpha and ppc64-based kernels are ", +" supported. Other architectures may be addressed in the future.", "", " o One size fits all -- the utility can be run on any Linux kernel version ", " from 2.2.5-15 through 2.6.*.", --- crash/task.c.orig 2005-03-03 11:36:20.000000000 -0500 +++ crash/task.c 2005-01-28 15:26:13.000000000 -0500 @@ -2842,6 +2842,10 @@ fprintf(fp, "(HARDWARE RESET)"); else if (machdep->flags & SYSRQ) fprintf(fp, "(SYSRQ)"); + else if (machdep->flags & INIT) + fprintf(fp, "(INIT)"); + else if (kt->cpu_flags[tc->processor] & NMI) + fprintf(fp, "(NMI)"); else if (tc->task == tt->panic_task) fprintf(fp, "(PANIC)"); else --- crash/kernel.c.orig 2005-03-03 11:36:20.000000000 -0500 +++ crash/kernel.c 2005-01-28 15:26:13.000000000 -0500 @@ -3252,6 +3252,9 @@ for (i = 0; i < NR_CPUS; i++) fprintf(fp, "%s%.*lx ", (i % 4) == 0 ? "\n " : "", LONG_PRLEN, kt->__per_cpu_offset[i]); + fprintf(fp, "\n cpu_flags[NR_CPUS]:"); + for (i = 0; i < NR_CPUS; i++) + fprintf(fp, "%lx ", kt->cpu_flags[i]); fprintf(fp, "\n"); } --- crash/gdb_interface.c.orig 2005-03-03 11:36:20.000000000 -0500 +++ crash/gdb_interface.c 2005-03-02 16:19:05.000000000 -0500 @@ -755,7 +755,8 @@ { case SIZEOF_8BIT: p1 = (char *)buf; - if ((memtype == KVADDR) && text_value_cache_byte(addr, p1)) + if ((memtype == KVADDR) && + text_value_cache_byte(addr, (unsigned char *)p1)) return TRUE; if (readmem(addr, memtype, locbuf, SIZEOF_32BIT, @@ -788,7 +789,7 @@ /* * Used by gdb_interface() to catch gdb-related errors, if desired. */ -volatile void +void gdb_error_hook(void) { char buf1[BUFSIZE]; --- crash/alpha.c.orig 2005-03-03 11:36:20.000000000 -0500 +++ crash/alpha.c 2005-03-02 14:24:46.000000000 -0500 @@ -2602,6 +2602,8 @@ int alpha_get_smp_cpus(void) { + int cpus; + if ((cpus = get_cpus_online())) return cpus; else --- crash/x86.c.orig 2005-03-03 11:36:20.000000000 -0500 +++ crash/x86.c 2005-03-02 16:19:05.000000000 -0500 @@ -487,7 +487,8 @@ else GET_STACK_DATA(addr, data, size); } else { - if ((size == sizeof(int)) && text_value_cache(addr, 0, &value)) + if ((size == sizeof(int)) && + text_value_cache(addr, 0, (uint32_t *)&value)) return value; if (!readmem(addr, KVADDR, data, size, "db_get_value", @@ -2939,6 +2940,25 @@ value_to_symstr(value, buf2, pc->output_radix)); sprintf(p1, buf1); + } else if (STREQ(argv[argc-2], "call") && + hexadecimal(argv[argc-1], 0)) { + /* + * Update module code of the form: + * + * call 0xe081e1e0 + * + * to show a bracketed direct call target. + */ + p1 = &LASTCHAR(inbuf); + + if (extract_hex(argv[argc-1], &value, NULLCHAR, TRUE)) { + sprintf(buf1, " <%s>\n", + value_to_symstr(value, buf2, + pc->output_radix)); + if (IS_MODULE_VADDR(value) && + !strstr(buf2, "+")) + sprintf(p1, buf1); + } } if (CRASHDEBUG(1)) --- crash/ia64.c.orig 2005-03-03 11:36:20.000000000 -0500 +++ crash/ia64.c 2005-02-14 08:57:07.000000000 -0500 @@ -56,6 +56,7 @@ static struct line_number_hook ia64_line_number_hooks[]; static ulong ia64_get_stackbase(ulong); static ulong ia64_get_stacktop(ulong); +static void parse_cmdline_arg(void); struct unw_frame_info; static void dump_unw_frame_info(struct unw_frame_info *); @@ -112,12 +113,11 @@ machdep->last_ptbl_read = 0; machdep->verify_paddr = ia64_verify_paddr; machdep->ptrs_per_pgd = PTRS_PER_PGD; - if (machdep->cmdline_arg) - machdep->machspec->phys_start = - htol(machdep->cmdline_arg, RETURN_ON_ERROR, NULL); - else - machdep->machspec->phys_start = UNKNOWN_PHYS_START; - machdep->flags |= DEVMEMRD; + machdep->machspec->phys_start = UNKNOWN_PHYS_START; + if (machdep->cmdline_arg) + parse_cmdline_arg(); + if (ACTIVE()) + machdep->flags |= DEVMEMRD; break; case PRE_GDB: @@ -218,6 +218,108 @@ } } +/* + * --machdep defaults to the physical start location. + * + * Otherwise, it's got to be a "item=value" string, separated + * by commas if more than one is passed in. + */ + +void +parse_cmdline_arg(void) +{ + int i, c, errflag; + char *p; + char buf[BUFSIZE]; + char *arglist[MAXARGS]; + ulong value; + struct machine_specific *ms; + + ms = &ia64_machine_specific; + + if (!strstr(machdep->cmdline_arg, "=")) { + errflag = 0; + value = htol(machdep->cmdline_arg, + RETURN_ON_ERROR|QUIET, &errflag); + if (!errflag) { + ms->phys_start = value; + error(NOTE, "setting phys_start to: 0x%lx\n", + ms->phys_start); + } else + error(WARNING, "ignoring --machdep option: %s\n\n", + machdep->cmdline_arg); + return; + } + + strcpy(buf, machdep->cmdline_arg); + + for (p = buf; *p; p++) { + if (*p == ',') + *p = ' '; + } + + c = parse_line(buf, arglist); + + for (i = 0; i < c; i++) { + errflag = 0; + + if (STRNEQ(arglist[i], "phys_start=")) { + p = arglist[i] + strlen("phys_start="); + if (strlen(p)) { + value = htol(p, RETURN_ON_ERROR|QUIET, + &errflag); + if (!errflag) { + ms->phys_start = value; + error(NOTE, + "setting phys_start to: 0x%lx\n", + ms->phys_start); + continue; + } + } + } else if (STRNEQ(arglist[i], "init_stack_size=")) { + p = arglist[i] + strlen("init_stack_size="); + if (strlen(p)) { + value = stol(p, RETURN_ON_ERROR|QUIET, + &errflag); + if (!errflag) { + ms->ia64_init_stack_size = (int)value; + error(NOTE, + "setting init_stack_size to: 0x%x (%d)\n", + ms->ia64_init_stack_size, + ms->ia64_init_stack_size); + continue; + } + } + } + + error(WARNING, "ignoring --machdep option: %s\n", arglist[i]); + } + + if (c) + fprintf(fp, "\n"); +} + + +int +ia64_in_init_stack(ulong addr) +{ + ulong init_stack_addr; + + if (!symbol_exists("ia64_init_stack")) + return FALSE; + + /* + * ia64_init_stack could be aliased to region 5 + */ + init_stack_addr = ia64_VTOP(symbol_value("ia64_init_stack")); + addr = ia64_VTOP(addr); + if ((addr < init_stack_addr) || + (addr >= (init_stack_addr+machdep->machspec->ia64_init_stack_size))) + return FALSE; + + return TRUE; +} + void ia64_dump_machdep_table(ulong arg) { @@ -309,6 +411,8 @@ fprintf(fp, "%sSYSRQ", others++ ? "|" : ""); if (machdep->flags & DEVMEMRD) fprintf(fp, "%sDEVMEMRD", others++ ? "|" : ""); + if (machdep->flags & INIT) + fprintf(fp, "%sINIT", others++ ? "|" : ""); fprintf(fp, ")\n"); fprintf(fp, " kvbase: %lx\n", machdep->kvbase); fprintf(fp, " identity_map_base: %lx\n", machdep->identity_map_base); @@ -446,6 +550,9 @@ else fprintf(fp, "%lx\n", (ulong)ms->unwind_debug); + fprintf(fp, " ia64_init_stack_size: %d\n", + ms->ia64_init_stack_size); + if (verbose) ia64_display_memmap(); } @@ -1077,9 +1184,9 @@ { char buf1[BUFSIZE]; char buf2[BUFSIZE]; - char *colon, *p1; + char *colon, *p1, *p2; int argc; - int revise, stop_bit; + int revise_bracket, stop_bit; char *argv[MAXARGS]; ulong value; @@ -1105,25 +1212,24 @@ strcpy(buf1, inbuf); argc = parse_line(buf1, argv); - revise = stop_bit = 0; + revise_bracket = stop_bit = 0; if ((FIRSTCHAR(argv[argc-1]) == '<') && (LASTCHAR(argv[argc-1]) == '>')) { - revise = TRUE; + revise_bracket = TRUE; stop_bit = FALSE; } else if ((FIRSTCHAR(argv[argc-1]) == '<') && strstr(argv[argc-1], ">;;")) { - revise = TRUE; + revise_bracket = TRUE; stop_bit = TRUE; } - if (revise) { + if (revise_bracket) { p1 = rindex(inbuf, '<'); - while ((p1 > inbuf) && !STRNEQ(p1, " 0x")) + while ((p1 > inbuf) && !STRNEQ(p1, "0x")) p1--; - if (!STRNEQ(p1, " 0x")) + if (!STRNEQ(p1, "0x")) return FALSE; - p1++; if (!extract_hex(p1, &value, NULLCHAR, TRUE)) return FALSE; @@ -1133,10 +1239,46 @@ stop_bit ? ";;" : ""); sprintf(p1, "%s", buf1); - } - console(" %s", inbuf); + } else if (STRNEQ(argv[argc-2], "br.call.") && + STRNEQ(argv[argc-1], "b0=0x")) { + /* + * Update module function calls of these formats: + * + * br.call.sptk.many b0=0xa0000000003d5e40;; + * br.call.sptk.many b0=0xa00000000001dfc0 + * + * to show a bracketed function name if the destination + * address is a known symbol with no offset. + */ + if ((p1 = strstr(argv[argc-1], ";;")) && + (p2 = strstr(inbuf, ";;\n"))) { + *p1 = NULLCHAR; + p1 = &argv[argc-1][3]; + + if (extract_hex(p1, &value, NULLCHAR, TRUE)) { + sprintf(buf1, " <%s>;;\n", + value_to_symstr(value, buf2, + pc->output_radix)); + if (IS_MODULE_VADDR(value) && + !strstr(buf2, "+")) + sprintf(p2, buf1); + } + } else { + p1 = &argv[argc-1][3]; + p2 = &LASTCHAR(inbuf); + if (extract_hex(p1, &value, '\n', TRUE)) { + sprintf(buf1, " <%s>\n", + value_to_symstr(value, buf2, + pc->output_radix)); + if (IS_MODULE_VADDR(value) && + !strstr(buf2, "+")) + sprintf(p2, buf1); + } + } + } + console(" %s", inbuf); return TRUE; } @@ -2540,6 +2682,13 @@ "unimpl_pa_mask", FAULT_ON_ERROR); } } + + if (symbol_exists("ia64_init_stack") && !ms->ia64_init_stack_size) + ms->ia64_init_stack_size = get_array_length("ia64_init_stack", + NULL, 0); + + if (DUMPFILE() && ia64_in_init_stack(SWITCH_STACK_ADDR(CURRENT_TASK()))) + machdep->flags |= INIT; } /* --- crash/x86_64.c.orig 2005-03-03 11:36:20.000000000 -0500 +++ crash/x86_64.c 2005-02-14 16:59:44.000000000 -0500 @@ -64,6 +64,7 @@ static void x86_64_init_kernel_pgd(void); static void x86_64_cpu_pda_init(void); static void x86_64_ist_init(void); +static void x86_64_post_init(void); struct machine_specific x86_64_machine_specific = { 0 }; @@ -172,6 +173,7 @@ break; case POST_INIT: + x86_64_post_init(); break; } } @@ -482,6 +484,55 @@ } } +static void +x86_64_post_init(void) +{ + int c, i, clues; + struct machine_specific *ms; + ulong *up; + struct syment *spt, *spc; + ulong offset; + + /* + * Check whether each cpu was stopped by an NMI. + */ + ms = machdep->machspec; + + for (c = 0; c < kt->cpus; c++) { + if (ms->stkinfo.ebase[c][NMI_STACK] == 0) + break; + + if (!readmem(ms->stkinfo.ebase[c][NMI_STACK], + KVADDR, ms->irqstack, + ms->stkinfo.esize, + "NMI exception stack contents", + RETURN_ON_ERROR|QUIET)) + continue; + + for (i = clues = 0; i < (ms->stkinfo.esize)/sizeof(ulong); i++){ + up = (ulong *)(&ms->irqstack[i*sizeof(ulong)]); + + if (!is_kernel_text(*up) || + !(spt = value_search(*up, &offset))) + continue; + + if (STREQ(spt->name, "try_crashdump") || + STREQ(spt->name, "die_nmi")) + clues++; + + if ((STREQ(spt->name, "nmi_watchdog_tick") || + STREQ(spt->name, "default_do_nmi"))) { + spc = x86_64_function_called_by((*up)-5); + if (spc && STREQ(spc->name, "die_nmi")) + clues += 2; + } + } + + if (clues >= 2) + kt->cpu_flags[c] |= NMI; + } +} + /* * No x86_64 swapper_pg_dir; initialize the vt->kernel_pgd[NR_CPUS] array * with the lazily-sync'd init_level4_pgt page address. The level4 page @@ -1128,7 +1179,8 @@ return BACKTRACE_ENTRY_DISPLAYED; } - if (!offset && !(bt->flags & BT_EXCEPTION_FRAME)) { + if (!offset && !(bt->flags & BT_EXCEPTION_FRAME) && + !(bt->flags & BT_START)) { if (STREQ(name, "child_rip")) { if (symbol_exists("kernel_thread")) name = "kernel_thread"; @@ -1164,6 +1216,8 @@ if (bt->flags & BT_EXCEPTION_FRAME) rsp = bt->stkptr; + else if (bt->flags & BT_START) + rsp = bt->stkptr; else rsp = bt->stackbase + (stkindex * sizeof(long)); @@ -1320,6 +1374,10 @@ irq_eframe = 0; bt->call_target = NULL; rsp = bt->stkptr; + if (!rsp) { + error(INFO, "cannot determine starting stack pointer\n"); + return; + } ms = machdep->machspec; if (BT_REFERENCE_CHECK(bt)) ofp = pc->nullfp; @@ -1333,7 +1391,12 @@ STREQ(closest_symbol(bt->instptr), "thread_return") ? " (schedule)" : "", bt->instptr); - } + } else if (bt->flags & BT_START) { + x86_64_print_stack_entry(bt, ofp, level, + 0, bt->instptr); + bt->flags &= ~BT_START; + level++; + } if ((estack = x86_64_in_exception_stack(bt))) { @@ -1403,7 +1466,8 @@ bt->stackbuf + (bt->stacktop - bt->stackbase) - SIZE(pt_regs), bt, ofp); - fprintf(fp, "--- ---\n"); + if (!BT_REFERENCE_CHECK(bt)) + fprintf(fp, "--- ---\n"); /* * stack = (unsigned long *) estack_end[-2]; @@ -1411,13 +1475,24 @@ up = (ulong *)(&bt->stackbuf[bt->stacktop - bt->stackbase]); up -= 2; rsp = bt->stkptr = *up; - up -= 5; + up -= 3; bt->instptr = *up; if (cs & 3) done = TRUE; /* user-mode exception */ else done = FALSE; /* kernel-mode exception */ bt->frameptr = 0; + + /* + * Print the return values from the estack end. + */ + if (!done) { + bt->flags |= BT_START; + x86_64_print_stack_entry(bt, ofp, level, + 0, bt->instptr); + bt->flags &= ~BT_START; + level++; + } } /* @@ -1466,7 +1541,8 @@ } } - fprintf(fp, "--- ---\n"); + if (!BT_REFERENCE_CHECK(bt)) + fprintf(fp, "--- ---\n"); /* * stack = (unsigned long *) (irqstack_end[-1]); @@ -1950,6 +2026,7 @@ int panic_task; int i, panic, stage; char *sym; + struct syment *sp; ulong *up; struct bt_info bt_local, *bt; struct machine_specific *ms; @@ -1999,12 +2076,27 @@ if (STREQ(sym, "netconsole_netdump") || STREQ(sym, "netpoll_start_netdump") || STREQ(sym, "start_disk_dump") || - STREQ(sym, "disk_dump")) { + STREQ(sym, "disk_dump") || + STREQ(sym, "try_crashdump")) { *rip = *up; *rsp = bt->stackbase + ((char *)(up) - bt->stackbuf); return; } + if ((stage == 2) && + (STREQ(sym, "nmi_watchdog_tick") || + STREQ(sym, "default_do_nmi"))) { + sp = x86_64_function_called_by((*up)-5); + if (!sp || !STREQ(sp->name, "die_nmi")) + continue; + *rip = *up; + *rsp = bt->stackbase + ((char *)(up) - bt->stackbuf); + bt_in->flags |= BT_START; + *rip = symbol_value("die_nmi"); + *rsp = (*rsp) - (7*sizeof(ulong)); + return; + } + if (STREQ(sym, "panic")) { *rip = *up; *rsp = bt->stackbase + ((char *)(up) - bt->stackbuf); @@ -2062,7 +2154,19 @@ stage = 1; goto next_stack; + /* + * Check the NMI exception stack. + */ case 1: + bt->stackbase = ms->stkinfo.ebase[bt->tc->processor][NMI_STACK]; + bt->stacktop = ms->stkinfo.ebase[bt->tc->processor][NMI_STACK] + + ms->stkinfo.esize; + bt->stackbuf = ms->irqstack; + alter_stackbuf(bt); + stage = 2; + goto next_stack; + + case 2: break; } @@ -2277,7 +2381,27 @@ value_to_symstr(value, buf2, pc->output_radix)); sprintf(p1, buf1); - } + + } else if (STREQ(argv[argc-2], "callq") && + hexadecimal(argv[argc-1], 0)) { + /* + * Update module code of the form: + * + * callq 0xffffffffa0017aa0 + * + * to show a bracketed direct call target. + */ + p1 = &LASTCHAR(inbuf); + + if (extract_hex(argv[argc-1], &value, NULLCHAR, TRUE)) { + sprintf(buf1, " <%s>\n", + value_to_symstr(value, buf2, + pc->output_radix)); + if (IS_MODULE_VADDR(value) && + !strstr(buf2, "+")) + sprintf(p1, buf1); + } + } console(" %s", inbuf); --- crash/remote.c.orig 2005-03-03 11:36:20.000000000 -0500 +++ crash/remote.c 2005-03-02 16:19:05.000000000 -0500 @@ -2134,7 +2134,7 @@ optlen = sizeof(rcvbuf); if (getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (char *)&rcvbuf, - &optlen) < 0) { + (socklen_t *)&optlen) < 0) { error(INFO, "SO_RCVBUF getsockopt error\n"); return; } @@ -2159,7 +2159,7 @@ optlen = sizeof(rcvbuf); if (getsockopt(sockfd, SOL_SOCKET, SO_RCVLOWAT, (char *)&rcvbuf, - &optlen) < 0) { + (socklen_t *)&optlen) < 0) { error(INFO, "SO_RCVLOWAT getsockopt error\n"); return; } --- crash/symbols.c.orig 2005-03-03 11:36:20.000000000 -0500 +++ crash/symbols.c 2005-03-02 16:19:05.000000000 -0500 @@ -411,7 +411,8 @@ #if defined(GDB_5_3) file_crc = calc_crc32(file_crc, buffer, count); #elif defined(GDB_6_0) || defined(GDB_6_1) - file_crc = gnu_debuglink_crc32(file_crc, buffer, count); + file_crc = gnu_debuglink_crc32(file_crc, + (unsigned char *)buffer, count); #else file_crc = 0xdeadbeef; /* can't get here */ #endif --- crash/lkcd_common.c.orig 2005-03-03 11:36:20.000000000 -0500 +++ crash/lkcd_common.c 2005-03-02 16:19:05.000000000 -0500 @@ -1085,7 +1085,8 @@ case LKCD_DUMP_COMPRESS_GZIP: if (!lkcd_uncompress_gzip((unsigned char *) lkcd->page_cache_hdr[i].pg_bufptr, lkcd->page_size, - lkcd->compressed_page, lkcd->get_dp_size())) { + (unsigned char *)lkcd->compressed_page, + lkcd->get_dp_size())) { lkcd_print("uncompress of page "); lkcd_print(BITS32() ? "%llx failed!\n" : "%lx failed!\n", --- crash/lkcd_x86_trace.c.orig 2005-03-03 11:36:20.000000000 -0500 +++ crash/lkcd_x86_trace.c 2005-03-02 16:19:05.000000000 -0500 @@ -4803,7 +4803,7 @@ instrbuf.addr = pc; instrbuf.size = 256; #ifdef REDHAT - fill_instr_cache(pc, instrbuf.buf); + fill_instr_cache(pc, (char *)instrbuf.buf); #else GET_BLOCK(pc, 256, instrbuf.buf); #endif --- crash/netdump.c.orig 2005-03-03 11:36:20.000000000 -0500 +++ crash/netdump.c 2005-02-17 10:48:56.000000000 -0500 @@ -111,7 +111,7 @@ default: goto bailout; } - nd->flags |= NETDUMP_ELF32; + nd->flags |= NETDUMP_ELF32; load32 = (Elf32_Phdr *) &header[sizeof(Elf32_Ehdr)+sizeof(Elf32_Phdr)]; size = (size_t)load32->p_offset; @@ -127,14 +127,23 @@ if ((elf64->e_ident[EI_DATA] == ELFDATA2LSB) && STREQ(MACHINE_TYPE, "IA64")) break; + else + goto bailout; + case EM_PPC64: if ((elf64->e_ident[EI_DATA] == ELFDATA2MSB) && STREQ(MACHINE_TYPE, "PPC64")) break; + else + goto bailout; + case EM_X86_64: if ((elf64->e_ident[EI_DATA] == ELFDATA2LSB) && STREQ(MACHINE_TYPE, "X86_64")) break; + else + goto bailout; + default: goto bailout; } @@ -226,7 +235,7 @@ offset = (off_t)paddr + (off_t)nd->header_size; - if (lseek(nd->ndfd, offset, SEEK_SET) != offset) + if (lseek(nd->ndfd, offset, SEEK_SET) == -1) return SEEK_ERROR; if (read(nd->ndfd, bufptr, cnt) != cnt) --- crash/unwind.c.orig 2005-03-03 11:36:20.000000000 -0500 +++ crash/unwind.c 2005-02-07 16:02:44.000000000 -0500 @@ -31,6 +31,10 @@ * unwind_v[123].o object files. */ +/* + * 2004-09-14 J. Nomura Added OS_INIT handling + */ + /* #include can't include this -- it's changing over time! */ #include "defs.h" @@ -56,6 +60,13 @@ static void dump_unwind_table(struct unw_table *); static int unw_init_from_blocked_task(struct unw_frame_info *, struct bt_info *); +static void unw_init_from_interruption(struct unw_frame_info *, + struct bt_info *, ulong, ulong); +static int unw_switch_from_osinit_v1(struct unw_frame_info *, + struct bt_info *); +static int unw_switch_from_osinit_v2(struct unw_frame_info *, + struct bt_info *); +static unsigned long get_init_stack_ulong(unsigned long addr); static void unw_init_frame_info(struct unw_frame_info *, struct bt_info *, ulong); static int find_save_locs(struct unw_frame_info *); @@ -406,8 +417,8 @@ else *nat_addr &= ~nat_mask; } else { - if ((GET_STACK_ULONG(nat_addr) & nat_mask) == 0) { - *val = GET_STACK_ULONG(addr); + if ((IA64_GET_STACK_ULONG(nat_addr) & nat_mask) == 0) { + *val = IA64_GET_STACK_ULONG(addr); *nat = 0; } else { *val = 0; /* if register is a NaT, *addr may contain kernel data! */ @@ -457,7 +468,7 @@ if (write) *addr = *val; else - *val = GET_STACK_ULONG(addr); + *val = IA64_GET_STACK_ULONG(addr); return 0; } @@ -695,7 +706,7 @@ *info->cfm_loc = (*info->cfm_loc & ~(0x3fUL << 52)) | ((*val & 0x3f) << 52); else - *val = (GET_STACK_ULONG(info->cfm_loc) >> 52) & 0x3f; + *val = (IA64_GET_STACK_ULONG(info->cfm_loc) >> 52) & 0x3f; return 0; case UNW_AR_FPSR: @@ -739,7 +750,7 @@ if (write) *addr = *val; else - *val = GET_STACK_ULONG(addr); + *val = IA64_GET_STACK_ULONG(addr); return 0; } @@ -764,7 +775,7 @@ if (write) *addr = *val; else - *val = GET_STACK_ULONG(addr); + *val = IA64_GET_STACK_ULONG(addr); return 0; } @@ -1644,6 +1655,7 @@ frame = 0; do { +restart: unw_get_ip(info, &ip); unw_get_sp(info, &sp); unw_get_bsp(info, &bsp); @@ -1695,6 +1707,26 @@ STREQ(name, "start_kernel_thread")) break; + /* + * "init_handler_platform" indicates that this task was + * interrupted by INIT and its stack was switched. + */ + if (STREQ(name, "init_handler_platform")) { + unw_switch_from_osinit_v1(info, bt); + frame++; + goto restart; + } + + /* + * In some cases, init_handler_platform is inlined into + * ia64_init_handler. + */ + if (STREQ(name, "ia64_init_handler")) { + unw_switch_from_osinit_v2(info, bt); + frame++; + goto restart; + } + frame++; } while (unw_unwind(info) >= 0); @@ -1797,6 +1829,16 @@ dump_struct("unw_table", (ulong)table, RADIX(16)); } +static unsigned long +get_init_stack_ulong(unsigned long addr) +{ + unsigned long tmp; + + readmem(addr, KVADDR, &tmp, sizeof(unsigned long), + "get_init_stack_ulong", FAULT_ON_ERROR); + + return tmp; +} static int unw_init_from_blocked_task(struct unw_frame_info *info, struct bt_info *bt) @@ -1804,13 +1846,129 @@ ulong sw; sw = SWITCH_STACK_ADDR(bt->task); - if (!INSTACK(sw, bt)) + if (!INSTACK(sw, bt) && !ia64_in_init_stack(sw)) return FALSE; unw_init_frame_info(info, bt, sw); return TRUE; } +/* + * unw_init_from_interruption + * Initialize frame info from specified pt_regs/switch_stack. + * + * Similar to unw_init_frame_info() except that: + * - do not use readmem to access stack + * (because stack may be modified by unw_init_from_saved_regs) + * - use ar.ifs and ar.iip instead of ar.pfs and b0, respectively + * - use sof(size-of-frame) of ar.ifs to caluculate bsp, + * instead of sol(size-of-local) of ar.pfs + * (because of cover instruction in kernel minstate save macro) + */ +static void +unw_init_from_interruption(struct unw_frame_info *info, struct bt_info *bt, ulong pt, ulong sw) +{ +// unsigned long rbslimit, rbstop, stklimit, stktop, sof, ar_pfs; + unsigned long rbslimit, rbstop, stklimit, stktop, sof; + ulong t; + + t = bt->task; + + memset(info, 0, sizeof(*info)); + + rbslimit = (unsigned long) t + IA64_RBS_OFFSET; + rbstop = IA64_GET_STACK_ULONG(sw + OFFSET(switch_stack_ar_bspstore)); + if (rbstop - (unsigned long) t >= IA64_STK_OFFSET) + rbstop = rbslimit; + + stklimit = (unsigned long) t + IA64_STK_OFFSET; + stktop = IA64_GET_STACK_ULONG(pt + offsetof(struct pt_regs, r12)); + if (stktop <= rbstop) + stktop = rbstop; + + info->regstk.limit = rbslimit; + info->regstk.top = rbstop; + info->memstk.limit = stklimit; + info->memstk.top = stktop; + info->task = (struct task_struct *)bt; + info->sw = (struct switch_stack *)sw; + info->sp = info->psp = stktop; + info->pr = IA64_GET_STACK_ULONG(sw + OFFSET(switch_stack_pr)); + + info->cfm_loc = (unsigned long *) (pt + offsetof(struct pt_regs, cr_ifs)); + info->unat_loc = (unsigned long *) (pt + offsetof(struct pt_regs, ar_unat)); + info->pfs_loc = (unsigned long *) (pt + offsetof(struct pt_regs, ar_pfs)); + /* register stack is covered */ + sof = IA64_GET_STACK_ULONG(info->cfm_loc) & 0x7f; + info->bsp = (unsigned long) + ia64_rse_skip_regs((unsigned long *) info->regstk.top, -sof); + /* interrupted ip is saved in iip */ + info->ip = IA64_GET_STACK_ULONG(pt + offsetof(struct pt_regs, cr_iip)); +#if defined(UNWIND_V2) || defined(UNWIND_V3) + info->pt = pt; +#endif + + find_save_locs(info); +} + +/* + * unw_switch_from_osinit + * switch back to interrupted context + * + * assumption: init_handler_platform() has 3 arguments, + * 2nd arg is pt_regs and 3rd arg is switch_stack. + */ +static int +unw_switch_from_osinit_v1(struct unw_frame_info *info, struct bt_info *bt) +{ + unsigned long pt, sw; + char is_nat; + + /* pt_regs is the 2nd argument of init_handler_platform */ + if (unw_get_gr(info, 33, &pt, &is_nat)) { + fprintf(fp, "gr 33 get error\n"); + return FALSE; + } + /* switch_stack is the 3rd argument of init_handler_platform */ + if (unw_get_gr(info, 34, &sw, &is_nat)) { + fprintf(fp, "gr 33 get error\n"); + return FALSE; + } + + unw_init_from_interruption(info, bt, pt, sw); + ia64_exception_frame(pt, bt); + + return TRUE; +} + +static int +unw_switch_from_osinit_v2(struct unw_frame_info *info, struct bt_info *bt) +{ + unsigned long pt, sw; + char is_nat; + + /* pt_regs is the 1st argument of ia64_init_handler */ + if (unw_get_gr(info, 32, &pt, &is_nat)) { + fprintf(fp, "gr 32 get error\n"); + + return FALSE; + } + /* switch_stack is the 2nd argument of ia64_init_handler */ + if (unw_get_gr(info, 33, &sw, &is_nat)) { + fprintf(fp, "gr 33 get error\n"); + return FALSE; + } + + /* Fix me! */ + sw = info->psp + 16; + pt = sw + STRUCT_SIZE("switch_stack"); + + unw_init_from_interruption(info, bt, pt, sw); + ia64_exception_frame(pt, bt); + + return TRUE; +} + static void unw_init_frame_info (struct unw_frame_info *info, struct bt_info *bt, ulong sw) { @@ -1851,12 +2009,12 @@ info->sw = (struct switch_stack *)sw; info->sp = info->psp = (unsigned long) (sw + SIZE(switch_stack)) - 16; info->cfm_loc = (ulong *)(sw + OFFSET(switch_stack_ar_pfs)); - ar_pfs = GET_STACK_ULONG(info->cfm_loc); + ar_pfs = IA64_GET_STACK_ULONG(info->cfm_loc); sol = (ar_pfs >> 7) & 0x7f; info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->regstk.top, -sol); - info->ip = GET_STACK_ULONG(sw + OFFSET(switch_stack_b0)); - info->pr = GET_STACK_ULONG(sw + OFFSET(switch_stack_pr)); + info->ip = IA64_GET_STACK_ULONG(sw + OFFSET(switch_stack_b0)); + info->pr = IA64_GET_STACK_ULONG(sw + OFFSET(switch_stack_pr)); find_save_locs(info); } @@ -1973,7 +2131,7 @@ info->ip); return -1; } - ip = info->ip = GET_STACK_ULONG(info->rp_loc); + ip = info->ip = IA64_GET_STACK_ULONG(info->rp_loc); if (ip < GATE_ADDR + PAGE_SIZE) { /* * We don't have unwind info for the gate page, @@ -1997,26 +2155,26 @@ if ((info->flags & UNW_FLAG_INTERRUPT_FRAME)) { #ifdef UNWIND_V1 if ((pr & (1UL << pNonSys)) != 0) - num_regs = GET_STACK_ULONG(info->cfm_loc) & 0x7f; /* size of frame */ + num_regs = IA64_GET_STACK_ULONG(info->cfm_loc) & 0x7f; /* size of frame */ info->pfs_loc = (unsigned long *) (info->sp + 16 + struct_offset(struct pt_regs, ar_pfs)); #endif #ifdef UNWIND_V2 info->pt = info->sp + 16; if ((pr & (1UL << pNonSys)) != 0) - num_regs = GET_STACK_ULONG(info->cfm_loc) & 0x7f; /* size of frame */ + num_regs = IA64_GET_STACK_ULONG(info->cfm_loc) & 0x7f; /* size of frame */ info->pfs_loc = (unsigned long *) (info->pt + offsetof(struct pt_regs, ar_pfs)); #endif #ifdef UNWIND_V3 info->pt = info->sp + 16; if ((pr & (1UL << pNonSys)) != 0) - num_regs = GET_STACK_ULONG(info->cfm_loc) & 0x7f; /* size of frame */ + num_regs = IA64_GET_STACK_ULONG(info->cfm_loc) & 0x7f; /* size of frame */ info->pfs_loc = (unsigned long *) (info->pt + offsetof(struct pt_regs, ar_pfs)); #endif } else - num_regs = (GET_STACK_ULONG(info->cfm_loc) >> 7) & 0x7f; /* size of locals */ + num_regs = (IA64_GET_STACK_ULONG(info->cfm_loc) >> 7) & 0x7f; /* size of locals */ info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->bsp, -num_regs); if (info->bsp < info->regstk.limit || info->bsp > info->regstk.top) { error(INFO, "unwind: bsp (0x%lx) out of range [0x%lx-0x%lx]\n", @@ -2026,7 +2184,8 @@ /* restore the sp: */ info->sp = info->psp; - if (info->sp < info->memstk.top || info->sp > info->memstk.limit) { + if ((info->sp < info->memstk.top || info->sp > info->memstk.limit) + && !ia64_in_init_stack(info->sp)) { error(INFO, "unwind: sp (0x%lx) out of range [0x%lx-0x%lx]\n", info->sp, info->memstk.top, info->memstk.limit); return -1; @@ -2135,7 +2294,7 @@ break; } #endif - s[dst] = GET_STACK_ULONG(s[val]); + s[dst] = IA64_GET_STACK_ULONG(s[val]); break; } } --- crash/defs.h.orig 2005-03-03 11:36:20.000000000 -0500 +++ crash/defs.h 2005-03-02 16:19:05.000000000 -0500 @@ -62,7 +62,7 @@ #include #include -#define BASELEVEL_REVISION "3.8" +#define BASELEVEL_REVISION "3.10" #undef TRUE #undef FALSE @@ -103,8 +103,9 @@ #define HIST_BLKSIZE (4096) -#define STREQ(A, B) (A && B && (strcmp(A, B) == 0)) -#define STRNEQ(A, B) (A && B && (strncmp(A, B, strlen(B)) == 0)) +#define STREQ(A, B) (A && B && (strcmp((char *)(A), (char *)(B)) == 0)) +#define STRNEQ(A, B) (A && B && \ + (strncmp((char *)(A), (char *)(B), strlen((char *)(B))) == 0)) #define BZERO(S, N) (memset(S, NULLCHAR, N)) #define BCOPY(S, D, C) (memcpy(D, S, C)) #define BNEG(S, N) (memset(S, 0xff, N)) @@ -446,6 +447,8 @@ long __rq_idx[NR_CPUS]; long __cpu_idx[NR_CPUS]; long __per_cpu_offset[NR_CPUS]; + long cpu_flags[NR_CPUS]; +#define NMI 0x1 }; /* @@ -674,6 +677,7 @@ #define FRAMESIZE_DEBUG (0x10000000) #define MACHDEP_BT_TEXT (0x8000000) #define DEVMEMRD (0x4000000) +#define INIT (0x2000000) #define SYSRQ_TASK(X) ((machdep->flags & SYSRQ) && is_task_active(X)) extern struct machdep_table *machdep; @@ -2030,6 +2034,9 @@ #define UNKNOWN_PHYS_START ((ulong)(-1)) #define DEFAULT_PHYS_START (KERNEL_TR_PAGE_SIZE * 1) +#define IA64_GET_STACK_ULONG(OFF) \ + ((INSTACK(OFF,bt)) ? (GET_STACK_ULONG(OFF)) : get_init_stack_ulong((unsigned long)OFF)) + #endif /* IA64 */ #ifdef PPC64 @@ -3106,6 +3113,7 @@ #define BT_IRQSTACK (0x200000000ULL) #define BT_DUMPFILE_SEARCH (0x400000000ULL) #define BT_EFRAME_SEARCH2 (0x800000000ULL) +#define BT_START (0x1000000000ULL) #define BT_REF_HEXVAL (0x1) #define BT_REF_SYMBOL (0x2) @@ -3229,6 +3237,8 @@ int isize; }; +#define NMI_STACK 2 /* ebase[] offset to NMI exception stack */ + struct machine_specific { char *pml4; char *irqstack; @@ -3318,6 +3328,7 @@ int ia64_IS_VMALLOC_ADDR(ulong); #define display_idt_table() \ error(FATAL, "-d option TBD on ia64 architecture\n"); +int ia64_in_init_stack(ulong addr); #define OLD_UNWIND (0x1) /* CONFIG_IA64_NEW_UNWIND not turned on */ #define NEW_UNWIND (0x2) /* CONFIG_IA64_NEW_UNWIND turned on */ @@ -3359,8 +3370,10 @@ void (*unwind)(struct bt_info *); void (*dump_unwind_stats)(void); int (*unwind_debug)(ulong); + int ia64_init_stack_size; }; + /* * unwind.c */ @@ -3769,7 +3782,7 @@ void gdb_interface(struct gnu_request *); int gdb_pass_through(char *, FILE *, ulong); int gdb_readmem_callback(ulong, void *, int, int); -volatile void gdb_error_hook(void); +void gdb_error_hook(void); void restore_gdb_sanity(void); int is_gdb_command(int, ulong); char *gdb_command_string(int, char *, int); @@ -3784,7 +3797,7 @@ * gdb/top.c */ extern void (*command_loop_hook)(void); -extern volatile void (*error_hook)(void); +extern void (*error_hook)(void); extern void execute_command (char *, int); /* --- crash/Makefile.orig 2005-03-03 11:36:20.000000000 -0500 +++ crash/Makefile 2005-03-03 11:36:20.000000000 -0500 @@ -144,7 +144,7 @@ ${GDB}/gdb/symfile.c ${GDB}/gdb/elfread.c \ ${GDB}/gdb/ui-file.c ${GDB}/gdb/utils.c \ ${GDB}/gdb/ppc-linux-tdep.c ${GDB}/sim/ppc/ppc-instructions \ - ${GDB}/bfd/simple.c + ${GDB}/bfd/simple.c ${GDB}/include/obstack.h GDB_6.0_OFILES=${GDB}/gdb/main.o ${GDB}/gdb/symtab.o \ ${GDB}/gdb/target.o ${GDB}/gdb/symfile.o ${GDB}/gdb/elfread.o \ ${GDB}/gdb/ui-file.o ${GDB}/gdb/utils.o \ @@ -153,10 +153,11 @@ GDB_6.1_FILES=${GDB}/gdb/Makefile.in ${GDB}/Makefile.in \ ${GDB}/gdb/main.c ${GDB}/gdb/symtab.c ${GDB}/gdb/target.c \ ${GDB}/gdb/symfile.c ${GDB}/gdb/elfread.c \ - ${GDB}/gdb/ui-file.c ${GDB}/gdb/utils.c + ${GDB}/gdb/ui-file.c ${GDB}/gdb/utils.c ${GDB}/gdb/dwarf2read.c \ + ${GDB}/include/obstack.h GDB_6.1_OFILES=${GDB}/gdb/main.o ${GDB}/gdb/symtab.o \ ${GDB}/gdb/target.o ${GDB}/gdb/symfile.o ${GDB}/gdb/elfread.o \ - ${GDB}/gdb/ui-file.o ${GDB}/gdb/utils.o + ${GDB}/gdb/ui-file.o ${GDB}/gdb/utils.o ${GDB}/gdb/dwarf2read.o # # GDB_FLAGS is passed up from the gdb Makefile. --- crash/crash.8.orig 2005-03-03 11:36:20.000000000 -0500 +++ crash/crash.8 2005-01-31 10:55:43.000000000 -0500 @@ -104,9 +104,8 @@ .TP .BI \-d \ num .B Crash -sets its internal debug level -.I num -. The higher the number, the more debugging data will be printed while +sets its internal debug level. +The higher the number, the more debugging data will be printed while .B crash runs. .TP