diff options
-rw-r--r-- | gdb/buildsym.c | 1170 | ||||
-rw-r--r-- | gdb/jv-lang.c | 1098 | ||||
-rw-r--r-- | gdb/symmisc.c | 1087 |
3 files changed, 3355 insertions, 0 deletions
diff --git a/gdb/buildsym.c b/gdb/buildsym.c new file mode 100644 index 0000000..9d9b4f7 --- /dev/null +++ b/gdb/buildsym.c @@ -0,0 +1,1170 @@ +/* Support routines for building symbol tables in GDB's internal format. + Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, + 1996, 1997, 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + + This file is part of GDB. + + 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 of the License, 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. */ + +/* This module provides subroutines used for creating and adding to + the symbol table. These routines are called from various symbol- + file-reading routines. + + Routines to support specific debugging information formats (stabs, + DWARF, etc) belong somewhere else. */ + +#include "defs.h" +#include "bfd.h" +#include "gdb_obstack.h" +#include "symtab.h" +#include "symfile.h" /* Needed for "struct complaint" */ +#include "objfiles.h" +#include "gdbtypes.h" +#include "complaints.h" +#include "gdb_string.h" +#include "expression.h" /* For "enum exp_opcode" used by... */ +#include "language.h" /* For "local_hex_string" */ +#include "bcache.h" +#include "filenames.h" /* For DOSish file names */ +#include "macrotab.h" +#include "demangle.h" /* Needed by SYMBOL_INIT_DEMANGLED_NAME. */ +/* Ask buildsym.h to define the vars it normally declares `extern'. */ +#define EXTERN +/**/ +#include "buildsym.h" /* Our own declarations */ +#undef EXTERN + +/* For cleanup_undefined_types and finish_global_stabs (somewhat + questionable--see comment where we call them). */ + +#include "stabsread.h" + +/* List of free `struct pending' structures for reuse. */ + +static struct pending *free_pendings; + +/* Non-zero if symtab has line number info. This prevents an + otherwise empty symtab from being tossed. */ + +static int have_line_numbers; + +static int compare_line_numbers (const void *ln1p, const void *ln2p); + + +/* Initial sizes of data structures. These are realloc'd larger if + needed, and realloc'd down to the size actually used, when + completed. */ + +#define INITIAL_CONTEXT_STACK_SIZE 10 +#define INITIAL_LINE_VECTOR_LENGTH 1000 + + +/* Complaints about the symbols we have encountered. */ + +struct complaint block_end_complaint = +{"block end address less than block start address in %s (patched it)", 0, 0}; + +struct complaint anon_block_end_complaint = +{"block end address 0x%lx less than block start address 0x%lx (patched it)", 0, 0}; + +struct complaint innerblock_complaint = +{"inner block not inside outer block in %s", 0, 0}; + +struct complaint innerblock_anon_complaint = +{"inner block (0x%lx-0x%lx) not inside outer block (0x%lx-0x%lx)", 0, 0}; + +struct complaint blockvector_complaint = +{"block at %s out of order", 0, 0}; + +/* maintain the lists of symbols and blocks */ + +/* Add a pending list to free_pendings. */ +void +add_free_pendings (struct pending *list) +{ + register struct pending *link = list; + + if (list) + { + while (link->next) link = link->next; + link->next = free_pendings; + free_pendings = list; + } +} + +/* Add a symbol to one of the lists of symbols. */ + +void +add_symbol_to_list (struct symbol *symbol, struct pending **listhead) +{ + register struct pending *link; + + /* If this is an alias for another symbol, don't add it. */ + if (symbol->ginfo.name && symbol->ginfo.name[0] == '#') + return; + + /* We keep PENDINGSIZE symbols in each link of the list. If we + don't have a link with room in it, add a new link. */ + if (*listhead == NULL || (*listhead)->nsyms == PENDINGSIZE) + { + if (free_pendings) + { + link = free_pendings; + free_pendings = link->next; + } + else + { + link = (struct pending *) xmalloc (sizeof (struct pending)); + } + + link->next = *listhead; + *listhead = link; + link->nsyms = 0; + } + + (*listhead)->symbol[(*listhead)->nsyms++] = symbol; +} + +/* Find a symbol named NAME on a LIST. NAME need not be + '\0'-terminated; LENGTH is the length of the name. */ + +struct symbol * +find_symbol_in_list (struct pending *list, char *name, int length) +{ + int j; + char *pp; + + while (list != NULL) + { + for (j = list->nsyms; --j >= 0;) + { + pp = SYMBOL_NAME (list->symbol[j]); + if (*pp == *name && strncmp (pp, name, length) == 0 && + pp[length] == '\0') + { + return (list->symbol[j]); + } + } + list = list->next; + } + return (NULL); +} + +/* At end of reading syms, or in case of quit, really free as many + `struct pending's as we can easily find. */ + +/* ARGSUSED */ +void +really_free_pendings (PTR dummy) +{ + struct pending *next, *next1; + + for (next = free_pendings; next; next = next1) + { + next1 = next->next; + xfree ((void *) next); + } + free_pendings = NULL; + + free_pending_blocks (); + + for (next = file_symbols; next != NULL; next = next1) + { + next1 = next->next; + xfree ((void *) next); + } + file_symbols = NULL; + + for (next = global_symbols; next != NULL; next = next1) + { + next1 = next->next; + xfree ((void *) next); + } + global_symbols = NULL; + + if (pending_macros) + free_macro_table (pending_macros); +} + +/* This function is called to discard any pending blocks. */ + +void +free_pending_blocks (void) +{ +#if 0 /* Now we make the links in the + symbol_obstack, so don't free + them. */ + struct pending_block *bnext, *bnext1; + + for (bnext = pending_blocks; bnext; bnext = bnext1) + { + bnext1 = bnext->next; + xfree ((void *) bnext); + } +#endif + pending_blocks = NULL; +} + +/* Take one of the lists of symbols and make a block from it. Keep + the order the symbols have in the list (reversed from the input + file). Put the block on the list of pending blocks. */ + +void +finish_block (struct symbol *symbol, struct pending **listhead, + struct pending_block *old_blocks, + CORE_ADDR start, CORE_ADDR end, + struct objfile *objfile) +{ + register struct pending *next, *next1; + register struct block *block; + register struct pending_block *pblock; + struct pending_block *opblock; + register int i; + register int j; + + /* Count the length of the list of symbols. */ + + for (next = *listhead, i = 0; + next; + i += next->nsyms, next = next->next) + { + /* EMPTY */ ; + } + + /* Copy the symbols into the block. */ + + if (symbol) + { + block = (struct block *) + obstack_alloc (&objfile->symbol_obstack, + (sizeof (struct block) + + ((i - 1) * sizeof (struct symbol *)))); + BLOCK_NSYMS (block) = i; + for (next = *listhead; next; next = next->next) + for (j = next->nsyms - 1; j >= 0; j--) + { + BLOCK_SYM (block, --i) = next->symbol[j]; + } + } + else + { + int htab_size = BLOCK_HASHTABLE_SIZE (i); + + block = (struct block *) + obstack_alloc (&objfile->symbol_obstack, + (sizeof (struct block) + + ((htab_size - 1) * sizeof (struct symbol *)))); + for (j = 0; j < htab_size; j++) + { + BLOCK_BUCKET (block, j) = 0; + } + BLOCK_BUCKETS (block) = htab_size; + for (next = *listhead; next; next = next->next) + { + for (j = next->nsyms - 1; j >= 0; j--) + { + struct symbol *sym; + unsigned int hash_index; + const char *name = SYMBOL_DEMANGLED_NAME (next->symbol[j]); + if (name == NULL) + name = SYMBOL_NAME (next->symbol[j]); + hash_index = msymbol_hash_iw (name); + hash_index = hash_index % BLOCK_BUCKETS (block); + sym = BLOCK_BUCKET (block, hash_index); + BLOCK_BUCKET (block, hash_index) = next->symbol[j]; + next->symbol[j]->hash_next = sym; + } + } + } + + BLOCK_START (block) = start; + BLOCK_END (block) = end; + /* Superblock filled in when containing block is made */ + BLOCK_SUPERBLOCK (block) = NULL; + + BLOCK_GCC_COMPILED (block) = processing_gcc_compilation; + + /* Put the block in as the value of the symbol that names it. */ + + if (symbol) + { + struct type *ftype = SYMBOL_TYPE (symbol); + SYMBOL_BLOCK_VALUE (symbol) = block; + BLOCK_FUNCTION (block) = symbol; + BLOCK_HASHTABLE (block) = 0; + + if (TYPE_NFIELDS (ftype) <= 0) + { + /* No parameter type information is recorded with the + function's type. Set that from the type of the + parameter symbols. */ + int nparams = 0, iparams; + struct symbol *sym; + ALL_BLOCK_SYMBOLS (block, i, sym) + { + switch (SYMBOL_CLASS (sym)) + { + case LOC_ARG: + case LOC_REF_ARG: + case LOC_REGPARM: + case LOC_REGPARM_ADDR: + case LOC_BASEREG_ARG: + case LOC_LOCAL_ARG: + nparams++; + break; + case LOC_UNDEF: + case LOC_CONST: + case LOC_STATIC: + case LOC_INDIRECT: + case LOC_REGISTER: + case LOC_LOCAL: + case LOC_TYPEDEF: + case LOC_LABEL: + case LOC_BLOCK: + case LOC_CONST_BYTES: + case LOC_BASEREG: + case LOC_UNRESOLVED: + case LOC_OPTIMIZED_OUT: + default: + break; + } + } + if (nparams > 0) + { + TYPE_NFIELDS (ftype) = nparams; + TYPE_FIELDS (ftype) = (struct field *) + TYPE_ALLOC (ftype, nparams * sizeof (struct field)); + + for (i = iparams = 0; iparams < nparams; i++) + { + sym = BLOCK_SYM (block, i); + switch (SYMBOL_CLASS (sym)) + { + case LOC_ARG: + case LOC_REF_ARG: + case LOC_REGPARM: + case LOC_REGPARM_ADDR: + case LOC_BASEREG_ARG: + case LOC_LOCAL_ARG: + TYPE_FIELD_TYPE (ftype, iparams) = SYMBOL_TYPE (sym); + TYPE_FIELD_ARTIFICIAL (ftype, iparams) = 0; + iparams++; + break; + case LOC_UNDEF: + case LOC_CONST: + case LOC_STATIC: + case LOC_INDIRECT: + case LOC_REGISTER: + case LOC_LOCAL: + case LOC_TYPEDEF: + case LOC_LABEL: + case LOC_BLOCK: + case LOC_CONST_BYTES: + case LOC_BASEREG: + case LOC_UNRESOLVED: + case LOC_OPTIMIZED_OUT: + default: + break; + } + } + } + } + } + else + { + BLOCK_FUNCTION (block) = NULL; + BLOCK_HASHTABLE (block) = 1; + } + + /* Now "free" the links of the list, and empty the list. */ + + for (next = *listhead; next; next = next1) + { + next1 = next->next; + next->next = free_pendings; + free_pendings = next; + } + *listhead = NULL; + +#if 1 + /* Check to be sure that the blocks have an end address that is + greater than starting address */ + + if (BLOCK_END (block) < BLOCK_START (block)) + { + if (symbol) + { + complain (&block_end_complaint, SYMBOL_SOURCE_NAME (symbol)); + } + else + { + complain (&anon_block_end_complaint, BLOCK_END (block), BLOCK_START (block)); + } + /* Better than nothing */ + BLOCK_END (block) = BLOCK_START (block); + } +#endif + + /* Install this block as the superblock of all blocks made since the + start of this scope that don't have superblocks yet. */ + + opblock = NULL; + for (pblock = pending_blocks; + pblock && pblock != old_blocks; + pblock = pblock->next) + { + if (BLOCK_SUPERBLOCK (pblock->block) == NULL) + { +#if 1 + /* Check to be sure the blocks are nested as we receive + them. If the compiler/assembler/linker work, this just + burns a small amount of time. */ + if (BLOCK_START (pblock->block) < BLOCK_START (block) || + BLOCK_END (pblock->block) > BLOCK_END (block)) + { + if (symbol) + { + complain (&innerblock_complaint, + SYMBOL_SOURCE_NAME (symbol)); + } + else + { + complain (&innerblock_anon_complaint, BLOCK_START (pblock->block), + BLOCK_END (pblock->block), BLOCK_START (block), + BLOCK_END (block)); + } + if (BLOCK_START (pblock->block) < BLOCK_START (block)) + BLOCK_START (pblock->block) = BLOCK_START (block); + if (BLOCK_END (pblock->block) > BLOCK_END (block)) + BLOCK_END (pblock->block) = BLOCK_END (block); + } +#endif + BLOCK_SUPERBLOCK (pblock->block) = block; + } + opblock = pblock; + } + + record_pending_block (objfile, block, opblock); +} + +/* Record BLOCK on the list of all blocks in the file. Put it after + OPBLOCK, or at the beginning if opblock is NULL. This puts the + block in the list after all its subblocks. + + Allocate the pending block struct in the symbol_obstack to save + time. This wastes a little space. FIXME: Is it worth it? */ + +void +record_pending_block (struct objfile *objfile, struct block *block, + struct pending_block *opblock) +{ + register struct pending_block *pblock; + + pblock = (struct pending_block *) + obstack_alloc (&objfile->symbol_obstack, sizeof (struct pending_block)); + pblock->block = block; + if (opblock) + { + pblock->next = opblock->next; + opblock->next = pblock; + } + else + { + pblock->next = pending_blocks; + pending_blocks = pblock; + } +} + +/* OBSOLETE Note that this is only used in this file and in dstread.c, which */ +/* OBSOLETE should be fixed to not need direct access to this function. When */ +/* OBSOLETE that is done, it can be made static again. */ + +static struct blockvector * +make_blockvector (struct objfile *objfile) +{ + register struct pending_block *next; + register struct blockvector *blockvector; + register int i; + + /* Count the length of the list of blocks. */ + + for (next = pending_blocks, i = 0; next; next = next->next, i++) + {; + } + + blockvector = (struct blockvector *) + obstack_alloc (&objfile->symbol_obstack, + (sizeof (struct blockvector) + + (i - 1) * sizeof (struct block *))); + + /* Copy the blocks into the blockvector. This is done in reverse + order, which happens to put the blocks into the proper order + (ascending starting address). finish_block has hair to insert + each block into the list after its subblocks in order to make + sure this is true. */ + + BLOCKVECTOR_NBLOCKS (blockvector) = i; + for (next = pending_blocks; next; next = next->next) + { + BLOCKVECTOR_BLOCK (blockvector, --i) = next->block; + } + +#if 0 /* Now we make the links in the + obstack, so don't free them. */ + /* Now free the links of the list, and empty the list. */ + + for (next = pending_blocks; next; next = next1) + { + next1 = next->next; + xfree (next); + } +#endif + pending_blocks = NULL; + +#if 1 /* FIXME, shut this off after a while + to speed up symbol reading. */ + /* Some compilers output blocks in the wrong order, but we depend on + their being in the right order so we can binary search. Check the + order and moan about it. FIXME. */ + if (BLOCKVECTOR_NBLOCKS (blockvector) > 1) + { + for (i = 1; i < BLOCKVECTOR_NBLOCKS (blockvector); i++) + { + if (BLOCK_START (BLOCKVECTOR_BLOCK (blockvector, i - 1)) + > BLOCK_START (BLOCKVECTOR_BLOCK (blockvector, i))) + { + CORE_ADDR start + = BLOCK_START (BLOCKVECTOR_BLOCK (blockvector, i)); + + complain (&blockvector_complaint, + local_hex_string ((LONGEST) start)); + } + } + } +#endif + + return (blockvector); +} + +/* Start recording information about source code that came from an + included (or otherwise merged-in) source file with a different + name. NAME is the name of the file (cannot be NULL), DIRNAME is + the directory in which it resides (or NULL if not known). */ + +void +start_subfile (char *name, char *dirname) +{ + register struct subfile *subfile; + + /* See if this subfile is already known as a subfile of the current + main source file. */ + + for (subfile = subfiles; subfile; subfile = subfile->next) + { + if (FILENAME_CMP (subfile->name, name) == 0) + { + current_subfile = subfile; + return; + } + } + + /* This subfile is not known. Add an entry for it. Make an entry + for this subfile in the list of all subfiles of the current main + source file. */ + + subfile = (struct subfile *) xmalloc (sizeof (struct subfile)); + memset ((char *) subfile, 0, sizeof (struct subfile)); + subfile->next = subfiles; + subfiles = subfile; + current_subfile = subfile; + + /* Save its name and compilation directory name */ + subfile->name = (name == NULL) ? NULL : savestring (name, strlen (name)); + subfile->dirname = + (dirname == NULL) ? NULL : savestring (dirname, strlen (dirname)); + + /* Initialize line-number recording for this subfile. */ + subfile->line_vector = NULL; + + /* Default the source language to whatever can be deduced from the + filename. If nothing can be deduced (such as for a C/C++ include + file with a ".h" extension), then inherit whatever language the + previous subfile had. This kludgery is necessary because there + is no standard way in some object formats to record the source + language. Also, when symtabs are allocated we try to deduce a + language then as well, but it is too late for us to use that + information while reading symbols, since symtabs aren't allocated + until after all the symbols have been processed for a given + source file. */ + + subfile->language = deduce_language_from_filename (subfile->name); + if (subfile->language == language_unknown && + subfile->next != NULL) + { + subfile->language = subfile->next->language; + } + + /* Initialize the debug format string to NULL. We may supply it + later via a call to record_debugformat. */ + subfile->debugformat = NULL; + + /* cfront output is a C program, so in most ways it looks like a C + program. But to demangle we need to set the language to C++. We + can distinguish cfront code by the fact that it has #line + directives which specify a file name ending in .C. + + So if the filename of this subfile ends in .C, then change the + language of any pending subfiles from C to C++. We also accept + any other C++ suffixes accepted by deduce_language_from_filename + (in particular, some people use .cxx with cfront). */ + /* Likewise for f2c. */ + + if (subfile->name) + { + struct subfile *s; + enum language sublang = deduce_language_from_filename (subfile->name); + + if (sublang == language_cplus || sublang == language_fortran) + for (s = subfiles; s != NULL; s = s->next) + if (s->language == language_c) + s->language = sublang; + } + + /* And patch up this file if necessary. */ + if (subfile->language == language_c + && subfile->next != NULL + && (subfile->next->language == language_cplus + || subfile->next->language == language_fortran)) + { + subfile->language = subfile->next->language; + } +} + +/* For stabs readers, the first N_SO symbol is assumed to be the + source file name, and the subfile struct is initialized using that + assumption. If another N_SO symbol is later seen, immediately + following the first one, then the first one is assumed to be the + directory name and the second one is really the source file name. + + So we have to patch up the subfile struct by moving the old name + value to dirname and remembering the new name. Some sanity + checking is performed to ensure that the state of the subfile + struct is reasonable and that the old name we are assuming to be a + directory name actually is (by checking for a trailing '/'). */ + +void +patch_subfile_names (struct subfile *subfile, char *name) +{ + if (subfile != NULL && subfile->dirname == NULL && subfile->name != NULL + && subfile->name[strlen (subfile->name) - 1] == '/') + { + subfile->dirname = subfile->name; + subfile->name = savestring (name, strlen (name)); + last_source_file = name; + + /* Default the source language to whatever can be deduced from + the filename. If nothing can be deduced (such as for a C/C++ + include file with a ".h" extension), then inherit whatever + language the previous subfile had. This kludgery is + necessary because there is no standard way in some object + formats to record the source language. Also, when symtabs + are allocated we try to deduce a language then as well, but + it is too late for us to use that information while reading + symbols, since symtabs aren't allocated until after all the + symbols have been processed for a given source file. */ + + subfile->language = deduce_language_from_filename (subfile->name); + if (subfile->language == language_unknown && + subfile->next != NULL) + { + subfile->language = subfile->next->language; + } + } +} + +/* Handle the N_BINCL and N_EINCL symbol types that act like N_SOL for + switching source files (different subfiles, as we call them) within + one object file, but using a stack rather than in an arbitrary + order. */ + +void +push_subfile (void) +{ + register struct subfile_stack *tem + = (struct subfile_stack *) xmalloc (sizeof (struct subfile_stack)); + + tem->next = subfile_stack; + subfile_stack = tem; + if (current_subfile == NULL || current_subfile->name == NULL) + { + internal_error (__FILE__, __LINE__, "failed internal consistency check"); + } + tem->name = current_subfile->name; +} + +char * +pop_subfile (void) +{ + register char *name; + register struct subfile_stack *link = subfile_stack; + + if (link == NULL) + { + internal_error (__FILE__, __LINE__, "failed internal consistency check"); + } + name = link->name; + subfile_stack = link->next; + xfree ((void *) link); + return (name); +} + +/* Add a linetable entry for line number LINE and address PC to the + line vector for SUBFILE. */ + +void +record_line (register struct subfile *subfile, int line, CORE_ADDR pc) +{ + struct linetable_entry *e; + /* Ignore the dummy line number in libg.o */ + + if (line == 0xffff) + { + return; + } + + /* Make sure line vector exists and is big enough. */ + if (!subfile->line_vector) + { + subfile->line_vector_length = INITIAL_LINE_VECTOR_LENGTH; + subfile->line_vector = (struct linetable *) + xmalloc (sizeof (struct linetable) + + subfile->line_vector_length * sizeof (struct linetable_entry)); + subfile->line_vector->nitems = 0; + have_line_numbers = 1; + } + + if (subfile->line_vector->nitems + 1 >= subfile->line_vector_length) + { + subfile->line_vector_length *= 2; + subfile->line_vector = (struct linetable *) + xrealloc ((char *) subfile->line_vector, + (sizeof (struct linetable) + + (subfile->line_vector_length + * sizeof (struct linetable_entry)))); + } + + e = subfile->line_vector->item + subfile->line_vector->nitems++; + e->line = line; + e->pc = ADDR_BITS_REMOVE(pc); +} + +/* Needed in order to sort line tables from IBM xcoff files. Sigh! */ + +static int +compare_line_numbers (const void *ln1p, const void *ln2p) +{ + struct linetable_entry *ln1 = (struct linetable_entry *) ln1p; + struct linetable_entry *ln2 = (struct linetable_entry *) ln2p; + + /* Note: this code does not assume that CORE_ADDRs can fit in ints. + Please keep it that way. */ + if (ln1->pc < ln2->pc) + return -1; + + if (ln1->pc > ln2->pc) + return 1; + + /* If pc equal, sort by line. I'm not sure whether this is optimum + behavior (see comment at struct linetable in symtab.h). */ + return ln1->line - ln2->line; +} + +/* Start a new symtab for a new source file. Called, for example, + when a stabs symbol of type N_SO is seen, or when a DWARF + TAG_compile_unit DIE is seen. It indicates the start of data for + one original source file. */ + +void +start_symtab (char *name, char *dirname, CORE_ADDR start_addr) +{ + + last_source_file = name; + last_source_start_addr = start_addr; + file_symbols = NULL; + global_symbols = NULL; + within_function = 0; + have_line_numbers = 0; + + /* Context stack is initially empty. Allocate first one with room + for 10 levels; reuse it forever afterward. */ + if (context_stack == NULL) + { + context_stack_size = INITIAL_CONTEXT_STACK_SIZE; + context_stack = (struct context_stack *) + xmalloc (context_stack_size * sizeof (struct context_stack)); + } + context_stack_depth = 0; + + /* Initialize the list of sub source files with one entry for this + file (the top-level source file). */ + + subfiles = NULL; + current_subfile = NULL; + start_subfile (name, dirname); +} + +/* Finish the symbol definitions for one main source file, close off + all the lexical contexts for that file (creating struct block's for + them), then make the struct symtab for that file and put it in the + list of all such. + + END_ADDR is the address of the end of the file's text. SECTION is + the section number (in objfile->section_offsets) of the blockvector + and linetable. + + Note that it is possible for end_symtab() to return NULL. In + particular, for the DWARF case at least, it will return NULL when + it finds a compilation unit that has exactly one DIE, a + TAG_compile_unit DIE. This can happen when we link in an object + file that was compiled from an empty source file. Returning NULL + is probably not the correct thing to do, because then gdb will + never know about this empty file (FIXME). */ + +struct symtab * +end_symtab (CORE_ADDR end_addr, struct objfile *objfile, int section) +{ + register struct symtab *symtab = NULL; + register struct blockvector *blockvector; + register struct subfile *subfile; + register struct context_stack *cstk; + struct subfile *nextsub; + + /* Finish the lexical context of the last function in the file; pop + the context stack. */ + + if (context_stack_depth > 0) + { + cstk = pop_context (); + /* Make a block for the local symbols within. */ + finish_block (cstk->name, &local_symbols, cstk->old_blocks, + cstk->start_addr, end_addr, objfile); + + if (context_stack_depth > 0) + { + /* This is said to happen with SCO. The old coffread.c + code simply emptied the context stack, so we do the + same. FIXME: Find out why it is happening. This is not + believed to happen in most cases (even for coffread.c); + it used to be an abort(). */ + static struct complaint msg = + {"Context stack not empty in end_symtab", 0, 0}; + complain (&msg); + context_stack_depth = 0; + } + } + + /* Reordered executables may have out of order pending blocks; if + OBJF_REORDERED is true, then sort the pending blocks. */ + if ((objfile->flags & OBJF_REORDERED) && pending_blocks) + { + /* FIXME! Remove this horrid bubble sort and use merge sort!!! */ + int swapped; + do + { + struct pending_block *pb, *pbnext; + + pb = pending_blocks; + pbnext = pb->next; + swapped = 0; + + while (pbnext) + { + /* swap blocks if unordered! */ + + if (BLOCK_START (pb->block) < BLOCK_START (pbnext->block)) + { + struct block *tmp = pb->block; + pb->block = pbnext->block; + pbnext->block = tmp; + swapped = 1; + } + pb = pbnext; + pbnext = pbnext->next; + } + } + while (swapped); + } + + /* Cleanup any undefined types that have been left hanging around + (this needs to be done before the finish_blocks so that + file_symbols is still good). + + Both cleanup_undefined_types and finish_global_stabs are stabs + specific, but harmless for other symbol readers, since on gdb + startup or when finished reading stabs, the state is set so these + are no-ops. FIXME: Is this handled right in case of QUIT? Can + we make this cleaner? */ + + cleanup_undefined_types (); + finish_global_stabs (objfile); + + if (pending_blocks == NULL + && file_symbols == NULL + && global_symbols == NULL + && have_line_numbers == 0 + && pending_macros == NULL) + { + /* Ignore symtabs that have no functions with real debugging + info. */ + blockvector = NULL; + } + else + { + /* Define the STATIC_BLOCK & GLOBAL_BLOCK, and build the + blockvector. */ + finish_block (0, &file_symbols, 0, last_source_start_addr, end_addr, + objfile); + finish_block (0, &global_symbols, 0, last_source_start_addr, end_addr, + objfile); + blockvector = make_blockvector (objfile); + } + +#ifndef PROCESS_LINENUMBER_HOOK +#define PROCESS_LINENUMBER_HOOK() +#endif + PROCESS_LINENUMBER_HOOK (); /* Needed for xcoff. */ + + /* Now create the symtab objects proper, one for each subfile. */ + /* (The main file is the last one on the chain.) */ + + for (subfile = subfiles; subfile; subfile = nextsub) + { + int linetablesize = 0; + symtab = NULL; + + /* If we have blocks of symbols, make a symtab. Otherwise, just + ignore this file and any line number info in it. */ + if (blockvector) + { + if (subfile->line_vector) + { + linetablesize = sizeof (struct linetable) + + subfile->line_vector->nitems * sizeof (struct linetable_entry); +#if 0 + /* I think this is artifact from before it went on the + obstack. I doubt we'll need the memory between now + and when we free it later in this function. */ + /* First, shrink the linetable to make more memory. */ + subfile->line_vector = (struct linetable *) + xrealloc ((char *) subfile->line_vector, linetablesize); +#endif + + /* Like the pending blocks, the line table may be + scrambled in reordered executables. Sort it if + OBJF_REORDERED is true. */ + if (objfile->flags & OBJF_REORDERED) + qsort (subfile->line_vector->item, + subfile->line_vector->nitems, + sizeof (struct linetable_entry), compare_line_numbers); + } + + /* Now, allocate a symbol table. */ + symtab = allocate_symtab (subfile->name, objfile); + + /* Fill in its components. */ + symtab->blockvector = blockvector; + symtab->macro_table = pending_macros; + if (subfile->line_vector) + { + /* Reallocate the line table on the symbol obstack */ + symtab->linetable = (struct linetable *) + obstack_alloc (&objfile->symbol_obstack, linetablesize); + memcpy (symtab->linetable, subfile->line_vector, linetablesize); + } + else + { + symtab->linetable = NULL; + } + symtab->block_line_section = section; + if (subfile->dirname) + { + /* Reallocate the dirname on the symbol obstack */ + symtab->dirname = (char *) + obstack_alloc (&objfile->symbol_obstack, + strlen (subfile->dirname) + 1); + strcpy (symtab->dirname, subfile->dirname); + } + else + { + symtab->dirname = NULL; + } + symtab->free_code = free_linetable; + symtab->free_ptr = NULL; + + /* Use whatever language we have been using for this + subfile, not the one that was deduced in allocate_symtab + from the filename. We already did our own deducing when + we created the subfile, and we may have altered our + opinion of what language it is from things we found in + the symbols. */ + symtab->language = subfile->language; + + /* Save the debug format string (if any) in the symtab */ + if (subfile->debugformat != NULL) + { + symtab->debugformat = obsavestring (subfile->debugformat, + strlen (subfile->debugformat), + &objfile->symbol_obstack); + } + + /* All symtabs for the main file and the subfiles share a + blockvector, so we need to clear primary for everything + but the main file. */ + + symtab->primary = 0; + } + if (subfile->name != NULL) + { + xfree ((void *) subfile->name); + } + if (subfile->dirname != NULL) + { + xfree ((void *) subfile->dirname); + } + if (subfile->line_vector != NULL) + { + xfree ((void *) subfile->line_vector); + } + if (subfile->debugformat != NULL) + { + xfree ((void *) subfile->debugformat); + } + + nextsub = subfile->next; + xfree ((void *) subfile); + } + + /* Set this for the main source file. */ + if (symtab) + { + symtab->primary = 1; + } + + last_source_file = NULL; + current_subfile = NULL; + pending_macros = NULL; + + return symtab; +} + +/* Push a context block. Args are an identifying nesting level + (checkable when you pop it), and the starting PC address of this + context. */ + +struct context_stack * +push_context (int desc, CORE_ADDR valu) +{ + register struct context_stack *new; + + if (context_stack_depth == context_stack_size) + { + context_stack_size *= 2; + context_stack = (struct context_stack *) + xrealloc ((char *) context_stack, + (context_stack_size * sizeof (struct context_stack))); + } + + new = &context_stack[context_stack_depth++]; + new->depth = desc; + new->locals = local_symbols; + new->params = param_symbols; + new->old_blocks = pending_blocks; + new->start_addr = valu; + new->name = NULL; + + local_symbols = NULL; + param_symbols = NULL; + + return new; +} + + +/* Compute a small integer hash code for the given name. */ + +int +hashname (char *name) +{ + return (hash(name,strlen(name)) % HASHSIZE); +} + + +void +record_debugformat (char *format) +{ + current_subfile->debugformat = savestring (format, strlen (format)); +} + +/* Merge the first symbol list SRCLIST into the second symbol list + TARGETLIST by repeated calls to add_symbol_to_list(). This + procedure "frees" each link of SRCLIST by adding it to the + free_pendings list. Caller must set SRCLIST to a null list after + calling this function. + + Void return. */ + +void +merge_symbol_lists (struct pending **srclist, struct pending **targetlist) +{ + register int i; + + if (!srclist || !*srclist) + return; + + /* Merge in elements from current link. */ + for (i = 0; i < (*srclist)->nsyms; i++) + add_symbol_to_list ((*srclist)->symbol[i], targetlist); + + /* Recurse on next. */ + merge_symbol_lists (&(*srclist)->next, targetlist); + + /* "Free" the current link. */ + (*srclist)->next = free_pendings; + free_pendings = (*srclist); +} + +/* Initialize anything that needs initializing when starting to read a + fresh piece of a symbol file, e.g. reading in the stuff + corresponding to a psymtab. */ + +void +buildsym_init (void) +{ + free_pendings = NULL; + file_symbols = NULL; + global_symbols = NULL; + pending_blocks = NULL; + pending_macros = NULL; +} + +/* Initialize anything that needs initializing when a completely new + symbol file is specified (not just adding some symbols from another + file, e.g. a shared library). */ + +void +buildsym_new_init (void) +{ + buildsym_init (); +} diff --git a/gdb/jv-lang.c b/gdb/jv-lang.c new file mode 100644 index 0000000..3afdebd --- /dev/null +++ b/gdb/jv-lang.c @@ -0,0 +1,1098 @@ +/* Java language support routines for GDB, the GNU debugger. + Copyright 1997, 1998, 1999, 2000 Free Software Foundation, Inc. + + This file is part of GDB. + + 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 of the License, 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. */ + +#include "defs.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "expression.h" +#include "parser-defs.h" +#include "language.h" +#include "gdbtypes.h" +#include "symtab.h" +#include "symfile.h" +#include "objfiles.h" +#include "gdb_string.h" +#include "value.h" +#include "c-lang.h" +#include "jv-lang.h" +#include "gdbcore.h" +#include <ctype.h> + +struct type *java_int_type; +struct type *java_byte_type; +struct type *java_short_type; +struct type *java_long_type; +struct type *java_boolean_type; +struct type *java_char_type; +struct type *java_float_type; +struct type *java_double_type; +struct type *java_void_type; + +/* Local functions */ + +extern void _initialize_java_language (void); + +static int java_demangled_signature_length (char *); +static void java_demangled_signature_copy (char *, char *); + +static struct symtab *get_java_class_symtab (void); +static char *get_java_utf8_name (struct obstack *obstack, struct value *name); +static int java_class_is_primitive (struct value *clas); +static struct type *java_lookup_type (char *signature); +static struct value *java_value_string (char *ptr, int len); + +static void java_emit_char (int c, struct ui_file * stream, int quoter); + +/* This objfile contains symtabs that have been dynamically created + to record dynamically loaded Java classes and dynamically + compiled java methods. */ + +static struct objfile *dynamics_objfile = NULL; + +static struct type *java_link_class_type (struct type *, struct value *); + +static struct objfile * +get_dynamics_objfile (void) +{ + if (dynamics_objfile == NULL) + { + dynamics_objfile = allocate_objfile (NULL, 0); + } + return dynamics_objfile; +} + +#if 1 +/* symtab contains classes read from the inferior. */ + +static struct symtab *class_symtab = NULL; + +/* Maximum number of class in class_symtab before relocation is needed. */ + +static int class_symtab_space; + +static struct symtab * +get_java_class_symtab (void) +{ + if (class_symtab == NULL) + { + struct objfile *objfile = get_dynamics_objfile (); + struct blockvector *bv; + struct block *bl; + class_symtab = allocate_symtab ("<java-classes>", objfile); + class_symtab->language = language_java; + bv = (struct blockvector *) + obstack_alloc (&objfile->symbol_obstack, sizeof (struct blockvector)); + BLOCKVECTOR_NBLOCKS (bv) = 1; + BLOCKVECTOR (class_symtab) = bv; + + /* Allocate dummy STATIC_BLOCK. */ + bl = (struct block *) + obstack_alloc (&objfile->symbol_obstack, sizeof (struct block)); + BLOCK_NSYMS (bl) = 0; + BLOCK_HASHTABLE (bl) = 0; + BLOCK_START (bl) = 0; + BLOCK_END (bl) = 0; + BLOCK_FUNCTION (bl) = NULL; + BLOCK_SUPERBLOCK (bl) = NULL; + BLOCK_GCC_COMPILED (bl) = 0; + BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK) = bl; + + /* Allocate GLOBAL_BLOCK. This has to be relocatable. */ + class_symtab_space = 128; + bl = xmmalloc (objfile->md, + sizeof (struct block) + + ((class_symtab_space - 1) * sizeof (struct symbol *))); + *bl = *BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); + BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK) = bl; + class_symtab->free_ptr = (char *) bl; + } + return class_symtab; +} + +static void +add_class_symtab_symbol (struct symbol *sym) +{ + struct symtab *symtab = get_java_class_symtab (); + struct blockvector *bv = BLOCKVECTOR (symtab); + struct block *bl = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); + if (BLOCK_NSYMS (bl) >= class_symtab_space) + { + /* Need to re-allocate. */ + class_symtab_space *= 2; + bl = xmrealloc (symtab->objfile->md, bl, + sizeof (struct block) + + ((class_symtab_space - 1) * sizeof (struct symbol *))); + class_symtab->free_ptr = (char *) bl; + BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK) = bl; + } + + BLOCK_SYM (bl, BLOCK_NSYMS (bl)) = sym; + BLOCK_NSYMS (bl) = BLOCK_NSYMS (bl) + 1; +} + +static struct symbol *add_class_symbol (struct type *type, CORE_ADDR addr); + +static struct symbol * +add_class_symbol (struct type *type, CORE_ADDR addr) +{ + struct symbol *sym; + sym = (struct symbol *) + obstack_alloc (&dynamics_objfile->symbol_obstack, sizeof (struct symbol)); + memset (sym, 0, sizeof (struct symbol)); + SYMBOL_LANGUAGE (sym) = language_java; + SYMBOL_NAME (sym) = TYPE_TAG_NAME (type); + SYMBOL_CLASS (sym) = LOC_TYPEDEF; + /* SYMBOL_VALUE (sym) = valu; */ + SYMBOL_TYPE (sym) = type; + SYMBOL_NAMESPACE (sym) = STRUCT_NAMESPACE; + SYMBOL_VALUE_ADDRESS (sym) = addr; + return sym; +} +#endif + +struct type * +java_lookup_class (char *name) +{ + struct symbol *sym; + sym = lookup_symbol (name, expression_context_block, STRUCT_NAMESPACE, + (int *) 0, (struct symtab **) NULL); + if (sym != NULL) + return SYMBOL_TYPE (sym); +#if 0 + CORE_ADDR addr; + if (called from parser) + { + call lookup_class (or similar) in inferior; + if not + found: + return NULL; + addr = found in inferior; + } + else + addr = 0; + struct type *type; + type = alloc_type (objfile); + TYPE_CODE (type) = TYPE_CODE_STRUCT; + INIT_CPLUS_SPECIFIC (type); + TYPE_TAG_NAME (type) = obsavestring (name, strlen (name), &objfile->type_obstack); + TYPE_FLAGS (type) |= TYPE_FLAG_STUB; + TYPE ? = addr; + return type; +#else + /* FIXME - should search inferior's symbol table. */ + return NULL; +#endif +} + +/* Return a nul-terminated string (allocated on OBSTACK) for + a name given by NAME (which has type Utf8Const*). */ + +char * +get_java_utf8_name (struct obstack *obstack, struct value *name) +{ + char *chrs; + struct value *temp = name; + int name_length; + CORE_ADDR data_addr; + temp = value_struct_elt (&temp, NULL, "length", NULL, "structure"); + name_length = (int) value_as_long (temp); + data_addr = VALUE_ADDRESS (temp) + VALUE_OFFSET (temp) + + TYPE_LENGTH (VALUE_TYPE (temp)); + chrs = obstack_alloc (obstack, name_length + 1); + chrs[name_length] = '\0'; + read_memory (data_addr, chrs, name_length); + return chrs; +} + +struct value * +java_class_from_object (struct value *obj_val) +{ + /* This is all rather inefficient, since the offsets of vtable and + class are fixed. FIXME */ + struct value *vtable_val; + + if (TYPE_CODE (VALUE_TYPE (obj_val)) == TYPE_CODE_PTR + && TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (obj_val))) == 0) + obj_val = value_at (get_java_object_type (), + value_as_address (obj_val), NULL); + + vtable_val = value_struct_elt (&obj_val, NULL, "vtable", NULL, "structure"); + return value_struct_elt (&vtable_val, NULL, "class", NULL, "structure"); +} + +/* Check if CLASS_IS_PRIMITIVE(value of clas): */ +static int +java_class_is_primitive (struct value *clas) +{ + struct value *vtable = value_struct_elt (&clas, NULL, "vtable", NULL, "struct"); + CORE_ADDR i = value_as_address (vtable); + return (int) (i & 0x7fffffff) == (int) 0x7fffffff; +} + +/* Read a GCJ Class object, and generated a gdb (TYPE_CODE_STRUCT) type. */ + +struct type * +type_from_class (struct value *clas) +{ + struct type *type; + char *name; + struct value *temp; + struct objfile *objfile; + struct value *utf8_name; + char *nptr; + CORE_ADDR addr; + struct block *bl; + int i; + int is_array = 0; + + type = check_typedef (VALUE_TYPE (clas)); + if (TYPE_CODE (type) == TYPE_CODE_PTR) + { + if (value_logical_not (clas)) + return NULL; + clas = value_ind (clas); + } + addr = VALUE_ADDRESS (clas) + VALUE_OFFSET (clas); + +#if 0 + get_java_class_symtab (); + bl = BLOCKVECTOR_BLOCK (BLOCKVECTOR (class_symtab), GLOBAL_BLOCK); + for (i = BLOCK_NSYMS (bl); --i >= 0;) + { + struct symbol *sym = BLOCK_SYM (bl, i); + if (SYMBOL_VALUE_ADDRESS (sym) == addr) + return SYMBOL_TYPE (sym); + } +#endif + + objfile = get_dynamics_objfile (); + if (java_class_is_primitive (clas)) + { + struct value *sig; + temp = clas; + sig = value_struct_elt (&temp, NULL, "method_count", NULL, "structure"); + return java_primitive_type (value_as_long (sig)); + } + + /* Get Class name. */ + /* if clasloader non-null, prepend loader address. FIXME */ + temp = clas; + utf8_name = value_struct_elt (&temp, NULL, "name", NULL, "structure"); + name = get_java_utf8_name (&objfile->type_obstack, utf8_name); + for (nptr = name; *nptr != 0; nptr++) + { + if (*nptr == '/') + *nptr = '.'; + } + + type = java_lookup_class (name); + if (type != NULL) + return type; + + type = alloc_type (objfile); + TYPE_CODE (type) = TYPE_CODE_STRUCT; + INIT_CPLUS_SPECIFIC (type); + + if (name[0] == '[') + { + char *signature = name; + int namelen = java_demangled_signature_length (signature); + if (namelen > strlen (name)) + name = obstack_alloc (&objfile->type_obstack, namelen + 1); + java_demangled_signature_copy (name, signature); + name[namelen] = '\0'; + is_array = 1; + temp = clas; + /* Set array element type. */ + temp = value_struct_elt (&temp, NULL, "methods", NULL, "structure"); + VALUE_TYPE (temp) = lookup_pointer_type (VALUE_TYPE (clas)); + TYPE_TARGET_TYPE (type) = type_from_class (temp); + } + + ALLOCATE_CPLUS_STRUCT_TYPE (type); + TYPE_TAG_NAME (type) = name; + + add_class_symtab_symbol (add_class_symbol (type, addr)); + return java_link_class_type (type, clas); +} + +/* Fill in class TYPE with data from the CLAS value. */ + +struct type * +java_link_class_type (struct type *type, struct value *clas) +{ + struct value *temp; + char *unqualified_name; + char *name = TYPE_TAG_NAME (type); + int ninterfaces, nfields, nmethods; + int type_is_object = 0; + struct fn_field *fn_fields; + struct fn_fieldlist *fn_fieldlists; + struct value *fields; + struct value *methods; + struct value *method = NULL; + struct value *field = NULL; + int i, j; + struct objfile *objfile = get_dynamics_objfile (); + struct type *tsuper; + + unqualified_name = strrchr (name, '.'); + if (unqualified_name == NULL) + unqualified_name = name; + + temp = clas; + temp = value_struct_elt (&temp, NULL, "superclass", NULL, "structure"); + if (name != NULL && strcmp (name, "java.lang.Object") == 0) + { + tsuper = get_java_object_type (); + if (tsuper && TYPE_CODE (tsuper) == TYPE_CODE_PTR) + tsuper = TYPE_TARGET_TYPE (tsuper); + type_is_object = 1; + } + else + tsuper = type_from_class (temp); + +#if 1 + ninterfaces = 0; +#else + temp = clas; + ninterfaces = value_as_long (value_struct_elt (&temp, NULL, "interface_len", NULL, "structure")); +#endif + TYPE_N_BASECLASSES (type) = (tsuper == NULL ? 0 : 1) + ninterfaces; + temp = clas; + nfields = value_as_long (value_struct_elt (&temp, NULL, "field_count", NULL, "structure")); + nfields += TYPE_N_BASECLASSES (type); + nfields++; /* Add one for dummy "class" field. */ + TYPE_NFIELDS (type) = nfields; + TYPE_FIELDS (type) = (struct field *) + TYPE_ALLOC (type, sizeof (struct field) * nfields); + + memset (TYPE_FIELDS (type), 0, sizeof (struct field) * nfields); + + TYPE_FIELD_PRIVATE_BITS (type) = + (B_TYPE *) TYPE_ALLOC (type, B_BYTES (nfields)); + B_CLRALL (TYPE_FIELD_PRIVATE_BITS (type), nfields); + + TYPE_FIELD_PROTECTED_BITS (type) = + (B_TYPE *) TYPE_ALLOC (type, B_BYTES (nfields)); + B_CLRALL (TYPE_FIELD_PROTECTED_BITS (type), nfields); + + TYPE_FIELD_IGNORE_BITS (type) = + (B_TYPE *) TYPE_ALLOC (type, B_BYTES (nfields)); + B_CLRALL (TYPE_FIELD_IGNORE_BITS (type), nfields); + + TYPE_FIELD_VIRTUAL_BITS (type) = (B_TYPE *) + TYPE_ALLOC (type, B_BYTES (TYPE_N_BASECLASSES (type))); + B_CLRALL (TYPE_FIELD_VIRTUAL_BITS (type), TYPE_N_BASECLASSES (type)); + + if (tsuper != NULL) + { + TYPE_BASECLASS (type, 0) = tsuper; + if (type_is_object) + SET_TYPE_FIELD_PRIVATE (type, 0); + } + + i = strlen (name); + if (i > 2 && name[i - 1] == ']' && tsuper != NULL) + { + /* FIXME */ + TYPE_LENGTH (type) = TYPE_LENGTH (tsuper) + 4; /* size with "length" */ + } + else + { + temp = clas; + temp = value_struct_elt (&temp, NULL, "size_in_bytes", NULL, "structure"); + TYPE_LENGTH (type) = value_as_long (temp); + } + + fields = NULL; + nfields--; /* First set up dummy "class" field. */ + SET_FIELD_PHYSADDR (TYPE_FIELD (type, nfields), + VALUE_ADDRESS (clas) + VALUE_OFFSET (clas)); + TYPE_FIELD_NAME (type, nfields) = "class"; + TYPE_FIELD_TYPE (type, nfields) = VALUE_TYPE (clas); + SET_TYPE_FIELD_PRIVATE (type, nfields); + + for (i = TYPE_N_BASECLASSES (type); i < nfields; i++) + { + int accflags; + int boffset; + if (fields == NULL) + { + temp = clas; + fields = value_struct_elt (&temp, NULL, "fields", NULL, "structure"); + field = value_ind (fields); + } + else + { /* Re-use field value for next field. */ + VALUE_ADDRESS (field) += TYPE_LENGTH (VALUE_TYPE (field)); + VALUE_LAZY (field) = 1; + } + temp = field; + temp = value_struct_elt (&temp, NULL, "name", NULL, "structure"); + TYPE_FIELD_NAME (type, i) = + get_java_utf8_name (&objfile->type_obstack, temp); + temp = field; + accflags = value_as_long (value_struct_elt (&temp, NULL, "accflags", + NULL, "structure")); + temp = field; + temp = value_struct_elt (&temp, NULL, "info", NULL, "structure"); + boffset = value_as_long (value_struct_elt (&temp, NULL, "boffset", + NULL, "structure")); + if (accflags & 0x0001) /* public access */ + { + /* ??? */ + } + if (accflags & 0x0002) /* private access */ + { + SET_TYPE_FIELD_PRIVATE (type, i); + } + if (accflags & 0x0004) /* protected access */ + { + SET_TYPE_FIELD_PROTECTED (type, i); + } + if (accflags & 0x0008) /* ACC_STATIC */ + SET_FIELD_PHYSADDR (TYPE_FIELD (type, i), boffset); + else + TYPE_FIELD_BITPOS (type, i) = 8 * boffset; + if (accflags & 0x8000) /* FIELD_UNRESOLVED_FLAG */ + { + TYPE_FIELD_TYPE (type, i) = get_java_object_type (); /* FIXME */ + } + else + { + struct type *ftype; + temp = field; + temp = value_struct_elt (&temp, NULL, "type", NULL, "structure"); + ftype = type_from_class (temp); + if (TYPE_CODE (ftype) == TYPE_CODE_STRUCT) + ftype = lookup_pointer_type (ftype); + TYPE_FIELD_TYPE (type, i) = ftype; + } + } + + temp = clas; + nmethods = value_as_long (value_struct_elt (&temp, NULL, "method_count", + NULL, "structure")); + TYPE_NFN_FIELDS_TOTAL (type) = nmethods; + j = nmethods * sizeof (struct fn_field); + fn_fields = (struct fn_field *) + obstack_alloc (&dynamics_objfile->symbol_obstack, j); + memset (fn_fields, 0, j); + fn_fieldlists = (struct fn_fieldlist *) + alloca (nmethods * sizeof (struct fn_fieldlist)); + + methods = NULL; + for (i = 0; i < nmethods; i++) + { + char *mname; + int k; + if (methods == NULL) + { + temp = clas; + methods = value_struct_elt (&temp, NULL, "methods", NULL, "structure"); + method = value_ind (methods); + } + else + { /* Re-use method value for next method. */ + VALUE_ADDRESS (method) += TYPE_LENGTH (VALUE_TYPE (method)); + VALUE_LAZY (method) = 1; + } + + /* Get method name. */ + temp = method; + temp = value_struct_elt (&temp, NULL, "name", NULL, "structure"); + mname = get_java_utf8_name (&objfile->type_obstack, temp); + if (strcmp (mname, "<init>") == 0) + mname = unqualified_name; + + /* Check for an existing method with the same name. + * This makes building the fn_fieldslists an O(nmethods**2) + * operation. That could be using hashing, but I doubt it + * is worth it. Note that we do maintain the order of methods + * in the inferior's Method table (as long as that is grouped + * by method name), which I think is desirable. --PB */ + for (k = 0, j = TYPE_NFN_FIELDS (type);;) + { + if (--j < 0) + { /* No match - new method name. */ + j = TYPE_NFN_FIELDS (type)++; + fn_fieldlists[j].name = mname; + fn_fieldlists[j].length = 1; + fn_fieldlists[j].fn_fields = &fn_fields[i]; + k = i; + break; + } + if (strcmp (mname, fn_fieldlists[j].name) == 0) + { /* Found an existing method with the same name. */ + int l; + if (mname != unqualified_name) + obstack_free (&objfile->type_obstack, mname); + mname = fn_fieldlists[j].name; + fn_fieldlists[j].length++; + k = i - k; /* Index of new slot. */ + /* Shift intervening fn_fields (between k and i) down. */ + for (l = i; l > k; l--) + fn_fields[l] = fn_fields[l - 1]; + for (l = TYPE_NFN_FIELDS (type); --l > j;) + fn_fieldlists[l].fn_fields++; + break; + } + k += fn_fieldlists[j].length; + } + fn_fields[k].physname = ""; + fn_fields[k].is_stub = 1; + fn_fields[k].type = make_function_type (java_void_type, NULL); /* FIXME */ + TYPE_CODE (fn_fields[k].type) = TYPE_CODE_METHOD; + } + + j = TYPE_NFN_FIELDS (type) * sizeof (struct fn_fieldlist); + TYPE_FN_FIELDLISTS (type) = (struct fn_fieldlist *) + obstack_alloc (&dynamics_objfile->symbol_obstack, j); + memcpy (TYPE_FN_FIELDLISTS (type), fn_fieldlists, j); + + return type; +} + +static struct type *java_object_type; + +struct type * +get_java_object_type (void) +{ + if (java_object_type == NULL) + { + struct symbol *sym; + sym = lookup_symbol ("java.lang.Object", NULL, STRUCT_NAMESPACE, + (int *) 0, (struct symtab **) NULL); + if (sym == NULL) + error ("cannot find java.lang.Object"); + java_object_type = SYMBOL_TYPE (sym); + } + return java_object_type; +} + +int +get_java_object_header_size (void) +{ + struct type *objtype = get_java_object_type (); + if (objtype == NULL) + return (2 * TARGET_PTR_BIT / TARGET_CHAR_BIT); + else + return TYPE_LENGTH (objtype); +} + +int +is_object_type (struct type *type) +{ + CHECK_TYPEDEF (type); + if (TYPE_CODE (type) == TYPE_CODE_PTR) + { + struct type *ttype = check_typedef (TYPE_TARGET_TYPE (type)); + char *name; + if (TYPE_CODE (ttype) != TYPE_CODE_STRUCT) + return 0; + while (TYPE_N_BASECLASSES (ttype) > 0) + ttype = TYPE_BASECLASS (ttype, 0); + name = TYPE_TAG_NAME (ttype); + if (name != NULL && strcmp (name, "java.lang.Object") == 0) + return 1; + name = TYPE_NFIELDS (ttype) > 0 ? TYPE_FIELD_NAME (ttype, 0) : (char *) 0; + if (name != NULL && strcmp (name, "vtable") == 0) + { + if (java_object_type == NULL) + java_object_type = type; + return 1; + } + } + return 0; +} + +struct type * +java_primitive_type (int signature) +{ + switch (signature) + { + case 'B': + return java_byte_type; + case 'S': + return java_short_type; + case 'I': + return java_int_type; + case 'J': + return java_long_type; + case 'Z': + return java_boolean_type; + case 'C': + return java_char_type; + case 'F': + return java_float_type; + case 'D': + return java_double_type; + case 'V': + return java_void_type; + } + error ("unknown signature '%c' for primitive type", (char) signature); +} + +/* If name[0 .. namelen-1] is the name of a primitive Java type, + return that type. Otherwise, return NULL. */ + +struct type * +java_primitive_type_from_name (char *name, int namelen) +{ + switch (name[0]) + { + case 'b': + if (namelen == 4 && memcmp (name, "byte", 4) == 0) + return java_byte_type; + if (namelen == 7 && memcmp (name, "boolean", 7) == 0) + return java_boolean_type; + break; + case 'c': + if (namelen == 4 && memcmp (name, "char", 4) == 0) + return java_char_type; + case 'd': + if (namelen == 6 && memcmp (name, "double", 6) == 0) + return java_double_type; + break; + case 'f': + if (namelen == 5 && memcmp (name, "float", 5) == 0) + return java_float_type; + break; + case 'i': + if (namelen == 3 && memcmp (name, "int", 3) == 0) + return java_int_type; + break; + case 'l': + if (namelen == 4 && memcmp (name, "long", 4) == 0) + return java_long_type; + break; + case 's': + if (namelen == 5 && memcmp (name, "short", 5) == 0) + return java_short_type; + break; + case 'v': + if (namelen == 4 && memcmp (name, "void", 4) == 0) + return java_void_type; + break; + } + return NULL; +} + +/* Return the length (in bytes) of demangled name of the Java type + signature string SIGNATURE. */ + +static int +java_demangled_signature_length (char *signature) +{ + int array = 0; + for (; *signature == '['; signature++) + array += 2; /* Two chars for "[]". */ + switch (signature[0]) + { + case 'L': + /* Subtract 2 for 'L' and ';'. */ + return strlen (signature) - 2 + array; + default: + return strlen (TYPE_NAME (java_primitive_type (signature[0]))) + array; + } +} + +/* Demangle the Java type signature SIGNATURE, leaving the result in RESULT. */ + +static void +java_demangled_signature_copy (char *result, char *signature) +{ + int array = 0; + char *ptr; + int i; + while (*signature == '[') + { + array++; + signature++; + } + switch (signature[0]) + { + case 'L': + /* Subtract 2 for 'L' and ';', but add 1 for final nul. */ + signature++; + ptr = result; + for (; *signature != ';' && *signature != '\0'; signature++) + { + if (*signature == '/') + *ptr++ = '.'; + else + *ptr++ = *signature; + } + break; + default: + ptr = TYPE_NAME (java_primitive_type (signature[0])); + i = strlen (ptr); + strcpy (result, ptr); + ptr = result + i; + break; + } + while (--array >= 0) + { + *ptr++ = '['; + *ptr++ = ']'; + } +} + +/* Return the demangled name of the Java type signature string SIGNATURE, + as a freshly allocated copy. */ + +char * +java_demangle_type_signature (char *signature) +{ + int length = java_demangled_signature_length (signature); + char *result = xmalloc (length + 1); + java_demangled_signature_copy (result, signature); + result[length] = '\0'; + return result; +} + +struct type * +java_lookup_type (char *signature) +{ + switch (signature[0]) + { + case 'L': + case '[': + error ("java_lookup_type not fully implemented"); + default: + return java_primitive_type (signature[0]); + } +} + +/* Return the type of TYPE followed by DIMS pairs of [ ]. + If DIMS == 0, TYPE is returned. */ + +struct type * +java_array_type (struct type *type, int dims) +{ + struct type *range_type; + + while (dims-- > 0) + { + range_type = create_range_type (NULL, builtin_type_int, 0, 0); + /* FIXME This is bogus! Java arrays are not gdb arrays! */ + type = create_array_type (NULL, type, range_type); + } + + return type; +} + +/* Create a Java string in the inferior from a (Utf8) literal. */ + +static struct value * +java_value_string (char *ptr, int len) +{ + error ("not implemented - java_value_string"); /* FIXME */ +} + +/* Print the character C on STREAM as part of the contents of a literal + string whose delimiter is QUOTER. Note that that format for printing + characters and strings is language specific. */ + +static void +java_emit_char (int c, struct ui_file *stream, int quoter) +{ + switch (c) + { + case '\\': + case '\'': + fprintf_filtered (stream, "\\%c", c); + break; + case '\b': + fputs_filtered ("\\b", stream); + break; + case '\t': + fputs_filtered ("\\t", stream); + break; + case '\n': + fputs_filtered ("\\n", stream); + break; + case '\f': + fputs_filtered ("\\f", stream); + break; + case '\r': + fputs_filtered ("\\r", stream); + break; + default: + if (isprint (c)) + fputc_filtered (c, stream); + else + fprintf_filtered (stream, "\\u%.4x", (unsigned int) c); + break; + } +} + +static struct value * +evaluate_subexp_java (struct type *expect_type, register struct expression *exp, + register int *pos, enum noside noside) +{ + int pc = *pos; + int i; + char *name; + enum exp_opcode op = exp->elts[*pos].opcode; + struct value *arg1; + struct value *arg2; + struct type *type; + switch (op) + { + case UNOP_IND: + if (noside == EVAL_SKIP) + goto standard; + (*pos)++; + arg1 = evaluate_subexp_java (NULL_TYPE, exp, pos, EVAL_NORMAL); + if (is_object_type (VALUE_TYPE (arg1))) + { + struct type *type; + + type = type_from_class (java_class_from_object (arg1)); + arg1 = value_cast (lookup_pointer_type (type), arg1); + } + if (noside == EVAL_SKIP) + goto nosideret; + return value_ind (arg1); + + case BINOP_SUBSCRIPT: + (*pos)++; + arg1 = evaluate_subexp_with_coercion (exp, pos, noside); + arg2 = evaluate_subexp_with_coercion (exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + /* If the user attempts to subscript something that is not an + array or pointer type (like a plain int variable for example), + then report this as an error. */ + + COERCE_REF (arg1); + type = check_typedef (VALUE_TYPE (arg1)); + if (TYPE_CODE (type) == TYPE_CODE_PTR) + type = check_typedef (TYPE_TARGET_TYPE (type)); + name = TYPE_NAME (type); + if (name == NULL) + name = TYPE_TAG_NAME (type); + i = name == NULL ? 0 : strlen (name); + if (TYPE_CODE (type) == TYPE_CODE_STRUCT + && i > 2 && name[i - 1] == ']') + { + CORE_ADDR address; + long length, index; + struct type *el_type; + char buf4[4]; + + struct value *clas = java_class_from_object (arg1); + struct value *temp = clas; + /* Get CLASS_ELEMENT_TYPE of the array type. */ + temp = value_struct_elt (&temp, NULL, "methods", + NULL, "structure"); + VALUE_TYPE (temp) = VALUE_TYPE (clas); + el_type = type_from_class (temp); + if (TYPE_CODE (el_type) == TYPE_CODE_STRUCT) + el_type = lookup_pointer_type (el_type); + + if (noside == EVAL_AVOID_SIDE_EFFECTS) + return value_zero (el_type, VALUE_LVAL (arg1)); + address = value_as_address (arg1); + address += JAVA_OBJECT_SIZE; + read_memory (address, buf4, 4); + length = (long) extract_signed_integer (buf4, 4); + index = (long) value_as_long (arg2); + if (index >= length || index < 0) + error ("array index (%ld) out of bounds (length: %ld)", + index, length); + address = (address + 4) + index * TYPE_LENGTH (el_type); + return value_at (el_type, address, NULL); + } + else if (TYPE_CODE (type) == TYPE_CODE_ARRAY) + { + if (noside == EVAL_AVOID_SIDE_EFFECTS) + return value_zero (TYPE_TARGET_TYPE (type), VALUE_LVAL (arg1)); + else + return value_subscript (arg1, arg2); + } + if (name) + error ("cannot subscript something of type `%s'", name); + else + error ("cannot subscript requested type"); + + case OP_STRING: + (*pos)++; + i = longest_to_int (exp->elts[pc + 1].longconst); + (*pos) += 3 + BYTES_TO_EXP_ELEM (i + 1); + if (noside == EVAL_SKIP) + goto nosideret; + return java_value_string (&exp->elts[pc + 2].string, i); + + case STRUCTOP_STRUCT: + arg1 = evaluate_subexp_standard (expect_type, exp, pos, noside); + /* Convert object field (such as TYPE.class) to reference. */ + if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_STRUCT) + arg1 = value_addr (arg1); + return arg1; + default: + break; + } +standard: + return evaluate_subexp_standard (expect_type, exp, pos, noside); +nosideret: + return value_from_longest (builtin_type_long, (LONGEST) 1); +} + +static struct type * +java_create_fundamental_type (struct objfile *objfile, int typeid) +{ + switch (typeid) + { + case FT_VOID: + return java_void_type; + case FT_BOOLEAN: + return java_boolean_type; + case FT_CHAR: + return java_char_type; + case FT_FLOAT: + return java_float_type; + case FT_DBL_PREC_FLOAT: + return java_double_type; + case FT_BYTE: + case FT_SIGNED_CHAR: + return java_byte_type; + case FT_SHORT: + case FT_SIGNED_SHORT: + return java_short_type; + case FT_INTEGER: + case FT_SIGNED_INTEGER: + return java_int_type; + case FT_LONG: + case FT_SIGNED_LONG: + return java_long_type; + } + return c_create_fundamental_type (objfile, typeid); +} + +/* Table mapping opcodes into strings for printing operators + and precedences of the operators. */ + +const struct op_print java_op_print_tab[] = +{ + {",", BINOP_COMMA, PREC_COMMA, 0}, + {"=", BINOP_ASSIGN, PREC_ASSIGN, 1}, + {"||", BINOP_LOGICAL_OR, PREC_LOGICAL_OR, 0}, + {"&&", BINOP_LOGICAL_AND, PREC_LOGICAL_AND, 0}, + {"|", BINOP_BITWISE_IOR, PREC_BITWISE_IOR, 0}, + {"^", BINOP_BITWISE_XOR, PREC_BITWISE_XOR, 0}, + {"&", BINOP_BITWISE_AND, PREC_BITWISE_AND, 0}, + {"==", BINOP_EQUAL, PREC_EQUAL, 0}, + {"!=", BINOP_NOTEQUAL, PREC_EQUAL, 0}, + {"<=", BINOP_LEQ, PREC_ORDER, 0}, + {">=", BINOP_GEQ, PREC_ORDER, 0}, + {">", BINOP_GTR, PREC_ORDER, 0}, + {"<", BINOP_LESS, PREC_ORDER, 0}, + {">>", BINOP_RSH, PREC_SHIFT, 0}, + {"<<", BINOP_LSH, PREC_SHIFT, 0}, +#if 0 + {">>>", BINOP_ ? ? ?, PREC_SHIFT, 0}, +#endif + {"+", BINOP_ADD, PREC_ADD, 0}, + {"-", BINOP_SUB, PREC_ADD, 0}, + {"*", BINOP_MUL, PREC_MUL, 0}, + {"/", BINOP_DIV, PREC_MUL, 0}, + {"%", BINOP_REM, PREC_MUL, 0}, + {"-", UNOP_NEG, PREC_PREFIX, 0}, + {"!", UNOP_LOGICAL_NOT, PREC_PREFIX, 0}, + {"~", UNOP_COMPLEMENT, PREC_PREFIX, 0}, + {"*", UNOP_IND, PREC_PREFIX, 0}, +#if 0 + {"instanceof", ? ? ?, ? ? ?, 0}, +#endif + {"++", UNOP_PREINCREMENT, PREC_PREFIX, 0}, + {"--", UNOP_PREDECREMENT, PREC_PREFIX, 0}, + {NULL, 0, 0, 0} +}; + +const struct language_defn java_language_defn = +{ + "java", /* Language name */ + language_java, + c_builtin_types, + range_check_off, + type_check_off, + case_sensitive_on, + java_parse, + java_error, + evaluate_subexp_java, + c_printchar, /* Print a character constant */ + c_printstr, /* Function to print string constant */ + java_emit_char, /* Function to print a single character */ + java_create_fundamental_type, /* Create fundamental type in this language */ + java_print_type, /* Print a type using appropriate syntax */ + java_val_print, /* Print a value using appropriate syntax */ + java_value_print, /* Print a top-level value */ + {"", "", "", ""}, /* Binary format info */ + {"0%lo", "0", "o", ""}, /* Octal format info */ + {"%ld", "", "d", ""}, /* Decimal format info */ + {"0x%lx", "0x", "x", ""}, /* Hex format info */ + java_op_print_tab, /* expression operators for printing */ + 0, /* not c-style arrays */ + 0, /* String lower bound */ + &builtin_type_char, /* Type of string elements */ + LANG_MAGIC +}; + +void +_initialize_java_language (void) +{ + + java_int_type = init_type (TYPE_CODE_INT, 4, 0, "int", NULL); + java_short_type = init_type (TYPE_CODE_INT, 2, 0, "short", NULL); + java_long_type = init_type (TYPE_CODE_INT, 8, 0, "long", NULL); + java_byte_type = init_type (TYPE_CODE_INT, 1, 0, "byte", NULL); + java_boolean_type = init_type (TYPE_CODE_BOOL, 1, 0, "boolean", NULL); + java_char_type = init_type (TYPE_CODE_CHAR, 2, TYPE_FLAG_UNSIGNED, "char", NULL); + java_float_type = init_type (TYPE_CODE_FLT, 4, 0, "float", NULL); + java_double_type = init_type (TYPE_CODE_FLT, 8, 0, "double", NULL); + java_void_type = init_type (TYPE_CODE_VOID, 1, 0, "void", NULL); + + add_language (&java_language_defn); +} + +/* Cleanup code that should be run on every "run". + We should use make_run_cleanup to have this be called. + But will that mess up values in value histry? FIXME */ + +extern void java_rerun_cleanup (void); +void +java_rerun_cleanup (void) +{ + if (class_symtab != NULL) + { + free_symtab (class_symtab); /* ??? */ + class_symtab = NULL; + } + if (dynamics_objfile != NULL) + { + free_objfile (dynamics_objfile); + dynamics_objfile = NULL; + } + + java_object_type = NULL; +} diff --git a/gdb/symmisc.c b/gdb/symmisc.c new file mode 100644 index 0000000..198b2d6 --- /dev/null +++ b/gdb/symmisc.c @@ -0,0 +1,1087 @@ +/* Do various things to symbol tables (other than lookup), for GDB. + + Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, + 1995, 1996, 1997, 1998, 1999, 2000, 2002 Free Software Foundation, + Inc. + + This file is part of GDB. + + 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 of the License, 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. */ + +#include "defs.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "bfd.h" +#include "symfile.h" +#include "objfiles.h" +#include "breakpoint.h" +#include "command.h" +#include "gdb_obstack.h" +#include "language.h" +#include "bcache.h" + +#include "gdb_string.h" + +#ifndef DEV_TTY +#define DEV_TTY "/dev/tty" +#endif + +/* Unfortunately for debugging, stderr is usually a macro. This is painful + when calling functions that take FILE *'s from the debugger. + So we make a variable which has the same value and which is accessible when + debugging GDB with itself. Because stdin et al need not be constants, + we initialize them in the _initialize_symmisc function at the bottom + of the file. */ +FILE *std_in; +FILE *std_out; +FILE *std_err; + +/* Prototypes for local functions */ + +static void dump_symtab (struct objfile *, struct symtab *, + struct ui_file *); + +static void dump_psymtab (struct objfile *, struct partial_symtab *, + struct ui_file *); + +static void dump_msymbols (struct objfile *, struct ui_file *); + +static void dump_objfile (struct objfile *); + +static int block_depth (struct block *); + +static void print_partial_symbols (struct partial_symbol **, int, + char *, struct ui_file *); + +static void free_symtab_block (struct objfile *, struct block *); + +void _initialize_symmisc (void); + +struct print_symbol_args + { + struct symbol *symbol; + int depth; + struct ui_file *outfile; + }; + +static int print_symbol (PTR); + +static void free_symtab_block (struct objfile *, struct block *); + + +/* Free a struct block <- B and all the symbols defined in that block. */ + +static void +free_symtab_block (struct objfile *objfile, struct block *b) +{ + register int i, n; + struct symbol *sym, *next_sym; + + n = BLOCK_BUCKETS (b); + for (i = 0; i < n; i++) + { + for (sym = BLOCK_BUCKET (b, i); sym; sym = next_sym) + { + next_sym = sym->hash_next; + xmfree (objfile->md, SYMBOL_NAME (sym)); + xmfree (objfile->md, (PTR) sym); + } + } + xmfree (objfile->md, (PTR) b); +} + +/* Free all the storage associated with the struct symtab <- S. + Note that some symtabs have contents malloc'ed structure by structure, + while some have contents that all live inside one big block of memory, + and some share the contents of another symbol table and so you should + not free the contents on their behalf (except sometimes the linetable, + which maybe per symtab even when the rest is not). + It is s->free_code that says which alternative to use. */ + +void +free_symtab (register struct symtab *s) +{ + register int i, n; + register struct blockvector *bv; + + switch (s->free_code) + { + case free_nothing: + /* All the contents are part of a big block of memory (an obstack), + and some other symtab is in charge of freeing that block. + Therefore, do nothing. */ + break; + + case free_contents: + /* Here all the contents were malloc'ed structure by structure + and must be freed that way. */ + /* First free the blocks (and their symbols. */ + bv = BLOCKVECTOR (s); + n = BLOCKVECTOR_NBLOCKS (bv); + for (i = 0; i < n; i++) + free_symtab_block (s->objfile, BLOCKVECTOR_BLOCK (bv, i)); + /* Free the blockvector itself. */ + xmfree (s->objfile->md, (PTR) bv); + /* Also free the linetable. */ + + case free_linetable: + /* Everything will be freed either by our `free_ptr' + or by some other symtab, except for our linetable. + Free that now. */ + if (LINETABLE (s)) + xmfree (s->objfile->md, (PTR) LINETABLE (s)); + break; + } + + /* If there is a single block of memory to free, free it. */ + if (s->free_ptr != NULL) + xmfree (s->objfile->md, s->free_ptr); + + /* Free source-related stuff */ + if (s->line_charpos != NULL) + xmfree (s->objfile->md, (PTR) s->line_charpos); + if (s->fullname != NULL) + xmfree (s->objfile->md, s->fullname); + if (s->debugformat != NULL) + xmfree (s->objfile->md, s->debugformat); + xmfree (s->objfile->md, (PTR) s); +} + +void +print_symbol_bcache_statistics (void) +{ + struct objfile *objfile; + + immediate_quit++; + ALL_OBJFILES (objfile) + { + printf_filtered ("Byte cache statistics for '%s':\n", objfile->name); + print_bcache_statistics (objfile->psymbol_cache, "partial symbol cache"); + } + immediate_quit--; +} + +void +print_objfile_statistics (void) +{ + struct objfile *objfile; + + immediate_quit++; + ALL_OBJFILES (objfile) + { + printf_filtered ("Statistics for '%s':\n", objfile->name); + if (OBJSTAT (objfile, n_stabs) > 0) + printf_filtered (" Number of \"stab\" symbols read: %d\n", + OBJSTAT (objfile, n_stabs)); + if (OBJSTAT (objfile, n_minsyms) > 0) + printf_filtered (" Number of \"minimal\" symbols read: %d\n", + OBJSTAT (objfile, n_minsyms)); + if (OBJSTAT (objfile, n_psyms) > 0) + printf_filtered (" Number of \"partial\" symbols read: %d\n", + OBJSTAT (objfile, n_psyms)); + if (OBJSTAT (objfile, n_syms) > 0) + printf_filtered (" Number of \"full\" symbols read: %d\n", + OBJSTAT (objfile, n_syms)); + if (OBJSTAT (objfile, n_types) > 0) + printf_filtered (" Number of \"types\" defined: %d\n", + OBJSTAT (objfile, n_types)); + if (OBJSTAT (objfile, sz_strtab) > 0) + printf_filtered (" Space used by a.out string tables: %d\n", + OBJSTAT (objfile, sz_strtab)); + printf_filtered (" Total memory used for psymbol obstack: %d\n", + obstack_memory_used (&objfile->psymbol_obstack)); + printf_filtered (" Total memory used for psymbol cache: %d\n", + bcache_memory_used (objfile->psymbol_cache)); + printf_filtered (" Total memory used for macro cache: %d\n", + bcache_memory_used (objfile->macro_cache)); + printf_filtered (" Total memory used for symbol obstack: %d\n", + obstack_memory_used (&objfile->symbol_obstack)); + printf_filtered (" Total memory used for type obstack: %d\n", + obstack_memory_used (&objfile->type_obstack)); + } + immediate_quit--; +} + +static void +dump_objfile (struct objfile *objfile) +{ + struct symtab *symtab; + struct partial_symtab *psymtab; + + printf_filtered ("\nObject file %s: ", objfile->name); + printf_filtered ("Objfile at "); + gdb_print_host_address (objfile, gdb_stdout); + printf_filtered (", bfd at "); + gdb_print_host_address (objfile->obfd, gdb_stdout); + printf_filtered (", %d minsyms\n\n", + objfile->minimal_symbol_count); + + if (objfile->psymtabs) + { + printf_filtered ("Psymtabs:\n"); + for (psymtab = objfile->psymtabs; + psymtab != NULL; + psymtab = psymtab->next) + { + printf_filtered ("%s at ", + psymtab->filename); + gdb_print_host_address (psymtab, gdb_stdout); + printf_filtered (", "); + if (psymtab->objfile != objfile) + { + printf_filtered ("NOT ON CHAIN! "); + } + wrap_here (" "); + } + printf_filtered ("\n\n"); + } + + if (objfile->symtabs) + { + printf_filtered ("Symtabs:\n"); + for (symtab = objfile->symtabs; + symtab != NULL; + symtab = symtab->next) + { + printf_filtered ("%s at ", symtab->filename); + gdb_print_host_address (symtab, gdb_stdout); + printf_filtered (", "); + if (symtab->objfile != objfile) + { + printf_filtered ("NOT ON CHAIN! "); + } + wrap_here (" "); + } + printf_filtered ("\n\n"); + } +} + +/* Print minimal symbols from this objfile. */ + +static void +dump_msymbols (struct objfile *objfile, struct ui_file *outfile) +{ + struct minimal_symbol *msymbol; + int index; + char ms_type; + + fprintf_filtered (outfile, "\nObject file %s:\n\n", objfile->name); + if (objfile->minimal_symbol_count == 0) + { + fprintf_filtered (outfile, "No minimal symbols found.\n"); + return; + } + for (index = 0, msymbol = objfile->msymbols; + SYMBOL_NAME (msymbol) != NULL; msymbol++, index++) + { + switch (msymbol->type) + { + case mst_unknown: + ms_type = 'u'; + break; + case mst_text: + ms_type = 'T'; + break; + case mst_solib_trampoline: + ms_type = 'S'; + break; + case mst_data: + ms_type = 'D'; + break; + case mst_bss: + ms_type = 'B'; + break; + case mst_abs: + ms_type = 'A'; + break; + case mst_file_text: + ms_type = 't'; + break; + case mst_file_data: + ms_type = 'd'; + break; + case mst_file_bss: + ms_type = 'b'; + break; + default: + ms_type = '?'; + break; + } + fprintf_filtered (outfile, "[%2d] %c ", index, ms_type); + print_address_numeric (SYMBOL_VALUE_ADDRESS (msymbol), 1, outfile); + fprintf_filtered (outfile, " %s", SYMBOL_NAME (msymbol)); + if (SYMBOL_BFD_SECTION (msymbol)) + fprintf_filtered (outfile, " section %s", + bfd_section_name (objfile->obfd, + SYMBOL_BFD_SECTION (msymbol))); + if (SYMBOL_DEMANGLED_NAME (msymbol) != NULL) + { + fprintf_filtered (outfile, " %s", SYMBOL_DEMANGLED_NAME (msymbol)); + } +#ifdef SOFUN_ADDRESS_MAYBE_MISSING + if (msymbol->filename) + fprintf_filtered (outfile, " %s", msymbol->filename); +#endif + fputs_filtered ("\n", outfile); + } + if (objfile->minimal_symbol_count != index) + { + warning ("internal error: minimal symbol count %d != %d", + objfile->minimal_symbol_count, index); + } + fprintf_filtered (outfile, "\n"); +} + +static void +dump_psymtab (struct objfile *objfile, struct partial_symtab *psymtab, + struct ui_file *outfile) +{ + int i; + + fprintf_filtered (outfile, "\nPartial symtab for source file %s ", + psymtab->filename); + fprintf_filtered (outfile, "(object "); + gdb_print_host_address (psymtab, outfile); + fprintf_filtered (outfile, ")\n\n"); + fprintf_unfiltered (outfile, " Read from object file %s (", + objfile->name); + gdb_print_host_address (objfile, outfile); + fprintf_unfiltered (outfile, ")\n"); + + if (psymtab->readin) + { + fprintf_filtered (outfile, + " Full symtab was read (at "); + gdb_print_host_address (psymtab->symtab, outfile); + fprintf_filtered (outfile, " by function at "); + gdb_print_host_address ((PTR) psymtab->read_symtab, outfile); + fprintf_filtered (outfile, ")\n"); + } + + fprintf_filtered (outfile, " Relocate symbols by "); + for (i = 0; i < psymtab->objfile->num_sections; ++i) + { + if (i != 0) + fprintf_filtered (outfile, ", "); + wrap_here (" "); + print_address_numeric (ANOFFSET (psymtab->section_offsets, i), + 1, + outfile); + } + fprintf_filtered (outfile, "\n"); + + fprintf_filtered (outfile, " Symbols cover text addresses "); + print_address_numeric (psymtab->textlow, 1, outfile); + fprintf_filtered (outfile, "-"); + print_address_numeric (psymtab->texthigh, 1, outfile); + fprintf_filtered (outfile, "\n"); + fprintf_filtered (outfile, " Depends on %d other partial symtabs.\n", + psymtab->number_of_dependencies); + for (i = 0; i < psymtab->number_of_dependencies; i++) + { + fprintf_filtered (outfile, " %d ", i); + gdb_print_host_address (psymtab->dependencies[i], outfile); + fprintf_filtered (outfile, " %s\n", + psymtab->dependencies[i]->filename); + } + if (psymtab->n_global_syms > 0) + { + print_partial_symbols (objfile->global_psymbols.list + + psymtab->globals_offset, + psymtab->n_global_syms, "Global", outfile); + } + if (psymtab->n_static_syms > 0) + { + print_partial_symbols (objfile->static_psymbols.list + + psymtab->statics_offset, + psymtab->n_static_syms, "Static", outfile); + } + fprintf_filtered (outfile, "\n"); +} + +static void +dump_symtab (struct objfile *objfile, struct symtab *symtab, + struct ui_file *outfile) +{ + register int i, j; + int len, blen; + register struct linetable *l; + struct blockvector *bv; + struct symbol *sym; + register struct block *b; + int depth; + + fprintf_filtered (outfile, "\nSymtab for file %s\n", symtab->filename); + if (symtab->dirname) + fprintf_filtered (outfile, "Compilation directory is %s\n", + symtab->dirname); + fprintf_filtered (outfile, "Read from object file %s (", objfile->name); + gdb_print_host_address (objfile, outfile); + fprintf_filtered (outfile, ")\n"); + fprintf_filtered (outfile, "Language: %s\n", language_str (symtab->language)); + + /* First print the line table. */ + l = LINETABLE (symtab); + if (l) + { + fprintf_filtered (outfile, "\nLine table:\n\n"); + len = l->nitems; + for (i = 0; i < len; i++) + { + fprintf_filtered (outfile, " line %d at ", l->item[i].line); + print_address_numeric (l->item[i].pc, 1, outfile); + fprintf_filtered (outfile, "\n"); + } + } + /* Now print the block info, but only for primary symtabs since we will + print lots of duplicate info otherwise. */ + if (symtab->primary) + { + fprintf_filtered (outfile, "\nBlockvector:\n\n"); + bv = BLOCKVECTOR (symtab); + len = BLOCKVECTOR_NBLOCKS (bv); + for (i = 0; i < len; i++) + { + b = BLOCKVECTOR_BLOCK (bv, i); + depth = block_depth (b) * 2; + print_spaces (depth, outfile); + fprintf_filtered (outfile, "block #%03d, object at ", i); + gdb_print_host_address (b, outfile); + if (BLOCK_SUPERBLOCK (b)) + { + fprintf_filtered (outfile, " under "); + gdb_print_host_address (BLOCK_SUPERBLOCK (b), outfile); + } + /* drow/2002-07-10: We could save the total symbols count + even if we're using a hashtable, but nothing else but this message + wants it. */ + blen = BLOCK_BUCKETS (b); + if (BLOCK_HASHTABLE (b)) + fprintf_filtered (outfile, ", %d buckets in ", blen); + else + fprintf_filtered (outfile, ", %d syms in ", blen); + print_address_numeric (BLOCK_START (b), 1, outfile); + fprintf_filtered (outfile, ".."); + print_address_numeric (BLOCK_END (b), 1, outfile); + if (BLOCK_FUNCTION (b)) + { + fprintf_filtered (outfile, ", function %s", SYMBOL_NAME (BLOCK_FUNCTION (b))); + if (SYMBOL_DEMANGLED_NAME (BLOCK_FUNCTION (b)) != NULL) + { + fprintf_filtered (outfile, ", %s", + SYMBOL_DEMANGLED_NAME (BLOCK_FUNCTION (b))); + } + } + if (BLOCK_GCC_COMPILED (b)) + fprintf_filtered (outfile, ", compiled with gcc%d", BLOCK_GCC_COMPILED (b)); + fprintf_filtered (outfile, "\n"); + /* Now print each symbol in this block (in no particular order, if + we're using a hashtable). */ + ALL_BLOCK_SYMBOLS (b, j, sym) + { + struct print_symbol_args s; + s.symbol = sym; + s.depth = depth + 1; + s.outfile = outfile; + catch_errors (print_symbol, &s, "Error printing symbol:\n", + RETURN_MASK_ALL); + } + } + fprintf_filtered (outfile, "\n"); + } + else + { + fprintf_filtered (outfile, "\nBlockvector same as previous symtab\n\n"); + } +} + +void +maintenance_print_symbols (char *args, int from_tty) +{ + char **argv; + struct ui_file *outfile; + struct cleanup *cleanups; + char *symname = NULL; + char *filename = DEV_TTY; + struct objfile *objfile; + struct symtab *s; + + dont_repeat (); + + if (args == NULL) + { + error ("\ +Arguments missing: an output file name and an optional symbol file name"); + } + else if ((argv = buildargv (args)) == NULL) + { + nomem (0); + } + cleanups = make_cleanup_freeargv (argv); + + if (argv[0] != NULL) + { + filename = argv[0]; + /* If a second arg is supplied, it is a source file name to match on */ + if (argv[1] != NULL) + { + symname = argv[1]; + } + } + + filename = tilde_expand (filename); + make_cleanup (xfree, filename); + + outfile = gdb_fopen (filename, FOPEN_WT); + if (outfile == 0) + perror_with_name (filename); + make_cleanup_ui_file_delete (outfile); + + immediate_quit++; + ALL_SYMTABS (objfile, s) + if (symname == NULL || (STREQ (symname, s->filename))) + dump_symtab (objfile, s, outfile); + immediate_quit--; + do_cleanups (cleanups); +} + +/* Print symbol ARGS->SYMBOL on ARGS->OUTFILE. ARGS->DEPTH says how + far to indent. ARGS is really a struct print_symbol_args *, but is + declared as char * to get it past catch_errors. Returns 0 for error, + 1 for success. */ + +static int +print_symbol (PTR args) +{ + struct symbol *symbol = ((struct print_symbol_args *) args)->symbol; + int depth = ((struct print_symbol_args *) args)->depth; + struct ui_file *outfile = ((struct print_symbol_args *) args)->outfile; + + print_spaces (depth, outfile); + if (SYMBOL_NAMESPACE (symbol) == LABEL_NAMESPACE) + { + fprintf_filtered (outfile, "label %s at ", SYMBOL_SOURCE_NAME (symbol)); + print_address_numeric (SYMBOL_VALUE_ADDRESS (symbol), 1, outfile); + if (SYMBOL_BFD_SECTION (symbol)) + fprintf_filtered (outfile, " section %s\n", + bfd_section_name (SYMBOL_BFD_SECTION (symbol)->owner, + SYMBOL_BFD_SECTION (symbol))); + else + fprintf_filtered (outfile, "\n"); + return 1; + } + if (SYMBOL_NAMESPACE (symbol) == STRUCT_NAMESPACE) + { + if (TYPE_TAG_NAME (SYMBOL_TYPE (symbol))) + { + LA_PRINT_TYPE (SYMBOL_TYPE (symbol), "", outfile, 1, depth); + } + else + { + fprintf_filtered (outfile, "%s %s = ", + (TYPE_CODE (SYMBOL_TYPE (symbol)) == TYPE_CODE_ENUM + ? "enum" + : (TYPE_CODE (SYMBOL_TYPE (symbol)) == TYPE_CODE_STRUCT + ? "struct" : "union")), + SYMBOL_NAME (symbol)); + LA_PRINT_TYPE (SYMBOL_TYPE (symbol), "", outfile, 1, depth); + } + fprintf_filtered (outfile, ";\n"); + } + else + { + if (SYMBOL_CLASS (symbol) == LOC_TYPEDEF) + fprintf_filtered (outfile, "typedef "); + if (SYMBOL_TYPE (symbol)) + { + /* Print details of types, except for enums where it's clutter. */ + LA_PRINT_TYPE (SYMBOL_TYPE (symbol), SYMBOL_SOURCE_NAME (symbol), + outfile, + TYPE_CODE (SYMBOL_TYPE (symbol)) != TYPE_CODE_ENUM, + depth); + fprintf_filtered (outfile, "; "); + } + else + fprintf_filtered (outfile, "%s ", SYMBOL_SOURCE_NAME (symbol)); + + switch (SYMBOL_CLASS (symbol)) + { + case LOC_CONST: + fprintf_filtered (outfile, "const %ld (0x%lx)", + SYMBOL_VALUE (symbol), + SYMBOL_VALUE (symbol)); + break; + + case LOC_CONST_BYTES: + { + unsigned i; + struct type *type = check_typedef (SYMBOL_TYPE (symbol)); + fprintf_filtered (outfile, "const %u hex bytes:", + TYPE_LENGTH (type)); + for (i = 0; i < TYPE_LENGTH (type); i++) + fprintf_filtered (outfile, " %02x", + (unsigned) SYMBOL_VALUE_BYTES (symbol)[i]); + } + break; + + case LOC_STATIC: + fprintf_filtered (outfile, "static at "); + print_address_numeric (SYMBOL_VALUE_ADDRESS (symbol), 1, outfile); + if (SYMBOL_BFD_SECTION (symbol)) + fprintf_filtered (outfile, " section %s", + bfd_section_name + (SYMBOL_BFD_SECTION (symbol)->owner, + SYMBOL_BFD_SECTION (symbol))); + break; + + case LOC_INDIRECT: + fprintf_filtered (outfile, "extern global at *("); + print_address_numeric (SYMBOL_VALUE_ADDRESS (symbol), 1, outfile); + fprintf_filtered (outfile, "),"); + break; + + case LOC_REGISTER: + fprintf_filtered (outfile, "register %ld", SYMBOL_VALUE (symbol)); + break; + + case LOC_ARG: + fprintf_filtered (outfile, "arg at offset 0x%lx", + SYMBOL_VALUE (symbol)); + break; + + case LOC_LOCAL_ARG: + fprintf_filtered (outfile, "arg at offset 0x%lx from fp", + SYMBOL_VALUE (symbol)); + break; + + case LOC_REF_ARG: + fprintf_filtered (outfile, "reference arg at 0x%lx", SYMBOL_VALUE (symbol)); + break; + + case LOC_REGPARM: + fprintf_filtered (outfile, "parameter register %ld", SYMBOL_VALUE (symbol)); + break; + + case LOC_REGPARM_ADDR: + fprintf_filtered (outfile, "address parameter register %ld", SYMBOL_VALUE (symbol)); + break; + + case LOC_LOCAL: + fprintf_filtered (outfile, "local at offset 0x%lx", + SYMBOL_VALUE (symbol)); + break; + + case LOC_BASEREG: + fprintf_filtered (outfile, "local at 0x%lx from register %d", + SYMBOL_VALUE (symbol), SYMBOL_BASEREG (symbol)); + break; + + case LOC_BASEREG_ARG: + fprintf_filtered (outfile, "arg at 0x%lx from register %d", + SYMBOL_VALUE (symbol), SYMBOL_BASEREG (symbol)); + break; + + case LOC_TYPEDEF: + break; + + case LOC_LABEL: + fprintf_filtered (outfile, "label at "); + print_address_numeric (SYMBOL_VALUE_ADDRESS (symbol), 1, outfile); + if (SYMBOL_BFD_SECTION (symbol)) + fprintf_filtered (outfile, " section %s", + bfd_section_name + (SYMBOL_BFD_SECTION (symbol)->owner, + SYMBOL_BFD_SECTION (symbol))); + break; + + case LOC_BLOCK: + fprintf_filtered (outfile, "block object "); + gdb_print_host_address (SYMBOL_BLOCK_VALUE (symbol), outfile); + fprintf_filtered (outfile, ", "); + print_address_numeric (BLOCK_START (SYMBOL_BLOCK_VALUE (symbol)), + 1, + outfile); + fprintf_filtered (outfile, ".."); + print_address_numeric (BLOCK_END (SYMBOL_BLOCK_VALUE (symbol)), + 1, + outfile); + if (SYMBOL_BFD_SECTION (symbol)) + fprintf_filtered (outfile, " section %s", + bfd_section_name + (SYMBOL_BFD_SECTION (symbol)->owner, + SYMBOL_BFD_SECTION (symbol))); + break; + + case LOC_UNRESOLVED: + fprintf_filtered (outfile, "unresolved"); + break; + + case LOC_OPTIMIZED_OUT: + fprintf_filtered (outfile, "optimized out"); + break; + + default: + fprintf_filtered (outfile, "botched symbol class %x", + SYMBOL_CLASS (symbol)); + break; + } + } + fprintf_filtered (outfile, "\n"); + return 1; +} + +void +maintenance_print_psymbols (char *args, int from_tty) +{ + char **argv; + struct ui_file *outfile; + struct cleanup *cleanups; + char *symname = NULL; + char *filename = DEV_TTY; + struct objfile *objfile; + struct partial_symtab *ps; + + dont_repeat (); + + if (args == NULL) + { + error ("print-psymbols takes an output file name and optional symbol file name"); + } + else if ((argv = buildargv (args)) == NULL) + { + nomem (0); + } + cleanups = make_cleanup_freeargv (argv); + + if (argv[0] != NULL) + { + filename = argv[0]; + /* If a second arg is supplied, it is a source file name to match on */ + if (argv[1] != NULL) + { + symname = argv[1]; + } + } + + filename = tilde_expand (filename); + make_cleanup (xfree, filename); + + outfile = gdb_fopen (filename, FOPEN_WT); + if (outfile == 0) + perror_with_name (filename); + make_cleanup_ui_file_delete (outfile); + + immediate_quit++; + ALL_PSYMTABS (objfile, ps) + if (symname == NULL || (STREQ (symname, ps->filename))) + dump_psymtab (objfile, ps, outfile); + immediate_quit--; + do_cleanups (cleanups); +} + +static void +print_partial_symbols (struct partial_symbol **p, int count, char *what, + struct ui_file *outfile) +{ + fprintf_filtered (outfile, " %s partial symbols:\n", what); + while (count-- > 0) + { + fprintf_filtered (outfile, " `%s'", SYMBOL_NAME (*p)); + if (SYMBOL_DEMANGLED_NAME (*p) != NULL) + { + fprintf_filtered (outfile, " `%s'", SYMBOL_DEMANGLED_NAME (*p)); + } + fputs_filtered (", ", outfile); + switch (SYMBOL_NAMESPACE (*p)) + { + case UNDEF_NAMESPACE: + fputs_filtered ("undefined namespace, ", outfile); + break; + case VAR_NAMESPACE: + /* This is the usual thing -- don't print it */ + break; + case STRUCT_NAMESPACE: + fputs_filtered ("struct namespace, ", outfile); + break; + case LABEL_NAMESPACE: + fputs_filtered ("label namespace, ", outfile); + break; + default: + fputs_filtered ("<invalid namespace>, ", outfile); + break; + } + switch (SYMBOL_CLASS (*p)) + { + case LOC_UNDEF: + fputs_filtered ("undefined", outfile); + break; + case LOC_CONST: + fputs_filtered ("constant int", outfile); + break; + case LOC_STATIC: + fputs_filtered ("static", outfile); + break; + case LOC_INDIRECT: + fputs_filtered ("extern global", outfile); + break; + case LOC_REGISTER: + fputs_filtered ("register", outfile); + break; + case LOC_ARG: + fputs_filtered ("pass by value", outfile); + break; + case LOC_REF_ARG: + fputs_filtered ("pass by reference", outfile); + break; + case LOC_REGPARM: + fputs_filtered ("register parameter", outfile); + break; + case LOC_REGPARM_ADDR: + fputs_filtered ("register address parameter", outfile); + break; + case LOC_LOCAL: + fputs_filtered ("stack parameter", outfile); + break; + case LOC_TYPEDEF: + fputs_filtered ("type", outfile); + break; + case LOC_LABEL: + fputs_filtered ("label", outfile); + break; + case LOC_BLOCK: + fputs_filtered ("function", outfile); + break; + case LOC_CONST_BYTES: + fputs_filtered ("constant bytes", outfile); + break; + case LOC_LOCAL_ARG: + fputs_filtered ("shuffled arg", outfile); + break; + case LOC_UNRESOLVED: + fputs_filtered ("unresolved", outfile); + break; + case LOC_OPTIMIZED_OUT: + fputs_filtered ("optimized out", outfile); + break; + default: + fputs_filtered ("<invalid location>", outfile); + break; + } + fputs_filtered (", ", outfile); + print_address_numeric (SYMBOL_VALUE_ADDRESS (*p), 1, outfile); + fprintf_filtered (outfile, "\n"); + p++; + } +} + +void +maintenance_print_msymbols (char *args, int from_tty) +{ + char **argv; + struct ui_file *outfile; + struct cleanup *cleanups; + char *filename = DEV_TTY; + char *symname = NULL; + struct objfile *objfile; + + dont_repeat (); + + if (args == NULL) + { + error ("print-msymbols takes an output file name and optional symbol file name"); + } + else if ((argv = buildargv (args)) == NULL) + { + nomem (0); + } + cleanups = make_cleanup_freeargv (argv); + + if (argv[0] != NULL) + { + filename = argv[0]; + /* If a second arg is supplied, it is a source file name to match on */ + if (argv[1] != NULL) + { + symname = argv[1]; + } + } + + filename = tilde_expand (filename); + make_cleanup (xfree, filename); + + outfile = gdb_fopen (filename, FOPEN_WT); + if (outfile == 0) + perror_with_name (filename); + make_cleanup_ui_file_delete (outfile); + + immediate_quit++; + ALL_OBJFILES (objfile) + if (symname == NULL || (STREQ (symname, objfile->name))) + dump_msymbols (objfile, outfile); + immediate_quit--; + fprintf_filtered (outfile, "\n\n"); + do_cleanups (cleanups); +} + +void +maintenance_print_objfiles (char *ignore, int from_tty) +{ + struct objfile *objfile; + + dont_repeat (); + + immediate_quit++; + ALL_OBJFILES (objfile) + dump_objfile (objfile); + immediate_quit--; +} + +/* Check consistency of psymtabs and symtabs. */ + +void +maintenance_check_symtabs (char *ignore, int from_tty) +{ + register struct symbol *sym; + register struct partial_symbol **psym; + register struct symtab *s = NULL; + register struct partial_symtab *ps; + struct blockvector *bv; + register struct objfile *objfile; + register struct block *b; + int length; + + ALL_PSYMTABS (objfile, ps) + { + s = PSYMTAB_TO_SYMTAB (ps); + if (s == NULL) + continue; + bv = BLOCKVECTOR (s); + b = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); + psym = ps->objfile->static_psymbols.list + ps->statics_offset; + length = ps->n_static_syms; + while (length--) + { + sym = lookup_block_symbol (b, SYMBOL_NAME (*psym), + NULL, SYMBOL_NAMESPACE (*psym)); + if (!sym) + { + printf_filtered ("Static symbol `"); + puts_filtered (SYMBOL_NAME (*psym)); + printf_filtered ("' only found in "); + puts_filtered (ps->filename); + printf_filtered (" psymtab\n"); + } + psym++; + } + b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); + psym = ps->objfile->global_psymbols.list + ps->globals_offset; + length = ps->n_global_syms; + while (length--) + { + sym = lookup_block_symbol (b, SYMBOL_NAME (*psym), + NULL, SYMBOL_NAMESPACE (*psym)); + if (!sym) + { + printf_filtered ("Global symbol `"); + puts_filtered (SYMBOL_NAME (*psym)); + printf_filtered ("' only found in "); + puts_filtered (ps->filename); + printf_filtered (" psymtab\n"); + } + psym++; + } + if (ps->texthigh < ps->textlow) + { + printf_filtered ("Psymtab "); + puts_filtered (ps->filename); + printf_filtered (" covers bad range "); + print_address_numeric (ps->textlow, 1, gdb_stdout); + printf_filtered (" - "); + print_address_numeric (ps->texthigh, 1, gdb_stdout); + printf_filtered ("\n"); + continue; + } + if (ps->texthigh == 0) + continue; + if (ps->textlow < BLOCK_START (b) || ps->texthigh > BLOCK_END (b)) + { + printf_filtered ("Psymtab "); + puts_filtered (ps->filename); + printf_filtered (" covers "); + print_address_numeric (ps->textlow, 1, gdb_stdout); + printf_filtered (" - "); + print_address_numeric (ps->texthigh, 1, gdb_stdout); + printf_filtered (" but symtab covers only "); + print_address_numeric (BLOCK_START (b), 1, gdb_stdout); + printf_filtered (" - "); + print_address_numeric (BLOCK_END (b), 1, gdb_stdout); + printf_filtered ("\n"); + } + } +} + + +/* Return the nexting depth of a block within other blocks in its symtab. */ + +static int +block_depth (struct block *block) +{ + register int i = 0; + while ((block = BLOCK_SUPERBLOCK (block)) != NULL) + { + i++; + } + return i; +} + + +/* Increase the space allocated for LISTP, which is probably + global_psymbols or static_psymbols. This space will eventually + be freed in free_objfile(). */ + +void +extend_psymbol_list (register struct psymbol_allocation_list *listp, + struct objfile *objfile) +{ + int new_size; + if (listp->size == 0) + { + new_size = 255; + listp->list = (struct partial_symbol **) + xmmalloc (objfile->md, new_size * sizeof (struct partial_symbol *)); + } + else + { + new_size = listp->size * 2; + listp->list = (struct partial_symbol **) + xmrealloc (objfile->md, (char *) listp->list, + new_size * sizeof (struct partial_symbol *)); + } + /* Next assumes we only went one over. Should be good if + program works correctly */ + listp->next = listp->list + listp->size; + listp->size = new_size; +} + + +/* Do early runtime initializations. */ +void +_initialize_symmisc (void) +{ + std_in = stdin; + std_out = stdout; + std_err = stderr; +} |