]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Modified Files:
authorKung Hsu <kung@cygnus>
Tue, 1 Mar 1994 23:13:56 +0000 (23:13 +0000)
committerKung Hsu <kung@cygnus>
Tue, 1 Mar 1994 23:13:56 +0000 (23:13 +0000)
ChangeLog objfiles.c objfiles.h symfile.c target.c main.c
Makefile.in configure.in
Added Files:
os9kread.c os9kstab.c remote-os9k.c

        * os9kread.c: New file to read os9000 style symbo table.
        * os9kstab.c: new file to read os9000 style stabs.
        * remote-os9k.c: remote protocol talking to os9000 rombug monitor.
        * objfiles.c (find_pc_objfile): new function to search objfile
        from pc.
        * objfiles.c (objfile_relocate_data): new function to relocate
        data symbols in symbol table.
        * objfiles.h: Add two aux fields in struct objfile to handle
        multiple symbol table files situation like in os9000.
        * symfile.c: Change so 'symbol-file' command can handle multiple
        files. Also call target_link() to get relocation infos.
        * target.c (target_link): new function to get relocation info when
        a symbol file is requested to load.
        * main.c (quit_command): take out 'inferior_pid != 0' condition,
        because in cross mode there's no inferior pid, bit they need to
        be detached.
        Makefile.in: add os9kread.c os9kstab.c and .o's.
        configure.in: add i386os9k target.
        config/i386/i386os9k.mt: new add.
        config/i386/tm-i386os9k.h: new add.

gdb/ChangeLog
gdb/Makefile.in
gdb/configure.in
gdb/main.c
gdb/objfiles.c
gdb/objfiles.h
gdb/os9kread.c [new file with mode: 0644]
gdb/os9kstab.c [new file with mode: 0644]
gdb/remote-os9k.c [new file with mode: 0644]
gdb/symfile.c
gdb/target.c

index 12f89b6655a56746a8ddd09e13b80ca9155eea9b..3ed27e1b544600782ea59d22a6e2c2242cfadc50 100644 (file)
@@ -1,3 +1,26 @@
+Tue Mar  1 14:56:14 1994  Kung Hsu  (kung@mexican.cygnus.com)
+
+       * os9kread.c: New file to read os9000 style symbo table.
+       * os9kstab.c: new file to read os9000 style stabs.
+       * remote-os9k.c: remote protocol talking to os9000 rombug monitor.
+       * objfiles.c (find_pc_objfile): new function to search objfile
+       from pc.
+       * objfiles.c (objfile_relocate_data): new function to relocate
+       data symbols in symbol table.
+       * objfiles.h: Add two aux fields in struct objfile to handle
+       multiple symbol table files situation like in os9000.
+       * symfile.c: Change so 'symbol-file' command can handle multiple
+       files. Also call target_link() to get relocation infos.
+       * target.c (target_link): new function to get relocation info when
+       a symbol file is requested to load.
+       * main.c (quit_command): take out 'inferior_pid != 0' condition,
+       because in cross mode there's no inferior pid, bit they need to
+       be detached.
+       Makefile.in: add os9kread.c os9kstab.c and .o's.
+       configure.in: add i386os9k target.
+       config/i386/i386os9k.mt: new add.
+       config/i386/tm-i386os9k.h: new add.
+
 Tue Mar  1 13:16:10 1994  Peter Schauer  (pes@regent.e-technik.tu-muenchen.de)
 
        * config/sparc/tm-sun4sol2.h (IN_SIGTRAMP):  Handle ucbsigvechandler.
index dfedc1f07d7ed07869515aaf72cf8414cfd3aa47..34407a8840bef7a11d3c45e00fa22254b7ae266d 100644 (file)
@@ -178,7 +178,7 @@ CDEPS = $(XM_CDEPS) $(TM_CDEPS) $(NAT_CDEPS) \
 ADD_FILES = $(REGEX) $(XM_ADD_FILES) $(TM_ADD_FILES) $(NAT_ADD_FILES)
 ADD_DEPS = $(REGEX1) $(XM_ADD_FILES) $(TM_ADD_FILES) $(NAT_ADD_FILES)
 
-VERSION = 4.12.1
+VERSION = 4.12.2
 DIST=gdb
 
 LINT=/usr/5bin/lint
@@ -305,7 +305,8 @@ SFILES = blockframe.c breakpoint.c buildsym.c c-exp.y c-lang.c \
        mem-break.c minsyms.c mipsread.c nlmread.c objfiles.c parse.c \
        printcmd.c remote.c source.c stabsread.c stack.c symfile.c symmisc.c \
        symtab.c target.c thread.c typeprint.c utils.c valarith.c valops.c \
-       valprint.c values.c serial.c ser-unix.c mdebugread.c
+       valprint.c values.c serial.c ser-unix.c mdebugread.c os9kread.c \
+       os9kstab.c
 
 # Files that are not source code, but need to go into
 # gdb-$(VERSION).tar.Z.
@@ -442,7 +443,7 @@ OBS =       version.o main.o blockframe.o breakpoint.o findvar.o stack.o thread.o \
        dwarfread.o mipsread.o stabsread.o core.o c-lang.o ch-lang.o m2-lang.o \
        complaints.o typeprint.o c-typeprint.o ch-typeprint.o m2-typeprint.o \
        c-valprint.o cp-valprint.o ch-valprint.o m2-valprint.o nlmread.o \
-       serial.o mdebugread.o
+       serial.o mdebugread.o os9kread.o os9kstab.o
 
 TSOBS = inflow.o
 
@@ -1275,6 +1276,14 @@ mdebugread.o: mdebugread.c buildsym.h complaints.h $(bfd_h) $(defs_h) \
        $(expression_h) gdb-stabs.h $(gdbcore_h) $(gdbtypes_h) language.h \
        objfiles.h partial-stab.h stabsread.h symfile.h $(symtab_h)
 
+os9kread.o: os9kread.c buildsym.h complaints.h $(bfd_h) $(def_h) \
+        $(expression_h) gdb-stabs.h $(gdbcore_h) $(gdbtypes_h) language.h \
+        objfiles.h partial-stab.h stabsread.h symfile.h $(symtab_h)
+
+os9kstab.o: os9kstab.c $(bfd_h) $(INCLUDE_DIR)/aout/stab.def \
+       $(INCLUDE_DIR)/aout/stab_gnu.h buildsym.h complaints.h $(defs_h) \
+       $(gdbtypes_h) objfiles.h stabsread.h symfile.h $(symtab_h)
+
 mem-break.o: mem-break.c $(defs_h) 
 
 minsyms.o: minsyms.c $(bfd_h) $(defs_h) objfiles.h symfile.h \
index 9af7805ad56d2e365c1d0a36bc3b19cb687edcdc..1f9682b2cd646139264917cbe6629bb7cf75a1f3 100644 (file)
@@ -59,6 +59,7 @@ i[34]86-*-sysv4*)     gdb_host=i386v4 ;;
 i[34]86-*-unixware)    gdb_host=i386v4 ;;
 i[34]86-*-sysv*)       gdb_host=i386v ;;
 i[34]86-*-isc*)                gdb_host=i386v32 ;;
+i[34]86-*-os9k)                gdb_host=i386os9k ;;
 
 m680[01]0-sun-sunos3*) gdb_host=sun2os3 ;;
 m680[01]0-sun-sunos4*) gdb_host=sun2os4 ;;
@@ -199,6 +200,7 @@ i[34]86-*-elf*)             gdb_target=i386v ;;
 i[34]86-*-aix*)                gdb_target=i386aix ;;
 i[34]86-*-bsd*)                gdb_target=i386bsd ;;
 i[34]86-*-netbsd*)     gdb_target=i386bsd ;;
+i[34]86-*-os9k)                gdb_target=i386os9k ;;
 i[34]86-*-go32*)       gdb_target=i386aout ;;
 i[34]86-*-lynxos*)     gdb_target=i386lynx
                        configdirs="${configdirs} gdbserver" 
index 2cdabaf29b2b33b998d72a21769aa5ca933b8966..13154e14a4eade4087572a7968c5b563a8b60529 100644 (file)
@@ -2222,7 +2222,10 @@ quit_command (args, from_tty)
      char *args;
      int from_tty;
 {
-  if (inferior_pid != 0 && target_has_execution)
+  /* kung: inferior_pid may not exist in cross mode debugging, 
+     I commented it out temporarily, if it does not cause other problem,
+     we should take it out permenantly. */
+  if (/*inferior_pid != 0 &&*/ target_has_execution)
     {
       if (attach_flag)
        {
@@ -2239,9 +2242,13 @@ quit_command (args, from_tty)
            error ("Not confirmed.");
        }
     }
+  /* UDI wants this, to kill the TIP.  */
+  target_close (1);
+
   /* Save the history information if it is appropriate to do so.  */
   if (write_history_p && history_filename)
     write_history (history_filename);
+
   exit (0);
 }
 
index 381a095b15bf5e92eeee2590fd66863e21dcec52..40ab8fba8d1c88b46fca85ce8c66dd78d5526f82 100644 (file)
@@ -421,6 +421,21 @@ free_all_objfiles ()
   clear_symtab_users ();
 }
 \f
+struct objfile *
+find_pc_objfile(pc)
+     CORE_ADDR pc;
+{
+struct objfile *obj;
+struct obj_section *s;
+
+  ALL_OBJFILES (obj)
+    for (s = obj->sections; s < obj->sections_end; s++)
+      {
+       if (s->addr <= pc && s->endaddr > pc) return obj;
+      }
+  return (struct objfile *)NULL;
+}
+
 /* Relocate OBJFILE to NEW_OFFSETS.  There should be OBJFILE->NUM_SECTIONS
    entries in new_offsets.  */
 void
@@ -540,6 +555,107 @@ objfile_relocate (objfile, new_offsets)
   }
 }
 \f
+/* Relocate OBJFILE to NEW_OFFSETS.  There should be OBJFILE->NUM_SECTIONS
+   entries in new_offsets.  */
+void
+objfile_relocate_data (objfile, new_offsets)
+     struct objfile *objfile;
+     struct section_offsets *new_offsets;
+{
+  struct section_offsets *delta = (struct section_offsets *) alloca
+    (sizeof (struct section_offsets)
+     + objfile->num_sections * sizeof (delta->offsets));
+
+  {
+    int i;
+    int something_changed = 0;
+    for (i = 0; i < objfile->num_sections; ++i)
+      {
+       if (i != SECT_OFF_DATA && i != SECT_OFF_BSS)
+         ANOFFSET (delta, i) = 0;
+       else
+         ANOFFSET (delta, i) = ANOFFSET(new_offsets, i)
+                - ANOFFSET (objfile->section_offsets, i);
+       if (ANOFFSET (delta, i) != 0)
+         something_changed = 1;
+      }
+    if (!something_changed)
+      return;
+  }
+
+  /* OK, get all the symtabs.  */
+  {
+    struct symtab *s;
+
+    for (s = objfile->symtabs; s; s = s->next)
+      {
+       struct linetable *l;
+       struct blockvector *bv;
+       int i;
+       
+       /* Don't relocate a shared blockvector more than once.  */
+       if (!s->primary)
+         continue;
+
+       bv = BLOCKVECTOR (s);
+       for (i = 0; i < BLOCKVECTOR_NBLOCKS (bv); ++i)
+         {
+           struct block *b;
+           int j;
+           
+           b = BLOCKVECTOR_BLOCK (bv, i);
+           BLOCK_START (b) += ANOFFSET (delta, s->block_line_section);
+           BLOCK_END (b) += ANOFFSET (delta, s->block_line_section);
+
+           for (j = 0; j < BLOCK_NSYMS (b); ++j)
+             {
+               struct symbol *sym = BLOCK_SYM (b, j);
+               /* The RS6000 code from which this was taken skipped
+                  any symbols in STRUCT_NAMESPACE or UNDEF_NAMESPACE.
+                  But I'm leaving out that test, on the theory that
+                  they can't possibly pass the tests below.  */
+               if ((SYMBOL_CLASS (sym) == LOC_LABEL
+                    || SYMBOL_CLASS (sym) == LOC_STATIC)
+                   && SYMBOL_SECTION (sym) >= 0)
+                 {
+                   SYMBOL_VALUE_ADDRESS (sym) +=
+                     ANOFFSET (delta, SYMBOL_SECTION (sym));
+                 }
+             }
+         }
+      }
+  }
+
+  {
+    struct partial_symbol *psym;
+
+    for (psym = objfile->global_psymbols.list;
+        psym < objfile->global_psymbols.next;
+        psym++)
+      if (SYMBOL_SECTION (psym) >= 0)
+       SYMBOL_VALUE_ADDRESS (psym) += ANOFFSET (delta, SYMBOL_SECTION (psym));
+    for (psym = objfile->static_psymbols.list;
+        psym < objfile->static_psymbols.next;
+        psym++)
+      if (SYMBOL_SECTION (psym) >= 0)
+       SYMBOL_VALUE_ADDRESS (psym) += ANOFFSET (delta, SYMBOL_SECTION (psym));
+  }
+
+  {
+    struct minimal_symbol *msym;
+    ALL_OBJFILE_MSYMBOLS (objfile, msym)
+      if (SYMBOL_SECTION (msym) >= 0)
+       SYMBOL_VALUE_ADDRESS (msym) += ANOFFSET (delta, SYMBOL_SECTION (msym));
+  }
+
+  {
+    int i;
+    for (i = 0; i < objfile->num_sections; ++i)
+      if (i == SECT_OFF_DATA || i == SECT_OFF_BSS)
+        ANOFFSET (objfile->section_offsets, i) = ANOFFSET (new_offsets, i);
+  }
+}
+\f
 /* Many places in gdb want to test just to see if we have any partial
    symbols available.  This function returns zero if none are currently
    available, nonzero otherwise. */
index 6cff2cad93e58ef5d483e225108919b2c473aca7..381a6d6bfe8560e668d270ba482029969273322a 100644 (file)
@@ -310,6 +310,9 @@ struct objfile
   struct obj_section
     *sections,
     *sections_end;
+
+  /* two auxiliary fields, used to hold the fp of separate symbol files */
+  FILE *auxf1, *auxf2;
 };
 
 /* Defines for the objfile flag word. */
@@ -370,6 +373,8 @@ extern void free_objfile PARAMS ((struct objfile *));
 extern void
 free_all_objfiles PARAMS ((void));
 
+extern struct objfile * find_pc_objfile PARAMS ((CORE_ADDR));
+
 extern void
 objfile_relocate PARAMS ((struct objfile *, struct section_offsets *));
 
