aboutsummaryrefslogtreecommitdiff
path: root/gdb/RCS/dbxread.c,v
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/RCS/dbxread.c,v')
-rw-r--r--gdb/RCS/dbxread.c,v4610
1 files changed, 4610 insertions, 0 deletions
diff --git a/gdb/RCS/dbxread.c,v b/gdb/RCS/dbxread.c,v
new file mode 100644
index 0000000..eb9d1cd
--- /dev/null
+++ b/gdb/RCS/dbxread.c,v
@@ -0,0 +1,4610 @@
+head 1.3;
+access ;
+symbols ;
+locks ; strict;
+comment @ * @;
+
+
+1.3
+date 89.03.27.18.41.32; author gnu; state Exp;
+branches ;
+next 1.2;
+
+1.2
+date 89.02.10.01.38.34; author gnu; state Exp;
+branches ;
+next 1.1;
+
+1.1
+date 89.02.10.01.30.11; author gnu; state Exp;
+branches ;
+next ;
+
+
+desc
+@@
+
+
+1.3
+log
+@Avoid sys/fcntl.h.
+@
+text
+@/* Read dbx symbol tables and convert to internal format, for GDB.
+ Copyright (C) 1986, 1987, 1988, 1989 Free Software Foundation, Inc.
+
+GDB is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY. No author or distributor accepts responsibility to anyone
+for the consequences of using it or for whether it serves any
+particular purpose or works at all, unless he says so in writing.
+Refer to the GDB General Public License for full details.
+
+Everyone is granted permission to copy, modify and redistribute GDB,
+but only under the conditions described in the GDB General Public
+License. A copy of this license is supposed to have been given to you
+along with GDB so you can know your rights and responsibilities. It
+should be in a file named COPYING. Among other things, the copyright
+notice and this notice must be preserved on all copies.
+
+In other words, go ahead and share GDB, but don't try to stop
+anyone else from sharing it farther. Help stamp out software hoarding!
+*/
+
+#include "param.h"
+
+#ifdef READ_DBX_FORMAT
+
+#ifdef USG
+#include <sys/types.h>
+#include <fcntl.h>
+#define L_SET 0
+#define L_INCR 1
+#endif
+
+#ifdef COFF_ENCAPSULATE
+#include "a.out.encap.h"
+#include "stab.gnu.h"
+#else
+#include <a.out.h>
+#include <stab.h>
+#endif
+
+/*
+ * Define specifically gnu symbols here.
+ */
+
+/* The following type indicates the definition of a symbol as being
+ an indirect reference to another symbol. The other symbol
+ appears as an undefined reference, immediately following this symbol.
+
+ Indirection is asymmetrical. The other symbol's value will be used
+ to satisfy requests for the indirect symbol, but not vice versa.
+ If the other symbol does not have a definition, libraries will
+ be searched to find a definition. */
+#ifndef N_INDR
+#define N_INDR 0xa
+#endif
+
+/* The following symbols refer to set elements.
+ All the N_SET[ATDB] symbols with the same name form one set.
+ Space is allocated for the set in the text section, and each set
+ element's value is stored into one word of the space.
+ The first word of the space is the length of the set (number of elements).
+
+ The address of the set is made into an N_SETV symbol
+ whose name is the same as the name of the set.
+ This symbol acts like a N_DATA global symbol
+ in that it can satisfy undefined external references. */
+
+#ifndef N_SETA
+#define N_SETA 0x14 /* Absolute set element symbol */
+#endif /* This is input to LD, in a .o file. */
+
+#ifndef N_SETT
+#define N_SETT 0x16 /* Text set element symbol */
+#endif /* This is input to LD, in a .o file. */
+
+#ifndef N_SETD
+#define N_SETD 0x18 /* Data set element symbol */
+#endif /* This is input to LD, in a .o file. */
+
+#ifndef N_SETB
+#define N_SETB 0x1A /* Bss set element symbol */
+#endif /* This is input to LD, in a .o file. */
+
+/* Macros dealing with the set element symbols defined in a.out.h */
+#define SET_ELEMENT_P(x) ((x)>=N_SETA&&(x)<=(N_SETB|N_EXT))
+#define TYPE_OF_SET_ELEMENT(x) ((x)-N_SETA+N_ABS)
+
+#ifndef N_SETV
+#define N_SETV 0x1C /* Pointer to set vector in data area. */
+#endif /* This is output from LD. */
+
+#ifndef N_WARNING
+#define N_WARNING 0x1E /* Warning message to print if file included */
+#endif /* This is input to ld */
+
+#ifndef __GNU_STAB__
+
+/* Line number for the data section. This is to be used to describe
+ the source location of a variable declaration. */
+#ifndef N_DSLINE
+#define N_DSLINE (N_SLINE+N_DATA-N_TEXT)
+#endif
+
+/* Line number for the bss section. This is to be used to describe
+ the source location of a variable declaration. */
+#ifndef N_BSLINE
+#define N_BSLINE (N_SLINE+N_BSS-N_TEXT)
+#endif
+
+#endif /* not __GNU_STAB__ */
+
+#include <stdio.h>
+#include <obstack.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include "defs.h"
+#include "symtab.h"
+
+#ifndef COFF_FORMAT
+#define AOUTHDR struct exec
+#endif
+
+static void add_symbol_to_list ();
+static void read_dbx_symtab ();
+static void process_one_symbol ();
+static void free_all_psymbols ();
+static struct type *read_type ();
+static struct type *read_range_type ();
+static struct type *read_enum_type ();
+static struct type *read_struct_type ();
+static struct type *read_array_type ();
+static long read_number ();
+static void finish_block ();
+static struct blockvector *make_blockvector ();
+static struct symbol *define_symbol ();
+static void start_subfile ();
+static int hashname ();
+static void hash_symsegs ();
+
+extern struct symtab *read_symsegs ();
+extern void free_all_symtabs ();
+extern void free_all_psymtabs ();
+extern void free_inclink_symtabs ();
+
+/* C++ */
+static struct type **read_args();
+
+/* Macro to determine which symbols to ignore when reading the first symbol
+ of a file. Some machines override this definition. */
+#ifdef N_NSYMS
+#ifndef IGNORE_SYMBOL
+/* This code is used on Ultrix systems. Ignore it */
+#define IGNORE_SYMBOL(type) (type == N_NSYMS)
+#endif
+#else
+#ifndef IGNORE_SYMBOL
+/* Don't ignore any symbols. */
+#define IGNORE_SYMBOL(type) (0)
+#endif
+#endif /* not N_NSYMS */
+
+/* Macro for number of symbol table entries (in usual a.out format).
+ Some machines override this definition. */
+#ifndef NUMBER_OF_SYMBOLS
+#ifdef COFF_HEADER
+#define NUMBER_OF_SYMBOLS \
+ ((COFF_HEADER(hdr) ? hdr.coffhdr.filehdr.f_nsyms : hdr.a_syms) / \
+ sizeof (struct nlist))
+#else
+#define NUMBER_OF_SYMBOLS (hdr.a_syms / sizeof (struct nlist))
+#endif
+#endif
+
+/* Macro for file-offset of symbol table (in usual a.out format). */
+#ifndef SYMBOL_TABLE_OFFSET
+#define SYMBOL_TABLE_OFFSET N_SYMOFF (hdr)
+#endif
+
+/* Macro for file-offset of string table (in usual a.out format). */
+#ifndef STRING_TABLE_OFFSET
+#define STRING_TABLE_OFFSET (N_SYMOFF (hdr) + hdr.a_syms)
+#endif
+
+/* Macro to store the length of the string table data in INTO. */
+#ifndef READ_STRING_TABLE_SIZE
+#define READ_STRING_TABLE_SIZE(INTO) \
+{ val = myread (desc, &INTO, sizeof INTO); \
+ if (val < 0) perror_with_name (name); }
+#endif
+
+/* Macro to declare variables to hold the file's header data. */
+#ifndef DECLARE_FILE_HEADERS
+#define DECLARE_FILE_HEADERS AOUTHDR hdr
+#endif
+
+/* Macro to read the header data from descriptor DESC and validate it.
+ NAME is the file name, for error messages. */
+#ifndef READ_FILE_HEADERS
+#ifdef HEADER_SEEK_FD
+#define READ_FILE_HEADERS(DESC, NAME) \
+{ HEADER_SEEK_FD (DESC); \
+ val = myread (DESC, &hdr, sizeof hdr); \
+ if (val < 0) perror_with_name (NAME); \
+ if (N_BADMAG (hdr)) \
+ error ("File \"%s\" not in executable format.", NAME); }
+#else
+#define READ_FILE_HEADERS(DESC, NAME) \
+{ val = myread (DESC, &hdr, sizeof hdr); \
+ if (val < 0) perror_with_name (NAME); \
+ if (N_BADMAG (hdr)) \
+ error ("File \"%s\" not in executable format.", NAME); }
+#endif
+#endif
+
+/* Macro for size of text segment */
+#ifndef SIZE_OF_TEXT_SEGMENT
+#define SIZE_OF_TEXT_SEGMENT hdr.a_text
+#endif
+
+/* Macro for name of symbol to indicate a file compiled with gcc. */
+#ifndef GCC_COMPILED_FLAG_SYMBOL
+#define GCC_COMPILED_FLAG_SYMBOL "gcc_compiled."
+#endif
+
+/* Chain of symtabs made from reading the file's symsegs.
+ These symtabs do not go into symtab_list themselves,
+ but the information is copied from them when appropriate
+ to make the symtabs that will exist permanently. */
+
+static struct symtab *symseg_chain;
+
+/* Symseg symbol table for the file whose data we are now processing.
+ It is one of those in symseg_chain. Or 0, for a compilation that
+ has no symseg. */
+
+static struct symtab *current_symseg;
+
+/* Name of source file whose symbol data we are now processing.
+ This comes from a symbol of type N_SO. */
+
+static char *last_source_file;
+
+/* Core address of start of text of current source file.
+ This too comes from the N_SO symbol. */
+
+static CORE_ADDR last_source_start_addr;
+
+/* End of the text segment of the executable file,
+ as found in the symbol _etext. */
+
+static CORE_ADDR end_of_text_addr;
+
+/* The list of sub-source-files within the current individual compilation.
+ Each file gets its own symtab with its own linetable and associated info,
+ but they all share one blockvector. */
+
+struct subfile
+{
+ struct subfile *next;
+ char *name;
+ struct linetable *line_vector;
+ int line_vector_length;
+ int line_vector_index;
+ int prev_line_number;
+};
+
+static struct subfile *subfiles;
+
+static struct subfile *current_subfile;
+
+/* Count symbols as they are processed, for error messages. */
+
+static int symnum;
+
+/* Vector of types defined so far, indexed by their dbx type numbers.
+ (In newer sun systems, dbx uses a pair of numbers in parens,
+ as in "(SUBFILENUM,NUMWITHINSUBFILE)". Then these numbers must be
+ translated through the type_translations hash table to get
+ the index into the type vector.) */
+
+static struct typevector *type_vector;
+
+/* Number of elements allocated for type_vector currently. */
+
+static int type_vector_length;
+
+/* Vector of line number information. */
+
+static struct linetable *line_vector;
+
+/* Index of next entry to go in line_vector_index. */
+
+static int line_vector_index;
+
+/* Last line number recorded in the line vector. */
+
+static int prev_line_number;
+
+/* Number of elements allocated for line_vector currently. */
+
+static int line_vector_length;
+
+/* Hash table of global symbols whose values are not known yet.
+ They are chained thru the SYMBOL_VALUE, since we don't
+ have the correct data for that slot yet. */
+
+#define HASHSIZE 127
+static struct symbol *global_sym_chain[HASHSIZE];
+
+/* Record the symbols defined for each context in a list.
+ We don't create a struct block for the context until we
+ know how long to make it. */
+
+#define PENDINGSIZE 100
+
+struct pending
+{
+ struct pending *next;
+ int nsyms;
+ struct symbol *symbol[PENDINGSIZE];
+};
+
+/* List of free `struct pending' structures for reuse. */
+struct pending *free_pendings;
+
+/* Here are the three lists that symbols are put on. */
+
+struct pending *file_symbols; /* static at top level, and types */
+
+struct pending *global_symbols; /* global functions and variables */
+
+struct pending *local_symbols; /* everything local to lexical context */
+
+/* Stack representing unclosed lexical contexts
+ (that will become blocks, eventually). */
+
+struct context_stack
+{
+ struct pending *locals;
+ struct pending_block *old_blocks;
+ struct symbol *name;
+ CORE_ADDR start_addr;
+ int depth;
+};
+
+struct context_stack *context_stack;
+
+/* Index of first unused entry in context stack. */
+int context_stack_depth;
+
+/* Currently allocated size of context stack. */
+
+int context_stack_size;
+
+/* Nonzero if within a function (so symbols should be local,
+ if nothing says specifically). */
+
+int within_function;
+
+/* List of blocks already made (lexical contexts already closed).
+ This is used at the end to make the blockvector. */
+
+struct pending_block
+{
+ struct pending_block *next;
+ struct block *block;
+};
+
+struct pending_block *pending_blocks;
+
+extern CORE_ADDR first_object_file_end; /* From blockframe.c */
+
+/* File name symbols were loaded from. */
+
+static char *symfile;
+
+/* Low and high symbol values (inclusive) for the global variable
+ entries in the symbol file. */
+
+static int first_global_sym, last_global_sym;
+
+/* Partial symbol list for all of the global and static symbols found
+ in a file */
+
+struct partial_symbol *global_psymbols, *static_psymbols;
+int global_psymbols_allocated, static_psymbols_allocated;
+
+/* Position for next psymbol to be added */
+
+struct partial_symbol *next_ps_global, *next_ps_static;
+
+/* Global variable which, when set, indicates that we are processing a
+ .o file compiled with gcc */
+
+static unsigned char processing_gcc_compilation;
+
+static int
+xxmalloc (n)
+{
+ int v = malloc (n);
+ if (v == 0)
+ abort ();
+ return v;
+}
+
+/* Make a copy of the string at PTR with SIZE characters in the symbol obstack
+ (and add a null character at the end in the copy).
+ Returns the address of the copy. */
+
+static char *
+obsavestring (ptr, size)
+ char *ptr;
+ int size;
+{
+ register char *p = (char *) obstack_alloc (symbol_obstack, size + 1);
+ /* Open-coded bcopy--saves function call time.
+ These strings are usually short. */
+ {
+ register char *p1 = ptr;
+ register char *p2 = p;
+ char *end = ptr + size;
+ while (p1 != end)
+ *p2++ = *p1++;
+ }
+ p[size] = 0;
+ return p;
+}
+
+/* Concatenate strings S1, S2 and S3; return the new string.
+ Space is found in the symbol_obstack. */
+
+static char *
+obconcat (s1, s2, s3)
+ char *s1, *s2, *s3;
+{
+ register int len = strlen (s1) + strlen (s2) + strlen (s3) + 1;
+ register char *val = (char *) obstack_alloc (symbol_obstack, len);
+ strcpy (val, s1);
+ strcat (val, s2);
+ strcat (val, s3);
+ return val;
+}
+
+/* Support for Sun changes to dbx symbol format */
+
+/* For each identified header file, we have a table of types defined
+ in that header file.
+
+ header_files maps header file names to their type tables.
+ It is a vector of n_header_files elements.
+ Each element describes one header file.
+ It contains a vector of types.
+
+ Sometimes it can happen that the same header file produces
+ different results when included in different places.
+ This can result from conditionals or from different
+ things done before including the file.
+ When this happens, there are multiple entries for the file in this table,
+ one entry for each distinct set of results.
+ The entries are distinguished by the INSTANCE field.
+ The INSTANCE field appears in the N_BINCL and N_EXCL symbol table and is
+ used to match header-file references to their corresponding data. */
+
+struct header_file
+{
+ char *name; /* Name of header file */
+ int instance; /* Numeric code distinguishing instances
+ of one header file that produced
+ different results when included.
+ It comes from the N_BINCL or N_EXCL. */
+ struct type **vector; /* Pointer to vector of types */
+ int length; /* Allocated length (# elts) of that vector */
+};
+
+static struct header_file *header_files;
+
+static int n_header_files;
+
+static int n_allocated_header_files;
+
+/* During initial symbol readin, we need to have a structure to keep
+ track of which psymtabs have which bincls in them. This structure
+ is used during readin to setup the list of dependencies within each
+ partial symbol table. */
+
+struct header_file_location
+{
+ char *name; /* Name of header file */
+ int instance; /* See above */
+ struct partial_symtab *pst; /* Partial symtab that has the
+ BINCL/EINCL defs for this file */
+};
+
+/* The actual list and controling variables */
+static struct header_file_location *bincl_list, *next_bincl;
+static int bincls_allocated;
+
+/* Within each object file, various header files are assigned numbers.
+ A type is defined or referred to with a pair of numbers
+ (FILENUM,TYPENUM) where FILENUM is the number of the header file
+ and TYPENUM is the number within that header file.
+ TYPENUM is the index within the vector of types for that header file.
+
+ FILENUM == 1 is special; it refers to the main source of the object file,
+ and not to any header file. FILENUM != 1 is interpreted by looking it up
+ in the following table, which contains indices in header_files. */
+
+static int *this_object_header_files;
+
+static int n_this_object_header_files;
+
+static int n_allocated_this_object_header_files;
+
+/* When a header file is getting special overriding definitions
+ for one source file, record here the header_files index
+ of its normal definition vector.
+ At other times, this is -1. */
+
+static int header_file_prev_index;
+
+/* At the start of reading dbx symbols, allocate our tables. */
+
+static void
+init_header_files ()
+{
+ n_allocated_header_files = 10;
+ header_files = (struct header_file *) xxmalloc (10 * sizeof (struct header_file));
+ n_header_files = 0;
+
+ n_allocated_this_object_header_files = 10;
+ this_object_header_files = (int *) xxmalloc (10 * sizeof (int));
+}
+
+/* At the end of reading dbx symbols, free our tables. */
+
+static void
+free_header_files ()
+{
+ register int i;
+ for (i = 0; i < n_header_files; i++)
+ free (header_files[i].name);
+ if (header_files) free (header_files);
+ if (this_object_header_files)
+ free (this_object_header_files);
+}
+
+/* Called at the start of each object file's symbols.
+ Clear out the mapping of header file numbers to header files. */
+
+static void
+new_object_header_files ()
+{
+ /* Leave FILENUM of 0 free for builtin types and this file's types. */
+ n_this_object_header_files = 1;
+ header_file_prev_index = -1;
+}
+
+/* Add header file number I for this object file
+ at the next successive FILENUM. */
+
+static void
+add_this_object_header_file (i)
+ int i;
+{
+ if (n_this_object_header_files == n_allocated_this_object_header_files)
+ {
+ n_allocated_this_object_header_files *= 2;
+ this_object_header_files
+ = (int *) xrealloc (this_object_header_files,
+ n_allocated_this_object_header_files * sizeof (int));
+ }
+
+ this_object_header_files[n_this_object_header_files++] = i;
+}
+
+/* Add to this file an "old" header file, one already seen in
+ a previous object file. NAME is the header file's name.
+ INSTANCE is its instance code, to select among multiple
+ symbol tables for the same header file. */
+
+static void
+add_old_header_file (name, instance)
+ char *name;
+ int instance;
+{
+ register struct header_file *p = header_files;
+ register int i;
+
+ for (i = 0; i < n_header_files; i++)
+ if (!strcmp (p[i].name, name) && instance == p[i].instance)
+ {
+ add_this_object_header_file (i);
+ return;
+ }
+ error ("Invalid symbol data: \"repeated\" header file that hasn't been seen before, at symtab pos %d.",
+ symnum);
+}
+
+/* Add to this file a "new" header file: definitions for its types follow.
+ NAME is the header file's name.
+ Most often this happens only once for each distinct header file,
+ but not necessarily. If it happens more than once, INSTANCE has
+ a different value each time, and references to the header file
+ use INSTANCE values to select among them.
+
+ dbx output contains "begin" and "end" markers for each new header file,
+ but at this level we just need to know which files there have been;
+ so we record the file when its "begin" is seen and ignore the "end". */
+
+static void
+add_new_header_file (name, instance)
+ char *name;
+ int instance;
+{
+ register int i;
+ register struct header_file *p = header_files;
+ header_file_prev_index = -1;
+
+#if 0
+ /* This code was used before I knew about the instance codes.
+ My first hypothesis is that it is not necessary now
+ that instance codes are handled. */
+
+ /* Has this header file a previous definition?
+ If so, make a new entry anyway so that this use in this source file
+ gets a separate entry. Later source files get the old entry.
+ Record here the index of the old entry, so that any type indices
+ not previously defined can get defined in the old entry as
+ well as in the new one. */
+
+ for (i = 0; i < n_header_files; i++)
+ if (!strcmp (p[i].name, name))
+ {
+ header_file_prev_index = i;
+ }
+
+#endif
+
+ /* Make sure there is room for one more header file. */
+
+ if (n_header_files == n_allocated_header_files)
+ {
+ n_allocated_header_files *= 2;
+ header_files = (struct header_file *)
+ xrealloc (header_files,
+ (n_allocated_header_files
+ * sizeof (struct header_file)));
+ }
+
+ /* Create an entry for this header file. */
+
+ i = n_header_files++;
+ header_files[i].name = savestring (name, strlen(name));
+ header_files[i].instance = instance;
+ header_files[i].length = 10;
+ header_files[i].vector
+ = (struct type **) xxmalloc (10 * sizeof (struct type *));
+ bzero (header_files[i].vector, 10 * sizeof (struct type *));
+
+ add_this_object_header_file (i);
+}
+
+/* Look up a dbx type-number pair. Return the address of the slot
+ where the type for that number-pair is stored.
+ The number-pair is in TYPENUMS.
+
+ This can be used for finding the type associated with that pair
+ or for associating a new type with the pair. */
+
+static struct type **
+dbx_lookup_type (typenums)
+ int typenums[2];
+{
+ register int filenum = typenums[0], index = typenums[1];
+
+ if (filenum < 0 || filenum >= n_this_object_header_files)
+ error ("Invalid symbol data: type number (%d,%d) out of range at symtab pos %d.",
+ filenum, index, symnum);
+
+ if (filenum == 0)
+ {
+ /* Type is defined outside of header files.
+ Find it in this object file's type vector. */
+ if (index >= type_vector_length)
+ {
+ type_vector_length *= 2;
+ type_vector = (struct typevector *)
+ xrealloc (type_vector,
+ (sizeof (struct typevector)
+ + type_vector_length * sizeof (struct type *)));
+ bzero (&type_vector->type[type_vector_length / 2],
+ type_vector_length * sizeof (struct type *) / 2);
+ }
+ return &type_vector->type[index];
+ }
+ else
+ {
+ register int real_filenum = this_object_header_files[filenum];
+ register struct header_file *f;
+
+ if (real_filenum >= n_header_files)
+ abort ();
+
+ f = &header_files[real_filenum];
+
+ if (index >= f->length)
+ {
+ f->length *= 2;
+ f->vector = (struct type **)
+ xrealloc (f->vector, f->length * sizeof (struct type *));
+ bzero (&f->vector[f->length / 2],
+ f->length * sizeof (struct type *) / 2);
+ }
+ return &f->vector[index];
+ }
+}
+
+/* Make sure there is a type allocated for type numbers TYPENUMS
+ and return the type object.
+ This can create an empty (zeroed) type object. */
+
+static struct type *
+dbx_alloc_type (typenums)
+ int typenums[2];
+{
+ register struct type **type_addr = dbx_lookup_type (typenums);
+ register struct type *type = *type_addr;
+
+ /* If we are referring to a type not known at all yet,
+ allocate an empty type for it.
+ We will fill it in later if we find out how. */
+ if (type == 0)
+ {
+ type = (struct type *) obstack_alloc (symbol_obstack,
+ sizeof (struct type));
+ bzero (type, sizeof (struct type));
+ TYPE_VPTR_FIELDNO (type) = -1;
+ *type_addr = type;
+ }
+ return type;
+}
+
+#if 0
+static struct type **
+explicit_lookup_type (real_filenum, index)
+ int real_filenum, index;
+{
+ register struct header_file *f = &header_files[real_filenum];
+
+ if (index >= f->length)
+ {
+ f->length *= 2;
+ f->vector = (struct type **)
+ xrealloc (f->vector, f->length * sizeof (struct type *));
+ bzero (&f->vector[f->length / 2],
+ f->length * sizeof (struct type *) / 2);
+ }
+ return &f->vector[index];
+}
+#endif
+
+/* maintain the lists of symbols and blocks */
+
+/* Add a symbol to one of the lists of symbols. */
+static void
+add_symbol_to_list (symbol, listhead)
+ struct symbol *symbol;
+ struct pending **listhead;
+{
+ /* 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 == 0 || (*listhead)->nsyms == PENDINGSIZE)
+ {
+ register struct pending *link;
+ if (free_pendings)
+ {
+ link = free_pendings;
+ free_pendings = link->next;
+ }
+ else
+ link = (struct pending *) xxmalloc (sizeof (struct pending));
+
+ link->next = *listhead;
+ *listhead = link;
+ link->nsyms = 0;
+ }
+
+ (*listhead)->symbol[(*listhead)->nsyms++] = symbol;
+}
+
+/* At end of reading syms, or in case of quit,
+ really free as many `struct pending's as we can easily find. */
+
+static void
+really_free_pendings ()
+{
+ struct pending *next, *next1;
+ struct pending_block *bnext, *bnext1;
+
+ for (next = free_pendings; next; next = next1)
+ {
+ next1 = next->next;
+ free (next);
+ }
+ free_pendings = 0;
+
+ for (bnext = pending_blocks; bnext; bnext = bnext1)
+ {
+ bnext1 = bnext->next;
+ free (bnext);
+ }
+ pending_blocks = 0;
+
+ for (next = file_symbols; next; next = next1)
+ {
+ next1 = next->next;
+ free (next);
+ }
+ for (next = global_symbols; next; next = next1)
+ {
+ next1 = next->next;
+ free (next);
+ }
+}
+
+/* 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. */
+
+static void
+finish_block (symbol, listhead, old_blocks, start, end)
+ struct symbol *symbol;
+ struct pending **listhead;
+ struct pending_block *old_blocks;
+ CORE_ADDR start, end;
+{
+ register struct pending *next, *next1;
+ register struct block *block;
+ register struct pending_block *pblock;
+ struct pending_block *opblock;
+ register int i;
+
+ /* Count the length of the list of symbols. */
+
+ for (next = *listhead, i = 0; next; i += next->nsyms, next = next->next);
+
+ block = (struct block *) obstack_alloc (symbol_obstack,
+ (sizeof (struct block)
+ + ((i - 1)
+ * sizeof (struct symbol *))));
+
+ /* Copy the symbols into the block. */
+
+ BLOCK_NSYMS (block) = i;
+ for (next = *listhead; next; next = next->next)
+ {
+ register int j;
+ for (j = next->nsyms - 1; j >= 0; j--)
+ BLOCK_SYM (block, --i) = next->symbol[j];
+ }
+
+ BLOCK_START (block) = start;
+ BLOCK_END (block) = end;
+ BLOCK_SUPERBLOCK (block) = 0; /* Filled in when containing block is made */
+ BLOCK_GCC_COMPILED (block) = processing_gcc_compilation;
+
+ /* Put the block in as the value of the symbol that names it. */
+
+ if (symbol)
+ {
+ SYMBOL_BLOCK_VALUE (symbol) = block;
+ BLOCK_FUNCTION (block) = symbol;
+ }
+ else
+ BLOCK_FUNCTION (block) = 0;
+
+ /* 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 = 0;
+
+ /* Install this block as the superblock
+ of all blocks made since the start of this scope
+ that don't have superblocks yet. */
+
+ opblock = 0;
+ for (pblock = pending_blocks; pblock != old_blocks; pblock = pblock->next)
+ {
+ if (BLOCK_SUPERBLOCK (pblock->block) == 0)
+ BLOCK_SUPERBLOCK (pblock->block) = block;
+ opblock = pblock;
+ }
+
+ /* Record this block on the list of all blocks in the file.
+ Put it after opblock, or at the beginning if opblock is 0.
+ This puts the block in the list after all its subblocks. */
+
+ /* Allocate in the symbol_obstack to save time.
+ It wastes a little space. */
+ pblock = (struct pending_block *)
+ obstack_alloc (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;
+ }
+}
+
+static struct blockvector *
+make_blockvector ()
+{
+ register struct pending_block *next, *next1;
+ 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 (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;
+ free (next);
+ }
+#endif
+ pending_blocks = 0;
+
+ return blockvector;
+}
+
+/* Manage the vector of line numbers. */
+
+static void
+record_line (line, pc)
+ 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 is big enough. */
+
+ if (line_vector_index + 1 >= line_vector_length)
+ {
+ line_vector_length *= 2;
+ line_vector = (struct linetable *)
+ xrealloc (line_vector,
+ (sizeof (struct linetable)
+ + line_vector_length * sizeof (struct linetable_entry)));
+ current_subfile->line_vector = line_vector;
+ }
+
+ e = line_vector->item + line_vector_index++;
+ e->line = line; e->pc = pc;
+}
+
+/* Start a new symtab for a new source file.
+ This is called when a dbx symbol of type N_SO is seen;
+ it indicates the start of data for one original source file. */
+
+static void
+start_symtab (name, start_addr)
+ char *name;
+ CORE_ADDR start_addr;
+{
+ register struct symtab *s;
+
+ last_source_file = name;
+ last_source_start_addr = start_addr;
+ file_symbols = 0;
+ global_symbols = 0;
+ within_function = 0;
+
+ /* Context stack is initially empty, with room for 10 levels. */
+ context_stack
+ = (struct context_stack *) xxmalloc (10 * sizeof (struct context_stack));
+ context_stack_size = 10;
+ context_stack_depth = 0;
+
+ new_object_header_files ();
+
+ for (s = symseg_chain; s; s = s->next)
+ if (s->ldsymoff == symnum * sizeof (struct nlist))
+ break;
+ current_symseg = s;
+ if (s != 0)
+ return;
+
+ type_vector_length = 160;
+ type_vector = (struct typevector *)
+ xxmalloc (sizeof (struct typevector)
+ + type_vector_length * sizeof (struct type *));
+ bzero (type_vector->type, type_vector_length * sizeof (struct type *));
+
+ /* Initialize the list of sub source files with one entry
+ for this file (the top-level source file). */
+
+ subfiles = 0;
+ current_subfile = 0;
+ start_subfile (name);
+
+ /* Set default for compiler to pcc; assume that we aren't processing
+ a gcc compiled file until proved otherwise. */
+
+ processing_gcc_compilation = 0;
+}
+
+/* Handle an N_SOL symbol, which indicates the start of
+ code that came from an included (or otherwise merged-in)
+ source file with a different name. */
+
+static void
+start_subfile (name)
+ char *name;
+{
+ register struct subfile *subfile;
+
+ /* Save the current subfile's line vector data. */
+
+ if (current_subfile)
+ {
+ current_subfile->line_vector_index = line_vector_index;
+ current_subfile->line_vector_length = line_vector_length;
+ current_subfile->prev_line_number = prev_line_number;
+ }
+
+ /* See if this subfile is already known as a subfile of the
+ current main source file. */
+
+ for (subfile = subfiles; subfile; subfile = subfile->next)
+ {
+ if (!strcmp (subfile->name, name))
+ {
+ line_vector = subfile->line_vector;
+ line_vector_index = subfile->line_vector_index;
+ line_vector_length = subfile->line_vector_length;
+ prev_line_number = subfile->prev_line_number;
+ current_subfile = subfile;
+ return;
+ }
+ }
+
+ /* This subfile is not known. Add an entry for it. */
+
+ line_vector_index = 0;
+ line_vector_length = 1000;
+ prev_line_number = -2; /* Force first line number to be explicit */
+ line_vector = (struct linetable *)
+ xxmalloc (sizeof (struct linetable)
+ + line_vector_length * sizeof (struct linetable_entry));
+
+ /* Make an entry for this subfile in the list of all subfiles
+ of the current main source file. */
+
+ subfile = (struct subfile *) xxmalloc (sizeof (struct subfile));
+ subfile->next = subfiles;
+ subfile->name = savestring (name, strlen (name));
+ subfile->line_vector = line_vector;
+ subfiles = subfile;
+ current_subfile = subfile;
+}
+
+/* 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. */
+
+static void
+end_symtab (end_addr)
+ CORE_ADDR end_addr;
+{
+ register struct symtab *symtab;
+ register struct blockvector *blockvector;
+ register struct subfile *subfile;
+ register struct linetable *lv;
+ struct subfile *nextsub;
+
+ if (current_symseg != 0)
+ {
+ last_source_file = 0;
+ current_symseg = 0;
+ return;
+ }
+
+ /* Finish the lexical context of the last function in the file;
+ pop the context stack. */
+
+ if (context_stack_depth > 0)
+ {
+ register struct context_stack *cstk;
+ context_stack_depth--;
+ cstk = &context_stack[context_stack_depth];
+ /* Make a block for the local symbols within. */
+ finish_block (cstk->name, &local_symbols, cstk->old_blocks,
+ cstk->start_addr, end_addr);
+ }
+
+ /* Finish defining all the blocks of this symtab. */
+ finish_block (0, &file_symbols, 0, last_source_start_addr, end_addr);
+ finish_block (0, &global_symbols, 0, last_source_start_addr, end_addr);
+ blockvector = make_blockvector ();
+
+ current_subfile->line_vector_index = line_vector_index;
+
+ /* Now create the symtab objects proper, one for each subfile. */
+ /* (The main file is one of them.) */
+
+ for (subfile = subfiles; subfile; subfile = nextsub)
+ {
+ symtab = (struct symtab *) xxmalloc (sizeof (struct symtab));
+ symtab->free_ptr = 0;
+
+ /* Fill in its components. */
+ symtab->blockvector = blockvector;
+ type_vector->length = type_vector_length;
+ symtab->typevector = type_vector;
+ symtab->free_code = free_linetable;
+ if (subfile->next == 0)
+ symtab->free_ptr = (char *) type_vector;
+
+ symtab->filename = subfile->name;
+ lv = subfile->line_vector;
+ lv->nitems = subfile->line_vector_index;
+ symtab->linetable = (struct linetable *)
+ xrealloc (lv, (sizeof (struct linetable)
+ + lv->nitems * sizeof (struct linetable_entry)));
+ symtab->nlines = 0;
+ symtab->line_charpos = 0;
+
+ /* Link the new symtab into the list of such. */
+ symtab->next = symtab_list;
+ symtab_list = symtab;
+
+ nextsub = subfile->next;
+ free (subfile);
+ }
+
+ type_vector = 0;
+ type_vector_length = -1;
+ line_vector = 0;
+ line_vector_length = -1;
+ last_source_file = 0;
+}
+
+#ifdef N_BINCL
+
+/* 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. */
+
+struct subfile_stack
+{
+ struct subfile_stack *next;
+ char *name;
+ int prev_index;
+};
+
+struct subfile_stack *subfile_stack;
+
+static void
+push_subfile ()
+{
+ register struct subfile_stack *tem
+ = (struct subfile_stack *) xxmalloc (sizeof (struct subfile_stack));
+
+ tem->next = subfile_stack;
+ subfile_stack = tem;
+ if (current_subfile == 0 || current_subfile->name == 0)
+ abort ();
+ tem->name = current_subfile->name;
+ tem->prev_index = header_file_prev_index;
+}
+
+static char *
+pop_subfile ()
+{
+ register char *name;
+ register struct subfile_stack *link = subfile_stack;
+
+ if (link == 0)
+ abort ();
+
+ name = link->name;
+ subfile_stack = link->next;
+ header_file_prev_index = link->prev_index;
+ free (link);
+
+ return name;
+}
+#endif /* Have N_BINCL */
+
+/* Accumulate the misc functions in bunches of 127.
+ At the end, copy them all into one newly allocated structure. */
+
+#define MISC_BUNCH_SIZE 127
+
+struct misc_bunch
+{
+ struct misc_bunch *next;
+ struct misc_function contents[MISC_BUNCH_SIZE];
+};
+
+/* Bunch currently being filled up.
+ The next field points to chain of filled bunches. */
+
+static struct misc_bunch *misc_bunch;
+
+/* Number of slots filled in current bunch. */
+
+static int misc_bunch_index;
+
+/* Total number of misc functions recorded so far. */
+
+static int misc_count;
+
+static void
+init_misc_functions ()
+{
+ misc_count = 0;
+ misc_bunch = 0;
+ misc_bunch_index = MISC_BUNCH_SIZE;
+}
+
+static void
+record_misc_function (name, address)
+ char *name;
+ CORE_ADDR address;
+{
+ register struct misc_bunch *new;
+
+ if (misc_bunch_index == MISC_BUNCH_SIZE)
+ {
+ new = (struct misc_bunch *) xxmalloc (sizeof (struct misc_bunch));
+ misc_bunch_index = 0;
+ new->next = misc_bunch;
+ misc_bunch = new;
+ }
+ misc_bunch->contents[misc_bunch_index].name = name;
+ misc_bunch->contents[misc_bunch_index].address = address;
+ misc_bunch_index++;
+ misc_count++;
+}
+
+static int
+compare_misc_functions (fn1, fn2)
+ struct misc_function *fn1, *fn2;
+{
+ /* Return a signed result based on unsigned comparisons
+ so that we sort into unsigned numeric order. */
+ if (fn1->address < fn2->address)
+ return -1;
+ if (fn1->address > fn2->address)
+ return 1;
+ return 0;
+}
+
+static void
+discard_misc_bunches ()
+{
+ register struct misc_bunch *next;
+
+ while (misc_bunch)
+ {
+ next = misc_bunch->next;
+ free (misc_bunch);
+ misc_bunch = next;
+ }
+}
+
+/* INCLINK nonzero means bunches are from an incrementally-linked file.
+ Add them to the existing bunches.
+ Otherwise INCLINK is zero, and we start from scratch. */
+static void
+condense_misc_bunches (inclink)
+ int inclink;
+{
+ register int i, j;
+ register struct misc_bunch *bunch;
+#ifdef NAMES_HAVE_UNDERSCORE
+ int offset = 1;
+#else
+ int offset = 0;
+#endif
+
+ if (inclink)
+ {
+ misc_function_vector
+ = (struct misc_function *)
+ xrealloc (misc_function_vector, (misc_count + misc_function_count)
+ * sizeof (struct misc_function));
+ j = misc_function_count;
+ }
+ else
+ {
+ misc_function_vector
+ = (struct misc_function *)
+ xxmalloc (misc_count * sizeof (struct misc_function));
+ j = 0;
+ }
+
+ bunch = misc_bunch;
+ while (bunch)
+ {
+ for (i = 0; i < misc_bunch_index; i++)
+ {
+ misc_function_vector[j] = bunch->contents[i];
+ misc_function_vector[j].name
+ = obconcat (misc_function_vector[j].name
+ + (misc_function_vector[j].name[0] == '_' ? offset : 0),
+ "", "");
+ j++;
+ }
+ bunch = bunch->next;
+ misc_bunch_index = MISC_BUNCH_SIZE;
+ }
+
+ if (inclink)
+ misc_function_count += misc_count;
+ else
+ misc_function_count = j;
+
+ /* Sort the misc functions by address. */
+
+ qsort (misc_function_vector, misc_function_count,
+ sizeof (struct misc_function),
+ compare_misc_functions);
+}
+
+/* Call sort_syms to sort alphabetically
+ the symbols of each block of each symtab. */
+
+static int
+compare_symbols (s1, s2)
+ struct symbol **s1, **s2;
+{
+ register int namediff;
+
+ /* Compare the initial characters. */
+ namediff = SYMBOL_NAME (*s1)[0] - SYMBOL_NAME (*s2)[0];
+ if (namediff != 0) return namediff;
+
+ /* If they match, compare the rest of the names. */
+ namediff = strcmp (SYMBOL_NAME (*s1), SYMBOL_NAME (*s2));
+ if (namediff != 0) return namediff;
+
+ /* For symbols of the same name, registers should come first. */
+ return ((SYMBOL_CLASS (*s2) == LOC_REGISTER)
+ - (SYMBOL_CLASS (*s1) == LOC_REGISTER));
+}
+
+static void sort_symtab_syms ();
+
+static void
+sort_syms ()
+{
+ register struct symtab *s;
+
+ for (s = symtab_list; s; s = s->next)
+ sort_symtab_syms (s);
+}
+
+static void
+sort_symtab_syms (s)
+ register struct symtab *s;
+{
+ register struct blockvector *bv = BLOCKVECTOR (s);
+ int nbl = BLOCKVECTOR_NBLOCKS (bv);
+ int i;
+ register struct block *b;
+
+ /* Note that in the following sort, we always make sure that
+ register debug symbol declarations always come before regular
+ debug symbol declarations (as might happen when parameters are
+ then put into registers by the compiler). We do this by a
+ correct compare in compare_symbols, and by the reversal of the
+ symbols if we don't sort. This works as long as a register debug
+ symbol always comes after a parameter debug symbol. */
+
+ /* This is no longer necessary; lookup_block_symbol now always
+ prefers some other declaration over a parameter declaration. We
+ still sort the thing (that is necessary), but we don't reverse it
+ if we shouldn't sort it. */
+
+ for (i = 0; i < nbl; i++)
+ {
+ b = BLOCKVECTOR_BLOCK (bv, i);
+ if (BLOCK_SHOULD_SORT (b))
+ qsort (&BLOCK_SYM (b, 0), BLOCK_NSYMS (b),
+ sizeof (struct symbol *), compare_symbols);
+ }
+}
+
+
+extern struct symtab *psymtab_to_symtab ();
+
+/* This is the symbol-file command. Read the file, analyze its symbols,
+ and add a struct symtab to symtab_list. */
+
+void
+symbol_file_command (name)
+ char *name;
+{
+ register int desc;
+ DECLARE_FILE_HEADERS;
+ struct nlist *nlist;
+ char *stringtab;
+ long buffer;
+ register int val;
+ extern void close ();
+ struct cleanup *old_chain;
+ struct symtab *symseg;
+ struct stat statbuf;
+
+ dont_repeat ();
+
+ if (name == 0)
+ {
+ if ((symtab_list || partial_symtab_list)
+ && !query ("Discard symbol table? ", 0))
+ error ("Not confirmed.");
+ if (symfile)
+ free (symfile);
+ symfile = 0;
+ free_all_symtabs ();
+ free_all_psymtabs ();
+ return;
+ }
+
+ if ((symtab_list || partial_symtab_list)
+ && !query ("Load new symbol table from \"%s\"? ", name))
+ error ("Not confirmed.");
+
+ {
+ char *absolute_name;
+ desc = openp (getenv ("PATH"), 1, name, O_RDONLY, 0, &absolute_name);
+ if (desc < 0)
+ perror_with_name (name);
+ else
+ name = absolute_name;
+ }
+
+ old_chain = make_cleanup (close, desc);
+ make_cleanup (free_current_contents, &name);
+
+ READ_FILE_HEADERS (desc, name);
+
+ if (NUMBER_OF_SYMBOLS == 0)
+ {
+ if (symfile)
+ free (symfile);
+ symfile = 0;
+ free_all_symtabs ();
+ free_all_psymtabs ();
+ printf ("%s has no symbol-table; symbols discarded.\n", name);
+ fflush (stdout);
+ do_cleanups (old_chain);
+ return;
+ }
+
+ printf ("Reading symbol data from %s...", name);
+ fflush (stdout);
+
+ /* Now read the string table, all at once. */
+ val = lseek (desc, STRING_TABLE_OFFSET, 0);
+ if (val < 0)
+ perror_with_name (name);
+ stat (name, &statbuf);
+ READ_STRING_TABLE_SIZE (buffer);
+ if (buffer >= 0 && buffer < statbuf.st_size)
+ stringtab = (char *) alloca (buffer);
+ else
+ stringtab = NULL;
+ if (stringtab == NULL)
+ error ("ridiculous string table size: %d bytes", name, buffer);
+
+ bcopy (&buffer, stringtab, sizeof buffer);
+ val = myread (desc, stringtab + sizeof buffer, buffer - sizeof buffer);
+ if (val < 0)
+ perror_with_name (name);
+
+ /* Throw away the old symbol table. */
+
+ if (symfile)
+ free (symfile);
+ symfile = 0;
+ free_all_symtabs ();
+ free_all_psymtabs ();
+
+ /* Empty the hash table of global syms looking for values. */
+ bzero (global_sym_chain, sizeof global_sym_chain);
+
+#ifdef READ_GDB_SYMSEGS
+ /* That puts us at the symsegs. Read them. */
+ symseg_chain = read_symsegs (desc, name);
+ hash_symsegs ();
+
+ /* Free the symtabs made by read_symsegs, but not their contents,
+ which have been copied into symtabs on symtab_list. */
+ for (symseg = symseg_chain; symseg; symseg = symseg->next)
+ {
+ int i;
+ struct sourcevector *sv = (struct sourcevector *) symseg->linetable;
+
+ for (i = 0; i < sv->length; i++)
+ {
+ int j;
+ struct source *source = sv->source[i];
+ struct symtab *sp1
+ = (struct symtab *) xxmalloc (sizeof (struct symtab));
+
+ bcopy (symseg, sp1, sizeof (struct symtab));
+ sp1->filename = savestring (source->name, strlen (source->name));
+ sp1->linetable = &source->contents;
+ sp1->free_code = free_nothing;
+ sp1->free_ptr = (i == 0) ? (char *) symseg : 0;
+
+ sp1->next = symtab_list;
+ symtab_list = sp1;
+ }
+ }
+#else
+ /* Where people are using the 4.2 ld program, must not check for
+ symsegs, because that ld puts randonm garbage at the end of
+ the output file and that would trigger an error message. */
+ symseg_chain = 0;
+#endif
+
+ /* Position to read the symbol table. Do not read it all at once. */
+ val = lseek (desc, SYMBOL_TABLE_OFFSET, 0);
+ if (val < 0)
+ perror_with_name (name);
+
+ /* Don't put these on the cleanup chain; they need to stick around
+ until the next call to symbol_file_command. *Then* we'll free
+ them. */
+ free_header_files ();
+ init_header_files ();
+
+ init_misc_functions ();
+ make_cleanup (discard_misc_bunches, 0);
+
+ free_pendings = 0;
+ pending_blocks = 0;
+ file_symbols = 0;
+ global_symbols = 0;
+ make_cleanup (really_free_pendings, 0);
+
+ /* Now that the symbol table data of the executable file are all in core,
+ process them and define symbols accordingly. Closes desc. */
+
+ read_dbx_symtab (desc, stringtab, NUMBER_OF_SYMBOLS, 0, 0, 0);
+
+ /* Go over the misc functions and install them in vector. */
+
+ condense_misc_bunches (0);
+
+ /* Don't allow char * to have a typename (else would get caddr_t.) */
+
+ TYPE_NAME (lookup_pointer_type (builtin_type_char)) = 0;
+
+ /* Make a default for file to list. */
+
+ symfile = savestring (name, strlen (name));
+
+ /* Call to select_source_symtab used to be here; it was using too
+ much time. I'll make sure that list_sources can handle the lack
+ of current_source_symtab */
+
+ do_cleanups (old_chain); /* Descriptor closed here */
+
+ /* Free the symtabs made by read_symsegs, but not their contents,
+ which have been copied into symtabs on symtab_list. */
+ while (symseg_chain)
+ {
+ register struct symtab *s = symseg_chain->next;
+ free (symseg_chain);
+ symseg_chain = s;
+ }
+
+ if (!partial_symtab_list)
+ printf ("\n(no debugging symbols found)...");
+
+ printf ("done.\n");
+ fflush (stdout);
+}
+
+/* Return name of file symbols were loaded from, or 0 if none.. */
+
+char *
+get_sym_file ()
+{
+ return symfile;
+}
+
+/* Buffer for reading the symbol table entries. */
+static struct nlist symbuf[4096];
+static int symbuf_idx;
+static int symbuf_end;
+
+/* I/O descriptor for reading the symbol table. */
+static int symtab_input_desc;
+
+/* The address of the string table
+ of the object file we are reading (as copied into core). */
+static char *stringtab_global;
+
+/* Refill the symbol table input buffer
+ and set the variables that control fetching entries from it.
+ Reports an error if no data available.
+ This function can read past the end of the symbol table
+ (into the string table) but this does no harm. */
+
+static int
+fill_symbuf ()
+{
+ int nbytes = myread (symtab_input_desc, symbuf, sizeof (symbuf));
+ if (nbytes <= 0)
+ error ("error or end of file reading symbol table");
+ symbuf_end = nbytes / sizeof (struct nlist);
+ symbuf_idx = 0;
+ return 1;
+}
+
+/* dbx allows the text of a symbol name to be continued into the
+ next symbol name! When such a continuation is encountered
+ (a \ at the end of the text of a name)
+ call this function to get the continuation. */
+
+static char *
+next_symbol_text ()
+{
+ if (symbuf_idx == symbuf_end)
+ fill_symbuf ();
+ symnum++;
+ return symbuf[symbuf_idx++].n_un.n_strx + stringtab_global;
+}
+
+/*
+ * Initializes storage for all of the partial symbols that will be
+ * created by read_dbx_symtab and subsidiaries.
+ */
+void
+init_psymbol_list (total_symbols)
+ int total_symbols;
+{
+ /* Current best guess is that there are approximately a twentieth
+ of the total symbols (in a debugging file) are global or static
+ oriented symbols */
+ global_psymbols_allocated = total_symbols / 10;
+ static_psymbols_allocated = total_symbols / 10;
+ next_ps_global = global_psymbols = (struct partial_symbol *)
+ xmalloc (global_psymbols_allocated * sizeof (struct partial_symbol));
+ next_ps_static = static_psymbols = (struct partial_symbol *)
+ xmalloc (static_psymbols_allocated * sizeof (struct partial_symbol));
+}
+
+/*
+ * Initialize the list of bincls to contain none and have some
+ * allocated.
+ */
+static void
+init_bincl_list (number)
+ int number;
+{
+ bincls_allocated = number;
+ next_bincl = bincl_list = (struct header_file_location *)
+ xmalloc (bincls_allocated * sizeof(struct header_file_location));
+}
+
+/*
+ * Add a bincl to the list.
+ */
+static void
+add_bincl_to_list (pst, name, instance)
+ struct partial_symtab *pst;
+ char *name;
+ int instance;
+{
+ if (next_bincl >= bincl_list + bincls_allocated)
+ {
+ int offset = next_bincl - bincl_list;
+ bincls_allocated *= 2;
+ bincl_list = (struct header_file_location *)
+ xrealloc (bincl_list,
+ bincls_allocated * sizeof (struct header_file_location));
+ next_bincl = bincl_list + offset;
+ }
+ next_bincl->pst = pst;
+ next_bincl->instance = instance;
+ next_bincl++->name = name;
+}
+
+/*
+ * Given a name, value pair, find the corresponding
+ * bincl in the list. Return the partial symtab associated
+ * with that header_file_location.
+ */
+struct partial_symtab *
+find_corresponding_bincl_psymtab (name, instance)
+ char *name;
+ int instance;
+{
+ struct header_file_location *bincl;
+
+ for (bincl = bincl_list; bincl < next_bincl; bincl++)
+ if (bincl->instance == instance
+ && !strcmp (name, bincl->name))
+ return bincl->pst;
+
+ return (struct partial_symtab *) 0;
+}
+
+/*
+ * Free the storage allocated for the bincl list.
+ */
+static void
+free_bincl_list ()
+{
+ free (bincl_list);
+ bincls_allocated = 0;
+}
+
+static struct partial_symtab *start_psymtab ();
+static void add_psymtab_dependency ();
+static void end_psymtab();
+
+/* Given pointers to an a.out symbol table in core containing dbx
+ style data, setup partial_symtab's describing each source file for
+ which debugging information is available. NLISTLEN is the number
+ of symbols in the symbol table. All symbol names are given as
+ offsets relative to STRINGTAB.
+
+ I have no idea whether or not this routine should be setup to deal
+ with inclinks. It seems reasonable to me that they be dealt with
+ standardly, so I am not going to make a strong effort to deal with
+ them here.
+ */
+
+static void process_symbol_for_psymtab ();
+
+static void
+read_dbx_symtab (desc, stringtab, nlistlen, inclink, text_addr, text_size)
+ int desc;
+ register char *stringtab;
+ register int nlistlen;
+ int inclink;
+ unsigned text_addr;
+ int text_size;
+{
+ register char *namestring;
+ register struct symbol *sym, *prev;
+ int hash;
+ int num_object_files = 0;
+ int past_first_source_file = 0;
+ struct cleanup *old_chain;
+ int current_text_start, current_file_symbol_start;
+ struct pending *global_symbols, *static_symbols;
+ int nsl; /* Length of namestring, when needed */
+
+ /* Current partial symtab */
+ struct partial_symtab *pst;
+
+ /* List of current psymtab's include files */
+ char **psymtab_include_list;
+ int includes_allocated;
+ int includes_used;
+
+ /* Index within current psymtab dependency list */
+ struct partial_symtab **dependency_list;
+ int dependencies_used, dependencies_allocated;
+
+ /* Setup a define to deal cleanly with the underscore problem */
+
+#ifdef NAMES_HAVE_UNDERSCORE
+#define HASH_OFFSET 1
+#else
+#define HASH_OFFSET 0
+#endif
+
+ global_symbols = static_symbols =
+ (struct pending *) 0;
+ pst = (struct partial_symtab *) 0;
+
+ includes_allocated = 30;
+ includes_used = 0;
+ psymtab_include_list = (char **) alloca (includes_allocated *
+ sizeof (char *));
+
+ dependencies_allocated = 30;
+ dependencies_used = 0;
+ dependency_list =
+ (struct partial_symtab **) alloca (dependencies_allocated *
+ sizeof (struct partial_symtab *));
+
+ old_chain = make_cleanup (free_all_psymtabs, 0);
+
+ /* Init bincl list */
+ init_bincl_list (20);
+ make_cleanup (free_bincl_list, 0);
+
+ /* Setup global partial symbol list */
+ init_psymbol_list (nlistlen);
+
+ last_source_file = 0;
+
+#ifdef END_OF_TEXT_DEFAULT
+ end_of_text_addr = END_OF_TEXT_DEFAULT;
+#endif
+
+ symtab_input_desc = desc; /* This is needed for fill_symbuf below */
+ symbuf_end = symbuf_idx = 0;
+
+ for (symnum = 0; symnum < nlistlen; symnum++)
+ {
+ struct nlist *bufp;
+ unsigned char type;
+
+ /* Get the symbol for this run and pull out some info */
+ QUIT; /* allow this to be interruptable */
+ if (symbuf_idx == symbuf_end)
+ fill_symbuf ();
+ bufp = &symbuf[symbuf_idx++];
+ type = bufp->n_type;
+
+ /*
+ * Special cases to speed up readin.
+ */
+ if (type == N_SLINE) continue;
+
+ namestring = bufp->n_un.n_strx ? bufp->n_un.n_strx + stringtab : "";
+
+ switch (type)
+ {
+ /*
+ * Standard, non-debugger, symbols
+ */
+
+ case N_TEXT | N_EXT:
+ /* Catch etext */
+
+ if (!strcmp (namestring, "_etext"))
+ end_of_text_addr = bufp->n_value;
+ /* Fall through */
+
+#ifdef N_NBTEXT
+ case N_NBTEXT | N_EXT:
+#endif
+#ifdef N_NBDATA
+ case N_NBDATA | N_EXT:
+#endif
+#ifdef N_NBBSS
+ case N_NBBSS | N_EXT:
+#endif
+ case N_ABS | N_EXT:
+ case N_DATA | N_EXT:
+ case N_BSS | N_EXT:
+ /* Figure out beginning and end of global linker symbol
+ section and put non-debugger specified symbols on
+ tmp_symchain */
+
+ last_global_sym = symnum;
+ if (!first_global_sym) first_global_sym = symnum;
+
+ record_misc_function (namestring, bufp->n_value); /* Always */
+
+ continue;
+
+#ifdef N_NBTEXT
+ case N_NBTEXT:
+#endif
+ case N_TEXT:
+ if (!strcmp (namestring + strlen (namestring) - 2, ".o")
+ || !strncmp (namestring, "-l", 2))
+ {
+ if (num_object_files++ == 1)
+ first_object_file_end = bufp->n_value;
+ if (past_first_source_file && pst)
+ {
+ end_psymtab (pst, psymtab_include_list, includes_used,
+ symnum * sizeof (struct nlist), bufp->n_value,
+ dependency_list, dependencies_used,
+ next_ps_global, next_ps_static);
+ pst = (struct partial_symtab *) 0;
+ includes_used = 0;
+ dependencies_used = 0;
+ }
+ else
+ past_first_source_file = 1;
+ }
+ continue;
+
+ case N_UNDF:
+ case N_UNDF | N_EXT:
+ case N_ABS:
+ case N_DATA:
+ case N_BSS:
+#ifdef N_NBDATA
+ case N_NBDATA:
+#endif
+#ifdef N_NBBSS
+ case N_NBBSS:
+#endif
+ case N_FN:
+ /* Keep going . . .*/
+
+ /*
+ * Special symbol types for GNU
+ */
+#ifdef N_INDR
+ case N_INDR:
+ case N_INDR | N_EXT:
+#endif
+#ifdef N_SETA
+ case N_SETA:
+ case N_SETA | N_EXT:
+ case N_SETT:
+ case N_SETT | N_EXT:
+ case N_SETD:
+ case N_SETD | N_EXT:
+ case N_SETB:
+ case N_SETB | N_EXT:
+ case N_SETV:
+ case N_SETV | N_EXT:
+#endif
+ continue;
+
+ /*
+ * Debugger symbols
+ */
+
+ case N_SO:
+ /* End the current partial symtab and start a new one */
+
+ if (past_first_source_file && pst)
+ {
+ end_psymtab (pst, psymtab_include_list, includes_used,
+ symnum * sizeof (struct nlist), bufp->n_value,
+ dependency_list, dependencies_used,
+ next_ps_global, next_ps_static);
+ pst = (struct partial_symtab *) 0;
+ includes_used = 0;
+ dependencies_used = 0;
+ }
+ else
+ past_first_source_file = 1;
+
+ pst = start_psymtab (namestring, bufp->n_value,
+ symnum * sizeof (struct nlist),
+ next_ps_global, next_ps_static);
+
+ continue;
+
+#ifdef N_BINCL
+ case N_BINCL:
+ /* Add this bincl to the bincl_list for future EXCLs. No
+ need to save the string; it'll be around until
+ read_dbx_symtab function return */
+ add_bincl_to_list (pst, namestring, bufp->n_value);
+
+ /* Fall through */
+#endif
+
+ case N_SOL:
+ /* Mark down an include file in the current psymtab */
+
+ psymtab_include_list[includes_used++] = namestring;
+ if (includes_used >= includes_allocated)
+ {
+ char **orig = psymtab_include_list;
+
+ psymtab_include_list = (char **)
+ alloca ((includes_allocated *= 2) *
+ sizeof (char *));
+ bcopy (orig, psymtab_include_list,
+ includes_used * sizeof (char *));
+#ifdef DEBUG_INFO
+ fprintf (stderr, "Had to realloc includes. New size: %d\n",
+ includes_allocated);
+#endif
+ }
+ continue;
+
+ case N_FUN:
+ case N_SSYM:
+ case N_GSYM:
+ case N_LSYM:
+ case N_STSYM:
+ case N_LCSYM:
+ case N_ENTRY:
+#ifdef N_MAIN
+ case N_MAIN:
+#endif
+#ifdef N_BSLINE
+ case N_BSLINE:
+#endif
+ case N_PC:
+#ifdef N_M2C
+ case N_M2C:
+ case N_SCOPE:
+#endif
+ /* Process a symbol as appropriate for the type (this
+ information is contained in the name of the symbol) */
+
+ if (namestring[0] != '\0')
+#if 1
+ process_symbol_for_psymtab (namestring);
+#else
+ process_symbol_for_psymtab (namestring, tmp_symchain);
+#endif
+ continue;
+
+#ifdef N_BINCL
+ case N_EXCL:
+ /* Find the corresponding bincl and mark that psymtab on the
+ psymtab dependency list */
+ {
+ struct partial_symtab *needed_pst =
+ find_corresponding_bincl_psymtab (namestring, bufp->n_value);
+
+ /* If this include file was defined earlier in this file,
+ leave it alone. */
+ if (needed_pst == pst) continue;
+
+ if (needed_pst)
+ {
+ int i;
+ int found = 0;
+
+ for (i = 0; i < dependencies_used; i++)
+ if (dependency_list[i] == needed_pst)
+ {
+ found = 1;
+ break;
+ }
+
+ /* If it's already in the list, skip the rest. */
+ if (found) continue;
+
+ dependency_list[dependencies_used++] = needed_pst;
+ if (dependencies_used >= dependencies_allocated)
+ {
+ struct partial_symtab **orig = dependency_list;
+ dependency_list =
+ (struct partial_symtab **)
+ alloca ((dependencies_allocated *= 2)
+ * sizeof (struct partial_symtab *));
+ bcopy (orig, dependency_list,
+ (dependencies_used
+ * sizeof (struct partial_symtab *)));
+#ifdef DEBUG_INFO
+ fprintf (stderr, "Had to reallocate dependency list.\n");
+ fprintf (stderr, "New dependencies allocated: %d\n",
+ dependencies_allocated);
+#endif
+ }
+ }
+ else
+ error ("Invalid symbol data: \"repeated\" header file not previously seen, at symtab pos %d.",
+ symnum);
+ }
+ continue;
+
+ case N_EINCL:
+#endif
+#ifdef N_DSLINE
+ case N_DSLINE:
+#endif
+ case N_LENG:
+ case N_BCOMM:
+ case N_ECOMM:
+ case N_ECOML:
+ case N_FNAME:
+ case N_SLINE:
+ case N_RSYM:
+ case N_PSYM:
+ case N_LBRAC:
+ case N_RBRAC:
+ /* These symbols aren't interesting; don't worry about them */
+
+ continue;
+
+ default:
+ /* If we haven't found it yet, we've got problems */
+
+ if (IGNORE_SYMBOL (type))
+ continue;
+
+ fatal ("Bad symbol type 0x%x encountered in gdb scan", type);
+ }
+ }
+
+ if (last_source_file)
+ {
+ end_psymtab (pst, psymtab_include_list, includes_used,
+ symnum * sizeof (struct nlist), end_of_text_addr,
+ dependency_list, dependencies_used,
+ next_ps_global, next_ps_static);
+ includes_used = 0;
+ dependencies_used = 0;
+ pst = (struct partial_symtab *) 0;
+ }
+
+ free_bincl_list ();
+ discard_cleanups (old_chain);
+}
+
+/*
+ * Take a single symbol (name: NAME) and process it (add it to the
+ * app psymbol list or not).
+ */
+static void
+process_symbol_for_psymtab (name)
+ char *name;
+{
+ char *p = (char *) index(name, ':') + 1;
+ int deftype;
+ struct partial_symbol *sym;
+ enum { T_IGNORE, T_STATIC, T_GLOBAL } symbol_type;
+ enum namespace ns = UNDEF_NAMESPACE;
+ enum address_class class;
+ int hash;
+
+ if (p == (char *) 0x1)
+ /* No ":" ; I guess it's not a debuggging symbol */
+ return;
+
+ if ((*p >= '0' && *p <= '9') || *p == '(')
+ deftype = 'l';
+ else
+ deftype = *p;
+
+ /* Figure out how to handle this symbol */
+ switch (deftype)
+ {
+ /* T is a struct/union/enum, t is a typedef */
+ case 'T':
+ symbol_type = T_STATIC;
+ ns = STRUCT_NAMESPACE;
+ class = LOC_TYPEDEF;
+ break;
+ case 't':
+ symbol_type = T_STATIC;
+ ns = VAR_NAMESPACE;
+ class = LOC_TYPEDEF;
+ break;
+ case 'c':
+ symbol_type = T_STATIC;
+ ns = VAR_NAMESPACE;
+ class = LOC_CONST;
+ break;
+ case 'S':
+ symbol_type = T_STATIC;
+ ns = VAR_NAMESPACE;
+ class = LOC_STATIC;
+ break;
+ case 'f':
+ symbol_type = T_STATIC;
+ ns = VAR_NAMESPACE;
+ class = LOC_BLOCK;
+ break;
+ case 'F':
+ symbol_type = T_GLOBAL;
+ ns = VAR_NAMESPACE;
+ class = LOC_BLOCK;
+ break;
+ case 'G':
+ symbol_type = T_GLOBAL;
+ ns = VAR_NAMESPACE;
+ class = LOC_STATIC;
+ break;
+ default:
+ return;
+ }
+
+ /* Create the symbol and store it on the list */
+ /* There's a better algorithm possible for the allocation; figure
+ out how far through the symbol table we are and do a reestimate */
+ if (symbol_type == T_STATIC)
+ {
+ if (next_ps_static >= static_psymbols + static_psymbols_allocated)
+ {
+ static_psymbols = (struct partial_symbol *)
+ xrealloc (static_psymbols,
+ (static_psymbols_allocated * 2
+ * sizeof (struct partial_symbol)));
+ /* Next assumes we only went one over. Should be good if
+ program works correctly */
+ next_ps_static = static_psymbols + static_psymbols_allocated;
+ static_psymbols_allocated *= 2;
+#ifdef DEBUGINFO
+ fprintf(stderr, "debuginfo: Had to realloc statics\n");
+#endif
+ }
+ sym = next_ps_static++;
+ }
+ else
+ {
+ if (next_ps_global >= global_psymbols + global_psymbols_allocated)
+ {
+ global_psymbols = (struct partial_symbol *)
+ xrealloc (global_psymbols,
+ (global_psymbols_allocated * 2
+ * sizeof (struct partial_symbol)));
+ next_ps_global = global_psymbols + global_psymbols_allocated;
+ global_psymbols_allocated *= 2;
+#ifdef DEBUGINFO
+ fprintf(stderr, "debuginfo: Had to realloc globals\n");
+#endif
+ }
+ sym = next_ps_global++;
+ }
+
+ SYMBOL_NAME(sym) = (char *) obstack_alloc (psymbol_obstack,
+ p - name);
+ strncpy(SYMBOL_NAME(sym), name, p - name - 1);
+ SYMBOL_NAME(sym)[p - name - 1] = '\0';
+ SYMBOL_NAMESPACE(sym) = ns;
+ SYMBOL_CLASS(sym) = class;
+}
+#undef HASH_OFFSET
+
+/*
+ * Allocate and partially fill a partial symtab. It will be
+ * completely filled at the end of the symbol list.
+ */
+static struct partial_symtab *
+start_psymtab (filename, textlow, ldsymoff, global_syms, static_syms)
+ char *filename;
+ int textlow;
+ int ldsymoff;
+ struct partial_symbol *global_syms;
+ struct partial_symbol *static_syms;
+{
+ struct partial_symtab *result =
+ (struct partial_symtab *) obstack_alloc (psymbol_obstack,
+ sizeof (struct partial_symtab));
+
+ result->filename =
+ (char *) obstack_alloc (psymbol_obstack,
+ strlen (filename) + 1);
+ strcpy (result->filename, filename);
+
+ result->textlow = textlow;
+ result->ldsymoff = ldsymoff;
+
+ result->readin = 0;
+
+ result->globals_offset = global_syms - global_psymbols;
+ result->statics_offset = static_syms - static_psymbols;
+
+ result->n_global_syms = 0;
+ result->n_static_syms = 0;
+
+ return result;
+}
+
+static int
+compare_psymbols (s1, s2)
+ register struct partial_symbol *s1, *s2;
+{
+ register char
+ *st1 = SYMBOL_NAME (s1),
+ *st2 = SYMBOL_NAME (s2);
+
+ return (st1[0] - st2[0] ? st1[0] - st2[0] :
+ strcmp (st1 + 1, st2 + 1));
+}
+
+
+/* Close off the current usage of a partial_symbol table entry. This
+ involves setting the correct number of includes (with a realloc),
+ setting the high text mark, setting the symbol length in the
+ executable, and setting the length of the global and static lists
+ of psymbols.
+
+ The global symbols and static symbols are then seperately sorted.
+
+ Then the partial symtab is put on the global list.
+ *** List variables and peculiarities of same. ***
+ */
+static void
+end_psymtab (pst, include_list, num_includes, capping_symbol_offset,
+ capping_text, dependency_list, number_dependencies,
+ capping_global, capping_static)
+ struct partial_symtab *pst;
+ char **include_list;
+ int num_includes;
+ int capping_symbol_offset;
+ int capping_text;
+ struct partial_symtab **dependency_list;
+ int number_dependencies;
+ struct partial_symbol *capping_global, *capping_static;
+{
+ int i;
+
+ pst->ldsymlen = capping_symbol_offset - pst->ldsymoff;
+ pst->texthigh = capping_text;
+
+ pst->n_global_syms =
+ capping_global - (global_psymbols + pst->globals_offset);
+ pst->n_static_syms =
+ capping_static - (static_psymbols + pst->statics_offset);
+
+ pst->dependencies = (struct partial_symtab **)
+ obstack_alloc (psymbol_obstack,
+ number_dependencies * sizeof (struct partial_symtab *));
+ bcopy (dependency_list, pst->dependencies,
+ number_dependencies * sizeof (struct partial_symtab *));
+ pst->number_of_dependencies = number_dependencies;
+
+ for (i = 0; i < num_includes; i++)
+ {
+ /* Eventually, put this on obstack */
+ struct partial_symtab *subpst =
+ (struct partial_symtab *)
+ obstack_alloc (psymbol_obstack,
+ sizeof (struct partial_symtab));
+
+ subpst->filename =
+ (char *) obstack_alloc (psymbol_obstack,
+ strlen (include_list[i]) + 1);
+ strcpy (subpst->filename, include_list[i]);
+
+ subpst->ldsymoff =
+ subpst->ldsymlen =
+ subpst->textlow =
+ subpst->texthigh = 0;
+ subpst->readin = 0;
+
+ subpst->dependencies = (struct partial_symtab **)
+ obstack_alloc (psymbol_obstack,
+ sizeof (struct partial_symtab *));
+ subpst->dependencies[0] = pst;
+ subpst->number_of_dependencies = 1;
+
+ subpst->globals_offset =
+ subpst->n_global_syms =
+ subpst->statics_offset =
+ subpst->n_static_syms = 0;
+
+ subpst->next = partial_symtab_list;
+ partial_symtab_list = subpst;
+ }
+
+ /* Sort the global list; don't sort the static list */
+ qsort (global_psymbols + pst->globals_offset, pst->n_global_syms,
+ sizeof (struct partial_symbol), compare_psymbols);
+
+ /* Put the psymtab on the psymtab list */
+ pst->next = partial_symtab_list;
+ partial_symtab_list = pst;
+}
+
+/*
+ * Read in all of the symbols for a given psymtab for real. Return
+ * the value of the symtab you create. Do not free the storage
+ * allocated to the psymtab; it may have pointers to it.
+ */
+static void scan_file_globals ();
+static void read_ofile_symtab ();
+
+struct symtab *
+psymtab_to_symtab(pst)
+ struct partial_symtab *pst;
+{
+ int desc;
+ DECLARE_FILE_HEADERS;
+ char *stringtab;
+ struct partial_symtab **list_patch;
+ int stsize, val;
+ struct stat statbuf;
+ struct cleanup *old_chain;
+ extern void close ();
+ int i;
+ struct symtab *result;
+ char *name = symfile; /* Some of the macros require the */
+ /* variable "name" to be defined in */
+ /* the context in which they execute */
+ /* (Yech!) */
+
+ if (!pst)
+ return 0;
+
+ if (pst->readin)
+ {
+ fprintf (stderr, "Psymtab for %s already read in. Shouldn't happen.\n",
+ pst->filename);
+ return 0;
+ }
+
+ if (!name)
+ error("No symbol file currently specified; use command symbol-file");
+
+ /* Read in all partial symbtabs on which this one is dependent */
+ for (i = 0; i < pst->number_of_dependencies; i++)
+ if (!pst->dependencies[i]->readin)
+ psymtab_to_symtab (pst->dependencies[i]);
+
+ if (pst->ldsymlen) /* Otherwise it's a dummy */
+ {
+ /* Open symbol file and read in string table */
+ stat (name, &statbuf);
+ desc = open(name, O_RDONLY, 0); /* symbol_file_command
+ guarrantees that the symbol file name
+ will be absolute, so there is no
+ need for openp */
+
+ old_chain = make_cleanup (close, desc);
+
+ if (desc < 0)
+ error("Symbol file not readable");
+
+ READ_FILE_HEADERS (desc, name);
+
+ /* Read in the string table */
+ lseek (desc, STRING_TABLE_OFFSET, L_SET);
+ READ_STRING_TABLE_SIZE (stsize);
+ if (stsize >= 0 && stsize < statbuf.st_size)
+ stringtab = (char *) alloca (stsize);
+ else
+ stringtab = NULL;
+ if (stringtab == NULL)
+ error ("ridiculous string table size: %d bytes", name, stsize);
+
+ bcopy (&stsize, stringtab, sizeof stsize);
+ val = myread (desc, stringtab + sizeof stsize, stsize - sizeof stsize);
+ if (val < 0)
+ perror_with_name (name);
+
+ /* Init stuff necessary for reading in symbols */
+ free_pendings = 0;
+ pending_blocks = 0;
+ file_symbols = 0;
+ global_symbols = 0;
+ make_cleanup (really_free_pendings, 0);
+
+ /* Read in this files symbols */
+ lseek (desc, SYMBOL_TABLE_OFFSET, L_SET);
+ read_ofile_symtab (desc, stringtab, pst->ldsymoff,
+ pst->ldsymlen, pst->textlow,
+ pst->texthigh - pst->textlow, 0);
+ sort_symtab_syms (symtab_list); /* At beginning since just added */
+
+ /* Match with global symbols */
+ lseek (desc, SYMBOL_TABLE_OFFSET, L_SET);
+ scan_file_globals (desc, stringtab,
+ first_global_sym * sizeof(struct nlist),
+ last_global_sym - first_global_sym + 1);
+
+ do_cleanups (old_chain);
+ }
+
+ /* Find pst in list, prune it, and free it's storage */
+ for (list_patch = &partial_symtab_list;
+ *list_patch && *list_patch != pst;
+ list_patch = &((*list_patch)->next))
+ ;
+
+ if (!(*list_patch)) /* pst not in list. Don't worry about it? */
+ fatal ("internal: psymtab_to_symtab called with non-listed pst");
+
+ *list_patch = (*list_patch)->next; /* Prune */
+
+ pst->readin = 1; /* Mark as read in */
+
+ /* It's the last one if we actually read something in */
+ if (pst->ldsymlen)
+ return symtab_list;
+ else
+ /* Search through list for correct name. */
+ for (result = symtab_list; result; result = result->next)
+ if (!strcmp (result->filename, pst->filename))
+ return result;
+
+ return 0;
+}
+
+/*
+ * Scan through all of the global symbols defined in the object file,
+ * assigning values to the debugging symbols that need to be assigned
+ * to.
+ *
+ * DESC is the file descriptor of the symbol file, with the seek
+ * pointer pointing at the beginning of the symbol table.
+ * STRINGTAB is the file's string table, already read in.
+ * OFFSET is the offset (in bytes) of the beginning of the global
+ * symbols from the beginning of the symbol table.
+ * NUMSYMS is the number of symbols that have to be checked.
+ */
+static void
+scan_file_globals (desc, stringtab, offset, numsyms)
+ int desc;
+ char *stringtab;
+ int offset;
+ int numsyms;
+{
+ int hash;
+
+ lseek(desc, offset, L_INCR);
+ symtab_input_desc = desc;
+ symbuf_end = symbuf_idx = 0;
+
+ for (symnum = 0; symnum < numsyms; symnum++)
+ {
+ struct nlist *bufp;
+ unsigned char type;
+ char *namestring;
+
+ QUIT;
+ if (symbuf_idx == symbuf_end)
+ fill_symbuf ();
+
+ bufp = &symbuf[symbuf_idx++];
+ type = bufp->n_type;
+
+ if (type & N_EXT && type != N_EXT)
+ {
+ struct symbol *sym, *prev;
+
+ namestring = bufp->n_un.n_strx ?
+ bufp->n_un.n_strx + stringtab : "";
+ prev = (struct symbol *) 0;
+
+ /* Get the hash index and check all the symbols
+ under that hash index. */
+
+#ifdef NAMES_HAVE_UNDERSCORE
+ hash = hashname (namestring + 1);
+#else /* ! NAMES_HAVE_UNDERSCORE */
+ hash = hashname (namestring);
+#endif /* ! NAMES_HAVE_UNDERSCORE */
+ for (sym = global_sym_chain[hash]; sym;)
+ {
+ if (
+#ifdef NAMES_HAVE_UNDERSCORE
+ *namestring == '_'
+ && namestring[1] == SYMBOL_NAME (sym)[0]
+ && !strcmp(namestring + 2, SYMBOL_NAME (sym) + 1)
+#else /* ! NAMES_HAVE_UNDERSCORE */
+ namestring[0] == SYMBOL_NAME (sym) [0]
+ && !strcmp(namestring + 1, SYMBOL_NAME(sym) + 1)
+#endif /* ! NAMES_HAVE_UNDERSCORE */
+ )
+ {
+ /* Splice this symbol out of the hash chain and
+ assign the value we have to it. */
+ if (prev)
+ SYMBOL_VALUE (prev) = SYMBOL_VALUE (sym);
+ else
+ global_sym_chain[hash]
+ = (struct symbol *) SYMBOL_VALUE (sym);
+ SYMBOL_VALUE (sym) = bufp->n_value;
+ if (prev)
+ sym = (struct symbol *) SYMBOL_VALUE (prev);
+ else
+ sym = global_sym_chain[hash];
+ break; /* Only one reference per file */
+ }
+ else
+ {
+ prev = sym;
+ sym = (struct symbol *) SYMBOL_VALUE (sym);
+ }
+ }
+ }
+ }
+ /* There shouldn't be anything left on the hash list at this point.
+ If there is, we have done something wrong. For right now it's
+ worth checking, until I get the bugs out. */
+ /* Sigh. Unfortunately, the above is not true. If an extern
+ variable is mentioned in an include file (or a program) and the
+ variable is never either referenced or defined, there will be a
+ debugger symbol with no "real" symbol. Oh well. */
+}
+
+/*
+ * Read in a defined section of a specific object file's symbols.
+ *
+ * DESC is the file descriptor for the file, positioned at the
+ * beginning of the symtab
+ * STRINGTAB is a pointer to the files string
+ * table, already read in
+ * SYM_OFFSET is the offset within the file of
+ * the beginning of the symbols we want to read, NUM_SUMBOLS is the
+ * number of symbols to read
+ * TEXT_OFFSET is the offset to be added to
+ * all values of symbols coming in and
+ * TEXT_SIZE is the size of the text segment read in.
+ * OFFSET is a flag which indicates that the value of all of the
+ * symbols should be offset by TEXT_OFFSET (for the purposes of
+ * incremental linking).
+ */
+
+static void
+read_ofile_symtab (desc, stringtab, sym_offset,
+ sym_size, text_offset, text_size, offset)
+ int desc;
+ register char *stringtab;
+ int sym_offset;
+ int sym_size;
+ int text_offset;
+ int text_size;
+ int offset;
+{
+ register char *namestring;
+ register struct symbol *sym, *prev;
+ int hash;
+ struct cleanup *old_chain;
+ struct nlist *bufp;
+ unsigned char type;
+#ifdef N_BINCL
+ subfile_stack = 0;
+#endif
+
+ stringtab_global = stringtab;
+ last_source_file = 0;
+
+ symtab_input_desc = desc;
+ symbuf_end = symbuf_idx = 0;
+ lseek(desc, sym_offset, L_INCR);
+
+ fill_symbuf();
+ bufp = &symbuf[symbuf_idx];
+ if ((unsigned char) bufp->n_type != N_SO)
+ fatal("First symbol in segment of executable not a source symbol");
+
+ for (symnum = 0;
+ symnum < sym_size / sizeof(struct nlist);
+ symnum++)
+ {
+ QUIT; /* Allow this to be interruptable */
+ if (symbuf_idx == symbuf_end)
+ fill_symbuf();
+ bufp = &symbuf[symbuf_idx++];
+ type = bufp->n_type;
+
+ if (offset &&
+ (type == N_TEXT || type == N_DATA || type == N_BSS))
+ bufp->n_value += text_offset;
+
+ namestring = bufp->n_un.n_strx ? bufp->n_un.n_strx + stringtab : "";
+
+ if (type & N_STAB)
+ process_one_symbol(type, bufp->n_desc,
+ bufp->n_value, namestring);
+ /* We skip checking for a new .o or -l file; that should never
+ happen in this routine. */
+ else if (type == N_TEXT
+ && !strcmp (namestring, GCC_COMPILED_FLAG_SYMBOL))
+ processing_gcc_compilation = 1;
+ else if (type & N_EXT || type == N_TEXT
+#ifdef N_NBTEXT
+ || type == N_NBTEXT
+#endif
+ )
+ /* Global symbol: see if we came across a dbx defintion for
+ a corresponding symbol. If so, store the value. Remove
+ syms from the chain when their values are stored, but
+ search the whole chain, as there may be several syms from
+ different files with the same name. */
+ /* This is probably not true. Since the files will be read
+ in one at a time, each reference to a global symbol will
+ be satisfied in each file as it appears. So we skip this
+ section. */
+ &stringtab_global; /* For debugger; am I right? */
+ }
+ end_symtab (text_offset + text_size);
+}
+
+static int
+hashname (name)
+ char *name;
+{
+ register char *p = name;
+ register int total = p[0];
+ register int c;
+
+ c = p[1];
+ total += c << 2;
+ if (c)
+ {
+ c = p[2];
+ total += c << 4;
+ if (c)
+ total += p[3] << 6;
+ }
+
+ /* Ensure result is positive. */
+ if (total < 0) total += (1000 << 6);
+ return total % HASHSIZE;
+}
+
+/* Put all appropriate global symbols in the symseg data
+ onto the hash chains so that their addresses will be stored
+ when seen later in loader global symbols. */
+
+static void
+hash_symsegs ()
+{
+ /* Look at each symbol in each block in each symseg symtab. */
+ struct symtab *s;
+ for (s = symseg_chain; s; s = s->next)
+ {
+ register int n;
+ for (n = BLOCKVECTOR_NBLOCKS (BLOCKVECTOR (s)) - 1; n >= 0; n--)
+ {
+ register struct block *b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), n);
+ register int i;
+ for (i = BLOCK_NSYMS (b) - 1; i >= 0; i--)
+ {
+ register struct symbol *sym = BLOCK_SYM (b, i);
+
+ /* Put the symbol on a chain if its value is an address
+ that is figured out by the loader. */
+
+ if (SYMBOL_CLASS (sym) == LOC_EXTERNAL)
+ {
+ register int hash = hashname (SYMBOL_NAME (sym));
+ SYMBOL_VALUE (sym) = (int) global_sym_chain[hash];
+ global_sym_chain[hash] = sym;
+ SYMBOL_CLASS (sym) = LOC_STATIC;
+ }
+ }
+ }
+ }
+}
+
+static void
+process_one_symbol (type, desc, value, name)
+ int type, desc;
+ CORE_ADDR value;
+ char *name;
+{
+ register struct context_stack *new;
+
+ /* Something is wrong if we see real data before
+ seeing a source file name. */
+
+ if (last_source_file == 0 && type != N_SO)
+ {
+ /* Currently this ignores N_ENTRY on Gould machines, N_NSYM on machines
+ where that code is defined, and all symbols on the Convex. */
+ if (IGNORE_SYMBOL (type))
+ return;
+
+ error ("Invalid symbol data: does not start by identifying a source file.");
+ }
+
+ switch (type)
+ {
+ case N_FUN:
+ case N_FNAME:
+ /* Either of these types of symbols indicates the start of
+ a new function. We must process its "name" normally for dbx,
+ but also record the start of a new lexical context, and possibly
+ also the end of the lexical context for the previous function. */
+
+ within_function = 1;
+ if (context_stack_depth > 0)
+ {
+ new = &context_stack[--context_stack_depth];
+ /* Make a block for the local symbols within. */
+ finish_block (new->name, &local_symbols, new->old_blocks,
+ new->start_addr, value);
+ }
+ /* Stack must be empty now. */
+ if (context_stack_depth != 0)
+ error ("Invalid symbol data: unmatched N_LBRAC before symtab pos %d.",
+ symnum);
+
+ new = &context_stack[context_stack_depth++];
+ new->old_blocks = pending_blocks;
+ new->start_addr = value;
+ new->name = define_symbol (value, name, desc);
+ local_symbols = 0;
+ break;
+
+ case N_LBRAC:
+ /* This "symbol" just indicates the start of an inner lexical
+ context within a function. */
+
+ if (context_stack_depth == context_stack_size)
+ {
+ context_stack_size *= 2;
+ context_stack = (struct context_stack *)
+ xrealloc (context_stack,
+ (context_stack_size
+ * sizeof (struct context_stack)));
+ }
+
+ new = &context_stack[context_stack_depth++];
+ new->depth = desc;
+ new->locals = local_symbols;
+ new->old_blocks = pending_blocks;
+ new->start_addr = value;
+ new->name = 0;
+ local_symbols = 0;
+ break;
+
+ case N_RBRAC:
+ /* This "symbol" just indicates the end of an inner lexical
+ context that was started with N_RBRAC. */
+ new = &context_stack[--context_stack_depth];
+ if (desc != new->depth)
+ error ("Invalid symbol data: N_LBRAC/N_RBRAC symbol mismatch, symtab pos %d.", symnum);
+ local_symbols = new->locals;
+
+ /* If this is not the outermost LBRAC...RBRAC pair in the
+ function, its local symbols preceded it, and are the ones
+ just recovered from the context stack. Defined the block for them.
+
+ If this is the outermost LBRAC...RBRAC pair, there is no
+ need to do anything; leave the symbols that preceded it
+ to be attached to the function's own block. */
+ if (local_symbols && context_stack_depth > 1)
+ {
+ /* Muzzle a compiler bug that makes end > start. */
+ if (new->start_addr > value)
+ new->start_addr = value;
+ /* Make a block for the local symbols within. */
+ finish_block (0, &local_symbols, new->old_blocks,
+ new->start_addr + last_source_start_addr,
+ value + last_source_start_addr);
+ }
+ break;
+
+ case N_FN:
+ /* This kind of symbol supposedly indicates the start
+ of an object file. In fact this type does not appear. */
+ break;
+
+ case N_SO:
+ /* This type of symbol indicates the start of data
+ for one source file.
+ Finish the symbol table of the previous source file
+ (if any) and start accumulating a new symbol table. */
+ if (last_source_file)
+ end_symtab (value);
+ start_symtab (name, value);
+ break;
+
+ case N_SOL:
+ /* This type of symbol indicates the start of data for
+ a sub-source-file, one whose contents were copied or
+ included in the compilation of the main source file
+ (whose name was given in the N_SO symbol.) */
+ start_subfile (name);
+ break;
+
+#ifdef N_BINCL
+ case N_BINCL:
+ push_subfile ();
+ add_new_header_file (name, value);
+ start_subfile (name);
+ break;
+
+ case N_EINCL:
+ start_subfile (pop_subfile ());
+ break;
+
+ case N_EXCL:
+ add_old_header_file (name, value);
+ break;
+#endif /* have N_BINCL */
+
+ case N_SLINE:
+ /* This type of "symbol" really just records
+ one line-number -- core-address correspondence.
+ Enter it in the line list for this symbol table. */
+ record_line (desc, value);
+ break;
+
+ case N_BCOMM:
+ case N_ECOMM:
+ case N_ECOML:
+ case N_LENG:
+ break;
+
+ default:
+ if (name)
+ define_symbol (value, name, desc);
+ }
+}
+
+/* This function was added for C++ functionality. I presume that it
+ condenses the bunches formed by reading in an additional .o file
+ (incremental linking). */
+
+static void
+condense_addl_misc_bunches ()
+{
+ register int i, j;
+ register struct misc_bunch *bunch;
+#ifdef NAMES_HAVE_UNDERSCORE
+ int offset = 1;
+#else
+ int offset = 0;
+#endif
+
+ misc_function_vector
+ = (struct misc_function *) xrealloc (misc_function_vector,
+ (misc_count + misc_function_count) * sizeof (struct misc_function));
+
+ j = misc_function_count;
+ bunch = misc_bunch;
+ while (bunch)
+ {
+ for (i = 0; i < misc_bunch_index; i++)
+ {
+ misc_function_vector[j] = bunch->contents[i];
+ misc_function_vector[j].name
+ = concat (misc_function_vector[j].name
+ + (misc_function_vector[j].name[0] == '_' ? offset : 0),
+ "", "");
+ j++;
+ }
+ bunch = bunch->next;
+ misc_bunch_index = MISC_BUNCH_SIZE;
+ }
+
+ misc_function_count += misc_count;
+
+ /* Sort the misc functions by address. */
+
+ qsort (misc_function_vector, misc_function_count,
+ sizeof (struct misc_function), compare_misc_functions);
+}
+
+
+/* Read in another .o file and create a symtab entry for it.*/
+
+static void
+read_addl_syms (desc, stringtab, nlistlen, text_addr, text_size)
+ int desc;
+ register char *stringtab;
+ register int nlistlen;
+ unsigned text_addr;
+ int text_size;
+{
+ FILE *stream = fdopen (desc, "r");
+ register char *namestring;
+ register struct symbol *sym, *prev;
+ int hash;
+ int num_object_files = 0;
+
+#ifdef N_BINCL
+ subfile_stack = 0;
+#endif
+
+ last_source_file = 0;
+ bzero (global_sym_chain, sizeof global_sym_chain);
+ symtab_input_desc = desc;
+ stringtab_global = stringtab;
+ fill_symbuf ();
+
+ for (symnum = 0; symnum < nlistlen; symnum++)
+ {
+ struct nlist *bufp;
+ unsigned char type;
+
+ QUIT; /* allow this to be interruptable */
+ if (symbuf_idx == symbuf_end)
+ fill_symbuf ();
+ bufp = &symbuf[symbuf_idx++];
+ type = bufp->n_type & N_TYPE;
+ namestring = bufp->n_un.n_strx ? bufp->n_un.n_strx + stringtab : "";
+
+ if( (type == N_TEXT) || (type == N_DATA) || (type == N_BSS) )
+ {
+ /* Relocate this file's symbol table information
+ to the address it has been loaded into. */
+ bufp->n_value += text_addr;
+ }
+
+ type = bufp->n_type;
+
+ if (type & N_STAB)
+ process_one_symbol (type, bufp->n_desc,
+ bufp->n_value, namestring);
+ /* A static text symbol whose name ends in ".o"
+ can only mean the start of another object file.
+ So end the symtab of the source file we have been processing.
+ This is how we avoid counting the libraries as part
+ or the last source file.
+ Also this way we find end of first object file (crt0). */
+ else if ((type == N_TEXT
+#ifdef N_NBTEXT
+ || type == N_NBTEXT
+#endif
+ )
+ && (!strcmp (namestring + strlen (namestring) - 2, ".o"))
+ || ! strcmp (namestring, "-l", 2))
+ {
+ if (num_object_files++ == 1)
+ first_object_file_end = bufp->n_value;
+ if (last_source_file)
+ end_symtab (bufp->n_value);
+ }
+ else if (type & N_EXT || type == N_TEXT
+#ifdef N_NBTEXT
+ || type == N_NBTEXT
+#endif
+ )
+ {
+ int used_up = 0;
+
+ /* Record the location of _etext. */
+ if (type == (N_TEXT | N_EXT)
+ && !strcmp (namestring, "_etext"))
+ end_of_text_addr = bufp->n_value;
+
+ /* Global symbol: see if we came across a dbx definition
+ for a corresponding symbol. If so, store the value.
+ Remove syms from the chain when their values are stored,
+ but search the whole chain, as there may be several syms
+ from different files with the same name. */
+ if (type & N_EXT)
+ {
+ prev = 0;
+#ifdef NAMES_HAVE_UNDERSCORE
+ hash = hashname (namestring + 1);
+#else /* not NAMES_HAVE_UNDERSCORE */
+ hash = hashname (namestring);
+#endif /* not NAMES_HAVE_UNDERSCORE */
+ for (sym = global_sym_chain[hash];
+ sym;)
+ {
+ if (
+#ifdef NAMES_HAVE_UNDERSCORE
+ *namestring == '_'
+ && namestring[1] == SYMBOL_NAME (sym)[0]
+ &&
+ !strcmp (namestring + 2, SYMBOL_NAME (sym) + 1)
+#else /* NAMES_HAVE_UNDERSCORE */
+ namestring[0] == SYMBOL_NAME (sym)[0]
+ &&
+ !strcmp (namestring + 1, SYMBOL_NAME (sym) + 1)
+#endif /* NAMES_HAVE_UNDERSCORE */
+ )
+ {
+ if (prev)
+ SYMBOL_VALUE (prev) = SYMBOL_VALUE (sym);
+ else
+ global_sym_chain[hash]
+ = (struct symbol *) SYMBOL_VALUE (sym);
+ SYMBOL_VALUE (sym) = bufp->n_value;
+ if (prev)
+ sym = (struct symbol *) SYMBOL_VALUE (prev);
+ else
+ sym = global_sym_chain[hash];
+
+ used_up = 1;
+ }
+ else
+ {
+ prev = sym;
+ sym = (struct symbol *) SYMBOL_VALUE (sym);
+ }
+ }
+ }
+
+ /* Defined global or text symbol: record as a misc function
+ if it didn't give its address to a debugger symbol above. */
+ if (type <= (N_TYPE | N_EXT)
+ && type != N_EXT
+ && ! used_up)
+ record_misc_function (namestring, bufp->n_value);
+ }
+ }
+
+ if (last_source_file)
+ end_symtab (text_addr + text_size);
+
+ fclose (stream);
+}
+
+/* C++:
+ This function allows the addition of incrementally linked object files.
+ Since this has a fair amount of code in common with symbol_file_command,
+ it might be worthwhile to consolidate things, as was done with
+ read_dbx_symtab and condense_misc_bunches. */
+
+void
+add_file_command (arg_string)
+ char* arg_string;
+{
+ register int desc;
+ DECLARE_FILE_HEADERS;
+ struct nlist *nlist;
+ char *stringtab;
+ long buffer;
+ register int val;
+ extern void close ();
+ struct cleanup *old_chain;
+ struct symtab *symseg;
+ struct stat statbuf;
+ char *name;
+ unsigned text_addr;
+
+ if (arg_string == 0)
+ error ("add-file takes a file name and an address");
+
+ for( ; *arg_string == ' '; arg_string++ );
+ name = arg_string;
+ for( ; *arg_string && *arg_string != ' ' ; arg_string++ );
+ *arg_string++ = (char) 0;
+
+ if (name[0] == 0)
+ error ("add-file takes a file name and an address");
+
+ text_addr = parse_and_eval_address (arg_string);
+
+ dont_repeat ();
+
+ if (!query ("add symbol table from filename \"%s\" at text_addr = 0x%x\n",
+ name, text_addr))
+ error ("Not confirmed.");
+
+ desc = open (name, O_RDONLY);
+ if (desc < 0)
+ perror_with_name (name);
+
+ old_chain = make_cleanup (close, desc);
+ make_cleanup (free_current_contents, &name);
+
+ READ_FILE_HEADERS (desc, name);
+
+ if (NUMBER_OF_SYMBOLS == 0)
+ {
+ printf ("%s does not have a symbol-table.\n", name);
+ fflush (stdout);
+ return;
+ }
+
+ printf ("Reading symbol data from %s...", name);
+ fflush (stdout);
+
+ /* Now read the string table, all at once. */
+ val = lseek (desc, STRING_TABLE_OFFSET, 0);
+ if (val < 0)
+ perror_with_name (name);
+ stat (name, &statbuf);
+ READ_STRING_TABLE_SIZE (buffer);
+ if (buffer >= 0 && buffer < statbuf.st_size)
+ stringtab = (char *) alloca (buffer);
+ else
+ stringtab = NULL;
+ if (stringtab == NULL)
+ error ("ridiculous string table size: %d bytes", name, buffer);
+
+ bcopy (&buffer, stringtab, sizeof buffer);
+ val = myread (desc, stringtab + sizeof buffer, buffer - sizeof buffer);
+ if (val < 0)
+ perror_with_name (name);
+
+#ifdef READ_GDB_SYMSEGS
+ /* That puts us at the symsegs. Read them. */
+ symseg_chain = read_symsegs (desc, name);
+ hash_symsegs ();
+
+ /* Free the symtabs made by read_symsegs, but not their contents,
+ which have been copied into symtabs on symtab_list. */
+ for (symseg = symseg_chain; symseg; symseg = symseg->next)
+ {
+ int i;
+ struct sourcevector *sv = (struct sourcevector *) symseg->linetable;
+
+ for (i = 0; i < sv->length; i++)
+ {
+ int j;
+ struct source *source = sv->source[i];
+ struct symtab *sp1
+ = (struct symtab *) xxmalloc (sizeof (struct symtab));
+
+ bcopy (symseg, sp1, sizeof (struct symtab));
+ sp1->filename = savestring (source->name, strlen (source->name));
+ sp1->linetable = &source->contents;
+ sp1->free_code = free_nothing;
+ sp1->free_ptr = (i == 0) ? (char *) symseg : 0;
+
+ sp1->next = symtab_list;
+ symtab_list = sp1;
+ }
+ }
+#else
+ /* Where people are using the 4.2 ld program, must not check for
+ symsegs, because that ld puts randonm garbage at the end of
+ the output file and that would trigger an error message. */
+ symseg_chain = 0;
+#endif
+
+ /* Position to read the symbol table. Do not read it all at once. */
+ val = lseek (desc, SYMBOL_TABLE_OFFSET, 0);
+ if (val < 0)
+ perror_with_name (name);
+
+ init_misc_functions ();
+ make_cleanup (discard_misc_bunches, 0);
+ init_header_files ();
+ make_cleanup (free_header_files, 0);
+ free_pendings = 0;
+ pending_blocks = 0;
+ file_symbols = 0;
+ global_symbols = 0;
+ make_cleanup (really_free_pendings, 0);
+
+ read_addl_syms (desc, stringtab, NUMBER_OF_SYMBOLS, text_addr,
+ SIZE_OF_TEXT_SEGMENT);
+
+
+ /* Sort symbols alphabetically within each block. */
+
+ sort_syms ();
+
+ /* Go over the misc functions and install them in vector. */
+
+ condense_addl_misc_bunches (1);
+
+ /* Don't allow char * to have a typename (else would get caddr_t.) */
+
+ TYPE_NAME (lookup_pointer_type (builtin_type_char)) = 0;
+
+ /* Make a default for file to list. */
+ /* Hmmm. I'd say we don't want this in add_file_command, but . . . */
+
+ select_source_symtab (symtab_list);
+
+ do_cleanups (old_chain);
+
+ /* Free the symtabs made by read_symsegs, but not their contents,
+ which have been copied into symtabs on symtab_list. */
+ while (symseg_chain)
+ {
+ register struct symtab *s = symseg_chain->next;
+ free (symseg_chain);
+ symseg_chain = s;
+ }
+
+ printf ("done.\n");
+ fflush (stdout);
+}
+
+static struct symbol *
+define_symbol (value, string, desc)
+ int value;
+ char *string;
+ int desc;
+{
+ register struct symbol *sym
+ = (struct symbol *) obstack_alloc (symbol_obstack, sizeof (struct symbol));
+ char *p = (char *) index (string, ':');
+ int deftype;
+ register int i;
+
+ /* Ignore syms with empty names. */
+ if (string[0] == 0)
+ return 0;
+
+ SYMBOL_NAME (sym)
+ = (char *) obstack_alloc (symbol_obstack, ((p - string) + 1));
+ /* Open-coded bcopy--saves function call time. */
+ {
+ register char *p1 = string;
+ register char *p2 = SYMBOL_NAME (sym);
+ while (p1 != p)
+ *p2++ = *p1++;
+ *p2++ = '\0';
+ }
+ p++;
+ /* Determine the type of name being defined. */
+ if ((*p >= '0' && *p <= '9') || *p == '(')
+ deftype = 'l';
+ else
+ deftype = *p++;
+
+ /* c is a special case, not followed by a type-number.
+ SYMBOL:c=iVALUE for an integer constant symbol.
+ SYMBOL:c=rVALUE for a floating constant symbol. */
+ if (deftype == 'c')
+ {
+ if (*p++ != '=')
+ error ("Invalid symbol data at symtab pos %d.", symnum);
+ switch (*p++)
+ {
+ case 'r':
+ {
+ double d = atof (p);
+ char *value;
+
+ SYMBOL_TYPE (sym) = builtin_type_double;
+ value = (char *) obstack_alloc (symbol_obstack, sizeof (double));
+ bcopy (&d, value, sizeof (double));
+ SYMBOL_VALUE_BYTES (sym) = value;
+ SYMBOL_CLASS (sym) = LOC_CONST;
+ }
+ break;
+ case 'i':
+ {
+ SYMBOL_TYPE (sym) = builtin_type_int;
+ SYMBOL_VALUE (sym) = atoi (p);
+ SYMBOL_CLASS (sym) = LOC_CONST_BYTES;
+ }
+ break;
+ default:
+ error ("Invalid symbol data at symtab pos %d.", symnum);
+ }
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &file_symbols);
+ return sym;
+ }
+
+ /* Now usually comes a number that says which data type,
+ and possibly more stuff to define the type
+ (all of which is handled by read_type) */
+
+ if (deftype == 'p' && *p == 'F')
+ /* pF is a two-letter code that means a function parameter in Fortran.
+ The type-number specifies the type of the return value.
+ Translate it into a pointer-to-function type. */
+ {
+ p++;
+ SYMBOL_TYPE (sym)
+ = lookup_pointer_type (lookup_function_type (read_type (&p)));
+ }
+ else
+ {
+ struct type *type = read_type (&p);
+
+ if ((deftype == 'F' || deftype == 'f')
+ && TYPE_CODE (type) != TYPE_CODE_FUNC)
+ SYMBOL_TYPE (sym) = lookup_function_type (type);
+ else
+ SYMBOL_TYPE (sym) = type;
+ }
+
+ switch (deftype)
+ {
+ case 'f':
+ SYMBOL_CLASS (sym) = LOC_BLOCK;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &file_symbols);
+ break;
+
+ case 'F':
+ SYMBOL_CLASS (sym) = LOC_BLOCK;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &global_symbols);
+ break;
+
+ case 'G':
+ /* For a class G (global) symbol, it appears that the
+ value is not correct. It is necessary to search for the
+ corresponding linker definition to find the value.
+ These definitions appear at the end of the namelist. */
+ i = hashname (SYMBOL_NAME (sym));
+ SYMBOL_VALUE (sym) = (int) global_sym_chain[i];
+ global_sym_chain[i] = sym;
+ SYMBOL_CLASS (sym) = LOC_STATIC;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &global_symbols);
+ break;
+
+ /* This case is faked by a conditional above,
+ when there is no code letter in the dbx data.
+ Dbx data never actually contains 'l'. */
+ case 'l':
+ SYMBOL_CLASS (sym) = LOC_LOCAL;
+ SYMBOL_VALUE (sym) = value;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &local_symbols);
+ break;
+
+ case 'p':
+ SYMBOL_CLASS (sym) = LOC_ARG;
+ SYMBOL_VALUE (sym) = value;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &local_symbols);
+ /* DESC == 0 implies compiled with GCC.
+ In this case, if it says `short', believe it. */
+ if (desc == 0)
+ break;
+ /* If PCC says a parameter is a short or a char,
+ it is really an int. */
+ if (SYMBOL_TYPE (sym) == builtin_type_char
+ || SYMBOL_TYPE (sym) == builtin_type_short)
+ SYMBOL_TYPE (sym) = builtin_type_int;
+ else if (SYMBOL_TYPE (sym) == builtin_type_unsigned_char
+ || SYMBOL_TYPE (sym) == builtin_type_unsigned_short)
+ SYMBOL_TYPE (sym) = builtin_type_unsigned_int;
+ break;
+
+ case 'P':
+ SYMBOL_CLASS (sym) = LOC_REGPARM;
+ SYMBOL_VALUE (sym) = value;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &local_symbols);
+ break;
+
+ case 'r':
+ SYMBOL_CLASS (sym) = LOC_REGISTER;
+ SYMBOL_VALUE (sym) = value;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &local_symbols);
+ break;
+
+ case 'S':
+ /* Static symbol at top level of file */
+ SYMBOL_CLASS (sym) = LOC_STATIC;
+ SYMBOL_VALUE (sym) = value;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &file_symbols);
+ break;
+
+ case 't':
+ SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+ SYMBOL_VALUE (sym) = value;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ if (TYPE_NAME (SYMBOL_TYPE (sym)) == 0
+ && (TYPE_FLAGS (SYMBOL_TYPE (sym)) & TYPE_FLAG_PERM) == 0)
+ TYPE_NAME (SYMBOL_TYPE (sym)) =
+ obsavestring (SYMBOL_NAME (sym),
+ strlen (SYMBOL_NAME (sym)));
+ /* C++ vagaries: we may have a type which is derived from
+ a base type which did not have its name defined when the
+ derived class was output. We fill in the derived class's
+ base part member's name here in that case. */
+ else if ((TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_STRUCT
+ || TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_UNION)
+ && TYPE_N_BASECLASSES (SYMBOL_TYPE (sym)))
+ {
+ int i;
+ for (i = TYPE_N_BASECLASSES (SYMBOL_TYPE (sym)); i > 0; i--)
+ if (TYPE_FIELD_NAME (SYMBOL_TYPE (sym), i - 1) == 0)
+ TYPE_FIELD_NAME (SYMBOL_TYPE (sym), i - 1) =
+ TYPE_NAME (TYPE_BASECLASS (SYMBOL_TYPE (sym), i));
+ }
+
+ add_symbol_to_list (sym, &file_symbols);
+ break;
+
+ case 'T':
+ SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+ SYMBOL_VALUE (sym) = value;
+ SYMBOL_NAMESPACE (sym) = STRUCT_NAMESPACE;
+ if (TYPE_NAME (SYMBOL_TYPE (sym)) == 0
+ && (TYPE_FLAGS (SYMBOL_TYPE (sym)) & TYPE_FLAG_PERM) == 0)
+ TYPE_NAME (SYMBOL_TYPE (sym))
+ = obconcat ("",
+ (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_ENUM
+ ? "enum "
+ : (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_STRUCT
+ ? "struct " : "union ")),
+ SYMBOL_NAME (sym));
+ add_symbol_to_list (sym, &file_symbols);
+ break;
+
+ case 'V':
+ case 'v':
+ /* Static symbol of local scope */
+ SYMBOL_CLASS (sym) = LOC_STATIC;
+ SYMBOL_VALUE (sym) = value;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, &local_symbols);
+ break;
+
+ default:
+ error ("Invalid symbol data: unknown symbol-type code `%c' at symtab pos %d.", deftype, symnum);
+ }
+ return sym;
+}
+
+/* Read a number by which a type is referred to in dbx data,
+ or perhaps read a pair (FILENUM, TYPENUM) in parentheses.
+ Just a single number N is equivalent to (0,N).
+ Return the two numbers by storing them in the vector TYPENUMS.
+ TYPENUMS will then be used as an argument to dbx_lookup_type. */
+
+static void
+read_type_number (pp, typenums)
+ register char **pp;
+ register int *typenums;
+{
+ if (**pp == '(')
+ {
+ (*pp)++;
+ typenums[0] = read_number (pp, ',');
+ typenums[1] = read_number (pp, ')');
+ }
+ else
+ {
+ typenums[0] = 0;
+ typenums[1] = read_number (pp, 0);
+ }
+}
+
+/* Read a dbx type reference or definition;
+ return the type that is meant.
+ This can be just a number, in which case it references
+ a type already defined and placed in type_vector.
+ Or the number can be followed by an =, in which case
+ it means to define a new type according to the text that
+ follows the =. */
+
+static
+struct type *
+read_type (pp)
+ register char **pp;
+{
+ register struct type *type = 0;
+ register int n;
+ struct type *type1;
+ int typenums[2];
+ int xtypenums[2];
+
+ read_type_number (pp, typenums);
+
+ /* Detect random reference to type not yet defined.
+ Allocate a type object but leave it zeroed. */
+ if (**pp != '=')
+ return dbx_alloc_type (typenums);
+
+ *pp += 2;
+ switch ((*pp)[-1])
+ {
+ case 'x':
+ type = dbx_alloc_type (typenums);
+ /* Set the type code according to the following letter. */
+ switch ((*pp)[0])
+ {
+ case 's':
+ TYPE_CODE (type) = TYPE_CODE_STRUCT;
+ break;
+ case 'u':
+ TYPE_CODE (type) = TYPE_CODE_UNION;
+ break;
+ case 'e':
+ TYPE_CODE (type) = TYPE_CODE_ENUM;
+ break;
+ }
+ /* Skip the name the cross-ref points to. */
+ /* Note: for C++, the cross reference may be to a base type which
+ has not yet been seen. In this case, we skip to the comma,
+ which will mark the end of the base class name. (The ':'
+ at the end of the base class name will be skipped as well.) */
+ *pp = (char *) index (*pp, ',');
+ /* Just allocate the type and leave it zero if nothing known */
+ return dbx_alloc_type (typenums);
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '(':
+ (*pp)--;
+ read_type_number (pp, xtypenums);
+ type = *dbx_lookup_type (xtypenums);
+ if (type == 0)
+ type = builtin_type_void;
+ *dbx_lookup_type (typenums) = type;
+ break;
+
+ case '*':
+ type1 = read_type (pp);
+ if (TYPE_POINTER_TYPE (type1))
+ {
+ type = TYPE_POINTER_TYPE (type1);
+ *dbx_lookup_type (typenums) = type;
+ }
+ else
+ {
+ type = dbx_alloc_type (typenums);
+ smash_to_pointer_type (type, type1);
+ }
+ break;
+
+ case '@@':
+ {
+ struct type *domain = read_type (pp);
+ char c;
+ struct type *memtype;
+
+ if (*(*pp)++ != ',')
+ error ("invalid member type data format, at symtab pos %d.",
+ symnum);
+
+ memtype = read_type (pp);
+ type = dbx_alloc_type (typenums);
+ smash_to_member_type (type, domain, memtype);
+ }
+ break;
+
+ case '&':
+ type1 = read_type (pp);
+ if (TYPE_REFERENCE_TYPE (type1))
+ {
+ type = TYPE_REFERENCE_TYPE (type1);
+ *dbx_lookup_type (typenums) = type;
+ }
+ else
+ {
+ type = dbx_alloc_type (typenums);
+ smash_to_reference_type (type, type1);
+ }
+ break;
+
+ case 'f':
+ type1 = read_type (pp);
+ if (TYPE_FUNCTION_TYPE (type1))
+ {
+ type = TYPE_FUNCTION_TYPE (type1);
+ *dbx_lookup_type (typenums) = type;
+ }
+ else
+ {
+ type = dbx_alloc_type (typenums);
+ smash_to_function_type (type, type1);
+ }
+ break;
+
+ case 'r':
+ type = read_range_type (pp, typenums);
+ *dbx_lookup_type (typenums) = type;
+ break;
+
+ case 'e':
+ type = dbx_alloc_type (typenums);
+ type = read_enum_type (pp, type);
+ *dbx_lookup_type (typenums) = type;
+ break;
+
+ case 's':
+ type = dbx_alloc_type (typenums);
+ type = read_struct_type (pp, type);
+ break;
+
+ case 'u':
+ type = dbx_alloc_type (typenums);
+ type = read_struct_type (pp, type);
+ TYPE_CODE (type) = TYPE_CODE_UNION;
+ break;
+
+ case 'a':
+ if (*(*pp)++ != 'r')
+ error ("Invalid symbol data: unrecognized type-code `a%c' %s %d.",
+ (*pp)[-1], "at symtab position", symnum);
+
+ type = dbx_alloc_type (typenums);
+ type = read_array_type (pp, type);
+ break;
+
+#if 0
+ /* Format of an array type:
+ "ar<index type>;lower;upper;<array_contents_type>". Put code
+ in to handle this. */
+
+ /* dbx expresses array types in terms of a range type for the index,
+ and that range type is specified right inside the array type spec
+ making ar1;MIN;MAX;VALTYPE */
+ if (!strncmp (*pp, "r1;0;", 5))
+ (*pp) += 5;
+ else if (!strncmp (*pp, "r(0,1);0;", 9))
+ (*pp) += 9;
+ else break;
+
+ TYPE_CODE (type) = TYPE_CODE_ARRAY;
+ /* In Fortran, an upper bound may be T... meaning a parameter specifies
+ the length of the data. In this case, just pretend the bound is 1.
+ This happens only for array parameters, which are really passed
+ as pointers anyway, and we will translate them into such. */
+ if (**pp == 'T')
+ {
+ n = 1;
+ while (**pp != ';')
+ (*pp)++;
+ }
+ else
+ n = read_number (pp, ';') + 1;
+ TYPE_TARGET_TYPE (type) = read_type (pp);
+ TYPE_LENGTH (type) = TYPE_LENGTH (TYPE_TARGET_TYPE (type)) * n;
+ break;
+#endif
+
+ default:
+ error ("Invalid symbol data: unrecognized type-code `%c' at symtab pos %d.",
+ (*pp)[-1], symnum);
+ }
+
+ if (type == 0)
+ abort ();
+
+#if 0
+ /* If this is an overriding temporary alteration for a header file's
+ contents, and this type number is unknown in the global definition,
+ put this type into the global definition at this type number. */
+ if (header_file_prev_index >= 0)
+ {
+ register struct type **tp
+ = explicit_lookup_type (header_file_prev_index, typenums[1]);
+ if (*tp == 0)
+ *tp = type;
+ }
+#endif
+ return type;
+}
+
+/* This page contains subroutines of read_type. */
+
+/* Read the description of a structure (or union type)
+ and return an object describing the type. */
+
+static struct type *
+read_struct_type (pp, type)
+ char **pp;
+ register struct type *type;
+{
+ struct nextfield
+ {
+ struct nextfield *next;
+ int visibility;
+ struct field field;
+ };
+
+ struct next_fnfield
+ {
+ struct next_fnfield *next;
+ int visibility;
+ struct fn_field fn_field;
+ };
+
+ struct next_fnfieldlist
+ {
+ struct next_fnfieldlist *next;
+ struct fn_fieldlist fn_fieldlist;
+ };
+
+ register struct nextfield *list = 0;
+ struct nextfield *new;
+ int totalsize;
+ char *name;
+ register char *p;
+ int nfields = 0;
+ register int n;
+
+ register struct next_fnfieldlist *mainlist = 0;
+ int nfn_fields = 0;
+ struct type *baseclass = NULL;
+ int read_possible_virtual_info = 0;
+
+ TYPE_CODE (type) = TYPE_CODE_STRUCT;
+
+ /* First comes the total size in bytes. */
+
+ TYPE_LENGTH (type) = read_number (pp, 0);
+
+ /* C++: Now, if the class is a derived class, then the next character
+ will be a '!', followed by the number of base classes derived from.
+ Each element in the list contains visibility information,
+ the offset of this base class in the derived structure,
+ and then the base type. */
+ if (**pp == '!')
+ {
+ int i, n_baseclasses, offset;
+ struct type **baseclass_vec;
+ struct type *baseclass;
+ int via_public, via_virtual;
+
+ *pp += 1;
+
+ n_baseclasses = read_number (pp, ',');
+ baseclass_vec = (struct type **)
+ obstack_alloc (symbol_obstack,
+ (n_baseclasses) * sizeof (struct type **)) - 1;
+
+ for (i = 1; i <= n_baseclasses; i++)
+ {
+ if (**pp == '\\')
+ *pp = next_symbol_text ();
+
+ switch (*(*pp)++)
+ {
+ case '0':
+ via_virtual = 0;
+ break;
+ case '1':
+ via_virtual = 1;
+ break;
+ default:
+ error ("Invalid symbol data: bad visibility format at symtab pos %d",
+ symnum);
+ }
+
+ switch (*(*pp)++)
+ {
+ case '0':
+ via_public = 0;
+ break;
+ case '2':
+ via_public = 1;
+ break;
+ default:
+ error ("Invalid symbol data: bad visibility format at symtab pos %d.",
+ symnum);
+ }
+ offset = read_number (pp, ',');
+ baseclass = read_type (pp);
+ *pp += 1; /* skip trailing ';' */
+ baseclass_vec[i] = lookup_basetype_type (baseclass, offset, via_virtual, via_public);
+
+ /* Make this baseclass visible for structure-printing purposes. */
+ new = (struct nextfield *) alloca (sizeof (struct nextfield));
+ new->next = list;
+ list = new;
+ list->field.type = baseclass_vec[i];
+ list->field.name = TYPE_NAME (baseclass_vec[i]);
+ list->field.bitpos = offset;
+ list->field.bitsize = 0; /* this should be an unpacked field! */
+ nfields++;
+ }
+ TYPE_N_BASECLASSES (type) = n_baseclasses;
+ TYPE_BASECLASSES (type) = baseclass_vec;
+ }
+
+ /* Now come the fields, as NAME:?TYPENUM,BITPOS,BITSIZE; for each one.
+ At the end, we see a semicolon instead of a field.
+
+ In C++, this may wind up being NAME:?TYPENUM:PHYSNAME; for
+ a static field.
+
+ The `?' is a placeholder for one of '+' (public visibility),
+ '0' (protected visibility), and '-' (private visibility). */
+
+ while (**pp != ';')
+ {
+ int visibility;
+
+ /* Check for and handle cretinous dbx symbol name continuation! */
+ if (**pp == '\\') *pp = next_symbol_text ();
+
+ /* Get space to record the next field's data. */
+ new = (struct nextfield *) alloca (sizeof (struct nextfield));
+ new->next = list;
+ list = new;
+
+ /* Read the data. */
+ p = *pp;
+ while (*p != ':') p++;
+ list->field.name = obsavestring (*pp, p - *pp);
+
+ /* C++: Check to see if we have hit the methods yet. */
+ if (p[1] == ':')
+ break;
+
+ *pp = p + 1;
+
+ /* This means we have a visibility for a field coming. */
+ if (**pp == '/')
+ {
+ switch (*++*pp)
+ {
+ case '0':
+ visibility = 0;
+ *pp += 1;
+ break;
+
+ case '1':
+ visibility = 1;
+ *pp += 1;
+ break;
+
+ case '2':
+ visibility = 2;
+ *pp += 1;
+ break;
+ }
+ }
+ /* else normal dbx-style format. */
+
+ list->field.type = read_type (pp);
+ if (**pp == ':')
+ {
+ list->field.bitpos = (long)-1;
+ p = ++(*pp);
+ while (*p != ';') p++;
+ list->field.bitsize = (long) savestring (*pp, p - *pp);
+ *pp = p + 1;
+ nfields++;
+ continue;
+ }
+ else if (**pp != ',')
+ error ("Invalid symbol data: bad structure-type format at symtab pos %d.",
+ symnum);
+ (*pp)++; /* Skip the comma. */
+ list->field.bitpos = read_number (pp, ',');
+ list->field.bitsize = read_number (pp, ';');
+ /* Detect an unpacked field and mark it as such.
+ dbx gives a bit size for all fields.
+ Note that forward refs cannot be packed,
+ and treat enums as if they had the width of ints. */
+ if (TYPE_CODE (list->field.type) != TYPE_CODE_INT
+ && TYPE_CODE (list->field.type) != TYPE_CODE_ENUM)
+ list->field.bitsize = 0;
+ if ((list->field.bitsize == 8 * TYPE_LENGTH (list->field.type)
+ || (TYPE_CODE (list->field.type) == TYPE_CODE_ENUM
+ && list->field.bitsize == 8 * TYPE_LENGTH (builtin_type_int)))
+ &&
+ list->field.bitpos % 8 == 0)
+ list->field.bitsize = 0;
+ nfields++;
+ }
+
+ /* Now come the method fields, as NAME::methods
+ where each method is of the form TYPENUM,ARGS,...:PHYSNAME;
+ At the end, we see a semicolon instead of a field.
+
+ For the case of overloaded operators, the format is
+ OPERATOR::*.methods, where OPERATOR is the string "operator",
+ `*' holds the place for an operator name (such as `+=')
+ and `.' marks the end of the operator name. */
+ if (p[1] == ':')
+ {
+ /* Now, read in the methods. To simplify matters, we
+ "unread" the name that has been read, so that we can
+ start from the top. */
+
+ p = *pp;
+
+ /* chill the list of fields: the last entry (at the head)
+ is a partially constructed entry which we now scrub. */
+ list = list->next;
+
+ /* For each list of method lists... */
+ do
+ {
+ int i;
+ struct next_fnfield *sublist = 0;
+ struct fn_field *fn_fields = 0;
+ int length = 0;
+ struct next_fnfieldlist *new_mainlist =
+ (struct next_fnfieldlist *)alloca (sizeof (struct next_fnfieldlist));
+
+ /* read in the name. */
+ while (*p != ':') p++;
+ if ((*pp)[0] == 'o' && (*pp)[1] == 'p' && (*pp)[2] == '$')
+ {
+ static char opname[32] = "operator ";
+ char *o = opname + 9;
+
+ /* Skip past '::'. */
+ p += 2;
+ while (*p != '.')
+ *o++ = *p++;
+ new_mainlist->fn_fieldlist.name = savestring (opname, o - opname);
+ /* Skip past '.' */
+ *pp = p + 1;
+ }
+ else
+ {
+ i = 0;
+ new_mainlist->fn_fieldlist.name = savestring (*pp, p - *pp);
+ /* Skip past '::'. */
+ *pp = p + 2;
+ }
+
+ do
+ {
+ struct next_fnfield *new_sublist =
+ (struct next_fnfield *)alloca (sizeof (struct next_fnfield));
+
+ /* Check for and handle cretinous dbx symbol name continuation! */
+ if (**pp == '\\') *pp = next_symbol_text ();
+
+ new_sublist->fn_field.type = read_type (pp);
+ new_sublist->fn_field.args = read_args (pp, ':');
+ p = *pp;
+ while (*p != ';') p++;
+ new_sublist->fn_field.physname = savestring (*pp, p - *pp);
+ *pp = p + 1;
+ new_sublist->visibility = *(*pp)++ - '0';
+ if (**pp == '\\') *pp = next_symbol_text ();
+
+ if (*(*pp)++ == '*')
+ new_sublist->fn_field.voffset = read_number (pp, ';') + 1;
+ else
+ new_sublist->fn_field.voffset = 0;
+
+ new_sublist->next = sublist;
+ sublist = new_sublist;
+ length++;
+ }
+ while (**pp != ';');
+
+ *pp += 1;
+
+ new_mainlist->fn_fieldlist.fn_fields =
+ (struct fn_field *) obstack_alloc (symbol_obstack,
+ sizeof (struct fn_field) * length);
+ TYPE_FN_PRIVATE_BITS (new_mainlist->fn_fieldlist) =
+ (int *) obstack_alloc (symbol_obstack,
+ sizeof (int) * (1 + (length >> 5)));
+
+ TYPE_FN_PROTECTED_BITS (new_mainlist->fn_fieldlist) =
+ (int *) obstack_alloc (symbol_obstack,
+ sizeof (int) * (1 + (length >> 5)));
+
+ for (i = length; sublist; sublist = sublist->next)
+ {
+ new_mainlist->fn_fieldlist.fn_fields[--i] = sublist->fn_field;
+ if (sublist->visibility == 0)
+ B_SET (new_mainlist->fn_fieldlist.private_fn_field_bits, i);
+ else if (sublist->visibility == 1)
+ B_SET (new_mainlist->fn_fieldlist.protected_fn_field_bits, i);
+ }
+
+ new_mainlist->fn_fieldlist.length = length;
+ new_mainlist->next = mainlist;
+ mainlist = new_mainlist;
+ nfn_fields++;
+ }
+ while (**pp != ';');
+ }
+
+ *pp += 1;
+
+ /* Now create the vector of fields, and record how big it is. */
+
+ TYPE_NFIELDS (type) = nfields;
+ TYPE_FIELDS (type) = (struct field *) obstack_alloc (symbol_obstack,
+ sizeof (struct field) * nfields);
+ TYPE_FIELD_PRIVATE_BITS (type) =
+ (int *) obstack_alloc (symbol_obstack,
+ sizeof (int) * (1 + (nfields >> 5)));
+ TYPE_FIELD_PROTECTED_BITS (type) =
+ (int *) obstack_alloc (symbol_obstack,
+ sizeof (int) * (1 + (nfields >> 5)));
+
+ TYPE_NFN_FIELDS (type) = nfn_fields;
+ TYPE_NFN_FIELDS_TOTAL (type) = nfn_fields;
+ if (baseclass)
+ TYPE_NFN_FIELDS_TOTAL (type) += TYPE_NFN_FIELDS_TOTAL (baseclass);
+
+ TYPE_FN_FIELDLISTS (type) =
+ (struct fn_fieldlist *) obstack_alloc (symbol_obstack,
+ sizeof (struct fn_fieldlist) * nfn_fields);
+
+ /* Copy the saved-up fields into the field vector. */
+
+ for (n = nfields; list; list = list->next)
+ {
+ TYPE_FIELD (type, --n) = list->field;
+ if (list->visibility == 0)
+ SET_TYPE_FIELD_PRIVATE (type, n);
+ else if (list->visibility == 1)
+ SET_TYPE_FIELD_PROTECTED (type, n);
+ }
+
+ for (n = nfn_fields; mainlist; mainlist = mainlist->next)
+ TYPE_FN_FIELDLISTS (type)[--n] = mainlist->fn_fieldlist;
+
+ if (**pp == '~')
+ {
+ *pp += 1;
+
+ if (**pp == '=')
+ {
+ TYPE_FLAGS (type)
+ |= TYPE_FLAG_HAS_CONSTRUCTOR | TYPE_FLAG_HAS_DESTRUCTOR;
+ *pp += 1;
+ }
+ else if (**pp == '+')
+ {
+ TYPE_FLAGS (type) |= TYPE_FLAG_HAS_CONSTRUCTOR;
+ *pp += 1;
+ }
+ else if (**pp == '-')
+ {
+ TYPE_FLAGS (type) |= TYPE_FLAG_HAS_DESTRUCTOR;
+ *pp += 1;
+ }
+
+ /* Read either a '%' or the final ';'. */
+ if (*(*pp)++ == '%')
+ {
+ /* Now we must record the virtual function table pointer's
+ field information. */
+
+ struct type *t;
+ int i;
+
+ t = read_type (pp);
+ p = (*pp)++;
+ while (*p != ';') p++;
+ TYPE_VPTR_BASETYPE (type) = t;
+ if (type == t)
+ {
+ if (TYPE_FIELD_NAME (t, 0) == 0)
+ TYPE_VPTR_FIELDNO (type) = i = 0;
+ else for (i = TYPE_NFIELDS (t) - 1; i >= 0; --i)
+ if (! strncmp (TYPE_FIELD_NAME (t, i), *pp,
+ strlen (TYPE_FIELD_NAME (t, i))))
+ {
+ TYPE_VPTR_FIELDNO (type) = i;
+ break;
+ }
+ if (i < 0)
+ error ("virtual function table field not found");
+ }
+ else
+ TYPE_VPTR_FIELDNO (type) = TYPE_VPTR_FIELDNO (TYPE_BASECLASS (type, 1));
+ *pp = p + 1;
+ }
+ else
+ {
+ TYPE_VPTR_BASETYPE (type) = 0;
+ TYPE_VPTR_FIELDNO (type) = -1;
+ }
+ }
+ else
+ {
+ TYPE_VPTR_BASETYPE (type) = 0;
+ TYPE_VPTR_FIELDNO (type) = -1;
+ }
+
+ return type;
+}
+
+/* Read a definition of an enumberation type,
+ and create and return a suitable type object.
+ Also creates a range type which represents the bounds of that
+ array. */
+static struct type *
+read_array_type (pp, type)
+ register char **pp;
+ register struct type *type;
+{
+ struct type *index_type, *element_type, *range_type;
+ int lower, upper;
+
+ /* Format of an array type:
+ "ar<index type>;lower;upper;<array_contents_type>". Put code in
+ to handle this. */
+
+ index_type = read_type (pp);
+ if (*(*pp)++ != ';')
+ error ("Invalid symbol data; improper format of array type decl.");
+ lower = read_number (pp, ';');
+ upper = read_number (pp, ';');
+ element_type = read_type (pp);
+
+ {
+ /* Create range type. */
+ range_type = (struct type *) obstack_alloc (symbol_obstack,
+ sizeof (struct type));
+ TYPE_CODE (range_type) = TYPE_CODE_RANGE;
+ TYPE_TARGET_TYPE (range_type) = index_type;
+
+ /* This should never be needed. */
+ TYPE_LENGTH (range_type) = sizeof (int);
+
+ TYPE_NFIELDS (range_type) = 2;
+ TYPE_FIELDS (range_type) =
+ (struct field *) obstack_alloc (symbol_obstack,
+ 2 * sizeof (struct field));
+ TYPE_FIELD_BITPOS (range_type, 0) = lower;
+ TYPE_FIELD_BITPOS (range_type, 1) = upper;
+ }
+
+ TYPE_CODE (type) = TYPE_CODE_ARRAY;
+ TYPE_TARGET_TYPE (type) = element_type;
+ TYPE_LENGTH (type) = (upper - lower + 1) * TYPE_LENGTH (element_type);
+ TYPE_NFIELDS (type) = 1;
+ TYPE_FIELDS (type) =
+ (struct field *) obstack_alloc (symbol_obstack,
+ sizeof (struct field));
+ TYPE_FIELD_TYPE (type, 0) = range_type;
+
+ return type;
+}
+
+
+/* Read a definition of an enumeration type,
+ and create and return a suitable type object.
+ Also defines the symbols that represent the values of the type. */
+
+static struct type *
+read_enum_type (pp, type)
+ register char **pp;
+ register struct type *type;
+{
+ register char *p;
+ char *name;
+ register long n;
+ register struct symbol *sym;
+ int nsyms = 0;
+ struct pending **symlist;
+ struct pending *osyms, *syms;
+ int o_nsyms;
+
+ if (within_function)
+ symlist = &local_symbols;
+ else
+ symlist = &file_symbols;
+ osyms = *symlist;
+ o_nsyms = osyms ? osyms->nsyms : 0;
+
+ /* Read the value-names and their values.
+ The input syntax is NAME:VALUE,NAME:VALUE, and so on.
+ A semicolon instead of a NAME means the end. */
+ while (**pp && **pp != ';')
+ {
+ /* Check for and handle cretinous dbx symbol name continuation! */
+ if (**pp == '\\') *pp = next_symbol_text ();
+
+ p = *pp;
+ while (*p != ':') p++;
+ name = obsavestring (*pp, p - *pp);
+ *pp = p + 1;
+ n = read_number (pp, ',');
+
+ sym = (struct symbol *) obstack_alloc (symbol_obstack, sizeof (struct symbol));
+ bzero (sym, sizeof (struct symbol));
+ SYMBOL_NAME (sym) = name;
+ SYMBOL_CLASS (sym) = LOC_CONST;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ SYMBOL_VALUE (sym) = n;
+ add_symbol_to_list (sym, symlist);
+ nsyms++;
+ }
+
+ (*pp)++; /* Skip the semicolon. */
+
+ /* Now fill in the fields of the type-structure. */
+
+ TYPE_LENGTH (type) = sizeof (int);
+ TYPE_CODE (type) = TYPE_CODE_ENUM;
+ TYPE_NFIELDS (type) = nsyms;
+ TYPE_FIELDS (type) = (struct field *) obstack_alloc (symbol_obstack, sizeof (struct field) * nsyms);
+
+ /* Find the symbols for the values and put them into the type.
+ The symbols can be found in the symlist that we put them on
+ to cause them to be defined. osyms contains the old value
+ of that symlist; everything up to there was defined by us. */
+
+ for (syms = *symlist, n = nsyms; syms; syms = syms->next)
+ {
+ int j = 0;
+ if (syms == osyms)
+ j = o_nsyms;
+ for (; j < syms->nsyms; j++)
+ {
+ struct symbol *sym = syms->symbol[j];
+ SYMBOL_TYPE (sym) = type;
+ TYPE_FIELD_NAME (type, --n) = SYMBOL_NAME (sym);
+ TYPE_FIELD_VALUE (type, n) = 0;
+ TYPE_FIELD_BITPOS (type, n) = SYMBOL_VALUE (sym);
+ TYPE_FIELD_BITSIZE (type, n) = 0;
+ }
+ if (syms == osyms)
+ break;
+ }
+
+ return type;
+}
+
+#define MAX_OF_TYPE(t) ((1 << (sizeof (t) - 1)) - 1)
+#define MIN_OF_TYPE(t) (-(1 << (sizeof (t) - 1)))
+
+static struct type *
+read_range_type (pp, typenums)
+ char **pp;
+ int typenums[2];
+{
+ char *errp = *pp;
+ int rangenums[2];
+ int n2, n3;
+ int self_subrange;
+ struct type *result_type;
+
+ /* First comes a type we are a subrange of.
+ In C it is usually 0, 1 or the type being defined. */
+ read_type_number (pp, rangenums);
+ self_subrange = (rangenums[0] == typenums[0] &&
+ rangenums[1] == typenums[1]);
+
+ /* A semicolon should now follow; skip it. */
+ if (**pp == ';')
+ (*pp)++;
+
+ /* The remaining two operands are usually lower and upper bounds
+ of the range. But in some special cases they mean something else. */
+ n2 = read_number (pp, ';');
+ n3 = read_number (pp, ';');
+
+ /* A type defined as a subrange of itself, with bounds both 0, is void. */
+ if (self_subrange && n2 == 0 && n3 == 0)
+ return builtin_type_void;
+
+ /* If n3 is zero and n2 is not, we want a floating type,
+ and n2 is the width in bytes.
+
+ Fortran programs appear to use this for complex types also,
+ and they give no way to distinguish between double and single-complex!
+ We don't have complex types, so we would lose on all fortran files!
+ So return type `double' for all of those. It won't work right
+ for the complex values, but at least it makes the file loadable. */
+
+ if (n3 == 0 && n2 > 0)
+ {
+ if (n2 == sizeof (float))
+ return builtin_type_float;
+ return builtin_type_double;
+ }
+
+ /* If the upper bound is -1, it must really be an unsigned int. */
+
+ else if (n2 == 0 && n3 == -1)
+ {
+ if (sizeof (int) == sizeof (long))
+ return builtin_type_unsigned_int;
+ else
+ return builtin_type_unsigned_long;
+ }
+
+ /* Special case: char is defined (Who knows why) as a subrange of
+ itself with range 0-127. */
+ else if (self_subrange && n2 == 0 && n3 == 127)
+ return builtin_type_char;
+
+ /* Assumptions made here: Subrange of self is equivalent to subrange
+ of int. */
+ else if (n2 == 0
+ && (self_subrange ||
+ *dbx_lookup_type (rangenums) == builtin_type_int))
+ {
+ /* an unsigned type */
+ if (n3 == (1 << (8 * sizeof (int))) - 1)
+ return builtin_type_unsigned_int;
+ if (n3 == (1 << (8 * sizeof (short))) - 1)
+ return builtin_type_unsigned_short;
+ if (n3 == (1 << (8 * sizeof (char))) - 1)
+ return builtin_type_unsigned_char;
+ }
+ else if (n2 == -n3 -1)
+ {
+ /* a signed type */
+ if (n3 == (1 << (8 * sizeof (int) - 1)) - 1)
+ return builtin_type_int;
+ if (n3 == (1 << (8 * sizeof (long) - 1)) - 1)
+ return builtin_type_long;
+ if (n3 == (1 << (8 * sizeof (short) - 1)) - 1)
+ return builtin_type_short;
+ if (n3 == (1 << (8 * sizeof (char) - 1)) - 1)
+ return builtin_type_char;
+ }
+
+ /* We have a real range type on our hands. Allocate space and
+ return a real pointer. */
+
+ /* At this point I don't have the faintest idea how to deal with
+ a self_subrange type; I'm going to assume that this is used
+ as an idiom, and that all of them are special cases. So . . . */
+ if (self_subrange)
+ error ("Type defined as subrange of itself.");
+
+ result_type = (struct type *) obstack_alloc (symbol_obstack,
+ sizeof (struct type));
+ bzero (result_type, sizeof (struct type));
+
+ TYPE_TARGET_TYPE (result_type) = (self_subrange ?
+ builtin_type_int :
+ *dbx_lookup_type(rangenums));
+
+ /* We have to figure out how many bytes it takes to hold this
+ range type. I'm going to assume that anything that is pushing
+ the bounds of a long was taken care of above. */
+ if (n2 >= MIN_OF_TYPE(char) && n3 <= MAX_OF_TYPE(char))
+ TYPE_LENGTH (result_type) = 1;
+ else if (n2 >= MIN_OF_TYPE(short) && n3 <= MAX_OF_TYPE(short))
+ TYPE_LENGTH (result_type) = sizeof (short);
+ else if (n2 >= MIN_OF_TYPE(int) && n3 <= MAX_OF_TYPE(int))
+ TYPE_LENGTH (result_type) = sizeof (int);
+ else if (n2 >= MIN_OF_TYPE(long) && n3 <= MAX_OF_TYPE(long))
+ TYPE_LENGTH (result_type) = sizeof (long);
+ else
+ error ("Ranged type doesn't fit within known sizes.");
+
+ TYPE_LENGTH (result_type) = TYPE_LENGTH (TYPE_TARGET_TYPE (result_type));
+ TYPE_CODE (result_type) = TYPE_CODE_RANGE;
+ TYPE_NFIELDS (result_type) = 2;
+ TYPE_FIELDS (result_type) =
+ (struct field *) obstack_alloc (symbol_obstack,
+ 2 * sizeof (struct field));
+ bzero (TYPE_FIELDS (result_type), 2 * sizeof (struct field));
+ TYPE_FIELD_BITPOS (result_type, 0) = n2;
+ TYPE_FIELD_BITPOS (result_type, 1) = n3;
+
+ return result_type;
+}
+
+/* Read a number from the string pointed to by *PP.
+ The value of *PP is advanced over the number.
+ If END is nonzero, the character that ends the
+ number must match END, or an error happens;
+ and that character is skipped if it does match.
+ If END is zero, *PP is left pointing to that character. */
+
+static long
+read_number (pp, end)
+ char **pp;
+ int end;
+{
+ register char *p = *pp;
+ register long n = 0;
+ register int c;
+ int sign = 1;
+
+ /* Handle an optional leading minus sign. */
+
+ if (*p == '-')
+ {
+ sign = -1;
+ p++;
+ }
+
+ /* Read the digits, as far as they go. */
+
+ while ((c = *p++) >= '0' && c <= '9')
+ {
+ n *= 10;
+ n += c - '0';
+ }
+ if (end)
+ {
+ if (c && c != end)
+ error ("Invalid symbol data: invalid character \\%03o at symbol pos %d.", c, symnum);
+ }
+ else
+ --p;
+
+ *pp = p;
+ return n * sign;
+}
+
+/* Read in an argument list. This is a list of types. It is terminated with
+ a ':', FYI. Return the list of types read in. */
+static struct type **
+read_args (pp, end)
+ char **pp;
+ int end;
+{
+ struct type *types[1024], **rval; /* allow for fns of 1023 parameters */
+ int n = 0;
+
+ while (**pp != end)
+ {
+ if (**pp != ',')
+ error ("Invalid argument list: no ',', at symtab pos %d", symnum);
+ *pp += 1;
+
+ /* Check for and handle cretinous dbx symbol name continuation! */
+ if (**pp == '\\')
+ *pp = next_symbol_text ();
+
+ types[n++] = read_type (pp);
+ }
+ *pp += 1; /* get past `end' (the ':' character) */
+
+ if (n == 1)
+ {
+ rval = (struct type **) xmalloc (2 * sizeof (struct type *));
+ }
+ else if (TYPE_CODE (types[n-1]) != TYPE_CODE_VOID)
+ {
+ rval = (struct type **) xmalloc ((n + 1) * sizeof (struct type *));
+ bzero (rval + n, sizeof (struct type *));
+ }
+ else
+ {
+ rval = (struct type **) xmalloc (n * sizeof (struct type *));
+ }
+ bcopy (types, rval, n * sizeof (struct type *));
+ return rval;
+}
+
+/* This function is really horrible, but to avoid it, there would need
+ to be more filling in of forward references. THIS SHOULD BE MOVED OUT
+ OF COFFREAD.C AND DBXREAD.C TO SOME PLACE WHERE IT CAN BE SHARED */
+int
+fill_in_vptr_fieldno (type)
+ struct type *type;
+{
+ if (TYPE_VPTR_FIELDNO (type) < 0)
+ TYPE_VPTR_FIELDNO (type) =
+ fill_in_vptr_fieldno (TYPE_BASECLASS (type, 1));
+ return TYPE_VPTR_FIELDNO (type);
+}
+
+void
+_initialize_dbxread ()
+{
+ symfile = 0;
+ header_files = (struct header_file *) 0;
+ this_object_header_files = (int *) 0;
+
+ add_com ("symbol-file", class_files, symbol_file_command,
+ "Load symbol table (in dbx format) from executable file FILE.");
+
+ add_com ("add-file", class_files, add_file_command,
+ "Load the symbols from FILE, assuming its code is at TEXT_START.") ;
+}
+
+#endif /* READ_DBX_FORMAT */
+@
+
+
+1.2
+log
+@If discarding the symbol table, discard its name too, so "info files"
+will give the right answer.
+@
+text
+@d27 1
+a27 1
+#include <sys/fcntl.h>
+@
+
+
+1.1
+log
+@Initial revision
+@
+text
+@d2 1
+a2 1
+ Copyright (C) 1986, 1987, 1988 Free Software Foundation, Inc.
+d1457 3
+@