aboutsummaryrefslogtreecommitdiff
path: root/gdb/mipsread.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/mipsread.c')
-rw-r--r--gdb/mipsread.c2879
1 files changed, 2879 insertions, 0 deletions
diff --git a/gdb/mipsread.c b/gdb/mipsread.c
new file mode 100644
index 0000000..2c7112f
--- /dev/null
+++ b/gdb/mipsread.c
@@ -0,0 +1,2879 @@
+/* Read a symbol table in MIPS' format (Third-Eye).
+ Copyright (C) 1986, 1987, 1989-1991 Free Software Foundation, Inc.
+ Contributed by Alessandro Forin (af@cs.cmu.edu) at CMU
+
+This file is part of GDB.
+
+GDB is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GDB is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GDB; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include "param.h"
+#include "obstack.h"
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include "defs.h"
+#include "symtab.h"
+#include "gdbcore.h"
+#include "symfile.h"
+#ifdef CMUCS
+#include <mips/syms.h>
+#endif CMUCS
+
+/* Since these things are defined differently on various systems I'll
+ (re)define here what I really need in this module. I only assume the
+ three standard COFF structure definitions: filehdr, aouthdr, scnhdr */
+#define MIPS /* Kludge to get MIPS version of coff */
+#include "intel-coff.h"
+
+struct coff_exec {
+ struct filehdr f;
+ struct aouthdr a;
+};
+#undef a_magic
+#undef a_text
+#undef a_data
+#undef a_bss
+#undef a_syms
+#undef a_entry
+#define a_magic a.magic /* magic number */
+#define a_text a.tsize /* size of text segment */
+#define a_data a.dsize /* size of initialized data */
+#define a_bss a.bsize /* size of uninitialized data */
+#define a_syms f.f_nsyms /* size of symbol table */
+#define a_entry a.entry /* entry point */
+
+#undef N_BADMAG
+#define N_BADMAG(x) \
+ (((x).a_magic)!=OMAGIC && ((x).a_magic)!=NMAGIC && ((x).a_magic)!=ZMAGIC)
+
+/* Things we import explicitly from other modules */
+
+extern int info_verbose;
+extern struct block *block_for_pc();
+extern void sort_symtab_syms();
+
+/* Forward declarations */
+
+static void psymtab_to_symtab_1();
+
+/* Macros and extra defs */
+
+struct complaint unknown_ext_complaint =
+ {"unknown external symbol %s", 0, 0};
+
+/* Already parsed symbols are marked specially */
+
+#define stParsed stType
+
+/* Puns: hard to find whether -g was used and how */
+
+#define MIN_GLEVEL GLEVEL_0
+#define compare_glevel(a,b) \
+ (((a) == GLEVEL_3) ? ((b) < GLEVEL_3) : \
+ ((b) == GLEVEL_3) ? -1 : (int)((b) - (a)))
+
+/* When looking at .o files avoid tripping over bad addresses */
+
+#define SAFE_TEXT_ADDR 0x400000
+#define SAFE_DATA_ADDR 0x10000000
+
+#define UNSAFE_DATA_ADDR(p) ((unsigned)p < SAFE_DATA_ADDR || (unsigned)p > 2*SAFE_DATA_ADDR)
+
+
+/* Things we export to other modules */
+
+
+/* Lists of partial symbols */
+
+struct psymbol_allocation_list global_psymbols, static_psymbols;
+
+/* Address bounds for the signal trampoline in inferior, if any */
+
+CORE_ADDR sigtramp_address, sigtramp_end;
+
+
+/* Functions that we really export */
+
+/* THIS DESCRIPTION IS OBSOLETE POST-BFD; FIXME! */
+/* Basically, this module must provide two functions: symbol_file_command()
+ which loads the symbol table from a file, and add_file_command() which
+ adds more symbols to the symbol table (incrementally).
+
+ These two functions only do the minimum work necessary for letting the
+ user "name" things symbolically, they do not read the entire symtab.
+ Instead, they read in the external symbols and put them in partial
+ symbol tables. When more extensive information is requested of a
+ file the corresponding partial symbol table is mutated into a full
+ fledged symbol table by going back and reading the relative symbols
+ for real. mipscoff_psymtab_to_symtab() is the function that does this */
+
+/* The entry point (starting address) of the file, if it is an executable. */
+
+static CORE_ADDR entry_point;
+
+extern CORE_ADDR startup_file_start; /* From blockframe.c */
+extern CORE_ADDR startup_file_end; /* From blockframe.c */
+
+void
+mipscoff_new_init()
+{
+}
+
+void
+mipscoff_symfile_init (sf)
+ struct sym_fns *sf;
+{
+ bfd *abfd = sf->sym_bfd;
+ sf->sym_private = NULL;
+ /* Save startup file's range of PC addresses to help blockframe.c
+ decide where the bottom of the stack is. */
+ if (bfd_get_file_flags (abfd) & EXEC_P)
+ {
+ /* Executable file -- record its entry point so we'll recognize
+ the startup file because it contains the entry point. */
+ entry_point = bfd_get_start_address (abfd);
+ }
+ else
+ {
+ /* Examination of non-executable.o files. Short-circuit this stuff. */
+ /* ~0 will not be in any file, we hope. */
+ entry_point = ~0;
+ /* set the startup file to be an empty range. */
+ startup_file_start = 0;
+ startup_file_end = 0;
+ }
+}
+
+void
+mipscoff_symfile_read(sf, addr, mainline)
+ struct sym_fns *sf;
+ CORE_ADDR addr;
+ int mainline;
+{
+ struct coff_symfile_info *info = (struct coff_symfile_info *)sf->sym_private;
+ bfd *abfd = sf->sym_bfd;
+ char *name = bfd_get_filename (abfd);
+ int desc;
+ register int val;
+ int num_symbols;
+ int symtab_offset;
+ int stringtab_offset;
+
+/* WARNING WILL ROBINSON! ACCESSING BFD-PRIVATE DATA HERE! FIXME! */
+ desc = fileno ((FILE *)(abfd->iostream)); /* Raw file descriptor */
+ num_symbols = bfd_get_symcount (abfd); /* How many syms */
+/* symtab_offset = obj_sym_filepos (abfd); * Symbol table file offset */
+/* stringtab_offset = symtab_offset + num_symbols * SYMESZ; * String tab */
+/* End of warning */
+
+#ifdef TDESC
+ debug_info = text_hdr.s_relptr;
+ if (tdesc_handle)
+ {
+ dc_terminate (tdesc_handle);
+ tdesc_handle = 0;
+ }
+#endif
+
+#if 0
+ /* Read the line number table, all at once. */
+ info->min_lineno_offset = 0;
+ info->max_lineno_offset = 0;
+ bfd_map_over_sections (abfd, find_linenos, info);
+
+ val = init_lineno (desc, info->min_lineno_offset,
+ info->max_lineno_offset - info->min_lineno_offset);
+ if (val < 0)
+ error ("\"%s\": error reading line numbers\n", name);
+
+ /* Now read the string table, all at once. */
+
+ val = init_stringtab (desc, stringtab_offset);
+ if (val < 0)
+ {
+ free_all_symtabs (); /* FIXME blows whole symtab */
+ printf ("\"%s\": can't get string table", name);
+ fflush (stdout);
+ return;
+ }
+ make_cleanup (free_stringtab, 0);
+#endif
+ /* Position to read the symbol table. Do not read it all at once. */
+ val = lseek (desc, (long)symtab_offset, 0);
+ if (val < 0)
+ perror_with_name (name);
+
+ init_misc_bunches ();
+ make_cleanup (discard_misc_bunches, 0);
+
+ /* Now that the executable file is positioned at symbol table,
+ process it and define symbols accordingly. */
+
+ printf("Reading symbol data from %s...", name);
+ fflush(stdout);
+ read_mips_symtab(desc, 0);
+
+/* patch_opaque_types ();*/
+
+ /* Sort symbols alphabetically within each block. */
+
+ sort_all_symtab_syms ();
+
+ /* Go over the misc symbol bunches and install them in vector. */
+
+ condense_misc_bunches (0);
+
+ /* Make a default for file to list. */
+
+ select_source_symtab (0); /* FIXME, this might be too slow, see dbxread */
+}
+
+void
+mipscoff_symfile_discard()
+{
+}
+
+
+#if 0
+/* Exported procedure: Reads symbols from file NAME.
+ Invoked at startup time if executable was given.
+ When invoked cleans up the world */
+
+void
+symbol_file_command(name, from_tty)
+ char *name;
+ int from_tty;
+{
+ int desc;
+ struct coff_exec hdr;
+ register int val;
+ extern void close();
+ struct cleanup *old_chain;
+
+ dont_repeat();
+
+ /*
+ * Make sure s/he means it
+ */
+ if (name == 0) {
+ if ((symtab_list || partial_symtab_list)
+ && from_tty
+ && !query("Discard symbol table? ", 0))
+ error("Not confirmed.");
+ destroy_all_symtabs();
+ return;
+ }
+
+ name = tilde_expand(name);
+ make_cleanup(free, name);
+
+ if (symtab_list &&
+ !query("Load new symbol table from \"%s\"? ", name))
+ error("Not confirmed.");
+
+ /* Open the file */
+ {
+ 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);
+
+ /*
+ * Check file is indeed executable
+ */
+ 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);
+
+ if (hdr.a.entry < SAFE_TEXT_ADDR && access(name, 1))
+ printf_filtered("Warning: %s is not executable!\n", name);
+
+ if (hdr.a_syms == 0) {
+ printf_filtered("%s does not have a symbol-table.\n", name);
+ fflush(stdout);
+ return;
+ }
+
+ /* Get the modification time. */
+ {
+ struct stat symstat;
+
+ if (fstat (desc, &symstat) < 0)
+ perror_with_name (name);
+
+ symfile_mtime = symstat.st_mtime;
+ }
+
+ /*
+ * Throw away the old symbol table.
+ */
+
+ destroy_all_symtabs();
+
+ /* Make a default for file to list. */
+
+ symfile = savestring (name, strlen (name));
+
+ /* Prepare to remember misc symbol values */
+
+ init_misc_bunches ();
+ make_cleanup (discard_misc_bunches, 0);
+
+ /*
+ * Now read the new symbol table
+ */
+
+ read_mips_symtab(desc, 0);
+
+ /* Go over the misc symbol bunches 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;
+
+ /* Force reinit of the sigtramp info */
+ sigtramp_address = 0;
+
+ do_cleanups (old_chain); /* Descriptor closed here */
+
+ if (!partial_symtab_list)
+ printf ("\n(no debugging symbols found)...");
+
+ printf ("done.\n");
+ fflush(stdout);
+}
+#endif
+
+/* 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. */
+
+/* Exported procedure: add more symbols from file NAME. */
+
+void
+add_file_command(arg_string)
+ char* arg_string;
+{
+ int desc;
+ struct coff_exec hdr;
+ register int val;
+ extern void close();
+ struct cleanup *old_chain;
+ char *name;
+ unsigned text_addr;
+
+ if (arg_string == 0)
+ error ("add-file takes a file name and an address");
+
+ if (arg_string == 0)
+ error ("add-file takes a file name and an address");
+
+ arg_string = tilde_expand (arg_string);
+ make_cleanup (free, arg_string);
+
+ 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.");
+
+ /*
+ * Open the file
+ */
+ {
+ 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);
+
+
+ /*
+ * Check file is indeed executable
+ */
+ 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);
+
+ if (hdr.a.entry < SAFE_TEXT_ADDR && access(name, 1))
+ printf_filtered("Warning: %s is not executable!\n", name);
+
+ if (hdr.a_syms == 0) {
+ printf_filtered("%s does not have a symbol-table.\n", name);
+ fflush(stdout);
+ return;
+ }
+
+ if (symfile)
+ free(symfile);
+ symfile = 0;
+
+ /*
+ * Now read the new symbol table
+ */
+
+ symfile = savestring(name, strlen(name));
+
+ init_misc_bunches ();
+ make_cleanup (discard_misc_bunches, 0);
+ read_mips_symtab(desc, 1);
+
+ /* Go over the misc symbol bunches and install them in vector. */
+
+ condense_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;
+
+ do_cleanups (old_chain);
+
+ printf_filtered("done.\n");
+ fflush(stdout);
+}
+
+/* Exported procedure: Allocate zeroed memory */
+
+char *xzalloc(size)
+{
+ char *p = xmalloc(size);
+
+ bzero(p, size);
+ return p;
+}
+
+/* Exported procedure: Builds a symtab from the PST partial one.
+ Restores the environment in effect when PST was created, delegates
+ most of the work to an ancillary procedure, and sorts
+ and reorders the symtab list at the end */
+
+/* Forward decls */
+static HDRR *cur_hdr; /* MIPS symtab header for the current file */
+
+void
+mipscoff_psymtab_to_symtab(pst)
+ struct partial_symtab *pst;
+{
+ struct symtab *ret;
+ int i;
+
+ if (!pst)
+ return;
+
+ if (info_verbose) {
+ printf_filtered("Reading in symbols for %s...", pst->filename);
+ fflush(stdout);
+ }
+ /* Restore the header and list of pending typedefs */
+ cur_hdr = (HDRR *) pst->ldsymlen;
+
+ psymtab_to_symtab_1(pst);
+
+ reorder_symtabs();
+
+ /* Finish up the debug error message. */
+ if (info_verbose)
+ printf_filtered("done.\n");
+}
+
+/* Exported procedure: Is PC in the signal trampoline code */
+
+int in_sigtramp(pc,name)
+ CORE_ADDR pc;
+{
+ if (sigtramp_address == 0)
+ fixup_sigtramp();
+ return (pc >= sigtramp_address && pc < sigtramp_end);
+}
+
+
+/* Things that really are local to this module */
+
+/* All allocated symtabs and psymtabs */
+
+static int all_symtabs_count;
+static int all_psymtabs_count;
+
+/* GDB symtable for the current compilation unit */
+
+static struct symtab *cur_stab;
+
+/* Header for executable/object file we read symbols from */
+
+static struct coff_exec filhdr;
+#define END_OF_TEXT_SEGMENT(f) ((f).a.text_start + (f).a.tsize)
+
+/* Pointer to current file decriptor record, and its index */
+
+static FDR *cur_fdr;
+static int cur_fd;
+
+/* Index of current symbol */
+
+static int cur_sdx;
+
+/* Note how much "debuggable" this image is. We would like
+ to see at least one FDR with full symbols */
+
+static max_gdbinfo;
+static max_glevel;
+
+/* When examining .o files, report on undefined symbols */
+
+static int n_undef_symbols, n_undef_labels, n_undef_vars, n_undef_procs;
+
+/* Extra builtin types */
+
+struct type *builtin_type_complex;
+struct type *builtin_type_double_complex;
+struct type *builtin_type_fixed_dec;
+struct type *builtin_type_float_dec;
+struct type *builtin_type_string;
+
+/* Template types */
+
+static struct type *builtin_type_ptr;
+static struct type *builtin_type_struct;
+static struct type *builtin_type_union;
+static struct type *builtin_type_enum;
+static struct type *builtin_type_range;
+static struct type *builtin_type_set;
+
+
+/* Forward decls */
+
+static struct symbol *new_symbol();
+static struct type *new_type();
+static struct field *new_field();
+static struct block *new_block();
+static struct symtab *new_symtab();
+static struct linetable *new_linetable();
+static struct blockvector *new_bvect();
+
+static struct type *parse_type();
+static struct type *make_type();
+static struct symbol *mylookup_symbol();
+static struct block *shrink_block();
+
+static int compare_symtabs();
+static int compare_psymtabs();
+static int compare_blocks();
+
+static struct partial_symtab *new_psymtab();
+static struct partial_symbol *new_psymbol();
+static struct partial_symtab *parse_fdr();
+static int compare_psymbols();
+
+/* File-level interface functions */
+
+/* Read the symtab information from file FSYM into memory */
+
+static
+read_the_mips_symtab(fsym)
+{
+ int stsize, st_hdrsize;
+ unsigned st_filptr;
+ HDRR st_hdr;
+
+ /* Find and read the symbol table header */
+ st_hdrsize = filhdr.f.f_nsyms;
+ st_filptr = filhdr.f.f_symptr;
+ if (st_filptr == 0)
+ return 0;
+
+ lseek(fsym, st_filptr, L_SET);
+ if (read(fsym, &st_hdr, st_hdrsize) != st_hdrsize)
+ goto readerr;
+
+ /* Find out how large the symbol table is */
+ stsize = (st_hdr.cbExtOffset - (st_filptr + st_hdrsize))
+ + st_hdr.iextMax * cbEXTR;
+
+ /* Allocate space for the symbol table. Read it in. */
+ cur_hdr = (HDRR *) xmalloc(stsize + st_hdrsize);
+
+ bcopy(&st_hdr, cur_hdr, st_hdrsize);
+ if (read(fsym, (char *) cur_hdr + st_hdrsize, stsize) != stsize)
+ goto readerr;
+
+ /* Fixup file_pointers in it */
+ fixup_symtab(cur_hdr, (char *) cur_hdr + st_hdrsize,
+ st_filptr + st_hdrsize);
+
+ return;
+readerr:
+ error("Short read on %s", symfile);
+}
+
+
+/* Turn all file-relative pointers in the symtab described by HDR
+ into memory pointers, given that the symtab itself is located
+ at DATA in memory and F_PTR in the file. */
+
+static
+fixup_symtab( hdr, data, f_ptr)
+ HDRR *hdr;
+ char *data;
+{
+ int f_idx, s_idx;
+ FDR *fh;
+ SYMR *sh;
+ OPTR *op;
+ PDR *pr;
+ EXTR *esh;
+
+ /*
+ * These fields are useless (and empty) by now:
+ * hdr->cbDnOffset, hdr->cbOptOffset
+ * We use them for other internal purposes.
+ */
+ hdr->cbDnOffset = 0;
+ hdr->cbOptOffset = 0;
+
+#define FIX(off) \
+ if (hdr->off) hdr->off = (unsigned int)data + (hdr->off - f_ptr);
+
+ FIX(cbLineOffset);
+ FIX(cbPdOffset);
+ FIX(cbSymOffset);
+ FIX(cbOptOffset);
+ FIX(cbAuxOffset);
+ FIX(cbSsOffset);
+ FIX(cbSsExtOffset);
+ FIX(cbFdOffset);
+ FIX(cbRfdOffset);
+ FIX(cbExtOffset);
+#undef FIX
+
+
+ /*
+ * Fix all string pointers inside the symtab, and
+ * the FDR records. Also fix other miscellany.
+ */
+ for (f_idx = 0; f_idx < hdr->ifdMax; f_idx++) {
+ register unsigned code_offset;
+
+ /* Header itself, and strings */
+ fh = (FDR *) (hdr->cbFdOffset) + f_idx;
+ fh->issBase += hdr->cbSsOffset;
+ if (fh->rss != -1)
+ fh->rss = (long)fh->rss + fh->issBase;
+ for (s_idx = 0; s_idx < fh->csym; s_idx++) {
+ sh = (SYMR*)(hdr->cbSymOffset) + fh->isymBase + s_idx;
+ sh->iss = (long) sh->iss + fh->issBase;
+ sh->reserved = 0;
+ }
+
+ cur_fd = f_idx;
+
+ /* Local symbols */
+ fh->isymBase = (int)((SYMR*)(hdr->cbSymOffset)+fh->isymBase);
+
+ /* cannot fix fh->ipdFirst because it is a short */
+#define IPDFIRST(h,fh) \
+ ((long)h->cbPdOffset + fh->ipdFirst * sizeof(PDR))
+
+ /* Optional symbols (actually used for partial_symtabs) */
+ fh->ioptBase = 0;
+ fh->copt = 0;
+
+ /* Aux symbols */
+ if (fh->caux)
+ fh->iauxBase = hdr->cbAuxOffset + fh->iauxBase * sizeof(AUXU);
+ /* Relative file descriptor table */
+ fh->rfdBase = hdr->cbRfdOffset + fh->rfdBase * sizeof(RFDT);
+
+ /* Line numbers */
+ if (fh->cbLine)
+ fh->cbLineOffset += hdr->cbLineOffset;
+
+ /* Procedure symbols. (XXX This should be done later) */
+ code_offset = fh->adr;
+ for (s_idx = 0; s_idx < fh->cpd; s_idx++) {
+ unsigned name, only_ext;
+
+ pr = (PDR*)(IPDFIRST(hdr,fh)) + s_idx;
+
+ /* Simple rule to find files linked "-x" */
+ only_ext = fh->rss == -1;
+ if (only_ext) {
+ if (pr->isym == -1) {
+ /* static function */
+ sh = (SYMR*)-1;
+ } else {
+ /* external */
+ name = hdr->cbExtOffset + pr->isym * sizeof(EXTR);
+ sh = &((EXTR*)name)->asym;
+ }
+ } else {
+ /* Full symbols */
+ sh = (SYMR*)fh->isymBase + pr->isym;
+ /* Included code ? */
+ if (s_idx == 0 && pr->adr != 0)
+ code_offset -= pr->adr;
+ }
+
+ /* Turn index into a pointer */
+ pr->isym = (long)sh;
+
+ /* Fix line numbers */
+ pr->cbLineOffset += fh->cbLineOffset;
+
+ /* Relocate address */
+ if (!only_ext)
+ pr->adr += code_offset;
+ }
+ }
+
+ /* External symbols: fix string */
+ for (s_idx = 0; s_idx < hdr->iextMax; s_idx++) {
+ esh = (EXTR*)(hdr->cbExtOffset) + s_idx;
+ esh->asym.iss = esh->asym.iss + hdr->cbSsExtOffset;
+ }
+}
+
+
+/* Find a file descriptor given its index RF relative to a file CF */
+
+static
+FDR *get_rfd( cf, rf)
+{
+ register FDR *f;
+
+ f = (FDR *) (cur_hdr->cbFdOffset) + cf;
+ /* Object files do not have the RFD table, all refs are absolute */
+ if (f->rfdBase == 0)
+ return (FDR *) (cur_hdr->cbFdOffset) + rf;
+ cf = *((pRFDT) f->rfdBase + rf);
+ return (FDR *) (cur_hdr->cbFdOffset) + cf;
+}
+
+/* Return a safer print NAME for a file descriptor */
+
+static
+char *fdr_name(name)
+ char *name;
+{
+ if (name == (char *) -1)
+ return "<stripped file>";
+ if (UNSAFE_DATA_ADDR(name))
+ return "<NFY>";
+ return name;
+}
+
+
+/* Read in and parse the symtab of the file DESC. INCREMENTAL says
+ whether we are adding to the general symtab or not */
+
+static
+read_mips_symtab( desc, incremental)
+{
+ /*
+ * We get here with DESC pointing to the symtab header. But we need
+ * other info from the initial headers
+ */
+ lseek(desc, 0L, 0);
+ myread(desc, &filhdr, sizeof filhdr);
+
+ read_the_mips_symtab(desc);
+
+ parse_partial_symbols(cur_hdr, incremental);
+ cur_hdr = 0;
+
+ /*
+ * Check to make sure file was compiled with -g.
+ * If not, warn the user of this limitation.
+ */
+ if (compare_glevel(max_glevel, GLEVEL_2) < 0) {
+ if (max_gdbinfo == 0)
+ printf("\n%s not compiled with -g, debugging support is limited.", symfile);
+ printf("\nYou should compile with -g2 or -g3 for best debugging support.\n");
+ fflush(stdout);
+ }
+
+ /*
+ * Dont allow char * to have a typename (else would get
+ * caddr_t.)
+ */
+ TYPE_NAME(lookup_pointer_type(builtin_type_char)) = 0;
+}
+
+
+/* Local utilities */
+
+
+/* Map of FDR indexes to partial symtabs */
+
+static struct pst_map {
+ struct partial_symtab *pst; /* the psymtab proper */
+ int n_globals; /* globals it exports */
+} * fdr_to_pst;
+
+
+/* Utility stack, used to nest procedures and blocks properly.
+ It is a doubly linked list, to avoid too many alloc/free.
+ Since we might need it quite a few times it is NOT deallocated
+ after use. */
+
+static struct parse_stack {
+ struct parse_stack *next, *prev;
+ struct symtab *cur_st; /* Current symtab */
+ struct block *cur_block; /* Block in it */
+ int blocktype; /* What are we parsing */
+ int maxsyms; /* Max symbols in this block */
+ struct type *cur_type; /* Type we parse fields for */
+ int procadr; /* Start addres of this procedure */
+ int numargs; /* Its argument count */
+} *top_stack; /* Top stack ptr */
+
+
+/* Enter a new lexical context */
+
+static push_parse_stack()
+{
+ struct parse_stack *new;
+
+ /* Reuse frames if possible */
+ if (top_stack && top_stack->prev)
+ new = top_stack->prev;
+ else
+ new = (struct parse_stack *) xzalloc(sizeof(struct parse_stack));
+ /* Initialize new frame with previous content */
+ if (top_stack) {
+ register struct parse_stack *prev = new->prev;
+
+ *new = *top_stack;
+ top_stack->prev = new;
+ new->prev = prev;
+ new->next = top_stack;
+ }
+ top_stack = new;
+}
+
+/* Exit a lexical context */
+
+static pop_parse_stack()
+{
+ if (!top_stack)
+ return;
+ if (top_stack->next)
+ top_stack = top_stack->next;
+}
+
+
+/* Cross-references might be to things we haven't looked at
+ yet, e.g. type references. To avoid too many type
+ duplications we keep a quick fixup table, an array
+ of lists of references indexed by file descriptor */
+
+static struct pending {
+ struct pending *next; /* link */
+ SYMR *s; /* the symbol */
+ struct type *t; /* its partial type descriptor */
+} **pending_list;
+
+
+/* Check whether we already saw symbol SH in file FH as undefined */
+
+static
+struct pending *is_pending_symbol(fh, sh)
+ FDR *fh;
+ SYMR *sh;
+{
+ int f_idx = fh - (FDR *) cur_hdr->cbFdOffset;
+ register struct pending *p;
+
+ /* Linear search is ok, list is typically no more than 10 deep */
+ for (p = pending_list[f_idx]; p; p = p->next)
+ if (p->s == sh)
+ break;
+ return p;
+}
+
+/* Check whether we already saw type T in file FH as undefined */
+
+static
+struct pending *is_pending_type(fh, t)
+ FDR *fh;
+ struct type *t;
+{
+ int f_idx = fh - (FDR *) cur_hdr->cbFdOffset;
+ register struct pending *p;
+
+ for (p = pending_list[f_idx]; p; p = p->next)
+ if (p->t == t)
+ break;
+ return p;
+}
+
+/* Add a new undef symbol SH of type T */
+
+static
+add_pending(fh, sh, t)
+ FDR *fh;
+ SYMR *sh;
+ struct type *t;
+{
+ int f_idx = fh - (FDR *) cur_hdr->cbFdOffset;
+ struct pending *p = is_pending_symbol(fh, sh);
+
+ /* Make sure we do not make duplicates */
+ if (!p) {
+ p = (struct pending *) xmalloc(sizeof(*p));
+ p->s = sh;
+ p->t = t;
+ p->next = pending_list[f_idx];
+ pending_list[f_idx] = p;
+ }
+ sh->reserved = 1; /* for quick check */
+}
+
+/* Throw away undef entries when done with file index F_IDX */
+
+static
+free_pending(f_idx)
+{
+ register struct pending *p, *q;
+
+ for (p = pending_list[f_idx]; p; p = q) {
+ q = p->next;
+ free(p);
+ }
+ pending_list[f_idx] = 0;
+}
+
+/* The number of args to a procedure is not explicit in the symtab,
+ this is the list of all those we know of.
+ This makes parsing more reasonable and avoids extra passes */
+
+static struct numarg {
+ struct numarg *next; /* link */
+ unsigned adr; /* procedure's start address */
+ unsigned num; /* arg count */
+} *numargs_list;
+
+/* Record that the procedure at ADR takes NUM arguments. */
+
+static
+got_numargs(adr,num)
+{
+ struct numarg *n = (struct numarg *) xmalloc(sizeof(struct numarg));
+
+ n->adr = adr;
+ n->num = num;
+ n->next = numargs_list;
+ numargs_list = n;
+}
+
+/* See if we know how many arguments the procedure at ADR takes */
+
+static
+lookup_numargs(adr)
+{
+ struct numarg *n = numargs_list;
+
+ while (n && n->adr != adr)
+ n = n->next;
+ return (n) ? n->num : -1;
+}
+
+/* Release storage when done with this file */
+
+static
+free_numargs()
+{
+ struct numarg *n = numargs_list, *m;
+
+ while (n) {
+ m = n->next;
+ free(n);
+ n = m;
+ }
+ numargs_list = 0;
+}
+
+
+/* Parsing Routines proper. */
+
+/* Parse a single symbol. Mostly just make up a GDB symbol for it.
+ For blocks, procedures and types we open a new lexical context.
+ This is basically just a big switch on the symbol's type */
+
+static
+parse_symbol(sh, ax)
+ SYMR *sh;
+ AUXU *ax;
+{
+ struct symbol *s;
+ struct block *b;
+ struct type *t;
+ struct field *f;
+ /* When a symbol is cross-referenced from other files/symbols
+ we mark it explicitly */
+ int pend = (sh->reserved == 1);
+ enum address_class class;
+
+ switch (sh->st) {
+
+ case stNil:
+ break;
+
+ case stGlobal: /* external symbol, goes into the primary block */
+ class = LOC_STATIC;
+ b = BLOCKVECTOR_BLOCK(BLOCKVECTOR(top_stack->cur_st), 0);
+ goto data;
+
+ case stStatic: /* static data, goes into the current block. */
+ class = LOC_STATIC;
+ b = top_stack->cur_block;
+ goto data;
+
+ case stLocal: /* local variable, goes into the current block */
+ if (sh->sc == scRegister) {
+ class = LOC_REGISTER;
+ if (sh->value > 31)
+ sh->value += 6;
+ } else
+ class = LOC_LOCAL;
+ b = top_stack->cur_block;
+
+data: /* Common code for symbols describing data */
+ s = new_symbol(sh->iss);
+ SYMBOL_NAMESPACE(s) = VAR_NAMESPACE;
+ SYMBOL_CLASS(s) = class;
+ add_symbol(s, b);
+
+ /* Type could be missing in a number of cases */
+ if (sh->sc == scUndefined || sh->sc == scNil ||
+ sh->index == 0xfffff)
+ SYMBOL_TYPE(s) = builtin_type_int; /* undefined? */
+ else
+ SYMBOL_TYPE(s) = parse_type(ax + sh->index, sh, 0);
+ /* Value of a data symbol is its memory address */
+ SYMBOL_VALUE(s) = sh->value;
+ break;
+
+ case stParam: /* argument to procedure, goes into current block */
+ max_gdbinfo++;
+ top_stack->numargs++;
+ s = new_symbol(sh->iss);
+ SYMBOL_NAMESPACE(s) = VAR_NAMESPACE;
+ if (sh->sc == scRegister) {
+ SYMBOL_CLASS(s) = LOC_REGPARM;
+ if (sh->value > 31)
+ sh->value += 6;
+ } else
+ SYMBOL_CLASS(s) = LOC_ARG;
+ SYMBOL_VALUE(s) = sh->value;
+ SYMBOL_TYPE(s) = parse_type(ax + sh->index, sh, 0);
+ add_symbol(s, top_stack->cur_block);
+ break;
+
+ case stLabel: /* label, we do make a symbol for it */
+ s = new_symbol(sh->iss);
+ SYMBOL_NAMESPACE(s) = VAR_NAMESPACE; /* so that it can be used */
+ SYMBOL_CLASS(s) = LOC_LABEL; /* but not misused */
+ SYMBOL_VALUE(s) = sh->value;
+ SYMBOL_TYPE(s) = builtin_type_int;
+ add_symbol(s, top_stack->cur_block);
+ break;
+
+ case stProc: /* Procedure */
+ case stStaticProc: /* Static procedure */
+ s = new_symbol(sh->iss);
+ SYMBOL_NAMESPACE(s) = VAR_NAMESPACE;
+ SYMBOL_CLASS(s) = LOC_BLOCK;
+ /* Type of the return value */
+ if (sh->sc == scUndefined || sh->sc == scNil)
+ t = builtin_type_int;
+ else
+ t = parse_type(ax + sh->index, sh, 0);
+ add_symbol(s, top_stack->cur_block);
+
+ /* Make a type for the procedure itself */
+ SYMBOL_TYPE(s) = lookup_function_type (t);
+
+ /* Create and enter a new lexical context */
+ b = new_block(top_stack->maxsyms);
+ SYMBOL_BLOCK_VALUE(s) = b;
+ BLOCK_FUNCTION(b) = s;
+ BLOCK_START(b) = BLOCK_END(b) = sh->value;
+ BLOCK_SUPERBLOCK(b) = top_stack->cur_block;
+ add_block(b, top_stack->cur_st);
+
+ /* Not if we only have partial info */
+ if (sh->sc == scUndefined || sh->sc == scNil)
+ break;
+
+ push_parse_stack();
+ top_stack->cur_block = b;
+ top_stack->blocktype = sh->st;
+ top_stack->cur_type = SYMBOL_TYPE(s);
+ top_stack->procadr = sh->value;
+ top_stack->numargs = 0;
+
+ sh->value = (long) SYMBOL_TYPE(s);
+ break;
+
+ case stBlock: /* Either a lexical block, or some type */
+ push_parse_stack();
+ top_stack->blocktype = stBlock;
+ if (sh->sc == scInfo) { /* structure/union/enum def */
+ s = new_symbol(sh->iss);
+ SYMBOL_NAMESPACE(s) = STRUCT_NAMESPACE;
+ SYMBOL_CLASS(s) = LOC_TYPEDEF;
+ SYMBOL_VALUE(s) = 0;
+ add_symbol(s, top_stack->cur_block);
+ /* If this type was expected, use its partial definition */
+ if (pend) {
+ t = is_pending_symbol(cur_fdr, sh)->t;
+ } else {
+ /* Uhmm, can`t decide yet. Smash later */
+ t = new_type(sh->iss);
+ TYPE_CODE(t) = TYPE_CODE_UNDEF;
+ add_pending(cur_fdr, sh, t);
+ }
+ SYMBOL_TYPE(s) = t;
+ /* make this the current type */
+ top_stack->cur_type = t;
+ TYPE_LENGTH(t) = sh->value;
+ /* Mark that symbol has a type, and say which one */
+ sh->value = (long) t;
+ } else {
+ /* beginnning of (code) block. Value of symbol
+ is the displacement from procedure start */
+ b = new_block(top_stack->maxsyms);
+ BLOCK_START(b) = sh->value + top_stack->procadr;
+ BLOCK_SUPERBLOCK(b) = top_stack->cur_block;
+ top_stack->cur_block = b;
+ add_block(b, top_stack->cur_st);
+ }
+ break;
+
+ case stEnd: /* end (of anything) */
+ if (sh->sc == scInfo) {
+ /* Finished with type */
+ top_stack->cur_type = 0;
+ } else if (sh->sc == scText &&
+ (top_stack->blocktype == stProc ||
+ top_stack->blocktype == stStaticProc)) {
+ /* Finished with procedure */
+ struct blockvector *bv = BLOCKVECTOR(top_stack->cur_st);
+ struct block *b;
+ int i;
+
+ BLOCK_END(top_stack->cur_block) += sh->value; /* size */
+ got_numargs(top_stack->procadr, top_stack->numargs);
+ /* Reallocate symbols, saving memory */
+ b = shrink_block(top_stack->cur_block, top_stack->cur_st);
+
+ /* f77 emits proc-level with address bounds==[0,0],
+ So look for such child blocks, and patch them. */
+ for (i = 0; i < BLOCKVECTOR_NBLOCKS(bv); i++) {
+ struct block *b_bad = BLOCKVECTOR_BLOCK(bv,i);
+ if (BLOCK_SUPERBLOCK(b_bad) == b
+ && BLOCK_START(b_bad) == top_stack->procadr
+ && BLOCK_END(b_bad) == top_stack->procadr) {
+ BLOCK_START(b_bad) = BLOCK_START(b);
+ BLOCK_END(b_bad) = BLOCK_END(b);
+ }
+ }
+ } else if (sh->sc == scText && top_stack->blocktype == stBlock) {
+ /* End of (code) block. The value of the symbol
+ is the displacement from the procedure`s start
+ address of the end of this block. */
+ BLOCK_END(top_stack->cur_block) = sh->value + top_stack->procadr;
+ (void) shrink_block(top_stack->cur_block, top_stack->cur_st);
+ }
+ pop_parse_stack(); /* restore previous lexical context */
+ break;
+
+ case stMember: /* member of struct/union/enum.. */
+ f = new_field(top_stack->cur_type, sh->iss);
+ f->bitpos = sh->value;
+ f->type = parse_type(ax + sh->index, sh, &f->bitsize);
+ break;
+
+ case stTypedef: /* type definition */
+ s = new_symbol(sh->iss);
+ SYMBOL_NAMESPACE(s) = VAR_NAMESPACE;
+ SYMBOL_CLASS(s) = LOC_TYPEDEF;
+ SYMBOL_BLOCK_VALUE(s) = top_stack->cur_block;
+ add_symbol(s, top_stack->cur_block);
+ SYMBOL_TYPE(s) = parse_type(ax + sh->index, sh, 0);
+ sh->value = (long) SYMBOL_TYPE(s);
+ break;
+
+ case stFile: /* file name */
+ push_parse_stack();
+ top_stack->blocktype = sh->st;
+ break;
+
+ /* I`ve never seen these for C */
+ case stRegReloc:
+ break; /* register relocation */
+ case stForward:
+ break; /* forwarding address */
+ case stConstant:
+ break; /* constant */
+ default:
+ error("Unknown symbol type %x.", sh->st);
+ }
+ sh->st = stParsed;
+}
+
+/* Parse the type information provided in the AX entries for
+ the symbol SH. Return the bitfield size in BS, in case. */
+
+static struct type *parse_type(ax, sh, bs)
+ AUXU *ax;
+ SYMR *sh;
+ int *bs;
+{
+ /* Null entries in this map are treated specially */
+ static struct type **map_bt[] =
+ {
+ &builtin_type_void, /* btNil */
+ 0, /* btAdr */
+ &builtin_type_char, /* btChar */
+ &builtin_type_unsigned_char, /* btUChar */
+ &builtin_type_short, /* btShort */
+ &builtin_type_unsigned_short, /* btUShort */
+ &builtin_type_int, /* btInt */
+ &builtin_type_unsigned_int, /* btUInt */
+ &builtin_type_long, /* btLong */
+ &builtin_type_unsigned_long, /* btULong */
+ &builtin_type_float, /* btFloat */
+ &builtin_type_double, /* btDouble */
+ 0, /* btStruct */
+ 0, /* btUnion */
+ 0, /* btEnum */
+ 0, /* btTypedef */
+ 0, /* btRange */
+ 0, /* btSet */
+ &builtin_type_complex, /* btComplex */
+ &builtin_type_double_complex, /* btDComplex */
+ 0, /* btIndirect */
+ &builtin_type_fixed_dec, /* btFixedDec */
+ &builtin_type_float_dec, /* btFloatDec */
+ &builtin_type_string, /* btString */
+ 0, /* btBit */
+ 0, /* btPicture */
+ &builtin_type_void, /* btVoid */
+ };
+
+ TIR *t;
+ struct type *tp = 0, *tp1;
+ char *fmt = "%s";
+
+ /* Procedures start off by one */
+ if (sh->st == stProc || sh->st == stStaticProc)
+ ax++;
+
+ /* Undefined ? Should not happen */
+ if (ax->rndx.rfd == 0xfff) {
+ return builtin_type_void;
+ }
+
+ /* Use aux as a type information record, map its basic type */
+ t = &ax->ti;
+ if (t->bt > 26 || t->bt == btPicture) {
+ printf_filtered("Internal: cannot map MIPS basic type x%x\n", t->bt);
+ return builtin_type_int;
+ }
+ if (map_bt[t->bt])
+ tp = *map_bt[t->bt];
+ else {
+ /* Cannot use builtin types, use templates */
+ tp = make_type(TYPE_CODE_VOID, 0, 0, 0);
+ switch (t->bt) {
+ case btAdr:
+ *tp = *builtin_type_ptr;
+ break;
+ case btStruct:
+ *tp = *builtin_type_struct;
+ fmt = "struct %s";
+ break;
+ case btUnion:
+ *tp = *builtin_type_union;
+ fmt = "union %s";
+ break;
+ case btEnum:
+ *tp = *builtin_type_enum;
+ fmt = "enum %s";
+ break;
+ case btRange:
+ *tp = *builtin_type_range;
+ break;
+ case btSet:
+ *tp = *builtin_type_set;
+ fmt = "set %s";
+ break;
+ }
+ }
+
+ /* Move on to next aux */
+ ax++;
+ if (t->continued) {
+ /* This is the way it would work if the compiler worked */
+ register TIR *t1 = t;
+ while (t1->continued)
+ ax++;
+ }
+
+ /* For bitfields all we need is the width */
+ if (t->fBitfield) {
+ *bs = ax->width;
+ return tp;
+ }
+
+ /* All these types really point to some (common) MIPS type
+ definition, and only the type-qualifiers fully identify
+ them. We`ll make the same effort at sharing */
+ if (t->bt == btIndirect ||
+ t->bt == btStruct ||
+ t->bt == btUnion ||
+ t->bt == btEnum ||
+ t->bt == btTypedef ||
+ t->bt == btRange ||
+ t->bt == btSet) {
+ char name[256], *pn;
+
+ /* Try to cross reference this type */
+ tp1 = tp;
+ ax += cross_ref(ax, &tp1, &pn);
+ /* SOMEONE OUGHT TO FIX DBXREAD TO DROP "STRUCT" */
+ sprintf(name, fmt, pn);
+
+ /* reading .o file ? */
+ if (UNSAFE_DATA_ADDR(tp1))
+ tp1 = tp;
+ if (TYPE_CODE(tp1) == TYPE_CODE_UNDEF) {
+ /*
+ * Type was incompletely defined, now we know.
+ */
+ TYPE_CODE(tp1) = TYPE_CODE(tp);
+ TYPE_NAME(tp1) = obsavestring(name, strlen(name));
+ if (TYPE_CODE(tp1) == TYPE_CODE_ENUM) {
+ int i;
+
+ for (i = 0; i < TYPE_NFIELDS(tp1); i++)
+ make_enum_constant(&TYPE_FIELD(tp1,i), tp1);
+ }
+ }
+ if (tp1 != tp) {
+ /* found as cross ref, rid of our template */
+ if ((TYPE_FLAGS(tp) & TYPE_FLAG_PERM) == 0)
+ free(tp);
+ tp = tp1;
+ /* stupid idea of prepending "struct" to type names */
+ if (t->bt == btStruct && !index(TYPE_NAME(tp), ' ')) {
+ sprintf(name, fmt, TYPE_NAME(tp));
+ TYPE_NAME(tp) = obsavestring(name, strlen(name));
+ }
+ } else
+ TYPE_NAME(tp) = savestring(name, strlen(name));
+ }
+
+ /* Deal with range types */
+ if (t->bt == btRange) {
+ struct field *f;
+
+ f = new_field(tp, "Low");
+ f->bitpos = ax->dnLow;
+ ax++;
+ f = new_field(tp, "High");
+ f->bitpos = ax->dnHigh;
+ ax++;
+ }
+
+ /* Parse all the type qualifiers now. If there are more
+ than 6 the game will continue in the next aux */
+
+#define PARSE_TQ(tq) \
+ if (t->tq != tqNil) ax += upgrade_type(&tp, t->tq, ax, sh);
+
+again: PARSE_TQ(tq0);
+ PARSE_TQ(tq1);
+ PARSE_TQ(tq2);
+ PARSE_TQ(tq3);
+ PARSE_TQ(tq4);
+ PARSE_TQ(tq5);
+#undef PARSE_TQ
+
+ if (t->continued) {
+ t++;
+ goto again;
+ }
+ return tp;
+}
+
+/* Make up a complex type from a basic one. Type is passed by
+ reference in TPP and side-effected as necessary. The type
+ qualifier TQ says how to handle the aux symbols at AX for
+ the symbol SX we are currently analyzing.
+ Returns the number of aux symbols we parsed. */
+
+static
+upgrade_type(tpp, tq, ax, sh)
+ struct type **tpp;
+ AUXU *ax;
+ SYMR *sh;
+{
+ int off = 0;
+ int ret = 0;
+ struct type *t;
+
+ if (tq == tqPtr) {
+ t = lookup_pointer_type (*tpp);
+ } else if (tq == tqProc) {
+ t = lookup_function_type (*tpp);
+ } else if (tq == tqArray) {
+ int rf, id;
+ FDR *fh;
+ struct field *f;
+ SYMR ss;
+
+ t = make_type(TYPE_CODE_ARRAY, 0, 0, 0);
+ TYPE_TARGET_TYPE(t) = *tpp;
+
+ /* Pointer to domain type (type of index) */
+ id = ax->rndx.index;
+ if ((rf = ax->rndx.rfd) == 0xfff)
+ rf = (++ax)->isym, off++;
+
+ fh = get_rfd(cur_fd, rf);
+ f = new_field(t, 0);
+ bzero(&ss, sizeof ss);
+/* XXX */ f->type = parse_type(fh->iauxBase + id * sizeof(AUXU),
+ &ss, &f->bitsize);
+
+ /*
+ * This seems to be a pointer to the end of the Block defining
+ * the type. Why it is here is magic for me, and I have no
+ * good use for it anyways.
+ */
+ if (off == 0) {
+ off++;
+ id = (++ax)->rndx.index;
+ if ((rf = ax->rndx.rfd) == 0xfff)
+ rf = (++ax)->isym, off++;
+ }
+ f->bitpos = (++ax)->dnLow; /* ?? */
+ f->bitsize = (++ax)->dnHigh; /* ?? */
+ rf = (++ax)->width - 1; /* bit alignment */
+ id = TYPE_LENGTH(TYPE_TARGET_TYPE(t)) << 3; /* bitsize */
+
+ if (id == 0) {
+ /* Most likely an undefined type */
+ id = rf + 1;
+ TYPE_LENGTH(TYPE_TARGET_TYPE(t)) = id >> 3;
+ }
+ TYPE_LENGTH(t) = (f->bitsize < 0) ? 0 :
+ (f->bitsize - f->bitpos + 1) * (id >> 3);
+ ret = 4 + off;
+ } else {
+ if (tq != tqVol)
+ printf_filtered("Internal: unknown type qualifier %x\n", tq);
+ return ret;
+ }
+
+ *tpp = t;
+ return ret;
+}
+
+
+/* Parse a procedure descriptor record PR. Note that the procedure
+ is parsed _after_ the local symbols, now we just make up the
+ extra information we need into a special symbol that we insert
+ in the procedure's main block. Note also that images that
+ have been partially stripped (ld -x) have been deprived
+ of local symbols, and we have to cope with them here.
+ The procedure's code ends at BOUND */
+
+static
+parse_procedure(pr, bound)
+ PDR *pr;
+{
+ struct symbol *s, *i;
+ SYMR *sh = (SYMR*)pr->isym;
+ struct block *b;
+ struct mips_extra_func_info *e;
+ char name[100];
+ char *sh_name;
+
+ /* Reuse the MIPS record */
+ e = (struct mips_extra_func_info *) pr;
+ e->numargs = lookup_numargs(pr->adr);
+
+ /* Make up our special symbol */
+ i = new_symbol(".gdbinfo.");
+ SYMBOL_VALUE(i) = (int)e;
+ SYMBOL_NAMESPACE(i) = LABEL_NAMESPACE;
+ SYMBOL_CLASS(i) = LOC_CONST;
+ SYMBOL_TYPE(i) = builtin_type_void;
+
+ /* Make up a name for static procedures. Sigh. */
+ if (sh == (SYMR*)-1) {
+ sprintf(name,".static_procedure@%x",pr->adr);
+ sh_name = savestring(name, strlen(name));
+ s = NULL;
+ }
+ else {
+ sh_name = (char*)sh->iss;
+ s = mylookup_symbol(sh_name, top_stack->cur_block,
+ VAR_NAMESPACE, LOC_BLOCK);
+ }
+ if (s != 0) {
+ b = SYMBOL_BLOCK_VALUE(s);
+ } else {
+ s = new_symbol(sh_name);
+ SYMBOL_NAMESPACE(s) = VAR_NAMESPACE;
+ SYMBOL_CLASS(s) = LOC_BLOCK;
+ /* Donno its type, hope int is ok */
+ SYMBOL_TYPE(s) = lookup_function_type (builtin_type_int);
+ add_symbol(s, top_stack->cur_block);
+ /* Wont have symbols for this one */
+ b = new_block(2);
+ SYMBOL_BLOCK_VALUE(s) = b;
+ BLOCK_FUNCTION(b) = s;
+ BLOCK_START(b) = pr->adr;
+ BLOCK_END(b) = bound;
+ BLOCK_SUPERBLOCK(b) = top_stack->cur_block;
+ add_block(b, top_stack->cur_st);
+ }
+ e->isym = (long)s;
+ add_symbol(i,b);
+}
+
+/* Parse the external symbol ES. Just call parse_symbol() after
+ making sure we know where the aux are for it. For procedures,
+ parsing of the PDRs has already provided all the needed
+ information, we only parse them if SKIP_PROCEDURES is false,
+ and only if this causes no symbol duplication */
+
+static
+parse_external(es, skip_procedures)
+ EXTR *es;
+{
+ AUXU *ax;
+
+ if (es->ifd != ifdNil) {
+ cur_fd = es->ifd;
+ cur_fdr = (FDR*)(cur_hdr->cbFdOffset) + cur_fd;
+ ax = (AUXU*)cur_fdr->iauxBase;
+ } else {
+ cur_fdr = (FDR*)(cur_hdr->cbFdOffset);
+ ax = 0;
+ }
+ top_stack->cur_st = cur_stab;
+ top_stack->cur_block = BLOCKVECTOR_BLOCK(BLOCKVECTOR(top_stack->cur_st),0);
+
+ /* Reading .o files */
+ if (es->asym.sc == scUndefined || es->asym.sc == scNil) {
+ char *what;
+ switch (es->asym.st) {
+ case stStaticProc:
+ case stProc: what = "Procedure"; n_undef_procs++; break;
+ case stGlobal: what = "Variable"; n_undef_vars++; break;
+ case stLabel: what = "Label"; n_undef_labels++; break;
+ default : what = "Symbol"; break;
+ }
+ n_undef_symbols++;
+ if (info_verbose)
+ printf_filtered("Warning: %s %s is undefined (in %s)\n", what,
+ es->asym.iss, fdr_name(cur_fdr->rss));
+ return;
+ }
+
+ switch (es->asym.st) {
+ case stProc:
+ /* If we have full symbols we do not need more */
+ if (skip_procedures)
+ return;
+ if (mylookup_symbol (es->asym.iss, top_stack->cur_block,
+ VAR_NAMESPACE, LOC_BLOCK))
+ break;
+ /* fall through */
+ case stGlobal:
+ case stLabel:
+ /*
+ * Note that the case of a symbol with indexNil
+ * must be handled anyways by parse_symbol().
+ */
+ parse_symbol(&es->asym, ax);
+ break;
+ default:
+ break;
+ }
+}
+
+/* Parse the line number info for file descriptor FH into
+ GDB's linetable LT. MIPS' encoding requires a little bit
+ of magic to get things out. Note also that MIPS' line
+ numbers can go back and forth, apparently we can live
+ with that and do not need to reorder our linetables */
+
+static
+parse_lines(fh, lt)
+ FDR *fh;
+ struct linetable *lt;
+{
+ char *base = (char*)fh->cbLineOffset;
+ int i, j, k;
+ int delta, count, lineno = 0;
+ PDR *pr;
+
+ if (base == 0)
+ return;
+
+ /* Scan by procedure descriptors */
+ i = 0; j = 0, k = 0;
+ for (pr = (PDR*)IPDFIRST(cur_hdr,fh); j < fh->cpd; j++, pr++) {
+ int l, halt;
+
+ /* No code for this one */
+ if (pr->iline == ilineNil ||
+ pr->lnLow == -1 || pr->lnHigh == -1)
+ continue;
+ /*
+ * Aurgh! To know where to stop expanding we
+ * must look-ahead.
+ */
+ for (l = 1; l < (fh->cpd - j); l++)
+ if (pr[l].iline != -1)
+ break;
+ if (l == (fh->cpd - j))
+ halt = fh->cline;
+ else
+ halt = pr[l].iline;
+ /*
+ * When procedures are moved around the linenumbers
+ * are attributed to the next procedure up
+ */
+ if (pr->iline >= halt) continue;
+
+ base = (char*)pr->cbLineOffset;
+ l = pr->adr >> 2; /* in words */
+ halt += (pr->adr >> 2) - pr->iline;
+ for (lineno = pr->lnLow; l < halt;) {
+ count = *base & 0x0f;
+ delta = *base++ >> 4;
+ if (delta == -8) {
+ delta = (base[0] << 8) | (base[1] & 0xff);
+ base += 2;
+ }
+ lineno += delta;/* first delta is 0 */
+ k = add_line(lt, lineno, l, k);
+ l += count + 1;
+ }
+ }
+}
+
+
+/* Parse the symbols of the file described by FH, whose index is F_IDX.
+ BOUND is the highest core address of this file's procedures */
+
+static
+parse_one_file(fh, f_idx, bound)
+ FDR *fh;
+{
+ register int s_idx;
+ SYMR *sh;
+ PDR *pr;
+
+ /* Parse local symbols first */
+
+ for (s_idx = 0; s_idx < fh->csym; s_idx++) {
+ sh = (SYMR *) (fh->isymBase) + s_idx;
+ cur_sdx = s_idx;
+ parse_symbol(sh, fh->iauxBase);
+ }
+
+ /* Procedures next, note we need to look-ahead to
+ find out where the procedure's code ends */
+
+ for (s_idx = 0; s_idx < fh->cpd-1; s_idx++) {
+ pr = (PDR *) (IPDFIRST(cur_hdr, fh)) + s_idx;
+ parse_procedure(pr, pr[1].adr); /* next proc up */
+ }
+ if (fh->cpd) {
+ pr = (PDR *) (IPDFIRST(cur_hdr, fh)) + s_idx;
+ parse_procedure(pr, bound); /* next file up */
+ }
+
+ /* Linenumbers. At the end, check if we can save memory */
+ parse_lines(fh, LINETABLE(cur_stab));
+ if (LINETABLE(cur_stab)->nitems < fh->cline)
+ shrink_linetable(cur_stab);
+}
+
+
+/* Master parsing procedure. Parses the symtab described by the
+ symbolic header HDR. If INCREMENTAL is true we are called
+ by add-file and must preserve the old symtabs */
+static
+parse_partial_symbols(hdr, incremental)
+ HDRR *hdr;
+{
+ int f_idx, s_idx, h_max;
+ CORE_ADDR dummy, *prevhigh;
+ /* Running pointers */
+ FDR *fh;
+ RFDT *rh;
+ register EXTR *esh;
+
+ /*
+ * Big plan:
+ *
+ * Only parse the External symbols, and the Relative FDR.
+ * Fixup enough of the loader symtab to be able to use it.
+ * Allocate space only for the file`s portions we need to
+ * look at. (XXX)
+ */
+
+ cur_hdr = hdr;
+ max_gdbinfo = 0;
+ max_glevel = MIN_GLEVEL;
+
+ /* Allocate the map FDR -> PST.
+ Minor hack: -O3 images might claim some global data belongs
+ to FDR -1. We`ll go along with that */
+ fdr_to_pst = (struct pst_map *)xzalloc((hdr->ifdMax+1) * sizeof *fdr_to_pst);
+ fdr_to_pst++;
+ {
+ struct partial_symtab * pst = new_psymtab("");
+ fdr_to_pst[-1].pst = pst;
+ pst->ldsymoff = -1;
+ }
+
+ /* Now scan the FDRs, mostly for dependencies */
+ for (f_idx = 0; f_idx < hdr->ifdMax; f_idx++)
+ (void) parse_fdr(f_idx, 1);
+
+ /* Take a good guess at how many symbols we might ever need */
+ h_max = hdr->iextMax;
+
+ /* Parse externals: two passes because they can be ordered
+ in any way */
+
+ /* Pass 1: Presize and partition the list */
+ for (s_idx = 0; s_idx < hdr->iextMax; s_idx++) {
+ esh = (EXTR *) (hdr->cbExtOffset) + s_idx;
+ fdr_to_pst[esh->ifd].n_globals++;
+ }
+
+ if (global_psymbols.list) {
+ global_psymbols.list = (struct partial_symbol *)
+ xrealloc( global_psymbols.list, (h_max +
+ global_psymbols.size) * sizeof(struct partial_symbol));
+ global_psymbols.next = global_psymbols.list + global_psymbols.size;
+ global_psymbols.size += h_max;
+ } else {
+ global_psymbols.list = (struct partial_symbol *)
+ xmalloc( h_max * sizeof(struct partial_symbol));
+ global_psymbols.size = h_max;
+ global_psymbols.next = global_psymbols.list;
+ }
+
+ s_idx = global_psymbols.next - global_psymbols.list;
+ for (f_idx = -1; f_idx < hdr->ifdMax; f_idx++) {
+ fdr_to_pst[f_idx].pst->globals_offset = s_idx;
+ s_idx += fdr_to_pst[f_idx].n_globals;
+ }
+
+ /* Pass 2: fill in symbols */
+ for (s_idx = 0; s_idx < hdr->iextMax; s_idx++) {
+ register struct partial_symbol *p;
+ enum misc_function_type misc_type = mf_text;
+ esh = (EXTR *) (hdr->cbExtOffset) + s_idx;
+
+ if (esh->asym.sc == scUndefined || esh->asym.sc == scNil)
+ continue;
+ p = new_psymbol(&global_psymbols, esh->asym.iss, esh->ifd);
+ SYMBOL_VALUE(p) = esh->asym.value;
+ SYMBOL_NAMESPACE(p) = VAR_NAMESPACE;
+
+ switch (esh->asym.st) {
+ case stProc:
+ SYMBOL_CLASS(p) = LOC_BLOCK;
+ break;
+ case stGlobal:
+ SYMBOL_CLASS(p) = LOC_STATIC;
+ misc_type = mf_data;
+ break;
+ case stLabel:
+ SYMBOL_CLASS(p) = LOC_LABEL;
+ break;
+ default:
+ misc_type = mf_unknown;
+ complain (&unknown_ext_complaint, SYMBOL_NAME(p));
+ }
+ prim_record_misc_function (SYMBOL_NAME(p),
+ SYMBOL_VALUE(p),
+ misc_type);
+ }
+
+
+ /* The array (of lists) of globals must be sorted.
+ Take care, since we are at it, of pst->texthigh.
+
+ NOTE: The way we handle textlow/high is incorrect, but good
+ enough for a first approximation. The case we fail is on a
+ file "foo.c" that looks like
+ proc1() {...}
+ #include "bar.c" -- this contains proc2()
+ proc3() {...}
+ where proc3() is attributed to bar.c. But since this is a
+ dependent file it will cause loading of foo.c as well, so
+ everything will be fine at the end. */
+
+ prevhigh = &dummy;
+ for (f_idx = 0; f_idx < hdr->ifdMax; f_idx++) {
+ struct partial_symtab *pst = fdr_to_pst[f_idx].pst;
+ if (pst->n_global_syms > 1)
+ qsort (global_psymbols.list + pst->globals_offset,
+ pst->n_global_syms, sizeof (struct partial_symbol),
+ compare_psymbols);
+ if (pst->textlow) {
+ *prevhigh = pst->textlow;
+ prevhigh = &pst->texthigh;
+ }
+ }
+
+ /* Mark the last code address, and remember it for later */
+ *prevhigh = END_OF_TEXT_SEGMENT(filhdr);
+ hdr->cbDnOffset = END_OF_TEXT_SEGMENT(filhdr);
+
+ reorder_psymtabs();
+ free(&fdr_to_pst[-1]);
+ fdr_to_pst = 0;
+}
+
+
+/* Do the initial analisys of the F_IDX-th file descriptor.
+ Allocates a partial symtab for it, and builds the list
+ of dependent files by recursion. LEV says at which level
+ of recursion we are called (to pretty up debug traces) */
+
+static struct partial_symtab *
+parse_fdr(f_idx, lev)
+ int f_idx;
+{
+ register FDR *fh;
+ register struct partial_symtab *pst;
+ int s_idx, s_id0;
+
+ fh = (FDR *) (cur_hdr->cbFdOffset) + f_idx;
+
+ /* Use this to indicate into which symtab this file was parsed */
+ if (fh->ioptBase)
+ return (struct partial_symtab *) fh->ioptBase;
+
+ /* Debuggability level */
+ if (compare_glevel(max_glevel, fh->glevel) < 0)
+ max_glevel = fh->glevel;
+
+ /* Make a new partial_symtab */
+ pst = new_psymtab(fh->rss);
+ if (fh->cpd == 0){
+ pst->textlow = 0;
+ pst->texthigh = 0;
+ } else {
+ pst->textlow = fh->adr;
+ pst->texthigh = fh->cpd; /* To be fixed later */
+ }
+ /* Reverse mapping PST -> FDR */
+ pst->ldsymoff = f_idx;
+
+ fdr_to_pst[f_idx].pst = pst;
+ fh->ioptBase = (int)pst;
+
+ /* Analyze its dependencies */
+ if (fh->crfd <= 1)
+ return pst;
+
+ s_id0 = 0;
+ if (fh->cpd == 0) { /* If there are no functions defined here ... */
+ /* ...then presumably a .h file: drop reverse depends .h->.c */
+ for (; s_id0 < fh->crfd; s_id0++) {
+ RFDT *rh = (RFDT *) (fh->rfdBase) + s_id0;
+ if (*rh == f_idx) {
+ s_id0++; /* Skip self-dependency */
+ break;
+ }
+ }
+ }
+ pst->number_of_dependencies = fh->crfd - s_id0;
+ pst->dependencies = (struct partial_symtab **)
+ obstack_alloc (psymbol_obstack,
+ pst->number_of_dependencies * sizeof(char*));
+ for (s_idx = s_id0; s_idx < fh->crfd; s_idx++) {
+ RFDT *rh = (RFDT *) (fh->rfdBase) + s_idx;
+
+ pst->dependencies[s_idx-s_id0] = parse_fdr(*rh, lev+1);
+
+ }
+
+ return pst;
+}
+
+
+/* Ancillary function to psymtab_to_symtab(). Does all the work
+ for turning the partial symtab PST into a symtab, recurring
+ first on all dependent psymtabs */
+
+static void psymtab_to_symtab_1(pst)
+ struct partial_symtab *pst;
+{
+ int i, f_max;
+ struct symtab *st;
+ FDR *fh;
+
+ if (pst->readin)
+ return;
+ pst->readin = 1;
+
+ pending_list = (struct pending **) cur_hdr->cbOptOffset;
+ if (pending_list == 0) {
+ pending_list = (struct pending **)
+ xzalloc(cur_hdr->ifdMax * sizeof(struct pending *));
+ cur_hdr->cbOptOffset = (int)pending_list;
+ }
+
+ /* How many symbols will we need */
+ f_max = pst->n_global_syms + pst->n_static_syms;
+ if (pst->ldsymoff == -1) {
+ fh = 0;
+ st = new_symtab( "unknown", f_max, 0);
+ } else {
+ fh = (FDR *) (cur_hdr->cbFdOffset) + pst->ldsymoff;
+ f_max += fh->csym + fh->cpd;
+ st = new_symtab(pst->filename, 2 * f_max, 2 * fh->cline);
+ }
+
+ /*
+ * Read in all partial symbtabs on which this one is dependent.
+ * NOTE that we do have circular dependencies, sigh.
+ */
+ for (i = 0; i < pst->number_of_dependencies; i++)
+ if (!pst->dependencies[i]->readin) {
+ /*
+ * DO NOT inform about additional files that need to
+ * be read in, it would only annoy the user.
+ */
+ psymtab_to_symtab_1(pst->dependencies[i]);
+ }
+
+ /* Now read the symbols for this symtab */
+
+ cur_fd = pst->ldsymoff;
+ cur_fdr = fh;
+ cur_stab = st;
+
+ /* Get a new lexical context */
+
+ push_parse_stack();
+ top_stack->cur_st = cur_stab;
+ top_stack->cur_block = BLOCKVECTOR_BLOCK(BLOCKVECTOR(cur_stab), 0);
+ BLOCK_START(top_stack->cur_block) = fh ? fh->adr : 0;
+ BLOCK_END(top_stack->cur_block) = 0;
+ top_stack->blocktype = stFile;
+ top_stack->maxsyms = f_max;
+ top_stack->cur_type = 0;
+ top_stack->procadr = 0;
+ top_stack->numargs = 0;
+
+ /* Parse locals and procedures */
+ if (fh)
+ parse_one_file(fh, cur_fd, (cur_fd == (cur_hdr->ifdMax - 1)) ?
+ cur_hdr->cbDnOffset : fh[1].adr);
+
+ /* .. and our share of externals.
+ XXX use the global list to speed up things here. how ? */
+ top_stack->blocktype = stFile;
+ top_stack->maxsyms = cur_hdr->isymMax + cur_hdr->ipdMax + cur_hdr->iextMax;
+ for (i = 0; i < cur_hdr->iextMax; i++) {
+ register EXTR *esh = (EXTR *) (cur_hdr->cbExtOffset) + i;
+ if (esh->ifd == cur_fd)
+ parse_external(esh, 1);
+ }
+
+ /* If there are undefined, tell the user */
+ if (n_undef_symbols) {
+ printf_filtered("File %s contains %d unresolved references:",
+ st->filename, n_undef_symbols);
+ printf_filtered("\n\t%4d variables\n\t%4d procedures\n\t%4d labels\n",
+ n_undef_vars, n_undef_procs, n_undef_labels);
+ n_undef_symbols = n_undef_labels = n_undef_vars = n_undef_procs = 0;
+ }
+
+ pop_parse_stack();
+
+ /*
+ * Sort the symbol table now, we are done adding symbols to it.
+ */
+ sort_symtab_syms(st);
+}
+
+
+
+
+/* Ancillary parsing procedures. */
+
+/* Lookup the type at relative index RN. Return it in TPP
+ if found and in any event come up with its name PNAME.
+ Return value says how many aux symbols we ate */
+
+static
+cross_ref(rn, tpp, pname)
+ RNDXR *rn;
+ struct type **tpp;
+ char **pname;
+{
+ unsigned rf;
+
+ /* Escape index means 'the next one' */
+ if (rn->rfd == 0xfff)
+ rf = *(unsigned *) (rn + 1);
+ else
+ rf = rn->rfd;
+
+ if (rf == -1) {
+ /* Ooops */
+ *pname = "<undefined>";
+ } else {
+ /*
+ * Find the relative file descriptor and the symbol in it
+ */
+ FDR *fh = get_rfd(cur_fd, rf);
+ SYMR *sh;
+ struct type *t;
+
+ /*
+ * If we have processed this symbol then we left a forwarding
+ * pointer to the corresponding GDB symbol. If not, we`ll put
+ * it in a list of pending symbols, to be processed later when
+ * the file f will be. In any event, we collect the name for
+ * the type here. Which is why we made a first pass at
+ * strings.
+ */
+ sh = (SYMR *) (fh->isymBase) + rn->index;
+
+ /* Careful, we might be looking at .o files */
+ *pname = (UNSAFE_DATA_ADDR(sh->iss)) ? "<undefined>" :
+ (char *) sh->iss;
+
+ /* Have we parsed it ? */
+ if ((!UNSAFE_DATA_ADDR(sh->value)) && (sh->st == stParsed)) {
+ t = (struct type *) sh->value;
+ *tpp = t;
+ } else {
+ struct pending *p;
+
+ /* Avoid duplicates */
+ p = is_pending_symbol(fh, sh);
+
+ if (p)
+ *tpp = p->t;
+ else
+ add_pending(fh, sh, *tpp);
+ }
+ }
+ return (rn->rfd == 0xfff);
+}
+
+
+/* Quick&dirty lookup procedure, to avoid the MI ones that require
+ keeping the symtab sorted */
+
+static struct symbol *
+mylookup_symbol (name, block, namespace, class)
+ char *name;
+ register struct block *block;
+ enum namespace namespace;
+ enum address_class class;
+{
+ register int bot, top, inc;
+ register struct symbol *sym;
+
+ bot = 0;
+ top = BLOCK_NSYMS(block);
+ inc = name[0];
+ while (bot < top) {
+ sym = BLOCK_SYM(block, bot);
+ if (SYMBOL_NAME(sym)[0] == inc
+ && SYMBOL_NAMESPACE(sym) == namespace
+ && SYMBOL_CLASS(sym) == class
+ && !strcmp(SYMBOL_NAME(sym), name))
+ return sym;
+ bot++;
+ }
+ if (block = BLOCK_SUPERBLOCK (block))
+ return mylookup_symbol (name, block, namespace, class);
+ return 0;
+}
+
+
+/* Add a new symbol S to a block B */
+
+static
+add_symbol(s,b)
+ struct symbol *s;
+ struct block *b;
+{
+ BLOCK_SYM(b,BLOCK_NSYMS(b)++) = s;
+ if (b == top_stack->cur_block &&
+ BLOCK_NSYMS(b) > top_stack->maxsyms)
+ printf_filtered("Internal: block at @%x overfilled (by %d)\n",
+ b, BLOCK_NSYMS(b) - top_stack->maxsyms);
+}
+
+/* Add a new block B to a symtab S */
+
+static
+add_block(b,s)
+ struct block *b;
+ struct symtab *s;
+{
+ struct blockvector *bv = BLOCKVECTOR(s);
+
+ bv = (struct blockvector *)xrealloc(bv, sizeof(struct blockvector) +
+ BLOCKVECTOR_NBLOCKS(bv) * sizeof(bv->block));
+ if (bv != BLOCKVECTOR(s))
+ BLOCKVECTOR(s) = bv;
+
+ BLOCKVECTOR_BLOCK(bv, BLOCKVECTOR_NBLOCKS(bv)++) = b;
+}
+
+/* Add a new linenumber entry (LINENO,ADR) to a linevector LT.
+ MIPS' linenumber encoding might need more than one byte
+ to describe it, LAST is used to detect these continuation lines */
+
+static
+add_line(lt, lineno, adr, last)
+ struct linetable *lt;
+ CORE_ADDR adr;
+{
+ if (last == 0)
+ last = -2; /* make sure we record first line */
+
+ if (last == lineno) /* skip continuation lines */
+ return lineno;
+
+ lt->item[lt->nitems].line = lineno;
+ lt->item[lt->nitems++].pc = adr << 2;
+ return lineno;
+}
+
+
+
+/* Comparison functions, used when sorting things */
+
+/* Symtabs must be ordered viz the code segments they cover */
+
+static int
+compare_symtabs( s1, s2)
+ struct symtab **s1, **s2;
+{
+ /* "most specific" first */
+
+ register struct block *b1, *b2;
+ b1 = BLOCKVECTOR_BLOCK(BLOCKVECTOR(*s1),0);
+ b2 = BLOCKVECTOR_BLOCK(BLOCKVECTOR(*s2),0);
+ if (BLOCK_END(b1) == BLOCK_END(b2))
+ return BLOCK_START(b1) - BLOCK_START(b2);
+ return BLOCK_END(b1) - BLOCK_END(b2);
+}
+
+
+/* Partial Symtabs, same */
+
+static int
+compare_psymtabs( s1, s2)
+ struct partial_symtab **s1, **s2;
+{
+ /* Perf twist: put the ones with no code at the end */
+
+ register int a = (*s1)->textlow;
+ register int b = (*s2)->textlow;
+ if (a == 0)
+ return b;
+ if (b == 0)
+ return -a;
+ return a - b;
+}
+
+
+/* Partial symbols are compared lexicog by their print names */
+
+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));
+}
+
+/* Blocks with a smaller low bound should come first */
+
+static int compare_blocks(b1,b2)
+ struct block **b1, **b2;
+{
+ register int addr_diff;
+
+ addr_diff = (BLOCK_START((*b1))) - (BLOCK_START((*b2)));
+ if (addr_diff == 0)
+ return (BLOCK_END((*b1))) - (BLOCK_END((*b2)));
+ return addr_diff;
+}
+
+
+/* Sorting and reordering procedures */
+
+/* Sort the blocks of a symtab S.
+ Reorder the blocks in the blockvector by code-address,
+ as required by some MI search routines */
+
+static
+sort_blocks(s)
+ struct symtab *s;
+{
+ struct blockvector *bv = BLOCKVECTOR(s);
+
+ if (BLOCKVECTOR_NBLOCKS(bv) <= 2) {
+ /* Cosmetic */
+ if (BLOCK_END(BLOCKVECTOR_BLOCK(bv,0)) == 0)
+ BLOCK_START(BLOCKVECTOR_BLOCK(bv,0)) = 0;
+ return;
+ }
+ /*
+ * This is very unfortunate: normally all functions are compiled in
+ * the order they are found, but if the file is compiled -O3 things
+ * are very different. It would be nice to find a reliable test
+ * to detect -O3 images in advance.
+ */
+ if (BLOCKVECTOR_NBLOCKS(bv) > 3)
+ qsort(&BLOCKVECTOR_BLOCK(bv,2),
+ BLOCKVECTOR_NBLOCKS(bv) - 2,
+ sizeof(struct block *),
+ compare_blocks);
+
+ {
+ register CORE_ADDR high = 0;
+ register int i, j = BLOCKVECTOR_NBLOCKS(bv);
+
+ for (i = 2; i < j; i++)
+ if (high < BLOCK_END(BLOCKVECTOR_BLOCK(bv,i)))
+ high = BLOCK_END(BLOCKVECTOR_BLOCK(bv,i));
+ BLOCK_END(BLOCKVECTOR_BLOCK(bv,0)) = high;
+ }
+
+ BLOCK_START(BLOCKVECTOR_BLOCK(bv,0)) = BLOCK_START(BLOCKVECTOR_BLOCK(bv,2));
+
+ BLOCK_START(BLOCKVECTOR_BLOCK(bv,1)) = BLOCK_START(BLOCKVECTOR_BLOCK(bv,0));
+ BLOCK_END (BLOCKVECTOR_BLOCK(bv,1)) = BLOCK_END (BLOCKVECTOR_BLOCK(bv,0));
+}
+
+/* Sort the symtab list, as required by some search procedures.
+ We want files ordered to make them look right to users, and for
+ searching (see block_for_pc). */
+
+static
+reorder_symtabs()
+{
+ register int i;
+ struct symtab *stab;
+ struct symtab **all_symtabs = (struct symtab **)
+ obstack_alloc (psymbol_obstack,
+ all_symtabs_count * sizeof (struct symtab *));
+
+ /* Create an array of pointers to all the symtabs. */
+ for (i = 0, stab = symtab_list;
+ i < all_symtabs_count;
+ i++, stab = stab->next) {
+ all_symtabs[i] = stab;
+ /* FIXME: Only do this for new symtabs ??? */
+ sort_blocks(all_symtabs[i]);
+ }
+
+ qsort(all_symtabs, all_symtabs_count,
+ sizeof(struct symtab *), compare_symtabs);
+
+ /* Re-construct the symtab list, but now it is sorted. */
+ for (i = 0; i < all_symtabs_count-1; i++)
+ all_symtabs[i]->next = all_symtabs[i+1];
+ all_symtabs[i]->next = 0;
+ symtab_list = all_symtabs[0];
+ obstack_free (psymbol_obstack, all_symtabs);
+}
+
+/* Sort the partial symtab list, as required by some search procedures */
+
+static reorder_psymtabs()
+{
+ register int i;
+ struct partial_symtab *pstab;
+
+ /*
+ * PC lookups stop at the first psymtab such that
+ * textlow <= PC < texthigh
+ */
+ /* Create an array of pointers to all the partial_symtabs. */
+ struct partial_symtab **all_psymtabs = (struct partial_symtab **)
+ obstack_alloc (psymbol_obstack,
+ all_psymtabs_count*sizeof(struct partial_symtab*));
+ for (i = 0, pstab = partial_symtab_list;
+ i < all_psymtabs_count;
+ i++, pstab = pstab->next)
+ all_psymtabs[i] = pstab;
+
+ qsort(all_psymtabs, all_psymtabs_count,
+ sizeof(struct partial_symtab *), compare_psymtabs);
+
+ /* Re-construct the partial_symtab_list, but now it is sorted. */
+
+ for (i = 0; i < all_psymtabs_count-1; i++)
+ all_psymtabs[i]->next = all_psymtabs[i+1];
+ all_psymtabs[i]->next = 0;
+ partial_symtab_list = all_psymtabs[0];
+
+ obstack_free (psymbol_obstack, all_psymtabs);
+}
+
+
+
+/* Constructor/restructor/destructor procedures */
+
+/* Allocate a new symtab for NAME. Needs an estimate of how many symbols
+ MAXSYMS and linenumbers MAXLINES we'll put in it */
+
+static
+struct symtab *
+new_symtab(name, maxsyms, maxlines)
+ char *name;
+{
+ struct symtab *s = (struct symtab *) xzalloc(sizeof(struct symtab));
+ int i;
+
+ LINETABLE(s) = new_linetable(maxlines);
+
+ s->filename = name;
+
+ /* All symtabs must have at least two blocks */
+ BLOCKVECTOR(s) = new_bvect(2);
+ BLOCKVECTOR_BLOCK(BLOCKVECTOR(s), 0) = new_block(maxsyms);
+ BLOCKVECTOR_BLOCK(BLOCKVECTOR(s), 1) = new_block(maxsyms);
+ BLOCK_SUPERBLOCK( BLOCKVECTOR_BLOCK(BLOCKVECTOR(s),1)) =
+ BLOCKVECTOR_BLOCK(BLOCKVECTOR(s), 0);
+
+ s->free_code = free_linetable;
+
+ /* Link the new symtab into the list of such. */
+ s->next = symtab_list;
+ symtab_list = s;
+
+ all_symtabs_count++;
+
+ return s;
+}
+
+/* Cleanup before loading a fresh image */
+
+static destroy_all_symtabs()
+{
+ if (symfile)
+ free(symfile);
+ symfile = 0;
+
+ free_all_symtabs();
+ all_symtabs_count = 0;
+ current_source_symtab = 0;
+ /* psymtabs! */
+}
+
+/* Allocate a new partial_symtab NAME */
+
+static struct partial_symtab *
+new_psymtab(name)
+ char *name;
+{
+ struct partial_symtab *pst;
+
+ pst = (struct partial_symtab *)
+ obstack_alloc (psymbol_obstack, sizeof (*pst));
+ bzero (pst, sizeof (*pst));
+
+ if (name == (char*)-1) /* FIXME -- why not null here? */
+ pst->filename = "<no name>";
+ else
+ pst->filename = name;
+
+ pst->next = partial_symtab_list;
+ partial_symtab_list = pst;
+ all_psymtabs_count++;
+
+ /* Keep a backpointer to the file`s symbols */
+ pst->ldsymlen = (int)cur_hdr;
+
+ /* The way to turn this into a symtab is to call... */
+ pst->read_symtab = mipscoff_psymtab_to_symtab;
+
+ return pst;
+}
+
+
+/* Allocate a new NAME psymbol from LIST, extending it if necessary.
+ The psymbol belongs to the psymtab at index PST_IDX */
+
+static struct partial_symbol *
+new_psymbol(list, name, pst_idx)
+ struct psymbol_allocation_list *list;
+ char *name;
+{
+ struct partial_symbol *p;
+ struct partial_symtab *pst = fdr_to_pst[pst_idx].pst;
+
+ /* Lists are pre-sized, we won`t overflow */
+
+ p = list->list + pst->globals_offset + pst->n_global_syms++;
+ SYMBOL_NAME(p) = name;
+ return p;
+}
+
+
+/* Allocate a linetable array of the given SIZE */
+
+static
+struct linetable *new_linetable(size)
+{
+ struct linetable *l;
+
+ size = size * sizeof(l->item) + sizeof(struct linetable);
+ l = (struct linetable *)xmalloc(size);
+ l->nitems = 0;
+ return l;
+}
+
+/* Oops, too big. Shrink it. This was important with the 2.4 linetables,
+ I am not so sure about the 3.4 ones */
+
+static shrink_linetable(s)
+ struct symtab *s;
+{
+ struct linetable *l = new_linetable(LINETABLE(s)->nitems);
+
+ bcopy(LINETABLE(s), l,
+ LINETABLE(s)->nitems * sizeof(l->item) + sizeof(struct linetable));
+ free (LINETABLE(s));
+ LINETABLE(s) = l;
+}
+
+/* Allocate and zero a new blockvector of NBLOCKS blocks. */
+
+static
+struct blockvector *new_bvect(nblocks)
+{
+ struct blockvector *bv;
+ int size;
+
+ size = sizeof(struct blockvector) + nblocks * sizeof(struct block*);
+ bv = (struct blockvector *) xzalloc(size);
+
+ BLOCKVECTOR_NBLOCKS(bv) = nblocks;
+
+ return bv;
+}
+
+/* Allocate and zero a new block of MAXSYMS symbols */
+
+static
+struct block *new_block(maxsyms)
+{
+ int size = sizeof(struct block) + (maxsyms-1) * sizeof(struct symbol *);
+ struct block *b = (struct block *)xzalloc(size);
+
+ return b;
+}
+
+/* Ooops, too big. Shrink block B in symtab S to its minimal size */
+
+static struct block *
+shrink_block(b, s)
+ struct block *b;
+ struct symtab *s;
+{
+ struct block *new;
+ struct blockvector *bv = BLOCKVECTOR(s);
+ int i;
+
+ /* Just get a new one, copy, and fix references to the old one */
+
+ new = (struct block *)xmalloc(sizeof(struct block) +
+ (BLOCK_NSYMS(b)-1) * sizeof(struct symbol *));
+
+ bcopy(b, new, sizeof(*new) + (BLOCK_NSYMS(b) - 1) * sizeof(struct symbol*));
+
+ /* Should chase pointers to old one. Fortunately, that`s just
+ the block`s function and inferior blocks */
+ if (BLOCK_FUNCTION(b) && SYMBOL_BLOCK_VALUE(BLOCK_FUNCTION(b)) == b)
+ SYMBOL_BLOCK_VALUE(BLOCK_FUNCTION(b)) = new;
+ for (i = 0; i < BLOCKVECTOR_NBLOCKS(bv); i++)
+ if (BLOCKVECTOR_BLOCK(bv,i) == b)
+ BLOCKVECTOR_BLOCK(bv,i) = new;
+ else if (BLOCK_SUPERBLOCK(BLOCKVECTOR_BLOCK(bv,i)) == b)
+ BLOCK_SUPERBLOCK(BLOCKVECTOR_BLOCK(bv,i)) = new;
+ free(b);
+ return new;
+}
+
+/* Create a new symbol with printname NAME */
+
+static
+struct symbol *
+new_symbol(name)
+ char *name;
+{
+ struct symbol *s = (struct symbol *)
+ obstack_alloc (symbol_obstack, sizeof (struct symbol));
+
+ bzero (s, sizeof (*s));
+ SYMBOL_NAME(s) = name;
+ return s;
+}
+
+/* Create a new type with printname NAME */
+
+static
+struct type *
+new_type(name)
+ char *name;
+{
+ struct type *t = (struct type *)
+ obstack_alloc (symbol_obstack, sizeof (struct type));
+
+ bzero (t, sizeof (*t));
+ TYPE_NAME(t) = name;
+ return t;
+}
+
+/* Create and initialize a new type with printname NAME.
+ CODE and LENGTH are the initial info we put in,
+ UNS says whether the type is unsigned or not. */
+
+static
+struct type *
+make_type(code, length, uns, name)
+ enum type_code code;
+ int length, uns;
+ char *name;
+{
+ register struct type *type;
+
+ type = (struct type *) xzalloc(sizeof(struct type));
+ TYPE_CODE(type) = code;
+ TYPE_LENGTH(type) = length;
+ TYPE_FLAGS(type) = uns ? TYPE_FLAG_UNSIGNED : 0;
+ TYPE_NAME(type) = name;
+
+ return type;
+}
+
+/* Allocate a new field named NAME to the type TYPE */
+
+static
+struct field *new_field(type,name)
+ struct type *type;
+ char *name;
+{
+ struct field *f;
+
+ /* Fields are kept in an array */
+ if (TYPE_NFIELDS(type))
+ TYPE_FIELDS(type) = (struct field*)xrealloc(TYPE_FIELDS(type),
+ (TYPE_NFIELDS(type)+1) * sizeof(struct field));
+ else
+ TYPE_FIELDS(type) = (struct field*)xzalloc(2*sizeof(struct field));
+ f = &(TYPE_FIELD(type,TYPE_NFIELDS(type)++));
+ bzero(f, sizeof(struct field));
+ if (name)
+ f->name = name;
+ return f;
+}
+
+/* Make an enum constant for a member F of an enumerated type T */
+
+static
+make_enum_constant(f,t)
+ struct field *f;
+ struct type *t;
+{
+ struct symbol *s;
+ /*
+ * This is awful, but that`s the way it is supposed to be
+ * (BTW, no need to free the real 'type', it's a builtin)
+ */
+ f->type = (struct type *) f->bitpos;
+
+ s = new_symbol(f->name);
+ SYMBOL_NAMESPACE(s) = VAR_NAMESPACE;
+ SYMBOL_CLASS(s) = LOC_CONST;
+ SYMBOL_TYPE(s) = t;
+ SYMBOL_VALUE(s) = f->bitpos;
+ add_symbol(s, top_stack->cur_block);
+}
+
+
+
+/* Things used for calling functions in the inferior.
+ These functions are exported to our companion
+ mips-dep.c file and are here because they play
+ with the symbol-table explicitly. */
+
+#if 0
+/* Need to make a new symbol on the fly for the dummy
+ frame we put on the stack. Which goes in the.. */
+
+static struct symtab *dummy_symtab;
+
+/* Make up a dummy symbol for the code we put at END_PC,
+ of size SIZE, invoking a function with NARGS arguments
+ and using a frame of FRAMESIZE bytes */
+
+mips_create_dummy_symbol(end_pc, size, nargs, framesize)
+{
+ struct block *bl;
+ struct symbol *g;
+ struct mips_extra_func_info *gdbinfo;
+
+ /* Allocate symtab if not done already */
+ if (dummy_symtab == 0)
+ dummy_symtab = new_symtab(".dummy_symtab.", 100, 0);
+
+ /* Make a new block. Only needs one symbol */
+ bl = new_block(1);
+ BLOCK_START(bl) = end_pc - size;
+ BLOCK_END(bl) = end_pc;
+
+ BLOCK_SUPERBLOCK(bl) = BLOCKVECTOR_BLOCK(BLOCKVECTOR(dummy_symtab),0);
+ add_block(bl, dummy_symtab);
+ sort_blocks(dummy_symtab);
+
+ BLOCK_FUNCTION(bl) = new_symbol("??");
+ SYMBOL_BLOCK_VALUE(BLOCK_FUNCTION(bl)) = bl;
+ g = new_symbol(".gdbinfo.");
+ BLOCK_SYM(bl,BLOCK_NSYMS(bl)++) = g;
+
+ SYMBOL_NAMESPACE(g) = LABEL_NAMESPACE;
+ SYMBOL_CLASS(g) = LOC_CONST;
+ SYMBOL_TYPE(g) = builtin_type_void;
+ gdbinfo = (struct mips_extra_func_info *)
+ xzalloc(sizeof(struct mips_extra_func_info));
+
+ SYMBOL_VALUE(g) = (long) gdbinfo;
+
+ gdbinfo->numargs = nargs;
+ gdbinfo->framesize = framesize;
+ gdbinfo->framereg = 29;
+ gdbinfo->pcreg = 31;
+ gdbinfo->regmask = -2;
+ gdbinfo->regoffset = -4;
+ gdbinfo->fregmask = 0; /* XXX */
+ gdbinfo->fregoffset = 0; /* XXX */
+}
+
+/* We just returned from the dummy code at END_PC, drop its symbol */
+
+mips_destroy_dummy_symbol(end_pc)
+{
+ struct block *bl;
+ struct blockvector *bv = BLOCKVECTOR(dummy_symtab);
+ int i;
+
+ bl = block_for_pc(end_pc);
+ free(BLOCK_FUNCTION(bl));
+ free(SYMBOL_VALUE(BLOCK_SYM(bl,0)));
+ free(BLOCK_SYM(bl,0));
+
+ for (i = 2; i < BLOCKVECTOR_NBLOCKS(bv); i++)
+ if (BLOCKVECTOR_BLOCK(bv,i) == bl)
+ break;
+ for (; i < BLOCKVECTOR_NBLOCKS(bv) - 1; i++)
+ BLOCKVECTOR_BLOCK(bv,i) = BLOCKVECTOR_BLOCK(bv,i+1);
+ BLOCKVECTOR_NBLOCKS(bv)--;
+ sort_blocks(dummy_symtab);
+ free(bl);
+}
+#endif
+
+/* Sigtramp: make sure we have all the necessary information
+ about the signal trampoline code. Since the official code
+ from MIPS does not do so, we make up that information ourselves.
+ If they fix the library (unlikely) this code will neutralize itself. */
+
+static
+fixup_sigtramp()
+{
+ struct symbol *s;
+ struct symtab *st;
+ struct block *b, *b0;
+
+ sigtramp_address = -1;
+
+ /* We know it is sold as sigvec */
+ s = lookup_symbol("sigvec", 0, VAR_NAMESPACE, 0, NULL);
+
+ /* Most programs do not play with signals */
+ if (s == 0)
+ return;
+
+ b0 = SYMBOL_BLOCK_VALUE(s);
+
+ /* A label of sigvec, to be more precise */
+ s = lookup_symbol("sigtramp", b0, VAR_NAMESPACE, 0, NULL);
+
+ /* But maybe this program uses its own version of sigvec */
+ if (s == 0)
+ return;
+
+ sigtramp_address = SYMBOL_VALUE(s);
+ sigtramp_end = sigtramp_address + 0x88; /* black magic */
+
+ /* Did we or MIPSco fix the library ? */
+ if (SYMBOL_CLASS(s) == LOC_BLOCK)
+ return;
+
+ /* But what symtab does it live in ? */
+ st = find_pc_symtab(SYMBOL_VALUE(s));
+
+ /*
+ * Ok, there goes the fix: turn it into a procedure, with all the
+ * needed info. Note we make it a nested procedure of sigvec,
+ * which is the way the (assembly) code is actually written.
+ */
+ SYMBOL_NAMESPACE(s) = VAR_NAMESPACE;
+ SYMBOL_CLASS(s) = LOC_BLOCK;
+ SYMBOL_TYPE(s) = make_type(TYPE_CODE_FUNC, 4, 0, 0);
+ TYPE_TARGET_TYPE(SYMBOL_TYPE(s)) = builtin_type_void;
+
+ /* Need a block to allocate .gdbinfo. in */
+ b = new_block(1);
+ SYMBOL_BLOCK_VALUE(s) = b;
+ BLOCK_START(b) = sigtramp_address;
+ BLOCK_END(b) = sigtramp_end;
+ BLOCK_FUNCTION(b) = s;
+ BLOCK_SUPERBLOCK(b) = BLOCK_SUPERBLOCK(b0);
+ add_block(b, st);
+ sort_blocks(st);
+
+ /* Make a .gdbinfo. for it */
+ {
+ struct mips_extra_func_info *e =
+ (struct mips_extra_func_info *)
+ xzalloc(sizeof(struct mips_extra_func_info));
+
+ e->numargs = 0; /* the kernel thinks otherwise */
+ /* align_longword(sigcontext + SIGFRAME) */
+ e->framesize = 0x150;
+ e->framereg = SP_REGNUM;
+ e->pcreg = 31;
+ e->regmask = -2;
+ e->regoffset = -(41 * sizeof(int));
+ e->fregmask = -1;
+ e->fregoffset = -(37 * sizeof(int));
+ e->isym = (long)s;
+
+ s = new_symbol(".gdbinfo.");
+ SYMBOL_VALUE(s) = (int) e;
+ SYMBOL_NAMESPACE(s) = LABEL_NAMESPACE;
+ SYMBOL_CLASS(s) = LOC_CONST;
+ SYMBOL_TYPE(s) = builtin_type_void;
+ }
+
+ BLOCK_SYM(b,BLOCK_NSYMS(b)++) = s;
+}
+
+
+/* Initialization */
+
+static struct sym_fns ecoff_sym_fns = {"ecoff", 5,
+ mipscoff_new_init, mipscoff_symfile_init,
+ mipscoff_symfile_read, mipscoff_symfile_discard};
+
+_initialize_mipsread ()
+{
+ add_symtab_fns (&ecoff_sym_fns);
+
+ bzero (&global_psymbols, sizeof (global_psymbols));
+ bzero (&static_psymbols, sizeof (static_psymbols));
+
+ add_com("add-file", class_files, add_file_command,
+ "Add a new symbol table (in mips format) from file FILE.");
+
+ /* Missing basic types */
+ builtin_type_string = make_type(TYPE_CODE_PASCAL_ARRAY,
+ 1, 0, "string");
+ builtin_type_complex = make_type(TYPE_CODE_FLT,
+ 2 * sizeof(float), 0, "complex");
+ builtin_type_double_complex = make_type(TYPE_CODE_FLT,
+ 2 * sizeof(double), 0, "double_complex");
+ builtin_type_fixed_dec = make_type(TYPE_CODE_INT, sizeof(int),
+ 0, "fixed_decimal");
+ builtin_type_float_dec = make_type(TYPE_CODE_FLT, sizeof(double),
+ 0, "floating_decimal");
+
+ /* Templates types */
+ builtin_type_ptr = lookup_pointer_type (builtin_type_void);
+ builtin_type_struct = make_type(TYPE_CODE_STRUCT, 0, 0, 0);
+ builtin_type_union = make_type(TYPE_CODE_UNION, 0, 0, 0);
+ builtin_type_enum = make_type(TYPE_CODE_ENUM, 0, 0, 0);
+ builtin_type_range = make_type(TYPE_CODE_RANGE, 0, 0, 0);
+ builtin_type_set = make_type(TYPE_CODE_SET, 0, 0, 0);
+}