diff --git a/gdb/os9kread.c b/gdb/os9kread.c
new file mode 100644 (file)
index 0000000..5857c25
--- /dev/null
@@ -0,0 +1,1659 @@
+/* Read os9/os9k symbol tables and convert to internal format, for GDB.
+   Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993
+   Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* This module provides three functions: os9k_symfile_init,
+   which initializes to read a symbol file; os9k_new_init, which 
+   discards existing cached information when all symbols are being
+   discarded; and os9k_symfile_read, which reads a symbol table
+   from a file.
+
+   os9k_symfile_read only does the minimum work necessary for letting the
+   user "name" things symbolically; it does not read the entire symtab.
+   Instead, it reads the external and static symbols and puts 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 symbols
+   for real.  os9k_psymtab_to_symtab() is the function that does this */
+
+#include "defs.h"
+#include <string.h>
+#include <stdio.h>
+
+#if defined(USG) || defined(__CYGNUSCLIB__)
+#include <sys/types.h>
+#include <fcntl.h>
+#endif
+
+#include <obstack.h>
+#include <sys/param.h>
+#ifndef        NO_SYS_FILE
+#include <sys/file.h>
+#endif
+#include <sys/stat.h>
+#include <ctype.h>
+#include "symtab.h"
+#include "breakpoint.h"
+#include "command.h"
+#include "target.h"
+#include "gdbcore.h"           /* for bfd stuff */
+#include "libbfd.h"            /* FIXME Secret internal BFD stuff (bfd_read) */
+#include "libaout.h"           /* FIXME Secret internal BFD stuff for a.out */
+#include "symfile.h"
+#include "objfiles.h"
+#include "buildsym.h"
+#include "gdb-stabs.h"
+#include "demangle.h"
+#include "language.h"          /* Needed inside partial-stab.h */
+#include "complaints.h"
+#include "os9k.h"
+
+#if !defined (SEEK_SET)
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#endif
+
+/* Each partial symbol table entry contains a pointer to private data for the
+   read_symtab() function to use when expanding a partial symbol table entry
+   to a full symbol table entry.
+
+   For dbxread this structure contains the offset within the file symbol table
+   of first local symbol for this file, and count of the section
+   of the symbol table devoted to this file's symbols (actually, the section
+   bracketed may contain more than just this file's symbols).  It also contains
+   further information needed to locate the symbols if they are in an ELF file.
+
+   If ldsymcnt is 0, the only reason for this thing's existence is the
+   dependency list.  Nothing else will happen when it is read in.  */
+
+#define LDSYMOFF(p) (((struct symloc *)((p)->read_symtab_private))->ldsymoff)
+#define LDSYMCNT(p) (((struct symloc *)((p)->read_symtab_private))->ldsymnum)
+
+struct symloc {
+  int ldsymoff;
+  int ldsymnum;
+};
+
+/* Remember what we deduced to be the source language of this psymtab. */
+static enum language psymtab_language = language_unknown;
+
+/* keep partial symbol table file nested depth */
+static int psymfile_depth = 0;
+
+/* keep symbol table file nested depth */
+static int symfile_depth = 0;
+
+/* Nonzero means give verbose info on gdb action.  From main.c.  */
+extern int info_verbose;
+
+extern int previous_stab_code;
+
+/* The BFD for this file -- implicit parameter to next_symbol_text.  */
+static bfd *symfile_bfd;
+
+/* Name of last function encountered.  Used in Solaris to approximate
+   object file boundaries.  */
+static char *last_function_name;
+
+/* Complaints about the symbols we have encountered.  */
+extern struct complaint lbrac_complaint;
+
+extern struct complaint unknown_symtype_complaint;
+
+extern struct complaint unknown_symchar_complaint;
+
+extern struct complaint lbrac_rbrac_complaint;
+
+extern struct complaint repeated_header_complaint;
+
+extern struct complaint repeated_header_name_complaint;
+
+static struct complaint lbrac_unmatched_complaint =
+  {"unmatched Increment Block Entry before symtab pos %d", 0, 0};
+
+static struct complaint lbrac_mismatch_complaint =
+  {"IBE/IDE symbol mismatch at symtab pos %d", 0, 0};
+
+extern struct symbol *
+os9k_define_symbol PARAMS ((CORE_ADDR, char *, int, int, struct objfile *));
+
+\f
+/* Local function prototypes */
+static void
+os9k_read_ofile_symtab PARAMS ((struct partial_symtab *));
+
+static void
+os9k_psymtab_to_symtab PARAMS ((struct partial_symtab *));
+
+static void
+os9k_psymtab_to_symtab_1 PARAMS ((struct partial_symtab *));
+
+static void
+read_os9k_psymtab PARAMS ((struct section_offsets *, struct objfile *,
+                         CORE_ADDR, int));
+
+static void
+init_psymbol_list PARAMS ((struct objfile *));
+
+static char *
+os9k_next_symbol_text PARAMS ((void));
+
+static int
+fill_sym PARAMS ((FILE *, bfd *));
+
+static void
+os9k_symfile_init PARAMS ((struct objfile *));
+
+static void
+os9k_new_init PARAMS ((struct objfile *));
+
+static void
+os9k_symfile_read PARAMS ((struct objfile *, struct section_offsets *, int));
+
+static void
+os9k_symfile_finish PARAMS ((struct objfile *));
+
+static void
+os9k_process_one_symbol PARAMS ((int, int, CORE_ADDR, char *, 
+     struct section_offsets *, struct objfile *));
+
+static struct partial_symtab *
+os9k_start_psymtab PARAMS ((struct objfile *, struct section_offsets *, char *,
+                       CORE_ADDR, int, int, struct partial_symbol *,
+                       struct partial_symbol *));
+
+static struct partial_symtab *
+os9k_end_psymtab PARAMS ((struct partial_symtab *, char **, int, int, CORE_ADDR,
+                     struct partial_symtab **, int));
+
+static void
+record_minimal_symbol PARAMS ((char *, CORE_ADDR, int, struct objfile *));
+\f
+#define HANDLE_RBRAC(val) \
+  if ((val) > pst->texthigh) pst->texthigh = (val);
+
+#define SWAP_STBHDR(hdrp, abfd) \
+  { \
+    (hdrp)->fmtno = bfd_get_16(abfd, (unsigned char *)&(hdrp)->fmtno); \
+    (hdrp)->crc = bfd_get_32(abfd, (unsigned char *)&(hdrp)->crc); \
+    (hdrp)->offset = bfd_get_32(abfd, (unsigned char *)&(hdrp)->offset); \
+    (hdrp)->nsym = bfd_get_32(abfd, (unsigned char *)&(hdrp)->nsym); \
+  }
+#define SWAP_STBSYM(symp, abfd) \
+  { \
+    (symp)->value = bfd_get_32(abfd, (unsigned char *)&(symp)->value); \
+    (symp)->type = bfd_get_16(abfd, (unsigned char *)&(symp)->type); \
+    (symp)->stroff = bfd_get_32(abfd, (unsigned char *)&(symp)->stroff); \
+  }
+#define N_DATA 0
+#define N_BSS 1
+#define N_RDATA 2
+#define N_IDATA 3
+#define N_TEXT 4
+#define N_ABS 6
+
+static void
+record_minimal_symbol (name, address, type, objfile)
+     char *name;
+     CORE_ADDR address;
+     int type;
+     struct objfile *objfile;
+{
+  enum minimal_symbol_type ms_type;
+
+  switch (type)
+    {
+    case N_TEXT:  ms_type = mst_text; break;
+    case N_DATA:  ms_type = mst_data; break;
+    case N_BSS:   ms_type = mst_bss;  break;
+    case N_RDATA: ms_type = mst_bss; break;
+    case N_IDATA: ms_type = mst_data; break;
+    case N_ABS:   ms_type = mst_abs;  break;
+    default:      ms_type = mst_unknown; break;
+  }
+
+  prim_record_minimal_symbol
+    (obsavestring (name, strlen(name), &objfile->symbol_obstack),
+     address, ms_type, objfile);
+}
+
+/* read and process .stb file and store in minimal symbol table */
+typedef char mhhdr[80];
+struct stbhdr {
+       mhhdr comhdr;
+       char * name;
+       short fmtno;
+       int crc;
+       int offset;
+       int nsym;
+       char *pad;
+};
+struct stbsymbol {
+       int value;
+       short type;
+       int stroff;
+};
+#define STBSYMSIZE 10
+
+static int 
+read_minimal_symbols(objfile)
+     struct objfile *objfile;
+{
+FILE *fp;
+bfd *abfd;
+struct stbhdr hdr;
+struct stbsymbol sym;
+int ch, i, j, off;
+char buf[64], buf1[128];
+               
+  fp = objfile->auxf1;
+  if (fp == NULL) return;
+  abfd = objfile->obfd;
+  fread(&hdr.comhdr[0], sizeof(mhhdr), 1, fp);
+  i = 0;
+  ch = getc(fp);
+  while (ch != -1) {
+    buf[i] = (char)ch;
+    i++;
+    if (ch == 0) break;
+    ch = getc(fp);
+  };
+  hdr.name = &buf[0];
+
+  fread(&hdr.fmtno, sizeof(hdr.fmtno), 1, fp);
+  fread(&hdr.crc, sizeof(hdr.crc), 1, fp);
+  fread(&hdr.offset, sizeof(hdr.offset), 1, fp);
+  fread(&hdr.nsym, sizeof(hdr.nsym), 1, fp);
+  SWAP_STBHDR(&hdr, abfd);      
+       
+  /* read symbols */
+  init_minimal_symbol_collection();
+  off = hdr.offset;
+  for (i = hdr.nsym; i > 0; i--) {
+    fseek(fp, (long)off, 0);
+    fread(&sym.value, sizeof(sym.value), 1, fp);
+    fread(&sym.type, sizeof(sym.type), 1, fp);
+    fread(&sym.stroff, sizeof(sym.stroff), 1, fp);
+    SWAP_STBSYM (&sym, abfd);
+    fseek(fp, (long)sym.stroff, 0);
+    j = 0;
+    ch = getc(fp);
+    while (ch != -1) {
+       buf1[j] = (char)ch;
+       j++;
+       if (ch == 0) break;
+       ch = getc(fp);
+    };
+    record_minimal_symbol(buf1, sym.value, sym.type&7, objfile);
+    off += STBSYMSIZE;
+  };
+  install_minimal_symbols (objfile);
+  return 1;
+}
+\f
+/* Scan and build partial symbols for a symbol file.
+   We have been initialized by a call to os9k_symfile_init, which 
+   put all the relevant info into a "struct os9k_symfile_info",
+   hung off the objfile structure.
+
+   SECTION_OFFSETS contains offsets relative to which the symbols in the
+   various sections are (depending where the sections were actually loaded).
+   MAINLINE is true if we are reading the main symbol
+   table (as opposed to a shared lib or dynamically loaded file).  */
+
+static void
+os9k_symfile_read (objfile, section_offsets, mainline)
+     struct objfile *objfile;
+     struct section_offsets *section_offsets;
+     int mainline;     /* FIXME comments above */
+{
+  bfd *sym_bfd;
+  int val;
+  int stb_exist;
+  struct cleanup *back_to;
+
+  sym_bfd = objfile->obfd;
+  /* If we are reinitializing, or if we have never loaded syms yet, init */
+  if (mainline || objfile->global_psymbols.size == 0 || 
+    objfile->static_psymbols.size == 0)
+    init_psymbol_list (objfile);
+
+  pending_blocks = 0;
+  back_to = make_cleanup (really_free_pendings, 0);
+
+  make_cleanup (discard_minimal_symbols, 0);
+  read_minimal_symbols (objfile);
+
+  /* Now that the symbol table data of the executable file are all in core,
+     process them and define symbols accordingly.  */
+  read_os9k_psymtab (section_offsets, objfile,
+                  bfd_section_vma  (sym_bfd, DBX_TEXT_SECT (objfile)),
+                  bfd_section_size (sym_bfd, DBX_TEXT_SECT (objfile)));
+
+  if (!have_partial_symbols ()) {
+    wrap_here ("");
+    printf_filtered ("(no debugging symbols found)...");
+    wrap_here ("");
+  }
+
+  do_cleanups (back_to);
+}
+
+/* Initialize anything that needs initializing when a completely new
+   symbol file is specified (not just adding some symbols from another
+   file, e.g. a shared library).  */
+
+static void
+os9k_new_init (ignore)
+     struct objfile *ignore;
+{
+  stabsread_new_init ();
+  buildsym_new_init ();
+  psymfile_depth = 0;
+/*
+  init_header_files ();
+*/
+}
+
+/* os9k_symfile_init ()
+   It is passed a struct objfile which contains, among other things,
+   the BFD for the file whose symbols are being read, and a slot for a pointer
+   to "private data" which we fill with goodies.
+
+   Since BFD doesn't know how to read debug symbols in a format-independent
+   way (and may never do so...), we have to do it ourselves.  We will never
+   be called unless this is an a.out (or very similar) file. 
+   FIXME, there should be a cleaner peephole into the BFD environment here.  */
+
+static void
+os9k_symfile_init (objfile)
+     struct objfile *objfile;
+{
+  int val;
+  bfd *sym_bfd = objfile->obfd;
+  char *name = bfd_get_filename (sym_bfd);
+  char dbgname[64], stbname[64];
+  FILE *symfile = 0;
+  FILE *minfile = 0;
+
+
+  strcpy(dbgname, name);
+  strcat(dbgname, ".dbg");
+  strcpy(stbname, name);
+  strcat(stbname, ".stb");
+
+  if ((symfile = fopen(dbgname, "r")) == NULL) {
+    warning("Symbol file %s not found", dbgname);
+  }
+  objfile->auxf2 = symfile;
+
+  if ((minfile = fopen(stbname, "r")) == NULL) {
+    warning("Symbol file %s not found", stbname);
+  }
+  objfile->auxf1 = minfile;
+
+  /* Allocate struct to keep track of the symfile */
+  objfile->sym_stab_info = (PTR)
+    xmmalloc (objfile -> md, sizeof (struct dbx_symfile_info));
+  DBX_SYMFILE_INFO (objfile)->stab_section_info = NULL;
+
+  DBX_TEXT_SECT (objfile) = bfd_get_section_by_name (sym_bfd, ".text");
+  if (!DBX_TEXT_SECT (objfile))
+    error ("Can't find .text section in file");
+
+  DBX_SYMBOL_SIZE (objfile) = 0;     /* variable size symbol */
+  DBX_SYMCOUNT (objfile) =  0;  /* used to be bfd_get_symcount(sym_bfd) */
+  DBX_SYMTAB_OFFSET (objfile) = 0;  /* used to be SYMBOL_TABLE_OFFSET */
+}
+
+/* Perform any local cleanups required when we are done with a particular
+   objfile.  I.E, we are in the process of discarding all symbol information
+   for an objfile, freeing up all memory held for it, and unlinking the
+   objfile struct from the global list of known objfiles. */
+
+static void
+os9k_symfile_finish (objfile)
+     struct objfile *objfile;
+{
+  if (objfile->sym_stab_info != NULL)
+    {
+      mfree (objfile -> md, objfile->sym_stab_info);
+    }
+/*
+  free_header_files ();
+*/
+}
+
+\f
+struct dbghdr {
+  int sync;
+  short rev;
+  int crc;
+  short os;
+  short cpu;
+};
+
+#define SWAP_DBGHDR(hdrp, abfd) \
+  { \
+    (hdrp)->sync = bfd_get_32(abfd, (unsigned char *)&(hdrp)->sync); \
+    (hdrp)->rev = bfd_get_16(abfd, (unsigned char *)&(hdrp)->rev); \
+    (hdrp)->crc = bfd_get_32(abfd, (unsigned char *)&(hdrp)->crc); \
+    (hdrp)->os = bfd_get_16(abfd, (unsigned char *)&(hdrp)->os); \
+    (hdrp)->cpu = bfd_get_16(abfd, (unsigned char *)&(hdrp)->cpu); \
+  }
+
+#define N_SYM_CMPLR     0
+#define N_SYM_SLINE     1
+#define N_SYM_SYM       2
+#define N_SYM_LBRAC     3
+#define N_SYM_RBRAC     4
+#define N_SYM_SE        5
+
+struct internal_symstruct {
+  short n_type;
+  short n_desc;
+  long n_value;
+  char * n_strx;
+};
+static struct internal_symstruct symbol;
+static struct internal_symstruct *symbuf = &symbol;
+static char strbuf[256];
+
+static int
+fill_sym (dbg_file, abfd)
+     FILE *dbg_file;
+     bfd *abfd;
+{
+short id;
+short si;
+long li;
+int ii;
+
+  int nbytes = fread(&si, sizeof(si), 1, dbg_file);
+  if (nbytes == 0)
+    return 0;
+  if (nbytes < 0)
+    perror_with_name ("reading .dbg file.");
+  symbuf->n_desc = 0;
+  symbuf->n_value = 0;
+  symbuf->n_strx = NULL;
+  symbuf->n_type = bfd_get_16 (abfd, (unsigned char *)&si);
+  symbuf->n_type = 0xf & symbuf->n_type;
+  switch (symbuf->n_type)
+    {
+    case N_SYM_CMPLR:
+      fread(&si, sizeof(si), 1, dbg_file);
+      symbuf->n_desc = bfd_get_16(abfd, (unsigned char *)&si);
+      break;
+    case N_SYM_SLINE:
+      fread(&li, sizeof(li), 1, dbg_file);
+      symbuf->n_value = bfd_get_32(abfd, (unsigned char *)&li);
+      fread(&li, sizeof(li), 1, dbg_file);
+      li = bfd_get_32(abfd, (unsigned char *)&li);
+      symbuf->n_strx = (char *)(li >> 12);
+      symbuf->n_desc = li & 0xfff;
+      break;
+    case N_SYM_SYM:
+      fread(&li, sizeof(li), 1, dbg_file);
+      symbuf->n_value = bfd_get_32(abfd, (unsigned char *)&li);
+      si = 0;
+      do {
+       ii = getc(dbg_file);
+       strbuf[si++] = (char) ii;
+      } while (ii != 0 || si % 2 != 0);
+      symbuf->n_strx = strbuf;
+      break;
+    case N_SYM_LBRAC:
+      fread(&li, sizeof(li), 1, dbg_file);
+      symbuf->n_value = bfd_get_32(abfd, (unsigned char *)&li);
+      break;
+    case N_SYM_RBRAC:
+      fread(&li, sizeof(li), 1, dbg_file);
+      symbuf->n_value = bfd_get_32(abfd, (unsigned char *)&li);
+      break;
+    case N_SYM_SE:
+      break;
+    }
+    return 1;
+}
+\f
+/* Initializes storage for all of the partial symbols that will be
+   created by read_dbx_symtab and subsidiaries.  */
+
+static void
+init_psymbol_list (objfile)
+     struct objfile *objfile;
+{
+  /* Free any previously allocated psymbol lists.  */
+  if (objfile -> global_psymbols.list)
+    mfree (objfile -> md, (PTR)objfile -> global_psymbols.list);
+  if (objfile -> static_psymbols.list)
+    mfree (objfile -> md, (PTR)objfile -> static_psymbols.list);
+
+  /* Current best guess is that there are approximately a twentieth
+     of the total symbols (in a debugging file) are global or static
+     oriented symbols */
+  objfile -> global_psymbols.size = DBX_SYMCOUNT (objfile) / 10;
+  objfile -> static_psymbols.size = DBX_SYMCOUNT (objfile) / 10;
+  objfile -> global_psymbols.next = objfile -> global_psymbols.list = (struct partial_symbol *)
+    xmmalloc (objfile -> md, objfile -> global_psymbols.size * sizeof (struct partial_symbol));
+  objfile -> static_psymbols.next = objfile -> static_psymbols.list = (struct partial_symbol *)
+    xmmalloc (objfile -> md, objfile -> static_psymbols.size * sizeof (struct partial_symbol));
+}
+
+/* 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.
+   SYMFILE_NAME is the name of the file we are reading from
+   and SECTION_OFFSETS is the set of offsets for the various sections
+   of the file (a set of zeros if the mainline program).  */
+
+static void
+read_os9k_psymtab (section_offsets, objfile, text_addr, text_size)
+     struct section_offsets *section_offsets;
+     struct objfile *objfile;
+     CORE_ADDR text_addr;
+     int text_size;
+{
+  register struct internal_symstruct *bufp = 0;        /* =0 avoids gcc -Wall glitch*/
+  register char *namestring;
+  int nsl;
+  int past_first_source_file = 0;
+  CORE_ADDR last_o_file_start = 0;
+  struct cleanup *back_to;
+  bfd *abfd;
+  FILE *fp;
+  struct dbghdr hdr;
+
+  /* End of the text segment of the executable file.  */
+  static CORE_ADDR end_of_text_addr;
+
+  /* Current partial symtab */
+  static struct partial_symtab *pst = 0;
+
+  /* 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;
+
+  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 *));
+
+  last_source_file = NULL;
+
+#ifdef END_OF_TEXT_DEFAULT
+  end_of_text_addr = END_OF_TEXT_DEFAULT;
+#else
+  end_of_text_addr = text_addr + section_offsets->offsets[SECT_OFF_TEXT]
+                              + text_size;     /* Relocate */
+#endif
+
+  abfd = objfile->obfd;
+  fp = objfile->auxf2; 
+               
+  fread(&hdr.sync, sizeof(hdr.sync), 1, fp);
+  fread(&hdr.rev, sizeof(hdr.rev), 1, fp);
+  fread(&hdr.crc, sizeof(hdr.crc), 1, fp);
+  fread(&hdr.os, sizeof(hdr.os), 1, fp);
+  fread(&hdr.cpu, sizeof(hdr.cpu), 1, fp);
+  SWAP_DBGHDR(&hdr, abfd);      
+
+  symnum = 0;
+  while(1)
+    {
+    int ret;
+    long cursymoffset;
+
+      /* Get the symbol for this run and pull out some info */
+      QUIT;    /* allow this to be interruptable */
+      cursymoffset = ftell(objfile->auxf2);
+      ret = fill_sym(objfile->auxf2, abfd);
+      if (ret <= 0) break;
+      else symnum++;
+      bufp = symbuf;
+
+      /* Special case to speed up readin. */
+      if (bufp->n_type == (short)N_SYM_SLINE) continue;
+
+#define CUR_SYMBOL_VALUE bufp->n_value
+      /* partial-stab.h */
+
+      switch (bufp->n_type)
+       {
+       char *p;
+
+       case N_SYM_CMPLR:
+         continue;
+
+       case N_SYM_SE:
+          CUR_SYMBOL_VALUE += ANOFFSET(section_offsets, SECT_OFF_TEXT);
+         if (psymfile_depth == 1 && pst)
+           {
+             os9k_end_psymtab (pst, psymtab_include_list, includes_used,
+                      symnum, CUR_SYMBOL_VALUE,
+                      dependency_list, dependencies_used);
+             pst = (struct partial_symtab *) 0;
+             includes_used = 0;
+             dependencies_used = 0;
+           }
+         psymfile_depth--;
+         continue;
+
+       case N_SYM_SYM:         /* Typedef or automatic variable. */
+         namestring = bufp->n_strx;
+          p = (char *) strchr (namestring, ':');
+          if (!p)
+            continue;           /* Not a debugging symbol.   */
+
+         /* Main processing section for debugging symbols which
+            the initial read through the symbol tables needs to worry
+            about.  If we reach this point, the symbol which we are
+            considering is definitely one we are interested in.
+            p must also contain the (valid) index into the namestring
+            which indicates the debugging type symbol.  */
+
+         switch (p[1])
+           {
+           case 'S' :
+             {
+               unsigned long valu;
+               enum language tmp_language;
+               
+               valu = CUR_SYMBOL_VALUE + 
+                 ANOFFSET (section_offsets, SECT_OFF_TEXT);
+               past_first_source_file = 1;
+
+               if (psymfile_depth == 0) {
+                 if (!pst)
+                   pst = os9k_start_psymtab (objfile, section_offsets,
+                                namestring, valu,
+                                cursymoffset,
+                                symnum-1,
+                                objfile -> global_psymbols.next,
+                                objfile -> static_psymbols.next);
+               } else { /* this is a include file */
+                 tmp_language = deduce_language_from_filename (namestring);
+                 if (tmp_language != language_unknown
+                       && (tmp_language != language_c
+                       || psymtab_language != language_cplus))
+                       psymtab_language = tmp_language;
+
+/*
+                 if (pst && STREQ (namestring, pst->filename))
+                   continue;
+                 {
+                   register int i;
+                   for (i = 0; i < includes_used; i++)
+                     if (STREQ (namestring, psymtab_include_list[i]))
+                       {
+                         i = -1; 
+                         break;
+                       }
+                   if (i == -1)
+                     continue;
+                 }
+*/
+
+                  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 *));
+                      memcpy ((PTR)psymtab_include_list, (PTR)orig,
+                          includes_used * sizeof (char *));
+                   }
+
+               }
+               psymfile_depth++;
+               continue;
+             }
+
+           case 'v':
+             ADD_PSYMBOL_ADDR_TO_LIST (namestring, p - namestring,
+                                       VAR_NAMESPACE, LOC_STATIC,
+                                       objfile->static_psymbols,
+                                       CUR_SYMBOL_VALUE,
+                                       psymtab_language, objfile);
+             continue;
+           case 'V':
+             ADD_PSYMBOL_ADDR_TO_LIST (namestring, p - namestring,
+                                       VAR_NAMESPACE, LOC_STATIC,
+                                       objfile->global_psymbols,
+                                       CUR_SYMBOL_VALUE,
+                                       psymtab_language, objfile);
+             continue;
+
+           case 'T':
+             if (p != namestring)      /* a name is there, not just :T... */
+               {
+                 ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+                                      STRUCT_NAMESPACE, LOC_TYPEDEF,
+                                      objfile->static_psymbols,
+                                      CUR_SYMBOL_VALUE,
+                                      psymtab_language, objfile);
+                 if (p[2] == 't')
+                   {
+                     /* Also a typedef with the same name.  */
+                     ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+                                          VAR_NAMESPACE, LOC_TYPEDEF,
+                                          objfile->static_psymbols,
+                                          CUR_SYMBOL_VALUE, psymtab_language,
+                                          objfile);
+                     p += 1;
+                   }
+                 /* The semantics of C++ state that "struct foo { ... }"
+                    also defines a typedef for "foo".  Unfortuantely, cfront
+                    never makes the typedef when translating from C++ to C.
+                    We make the typedef here so that "ptype foo" works as
+                    expected for cfront translated code.  */
+                 else if (psymtab_language == language_cplus)
+                  {
+                     /* Also a typedef with the same name.  */
+                     ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+                                          VAR_NAMESPACE, LOC_TYPEDEF,
+                                          objfile->static_psymbols,
+                                          CUR_SYMBOL_VALUE, psymtab_language,
+                                          objfile);
+                  }
+               }
+             goto check_enum;
+           case 't':
+             if (p != namestring)      /* a name is there, not just :T... */
+               {
+                 ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+                                      VAR_NAMESPACE, LOC_TYPEDEF,
+                                      objfile->static_psymbols,
+                                      CUR_SYMBOL_VALUE,
+                                      psymtab_language, objfile);
+               }
+           check_enum:
+             /* If this is an enumerated type, we need to
+                add all the enum constants to the partial symbol
+                table.  This does not cover enums without names, e.g.
+                "enum {a, b} c;" in C, but fortunately those are
+                rare.  There is no way for GDB to find those from the
+                enum type without spending too much time on it.  Thus
+                to solve this problem, the compiler needs to put out the
+                enum in a nameless type.  GCC2 does this.  */
+
+             /* We are looking for something of the form
+                <name> ":" ("t" | "T") [<number> "="] "e" <size>
+                {<constant> ":" <value> ","} ";".  */
+
+             /* Skip over the colon and the 't' or 'T'.  */
+             p += 2;
+             /* This type may be given a number.  Also, numbers can come
+                in pairs like (0,26).  Skip over it.  */
+             while ((*p >= '0' && *p <= '9')
+                    || *p == '(' || *p == ',' || *p == ')'
+                    || *p == '=')
+               p++;
+
+             if (*p++ == 'e')
+               {
+                 /* We have found an enumerated type. skip size */
+                 while (*p >= '0' && *p <= '9') p++;
+                 /* According to comments in read_enum_type
+                    a comma could end it instead of a semicolon.
+                    I don't know where that happens.
+                    Accept either.  */
+                 while (*p && *p != ';' && *p != ',')
+                   {
+                     char *q;
+
+                     /* Check for and handle cretinous dbx symbol name
+                        continuation! 
+                     if (*p == '\\')
+                       p = next_symbol_text ();
+                     */
+
+                     /* Point to the character after the name
+                        of the enum constant.  */
+                     for (q = p; *q && *q != ':'; q++)
+                       ;
+                     /* Note that the value doesn't matter for
+                        enum constants in psymtabs, just in symtabs.  */
+                     ADD_PSYMBOL_TO_LIST (p, q - p,
+                                          VAR_NAMESPACE, LOC_CONST,
+                                          objfile->static_psymbols, 0,
+                                          psymtab_language, objfile);
+                     /* Point past the name.  */
+                     p = q;
+                     /* Skip over the value.  */
+                     while (*p && *p != ',')
+                       p++;
+                     /* Advance past the comma.  */
+                     if (*p)
+                       p++;
+                   }
+               }
+             continue;
+           case 'c':
+             /* Constant, e.g. from "const" in Pascal.  */
+             ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+                                  VAR_NAMESPACE, LOC_CONST,
+                                  objfile->static_psymbols, CUR_SYMBOL_VALUE,
+                                  psymtab_language, objfile);
+             continue;
+
+           case 'f':
+             CUR_SYMBOL_VALUE += ANOFFSET(section_offsets, SECT_OFF_TEXT);
+              if (pst && pst->textlow == 0)
+                pst->textlow = CUR_SYMBOL_VALUE;
+
+             ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+                                  VAR_NAMESPACE, LOC_BLOCK,
+                                  objfile->static_psymbols, CUR_SYMBOL_VALUE,
+                                  psymtab_language, objfile);
+             continue;
+
+           case 'F':
+             CUR_SYMBOL_VALUE += ANOFFSET(section_offsets, SECT_OFF_TEXT);
+              if (pst && pst->textlow == 0)
+                pst->textlow = CUR_SYMBOL_VALUE;
+
+             ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+                                  VAR_NAMESPACE, LOC_BLOCK,
+                                  objfile->global_psymbols, CUR_SYMBOL_VALUE,
+                                  psymtab_language, objfile);
+             continue;
+
+           case 'p':
+           case 'l':
+             continue;
+
+           case ':':
+             /* It is a C++ nested symbol.  We don't need to record it
+                (I don't think); if we try to look up foo::bar::baz,
+                then symbols for the symtab containing foo should get
+                read in, I think.  */
+             /* Someone says sun cc puts out symbols like
+                /foo/baz/maclib::/usr/local/bin/maclib,
+                which would get here with a symbol type of ':'.  */
+             continue;
+
+           default:
+             /* Unexpected symbol descriptor.  The second and subsequent stabs
+                of a continued stab can show up here.  The question is
+                whether they ever can mimic a normal stab--it would be
+                nice if not, since we certainly don't want to spend the
+                time searching to the end of every string looking for
+                a backslash.  */
+
+             complain (&unknown_symchar_complaint, p[1]);
+             continue;
+           }
+
+       case N_SYM_RBRAC:
+         CUR_SYMBOL_VALUE += ANOFFSET(section_offsets, SECT_OFF_TEXT);
+#ifdef HANDLE_RBRAC
+         HANDLE_RBRAC(CUR_SYMBOL_VALUE);
+         continue;
+#endif
+       case N_SYM_LBRAC:
+         continue;
+
+       default:
+         /* If we haven't found it yet, ignore it.  It's probably some
+            new type we don't know about yet.  */
+         complain (&unknown_symtype_complaint,
+                   local_hex_string ((unsigned long) bufp->n_type));
+         continue;
+       }
+    }
+
+  DBX_SYMCOUNT (objfile) = symnum;
+
+  /* If there's stuff to be cleaned up, clean it up.  */
+  if (DBX_SYMCOUNT (objfile) > 0
+/*FIXME, does this have a bug at start address 0? */
+      && last_o_file_start
+      && objfile -> ei.entry_point < bufp->n_value
+      && objfile -> ei.entry_point >= last_o_file_start)
+    {
+      objfile -> ei.entry_file_lowpc = last_o_file_start;
+      objfile -> ei.entry_file_highpc = bufp->n_value;
+    }
+
+  if (pst)
+    {
+      os9k_end_psymtab (pst, psymtab_include_list, includes_used,
+                  symnum, end_of_text_addr,
+                  dependency_list, dependencies_used);
+    }
+/*
+  do_cleanups (back_to);
+*/
+}
+
+/* Allocate and partially fill a partial symtab.  It will be
+   completely filled at the end of the symbol list.
+
+   SYMFILE_NAME is the name of the symbol-file we are reading from, and ADDR
+   is the address relative to which its symbols are (incremental) or 0
+   (normal). */
+
+
+static struct partial_symtab *
+os9k_start_psymtab (objfile, section_offsets,
+              filename, textlow, ldsymoff,ldsymcnt,  global_syms, static_syms)
+     struct objfile *objfile;
+     struct section_offsets *section_offsets;
+     char *filename;
+     CORE_ADDR textlow;
+     int ldsymoff;
+     int ldsymcnt;
+     struct partial_symbol *global_syms;
+     struct partial_symbol *static_syms;
+{
+  struct partial_symtab *result =
+      start_psymtab_common(objfile, section_offsets,
+                          filename, textlow, global_syms, static_syms);
+
+  result->read_symtab_private = (char *)
+    obstack_alloc (&objfile -> psymbol_obstack, sizeof (struct symloc));
+
+  LDSYMOFF(result) = ldsymoff;
+  LDSYMCNT(result) = ldsymcnt;
+  result->read_symtab = os9k_psymtab_to_symtab;
+
+  /* Deduce the source language from the filename for this psymtab. */
+  psymtab_language = deduce_language_from_filename (filename);
+  return result;
+}
+
+/* Close off the current usage of PST.  
+   Returns PST or NULL if the partial symtab was empty and thrown away.
+   FIXME:  List variables and peculiarities of same.  */
+
+static struct partial_symtab *
+os9k_end_psymtab (pst, include_list, num_includes, capping_symbol_cnt,
+            capping_text, dependency_list, number_dependencies)
+     struct partial_symtab *pst;
+     char **include_list;
+     int num_includes;
+     int capping_symbol_cnt;
+     CORE_ADDR capping_text;
+     struct partial_symtab **dependency_list;
+     int number_dependencies;
+/*     struct partial_symbol *capping_global, *capping_static;*/
+{
+  int i;
+  struct partial_symtab *p1;
+  struct objfile *objfile = pst -> objfile;
+
+  if (capping_symbol_cnt != -1)
+      LDSYMCNT(pst) = capping_symbol_cnt - LDSYMCNT(pst);
+
+  /* Under Solaris, the N_SO symbols always have a value of 0,
+     instead of the usual address of the .o file.  Therefore,
+     we have to do some tricks to fill in texthigh and textlow.
+     The first trick is in partial-stab.h: if we see a static
+     or global function, and the textlow for the current pst
+     is still 0, then we use that function's address for 
+     the textlow of the pst.
+
+     Now, to fill in texthigh, we remember the last function seen
+     in the .o file (also in partial-stab.h).  Also, there's a hack in
+     bfd/elf.c and gdb/elfread.c to pass the ELF st_size field
+     to here via the misc_info field.  Therefore, we can fill in
+     a reliable texthigh by taking the address plus size of the
+     last function in the file.
+
+     Unfortunately, that does not cover the case where the last function
+     in the file is static.  See the paragraph below for more comments
+     on this situation.
+
+     Finally, if we have a valid textlow for the current file, we run
+     down the partial_symtab_list filling in previous texthighs that
+     are still unknown.  */
+
+  if (pst->texthigh == 0 && last_function_name) {
+    char *p;
+    int n;
+    struct minimal_symbol *minsym;
+
+    p = strchr (last_function_name, ':');
+    if (p == NULL)
+      p = last_function_name;
+    n = p - last_function_name;
+    p = alloca (n + 1);
+    strncpy (p, last_function_name, n);
+    p[n] = 0;
+    
+    minsym = lookup_minimal_symbol (p, objfile);
+
+    if (minsym) {
+      pst->texthigh = SYMBOL_VALUE_ADDRESS(minsym)+(long)MSYMBOL_INFO(minsym);
+    } else {
+      /* This file ends with a static function, and it's
+        difficult to imagine how hard it would be to track down
+        the elf symbol.  Luckily, most of the time no one will notice,
+        since the next file will likely be compiled with -g, so
+        the code below will copy the first fuction's start address 
+        back to our texthigh variable.  (Also, if this file is the
+        last one in a dynamically linked program, texthigh already
+        has the right value.)  If the next file isn't compiled
+        with -g, then the last function in this file winds up owning
+        all of the text space up to the next -g file, or the end (minus
+        shared libraries).  This only matters for single stepping,
+        and even then it will still work, except that it will single
+        step through all of the covered functions, instead of setting
+        breakpoints around them as it usualy does.  This makes it
+        pretty slow, but at least it doesn't fail.
+
+        We can fix this with a fairly big change to bfd, but we need
+        to coordinate better with Cygnus if we want to do that.  FIXME.  */
+    }
+    last_function_name = NULL;
+  }
+
+  /* this test will be true if the last .o file is only data */
+  if (pst->textlow == 0)
+    pst->textlow = pst->texthigh;
+
+  /* If we know our own starting text address, then walk through all other
+     psymtabs for this objfile, and if any didn't know their ending text
+     address, set it to our starting address.  Take care to not set our
+     own ending address to our starting address, nor to set addresses on
+     `dependency' files that have both textlow and texthigh zero.  */
+  if (pst->textlow) {
+    ALL_OBJFILE_PSYMTABS (objfile, p1) {
+      if (p1->texthigh == 0  && p1->textlow != 0 && p1 != pst) {
+       p1->texthigh = pst->textlow;
+       /* if this file has only data, then make textlow match texthigh */
+       if (p1->textlow == 0)
+         p1->textlow = p1->texthigh;
+      }
+    }
+  }
+
+  /* End of kludge for patching Solaris textlow and texthigh.  */
+
+  pst->n_global_syms =
+    objfile->global_psymbols.next - (objfile->global_psymbols.list + pst->globals_offset);
+  pst->n_static_syms =
+    objfile->static_psymbols.next - (objfile->static_psymbols.list + pst->statics_offset);
+
+  pst->number_of_dependencies = number_dependencies;
+  if (number_dependencies)
+    {
+      pst->dependencies = (struct partial_symtab **)
+       obstack_alloc (&objfile->psymbol_obstack,
+                      number_dependencies * sizeof (struct partial_symtab *));
+      memcpy (pst->dependencies, dependency_list,
+            number_dependencies * sizeof (struct partial_symtab *));
+    }
+  else
+    pst->dependencies = 0;
+
+  for (i = 0; i < num_includes; i++)
+    {
+      struct partial_symtab *subpst =
+       allocate_psymtab (include_list[i], objfile);
+
+      subpst->section_offsets = pst->section_offsets;
+      subpst->read_symtab_private =
+         (char *) obstack_alloc (&objfile->psymbol_obstack,
+                                 sizeof (struct symloc));
+      LDSYMOFF(subpst) =
+       LDSYMCNT(subpst) =
+         subpst->textlow =
+           subpst->texthigh = 0;
+
+      /* We could save slight bits of space by only making one of these,
+        shared by the entire set of include files.  FIXME-someday.  */
+      subpst->dependencies = (struct partial_symtab **)
+       obstack_alloc (&objfile->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->readin = 0;
+      subpst->symtab = 0;
+      subpst->read_symtab = pst->read_symtab;
+    }
+
+  sort_pst_symbols (pst);
+
+  /* If there is already a psymtab or symtab for a file of this name, 
+     remove it.
+     (If there is a symtab, more drastic things also happen.)
+     This happens in VxWorks.  */
+  free_named_symtabs (pst->filename);
+
+  if (num_includes == 0
+   && number_dependencies == 0
+   && pst->n_global_syms == 0
+   && pst->n_static_syms == 0) {
+    /* Throw away this psymtab, it's empty.  We can't deallocate it, since
+       it is on the obstack, but we can forget to chain it on the list.  */
+    struct partial_symtab *prev_pst;
+
+    /* First, snip it out of the psymtab chain */
+
+    if (pst->objfile->psymtabs == pst)
+      pst->objfile->psymtabs = pst->next;
+    else
+      for (prev_pst = pst->objfile->psymtabs; prev_pst; prev_pst = pst->next)
+       if (prev_pst->next == pst)
+         prev_pst->next = pst->next;
+
+    /* Next, put it on a free list for recycling */
+    pst->next = pst->objfile->free_psymtabs;
+    pst->objfile->free_psymtabs = pst;
+
+    /* Indicate that psymtab was thrown away.  */
+    pst = (struct partial_symtab *)NULL;
+  }
+  return pst;
+}
+\f
+static void
+os9k_psymtab_to_symtab_1 (pst)
+     struct partial_symtab *pst;
+{
+  struct cleanup *old_chain;
+  int i;
+  
+  if (!pst)
+    return;
+
+  if (pst->readin)
+    {
+      fprintf_unfiltered (gdb_stderr, "Psymtab for %s already read in.  Shouldn't happen.\n",
+              pst->filename);
+      return;
+    }
+
+  /* Read in all partial symtabs on which this one is dependent */
+  for (i = 0; i < pst->number_of_dependencies; i++)
+    if (!pst->dependencies[i]->readin)
+      {
+       /* Inform about additional files that need to be read in.  */
+       if (info_verbose)
+         {
+           fputs_filtered (" ", gdb_stdout);
+           wrap_here ("");
+           fputs_filtered ("and ", gdb_stdout);
+           wrap_here ("");
+           printf_filtered ("%s...", pst->dependencies[i]->filename);
+           wrap_here ("");             /* Flush output */
+           gdb_flush (gdb_stdout);
+         }
+       os9k_psymtab_to_symtab_1 (pst->dependencies[i]);
+      }
+
+  if (LDSYMCNT(pst))           /* Otherwise it's a dummy */
+    {
+      /* Init stuff necessary for reading in symbols */
+      stabsread_init ();
+      buildsym_init ();
+      old_chain = make_cleanup (really_free_pendings, 0);
+
+      /* Read in this file's symbols */
+      os9k_read_ofile_symtab (pst);
+      sort_symtab_syms (pst->symtab);
+      do_cleanups (old_chain);
+    }
+
+  pst->readin = 1;
+}
+
+/* Read in all of the symbols for a given psymtab for real.
+   Be verbose about it if the user wants that.  */
+
+static void
+os9k_psymtab_to_symtab (pst)
+     struct partial_symtab *pst;
+{
+  bfd *sym_bfd;
+
+  if (!pst)
+    return;
+
+  if (pst->readin)
+    {
+      fprintf_unfiltered (gdb_stderr, "Psymtab for %s already read in.  Shouldn't happen.\n",
+              pst->filename);
+      return;
+    }
+
+  if (LDSYMCNT(pst) || pst->number_of_dependencies)
+    {
+      /* Print the message now, before reading the string table,
+        to avoid disconcerting pauses.  */
+      if (info_verbose)
+       {
+         printf_filtered ("Reading in symbols for %s...", pst->filename);
+         gdb_flush (gdb_stdout);
+       }
+
+      sym_bfd = pst->objfile->obfd;
+      os9k_psymtab_to_symtab_1 (pst);
+
+      /* Match with global symbols.  This only needs to be done once,
+         after all of the symtabs and dependencies have been read in.   */
+      scan_file_globals (pst->objfile);
+
+      /* Finish up the debug error message.  */
+      if (info_verbose)
+       printf_filtered ("done.\n");
+    }
+}
+
+/* Read in a defined section of a specific object file's symbols. */
+static void
+os9k_read_ofile_symtab (pst)
+     struct partial_symtab *pst;
+{
+  register struct internal_symstruct *bufp;
+  unsigned char type;
+  unsigned max_symnum;
+  register bfd *abfd;
+  struct objfile *objfile;
+  int sym_offset;              /* Offset to start of symbols to read */
+  CORE_ADDR text_offset;       /* Start of text segment for symbols */
+  int text_size;               /* Size of text segment for symbols */
+  struct section_offsets *section_offsets;
+  FILE *dbg_file;
+
+  objfile = pst->objfile;
+  sym_offset = LDSYMOFF(pst);
+  max_symnum = LDSYMCNT(pst);
+  text_offset = pst->textlow;
+  text_size = pst->texthigh - pst->textlow;
+  section_offsets = pst->section_offsets;
+
+  current_objfile = objfile;
+  subfile_stack = NULL;
+  last_source_file = NULL;
+
+  abfd = objfile->obfd;
+  dbg_file = objfile->auxf2;
+
+#if 0
+  /* It is necessary to actually read one symbol *before* the start
+     of this symtab's symbols, because the GCC_COMPILED_FLAG_SYMBOL
+     occurs before the N_SO symbol.
+     Detecting this in read_dbx_symtab
+     would slow down initial readin, so we look for it here instead. */
+  if (!processing_acc_compilation && sym_offset >= (int)symbol_size)
+    {
+      fseek (objefile->auxf2, sym_offset, SEEK_CUR);
+      fill_sym(objfile->auxf2, abfd);
+      bufp = symbuf;
+
+      processing_gcc_compilation = 0;
+      if (bufp->n_type == N_TEXT)
+       {
+         if (STREQ (namestring, GCC_COMPILED_FLAG_SYMBOL))
+           processing_gcc_compilation = 1;
+         else if (STREQ (namestring, GCC2_COMPILED_FLAG_SYMBOL))
+           processing_gcc_compilation = 2;
+       }
+
+      /* Try to select a C++ demangling based on the compilation unit
+        producer. */
+
+      if (processing_gcc_compilation)
+       {
+         if (AUTO_DEMANGLING)
+           {
+             set_demangling_style (GNU_DEMANGLING_STYLE_STRING);
+           }
+       }
+    }
+  else
+    {
+      /* The N_SO starting this symtab is the first symbol, so we
+        better not check the symbol before it.  I'm not this can
+        happen, but it doesn't hurt to check for it.  */
+      bfd_seek (symfile_bfd, sym_offset, SEEK_CUR);
+      processing_gcc_compilation = 0;
+    }
+#endif 0
+
+  fseek(dbg_file, (long)sym_offset, 0);
+/*
+  if (bufp->n_type != (unsigned char)N_SYM_SYM)
+    error("First symbol in segment of executable not a source symbol");
+*/
+
+  for (symnum = 0; symnum < max_symnum; symnum++)
+    {
+      QUIT;                    /* Allow this to be interruptable */
+      fill_sym(dbg_file, abfd);
+      bufp = symbuf;
+      type = bufp->n_type;
+
+      os9k_process_one_symbol (type, bufp->n_desc, bufp->n_value,
+             bufp->n_strx, section_offsets, objfile);
+
+      /* We skip checking for a new .o or -l file; that should never
+         happen in this routine. */
+#if 0
+      else if (type == N_TEXT)
+       {
+         /* I don't think this code will ever be executed, because
+            the GCC_COMPILED_FLAG_SYMBOL usually is right before
+            the N_SO symbol which starts this source file.
+            However, there is no reason not to accept
+            the GCC_COMPILED_FLAG_SYMBOL anywhere.  */
+
+         if (STREQ (namestring, GCC_COMPILED_FLAG_SYMBOL))
+           processing_gcc_compilation = 1;
+         else if (STREQ (namestring, GCC2_COMPILED_FLAG_SYMBOL))
+           processing_gcc_compilation = 2;
+
+         if (AUTO_DEMANGLING)
+           {
+             set_demangling_style (GNU_DEMANGLING_STYLE_STRING);
+           }
+       }
+      else if (type & N_EXT || type == (unsigned char)N_TEXT
+              || type == (unsigned char)N_NBTEXT
+              ) {
+         /* 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. */
+         ;
+        }
+#endif 0
+    }
+
+  current_objfile = NULL;
+
+  /* In a Solaris elf file, this variable, which comes from the
+     value of the N_SO symbol, will still be 0.  Luckily, text_offset,
+     which comes from pst->textlow is correct. */
+  if (last_source_start_addr == 0)
+    last_source_start_addr = text_offset;
+  pst->symtab = end_symtab (text_offset + text_size, 0, 0, objfile,
+                           SECT_OFF_TEXT);
+  end_stabs ();
+}
+
+\f
+/* This handles a single symbol from the symbol-file, building symbols
+   into a GDB symtab.  It takes these arguments and an implicit argument.
+
+   TYPE is the type field of the ".stab" symbol entry.
+   DESC is the desc field of the ".stab" entry.
+   VALU is the value field of the ".stab" entry.
+   NAME is the symbol name, in our address space.
+   SECTION_OFFSETS is a set of amounts by which the sections of this object
+          file were relocated when it was loaded into memory.
+          All symbols that refer
+         to memory locations need to be offset by these amounts.
+   OBJFILE is the object file from which we are reading symbols.
+              It is used in end_symtab.  */
+
+static void
+os9k_process_one_symbol (type, desc, valu, name, section_offsets, objfile)
+     int type, desc;
+     CORE_ADDR valu;
+     char *name;
+     struct section_offsets *section_offsets;
+     struct objfile *objfile;
+{
+  register struct context_stack *new;
+  /* The stab type used for the definition of the last function.
+     N_STSYM or N_GSYM for SunOS4 acc; N_FUN for other compilers.  */
+  static int function_stab_type = 0;
+
+#if 0
+  /* Something is wrong if we see real data before
+     seeing a source file name.  */
+  if (last_source_file == NULL && type != (unsigned char)N_SO)
+    {
+      /* Ignore any symbols which appear before an N_SO symbol.  Currently
+        no one puts symbols there, but we should deal gracefully with the
+        case.  A complain()t might be in order (if !IGNORE_SYMBOL (type)),
+        but this should not be an error ().  */
+      return;
+    }
+#endif 0
+
+  switch (type)
+    {
+    case N_SYM_LBRAC:
+      /* On most machines, the block addresses are relative to the
+        N_SO, the linker did not relocate them (sigh).  */
+      valu += last_source_start_addr;
+      new = push_context (desc, valu);
+      break;
+
+    case N_SYM_RBRAC:
+      valu += last_source_start_addr;
+      new = pop_context();
+
+#if !defined (VARIABLES_INSIDE_BLOCK)
+#define VARIABLES_INSIDE_BLOCK(desc, gcc_p) 1
+#endif
+
+      if (!VARIABLES_INSIDE_BLOCK(desc, processing_gcc_compilation))
+       local_symbols = new->locals;
+
+      if (context_stack_depth > 1)
+       {
+         /* 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.  Define the block for them (but don't
+            bother if the block contains no symbols.  Should we complain
+            on blocks without symbols?  I can't think of any useful purpose
+            for them).  */
+         if (local_symbols != NULL)
+           {
+             /* Muzzle a compiler bug that makes end < start.  (which
+                compilers?  Is this ever harmful?).  */
+             if (new->start_addr > valu)
+               {
+                 complain (&lbrac_rbrac_complaint);
+                 new->start_addr = valu;
+               }
+             /* Make a block for the local symbols within.  */
+             finish_block (0, &local_symbols, new->old_blocks,
+                           new->start_addr, valu, objfile);
+           }
+       }
+      else
+       {
+         if (context_stack_depth == 0)
+           {
+             within_function = 0;
+             /* Make a block for the local symbols within.  */
+             finish_block (new->name, &local_symbols, new->old_blocks,
+                       new->start_addr, valu, objfile);
+           }
+         else
+           {
+             /* attach local_symbols to the end of new->locals */
+             if (!new->locals) new->locals = local_symbols;
+             else {
+               struct pending *p;
+
+               p = new->locals;
+               while (p->next) p = p->next; 
+               p->next = local_symbols;
+             }
+           }
+       }
+
+      if (VARIABLES_INSIDE_BLOCK(desc, processing_gcc_compilation))
+       /* Now pop locals of block just finished.  */
+       local_symbols = new->locals;
+      break;
+
+
+    case N_SYM_SLINE:
+      /* This type of "symbol" really just records
+        one line-number -- core-address correspondence.
+        Enter it in the line list for this symbol table.  */
+      /* Relocate for dynamic loading and for ELF acc fn-relative syms.  */
+      valu += last_source_start_addr;
+      record_line (current_subfile, (int)name, valu);
+      break;
+
+    /* The following symbol types need to have the appropriate offset added
+       to their value; then we process symbol definitions in the name.  */
+    case N_SYM_SYM:
+
+      if (name)
+       {
+         char deftype;
+         char *dirn, *n;
+         char *p = strchr (name, ':');
+         if (p == NULL)
+           deftype = '\0';
+         else
+           deftype = p[1];
+
+
+         switch (deftype)
+           {
+           case 'S':
+             valu += ANOFFSET (section_offsets, SECT_OFF_TEXT);
+             n = strrchr(name, '/');
+             if (n != NULL) {
+               *n = '\0';
+               n++;
+               dirn = name;
+             } else {
+               n = name;
+               dirn = NULL;
+             }
+             *p = '\0';
+             if (symfile_depth++ == 0) {
+               if (last_source_file) {
+                 end_symtab (valu, 0, 0, objfile, SECT_OFF_TEXT);
+                 end_stabs ();
+               }
+               start_stabs ();
+               start_symtab (n, dirn, valu);
+             } else {
+               push_subfile();
+               start_subfile (n, dirn!=NULL ? dirn : current_subfile->dirname);
+             }
+             break;
+
+           case 'f':
+           case 'F':
+              valu += ANOFFSET (section_offsets, SECT_OFF_TEXT);
+             function_stab_type = type;
+
+             within_function = 1;
+             new = push_context (0, valu);
+             new->name = os9k_define_symbol (valu, name, desc, type, objfile);
+             break;
+
+           case 'V':
+           case 'v':
+              valu += ANOFFSET (section_offsets, SECT_OFF_DATA);
+             os9k_define_symbol (valu, name, desc, type, objfile);
+             break;
+
+           default:
+             os9k_define_symbol (valu, name, desc, type, objfile);
+             break;
+           }
+       }
+      break;
+
+    case N_SYM_SE:
+       if (--symfile_depth != 0)
+         start_subfile(pop_subfile(), current_subfile->dirname);
+      break;
+
+    default:
+      complain (&unknown_symtype_complaint,
+               local_hex_string((unsigned long) type));
+      /* FALLTHROUGH */
+      break;
+
+    case N_SYM_CMPLR:
+      break;
+    }
+  previous_stab_code = type;
+}
+\f
+/* Parse the user's idea of an offset for dynamic linking, into our idea
+   of how to represent it for fast symbol reading.  */
+
+static struct section_offsets *
+os9k_symfile_offsets (objfile, addr)
+     struct objfile *objfile;
+     CORE_ADDR addr;
+{
+  struct section_offsets *section_offsets;
+  int i;
+
+  objfile->num_sections = SECT_OFF_MAX;
+  section_offsets = (struct section_offsets *)
+    obstack_alloc (&objfile -> psymbol_obstack,
+                  sizeof (struct section_offsets)
+                  + sizeof (section_offsets->offsets) * (SECT_OFF_MAX-1));
+
+  for (i = 0; i < SECT_OFF_MAX; i++)
+    ANOFFSET (section_offsets, i) = addr;
+  
+  return section_offsets;
+}
+\f
+static struct sym_fns os9k_sym_fns =
+{
+  bfd_target_os9k_flavour,
+  os9k_new_init,       /* sym_new_init: init anything gbl to entire symtab */
+  os9k_symfile_init,   /* sym_init: read initial info, setup for sym_read() */
+  os9k_symfile_read,   /* sym_read: read a symbol file into symtab */
+  os9k_symfile_finish, /* sym_finish: finished with file, cleanup */
+  os9k_symfile_offsets,        /* sym_offsets: parse user's offsets to internal form*/
+  NULL                 /* next: pointer to next struct sym_fns */
+};
+
+void
+_initialize_os9kread ()
+{
+  add_symtab_fns(&os9k_sym_fns);
+}
diff --git a/gdb/os9kstab.c b/gdb/os9kstab.c
new file mode 100644 (file)
index 0000000..828ac8f
--- /dev/null
@@ -0,0 +1,2024 @@
+/* Support routines for decoding "stabs" debugging information format.
+   Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993
+             Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* Support routines for reading and decoding debugging information in
+   the "stabs" format.  This format is used with many systems that use
+   the a.out object file format, as well as some systems that use
+   COFF or ELF where the stabs data is placed in a special section.
+   Avoid placing any object file format specific code in this file. */
+
+#include "defs.h"
+#include "bfd.h"
+#include "obstack.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "aout/stab_gnu.h"     /* We always use GNU stabs, not native */
+#include "buildsym.h"
+#include "complaints.h"
+#include "demangle.h"
+
+#include <ctype.h>
+
+/* Ask stabsread.h to define the vars it normally declares `extern'.  */
+#define EXTERN  /**/
+#include "stabsread.h"          /* Our own declarations */
+#undef  EXTERN
+
+/* The routines that read and process a complete stabs for a C struct or 
+   C++ class pass lists of data member fields and lists of member function
+   fields in an instance of a field_info structure, as defined below.
+   This is part of some reorganization of low level C++ support and is
+   expected to eventually go away... (FIXME) */
+
+struct field_info
+{
+  struct nextfield
+    {
+      struct nextfield *next;
+
+      /* This is the raw visibility from the stab.  It is not checked
+        for being one of the visibilities we recognize, so code which
+        examines this field better be able to deal.  */
+      int visibility;
+
+      struct field field;
+    } *list;
+  struct next_fnfieldlist
+    {
+      struct next_fnfieldlist *next;
+      struct fn_fieldlist fn_fieldlist;
+    } *fnlist;
+};
+
+static struct type *
+dbx_alloc_type PARAMS ((int [2], struct objfile *));
+
+static long read_huge_number PARAMS ((char **, int, int *));
+
+static struct type *error_type PARAMS ((char **));
+
+static int
+read_type_number PARAMS ((char **, int *));
+
+static struct type *
+read_range_type PARAMS ((char **, int [2], struct objfile *));
+
+static struct type *
+os9k_read_type PARAMS ((char **, struct objfile *));
+
+static struct type *
+os9k_read_enum_type PARAMS ((char **, struct type *, struct objfile *));
+
+static int
+read_struct_fields PARAMS ((struct field_info *, char **, struct type *,
+                           struct objfile *));
+
+static int
+attach_fields_to_type PARAMS ((struct field_info *, struct type *,
+                              struct objfile *));
+
+static struct type *
+os9k_read_array_type PARAMS ((char **, struct type *, struct objfile *));
+
+extern struct complaint error_type_complaint;
+extern struct complaint stabs_general_complaint;
+extern struct complaint range_type_base_complaint;
+extern struct complaint reg_value_complaint;
+
+/* Define this as 1 if a pcc declaration of a char or short argument
+   gives the correct address.  Otherwise assume pcc gives the
+   address of the corresponding int, which is not the same on a
+   big-endian machine.  */
+
+#ifndef BELIEVE_PCC_PROMOTION
+#define BELIEVE_PCC_PROMOTION 0
+#endif
+
+/* Make a list of forward references which haven't been defined.  */
+
+static struct type **undef_types;
+static int undef_types_allocated;
+static int undef_types_length;
+
+/* Check for and handle cretinous stabs symbol name continuation!  */
+#define STABS_CONTINUE(pp)                             \
+  do {                                                 \
+    if (**(pp) == '\\') *(pp) = next_symbol_text ();   \
+  } while (0)
+
+\f
+static struct type **init_type_vector[] = {
+       0,
+       &builtin_type_int,
+       &builtin_type_char,
+       &builtin_type_long,
+       &builtin_type_short,
+       &builtin_type_unsigned_char,
+       &builtin_type_unsigned_short,
+       &builtin_type_unsigned_long,
+       &builtin_type_unsigned_int,
+       &builtin_type_float,
+       &builtin_type_double,
+       &builtin_type_void,
+       &builtin_type_long_double
+};
+
+static void
+os9k_init_type_vector(tv)
+    struct type **tv;
+{
+  int i;
+  for (i=0; i<sizeof(init_type_vector)/sizeof(struct type **); i++)
+    tv[i] = (init_type_vector[i] == 0 ? 0 : *(init_type_vector[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];
+  register int index = typenums[1];
+  unsigned old_len;
+  register int real_filenum;
+  register struct header_file *f;
+  int f_orig_length;
+
+  if (filenum == -1)           /* -1,-1 is for temporary types.  */
+    return 0;
+
+  if (filenum < 0 || filenum >= n_this_object_header_files)
+    {
+      static struct complaint msg = {"\
+Invalid symbol data: type number (%d,%d) out of range at symtab pos %d.",
+                               0, 0};
+      complain (&msg, filenum, index, symnum);
+      goto error_return;
+    }
+
+  if (filenum == 0)
+    {
+      /* Type is defined outside of header files.
+        Find it in this object file's type vector.  */
+      if (index >= type_vector_length)
+       {
+         old_len = type_vector_length;
+         if (old_len == 0)
+           {
+             type_vector_length = INITIAL_TYPE_VECTOR_LENGTH;
+             type_vector = (struct type **)
+               malloc (type_vector_length * sizeof (struct type *));
+           }
+         while (index >= type_vector_length)
+           {
+             type_vector_length *= 2;
+           }
+         type_vector = (struct type **)
+           xrealloc ((char *) type_vector,
+                     (type_vector_length * sizeof (struct type *)));
+         memset (&type_vector[old_len], 0,
+                 (type_vector_length - old_len) * sizeof (struct type *));
+         os9k_init_type_vector(type_vector);
+       }
+      return (&type_vector[index]);
+    }
+  else
+    {
+      real_filenum = this_object_header_files[filenum];
+
+      if (real_filenum >= n_header_files)
+       {
+         struct type *temp_type;
+         struct type **temp_type_p;
+
+         warning ("GDB internal error: bad real_filenum");
+
+       error_return:
+         temp_type = init_type (TYPE_CODE_ERROR, 0, 0, NULL, NULL);
+         temp_type_p = (struct type **) xmalloc (sizeof (struct type *));
+         *temp_type_p = temp_type;
+         return temp_type_p;
+       }
+
+      f = &header_files[real_filenum];
+
+      f_orig_length = f->length;
+      if (index >= f_orig_length)
+       {
+         while (index >= f->length)
+           {
+             f->length *= 2;
+           }
+         f->vector = (struct type **)
+           xrealloc ((char *) f->vector, f->length * sizeof (struct type *));
+         memset (&f->vector[f_orig_length], 0,
+                 (f->length - f_orig_length) * sizeof (struct type *));
+       }
+      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.
+   TYPENUMS may be (-1, -1) to return a new type object that is not
+   put into the type vector, and so may not be referred to by number. */
+
+static struct type *
+dbx_alloc_type (typenums, objfile)
+     int typenums[2];
+     struct objfile *objfile;
+{
+  register struct type **type_addr;
+
+  if (typenums[0] == -1)
+    {
+      return (alloc_type (objfile));
+    }
+
+  type_addr = dbx_lookup_type (typenums);
+
+  /* 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_addr == 0)
+    {
+      *type_addr = alloc_type (objfile);
+    }
+
+  return (*type_addr);
+}
+
+\f
+/* 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.
+
+   Returns 0 for success, -1 for error.  */
+
+static int
+read_type_number (pp, typenums)
+     register char **pp;
+     register int *typenums;
+{
+  int nbits;
+  if (**pp == '(')
+    {
+      (*pp)++;
+      typenums[0] = read_huge_number (pp, ',', &nbits);
+      if (nbits != 0) return -1;
+      typenums[1] = read_huge_number (pp, ')', &nbits);
+      if (nbits != 0) return -1;
+    }
+  else
+    {
+      typenums[0] = 0;
+      typenums[1] = read_huge_number (pp, 0, &nbits);
+      if (nbits != 0) return -1;
+    }
+  return 0;
+}
+
+\f
+/* Skip rest of this symbol and return an error type.
+
+   General notes on error recovery:  error_type always skips to the
+   end of the symbol (modulo cretinous dbx symbol name continuation).
+   Thus code like this:
+
+   if (*(*pp)++ != ';')
+     return error_type (pp);
+
+   is wrong because if *pp starts out pointing at '\0' (typically as the
+   result of an earlier error), it will be incremented to point to the
+   start of the next symbol, which might produce strange results, at least
+   if you run off the end of the string table.  Instead use
+
+   if (**pp != ';')
+     return error_type (pp);
+   ++*pp;
+
+   or
+
+   if (**pp != ';')
+     foo = error_type (pp);
+   else
+     ++*pp;
+
+   And in case it isn't obvious, the point of all this hair is so the compiler
+   can define new types and new syntaxes, and old versions of the
+   debugger will be able to read the new symbol tables.  */
+
+static struct type *
+error_type (pp)
+     char **pp;
+{
+  complain (&error_type_complaint);
+  while (1)
+    {
+      /* Skip to end of symbol.  */
+      while (**pp != '\0')
+       {
+         (*pp)++;
+       }
+
+      /* Check for and handle cretinous dbx symbol name continuation!  */
+      if ((*pp)[-1] == '\\')
+       {
+         *pp = next_symbol_text ();
+       }
+      else
+       {
+         break;
+       }
+    }
+  return (builtin_type_error);
+}
+
+/* This page contains subroutines of read_type.  */
+
+#define VISIBILITY_PRIVATE      '0'     /* Stabs character for private field */
+#define VISIBILITY_PROTECTED    '1'     /* Stabs character for protected fld */
+#define VISIBILITY_PUBLIC       '2'     /* Stabs character for public field */
+#define VISIBILITY_IGNORE       '9'     /* Optimized out or zero length */
+
+static void
+read_one_struct_field (fip, pp, p, type, objfile)
+     struct field_info *fip;
+     char **pp;
+     char *p;
+     struct type *type;
+     struct objfile *objfile;
+{
+  fip -> list -> field.name =
+    obsavestring (*pp, p - *pp, &objfile -> type_obstack);
+  *pp = p + 1;
+
+  fip -> list -> visibility = VISIBILITY_PUBLIC;
+  fip -> list -> field.type = os9k_read_type (pp, objfile);
+  if (**pp == ':')
+    {
+      p = ++(*pp);
+#if 0
+      /* Possible future hook for nested types. */
+      if (**pp == '!')
+       {
+         fip -> list -> field.bitpos = (long)-2; /* nested type */
+         p = ++(*pp);
+       }
+      else
+#endif
+       {
+         /* Static class member.  */
+         fip -> list -> field.bitpos = (long) -1;
+       }
+      while (*p != ';') 
+       {
+         p++;
+       }
+      fip -> list -> field.bitsize = (long) savestring (*pp, p - *pp);
+      *pp = p + 1;
+      return;
+    }
+  else if (**pp != ',')
+    {
+      /* Bad structure-type format.  */
+      complain (&stabs_general_complaint, "bad structure-type format");
+      return;
+    }
+
+  (*pp)++;                     /* Skip the comma.  */
+
+  {
+    int nbits;
+    fip -> list -> field.bitpos = read_huge_number (pp, ',', &nbits);
+    if (nbits != 0)
+      {
+       complain (&stabs_general_complaint, "bad structure-type format");
+       return;
+      }
+    fip -> list -> field.bitsize = read_huge_number (pp, ';', &nbits);
+    if (nbits != 0)
+      {
+       complain (&stabs_general_complaint, "bad structure-type format");
+       return;
+      }
+  }
+
+  if (fip -> list -> field.bitpos == 0 && fip -> list -> field.bitsize == 0)
+    {
+      /* This can happen in two cases: (1) at least for gcc 2.4.5 or so,
+        it is a field which has been optimized out.  The correct stab for
+        this case is to use VISIBILITY_IGNORE, but that is a recent
+        invention.  (2) It is a 0-size array.  For example
+        union { int num; char str[0]; } foo.  Printing "<no value>" for
+        str in "p foo" is OK, since foo.str (and thus foo.str[3])
+        will continue to work, and a 0-size array as a whole doesn't
+        have any contents to print.
+
+        I suspect this probably could also happen with gcc -gstabs (not
+        -gstabs+) for static fields, and perhaps other C++ extensions.
+        Hopefully few people use -gstabs with gdb, since it is intended
+        for dbx compatibility.  */
+
+      /* Ignore this field.  */
+      fip -> list-> visibility = VISIBILITY_IGNORE;
+    }
+  else
+    {
+      /* 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 (fip -> list -> field.type) != TYPE_CODE_INT
+         && TYPE_CODE (fip -> list -> field.type) != TYPE_CODE_ENUM)
+       {
+         fip -> list -> field.bitsize = 0;
+       }
+      if ((fip -> list -> field.bitsize 
+          == TARGET_CHAR_BIT * TYPE_LENGTH (fip -> list -> field.type)
+          || (TYPE_CODE (fip -> list -> field.type) == TYPE_CODE_ENUM
+              && (fip -> list -> field.bitsize
+                  == TARGET_INT_BIT)
+              )
+          )
+         &&
+         fip -> list -> field.bitpos % 8 == 0)
+       {
+         fip -> list -> field.bitsize = 0;
+       }
+    }
+}
+
+
+/* Read struct or class data fields.  They have the form:
+
+       NAME : [VISIBILITY] TYPENUM , BITPOS , BITSIZE ;
+
+   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 optional VISIBILITY is one of:
+
+       '/0'    (VISIBILITY_PRIVATE)
+       '/1'    (VISIBILITY_PROTECTED)
+       '/2'    (VISIBILITY_PUBLIC)
+       '/9'    (VISIBILITY_IGNORE)
+
+   or nothing, for C style fields with public visibility.
+
+   Returns 1 for success, 0 for failure.  */
+
+static int
+read_struct_fields (fip, pp, type, objfile)
+     struct field_info *fip;
+     char **pp;
+     struct type *type;
+     struct objfile *objfile;
+{
+  register char *p;
+  struct nextfield *new;
+
+  /* We better set p right now, in case there are no fields at all...    */
+
+  p = *pp;
+
+  /* Read each data member type until we find the terminating ';' at the end of
+     the data member list, or break for some other reason such as finding the
+     start of the member function list. */
+
+  while (**pp != ';' && **pp != '\0')
+    {
+      STABS_CONTINUE (pp);
+      /* Get space to record the next field's data.  */
+      new = (struct nextfield *) xmalloc (sizeof (struct nextfield));
+      make_cleanup (free, new);
+      memset (new, 0, sizeof (struct nextfield));
+      new -> next = fip -> list;
+      fip -> list = new;
+
+      /* Get the field name.  */
+      p = *pp;
+
+      /* Look for the ':' that separates the field name from the field
+        values.  Data members are delimited by a single ':', while member
+        functions are delimited by a pair of ':'s.  When we hit the member
+        functions (if any), terminate scan loop and return. */
+
+      while (*p != ':' && *p != '\0') 
+       {
+         p++;
+       }
+      if (*p == '\0')
+       return 0;
+
+      /* Check to see if we have hit the member functions yet.  */
+      if (p[1] == ':')
+       {
+         break;
+       }
+      read_one_struct_field (fip, pp, p, type, objfile);
+    }
+  if (p[0] == ':' && p[1] == ':')
+    {
+      /* chill the list of fields: the last entry (at the head) is a
+        partially constructed entry which we now scrub. */
+      fip -> list = fip -> list -> next;
+    }
+  return 1;
+}
+
+/* Create the vector of fields, and record how big it is.
+   We need this info to record proper virtual function table information
+   for this class's virtual functions.  */
+
+static int
+attach_fields_to_type (fip, type, objfile)
+     struct field_info *fip;
+     register struct type *type;
+     struct objfile *objfile;
+{
+  register int nfields = 0;
+  register int non_public_fields = 0;
+  register struct nextfield *scan;
+
+  /* Count up the number of fields that we have, as well as taking note of
+     whether or not there are any non-public fields, which requires us to
+     allocate and build the private_field_bits and protected_field_bits
+     bitfields. */
+
+  for (scan = fip -> list; scan != NULL; scan = scan -> next)
+    {
+      nfields++;
+      if (scan -> visibility != VISIBILITY_PUBLIC)
+       {
+         non_public_fields++;
+       }
+    }
+
+  /* Now we know how many fields there are, and whether or not there are any
+     non-public fields.  Record the field count, allocate space for the
+     array of fields, and create blank visibility bitfields if necessary. */
+
+  TYPE_NFIELDS (type) = nfields;
+  TYPE_FIELDS (type) = (struct field *)
+    TYPE_ALLOC (type, sizeof (struct field) * nfields);
+  memset (TYPE_FIELDS (type), 0, sizeof (struct field) * nfields);
+
+  /* Copy the saved-up fields into the field vector.  Start from the head
+     of the list, adding to the tail of the field array, so that they end
+     up in the same order in the array in which they were added to the list. */
+
+  while (nfields-- > 0)
+    {
+      TYPE_FIELD (type, nfields) = fip -> list -> field;
+      fip -> list = fip -> list -> next;
+    }
+  return 1;
+}
+
+/* Read the description of a structure (or union type) and return an object
+   describing the type.
+
+   PP points to a character pointer that points to the next unconsumed token
+   in the the stabs string.  For example, given stabs "A:T4=s4a:1,0,32;;",
+   *PP will point to "4a:1,0,32;;".
+
+   TYPE points to an incomplete type that needs to be filled in.
+
+   OBJFILE points to the current objfile from which the stabs information is
+   being read.  (Note that it is redundant in that TYPE also contains a pointer
+   to this same objfile, so it might be a good idea to eliminate it.  FIXME). 
+   */
+
+static struct type *
+read_struct_type (pp, type, objfile)
+     char **pp;
+     struct type *type;
+     struct objfile *objfile;
+{
+  struct cleanup *back_to;
+  struct field_info fi;
+
+  fi.list = NULL;
+  fi.fnlist = NULL;
+
+  back_to = make_cleanup (null_cleanup, 0);
+
+  INIT_CPLUS_SPECIFIC (type);
+  TYPE_FLAGS (type) &= ~TYPE_FLAG_STUB;
+
+  /* First comes the total size in bytes.  */
+
+  {
+    int nbits;
+    TYPE_LENGTH (type) = read_huge_number (pp, 0, &nbits);
+    if (nbits != 0)
+      return error_type (pp);
+  }
+
+  /* Now read the baseclasses, if any, read the regular C struct or C++
+     class member fields, attach the fields to the type, read the C++
+     member functions, attach them to the type, and then read any tilde
+     field (baseclass specifier for the class holding the main vtable). */
+
+  if (!read_struct_fields (&fi, pp, type, objfile)
+      || !attach_fields_to_type (&fi, type, objfile)
+     )
+    {
+      do_cleanups (back_to);
+      return (error_type (pp));
+    }
+
+  do_cleanups (back_to);
+  return (type);
+}
+
+static long
+read_huge_number (pp, end, bits)
+     char **pp;
+     int end;
+     int *bits;
+{
+  char *p = *pp;
+  int sign = 1;
+  long n = 0;
+  int radix = 10;
+  char overflow = 0;
+  int nbits = 0;
+  int c;
+  long upper_limit;
+  
+  if (*p == '-')
+    {
+      sign = -1;
+      p++;
+    }
+
+  /* Leading zero means octal.  GCC uses this to output values larger
+     than an int (because that would be hard in decimal).  */
+  if (*p == '0')
+    {
+      radix = 8;
+      p++;
+    }
+
+  upper_limit = LONG_MAX / radix;
+  while ((c = *p++) >= '0' && c < ('0' + radix))
+    {
+      if (n <= upper_limit)
+       {
+         n *= radix;
+         n += c - '0';         /* FIXME this overflows anyway */
+       }
+      else
+       overflow = 1;
+      
+      /* This depends on large values being output in octal, which is
+        what GCC does. */
+      if (radix == 8)
+       {
+         if (nbits == 0)
+           {
+             if (c == '0')
+               /* Ignore leading zeroes.  */
+               ;
+             else if (c == '1')
+               nbits = 1;
+             else if (c == '2' || c == '3')
+               nbits = 2;
+             else
+               nbits = 3;
+           }
+         else
+           nbits += 3;
+       }
+    }
+  if (end)
+    {
+      if (c && c != end)
+       {
+         if (bits != NULL)
+           *bits = -1;
+         return 0;
+       }
+    }
+  else
+    --p;
+
+  *pp = p;
+  if (overflow)
+    {
+      if (nbits == 0)
+       {
+         /* Large decimal constants are an error (because it is hard to
+            count how many bits are in them).  */
+         if (bits != NULL)
+           *bits = -1;
+         return 0;
+       }
+      
+      /* -0x7f is the same as 0x80.  So deal with it by adding one to
+        the number of bits.  */
+      if (sign == -1)
+       ++nbits;
+      if (bits)
+       *bits = nbits;
+    }
+  else
+    {
+      if (bits)
+       *bits = 0;
+      return n * sign;
+    }
+  /* It's *BITS which has the interesting information.  */
+  return 0;
+}
+
+static struct type *
+read_range_type (pp, typenums, objfile)
+     char **pp;
+     int typenums[2];
+     struct objfile *objfile;
+{
+  int rangenums[2];
+  long n2, n3;
+  int n2bits, n3bits;
+  int self_subrange;
+  struct type *result_type;
+  struct type *index_type;
+
+  /* First comes a type we are a subrange of.
+     In C it is usually 0, 1 or the type being defined.  */
+  /* FIXME: according to stabs.texinfo and AIX doc, this can be a type-id
+     not just a type number.  */
+  if (read_type_number (pp, rangenums) != 0)
+    return error_type (pp);
+  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_huge_number (pp, ';', &n2bits);
+  n3 = read_huge_number (pp, ';', &n3bits);
+
+  if (n2bits == -1 || n3bits == -1)
+    return error_type (pp);
+  
+  /* If limits are huge, must be large integral type.  */
+  if (n2bits != 0 || n3bits != 0)
+    {
+      char got_signed = 0;
+      char got_unsigned = 0;
+      /* Number of bits in the type.  */
+      int nbits = 0;
+
+      /* Range from 0 to <large number> is an unsigned large integral type.  */
+      if ((n2bits == 0 && n2 == 0) && n3bits != 0)
+       {
+         got_unsigned = 1;
+         nbits = n3bits;
+       }
+      /* Range from <large number> to <large number>-1 is a large signed
+        integral type.  Take care of the case where <large number> doesn't
+        fit in a long but <large number>-1 does.  */
+      else if ((n2bits != 0 && n3bits != 0 && n2bits == n3bits + 1)
+              || (n2bits != 0 && n3bits == 0
+                  && (n2bits == sizeof (long) * HOST_CHAR_BIT)
+                  && n3 == LONG_MAX))
+       {
+         got_signed = 1;
+         nbits = n2bits;
+       }
+
+      if (got_signed || got_unsigned)
+       {
+         return init_type (TYPE_CODE_INT, nbits / TARGET_CHAR_BIT,
+                           got_unsigned ? TYPE_FLAG_UNSIGNED : 0, NULL,
+                           objfile);
+       }
+      else
+       return error_type (pp);
+    }
+
+  /* A type defined as a subrange of itself, with bounds both 0, is void.  */
+  if (self_subrange && n2 == 0 && n3 == 0)
+    return init_type (TYPE_CODE_VOID, 0, 0, NULL, objfile);
+
+  /* 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!
+
+     GDB does not have complex types.
+
+     Just return the complex as a float of that size.  It won't work right
+     for the complex values, but at least it makes the file loadable.  */
+
+  if (n3 == 0 && n2 > 0)
+    {
+      return init_type (TYPE_CODE_FLT, n2, 0, NULL, objfile);
+    }
+
+  /* If the upper bound is -1, it must really be an unsigned int.  */
+
+  else if (n2 == 0 && n3 == -1)
+    {
+      /* It is unsigned int or unsigned long.  */
+      /* GCC 2.3.3 uses this for long long too, but that is just a GDB 3.5
+        compatibility hack.  */
+      return init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT,
+                       TYPE_FLAG_UNSIGNED, NULL, objfile);
+    }
+
+  /* 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 init_type (TYPE_CODE_INT, 1, 0, NULL, objfile);
+
+  /* We used to do this only for subrange of self or subrange of int.  */
+  else if (n2 == 0)
+    {
+      if (n3 < 0)
+       /* n3 actually gives the size.  */
+       return init_type (TYPE_CODE_INT, - n3, TYPE_FLAG_UNSIGNED,
+                         NULL, objfile);
+      if (n3 == 0xff)
+       return init_type (TYPE_CODE_INT, 1, TYPE_FLAG_UNSIGNED, NULL, objfile);
+      if (n3 == 0xffff)
+       return init_type (TYPE_CODE_INT, 2, TYPE_FLAG_UNSIGNED, NULL, objfile);
+
+      /* -1 is used for the upper bound of (4 byte) "unsigned int" and
+        "unsigned long", and we already checked for that,
+        so don't need to test for it here.  */
+    }
+  /* I think this is for Convex "long long".  Since I don't know whether
+     Convex sets self_subrange, I also accept that particular size regardless
+     of self_subrange.  */
+  else if (n3 == 0 && n2 < 0
+          && (self_subrange
+              || n2 == - TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT))
+    return init_type (TYPE_CODE_INT, - n2, 0, NULL, objfile);
+  else if (n2 == -n3 -1)
+    {
+      if (n3 == 0x7f)
+       return init_type (TYPE_CODE_INT, 1, 0, NULL, objfile);
+      if (n3 == 0x7fff)
+       return init_type (TYPE_CODE_INT, 2, 0, NULL, objfile);
+      if (n3 == 0x7fffffff)
+       return init_type (TYPE_CODE_INT, 4, 0, NULL, objfile);
+    }
+
+  /* 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)
+    return error_type (pp);
+
+  index_type = *dbx_lookup_type (rangenums);
+  if (index_type == NULL)
+    {
+      /* Does this actually ever happen?  Is that why we are worrying
+         about dealing with it rather than just calling error_type?  */
+
+      static struct type *range_type_index;
+
+      complain (&range_type_base_complaint, rangenums[1]);
+      if (range_type_index == NULL)
+       range_type_index =
+         init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT,
+                    0, "range type index type", NULL);
+      index_type = range_type_index;
+    }
+
+  result_type = create_range_type ((struct type *) NULL, index_type, n2, n3);
+  return (result_type);
+}
+
+#if !defined (REG_STRUCT_HAS_ADDR)
+#define REG_STRUCT_HAS_ADDR(gcc_p) 0
+#endif
+
+static char *type_synonym_name = NULL;
+
+struct symbol *
+os9k_define_symbol (valu, string, desc, type, objfile)
+     CORE_ADDR valu;
+     char *string;
+     int desc;
+     int type;
+     struct objfile *objfile;
+{
+  register struct symbol *sym;
+  char *p = (char *) strchr (string, ':');
+  int deftype;
+  int synonym = 0;
+  register int i;
+
+  /* We would like to eliminate nameless symbols, but keep their types.
+     E.g. stab entry ":t10=*2" should produce a type 10, which is a pointer
+     to type 2, but, should not create a symbol to address that type. Since
+     the symbol will be nameless, there is no way any user can refer to it. */
+
+  int nameless;
+
+  /* Ignore syms with empty names.  */
+  if (string[0] == 0)
+    return 0;
+
+  /* Ignore old-style symbols from cc -go  */
+  if (p == 0)
+    return 0;
+
+  while (p[1] == ':')
+    {
+       p += 2;
+       p = strchr(p, ':');
+    }
+
+  /* If a nameless stab entry, all we need is the type, not the symbol.
+     e.g. ":t10=*2" or a nameless enum like " :T16=ered:0,green:1,blue:2,;" */
+  nameless = (p == string || ((string[0] == ' ') && (string[1] == ':')));
+
+  sym = (struct symbol *) 
+    obstack_alloc (&objfile -> symbol_obstack, sizeof (struct symbol));
+  memset (sym, 0, sizeof (struct symbol));
+
+  if (processing_gcc_compilation)
+    {
+      /* GCC 2.x puts the line number in desc.  SunOS apparently puts in the
+        number of bytes occupied by a type or object, which we ignore.  */
+      SYMBOL_LINE(sym) = desc;
+    }
+  else
+    {
+      SYMBOL_LINE(sym) = 0;                    /* unknown */
+    }
+
+  {
+      SYMBOL_LANGUAGE (sym) = current_subfile -> language;
+      SYMBOL_NAME (sym)        = (char *)
+       obstack_alloc (&objfile -> symbol_obstack, ((p - string) + 1));
+      /* Open-coded memcpy--saves function call time.  */
+      /* FIXME:  Does it really?  Try replacing with simple strcpy and
+        try it on an executable with a large symbol table. */
+      /* FIXME: considering that gcc can open code memcpy anyway, I
+        doubt it.  xoxorich. */
+      {
+       register char *p1 = string;
+       register char *p2 = SYMBOL_NAME (sym);
+       while (p1 != p)
+         {
+           *p2++ = *p1++;
+         }
+       *p2++ = '\0';
+      }
+
+      /* If this symbol is from a C++ compilation, then attempt to cache the
+        demangled form for future reference.  This is a typical time versus
+        space tradeoff, that was decided in favor of time because it sped up
+        C++ symbol lookups by a factor of about 20. */
+
+      SYMBOL_INIT_DEMANGLED_NAME (sym, &objfile->symbol_obstack);
+  }
+  p++;
+
+  /* Determine the type of name being defined.  */
+#if 0
+  /* Getting GDB to correctly skip the symbol on an undefined symbol
+     descriptor and not ever dump core is a very dodgy proposition if
+     we do things this way.  I say the acorn RISC machine can just
+     fix their compiler.  */
+  /* The Acorn RISC machine's compiler can put out locals that don't
+     start with "234=" or "(3,4)=", so assume anything other than the
+     deftypes we know how to handle is a local.  */
+  if (!strchr ("cfFGpPrStTvVXCR", *p))
+#else
+  if (isdigit (*p) || *p == '(' || *p == '-')
+#endif
+    deftype = 'l';
+  else
+    deftype = *p++;
+
+  switch (deftype)
+    {
+    case 'c':
+      /* 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.
+        SYMBOL:c=eTYPE,INTVALUE for an enum constant symbol.
+        e.g. "b:c=e6,0" for "const b = blob1"
+        (where type 6 is defined by "blobs:t6=eblob1:0,blob2:1,;").  */
+      if (*p != '=')
+       {
+         SYMBOL_CLASS (sym) = LOC_CONST;
+         SYMBOL_TYPE (sym) = error_type (&p);
+         SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+         add_symbol_to_list (sym, &file_symbols);
+         return sym;
+       }
+      ++p;
+      switch (*p++)
+       {
+       case 'r':
+         {
+           double d = atof (p);
+           char *dbl_valu;
+
+           /* FIXME-if-picky-about-floating-accuracy: Should be using
+              target arithmetic to get the value.  real.c in GCC
+              probably has the necessary code.  */
+
+           /* FIXME: lookup_fundamental_type is a hack.  We should be
+              creating a type especially for the type of float constants.
+              Problem is, what type should it be?
+
+              Also, what should the name of this type be?  Should we
+              be using 'S' constants (see stabs.texinfo) instead?  */
+
+           SYMBOL_TYPE (sym) = lookup_fundamental_type (objfile,
+                                                        FT_DBL_PREC_FLOAT);
+           dbl_valu = (char *)
+             obstack_alloc (&objfile -> symbol_obstack,
+                            TYPE_LENGTH (SYMBOL_TYPE (sym)));
+           store_floating (dbl_valu, TYPE_LENGTH (SYMBOL_TYPE (sym)), d);
+           SYMBOL_VALUE_BYTES (sym) = dbl_valu;
+           SYMBOL_CLASS (sym) = LOC_CONST_BYTES;
+         }
+         break;
+       case 'i':
+         {
+           /* Defining integer constants this way is kind of silly,
+              since 'e' constants allows the compiler to give not
+              only the value, but the type as well.  C has at least
+              int, long, unsigned int, and long long as constant
+              types; other languages probably should have at least
+              unsigned as well as signed constants.  */
+
+           /* We just need one int constant type for all objfiles.
+              It doesn't depend on languages or anything (arguably its
+              name should be a language-specific name for a type of
+              that size, but I'm inclined to say that if the compiler
+              wants a nice name for the type, it can use 'e').  */
+           static struct type *int_const_type;
+
+           /* Yes, this is as long as a *host* int.  That is because we
+              use atoi.  */
+           if (int_const_type == NULL)
+             int_const_type =
+               init_type (TYPE_CODE_INT,
+                          sizeof (int) * HOST_CHAR_BIT / TARGET_CHAR_BIT, 0,
+                          "integer constant",
+                          (struct objfile *)NULL);
+           SYMBOL_TYPE (sym) = int_const_type;
+           SYMBOL_VALUE (sym) = atoi (p);
+           SYMBOL_CLASS (sym) = LOC_CONST;
+         }
+         break;
+       case 'e':
+         /* SYMBOL:c=eTYPE,INTVALUE for a constant symbol whose value
+            can be represented as integral.
+            e.g. "b:c=e6,0" for "const b = blob1"
+            (where type 6 is defined by "blobs:t6=eblob1:0,blob2:1,;").  */
+         {
+           SYMBOL_CLASS (sym) = LOC_CONST;
+           SYMBOL_TYPE (sym) = os9k_read_type (&p, objfile);
+
+           if (*p != ',')
+             {
+               SYMBOL_TYPE (sym) = error_type (&p);
+               break;
+             }
+           ++p;
+
+           /* If the value is too big to fit in an int (perhaps because
+              it is unsigned), or something like that, we silently get
+              a bogus value.  The type and everything else about it is
+              correct.  Ideally, we should be using whatever we have
+              available for parsing unsigned and long long values,
+              however.  */
+           SYMBOL_VALUE (sym) = atoi (p);
+         }
+         break;
+       default:
+         {
+           SYMBOL_CLASS (sym) = LOC_CONST;
+           SYMBOL_TYPE (sym) = error_type (&p);
+         }
+       }
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      add_symbol_to_list (sym, &file_symbols);
+      return sym;
+
+    case 'C':
+      /* The name of a caught exception.  */
+      SYMBOL_TYPE (sym) = os9k_read_type (&p, objfile);
+      SYMBOL_CLASS (sym) = LOC_LABEL;
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      SYMBOL_VALUE_ADDRESS (sym) = valu;
+      add_symbol_to_list (sym, &local_symbols);
+      break;
+
+    case 'f':
+      /* A static function definition.  */
+      SYMBOL_TYPE (sym) = os9k_read_type (&p, objfile);
+      SYMBOL_CLASS (sym) = LOC_BLOCK;
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      add_symbol_to_list (sym, &file_symbols);
+      /* fall into process_function_types.  */
+
+    process_function_types:
+      /* Function result types are described as the result type in stabs.
+        We need to convert this to the function-returning-type-X type
+        in GDB.  E.g. "int" is converted to "function returning int".  */
+      if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_FUNC)
+       {
+#if 0
+         /* This code doesn't work -- it needs to realloc and can't.  */
+         /* Attempt to set up to record a function prototype... */
+         struct type *new = alloc_type (objfile);
+
+         /* Generate a template for the type of this function.  The 
+            types of the arguments will be added as we read the symbol 
+            table. */
+         *new = *lookup_function_type (SYMBOL_TYPE(sym));
+         SYMBOL_TYPE(sym) = new;
+         TYPE_OBJFILE (new) = objfile;
+         in_function_type = new;
+#else
+         SYMBOL_TYPE (sym) = lookup_function_type (SYMBOL_TYPE (sym));
+#endif
+       }
+      /* fall into process_prototype_types */
+
+    process_prototype_types:
+      /* Sun acc puts declared types of arguments here.  We don't care
+        about their actual types (FIXME -- we should remember the whole
+        function prototype), but the list may define some new types
+        that we have to remember, so we must scan it now.  */
+      while (*p == ';') {
+       p++;
+       os9k_read_type (&p, objfile);
+      }
+      break;
+
+    case 'F':
+      /* A global function definition.  */
+      SYMBOL_TYPE (sym) = os9k_read_type (&p, objfile);
+      SYMBOL_CLASS (sym) = LOC_BLOCK;
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      add_symbol_to_list (sym, &global_symbols);
+      goto process_function_types;
+
+    case 'V':
+      SYMBOL_TYPE (sym) = os9k_read_type (&p, objfile);
+      SYMBOL_VALUE_ADDRESS (sym) = valu;
+/*
+      i = hashname (SYMBOL_NAME (sym));
+      SYMBOL_VALUE_CHAIN (sym) = 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_TYPE (sym) = os9k_read_type (&p, objfile);
+      SYMBOL_CLASS (sym) = LOC_LOCAL;
+      SYMBOL_VALUE (sym) = valu;
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      add_symbol_to_list (sym, &local_symbols);
+      break;
+
+    case 'p':
+      SYMBOL_TYPE (sym) = os9k_read_type (&p, objfile);
+
+      /* Normally this is a parameter, a LOC_ARG.  On the i960, it
+        can also be a LOC_LOCAL_ARG depending on symbol type.  */
+#ifndef DBX_PARM_SYMBOL_CLASS
+#define        DBX_PARM_SYMBOL_CLASS(type)     LOC_ARG
+#endif
+
+      SYMBOL_CLASS (sym) = DBX_PARM_SYMBOL_CLASS (type);
+      SYMBOL_VALUE (sym) = valu;
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+#if 0
+      /* This doesn't work yet.  */
+      add_param_to_type (&in_function_type, sym);
+#endif
+      add_symbol_to_list (sym, &local_symbols);
+      break;
+
+    case 'P':
+      /* acc seems to use P to delare the prototypes of functions that
+         are referenced by this file.  gdb is not prepared to deal
+         with this extra information.  FIXME, it ought to.  */
+      if (type == N_FUN)
+       {
+         os9k_read_type (&p, objfile);
+         goto process_prototype_types;
+       }
+      /*FALLTHROUGH*/
+
+    case 'R':
+#if 0
+      /* Parameter which is in a register.  */
+      SYMBOL_TYPE (sym) = os9k_read_type (&p, objfile);
+      SYMBOL_CLASS (sym) = LOC_REGPARM;
+      SYMBOL_VALUE (sym) = STAB_REG_TO_REGNUM (valu);
+      if (SYMBOL_VALUE (sym) >= NUM_REGS)
+       {
+         complain (&reg_value_complaint, SYMBOL_SOURCE_NAME (sym));
+         SYMBOL_VALUE (sym) = SP_REGNUM;  /* Known safe, though useless */
+       }
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      add_symbol_to_list (sym, &local_symbols);
+      break;
+#endif 0
+    case 'r':
+      /* Register variable (either global or local).  */
+      SYMBOL_TYPE (sym) = os9k_read_type (&p, objfile);
+      SYMBOL_CLASS (sym) = LOC_REGISTER;
+      SYMBOL_VALUE (sym) = STAB_REG_TO_REGNUM (valu);
+      if (SYMBOL_VALUE (sym) >= NUM_REGS)
+       {
+         complain (&reg_value_complaint, SYMBOL_SOURCE_NAME (sym));
+         SYMBOL_VALUE (sym) = SP_REGNUM;  /* Known safe, though useless */
+       }
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      if (within_function)
+       {
+         /* Sun cc uses a pair of symbols, one 'p' and one 'r' with the same
+            name to represent an argument passed in a register.
+            GCC uses 'P' for the same case.  So if we find such a symbol pair
+            we combine it into one 'P' symbol.
+
+            But we only do this in the REG_STRUCT_HAS_ADDR case, so that
+            we can still get information about what is going on with the
+            stack (VAX for computing args_printed, using stack slots instead
+            of saved registers in backtraces, etc.).
+
+            Note that this code illegally combines
+              main(argc) struct foo argc; { register struct foo argc; }
+            but this case is considered pathological and causes a warning
+            from a decent compiler.  */
+
+         if (local_symbols
+             && local_symbols->nsyms > 0
+             && REG_STRUCT_HAS_ADDR (processing_gcc_compilation)
+             && (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_STRUCT
+                 || TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_UNION))
+           {
+             struct symbol *prev_sym;
+             prev_sym = local_symbols->symbol[local_symbols->nsyms - 1];
+             if (SYMBOL_CLASS (prev_sym) == LOC_ARG
+                 && STREQ (SYMBOL_NAME (prev_sym), SYMBOL_NAME(sym)))
+               {
+                 SYMBOL_CLASS (prev_sym) = LOC_REGPARM;
+                 /* Use the type from the LOC_REGISTER; that is the type
+                    that is actually in that register.  */
+                 SYMBOL_TYPE (prev_sym) = SYMBOL_TYPE (sym);
+                 SYMBOL_VALUE (prev_sym) = SYMBOL_VALUE (sym);
+                 sym = prev_sym;
+                 break;
+               }
+           }
+          add_symbol_to_list (sym, &local_symbols);
+       }
+      else
+        add_symbol_to_list (sym, &file_symbols);
+      break;
+
+    case 't':
+      SYMBOL_TYPE (sym) = os9k_read_type (&p, objfile);
+
+      /* For a nameless type, we don't want a create a symbol, thus we
+        did not use `sym'. Return without further processing. */
+      if (nameless) return NULL;
+
+      SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+      SYMBOL_VALUE (sym) = valu;
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+
+      if (TYPE_NAME (SYMBOL_TYPE (sym)) == NULL)
+       {
+         if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_PTR
+             || TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_FUNC)
+           {
+             /* If we are giving a name to a type such as "pointer to
+                foo" or "function returning foo", we better not set
+                the TYPE_NAME.  If the program contains "typedef char
+                *caddr_t;", we don't want all variables of type char
+                * to print as caddr_t.  This is not just a
+                consequence of GDB's type management; PCC and GCC (at
+                least through version 2.4) both output variables of
+                either type char * or caddr_t with the type number
+                defined in the 't' symbol for caddr_t.  If a future
+                compiler cleans this up it GDB is not ready for it
+                yet, but if it becomes ready we somehow need to
+                disable this check (without breaking the PCC/GCC2.4
+                case).
+
+                Sigh.
+
+                Fortunately, this check seems not to be necessary
+                for anything except pointers or functions.  */
+           }
+         else
+           TYPE_NAME (SYMBOL_TYPE (sym)) = SYMBOL_NAME (sym);
+       }
+
+      add_symbol_to_list (sym, &file_symbols);
+      break;
+
+    case 'T':
+      /* Struct, union, or enum tag.  For GNU C++, this can be be followed
+        by 't' which means we are typedef'ing it as well.  */
+      synonym = *p == 't';
+
+      if (synonym)
+       {
+         p++;
+         type_synonym_name = obsavestring (SYMBOL_NAME (sym),
+                                           strlen (SYMBOL_NAME (sym)),
+                                           &objfile -> symbol_obstack);
+       }
+      /* The semantics of C++ state that "struct foo { ... }" also defines 
+        a typedef for "foo".  Unfortunately, cfront never makes the typedef
+        when translating C++ into C.  We make the typedef here so that
+        "ptype foo" works as expected for cfront translated code.  */
+      else if (current_subfile->language == language_cplus)
+       {
+         synonym = 1;
+         type_synonym_name = obsavestring (SYMBOL_NAME (sym),
+                                           strlen (SYMBOL_NAME (sym)),
+                                           &objfile -> symbol_obstack);
+       }
+
+      SYMBOL_TYPE (sym) = os9k_read_type (&p, objfile);
+
+      /* For a nameless type, we don't want a create a symbol, thus we
+        did not use `sym'. Return without further processing. */
+      if (nameless) return NULL;
+
+      SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+      SYMBOL_VALUE (sym) = valu;
+     SYMBOL_NAMESPACE (sym) = STRUCT_NAMESPACE;
+      if (TYPE_TAG_NAME (SYMBOL_TYPE (sym)) == 0)
+       TYPE_TAG_NAME (SYMBOL_TYPE (sym))
+         = obconcat (&objfile -> type_obstack, "", "", SYMBOL_NAME (sym));
+      add_symbol_to_list (sym, &file_symbols);
+
+      if (synonym)
+       {
+         /* Clone the sym and then modify it. */
+         register struct symbol *typedef_sym = (struct symbol *)
+           obstack_alloc (&objfile -> symbol_obstack, sizeof (struct symbol));
+         *typedef_sym = *sym;
+         SYMBOL_CLASS (typedef_sym) = LOC_TYPEDEF;
+         SYMBOL_VALUE (typedef_sym) = valu;
+         SYMBOL_NAMESPACE (typedef_sym) = VAR_NAMESPACE;
+         if (TYPE_NAME (SYMBOL_TYPE (sym)) == 0)
+           TYPE_NAME (SYMBOL_TYPE (sym))
+             = obconcat (&objfile -> type_obstack, "", "", SYMBOL_NAME (sym));
+         add_symbol_to_list (typedef_sym, &file_symbols);
+       }
+      break;
+
+    case 'v':
+      /* Static symbol at top level of file */
+      SYMBOL_TYPE (sym) = os9k_read_type (&p, objfile);
+      SYMBOL_CLASS (sym) = LOC_STATIC;
+      SYMBOL_VALUE_ADDRESS (sym) = valu;
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      add_symbol_to_list (sym, &file_symbols);
+      break;
+
+    default:
+      SYMBOL_TYPE (sym) = error_type (&p);
+      SYMBOL_CLASS (sym) = LOC_CONST;
+      SYMBOL_VALUE (sym) = 0;
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      add_symbol_to_list (sym, &file_symbols);
+      break;
+    }
+
+  /* When passing structures to a function, some systems sometimes pass
+     the address in a register, not the structure itself. 
+
+     If REG_STRUCT_HAS_ADDR yields non-zero we have to convert LOC_REGPARM
+     to LOC_REGPARM_ADDR for structures and unions.  */
+
+  if (SYMBOL_CLASS (sym) == LOC_REGPARM
+      && REG_STRUCT_HAS_ADDR (processing_gcc_compilation)
+      && ((TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_STRUCT)
+         || (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_UNION)))
+    SYMBOL_CLASS (sym) = LOC_REGPARM_ADDR;
+
+  return sym;
+}
+
+\f
+/* Read type information or a type definition; return the type.  Even
+   though this routine accepts either type information or a type
+   definition, the distinction is relevant--some parts of stabsread.c
+   assume that type information starts with a digit, '-', or '(' in
+   deciding whether to call read_type.  */
+
+static struct type *
+os9k_read_type (pp, objfile)
+     register char **pp;
+     struct objfile *objfile;
+{
+  register struct type *type = 0;
+  struct type *type1;
+  int typenums[2];
+  int xtypenums[2];
+  char type_descriptor;
+
+  /* Size in bits of type if specified by a type attribute, or -1 if
+     there is no size attribute.  */
+  int type_size = -1;
+
+  /* Used to distinguish string and bitstring from char-array and set. */
+  int is_string = 0;
+
+  /* Read type number if present.  The type number may be omitted.
+     for instance in a two-dimensional array declared with type
+     "ar1;1;10;ar1;1;10;4".  */
+  if ((**pp >= '0' && **pp <= '9')
+      || **pp == '('
+      || **pp == '-')
+    {
+      if (read_type_number (pp, typenums) != 0)
+       return error_type (pp);
+      
+      /* Type is not being defined here.  Either it already exists,
+        or this is a forward reference to it.  dbx_alloc_type handles
+        both cases.  */
+      if (**pp != '=')
+       return dbx_alloc_type (typenums, objfile);
+
+      /* Type is being defined here.  */
+      /* Skip the '='.  */
+      ++(*pp);
+
+      while (**pp == '@')
+       {
+         char *p = *pp + 1;
+         /* It might be a type attribute or a member type.  */
+         if (isdigit (*p) || *p ==  '(' || *p == '-')
+           /* Member type.  */
+           break;
+         else
+           {
+             /* Type attributes.  */
+             char *attr = p;
+
+             /* Skip to the semicolon.  */
+             while (*p != ';' && *p != '\0')
+               ++p;
+             *pp = p;
+             if (*p == '\0')
+               return error_type (pp);
+             else
+               /* Skip the semicolon.  */
+               ++*pp;
+
+             switch (*attr)
+               {
+               case 's':
+                 type_size = atoi (attr + 1);
+                 if (type_size <= 0)
+                   type_size = -1;
+                 break;
+
+               case 'S':
+                 is_string = 1;
+                 break;
+
+               default:
+                 /* Ignore unrecognized type attributes, so future compilers
+                    can invent new ones.  */
+                 break;
+               }
+           }
+       }
+      /* Skip the type descriptor, we get it below with (*pp)[-1].  */
+      ++(*pp);
+    }
+  else
+    {
+      /* 'typenums=' not present, type is anonymous.  Read and return
+        the definition, but don't put it in the type vector.  */
+      typenums[0] = typenums[1] = -1;
+      (*pp)++;
+    }
+
+  type_descriptor = (*pp)[-1];
+  switch (type_descriptor)
+    {
+    case 'x':
+      {
+       enum type_code code;
+
+       /* Used to index through file_symbols.  */
+       struct pending *ppt;
+       int i;
+       
+       /* Name including "struct", etc.  */
+       char *type_name;
+       
+       {
+         char *from, *to, *p, *q1, *q2;
+         
+         /* Set the type code according to the following letter.  */
+         switch ((*pp)[0])
+           {
+           case 's':
+             code = TYPE_CODE_STRUCT;
+             break;
+           case 'u':
+             code = TYPE_CODE_UNION;
+             break;
+           case 'e':
+             code = TYPE_CODE_ENUM;
+             break;
+           default:
+             {
+               /* Complain and keep going, so compilers can invent new
+                  cross-reference types.  */
+               static struct complaint msg =
+                 {"Unrecognized cross-reference type `%c'", 0, 0};
+               complain (&msg, (*pp)[0]);
+               code = TYPE_CODE_STRUCT;
+               break;
+             }
+           }
+          
+         q1 = strchr(*pp, '<');
+         p = strchr(*pp, ':');
+         if (p == NULL)
+           return error_type (pp);
+         while (q1 && p > q1 && p[1] == ':')
+           {
+              q2 = strchr(q1, '>');
+              if (!q2 || q2 < p)
+                break;
+              p += 2;
+              p = strchr(p, ':');
+              if (p == NULL)
+                return error_type (pp);
+           }
+         to = type_name = 
+               (char *)obstack_alloc (&objfile->type_obstack, p - *pp + 1);
+       
+         /* Copy the name.  */
+         from = *pp + 1;
+         while (from < p) 
+           *to++ = *from++;
+         *to = '\0';
+         
+         /* Set the pointer ahead of the name which we just read, and
+            the colon.  */
+         *pp = from + 1;
+       }
+
+       /* Now check to see whether the type has already been
+          declared.  This was written for arrays of cross-referenced
+          types before we had TYPE_CODE_TARGET_STUBBED, so I'm pretty
+          sure it is not necessary anymore.  But it might be a good
+          idea, to save a little memory.  */
+
+       for (ppt = file_symbols; ppt; ppt = ppt->next)
+         for (i = 0; i < ppt->nsyms; i++)
+           {
+             struct symbol *sym = ppt->symbol[i];
+
+             if (SYMBOL_CLASS (sym) == LOC_TYPEDEF
+                 && SYMBOL_NAMESPACE (sym) == STRUCT_NAMESPACE
+                 && (TYPE_CODE (SYMBOL_TYPE (sym)) == code)
+                 && STREQ (SYMBOL_NAME (sym), type_name))
+               {
+                 obstack_free (&objfile -> type_obstack, type_name);
+                 type = SYMBOL_TYPE (sym);
+                 return type;
+               }
+           }
+
+       /* Didn't find the type to which this refers, so we must
+          be dealing with a forward reference.  Allocate a type
+          structure for it, and keep track of it so we can
+          fill in the rest of the fields when we get the full
+          type.  */
+       type = dbx_alloc_type (typenums, objfile);
+       TYPE_CODE (type) = code;
+       TYPE_TAG_NAME (type) = type_name;
+       TYPE_NAME(type) = NULL;
+       INIT_CPLUS_SPECIFIC(type);
+       TYPE_FLAGS (type) |= TYPE_FLAG_STUB;
+
+       add_undefined_type (type);
+       return type;
+      }
+
+    case '-':                          /* RS/6000 built-in type */
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+    case '6':
+    case '7':
+    case '8':
+    case '9':
+    case '(':
+
+      {
+       char *pp_saved;
+
+       (*pp)--;
+       pp_saved = *pp;
+
+       /* Peek ahead at the number to detect void.  */
+       if (read_type_number (pp, xtypenums) != 0)
+         return error_type (pp);
+
+       if (typenums[0] == xtypenums[0] && typenums[1] == xtypenums[1])
+         /* It's being defined as itself.  That means it is "void".  */
+         type = init_type (TYPE_CODE_VOID, 0, 0, NULL, objfile);
+       else
+         {
+           struct type *xtype;
+
+           /* Go back to the number and have read_type get it.  This means
+              that we can deal with something like t(1,2)=(3,4)=... which
+              the Lucid compiler uses.  */
+           *pp = pp_saved;
+           xtype = os9k_read_type (pp, objfile);
+
+           /* The type is being defined to another type.  So we copy the type.
+              This loses if we copy a C++ class and so we lose track of how
+              the names are mangled (but g++ doesn't output stabs like this
+              now anyway).  */
+
+           type = alloc_type (objfile);
+           memcpy (type, xtype, sizeof (struct type));
+
+           /* The idea behind clearing the names is that the only purpose
+              for defining a type to another type is so that the name of
+              one can be different.  So we probably don't need to worry much
+              about the case where the compiler doesn't give a name to the
+              new type.  */
+           TYPE_NAME (type) = NULL;
+           TYPE_TAG_NAME (type) = NULL;
+         }
+       if (typenums[0] != -1)
+         *dbx_lookup_type (typenums) = type;
+       break;
+      }
+
+    /* In the following types, we must be sure to overwrite any existing
+       type that the typenums refer to, rather than allocating a new one
+       and making the typenums point to the new one.  This is because there
+       may already be pointers to the existing type (if it had been
+       forward-referenced), and we must change it to a pointer, function,
+       reference, or whatever, *in-place*.  */
+
+    case '*':
+      type1 = os9k_read_type (pp, objfile);
+      type = make_pointer_type (type1, dbx_lookup_type (typenums));
+      break;
+
+    case '&':                          /* Reference to another type */
+      type1 = os9k_read_type (pp, objfile);
+      type = make_reference_type (type1, dbx_lookup_type (typenums));
+      break;
+
+    case 'f':                          /* Function returning another type */
+      if (**pp == '(') {
+       while (**pp != ')') ++*pp;      /* skip os9000 function prototype */
+        ++*pp;
+      }
+      type1 = os9k_read_type (pp, objfile);
+      type = make_function_type (type1, dbx_lookup_type (typenums));
+      break;
+
+    case 'c':                          /* Const qualifier on some type (Sun) */
+      type = os9k_read_type (pp, objfile);
+      /* FIXME! For now, we ignore const and volatile qualifiers.  */
+      break;
+
+    case 'b':                           /* Const volatile */
+    case 'i':                          /* Volatile qual on some type (Sun) */
+      type = os9k_read_type (pp, objfile);
+      /* FIXME! For now, we ignore const and volatile qualifiers.  */
+      break;
+
+/* FIXME -- we should be doing smash_to_XXX types here.  */
+    case '@':                          /* Member (class & variable) type */
+      {
+       struct type *domain = os9k_read_type (pp, objfile);
+       struct type *memtype;
+
+       if (**pp != ',')
+         /* Invalid member type data format.  */
+         return error_type (pp);
+       ++*pp;
+
+       memtype = os9k_read_type (pp, objfile);
+       type = dbx_alloc_type (typenums, objfile);
+       smash_to_member_type (type, domain, memtype);
+      }
+      break;
+
+    case 'r':                          /* Range type */
+      type = read_range_type (pp, typenums, objfile);
+      if (typenums[0] != -1)
+       *dbx_lookup_type (typenums) = type;
+      break;
+
+    case 'e':                          /* Enumeration type */
+      type = dbx_alloc_type (typenums, objfile);
+      type = os9k_read_enum_type (pp, type, objfile);
+      if (typenums[0] != -1)
+       *dbx_lookup_type (typenums) = type;
+      break;
+
+    case 's':                          /* Struct type */
+    case 'u':                          /* Union type */
+      type = dbx_alloc_type (typenums, objfile);
+      if (!TYPE_NAME (type))
+       {
+         TYPE_NAME (type) = type_synonym_name;
+       }
+      type_synonym_name = NULL;
+      switch (type_descriptor)
+       {
+         case 's':
+           TYPE_CODE (type) = TYPE_CODE_STRUCT;
+           break;
+         case 'u':
+           TYPE_CODE (type) = TYPE_CODE_UNION;
+           break;
+       }
+      type = read_struct_type (pp, type, objfile);
+      break;
+
+    case 'a':                          /* Array type */
+      if (**pp == 'r')
+        ++*pp;
+      
+      type = dbx_alloc_type (typenums, objfile);
+      type = os9k_read_array_type (pp, type, objfile);
+      if (is_string)
+       TYPE_CODE (type) = TYPE_CODE_STRING;
+      break;
+
+    case 'S':
+      type1 = os9k_read_type (pp, objfile);
+      type = create_set_type ((struct type*) NULL, type1);
+      if (is_string)
+       TYPE_CODE (type) = TYPE_CODE_BITSTRING;
+      if (typenums[0] != -1)
+       *dbx_lookup_type (typenums) = type;
+      break;
+
+    default:
+      --*pp;                   /* Go back to the symbol in error */
+                               /* Particularly important if it was \0! */
+      return error_type (pp);
+    }
+
+  if (type == 0)
+    {
+      warning ("GDB internal error, type is NULL in stabsread.c\n");
+      return error_type (pp);
+    }
+
+  /* Size specified in a type attribute overrides any other size.  */
+  if (type_size != -1)
+    TYPE_LENGTH (type) = type_size / TARGET_CHAR_BIT;
+
+  return type;
+}
+
+/* Read a definition of an array type,
+   and create and return a suitable type object.
+   Also creates a range type which represents the bounds of that
+   array.  */
+
+static struct type *
+os9k_read_array_type (pp, type, objfile)
+     register char **pp;
+     register struct type *type;
+     struct objfile *objfile;
+{
+  struct type *index_type, *element_type, *range_type;
+  int lower, upper;
+  int adjustable = 0;
+  int nbits;
+
+  /* Format of an array type:
+     "arlower,upper;<array_contents_type>".  Put code in
+     to handle this.
+
+     Fortran adjustable arrays use Adigits or Tdigits for lower or upper;
+     for these, produce a type like float[][].  */
+
+  index_type = builtin_type_int;
+
+  if (!(**pp >= '0' && **pp <= '9') && **pp != '-')
+    {
+      (*pp)++;
+      adjustable = 1;
+    }
+  lower = read_huge_number (pp, ',', &nbits);
+  if (nbits != 0)
+    return error_type (pp);
+
+  if (!(**pp >= '0' && **pp <= '9') && **pp != '-')
+    {
+      (*pp)++;
+      adjustable = 1;
+    }
+  upper = read_huge_number (pp, ';', &nbits);
+  if (nbits != 0)
+    return error_type (pp);
+  
+  element_type = os9k_read_type (pp, objfile);
+
+  if (adjustable)
+    {
+      lower = 0;
+      upper = -1;
+    }
+
+  range_type =
+    create_range_type ((struct type *) NULL, index_type, lower, upper);
+  type = create_array_type (type, element_type, range_type);
+
+  /* If we have an array whose element type is not yet known, but whose
+     bounds *are* known, record it to be adjusted at the end of the file.  */
+  /* FIXME: Why check for zero length rather than TYPE_FLAG_STUB?  I think
+     the two have the same effect except that the latter is cleaner and the
+     former would be wrong for types which really are zero-length (if we
+     have any).  */
+
+  if (TYPE_LENGTH (element_type) == 0 && !adjustable)
+    {
+      TYPE_FLAGS (type) |= TYPE_FLAG_TARGET_STUB;
+      add_undefined_type (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 *
+os9k_read_enum_type (pp, type, objfile)
+     register char **pp;
+     register struct type *type;
+     struct objfile *objfile;
+{
+  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;
+  int size;
+  int nbits;
+
+#if 0
+  /* FIXME!  The stabs produced by Sun CC merrily define things that ought
+     to be file-scope, between N_FN entries, using N_LSYM.  What's a mother
+     to do?  For now, force all enum values to file scope.  */
+  if (within_function)
+    symlist = &local_symbols;
+  else
+#endif
+    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 or comma instead of a NAME means the end.  */
+
+  size = read_huge_number(pp, 0, &nbits);
+  if (nbits != 0)
+    return error_type (pp);
+  while (**pp && **pp != ';' && **pp != ',')
+    {
+      STABS_CONTINUE (pp);
+      p = *pp;
+      while (*p != ':') p++;
+      name = obsavestring (*pp, p - *pp, &objfile -> symbol_obstack);
+      *pp = p + 1;
+      n = read_huge_number (pp, ',', &nbits);
+      if (nbits != 0)
+       return error_type (pp);
+
+      sym = (struct symbol *)
+       obstack_alloc (&objfile -> symbol_obstack, sizeof (struct symbol));
+      memset (sym, 0, sizeof (struct symbol));
+      SYMBOL_NAME (sym) = name;
+      SYMBOL_LANGUAGE (sym) = current_subfile -> language;
+      SYMBOL_CLASS (sym) = LOC_CONST;
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      SYMBOL_VALUE (sym) = n;
+      add_symbol_to_list (sym, symlist);
+      nsyms++;
+    }
+
+  if (**pp == ';')
+    (*pp)++;                   /* Skip the semicolon.  */
+
+  /* Now fill in the fields of the type-structure.  */
+
+  TYPE_LENGTH (type) = TARGET_INT_BIT / HOST_CHAR_BIT;
+  TYPE_CODE (type) = TYPE_CODE_ENUM;
+  TYPE_FLAGS (type) &= ~TYPE_FLAG_STUB;
+  TYPE_NFIELDS (type) = nsyms;
+  TYPE_FIELDS (type) = (struct field *)
+    TYPE_ALLOC (type, sizeof (struct field) * nsyms);
+  memset (TYPE_FIELDS (type), 0, 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.  */
+  /* Note that we preserve the order of the enum constants, so
+     that in something like "enum {FOO, LAST_THING=FOO}" we print
+     FOO, not LAST_THING.  */
+
+  for (syms = *symlist, n = 0; syms; syms = syms->next)
+    {
+      int j = 0;
+      if (syms == osyms)
+       j = o_nsyms;
+      for (; j < syms->nsyms; j++,n++)
+       {
+         struct symbol *xsym = syms->symbol[j];
+         SYMBOL_TYPE (xsym) = type;
+         TYPE_FIELD_NAME (type, n) = SYMBOL_NAME (xsym);
+         TYPE_FIELD_VALUE (type, n) = 0;
+         TYPE_FIELD_BITPOS (type, n) = SYMBOL_VALUE (xsym);
+         TYPE_FIELD_BITSIZE (type, n) = 0;
+       }
+      if (syms == osyms)
+       break;
+    }
+
+  return type;
+}
diff --git a/gdb/remote-os9k.c b/gdb/remote-os9k.c
new file mode 100644 (file)
index 0000000..855ea4f
--- /dev/null
@@ -0,0 +1,1181 @@
+ /* Remote debugging interface for boot monitors, for GDB.
+   Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* This file was derived from remote-eb.c, which did a similar job, but for
+   an AMD-29K running EBMON.  That file was in turn derived from remote.c
+   as mentioned in the following comment (left in for comic relief):
+
+  "This is like remote.c but is for a different situation--
+   having a PC running os9000 hook up with a unix machine with
+   a serial line, and running ctty com2 on the PC. os9000 has a debug
+   monitor called ROMBUG running.  Not to mention that the PC
+   has PC/NFS, so it can access the same executables that gdb can,
+   over the net in real time."
+
+   In reality, this module talks to a debug monitor called 'ROMBUG', which
+   We communicate with ROMBUG via a direct serial line, the network version
+   of ROMBUG is not available yet.
+*/
+
+#include "defs.h"
+#include "gdbcore.h"
+#include "target.h"
+#include "wait.h"
+#include <varargs.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/types.h>
+#include "command.h"
+#include "serial.h"
+#include "monitor.h"
+#include "remote-utils.h"
+#include "symtab.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "gdb-stabs.h"
+
+#ifdef HAVE_TERMIO
+#  define TERMINAL struct termios
+#else
+#  define TERMINAL struct sgttyb
+#endif
+
+struct monitor_ops *current_monitor;
+struct cmd_list_element *showlist;
+extern struct target_ops rombug_ops;           /* Forward declaration */
+extern struct monitor_ops rombug_cmds;         /* Forward declaration */
+extern struct cmd_list_element *setlist;
+extern struct cmd_list_element *unsetlist;
+extern int attach_flag;
+
+static void rombug_close();
+static void rombug_fetch_register();
+static void rombug_fetch_registers();
+static void rombug_store_register();
+#if 0
+static int sr_get_debug();                     /* flag set by "set remotedebug" */
+#endif
+static int hashmark;                           /* flag set by "set hash" */
+static int rombug_is_open = 0;
+
+/* FIXME: Replace with sr_get_debug ().  */
+#define LOG_FILE "monitor.log"
+#if defined (LOG_FILE)
+FILE *log_file;
+#endif
+
+static int timeout = 5;
+static int is_trace_mode = 0;
+/* Descriptor for I/O to remote machine.  Initialize it to NULL*/
+static serial_t monitor_desc = NULL;
+
+/* Send data to monitor.  Works just like printf. */
+static void
+printf_monitor(va_alist)
+     va_dcl
+{
+  va_list args;
+  char *pattern;
+  char buf[200];
+  int i;
+
+  va_start(args);
+
+  pattern = va_arg(args, char *);
+
+  vsprintf(buf, pattern, args);
+
+  if (SERIAL_WRITE(monitor_desc, buf, strlen(buf)))
+    fprintf(stderr, "SERIAL_WRITE failed: %s\n", safe_strerror(errno));
+}
+
+/* Read a character from the remote system, doing all the fancy timeout stuff*/
+static int
+readchar(timeout)
+     int timeout;
+{
+  int c;
+
+  c = SERIAL_READCHAR(monitor_desc, timeout);
+
+  if (sr_get_debug())
+    putchar(c & 0x7f);
+
+#ifdef LOG_FILE
+  if (isascii (c))
+    putc(c & 0x7f, log_file);
+#endif
+
+  if (c >= 0)
+    return c & 0x7f;
+
+  if (c == SERIAL_TIMEOUT)
+    {
+      if (timeout == 0)
+       return c;               /* Polls shouldn't generate timeout errors */
+
+      error("Timeout reading from remote system.");
+    }
+
+  perror_with_name("remote-monitor");
+}
+
+/* Scan input from the remote system, until STRING is found.  If DISCARD is
+   non-zero, then discard non-matching input, else print it out.
+   Let the user break out immediately.  */
+static void
+expect(string, discard)
+     char *string;
+     int discard;
+{
+  char *p = string;
+  int c;
+
+  if (sr_get_debug())
+    printf ("Expecting \"%s\"\n", string);
+
+  immediate_quit = 1;
+  while (1)
+    {
+      c = readchar(timeout);
+      if (!isascii (c))
+       continue;
+      if (c == *p++)
+       {
+         if (*p == '\0')
+           {
+             immediate_quit = 0;
+             if (sr_get_debug())
+               printf ("\nMatched\n");
+             return;
+           }
+       }
+      else
+       {
+         if (!discard)
+           {
+             fwrite(string, 1, (p - 1) - string, stdout);
+             putchar((char)c);
+             fflush(stdout);
+           }
+         p = string;
+       }
+    }
+}
+
+/* Keep discarding input until we see the ROMBUG prompt.
+
+   The convention for dealing with the prompt is that you
+   o give your command
+   o *then* wait for the prompt.
+
+   Thus the last thing that a procedure does with the serial line
+   will be an expect_prompt().  Exception:  rombug_resume does not
+   wait for the prompt, because the terminal is being handed over
+   to the inferior.  However, the next thing which happens after that
+   is a rombug_wait which does wait for the prompt.
+   Note that this includes abnormal exit, e.g. error().  This is
+   necessary to prevent getting into states from which we can't
+   recover.  */
+static void
+expect_prompt(discard)
+     int discard;
+{
+#if defined (LOG_FILE)
+  /* This is a convenient place to do this.  The idea is to do it often
+     enough that we never lose much data if we terminate abnormally.  */
+  fflush(log_file);
+#endif
+  if (is_trace_mode) {
+    expect("trace", discard);
+    is_trace_mode = 0;
+  } else {
+    expect (PROMPT, discard);
+  }
+}
+
+/* Get a hex digit from the remote system & return its value.
+   If ignore_space is nonzero, ignore spaces (not newline, tab, etc).  */
+static int
+get_hex_digit(ignore_space)
+     int ignore_space;
+{
+  int ch;
+  while (1)
+    {
+      ch = readchar(timeout);
+      if (ch >= '0' && ch <= '9')
+       return ch - '0';
+      else if (ch >= 'A' && ch <= 'F')
+       return ch - 'A' + 10;
+      else if (ch >= 'a' && ch <= 'f')
+       return ch - 'a' + 10;
+      else if (ch == ' ' && ignore_space)
+       ;
+      else
+       {
+         expect_prompt(1);
+         error("Invalid hex digit from remote system.");
+       }
+    }
+}
+
+/* Get a byte from monitor and put it in *BYT.  Accept any number
+   leading spaces.  */
+static void
+get_hex_byte (byt)
+     char *byt;
+{
+  int val;
+
+  val = get_hex_digit (1) << 4;
+  val |= get_hex_digit (0);
+  *byt = val;
+}
+
+/* Get N 32-bit words from remote, each preceded by a space,
+   and put them in registers starting at REGNO.  */
+static void
+get_hex_regs (n, regno)
+     int n;
+     int regno;
+{
+  long val;
+  int i;
+  unsigned char b;
+
+  for (i = 0; i < n; i++)
+    {
+      int j;
+      
+      val = 0;
+      for (j = 0; j < 4; j++)
+       {
+#if TARGET_BYTE_ORDER == BIG_ENDIAN
+         get_hex_byte(&b);
+         val = (val << 8) + b;
+#else
+         get_hex_byte(&b);
+         val = val + (b << (j*8));
+#endif
+       }
+      supply_register (regno++, (char *) &val);
+    }
+}
+
+/* This is called not only when we first attach, but also when the
+   user types "run" after having attached.  */
+static void
+rombug_create_inferior (execfile, args, env)
+     char *execfile;
+     char *args;
+     char **env;
+{
+  int entry_pt;
+
+  if (args && *args)
+    error("Can't pass arguments to remote ROMBUG process");
+
+  if (execfile == 0 || exec_bfd == 0)
+    error("No exec file specified");
+
+  entry_pt = (int) bfd_get_start_address (exec_bfd);
+
+#ifdef LOG_FILE
+  fputs ("\nIn Create_inferior()", log_file);
+#endif
+
+/* The "process" (board) is already stopped awaiting our commands, and
+   the program is already downloaded.  We just set its PC and go.  */
+
+  init_wait_for_inferior ();
+  proceed ((CORE_ADDR)entry_pt, TARGET_SIGNAL_DEFAULT, 0);
+}
+
+/* Open a connection to a remote debugger.
+   NAME is the filename used for communication.  */
+
+static int baudrate = 9600;
+static char dev_name[100];
+
+static void
+rombug_open(args, from_tty)
+     char *args;
+     int from_tty;
+{
+  if (args == NULL)
+    error ("Use `target RomBug DEVICE-NAME' to use a serial port, or \n\
+`target RomBug HOST-NAME:PORT-NUMBER' to use a network connection.");
+
+  target_preopen(from_tty);
+
+  if (rombug_is_open)
+    unpush_target(&rombug_ops);
+
+  strcpy(dev_name, args);
+  monitor_desc = SERIAL_OPEN(dev_name);
+  if (monitor_desc == NULL)
+    perror_with_name(dev_name);
+
+  /* The baud rate was specified when GDB was started. ***
+  if (SERIAL_SETBAUDRATE (monitor_desc, sr_get_baud_rate()))
+    {
+      SERIAL_CLOSE (monitor_desc);
+      perror_with_name ("RomBug");
+    }
+  */
+  SERIAL_RAW(monitor_desc);
+  rombug_is_open = 1;
+
+#if defined (LOG_FILE)
+  log_file = fopen (LOG_FILE, "w");
+  if (log_file == NULL)
+    perror_with_name (LOG_FILE);
+#endif
+
+  push_monitor (&rombug_cmds);
+
+  printf_monitor("\r");        /* CR wakes up monitor */
+  expect_prompt(1);
+
+  push_target (&rombug_ops);
+  if (from_tty)
+    printf("Remote %s connected to %s\n", target_shortname,
+          dev_name);
+
+  attach_flag = 1;
+  rombug_fetch_registers();
+}
+
+/*
+ * Close out all files and local state before this target loses control.
+ */
+
+static void
+rombug_close (quitting)
+     int quitting;
+{
+  if (rombug_is_open) {
+    SERIAL_CLOSE(monitor_desc);
+    monitor_desc = NULL;
+    rombug_is_open = 0;
+  }
+
+#if defined (LOG_FILE)
+  if (log_file) {
+    if (ferror(log_file))
+      fprintf(stderr, "Error writing log file.\n");
+    if (fclose(log_file) != 0)
+      fprintf(stderr, "Error closing log file.\n");
+    log_file = 0;
+  }
+#endif
+}
+
+int
+rombug_link(mod_name, text_reloc)
+     char *mod_name;
+     CORE_ADDR *text_reloc;
+{
+  int i, j;
+  unsigned long val;
+  unsigned char b;
+
+  printf_monitor("l %s \r", mod_name); 
+  expect_prompt(1);
+  printf_monitor(".r \r");
+  expect(REG_DELIM, 1);
+  for (i=0; i <= 7; i++)
+    {
+      val = 0;
+      for (j = 0; j < 4; j++)
+        {
+          get_hex_byte(&b);
+          val = (val << 8) + b;
+       }
+    }
+  expect_prompt(1);
+  *text_reloc = val;
+  return 1;
+}
+
+/* Terminate the open connection to the remote debugger.
+   Use this when you want to detach and do something else
+   with your gdb.  */
+static void
+rombug_detach (from_tty)
+     int from_tty;
+{
+  if (attach_flag) {
+    printf_monitor (GO_CMD);
+    attach_flag = 0;
+  }
+  pop_target();                /* calls rombug_close to do the real work */
+  if (from_tty)
+    printf ("Ending remote %s debugging\n", target_shortname);
+}
+/*
+ * Tell the remote machine to resume.
+ */
+static void
+rombug_resume (pid, step, sig)
+     int pid, step;
+     enum target_signal sig;
+{
+#ifdef LOG_FILE
+  fprintf (log_file, "\nIn Resume (step=%d, sig=%d)\n", step, sig);
+#endif
+
+  if (step)
+    {
+      is_trace_mode = 1;
+      printf_monitor (STEP_CMD);
+      /* wait for the echo.  */
+      expect (STEP_CMD, 1);
+    }
+  else
+    {
+      printf_monitor (GO_CMD);
+      /* swallow the echo.  */
+      expect (GO_CMD, 1);
+    }
+}
+
+/*
+ * Wait until the remote machine stops, then return,
+ * storing status in status just as `wait' would.
+ */
+
+static int
+rombug_wait (pid, status)
+     int pid;
+     struct target_waitstatus *status;
+{
+  int old_timeout = timeout;
+  struct section_offsets *offs;
+  CORE_ADDR addr, pc;
+  struct objfile *obj;
+
+#ifdef LOG_FILE
+  fputs ("\nIn wait ()", log_file);
+#endif
+
+  status->kind = TARGET_WAITKIND_EXITED;
+  status->value.integer = 0;
+
+  timeout = 0;         /* Don't time out -- user program is running. */
+  expect_prompt(1);     /* Wait for prompt, outputting extraneous text */
+
+  status->kind = TARGET_WAITKIND_STOPPED;
+  status->value.sig = TARGET_SIGNAL_TRAP;
+  timeout = old_timeout;
+  rombug_fetch_registers();
+  pc = read_register(PC_REGNUM);
+  addr = read_register(DATABASE_REG);
+  obj = find_pc_objfile(pc);
+  if (obj != NULL)
+    new_symfile_objfile(obj, 1, 0);
+  offs = ((struct section_offsets *)
+        alloca (sizeof (struct section_offsets)
+        + (symfile_objfile->num_sections * sizeof (offs->offsets))));
+  memcpy (offs, symfile_objfile->section_offsets,
+         (sizeof (struct section_offsets) + 
+        (symfile_objfile->num_sections * sizeof (offs->offsets))));
+  ANOFFSET (offs, SECT_OFF_DATA) = addr;
+  ANOFFSET (offs, SECT_OFF_BSS) = addr;
+
+  objfile_relocate_data(symfile_objfile, offs);
+
+  return 0;
+}
+
+/* Return the name of register number regno in the form input and output by
+   monitor.  Currently, register_names just happens to contain exactly what
+   monitor wants.  Lets take advantage of that just as long as possible! */
+
+static char *
+get_reg_name (regno)
+     int regno;
+{
+  static char buf[50];
+  char *p;
+  char *b;
+
+  b = buf;
+
+  if (regno < 0)
+    return ("");
+/*
+  for (p = reg_names[regno]; *p; p++)
+    *b++ = toupper(*p);
+  *b = '\000';
+*/
+  p = (char *)reg_names[regno];
+  return p;
+/*
+  return buf;
+*/
+}
+
+/* read the remote registers into the block regs.  */
+
+static void
+rombug_fetch_registers ()
+{
+  int regno, j, i;
+  long val;
+  unsigned char b;
+
+  printf_monitor (GET_REG);
+  expect("eax:", 1);
+  expect("\n", 1);
+  get_hex_regs(1, 0);
+  get_hex_regs(1, 3);
+  get_hex_regs(1, 1);
+  get_hex_regs(1, 2);
+  get_hex_regs(1, 6);
+  get_hex_regs(1, 7);
+  get_hex_regs(1, 5);
+  get_hex_regs(1, 4);
+  for (regno = 8; regno <= 15; regno++)
+    {
+      expect(REG_DELIM, 1);
+      if (regno >= 8 && regno <= 13)
+       {
+         val = 0;
+         for (j = 0; j < 2; j++)
+            {
+#if TARGET_BYTE_ORDER == BIG_ENDIAN
+              get_hex_byte(&b);
+              val = (val << 8) + b;
+#else
+              get_hex_byte(&b);
+              val = val + (b << (j*8));
+#endif
+            }
+
+         if (regno == 8) i = 10;
+         if (regno >=  9 && regno <= 12) i = regno + 3;
+         if (regno == 13) i = 11;
+         supply_register (i, (char *) &val);
+       }
+      else if (regno == 14)
+       {
+         get_hex_regs(1, PC_REGNUM);
+       }
+      else if (regno == 15)
+       {
+         get_hex_regs(1, 9);
+       }
+      else
+       {
+         val = 0;
+         supply_register(regno, (char *) &val);
+       }
+    }
+  expect_prompt (1);
+}
+
+/* Fetch register REGNO, or all registers if REGNO is -1.
+   Returns errno value.  */
+static void
+rombug_fetch_register (regno)
+     int regno;
+{
+  int val, j;
+  unsigned char b;
+
+#ifdef LOG_FILE
+  fprintf (log_file, "\nIn Fetch Register (reg=%s)\n", get_reg_name (regno));
+  fflush (log_file);
+#endif
+
+  if (regno < 0)
+    {
+      rombug_fetch_registers ();
+    }
+  else
+    {
+      char *name = get_reg_name (regno);
+      printf_monitor (GET_REG);
+      if (regno >= 10 && regno <= 15)
+       {
+         expect ("\n", 1);
+         expect ("\n", 1);
+          expect (name, 1);
+          expect (REG_DELIM, 1);
+         val = 0;
+         for (j = 0; j < 2; j++)
+            {
+#if TARGET_BYTE_ORDER == BIG_ENDIAN
+              get_hex_byte(&b);
+              val = (val << 8) + b;
+#else
+              get_hex_byte(&b);
+              val = val + (b << (j*8));
+#endif
+            }
+         supply_register (regno, (char *) &val);
+       }
+      else if (regno == 8 || regno == 9)
+       {
+         expect ("\n", 1);
+         expect ("\n", 1);
+         expect ("\n", 1);
+          expect (name, 1);
+          expect (REG_DELIM, 1);
+         get_hex_regs (1, regno);
+       }
+      else
+       {
+          expect (name, 1);
+          expect (REG_DELIM, 1);
+         expect("\n", 1);
+         get_hex_regs(1, 0);
+         get_hex_regs(1, 3);
+         get_hex_regs(1, 1);
+         get_hex_regs(1, 2);
+         get_hex_regs(1, 6);
+         get_hex_regs(1, 7);
+         get_hex_regs(1, 5);
+         get_hex_regs(1, 4);
+       }
+      expect_prompt (1);
+    }
+  return;
+}
+
+/* Store the remote registers from the contents of the block REGS.  */
+
+static void
+rombug_store_registers ()
+{
+  int regno;
+
+  for (regno = 0; regno <= PC_REGNUM; regno++)
+    rombug_store_register(regno);
+
+  registers_changed ();
+}
+
+/* Store register REGNO, or all if REGNO == 0.
+   return errno value.  */
+static void
+rombug_store_register (regno)
+     int regno;
+{
+char *name;
+
+#ifdef LOG_FILE
+  fprintf (log_file, "\nIn Store_register (regno=%d)\n", regno);
+#endif
+  if (regno == -1)
+    rombug_store_registers ();
+  else
+    {
+      if (sr_get_debug())
+       printf ("Setting register %s to 0x%x\n", get_reg_name (regno), read_register (regno));
+
+      name = get_reg_name(regno);
+      if (name == 0) return;
+      printf_monitor (SET_REG, name, read_register (regno));
+
+      expect_prompt (1);
+    }
+}
+
+/* Get ready to modify the registers array.  On machines which store
+   individual registers, this doesn't need to do anything.  On machines
+   which store all the registers in one fell swoop, this makes sure
+   that registers contains all the registers from the program being
+   debugged.  */
+
+static void
+rombug_prepare_to_store ()
+{
+  /* Do nothing, since we can store individual regs */
+}
+
+static void
+rombug_files_info ()
+{
+  printf ("\tAttached to %s at %d baud.\n",
+         dev_name, baudrate);
+}
+
+/* Copy LEN bytes of data from debugger memory at MYADDR
+   to inferior's memory at MEMADDR.  Returns length moved.  */
+static int
+rombug_write_inferior_memory (memaddr, myaddr, len)
+     CORE_ADDR memaddr;
+     unsigned char *myaddr;
+     int len;
+{
+  int i;
+  char buf[10];
+
+#ifdef LOG_FILE
+  fprintf (log_file, "\nIn Write_inferior_memory (memaddr=%x, len=%d)\n", memaddr, len);
+#endif
+  printf_monitor (MEM_SET_CMD, memaddr + i);
+  for (i = 0; i < len; i++)
+    {
+      expect (CMD_DELIM, 1);
+      printf_monitor ("%x", myaddr[i]);
+      if (sr_get_debug())
+       printf ("\nSet 0x%x to 0x%x\n", memaddr + i, myaddr[i]);
+    }
+  if (CMD_END)
+    printf_monitor (CMD_END);
+  expect_prompt (1);
+
+  return len;
+}
+
+/* Read LEN bytes from inferior memory at MEMADDR.  Put the result
+   at debugger address MYADDR.  Returns length moved.  */
+static int
+rombug_read_inferior_memory(memaddr, myaddr, len)
+     CORE_ADDR memaddr;
+     char *myaddr;
+     int len;
+{
+  int i, j;
+  char buf[20];
+
+  /* Number of bytes read so far.  */
+  int count;
+
+  /* Starting address of this pass.  */
+  unsigned long startaddr;
+
+  /* Number of bytes to read in this pass.  */
+  int len_this_pass;
+
+#ifdef LOG_FILE
+  fprintf (log_file, "\nIn Read_inferior_memory (memaddr=%x, len=%d)\n", memaddr, len);
+#endif
+
+  /* Note that this code works correctly if startaddr is just less
+     than UINT_MAX (well, really CORE_ADDR_MAX if there was such a
+     thing).  That is, something like
+     rombug_read_bytes (CORE_ADDR_MAX - 4, foo, 4)
+     works--it never adds len To memaddr and gets 0.  */
+  /* However, something like
+     rombug_read_bytes (CORE_ADDR_MAX - 3, foo, 4)
+     doesn't need to work.  Detect it and give up if there's an attempt
+     to do that.  */
+  if (((memaddr - 1) + len) < memaddr) {
+    errno = EIO;
+    return 0;
+  }
+  
+  startaddr = memaddr;
+  count = 0;
+  while (count < len)
+    {
+      len_this_pass = 16;
+      if ((startaddr % 16) != 0)
+       len_this_pass -= startaddr % 16;
+      if (len_this_pass > (len - count))
+       len_this_pass = (len - count);
+      if (sr_get_debug())
+       printf ("\nDisplay %d bytes at %x\n", len_this_pass, startaddr);
+
+      printf_monitor (MEM_DIS_CMD, startaddr, 16);
+      expect ("- ", 1);
+      for (i = 0; i < len_this_pass; i++)
+       {
+         get_hex_byte (&myaddr[count++]);
+         if (sr_get_debug())
+           printf ("\nRead a 0x%x from 0x%x\n", myaddr[count-1], startaddr);
+         startaddr += 1;
+       }
+      expect(CMD_DELIM, 1);
+    }
+  if (CMD_END) 
+      printf_monitor (CMD_END);
+  expect_prompt (1);
+
+  return len;
+}
+
+/* FIXME-someday!  merge these two.  */
+static int
+rombug_xfer_inferior_memory (memaddr, myaddr, len, write, target)
+     CORE_ADDR memaddr;
+     char *myaddr;
+     int len;
+     int write;
+     struct target_ops *target;                /* ignored */
+{
+  if (write)
+    return rombug_write_inferior_memory (memaddr, myaddr, len);
+  else
+    return rombug_read_inferior_memory (memaddr, myaddr, len);
+}
+
+static void
+rombug_kill (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  return;              /* ignore attempts to kill target system */
+}
+
+/* Clean up when a program exits.
+   The program actually lives on in the remote processor's RAM, and may be
+   run again without a download.  Don't leave it full of breakpoint
+   instructions.  */
+
+static void
+rombug_mourn_inferior ()
+{
+  remove_breakpoints ();
+  generic_mourn_inferior ();   /* Do all the proper things now */
+}
+
+#define MAX_MONITOR_BREAKPOINTS 16
+
+extern int memory_breakpoint_size;
+static CORE_ADDR breakaddr[MAX_MONITOR_BREAKPOINTS] = {0};
+
+static int
+rombug_insert_breakpoint (addr, shadow)
+     CORE_ADDR addr;
+     char *shadow;
+{
+  int i;
+
+#ifdef LOG_FILE
+  fprintf (log_file, "\nIn Insert_breakpoint (addr=%x)\n", addr);
+#endif
+  for (i = 0; i <= MAX_MONITOR_BREAKPOINTS; i++)
+    if (breakaddr[i] == 0)
+      {
+       breakaddr[i] = addr;
+       if (sr_get_debug())
+         printf ("Breakpoint at %x\n", addr);
+       rombug_read_inferior_memory(addr, shadow, memory_breakpoint_size);
+       printf_monitor(SET_BREAK_CMD, addr);
+       expect_prompt(1);
+       return 0;
+      }
+
+  fprintf(stderr, "Too many breakpoints (> 16) for monitor\n");
+  return 1;
+}
+
+/*
+ * _remove_breakpoint -- Tell the monitor to remove a breakpoint
+ */
+static int
+rombug_remove_breakpoint (addr, shadow)
+     CORE_ADDR addr;
+     char *shadow;
+{
+  int i;
+
+#ifdef LOG_FILE
+  fprintf (log_file, "\nIn Remove_breakpoint (addr=%x)\n", addr);
+#endif
+  for (i = 0; i < MAX_MONITOR_BREAKPOINTS; i++)
+    if (breakaddr[i] == addr)
+      {
+       breakaddr[i] = 0;
+       /* some monitors remove breakpoints based on the address */
+       if (strcasecmp (target_shortname, "bug") == 0)   
+           printf_monitor(CLR_BREAK_CMD, addr);
+         else
+           printf_monitor(CLR_BREAK_CMD, i);
+       expect_prompt(1);
+       return 0;
+      }
+
+  fprintf(stderr, "Can't find breakpoint associated with 0x%x\n", addr);
+  return 1;
+}
+
+/* Load a file. This is usually an srecord, which is ascii. No 
+   protocol, just sent line by line. */
+
+#define DOWNLOAD_LINE_SIZE 100
+static void
+rombug_load (arg)
+    char       *arg;
+{
+/* this part comment out for os9* */
+#if 0
+  FILE *download;
+  char buf[DOWNLOAD_LINE_SIZE];
+  int i, bytes_read;
+
+  if (sr_get_debug())
+    printf ("Loading %s to monitor\n", arg);
+
+  download = fopen (arg, "r");
+  if (download == NULL)
+    {
+    error (sprintf (buf, "%s Does not exist", arg));
+    return;
+  }
+
+  printf_monitor (LOAD_CMD);
+/*  expect ("Waiting for S-records from host... ", 1); */
+
+  while (!feof (download))
+    {
+      bytes_read = fread (buf, sizeof (char), DOWNLOAD_LINE_SIZE, download);
+      if (hashmark)
+       {
+         putchar ('.');
+         fflush (stdout);
+       }
+
+      if (SERIAL_WRITE(monitor_desc, buf, bytes_read)) {
+       fprintf(stderr, "SERIAL_WRITE failed: (while downloading) %s\n", safe_strerror(errno));
+       break;
+      }
+      i = 0;
+      while (i++ <=200000) {} ;                        /* Ugly HACK, probably needs flow control */
+      if (bytes_read < DOWNLOAD_LINE_SIZE)
+       {
+         if (!feof (download))
+           error ("Only read %d bytes\n", bytes_read);
+         break;
+       }
+    }
+
+  if (hashmark)
+    {
+      putchar ('\n');
+    }
+  if (!feof (download))
+    error ("Never got EOF while downloading");
+  fclose (download);
+#endif 0
+}
+
+/* Put a command string, in args, out to MONITOR.  
+   Output from MONITOR is placed on the users terminal until the prompt 
+   is seen. */
+
+static void
+rombug_command (args, fromtty)
+     char      *args;
+     int       fromtty;
+{
+#ifdef LOG_FILE
+  fprintf (log_file, "\nIn command (args=%s)\n", args);
+#endif
+  if (monitor_desc == NULL)
+    error("monitor target not open.");
+  
+  if (!args)
+    error("Missing command.");
+       
+  printf_monitor("%s\r", args);
+  expect_prompt(0);
+}
+
+#if 0
+/* Connect the user directly to MONITOR.  This command acts just like the
+   'cu' or 'tip' command.  Use <CR>~. or <CR>~^D to break out.  */
+
+static struct ttystate ttystate;
+
+static void
+cleanup_tty()
+{  printf("\r\n[Exiting connect mode]\r\n");
+  /*SERIAL_RESTORE(0, &ttystate);*/
+}
+
+static void
+connect_command (args, fromtty)
+     char      *args;
+     int       fromtty;
+{
+  fd_set readfds;
+  int numfds;
+  int c;
+  char cur_esc = 0;
+
+  dont_repeat();
+
+  if (monitor_desc == NULL)
+    error("monitor target not open.");
+  
+  if (args)
+    fprintf("This command takes no args.  They have been ignored.\n");
+       
+  printf("[Entering connect mode.  Use ~. or ~^D to escape]\n");
+
+  serial_raw(0, &ttystate);
+
+  make_cleanup(cleanup_tty, 0);
+
+  FD_ZERO(&readfds);
+
+  while (1)
+    {
+      do
+       {
+         FD_SET(0, &readfds);
+         FD_SET(monitor_desc, &readfds);
+         numfds = select(sizeof(readfds)*8, &readfds, 0, 0, 0);
+       }
+      while (numfds == 0);
+
+      if (numfds < 0)
+       perror_with_name("select");
+
+      if (FD_ISSET(0, &readfds))
+       {                       /* tty input, send to monitor */
+         c = getchar();
+         if (c < 0)
+           perror_with_name("connect");
+
+         printf_monitor("%c", c);
+         switch (cur_esc)
+           {
+           case 0:
+             if (c == '\r')
+               cur_esc = c;
+             break;
+           case '\r':
+             if (c == '~')
+               cur_esc = c;
+             else
+               cur_esc = 0;
+             break;
+           case '~':
+             if (c == '.' || c == '\004')
+               return;
+             else
+               cur_esc = 0;
+           }
+       }
+
+      if (FD_ISSET(monitor_desc, &readfds))
+       {
+         while (1)
+           {
+             c = readchar(0);
+             if (c < 0)
+               break;
+             putchar(c);
+           }
+         fflush(stdout);
+       }
+    }
+}
+#endif
+
+/*
+ * Define the monitor command strings. Since these are passed directly
+ * through to a printf style function, we need can include formatting
+ * strings. We also need a CR or LF on the end.
+ */
+struct monitor_ops rombug_cmds = {
+  "g \r",                              /* execute or usually GO command */
+  "g \r",                              /* continue command */
+  "gs \r",                             /* single step */
+  "b %x\r",                            /* set a breakpoint */
+  "k %x\r",                            /* clear a breakpoint */
+  "c %x\r",                            /* set memory to a value */
+  "d %x %d\r",                         /* display memory */
+  "$%08X",                             /* prompt memory commands use */
+  ".%s %x\r",                          /* set a register */
+  ":",                                 /* delimiter between registers */
+  ". \r",                              /* read a register */
+  "mf \r",                             /* download command */
+  "RomBug: ",                          /* monitor command prompt */
+  ": ",                                        /* end-of-command delimitor */
+  ".\r"                                        /* optional command terminator */
+};
+
+struct target_ops rombug_ops = {
+  "rombug",
+  "Microware's ROMBUG debug monitor",
+  "Use a remote computer running the ROMBUG debug monitor.\n\
+Specify the serial device it is connected to (e.g. /dev/ttya).",
+  rombug_open,
+  rombug_close, 
+  0,
+  rombug_detach,
+  rombug_resume,
+  rombug_wait,
+  rombug_fetch_register,
+  rombug_store_register,
+  rombug_prepare_to_store,
+  rombug_xfer_inferior_memory,
+  rombug_files_info,
+  rombug_insert_breakpoint,
+  rombug_remove_breakpoint,    /* Breakpoints */
+  0,
+  0,
+  0,
+  0,
+  0,                           /* Terminal handling */
+  rombug_kill,
+  rombug_load,                 /* load */
+  rombug_link,                 /* lookup_symbol */
+  rombug_create_inferior,
+  rombug_mourn_inferior,
+  0,                           /* can_run */
+  0,                           /* notice_signals */
+  process_stratum,
+  0,                           /* next */
+  1,
+  1,
+  1,
+  1,
+  1,                           /* has execution */
+  0,
+  0,                           /* Section pointers */
+  OPS_MAGIC,                   /* Always the last thing */
+};
+
+void
+_initialize_remote_os9k ()
+{
+  add_target (&rombug_ops);
+
+  add_show_from_set (
+        add_set_cmd ("hash", no_class, var_boolean, (char *)&hashmark,
+               "Set display of activity while downloading a file.\nWhen enabled, a period \'.\' is displayed.",
+                &setlist),
+       &showlist);
+
+  add_show_from_set (
+        add_set_cmd ("timeout", no_class, var_zinteger,
+                 (char *) &timeout,
+                 "Set timeout in seconds for remote MIPS serial I/O.",
+                 &setlist),
+        &showlist);
+
+
+  add_com ("rombug <command>", class_obscure, rombug_command,
+          "Send a command to the debug monitor."); 
+#if 0
+  add_com ("connect", class_obscure, connect_command,
+          "Connect the terminal directly up to a serial based command monitor.\nUse <CR>~. or <CR>~^D to break out.");
+#endif
+}
index a0d70950f0872da393dcd29337da853dc820f6ae..cb998bf9c4d2744f6335b87369dc365250b376f2 100644 (file)
@@ -48,7 +48,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #endif
 
 /* Global variables owned by this file */
-
+CORE_ADDR text_relocation = 0;         /* text_relocation */
 int readnow_symbol_files;              /* Read full symbols immediately */
 
 struct complaint oldsyms_complaint = {
@@ -675,7 +675,23 @@ symbol_file_command (args, from_tty)
            }
          else
            {
+           char *p;
+
              name = *argv;
+
+              /* this is for rombug remote only, to get the text relocation by
+              using link command */
+              p = strrchr(name, '/');
+              if (p != NULL) p++;
+              else p = name;
+
+              target_link(p, &text_relocation);
+
+             if (text_relocation)  
+               symbol_file_add (name, from_tty, (CORE_ADDR)text_relocation, 0, mapped, readnow);
+              else 
+               symbol_file_add (name, from_tty, (CORE_ADDR)0, 1, mapped, readnow);
+             set_initial_language ();
            }
          argv++;
        }
@@ -684,11 +700,6 @@ symbol_file_command (args, from_tty)
        {
          error ("no symbol file name was specified");
        }
-      else
-       {
-         symbol_file_add (name, from_tty, (CORE_ADDR)0, 1, mapped, readnow);
-         set_initial_language ();
-       }
       do_cleanups (cleanups);
     }
 }
@@ -972,14 +983,23 @@ add_symbol_file_command (args, from_tty)
      left pointing at the remainder of the command line, which should
      be the address expression to evaluate. */
 
-  if ((name == NULL) || (*args == '\000') )
+  if (name == NULL)
     {
-      error ("add-symbol-file takes a file name and an address");
+      error ("add-symbol-file takes a file name");
     }
   name = tilde_expand (name);
   make_cleanup (free, name);
 
-  text_addr = parse_and_eval_address (args);
+  if (*args != '\000')
+    {
+      text_addr = parse_and_eval_address (args);
+    }
+  else
+    {
+      target_link(name, &text_addr);
+      if (text_addr == (CORE_ADDR)-1)
+       error("Don't know how to get text start location for this file");
+    }
 
   /* FIXME-32x64: Assumes text_addr fits in a long.  */
   if (!query ("add symbol table from file \"%s\" at text_addr = %s?\n",
@@ -1078,10 +1098,12 @@ reread_symbols ()
          if (objfile->global_psymbols.list)
            mfree (objfile->md, objfile->global_psymbols.list);
          objfile->global_psymbols.list = NULL;
+         objfile->global_psymbols.next = NULL;
          objfile->global_psymbols.size = 0;
          if (objfile->static_psymbols.list)
            mfree (objfile->md, objfile->static_psymbols.list);
          objfile->static_psymbols.list = NULL;
+         objfile->static_psymbols.next = NULL;
          objfile->static_psymbols.size = 0;
 
          /* Free the obstacks for non-reusable objfiles */
index 038ca0d5f91317124ec19c871824cd9a6299b078..456fffd4fe2146a9742e0ba4216c4da80af09912 100644 (file)
@@ -710,6 +710,19 @@ target_detach (args, from_tty)
   (current_target->to_detach) (args, from_tty);
 }
 
+void
+target_link (modname, t_reloc)
+     char *modname;
+     CORE_ADDR *t_reloc;
+{
+  if (STREQ(current_target->to_shortname, "rombug"))
+    {
+      (current_target->to_lookup_symbol) (modname, t_reloc);
+    }
+  else
+    *t_reloc = (CORE_ADDR)-1;
+}
+
 /* Look through the list of possible targets for a target that can
    execute a run or attach command without any other data.  This is
    used to locate the default process stratum.