[comp.unix.ultrix] GDB, Gnu debugger for Ultrix 4.0

kenc@madmax.Viewlogic.COM (Kenstir) (11/06/90)

Here is a patch to get GDB 3.5 running under Ultrix 4.0.

For those not familiar with GDB:
   + You need to run it inside Emacs to really get the full effect.
   + 10,000x better than dxdb and look-alikes.

This patch includes in one shot:
   + Per Bothner's diffs (alpha version)
   + Bruce Bauman's (boot@donald.osf.org) post of 27 Sep 90 (gnu.gdb.bug)
   + Garrett Lau's (lau@efi.com) post of 26 Oct 90 (gnu.gdb.bug),
     his suggested change to the mipscoff.c:read_type function,
     and his post of 3 Nov 90 (gnu.gdb.bug)
   + Mark Reinhold's (mbr@larch.lcs.mit.edu) of 23 Oct 90 (gnu.gdb.bug)

--
Kenneth H. Cox
Viewlogic Systems, Inc.
kenstir@viewlogic.com
...!harvard!cg-atla!viewlog!kenstir

--------------------------- cut here ----------------------------
=====================================
=   Diffs for GDB 3.5, Ultrix 4.0
=====================================
= IMPORTANT:
=    Before running patch, you need to create some new files:
=       touch MIPS-NOTES m-decstatn.h m-mips.h mips-dep.c
=       touch mips-opcode.h mips-pinsn.c mipscoff.c
=    After running patch, you need to configure:
=       config.gdb decstatn
=       make
=       enjoy
=
= This patch includes in one shot:
=    + Per Bothner's diffs (alpha version)
=    + Bruce Bauman's (boot@donald.osf.org) post of 27 Sep 90 (gnu.gdb.bug)
=    + Garrett Lau's (lau@efi.com) post of 26 Oct 90 (gnu.gdb.bug),
=      his suggested change to the mipscoff.c:read_type function,
=      and his post of 3 Nov 90 (gnu.gdb.bug)
=    + Mark Reinhold's (mbr@larch.lcs.mit.edu) of 23 Oct 90 (gnu.gdb.bug)
=====================================


*** MIPS-NOTES.orig	Mon Nov  5 10:27:49 1990
--- MIPS-NOTES	Mon Nov  5 10:28:25 1990
***************
*** 0 ****
--- 1,21 ----
+ This is the alpha release of the gdb port to MIPS-based machines.
+ Only the (little-endian) DECstation3100 has been tested.
+ 
+ Here I will try to list known problems:
+ 
+ Calling a function in the debugger (as in 'print f(x)') normally
+ works correctly. One known exception is if you pass a structure
+ argument whose sizeof > 4. Currently, gdb will align it on
+ an 8-byte boundary, while the compiler while depend on
+ the alignment needed by the fields. (Unfortunately, the
+ distributed varargs.h and stdarg.h are inconsistent with
+ mips' compiler!)
+ 
+ Fortran debugging could be made nicer, but a lot of that is a
+ problem with the implementation-independent gdb.
+ 
+ Code in include files is handled poorly (missing line numbers).
+ 
+ Lots of testing is needed.
+ E.g. is IN_SIGTRAMP (in infrun.c) correct?
+ 
*** Makefile.dist.orig	Tue Jan 30 21:42:57 1990
--- Makefile.dist	Mon Nov  5 10:28:26 1990
***************
*** 328,338 ****
     cpp -M).  It does not include dependencies of .o files on .c files. */
  /* All files which depend on config.status also depend on param.h in case
     someone reconfigures gdb out from under an already compiled gdb.  */
  blockframe.o : defs.h param.h config.status symtab.h obstack.h
symseg.h frame.h 
  breakpoint.o : defs.h param.h config.status symtab.h obstack.h
symseg.h frame.h
! coffread.o : defs.h param.h config.status 
  command.o : command.h defs.h
  core.o : defs.h  param.h config.status a.out.encap.h
  dbxread.o : param.h config.status defs.h symtab.h obstack.h symseg.h
a.out.encap.h \
  	    stab.gnu.h
  environ.o : environ.h 
--- 328,338 ----
     cpp -M).  It does not include dependencies of .o files on .c files.
*/
  /* All files which depend on config.status also depend on param.h in
case
     someone reconfigures gdb out from under an already compiled gdb. 
*/
  blockframe.o : defs.h param.h config.status symtab.h obstack.h
symseg.h frame.h 
  breakpoint.o : defs.h param.h config.status symtab.h obstack.h
symseg.h frame.h
! coffread.o : defs.h param.h mipscoff.c config.status 
  command.o : command.h defs.h
  core.o : defs.h  param.h config.status a.out.encap.h
  dbxread.o : param.h config.status defs.h symtab.h obstack.h symseg.h
a.out.encap.h \
  	    stab.gnu.h
  environ.o : environ.h 
*** blockframe.c.orig	Sat Jan  6 15:34:14 1990
--- blockframe.c	Mon Nov  5 10:28:26 1990
***************
*** 261,279 ****
    prev->next = next_frame;
    prev->prev = (struct frame_info *) 0;
    prev->frame = address;
    prev->next_frame = prev->next ? prev->next->frame : 0;
  
- #ifdef INIT_EXTRA_FRAME_INFO
-   INIT_EXTRA_FRAME_INFO(prev);
- #endif
- 
    /* This entry is in the frame queue now, which is good since
       FRAME_SAVED_PC may use that queue to figure out it's value
       (see m-sparc.h).  We want the pc saved in the inferior frame. */
    prev->pc = (fromleaf ? SAVED_PC_AFTER_CALL (next_frame) :
  	      next_frame ? FRAME_SAVED_PC (next_frame) : read_pc ());
  
    return prev;
  }
  
  CORE_ADDR
--- 261,279 ----
    prev->next = next_frame;
    prev->prev = (struct frame_info *) 0;
    prev->frame = address;
    prev->next_frame = prev->next ? prev->next->frame : 0;
  
    /* This entry is in the frame queue now, which is good since
       FRAME_SAVED_PC may use that queue to figure out it's value
       (see m-sparc.h).  We want the pc saved in the inferior frame. */
    prev->pc = (fromleaf ? SAVED_PC_AFTER_CALL (next_frame) :
  	      next_frame ? FRAME_SAVED_PC (next_frame) : read_pc ());
+ 
+ #ifdef INIT_EXTRA_FRAME_INFO
+   INIT_EXTRA_FRAME_INFO(prev);
+ #endif
  
    return prev;
  }
  
  CORE_ADDR
*** breakpoint.c.orig	Wed Jan 10 18:49:07 1990
--- breakpoint.c	Mon Nov  5 10:28:27 1990
***************
*** 438,463 ****
  	last_addr = b->address;
  	if (b->symtab)
  	  {
  	    sym = find_pc_function (b->address);
  	    if (sym)
! 	      printf_filtered (" in %s (%s line %d)", SYMBOL_NAME (sym),
  			       b->symtab->filename, b->line_number);
  	    else
! 	      printf_filtered ("%s line %d", b->symtab->filename,
b->line_number);
  	  }
  	else
  	  {
  	    char *name;
  	    int addr;
  
  	    if (find_pc_partial_function (b->address, &name, &addr))
  	      {
  		if (b->address - addr)
! 		  printf_filtered ("<%s+%d>", name, b->address - addr);
  		else
! 		  printf_filtered ("<%s>", name);
  	      }
  	  }
  	      
  	printf_filtered ("\n");
  
--- 438,464 ----
  	last_addr = b->address;
  	if (b->symtab)
  	  {
  	    sym = find_pc_function (b->address);
  	    if (sym)
! 	      printf_filtered (" in %.100s (%.100s line %d)",
! 			       SYMBOL_NAME (sym),
  			       b->symtab->filename, b->line_number);
  	    else
! 	      printf_filtered ("%.100s line %d", b->symtab->filename,
b->line_number);
  	  }
  	else
  	  {
  	    char *name;
  	    int addr;
  
  	    if (find_pc_partial_function (b->address, &name, &addr))
  	      {
  		if (b->address - addr)
! 		  printf_filtered ("<%.200s+%d>", name, b->address - addr);
  		else
! 		  printf_filtered ("<%.200s>", name);
  	      }
  	  }
  	      
  	printf_filtered ("\n");
  
***************
*** 472,482 ****
  	    printf_filtered ("\n");
  	  }
  	if (l = b->commands)
  	  while (l)
  	    {
! 	      printf_filtered ("\t%s\n", l->line);
  	      l = l->next;
  	    }
        }
  
    /* Compare against (CORE_ADDR)-1 in case some compiler decides
--- 473,485 ----
  	    printf_filtered ("\n");
  	  }
  	if (l = b->commands)
  	  while (l)
  	    {
! 	      fputs_filtered (stdout, "\t");
! 	      fputs_filtered (stdout, l->line);
! 	      fputs_filtered (stdout, "\n");
  	      l = l->next;
  	    }
        }
  
    /* Compare against (CORE_ADDR)-1 in case some compiler decides
*** coffread.c.orig	Wed Jan 10 18:54:43 1990
--- coffread.c	Mon Nov  5 10:28:28 1990
***************
*** 22,31 ****
--- 22,34 ----
  
  #include <stdio.h>
  #include "defs.h"
  #include "param.h"
  #ifdef COFF_FORMAT
+ #ifdef THIRD_EYE_FORMAT
+ #include "mipscoff.c"
+ #else /* !THIRD_EYE_FORMAT */
  #include "symtab.h"
  
  #ifdef USG
  #include <sys/types.h>
  #include <fcntl.h>
***************
*** 2000,2009 ****
--- 2003,2014 ----
  }
  
  /* These will stay zero all the time */
  struct psymbol_allocation_list global_psymbols, static_psymbols;
  
+ #endif /* !THIRD_EYE_FORMAT */
+ 
  _initialize_coff ()
  {
    symfile = 0;
  
    bzero (&global_psymbols, sizeof (global_psymbols));
***************
*** 2011,2018 ****
  
    add_com ("symbol-file", class_files, symbol_file_command,
  	   "Load symbol table (in coff format) from executable file FILE.");
  }
  
- 
  #endif /* COFF_FORMAT */
- 
--- 2016,2021 ----
*** config.gdb.orig	Tue Jan 30 15:35:46 1990
--- config.gdb	Mon Nov  5 10:28:28 1990
***************
*** 319,328 ****
--- 319,341 ----
  	opcodefile=sparc-opcode.h
  	depfile=sparc-dep.c
  	;;
  convex)
  	;;
+ iris|mips)
+ 	echo "[Big-endian mips-based machines have not been tested]"
+ 	paramfile=m-mips.h
+ 	pinsnfile=mips-pinsn.c
+ 	opcodefile=mips-opcode.h
+ 	depfile=mips-dep.c
+ 	;;
+ dec-3100|decstatn)	# DECstation 3100 (alias PMAX) or DECstation 2100
+ 	paramfile=m-decstatn.h
+ 	pinsnfile=mips-pinsn.c
+ 	opcodefile=mips-opcode.h
+ 	depfile=mips-dep.c
+ 	;;
  test)
  	paramfile=one
  	pinsnfile=three
  	opcodefile=four
  	;;
*** eval.c.orig	Sun Nov  5 13:01:52 1989
--- eval.c	Mon Nov  5 10:28:29 1990
***************
*** 961,977 ****
    op = exp->elts[pc].opcode;
  
    switch (op)
      {
      case OP_VAR_VALUE:
!       if (TYPE_CODE (SYMBOL_TYPE (exp->elts[pc + 1].symbol)) ==
TYPE_CODE_ARRAY)
! 	{
! 	  (*pos) += 3;
! 	  val = locate_var_value (exp->elts[pc + 1].symbol, (CORE_ADDR) 0);
! 	  return value_cast (lookup_pointer_type (TYPE_TARGET_TYPE
(SYMBOL_TYPE (exp->elts[pc + 1].symbol))),
! 			     val);
! 	}
      }
  
    return evaluate_subexp (0, exp, pos, noside);
  }
  
--- 961,988 ----
    op = exp->elts[pc].opcode;
  
    switch (op)
      {
      case OP_VAR_VALUE:
!       {
! 	struct symbol *sym = exp->elts[pc + 1].symbol;
! 	struct type *sym_type = SYMBOL_TYPE (sym);
! 	if (TYPE_CODE (sym_type) == TYPE_CODE_ARRAY)
! 	  {
! 	    value val;
! 	    long low_bound=
! 	      TYPE_FIELD_BITPOS(TYPE_FIELD_TYPE (sym_type, 0), 0);
! 	    (*pos) += 3;
! 	    val = locate_var_value (sym, (CORE_ADDR) 0);
! 	    val = value_cast (lookup_pointer_type
(TYPE_TARGET_TYPE(sym_type)),
! 			      val);
! 	    if (low_bound)
! 	      val = value_sub (val,
! 			       value_from_long(builtin_type_long, low_bound));
! 	    return val;
! 	  }
!       }
      }
  
    return evaluate_subexp (0, exp, pos, noside);
  }
  
*** infrun.c.orig	Tue Jan 23 18:10:35 1990
--- infrun.c	Mon Nov  5 10:28:30 1990
***************
*** 173,183 ****
  static char signal_print[NSIG];
  static char signal_program[NSIG];
  
  /* Nonzero if breakpoints are now inserted in the inferior.  */
  
! static int breakpoints_inserted;
  
  /* Function inferior was in as of last step command.  */
  
  static struct symbol *step_start_function;
  
--- 173,183 ----
  static char signal_print[NSIG];
  static char signal_program[NSIG];
  
  /* Nonzero if breakpoints are now inserted in the inferior.  */
  
! int breakpoints_inserted;
  
  /* Function inferior was in as of last step command.  */
  
  static struct symbol *step_start_function;
  
*** m-decstatn.h.orig	Mon Nov  5 10:27:50 1990
--- m-decstatn.h	Mon Nov  5 10:56:26 1990
***************
*** 0 ****
--- 1,3 ----
+ #define DECSTATION
+ #define HAVE_VPRINTF
+ #include "m-mips.h"
*** m-mips.h.orig	Mon Nov  5 10:27:50 1990
--- m-mips.h	Mon Nov  5 10:28:30 1990
***************
*** 0 ****
--- 1,432 ----
+ /* Definitions to make GDB run on a MIPS-based machines.
+    Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc.
+ 
+ This file is part of GDB.
+ 
+ GDB is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+ 
+ GDB is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+ 
+ You should have received a copy of the GNU General Public License
+ along with GDB; see the file COPYING.  If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
*/
+ 
+ /* Define the bit, byte, and word ordering of the machine.  */
+ #ifndef DECSTATION
+ #define BITS_BIG_ENDIAN
+ #define BYTES_BIG_ENDIAN
+ #define WORDS_BIG_ENDIAN
+ #endif
+ 
+ #define IEEE_FLOAT
+ 
+ #define FLOAT_INFO { printf("FPA coprocessor available.\n"); }
+ 
+ /* Get rid of any system-imposed stack limit if possible.  */
+ 
+ #define SET_STACK_LIMIT_HUGE
+ 
+ /* Define this if the C compiler puts an underscore at the front
+    of external names before giving them to the linker.  */
+ 
+ #undef NAMES_HAVE_UNDERSCORE
+ 
+ /* Debugger information will be a variant of COFF */
+ 
+ /*#define READ_DBX_FORMAT*/
+ #define COFF_FORMAT
+ #define THIRD_EYE_FORMAT
+ 
+ /* We need to remember some procedure-specific values
+    to do stack traversal. Use the mips_proc_info type. */
+ 
+ #define mips_proc_info PDR
+ #define PROC_LOW_ADDR(proc) ((proc)->lnLow) /* least address */
+ #define PROC_HIGH_ADDR(proc) ((proc)->lnHigh) /* upper address bound
*/
+ #define PROC_FRAME_OFFSET(proc) ((proc)->frameoffset)
+ #define PROC_FRAME_REG(proc) ((proc)->framereg)
+ #define PROC_REG_MASK(proc) ((proc)->regmask)
+ #define PROC_FREG_MASK(proc) ((proc)->fregmask)
+ #define PROC_REG_OFFSET(proc) ((proc)->regoffset)
+ #define PROC_FREG_OFFSET(proc) ((proc)->fregoffset)
+ #define PROC_PC_REG(proc) ((proc)->pcreg)
+ #define PROC_SYMBOL(proc) (*(struct symbol**)&(proc)->isym)
+ #define _PROC_MAGIC_ 0x0F0F0F0F
+ #define PROC_DESC_IS_DUMMY(proc) ((proc)->isym == _PROC_MAGIC_)
+ #define SET_PROC_DESC_IS_DUMMY(proc) ((proc)->isym = _PROC_MAGIC_)
+ 
+ /* Offset from address of function to start of its code.
+    Zero on most machines.  */
+ 
+ #define FUNCTION_START_OFFSET 0
+ 
+ /* Advance PC across any function entry prologue instructions
+    to reach some "real" code.  */
+ 
+ #define SKIP_PROLOGUE(pc)	\
+ { register int op = read_memory_integer (pc, 4);	\
+   if ((op & 0xffff0000) == 0x27bd0000)			\
+     pc += 4;   /* Skip addiu $sp,$sp,offset */		\
+ }
+ 
+ /* Immediately after a function call, return the saved pc.
+    Can't always go through the frames for this because on some
machines
+    the new frame is not set up until the new function executes
+    some instructions.  */
+ 
+ #define SAVED_PC_AFTER_CALL(frame)
(CORE_ADDR)read_register(RA_REGNUM)
+ 
+ /* This is the amount to subtract from u.u_ar0
+    to get the offset in the core file of the register values.  */
+ 
+ #define KERNEL_U_ADDR (0x80000000 - (UPAGES * NBPG))
+ 
+ /* Address of end of stack space.  */
+ 
+ #define STACK_END_ADDR 0x7ffff000
+ 
+ /* Stack grows downward.  */
+ 
+ #define INNER_THAN <
+ 
+ /* Stack has strict alignment. However, use PUSH_ARGUMENTS
+    to take care of it. */
+ /*#define STACK_ALIGN(ADDR) (((ADDR)+7)&-8)*/
+ 
+ #define PUSH_ARGUMENTS(nargs, args, sp, struct_return, struct_addr) \
+     sp = mips_push_arguments(nargs, args, sp, struct_return,
struct_addr)
+ 
+ /* Sequence of bytes for breakpoint instruction.  */
+ 
+ #ifdef BYTES_BIG_ENDIAN
+ #define BREAKPOINT {0, 0, 0, 13}
+ #else
+ #define BREAKPOINT {13, 0, 0, 0}
+ #endif
+ 
+ /* Amount PC must be decremented by after a breakpoint.
+    This is often the number of bytes in BREAKPOINT
+    but not always.  */
+ 
+ #define DECR_PC_AFTER_BREAK 0
+ 
+ /* Nonzero if instruction at PC is a return instruction.  */
+ /* For Mips, this is jr $ra */
+ 
+ #define ABOUT_TO_RETURN(pc) \
+   (read_memory_integer (pc, 4) == 0x03e00008)
+ 
+ /* Return 1 if P points to an invalid floating point value.
+    LEN is the length in bytes -- not relevant on the Vax.  */
+ 
+ #define INVALID_FLOAT(p, len) ((*(short *) p & 0xff80) == 0x8000)
+ 
+ /* Largest integer type */
+ #define LONGEST long
+ 
+ /* Name of the builtin type for the LONGEST type above. */
+ #define BUILTIN_TYPE_LONGEST builtin_type_long
+ 
+ /* Say how long (ordinary) registers are.  */
+ 
+ #define REGISTER_TYPE long
+ 
+ /* Number of machine registers */
+ 
+ #define NUM_REGS 71
+ 
+ /* Initializer for an array of names of registers.
+    There should be NUM_REGS strings in this initializer.  */
+ 
+ /* Note that the symbol table parsing of scRegister symbols
+  * assumes r0=0, ..., r3=31, and f0=32, ... f31=32+31 */
+ 
+ #ifdef NUMERIC_REG_NAMES
+ #define REGISTER_NAMES {"r0", "r1", "r2", "r3", "r4", "r5", "r6",
"r7",\
+   "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",\
+   "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",\
+   "r24", "r25", "r26", "r27", "gp", "sp", "r30", "ra",	\
+   "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",	\
+   "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",	\
+   "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",\
+   "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",\
+   "pc", "cause", "hi", "lo", "fcrcs", "fcrir", "fp" };
+ #else /* !NUMERIC_REG_NAMES */
+ #define REGISTER_NAMES {"zero", "at", "v0", "v1", "a0", "a1", "a2",
"a3",\
+   "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",\
+   "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",\
+   "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra",	\
+   "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",	\
+   "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",	\
+   "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",\
+   "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",\
+   "pc", "cause", "hi", "lo", "fcrcs", "fcrir", "fp" };
+ #endif /* !NUMERIC_REG_NAMES */
+ 
+ /* Register numbers of various important registers.
+    Note that some of these values are "real" register numbers,
+    and correspond to the general registers of the machine,
+    and some are "phony" register numbers which are too large
+    to be actual register numbers as far as the user is concerned
+    but do serve to get the desired values when passed to
read_register.  */
+ 
+ /* Note the FP is a "virtual" register */
+ #define SP_REGNUM 29		/* Contains address of top of stack */
+ #define RA_REGNUM 31		/* Contains return address value */
+ #define FP0_REGNUM 32		/* Floating point register 0 (single float) */
+ #define PC_REGNUM 64		/* Contains program counter */
+ #define CAUSE_REGNUM 65
+ #define HI_REGNUM 66		/* Multiple/divide temp */
+ #define LO_REGNUM 67		/* ... */
+ #define FCRCS_REGNUM 68		/* FP control/status */
+ #define FCRIR_REGNUM 69		/* FP implementation/revision */
+ #define FP_REGNUM 70		/* Pseudo register that contains true address of
executing stack frame */
+ 
+ /* Define DO_REGISTERS_INFO() to do machine-specific formatting
+    of register dumps. */
+ 
+ #define DO_REGISTERS_INFO(_regnum) mips_do_registers_info(_regnum)
+ 
+ /* Total amount of space needed to store our copies of the machine's
+    register state, the array `registers'.  */
+ #define REGISTER_BYTES (4*NUM_REGS)
+ 
+ /* Index within `registers' of the first byte of the space for
+    register N.  */
+ 
+ #define REGISTER_BYTE(N) ((N) * 4)
+ 
+ /* Number of bytes of storage in the actual machine representation
+    for register N.*/
+ 
+ #define REGISTER_RAW_SIZE(N) 4
+ 
+ /* Number of bytes of storage in the program's representation
+    for register N.*/
+ 
+ #define REGISTER_VIRTUAL_SIZE(N) 4
+ 
+ /* Largest value REGISTER_RAW_SIZE can have.  */
+ 
+ #define MAX_REGISTER_RAW_SIZE 4
+ 
+ /* Largest value REGISTER_VIRTUAL_SIZE can have.  */
+ 
+ #define MAX_REGISTER_VIRTUAL_SIZE 4
+ 
+ /* Nonzero if register N requires conversion
+    from raw format to virtual format.  */
+ 
+ #define REGISTER_CONVERTIBLE(N) 0
+ 
+ /* Convert data from raw format for register REGNUM
+    to virtual format for register REGNUM.  */
+ 
+ #define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,FROM,TO)	\
+ { bcopy ((FROM), (TO), REGISTER_RAW_SIZE(REGNUM)); }
+ 
+ /* Convert data from virtual format for register REGNUM
+    to raw format for register REGNUM.  */
+ 
+ #define REGISTER_CONVERT_TO_RAW(REGNUM,FROM,TO)	\
+ { bcopy ((FROM), (TO), REGISTER_RAW_SIZE(REGNUM)); }
+ 
+ /* Return the GDB type object for the "standard" data type
+    of data in register N.  */
+ 
+ #define REGISTER_VIRTUAL_TYPE(N) \
+  ((N) < FP0_REGNUM ? builtin_type_int : (N) < PC_REGNUM ? 	\
+    builtin_type_float : builtin_type_int)
+ 
+ /* Store the address of the place in which to copy the structure the
+    subroutine will return.  This is called from call_function. */
+ 
+ #define STORE_STRUCT_RETURN(ADDR, SP) SP = push_word(SP, ADDR)
+ 
+ /* Extract from an array REGBUF containing the (raw) register state
+    a function return value of type TYPE, and copy that, in virtual
format,
+    into VALBUF.  */
+ 
+ #define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \
+   bcopy (REGBUF+REGISTER_BYTE (TYPE_CODE (TYPE) == TYPE_CODE_FLT ?
FP0_REGNUM : 2), VALBUF, TYPE_LENGTH (TYPE))
+ 
+ /* Write into appropriate registers a function return value
+    of type TYPE, given in virtual format.  */
+ 
+ #define STORE_RETURN_VALUE(TYPE,VALBUF) \
+   write_register_bytes (REGISTER_BYTE (TYPE_CODE (TYPE) ==
TYPE_CODE_FLT ? FP0_REGNUM : 2), VALBUF, TYPE_LENGTH (TYPE))
+ 
+ /* Extract from an array REGBUF containing the (raw) register state
+    the address in which a function should return its structure value,
+    as a CORE_ADDR (or an expression that can be used as one).  */
+ 
+ #define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) (*(int *)((REGBUF)+16))
+ 
+ /* Compensate for lack of `vprintf' function.  */
+ #ifndef HAVE_VPRINTF
+ #define vprintf(format, ap) _doprnt (format, ap, stdout)
+ #endif /* not HAVE_VPRINTF */
+ 
+ /* Describe the pointer in each stack frame to the previous stack
frame
+    (its caller).  */
+ 
+ /* FRAME_CHAIN takes a frame's nominal address
+    and produces the frame's chain-pointer.
+ 
+    FRAME_CHAIN_COMBINE takes the chain pointer and the frame's nominal
address
+    and produces the nominal address of the caller frame.
+ 
+    However, if FRAME_CHAIN_VALID returns zero,
+    it means the given frame is the outermost one and has no caller.
+    In that case, FRAME_CHAIN_COMBINE is not used.  */
+ 
+ /* In the case of the Vax, the frame's nominal address is the FP
value,
+    and 12 bytes later comes the saved previous FP value as a 4-byte
word.  */
+ 
+ #define EXTRA_FRAME_INFO \
+   char *proc_desc; /* actually, a PDR* */\
+   int num_args;\
+   struct frame_saved_regs *saved_regs;
+ #define INIT_EXTRA_FRAME_INFO(fci) init_extra_frame_info(fci)
+ 
+ #define FRAME_CHAIN(thisframe) (FRAME_ADDR)frame_chain(thisframe)
+ 
+ #define FRAME_CHAIN_VALID(chain, thisframe) (chain != 0)
+ 
+ #define FRAME_CHAIN_COMBINE(chain, thisframe) (chain)
+ 
+ /* Define other aspects of the stack frame.  */
+ 
+ /* A macro that tells us whether the function invocation represented
+    by FI does not have a frame on the stack associated with it.  If
it
+    does not, FRAMELESS is set to 1, else 0.  */
+ #define FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS)  {(FRAMELESS) =
0;}
+ 
+ /* Saved Pc.  */
+ 
+ #define FRAME_SAVED_PC(FRAME) frame_saved_pc(FRAME) 
+ 
+ /* If the argument is on the stack, it will be here. */
+ #define FRAME_ARGS_ADDRESS(fi) ((fi)->frame)
+ 
+ #define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame)
+ 
+ /* Return number of args passed to a frame.
+    Can return -1, meaning no way to tell.  */
+ 
+ #define FRAME_NUM_ARGS(numargs, fi)  (numargs = (fi)->num_args)
+ 
+ /* Return number of bytes at start of arglist that are not really
args.  */
+ 
+ #define FRAME_ARGS_SKIP 0
+ 
+ /* Put here the code to store, into a struct frame_saved_regs,
+    the addresses of the saved registers of frame described by
FRAME_INFO.
+    This includes special registers such as pc and fp saved in special
+    ways in the stack frame.  sp is even more special:
+    the address we return for it IS the sp for the next frame.  */
+ 
+ #define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) ( \
+   (frame_saved_regs) = *(frame_info)->saved_regs, \
+   (frame_saved_regs).regs[SP_REGNUM] = (frame_info)->frame)
+ 
+ /* Things needed for making the inferior call functions.  */
+ 
+ /* Push an empty stack frame, to record the current PC, etc.  */
+ 
+ #define PUSH_DUMMY_FRAME {push_dummy_frame();}
+ #if 0
+ { register CORE_ADDR sp = read_register (SP_REGNUM);\
+   register int regnum;				    \
+   sp = push_word (sp, 0); /* arglist */		    \
+   for (regnum = 11; regnum >= 0; regnum--)	    \
+     sp = push_word (sp, read_register (regnum));    \
+   sp = push_word (sp, read_register (PC_REGNUM));   \
+   sp = push_word (sp, read_register (FP_REGNUM));   \
+   sp = push_word (sp, 0); 			    \
+   write_register (SP_REGNUM, sp);		    \
+   write_register (FP_REGNUM, sp);      }
+ #endif
+ 
+ /* Discard from the stack the innermost frame, restoring all
registers.  */
+ 
+ #define POP_FRAME {pop_frame();}
+ 
+ #define MK_OP(op,rs,rt,offset)
(((op)<<26)|((rs)<<21)|((rt)<<16)|(offset))
+ #define CALL_DUMMY_SIZE 48
+ #define Dest_Reg 2
+ #define CALL_DUMMY {\
+  (017<<26)| (Dest_Reg << 16),	/*lui $r31,<target upper 16 bits>*/ \
+  MK_OP(13,Dest_Reg,Dest_Reg,0),	/*ori $r31,$r31,<lower 16 bits>*/ \
+  MK_OP(061,SP_REGNUM,12,0),	/* lwc1 $f12,0(sp) */\
+  MK_OP(061,SP_REGNUM,13,4),	/* lwc1 $f13,4(sp) */\
+  MK_OP(061,SP_REGNUM,14,8),	/* lwc1 $f14,8(sp) */\
+  MK_OP(061,SP_REGNUM,15,12),	/* lwc1 $f15,12(sp) */\
+  MK_OP(043,SP_REGNUM,4,0),	/* lw $r4,0(sp) */\
+  MK_OP(043,SP_REGNUM,5,4),	/* lw $r5,4(sp) */\
+  MK_OP(043,SP_REGNUM,6,8),	/* lw $r6,8(sp) */\
+  (Dest_Reg<<21) | (31<<11) | 9,	/* jalr $r31 */\
+  MK_OP(043,SP_REGNUM,7,12),	/* lw $r7,12(sp) */\
+  13,				/* bpt */\
+ }
+ 
+ #define CALL_DUMMY_START_OFFSET 0  /* Start execution at beginning of
dummy */
+ 
+ /* Insert the specified number of args and function address
+    into a call sequence of the above form stored at DUMMYNAME.  */
+ 
+ #define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, type)   \
+   (*(int *)dummyname |= (((unsigned long)(fun)) >> 16), \
+    ((int*)dummyname)[1] |= (unsigned short)(fun))
+ 
+ 
+ /* Interface definitions for kernel debugger KDB.  */
+ 
+ /* Map machine fault codes into signal numbers.
+    First subtract 0, divide by 4, then index in a table.
+    Faults for which the entry in this table is 0
+    are not handled by KDB; the program's own trap handler
+    gets to handle then.  */
+ 
+ #define FAULT_CODE_ORIGIN 0
+ #define FAULT_CODE_UNITS 4
+ #define FAULT_TABLE    \
+ { 0, SIGKILL, SIGSEGV, 0, 0, 0, 0, 0, \
+   0, 0, SIGTRAP, SIGTRAP, 0, 0, 0, 0, \
+   0, 0, 0, 0, 0, 0, 0, 0}
+ 
+ /* Start running with a stack stretching from BEG to END.
+    BEG and END should be symbols meaningful to the assembler.
+    This is used only for kdb.  */
+ 
+ #define INIT_STACK(beg, end)  \
+ { asm (".globl end");         \
+   asm ("movl $ end, sp");      \
+   asm ("clrl fp"); }
+ 
+ /* Push the frame pointer register on the stack.  */
+ #define PUSH_FRAME_PTR        \
+   asm ("pushl fp");
+ 
+ /* Copy the top-of-stack to the frame pointer register.  */
+ #define POP_FRAME_PTR  \
+   asm ("movl (sp), fp");
+ 
+ /* After KDB is entered by a fault, push all registers
+    that GDB thinks about (all NUM_REGS of them),
+    so that they appear in order of ascending GDB register number.
+    The fault code will be on the stack beyond the last register.  */
+ 
+ #define PUSH_REGISTERS   { abort(); }
+ 
+ /* Assuming the registers (including processor status) have been
+    pushed on the stack in order of ascending GDB register number,
+    restore them and return to the address in the saved PC register. 
*/
+ 
+ #define POP_REGISTERS { abort(); }
*** mips-dep.c.orig	Mon Nov  5 10:27:50 1990
--- mips-dep.c	Mon Nov  5 10:28:31 1990
***************
*** 0 ****
--- 1,1151 ----
+ /* Low level interface to ptrace, for GDB when running under Unix.
+    Copyright (C) 1988, 1989 Free Software Foundation, Inc.
+ 
+ This file is part of GDB.
+ 
+ GDB is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+ 
+ GDB is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+ 
+ You should have received a copy of the GNU General Public License
+ along with GDB; see the file COPYING.  If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
*/
+ 
+ /*
+  * The port to MIPS-based machines was mostly done
+  * by Per Bothner, bothner@cs.wisc.edu.
+  * The inspiration for the heuristics to deal with missing
+  * symbol tables, as well as many of the specific ideas for doing so,
+  * comes from Alessando Forin (Alessando.Forin@spice.cs.cmu.edu).
+  */
+ #include "defs.h"
+ #include "param.h"
+ #include "frame.h"
+ #include "inferior.h"
+ #include "value.h"
+ 
+ #ifdef USG
+ #include <sys/types.h>
+ #endif
+ 
+ #include <stdio.h>
+ #include <sys/param.h>
+ #include <sys/ptrace.h>
+ #include <sys/dir.h>
+ #include <signal.h>
+ #include <sys/ioctl.h>
+ /* #include <fcntl.h>  Can we live without this?  */
+ 
+ #ifdef COFF_ENCAPSULATE
+ #include "a.out.encap.h"
+ #else
+ #include <a.out.h>
+ #endif
+ #ifndef N_SET_MAGIC
+ #define N_SET_MAGIC(exec, val) ((exec).a_magic = (val))
+ #endif
+ #define VM_MIN_ADDRESS (unsigned)0x400000
+ #include <sys/user.h>		/* After a.out.h  */
+ #include <sys/file.h>
+ #include <sys/stat.h>
+ #include <machine/reg.h>
+ 
+ #ifdef COFF_FORMAT
+ #include "symtab.h"
+ 
+ #ifdef USG
+ #include <sys/types.h>
+ #include <fcntl.h>
+ #endif
+ 
+ #include <obstack.h>
+ /*#include <sys/param.h>*/
+ /*#include <sys/file.h>*/
+ 
+ extern void close ();
+ 
+ extern PDR *proc_desc_table;
+ extern long proc_desc_length;
+ 
+ struct linked_proc_info
+ {
+   mips_proc_info info;
+   struct linked_proc_info *next;
+ } * linked_proc_desc_table = NULL;
+ 
+ extern int errno;
+ 
+ /* This function simply calls ptrace with the given arguments.  
+    It exists so that all calls to ptrace are isolated in this 
+    machine-dependent file. */
+ int
+ call_ptrace (request, pid, arg3, arg4)
+      int request, pid, arg3, arg4;
+ {
+   return ptrace (request, pid, arg3, arg4);
+ }
+ 
+ kill_inferior ()
+ {
+   if (remote_debugging)
+     return;
+   if (inferior_pid == 0)
+     return;
+   ptrace (8, inferior_pid, 0, 0);
+   wait (0);
+   inferior_died ();
+ }
+ 
+ /* This is used when GDB is exiting.  It gives less chance of
error.*/
+ 
+ kill_inferior_fast ()
+ {
+   if (remote_debugging)
+     return;
+   if (inferior_pid == 0)
+     return;
+   ptrace (8, inferior_pid, 0, 0);
+   wait (0);
+ }
+ 
+ /* Resume execution of the inferior process.
+    If STEP is nonzero, single-step it.
+    If SIGNAL is nonzero, give it that signal.  */
+ 
+ void
+ resume (step, signal)
+      int step;
+      int signal;
+ {
+   errno = 0;
+   if (remote_debugging)
+     remote_resume (step, signal);
+   else
+     {
+       ptrace (step ? 9 : 7, inferior_pid, 1, signal);
+       if (errno)
+ 	perror_with_name ("ptrace");
+     }
+ }
+ 
+ static char register_ptrace_map[NUM_REGS] = {
+     /* general registers */
+     0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+     16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+     /* floating-point registers */
+     32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+     48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+     /* special registers */
+     PC, /* 96, pc */
+     CAUSE, /* 97,cause */
+     MMHI, /* 98,mdhi */
+     MMLO, /* 99,mdlow */
+     FPC_CSR,/* 100,fpc_csr */
+     FPC_EIR,/* 101,fpc_eir */
+     -1 /* fp */
+   };
+     
+ void
+ fetch_inferior_registers ()
+ {
+   register int regno;
+   register unsigned int regaddr;
+   char buf[MAX_REGISTER_RAW_SIZE];
+   register int i;
+ 
+   struct user u;
+ 
+   for (regno = 0; regno < NUM_REGS; regno++)
+     {
+       regaddr = register_ptrace_map[regno];
+       if (regaddr < 0) continue;
+       for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int))
+  	{
+  	  *(int *) &buf[i] = ptrace (3, inferior_pid, regaddr, 0);
+  	  regaddr++;
+  	}
+       supply_register (regno, buf);
+     }
+   /* for now, make FP = SP */
+   *(long*)buf = read_register(SP_REGNUM);
+   supply_register(FP_REGNUM, buf);
+ }
+ 
+ /* Store our register values back into the inferior.
+    If REGNO is -1, do this for all registers.
+    Otherwise, REGNO specifies which register (so we can save time). 
*/
+ 
+ store_inferior_registers (regno)
+      int regno;
+ {
+   register unsigned int regaddr;
+   char buf[80];
+   extern char registers[];
+   unsigned int i;
+ 
+   if (regno > FP_REGNUM)
+     return;
+   if (regno >= 0)
+     {
+       regaddr = register_ptrace_map[regno];
+       for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(int))
+ 	{
+ 	  errno = 0;
+ 	  ptrace (PT_WRITE_U, inferior_pid, regaddr,
+ 		  *(int *) &registers[REGISTER_BYTE (regno) + i]);
+ 	  if (errno != 0 && regno != CAUSE_REGNUM)
+ 	    {
+ 	      sprintf (buf, "writing register number %d(ptrace#%d)",
+ 		       regno, regaddr);
+ 	      perror_with_name (buf);
+ 	    }
+ 	  regaddr++;
+ 	}
+       return;
+     }
+ 
+  if (read_register (0) != 0)
+    {
+      int zero = 0;
+      error ("Cannot change register 0.");
+      supply_register (regno, &zero);
+    }
+   for (regno = 1; regno < FP_REGNUM; regno++)
+     {
+       regaddr = register_ptrace_map[regno];
+       if (regaddr < 0) continue;
+       for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(int))
+ 	{
+ 	  errno = 0;
+ 	  ptrace (PT_WRITE_U, inferior_pid, regaddr,
+ 		  *(int *) &registers[REGISTER_BYTE (regno) + i]);
+ 	  if (errno != 0)
+ 	    {
+ 	      sprintf (buf, "writing all regs, number %d(ptrace#%d)",
+ 		       regno, regaddr);
+ 	      perror_with_name (buf);
+ 	    }
+ 	  regaddr++;
+ 	}
+     }
+ }
+ 
+ /* Copy LEN bytes from inferior's memory starting at MEMADDR
+    to debugger memory starting at MYADDR. 
+    On failure (cannot read from inferior, usually because address is
out
+    of bounds) returns the value of errno. */
+ 
+ int
+ read_inferior_memory (memaddr, myaddr, len)
+      CORE_ADDR memaddr;
+      char *myaddr;
+      int len;
+ {
+   register int i;
+   /* Round starting address down to longword boundary.  */
+   register CORE_ADDR addr = memaddr & - sizeof (int);
+   /* Round ending address up; get number of longwords that makes.  */
+   register int count
+     = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int);
+   /* Allocate buffer of that many longwords.  */
+   register int *buffer = (int *) alloca (count * sizeof (int));
+   extern int errno;
+ 
+   /* Read all the longwords */
+   for (i = 0; i < count; i++, addr += sizeof (int))
+     {
+       errno = 0;
+ #if 0
+ This is now done by read_memory, because when this function did it,
+   reading a byte or short int hardware port read whole longs, causing
+   serious side effects
+   such as bus errors and unexpected hardware operation.  This would
+   also be a problem with ptrace if the inferior process could read
+   or write hardware registers, but that's not usually the case.
+       if (remote_debugging)
+ 	buffer[i] = remote_fetch_word (addr);
+       else
+ #endif
+ 	buffer[i] = ptrace (1, inferior_pid, addr, 0);
+       if (errno)
+ 	return errno;
+     }
+ 
+   /* Copy appropriate bytes out of the buffer.  */
+   bcopy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr,
len);
+   return 0;
+ }
+ 
+ /* Copy LEN bytes of data from debugger memory at MYADDR
+    to inferior's memory at MEMADDR.
+    On failure (cannot write the inferior)
+    returns the value of errno.  */
+ 
+ int
+ write_inferior_memory (memaddr, myaddr, len)
+      CORE_ADDR memaddr;
+      char *myaddr;
+      int len;
+ {
+   register int i;
+   /* Round starting address down to longword boundary.  */
+   register CORE_ADDR addr = memaddr & - sizeof (int);
+   /* Round ending address up; get number of longwords that makes.  */
+   register int count
+     = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int);
+   /* Allocate buffer of that many longwords.  */
+   register int *buffer = (int *) alloca (count * sizeof (int));
+   extern int errno;
+ 
+   /* Fill start and end extra bytes of buffer with existing memory
data.  */
+ 
+   if (remote_debugging)
+     buffer[0] = remote_fetch_word (addr);
+   else
+     buffer[0] = ptrace (1, inferior_pid, addr, 0);
+ 
+   if (count > 1)
+     {
+       if (remote_debugging)
+ 	buffer[count - 1]
+ 	  = remote_fetch_word (addr + (count - 1) * sizeof (int));
+       else
+ 	buffer[count - 1]
+ 	  = ptrace (1, inferior_pid,
+ 		    addr + (count - 1) * sizeof (int), 0);
+     }
+ 
+   /* Copy data to be written over corresponding part of buffer */
+ 
+   bcopy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)),
len);
+ 
+   /* Write the entire buffer.  */
+ 
+   for (i = 0; i < count; i++, addr += sizeof (int))
+     {
+       errno = 0;
+       if (remote_debugging)
+ 	remote_store_word (addr, buffer[i]);
+       else
+ 	ptrace (4, inferior_pid, addr, buffer[i]);
+       if (errno)
+ 	return errno;
+     }
+ 
+   return 0;
+ }
+ 
+ /* Work with core dump and executable files, for GDB. 
+    This code would be in core.c if it weren't machine-dependent. */
+ 
+ #ifndef N_TXTADDR
+ #define N_TXTADDR(hdr) 0
+ #endif /* no N_TXTADDR */
+ 
+ #ifndef N_DATADDR
+ #define N_DATADDR(hdr) hdr.a_text
+ #endif /* no N_DATADDR */
+ 
+ /* Make COFF and non-COFF names for things a little more compatible
+    to reduce conditionals later.  */
+ 
+ #ifdef COFF_FORMAT
+ #define a_magic magic
+ #endif
+ 
+ #ifndef COFF_FORMAT
+ #ifndef AOUTHDR
+ #define AOUTHDR struct exec
+ #endif
+ #endif
+ 
+ extern char *sys_siglist[];
+ 
+ 
+ /* Hook for `exec_file_command' command to call.  */
+ 
+ extern void (*exec_file_display_hook) ();
+    
+ /* File names of core file and executable file.  */
+ 
+ extern char *corefile;
+ extern char *execfile;
+ 
+ /* Descriptors on which core file and executable file are open.
+    Note that the execchan is closed when an inferior is created
+    and reopened if the inferior dies or is killed.  */
+ 
+ extern int corechan;
+ extern int execchan;
+ 
+ /* Last modification time of executable file.
+    Also used in source.c to compare against mtime of a source file. 
*/
+ 
+ extern int exec_mtime;
+ 
+ /* Virtual addresses of bounds of the two areas of memory in the core
file.  */
+ 
+ extern CORE_ADDR data_start;
+ extern CORE_ADDR data_end;
+ extern CORE_ADDR stack_start;
+ extern CORE_ADDR stack_end;
+ 
+ /* Virtual addresses of bounds of two areas of memory in the exec
file.
+    Note that the data area in the exec file is used only when there is
no core file.  */
+ 
+ extern CORE_ADDR text_start;
+ extern CORE_ADDR text_end;
+ 
+ extern CORE_ADDR exec_data_start;
+ extern CORE_ADDR exec_data_end;
+ 
+ /* Address in executable file of start of text area data.  */
+ 
+ extern int text_offset;
+ 
+ /* Address in executable file of start of data area data.  */
+ 
+ extern int exec_data_offset;
+ 
+ /* Address in core file of start of data area data.  */
+ 
+ extern int data_offset;
+ 
+ /* Address in core file of start of stack area data.  */
+ 
+ extern int stack_offset;
+ 
+ /* various coff data structures */
+ 
+ extern FILHDR file_hdr;
+ extern SCNHDR text_hdr;
+ extern SCNHDR data_hdr;
+ 
+ #endif /* not COFF_FORMAT */
+ 
+ /* a.out header saved in core file.  */
+   
+ extern AOUTHDR core_aouthdr;
+ 
+ /* a.out header of exec file.  */
+ 
+ extern AOUTHDR exec_aouthdr;
+ 
+ extern void validate_files ();
+ 
+ core_file_command (filename, from_tty)
+      char *filename;
+      int from_tty;
+ {
+   int val;
+   extern char registers[];
+ 
+   /* Discard all vestiges of any previous core file
+      and mark data and stack spaces as empty.  */
+ 
+   if (corefile)
+     free (corefile);
+   corefile = 0;
+ 
+   if (corechan >= 0)
+     close (corechan);
+   corechan = -1;
+ 
+   data_start = 0;
+   data_end = 0;
+   stack_start = STACK_END_ADDR;
+   stack_end = STACK_END_ADDR;
+ 
+   /* Now, if a new core file was specified, open it and digest it. 
*/
+ 
+   if (filename)
+     {
+       filename = tilde_expand (filename);
+       make_cleanup (free, filename);
+       
+       if (have_inferior_p ())
+ 	error ("To look at a core file, you must kill the inferior with
\"kill\".");
+       corechan = open (filename, O_RDONLY, 0);
+       if (corechan < 0)
+ 	perror_with_name (filename);
+       /* 4.2-style (and perhaps also sysV-style) core dump file.  */
+       {
+ 	struct user u;
+ 
+ 	unsigned int reg_offset;
+ 
+ 	val = myread (corechan, &u, sizeof u);
+ 	if (val < 0)
+ 	  perror_with_name ("Not a core file: reading upage");
+ 	if (val != sizeof u)
+ 	  error ("Not a core file: could only read %d bytes", val);
+ 	data_start = exec_data_start;
+ 
+ 	data_end = data_start + NBPG * u.u_dsize;
+ 	stack_start = stack_end - NBPG * u.u_ssize;
+ 	data_offset = NBPG * UPAGES;
+ 	stack_offset = NBPG * (UPAGES + u.u_dsize);
+ 
+ 	/* Some machines put an absolute address in here and some put
+ 	   the offset in the upage of the regs.  */
+ 	reg_offset = (int) u.u_ar0;
+ 	if (reg_offset > NBPG * UPAGES)
+ 	  reg_offset -= KERNEL_U_ADDR;
+ 
+ 	/* I don't know where to find this info.
+ 	   So, for now, mark it as not available.  */
+ 	N_SET_MAGIC (core_aouthdr, 0);
+ 
+ 	/* Read the register values out of the core file and store
+ 	   them where `read_register' will find them.  */
+ 
+ 	{
+ 	  register int regno;
+ 	  char buf[MAX_REGISTER_RAW_SIZE];
+ 
+ 	  *(long*)buf = 0;
+ 	  supply_register (regno, buf);
+ 
+ 	  for (regno = 1; regno < NUM_REGS; regno++)
+ 	    {
+ 	      int offset;
+ 
+ #define PCB_OFFSET(FIELD) ((int)&((struct user*)0)->u_pcb.FIELD)
+ 	      if (regno < FP0_REGNUM)
+ 		  offset =  UPAGES*NBPG-EF_SIZE+4*((regno)+EF_AT-1);
+ 	      else if (regno < PC_REGNUM)
+ 		  offset = PCB_OFFSET(pcb_fpregs[0]) + 4*(regno-FP0_REGNUM);
+ 	      else if (regno == LO_REGNUM)
+ 		  offset = UPAGES*NBPG-EF_SIZE+4*EF_MDLO;
+ 	      else if (regno == HI_REGNUM)
+ 		  offset = UPAGES*NBPG-EF_SIZE+4*EF_MDHI;
+ 	      else if (regno == PC_REGNUM)
+ 		  offset = UPAGES*NBPG-EF_SIZE+4*EF_EPC;
+ 	      else if (regno == CAUSE_REGNUM)
+ 		  offset = UPAGES*NBPG-EF_SIZE+4*EF_CAUSE;
+ 	      else if (regno == FCRIR_REGNUM)
+ 		  offset = PCB_OFFSET(pcb_fpc_eir);
+ 	      else if (regno == FCRCS_REGNUM)
+ 		  offset = PCB_OFFSET(pcb_fpc_csr);
+ 	      else
+ 		  continue;
+ 
+ 	      val = lseek (corechan, offset, 0);
+ 	      if (val < 0
+ 		  || (val = myread (corechan, buf, sizeof buf)) < 0)
+ 		{
+ 		  char * buffer = (char *) alloca (strlen (reg_names[regno])
+ 						   + 30);
+ 		  strcpy (buffer, "Reading register ");
+ 		  strcat (buffer, reg_names[regno]);
+ 						   
+ 		  perror_with_name (buffer);
+ 		}
+ 
+ 	      supply_register (regno, buf);
+ 	    }
+ 	}
+       }
+       if (filename[0] == '/')
+ 	corefile = savestring (filename, strlen (filename));
+       else
+ 	{
+ 	  corefile = concat (current_directory, "/", filename);
+ 	}
+ 
+       set_current_frame ( create_new_frame (read_register
(FP_REGNUM),
+ 					    read_pc ()));
+       select_frame (get_current_frame (), 0);
+       validate_files ();
+     }
+   else if (from_tty)
+     printf ("No core file now.\n");
+ }
+ 
+ exec_file_command (filename, from_tty)
+      char *filename;
+      int from_tty;
+ {
+   int val;
+ 
+   /* Eliminate all traces of old exec file.
+      Mark text segment as empty.  */
+ 
+   if (execfile)
+     free (execfile);
+   execfile = 0;
+   data_start = 0;
+   data_end -= exec_data_start;
+   text_start = 0;
+   text_end = 0;
+   exec_data_start = 0;
+   exec_data_end = 0;
+   if (execchan >= 0)
+     close (execchan);
+   execchan = -1;
+ 
+   /* Now open and digest the file the user requested, if any.  */
+ 
+   if (filename)
+     {
+       filename = tilde_expand (filename);
+       make_cleanup (free, filename);
+       
+       execchan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0,
+ 			&execfile);
+       if (execchan < 0)
+ 	perror_with_name (filename);
+ 
+       {
+ 	int aout_hdrsize;
+ 	int num_sections;
+ 
+ 	if (read_file_hdr (execchan, &file_hdr) < 0)
+ 	  error ("\"%s\": not in executable format.", execfile);
+ 
+ 	aout_hdrsize = file_hdr.f_opthdr;
+ 	num_sections = file_hdr.f_nscns;
+ 
+ 	if (read_aout_hdr (execchan, &exec_aouthdr, aout_hdrsize) < 0)
+ 	  error ("\"%s\": can't read optional aouthdr", execfile);
+ 
+ 	if (read_section_hdr (execchan, _TEXT, &text_hdr, num_sections) < 0)
+ 	  error ("\"%s\": can't read text section header", execfile);
+ 
+ 	if (read_section_hdr (execchan, _DATA, &data_hdr, num_sections) < 0)
+ 	  error ("\"%s\": can't read data section header", execfile);
+ 
+ 	text_start = exec_aouthdr.text_start;
+ 	text_end = text_start + exec_aouthdr.tsize;
+ 	text_offset = 0; /* text_hdr.s_scnptr */
+ 	exec_data_start = exec_aouthdr.data_start;
+ 	exec_data_end = exec_data_start + exec_aouthdr.dsize;
+ 	exec_data_offset = exec_aouthdr.tsize; /*data_hdr.s_scnptr;*/
+ 	data_start = exec_data_start;
+ 	data_end += exec_data_start;
+ 	exec_mtime = file_hdr.f_timdat;
+       }
+ 
+       validate_files ();
+     }
+   else if (from_tty)
+     printf ("No exec file now.\n");
+ 
+   /* Tell display code (if any) about the changed file name.  */
+   if (exec_file_display_hook)
+     (*exec_file_display_hook) (filename);
+ }
+ 
+ #define READ_FRAME_REG(fi, regno) read_next_frame_reg((fi)->next,
regno)
+ 
+ int
+ read_next_frame_reg(fi, regno)
+      FRAME fi;
+      int regno;
+ {
+   for (; fi; fi = fi->next)
+       if (regno == SP_REGNUM) return fi->frame;
+       else if (fi->saved_regs->regs[regno])
+ 	return read_memory_integer(fi->saved_regs->regs[regno], 4);
+   return read_register(regno);
+ }
+ 
+ int
+ frame_saved_pc(frame)
+      FRAME frame;
+ {
+   mips_proc_info *proc_desc = (mips_proc_info*)frame->proc_desc;
+   int pcreg = proc_desc ? PROC_PC_REG(proc_desc) : RA_REGNUM;
+   if (proc_desc && PROC_DESC_IS_DUMMY(proc_desc))
+       return read_memory_integer(frame->frame - 4, 4);
+ #if 0
+   /* If in the procedure prologue, RA_REGNUM might not have been saved
yet.
+    * Assume non-leaf functions start with:
+    *	addiu $sp,$sp,-frame_size
+    *	sw $ra,ra_offset($sp)
+    * This if the pc is pointing at either of these instructions,
+    * then $ra hasn't been trashed.
+    * If the pc has advanced beyond these two instructions,
+    * then $ra has been saved.
+    * critical, and much more complex. Handling $ra is enough to get
+    * a stack trace, but some register values with be wrong.
+    */
+   if (frame->proc_desc && frame->pc < PROC_LOW_ADDR(proc_desc) + 8)
+       return read_register(pcreg);
+ #endif
+   return read_next_frame_reg(frame, pcreg);
+ }
+ 
+ static PDR temp_proc_desc;
+ static struct frame_saved_regs temp_saved_regs;
+ 
+ CORE_ADDR heuristic_proc_start(pc)
+     CORE_ADDR pc;
+ {
+ 
+     CORE_ADDR start_pc = pc;
+     CORE_ADDR fence = start_pc - 10000;
+     if (fence < VM_MIN_ADDRESS) fence = VM_MIN_ADDRESS;
+     /* search back for previous return */
+     for (start_pc -= 4; ; start_pc -= 4)
+ 	if (start_pc < fence) return 0; 
+ 	else if (ABOUT_TO_RETURN(start_pc))
+ 	    break;
+ 
+     start_pc += 8; /* skip return, and iys delay slot */
+ #if 0
+     /* skip nops (usually 1) 0 - is this */
+     while (start_pc < pc && read_memory_integer (start_pc, 4) == 0)
+ 	start_pc += 4;
+ #endif
+     return start_pc;
+ }
+ 
+ PDR *heuristic_proc_desc(start_pc, limit_pc, next_frame)
+     CORE_ADDR start_pc, limit_pc;
+     FRAME next_frame;
+ {
+     CORE_ADDR sp = next_frame ? next_frame->frame : read_register
(SP_REGNUM);
+     CORE_ADDR cur_pc;
+     extern int breakpoints_inserted;
+     int frame_size;
+     int has_frame_reg = 0;
+     int reg30; /* Value of $r30. Used by gcc for frame-pointer */
+     unsigned long reg_mask = 0;
+     if (start_pc == 0) return NULL;
+     bzero(&temp_proc_desc, sizeof(PDR));
+     bzero(&temp_saved_regs, sizeof(struct frame_saved_regs));
+     if (start_pc + 200 < limit_pc) limit_pc = start_pc + 200;
+     remove_breakpoints ();
+     breakpoints_inserted = 0;
+   restart:
+     frame_size = 0;
+     for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += 4) {
+ 	unsigned long word = read_memory_integer(cur_pc, 4);
+ 	if ((word & 0xFFFF0000) == 0x27bd0000) /* addiu $sp,$sp,-i */
+ 	    frame_size += (-word) & 0xFFFF;
+ 	else if ((word & 0xFFFF0000) == 0x23bd0000) /* addu $sp,$sp,-i */
+ 	    frame_size += (-word) & 0xFFFF;
+ 	else if ((word & 0xFFE00000) == 0xafa00000) { /* sw reg,offset($sp)
*/
+ 	    int reg = (word & 0x001F0000) >> 16;
+ 	    reg_mask |= 1 << reg;
+ 	    temp_saved_regs.regs[reg] = sp + (short)word;
+ 	}
+ 	else if ((word & 0xFFFF0000) == 0x27be0000) { /* addiu $30,$sp,size
*/
+ 	    if ((unsigned short)word != frame_size)
+ 		reg30 = sp + (unsigned short)word;
+ 	    else if (!has_frame_reg) {
+ 		int alloca_adjust;
+ 		has_frame_reg = 1;
+ 		reg30 = read_next_frame_reg(next_frame, 30);
+ 		alloca_adjust = reg30 - (sp + (unsigned short)word);
+ 		if (alloca_adjust > 0) {
+ 		    /* FP > SP + frame_size. This may be because
+ 		    /* of an alloca or somethings similar.
+ 		     * Fix sp to "pre-alloca" value, and try again.
+ 		     */
+ 		    sp += alloca_adjust;
+ 		    goto restart;
+ 		}
+ 	    }
+ 	}
+ 	else if ((word & 0xFFE00000) == 0xafc00000) { /* sw reg,offset($30)
*/
+ 	    int reg = (word & 0x001F0000) >> 16;
+ 	    reg_mask |= 1 << reg;
+ 	    temp_saved_regs.regs[reg] = reg30 + (short)word;
+ 	}
+     }
+     if (has_frame_reg) {
+ 	PROC_FRAME_REG(&temp_proc_desc) = 30;
+ 	PROC_FRAME_OFFSET(&temp_proc_desc) = 0;
+     }
+     else {
+ 	PROC_FRAME_REG(&temp_proc_desc) = SP_REGNUM;
+ 	PROC_FRAME_OFFSET(&temp_proc_desc) = frame_size;
+     }
+     PROC_REG_MASK(&temp_proc_desc) = reg_mask;
+     PROC_PC_REG(&temp_proc_desc) = RA_REGNUM;
+     return &temp_proc_desc;
+ }
+ 
+ mips_proc_info *
+ find_proc_desc(pc, next_frame)
+     CORE_ADDR pc;
+     FRAME next_frame;
+ {
+   mips_proc_info *proc_desc;
+ 
+   int lo = 0;
+   int hi = proc_desc_length-1;
+   if (hi >= 0 && PROC_LOW_ADDR(&proc_desc_table[0]) <= pc
+       && PROC_HIGH_ADDR(&proc_desc_table[hi]) > pc)
+     {
+       for (;;) {
+ 	int new = (lo + hi) >> 1;
+ 	proc_desc = &proc_desc_table[new];
+ 	if (PROC_LOW_ADDR(proc_desc) > pc) hi = new;
+ 	else if (PROC_HIGH_ADDR(proc_desc) <= pc) lo = new;
+ 	else {
+ 	    /* IF this is the topmost frame AND
+ 	     * (this proc does not have debugging information OR
+ 	     * the PC is in the procedure prologue)
+ 	     * THEN create a "hueristic" proc_desc (by analyzing
+ 	     * the actual code) to replace the "official" proc_desc.
+ 	     */
+ 	    if (next_frame == NULL) {
+ 		struct symtab_and_line val;
+ 		struct symbol *proc_symbol = PROC_SYMBOL(proc_desc);
+ 		if (proc_symbol) {
+ 		    val = find_pc_line (BLOCK_START
+ 					  (SYMBOL_BLOCK_VALUE(proc_symbol)),
+ 					  0);
+ 		    val.pc = val.end ? val.end : pc;
+ 		}
+ 		if (!proc_symbol || pc < val.pc) {
+ 		    mips_proc_info *found_heuristic =
+ 			heuristic_proc_desc(PROC_LOW_ADDR(proc_desc),
+ 					    pc, next_frame);
+ 		    if (found_heuristic) proc_desc = found_heuristic;
+ 		}
+ 	    }
+ 	    break;
+ 	}
+ 	if (hi-lo <= 1) { proc_desc = 0; break; }
+       }
+     }
+   else
+     {
+       register struct linked_proc_info *link;
+       for (link = linked_proc_desc_table; link; link = link->next)
+ 	  if (PROC_LOW_ADDR(&link->info) <= pc
+ 	      && PROC_HIGH_ADDR(&link->info) > pc)
+ 	      return &link->info;
+       proc_desc =
+ 	  heuristic_proc_desc(heuristic_proc_start(pc), pc, next_frame);
+     }
+   return proc_desc;
+ }
+ 
+ PDR *cached_proc_desc;
+ 
+ FRAME_ADDR frame_chain(frame)
+     FRAME frame;
+ {
+     extern CORE_ADDR startup_file_start;	/* From blockframe.c */
+     mips_proc_info *proc_desc;
+     CORE_ADDR saved_pc = frame_saved_pc(frame);
+     if (startup_file_start)
+       { /* has at least the __start symbol */
+ 	if (saved_pc == 0 || !outside_startup_file (saved_pc)) return 0;
+       }
+     else
+       { /* This hack depends on the internals of __start. */
+ 	/* We also assume the breakpoints are *not* inserted */
+         if (read_memory_integer (saved_pc + 8, 4) == 0xd) /* break */
+ 	    return 0;
+       }
+     proc_desc = find_proc_desc(saved_pc, frame);
+     if (!proc_desc) return 0;
+     cached_proc_desc = proc_desc;
+     return read_next_frame_reg(frame, PROC_FRAME_REG(proc_desc))
+ 	+ PROC_FRAME_OFFSET(proc_desc);
+ }
+ 
+ void
+ init_extra_frame_info(fci)
+      struct frame_info *fci;
+ {
+   extern struct obstack frame_cache_obstack;
+   /* Use proc_desc calculated in frame_chain */
+   PDR *proc_desc = fci->next ? cached_proc_desc :
+       find_proc_desc(fci->pc, fci->next);
+   fci->saved_regs = (struct frame_saved_regs*)
+     obstack_alloc (&frame_cache_obstack, sizeof(struct
frame_saved_regs));
+   bzero(fci->saved_regs, sizeof(struct frame_saved_regs));
+   fci->proc_desc =
+       proc_desc == &temp_proc_desc ? (char*)NULL : (char*)proc_desc;
+   if (proc_desc)
+     {
+       int ireg;
+       CORE_ADDR reg_position;
+       unsigned long mask;
+       /* r0 bit means kernel trap */
+       int kernel_trap = PROC_REG_MASK(proc_desc) & 1;
+ 
+       /* Fixup frame-pointer - only needed for top frame */
+       /* This may not be quite right, if procedure has a real frame
register */
+       if (fci->pc == PROC_LOW_ADDR(proc_desc))
+ 	  fci->frame = read_register (SP_REGNUM);
+       else
+ 	  fci->frame = READ_FRAME_REG(fci, PROC_FRAME_REG(proc_desc))
+ 	      + PROC_FRAME_OFFSET(proc_desc);
+ 
+       if (proc_desc == &temp_proc_desc)
+ 	  *fci->saved_regs = temp_saved_regs;
+       else
+       {
+ 	  /* find which general-purpose registers were saved */
+ 	  reg_position = fci->frame + PROC_REG_OFFSET(proc_desc);
+ 	  mask = kernel_trap ? 0xFFFFFFFF : PROC_REG_MASK(proc_desc);
+ 	  for (ireg= 31; mask; --ireg, mask <<= 1)
+ 	      if (mask & 0x80000000)
+ 	      {
+ 		  fci->saved_regs->regs[ireg] = reg_position;
+ 		  reg_position -= 4;
+ 	      }
+ 	  /* find which floating-point registers were saved */
+ 	  reg_position = fci->frame + PROC_FREG_OFFSET(proc_desc);
+ 	  /* The freg_offset points to where the first *double* register is
saved.
+ 	   * So skip to the high-order word. */
+ 	  reg_position += 4;
+ 	  mask = kernel_trap ? 0xFFFFFFFF : PROC_FREG_MASK(proc_desc);
+ 	  for (ireg = 31; mask; --ireg, mask <<= 1)
+ 	      if (mask & 0x80000000)
+ 	      {
+ 		  fci->saved_regs->regs[32+ireg] = reg_position;
+ 		  reg_position -= 4;
+ 	      }
+       }
+ 
+       /* hack: if argument regs are saved, guess these contain args
*/
+       if ((PROC_REG_MASK(proc_desc) & 0xF0) == 0) fci->num_args = -1;
+       else if ((PROC_REG_MASK(proc_desc) & 0x80) == 0) fci->num_args =
4;
+       else if ((PROC_REG_MASK(proc_desc) & 0x40) == 0) fci->num_args =
3;
+       else if ((PROC_REG_MASK(proc_desc) & 0x20) == 0) fci->num_args =
2;
+       else if ((PROC_REG_MASK(proc_desc) & 0x10) == 0) fci->num_args =
1;
+ 
+       fci->saved_regs->regs[PC_REGNUM] =
fci->saved_regs->regs[RA_REGNUM];
+     }
+   if (fci->next == 0)
+       supply_register(FP_REGNUM, &fci->frame);
+ }
+ 
+ 
+ CORE_ADDR mips_push_arguments(nargs, args, sp, struct_return,
struct_addr)
+   int nargs;
+   value *args;
+   CORE_ADDR sp;
+   int struct_return;
+   CORE_ADDR struct_addr;
+ {
+   CORE_ADDR buf;
+   register i;
+   int accumulate_size = struct_return ? 4 : 0;
+   struct mips_arg { char *contents; int len; int offset; };
+   struct mips_arg *mips_args =
+       (struct mips_arg*)alloca(nargs * sizeof(struct mips_arg));
+   register struct mips_arg *m_arg;
+   for (i = 0, m_arg = mips_args; i < nargs; i++, m_arg++) {
+     extern value value_arg_coerce();
+     value arg = value_arg_coerce (args[i]);
+     m_arg->len = TYPE_LENGTH (VALUE_TYPE (arg));
+     /* This entire mips-specific routine is because doubles must be
aligned
+      * on 8-byte boundaries. It still isn't quite right, because MIPS
decided
+      * to align 'struct {int a, b}' on 4-byte boundaries (even though
this
+      * breaks their varargs implementation...). A correct solution
+      * requires an simulation of gcc's 'alignof' (and use of
'alignof'
+      * in stdarg.h/varargs.h).
+      */
+     if (m_arg->len > 4) accumulate_size = (accumulate_size + 7) & -8;
+     m_arg->offset = accumulate_size;
+     accumulate_size = (accumulate_size + m_arg->len + 3) & -4;
+     m_arg->contents = VALUE_CONTENTS(arg);
+   }
+   accumulate_size = (accumulate_size + 7) & (-8);
+   if (accumulate_size < 16) accumulate_size = 16; 
+   sp -= accumulate_size;
+   for (i = nargs; m_arg--, --i >= 0; )
+     write_memory(sp + m_arg->offset, m_arg->contents, m_arg->len);
+   if (struct_return) {
+     buf = struct_addr;
+     write_memory(sp, &buf, sizeof(CORE_ADDR));
+ }
+   return sp;
+ }
+ 
+ /* MASK(i,j) == (1<<i) + (1<<(i+1)) + ... + (1<<j)). Assume i<=j<31.
*/
+ #define MASK(i,j) ((1 << (j)+1)-1 ^ (1 << (i))-1)
+ 
+ void
+ push_dummy_frame()
+ {
+   int ireg;
+   struct linked_proc_info *link = (struct linked_proc_info*)
+       xmalloc(sizeof(struct linked_proc_info));
+   mips_proc_info *proc_desc = &link->info;
+   CORE_ADDR sp = read_register (SP_REGNUM);
+   CORE_ADDR save_address;
+   REGISTER_TYPE buffer;
+   link->next = linked_proc_desc_table;
+   linked_proc_desc_table = link;
+ #define PUSH_FP_REGNUM 16 /* must be a register preserved across calls
*/
+ #define GEN_REG_SAVE_MASK MASK(1,16)|MASK(24,28)|(1<<31)
+ #define GEN_REG_SAVE_COUNT 22
+ #define FLOAT_REG_SAVE_MASK MASK(0,19)
+ #define FLOAT_REG_SAVE_COUNT 20
+ #define SPECIAL_REG_SAVE_COUNT 4
+   /*
+    * The registers we must save are all those not preserved across
+    * procedure calls. Dest_Reg (see m-mips.h) must also be saved.
+    * In addition, we must save the PC, and PUSH_FP_REGNUM.
+    * (Ideally, we should also save MDLO/-HI and FP Control/Status
reg.)
+    *
+    * Dummy frame layout:
+    *  (high memory)
+    * 	Saved PC
+    *	Saved MMHI, MMLO, FPC_CSR
+    *	Saved R31
+    *	Saved R28
+    *	...
+    *	Saved R1
+    *    Saved D18 (i.e. F19, F18)
+    *    ...
+    *    Saved D0 (i.e. F1, F0)
+    *	CALL_DUMMY (subroutine stub; see m-mips.h)
+    *	Parameter build area (not yet implemented)
+    *  (low memory)
+    */
+   PROC_REG_MASK(proc_desc) = GEN_REG_SAVE_MASK;
+   PROC_FREG_MASK(proc_desc) = FLOAT_REG_SAVE_MASK;
+   PROC_REG_OFFSET(proc_desc) = /* offset of (Saved R31) from FP */
+       -sizeof(long) - 4 * SPECIAL_REG_SAVE_COUNT;
+   PROC_FREG_OFFSET(proc_desc) = /* offset of (Saved D18) from FP */
+       -sizeof(double) - 4 * (SPECIAL_REG_SAVE_COUNT +
GEN_REG_SAVE_COUNT);
+   /* save general registers */
+   save_address = sp + PROC_REG_OFFSET(proc_desc);
+   for (ireg = 32; --ireg >= 0; )
+     if (PROC_REG_MASK(proc_desc) & (1 << ireg))
+       {
+ 	buffer = read_register (ireg);
+ 	write_memory (save_address, &buffer, sizeof(REGISTER_TYPE));
+ 	save_address -= 4;
+       }
+   /* save floating-points registers */
+   save_address = sp + PROC_FREG_OFFSET(proc_desc);
+   for (ireg = 32; --ireg >= 0; )
+     if (PROC_FREG_MASK(proc_desc) & (1 << ireg))
+       {
+ 	buffer = read_register (ireg);
+ 	write_memory (save_address, &buffer, 4);
+ 	save_address -= 4;
+       }
+   write_register (PUSH_FP_REGNUM, sp);
+   PROC_FRAME_REG(proc_desc) = PUSH_FP_REGNUM;
+   PROC_FRAME_OFFSET(proc_desc) = 0;
+   buffer = read_register (PC_REGNUM);
+   write_memory (sp - 4, &buffer, sizeof(REGISTER_TYPE));
+   buffer = read_register (HI_REGNUM);
+   write_memory (sp - 8, &buffer, sizeof(REGISTER_TYPE));
+   buffer = read_register (LO_REGNUM);
+   write_memory (sp - 12, &buffer, sizeof(REGISTER_TYPE));
+   buffer = read_register (FCRCS_REGNUM);
+   write_memory (sp - 16, &buffer, sizeof(REGISTER_TYPE));
+   sp -= 4 *
(GEN_REG_SAVE_COUNT+FLOAT_REG_SAVE_COUNT+SPECIAL_REG_SAVE_COUNT);
+   write_register (SP_REGNUM, sp);
+   PROC_HIGH_ADDR(proc_desc) = sp;
+   PROC_LOW_ADDR(proc_desc) = sp - CALL_DUMMY_SIZE;
+   SET_PROC_DESC_IS_DUMMY(proc_desc);
+   PROC_PC_REG(proc_desc) = RA_REGNUM;
+ }
+ 
+ void
+ pop_frame()
+ { register int regnum;
+   FRAME frame = get_current_frame ();
+   CORE_ADDR new_sp = frame->frame;
+   mips_proc_info *proc_desc = (PDR*)frame->proc_desc;
+   if (PROC_DESC_IS_DUMMY(proc_desc))
+     {
+       struct linked_proc_info **ptr = &linked_proc_desc_table;;
+       for (; &ptr[0]->info != proc_desc; ptr = &ptr[0]->next )
+ 	  if (ptr[0] == NULL) abort();
+       *ptr = ptr[0]->next;
+       free (ptr[0]);
+       write_register (HI_REGNUM, read_memory_integer(new_sp - 8, 4));
+       write_register (LO_REGNUM, read_memory_integer(new_sp - 12,
4));
+       write_register (FCRCS_REGNUM, read_memory_integer(new_sp - 16,
4));
+     }
+   write_register (PC_REGNUM, FRAME_SAVED_PC(frame));
+   if (frame->proc_desc) {
+     for (regnum = 32; --regnum >= 0; )
+       if (PROC_REG_MASK(proc_desc) & (1 << regnum))
+ 	write_register (regnum,
+ 		  read_memory_integer (frame->saved_regs->regs[regnum], 4));
+     for (regnum = 64; --regnum >= 32; )
+       if (PROC_FREG_MASK(proc_desc) & (1 << regnum))
+ 	write_register (regnum,
+ 		  read_memory_integer (frame->saved_regs->regs[regnum], 4));
+   }
+   write_register (SP_REGNUM, new_sp);
+   flush_cached_frames ();
+   set_current_frame (create_new_frame (new_sp, read_pc ()));
+ }
+ 
+ static mips_print_register(regnum, all)
+      int regnum, all;
+ {
+       unsigned char raw_buffer[8];
+       REGISTER_TYPE val;
+ 
+       read_relative_register_raw_bytes (regnum, raw_buffer);
+ 
+       if (!(regnum & 1) && regnum >= FP0_REGNUM && regnum <
FP0_REGNUM+32) {
+ 	  read_relative_register_raw_bytes (regnum+1, raw_buffer+4);
+ 	  printf_filtered ("(d%d: ", regnum&31);
+ 	  val_print (builtin_type_double, raw_buffer, 0,
+ 		     stdout, 0, 1, 0, Val_pretty_default);
+ 	  printf_filtered ("); ", regnum&31);
+       }
+       fputs_filtered (reg_names[regnum], stdout);
+ #ifndef NUMERIC_REG_NAMES
+       if (regnum < 32)
+ 	  printf_filtered ("(r%d): ", regnum);
+       else
+ #endif
+ 	  printf_filtered (": ");
+ 
+       /* If virtual format is floating, print it that way.  */
+       if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (regnum)) == TYPE_CODE_FLT
+ 	  && ! INVALID_FLOAT (raw_buffer, REGISTER_VIRTUAL_SIZE(regnum))) {
+ 	  val_print (REGISTER_VIRTUAL_TYPE (regnum), raw_buffer, 0,
+ 		     stdout, 0, 1, 0, Val_pretty_default);
+       }
+       /* Else print as integer in hex.  */
+       else
+ 	{
+ 	  long val;
+ 
+ 	  bcopy (raw_buffer, &val, sizeof (long));
+ 	  if (val == 0)
+ 	    printf_filtered ("0");
+ 	  else if (all)
+ 	    printf_filtered ("0x%x", val);
+ 	  else
+ 	    printf_filtered ("0x%x=%d", val, val);
+ 	}
+ }
+ 
+ mips_do_registers_info(regnum)
+      int regnum;
+ {
+   if (regnum != -1) {
+       mips_print_register (regnum, 0);
+       printf_filtered ("\n");
+   }
+   else {
+       for (regnum = 0; regnum < NUM_REGS; ) {
+ 	  mips_print_register (regnum, 1);
+ 	  regnum++;
+ 	  if ((regnum & 3) == 0 || regnum == NUM_REGS)
+ 	      printf_filtered (";\n");
+ 	  else
+ 	      printf_filtered ("; ");
+       }
+   }
+ }
*** mips-opcode.h.orig	Mon Nov  5 10:27:50 1990
--- mips-opcode.h	Mon Nov  5 11:12:55 1990
***************
*** 0 ****
--- 1,367 ----
+ /* Mips opcde list for GDB, the GNU debugger.
+    Copyright (C) 1989 Free Software Foundation, Inc.
+    Contributed by Nobuyuki Hikichi(hikichi@sra.junet)
+    Made to work for little-endian machines, and debugged
+    by Per Bothner (bothner@cs.wisc.edu).
+    Many fixes contributed by Frank Yellin (fy@lucid.com).
+ 
+ This file is part of GDB.
+ 
+ GDB is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+ 
+ GDB is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+ 
+ You should have received a copy of the GNU General Public License
+ along with GDB; see the file COPYING.  If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
*/
+ 
+ #ifdef BITS_BIG_ENDIAN
+ #define BIT_FIELDS_2(a,b) a;b;
+ #define BIT_FIELDS_4(a,b,c,d) a;b;c;d;
+ #define BIT_FIELDS_6(a,b,c,d,e,f) a;b;c;d;e;f;
+ #else
+ #define BIT_FIELDS_2(a,b) b;a;
+ #define BIT_FIELDS_4(a,b,c,d) d;c;b;a;
+ #define BIT_FIELDS_6(a,b,c,d,e,f) f;e;d;c;b;a;
+ #endif
+ 
+ struct op_i_fmt
+ {
+ BIT_FIELDS_4(
+   unsigned op : 6,
+   unsigned rs : 5,
+   unsigned rt : 5,
+   unsigned immediate : 16)
+ };
+ 
+ struct op_j_fmt
+ {
+ BIT_FIELDS_2(
+   unsigned op : 6,
+   unsigned target : 26)
+ };
+ 
+ struct op_r_fmt
+ {
+ BIT_FIELDS_6(
+   unsigned op : 6,
+   unsigned rs : 5,
+   unsigned rt : 5,
+   unsigned rd : 5,
+   unsigned shamt : 5,
+   unsigned funct : 6)
+ };
+ 
+ 
+ struct fop_i_fmt
+ {
+ BIT_FIELDS_4(
+   unsigned op : 6,
+   unsigned rs : 5,
+   unsigned rt : 5,
+   unsigned immediate : 16)
+ };
+ 
+ struct op_b_fmt
+ {
+ BIT_FIELDS_4(
+   unsigned op : 6,
+   unsigned rs : 5,
+   unsigned rt : 5,
+   short delta : 16)
+ };
+ 
+ struct fop_r_fmt
+ {
+ BIT_FIELDS_6(
+   unsigned op : 6,
+   unsigned fmt : 5,
+   unsigned ft : 5,
+   unsigned fs : 5,
+   unsigned fd : 5,
+   unsigned funct : 6)
+ };
+ 
+ struct mips_opcode
+ {
+   char *name;
+   unsigned long opcode;
+   unsigned long match;
+   char *args;
+ };
+ 
+ /* args format;
+ 
+    "s" rs: source register specifier
+    "t" rt: target register
+    "i" immediate
+    "a" target address
+    "c" branch condition
+    "d" rd: destination register specifier
+    "h" shamt: shift amount
+    "f" funct: function field
+ 
+   for fpu
+    "S" fs source 1 register
+    "T" ft source 2 register
+    "D" destination register
+ */
+ 
+ #define one(x) (x << 26)
+ #define op_func(x, y) ((x << 26) | y)
+ #define op_cond(x, y) ((x << 26) | (y << 16))
+ #define op_rs_func(x, y, z) ((x << 26) | (y << 21) | z)
+ #define op_rs_b11(x, y, z) ((x << 26) | (y << 21) | z)
+ #define op_o16(x, y) ((x << 26) | (y << 16))
+ #define op_bc(x, y, z) ((x << 26) | (y << 21) | (z << 16))
+ 
+ struct mips_opcode mips_opcodes[] = 
+ {
+ /* These first opcodes are special cases of the ones in the comments
*/
+   {"nop",	0,		0xffffffff,	     /*li*/	""},
+   {"li",	op_bc(9,0,0),	op_bc(0x3f,31,0),    /*addiu*/	"t,j"},
+   {"b",		one(4),		0xffff0000,	     /*beq*/	"b"},
+   {"move",	op_func(0, 33),	op_cond(0x3f,31)|0x7ff,/*addu*/	"d,s"},
+ 
+   {"sll",	op_func(0, 0),	op_func(0x3f, 0x3f),		"d,t,h"},
+   {"srl",	op_func(0, 2),	op_func(0x3f, 0x3f),		"d,t,h"},
+   {"sra",	op_func(0, 3),	op_func(0x3f, 0x3f),		"d,t,h"},
+   {"sllv",	op_func(0, 4),	op_func(0x3f, 0x7ff),		"d,t,s"},
+   {"srlv",	op_func(0, 6),	op_func(0x3f, 0x7ff),		"d,t,s"},
+   {"srav",	op_func(0, 7),	op_func(0x3f, 0x7ff),		"d,t,s"},
+   {"jr",	op_func(0, 8),	op_func(0x3f, 0x1fffff),	"s"},
+   {"jalr",	op_func(0, 9),	op_func(0x3f, 0x1f07ff),	"d,s"},
+   {"syscall",	op_func(0, 12),	op_func(0x3f, 0x3f),		""},
+   {"break",	op_func(0, 13),	op_func(0x3f, 0x3f),		""},
+   {"mfhi",      op_func(0, 16), op_func(0x3f, 0x03ff07ff),      "d"},
+   {"mthi",      op_func(0, 17), op_func(0x3f, 0x1fffff),        "s"},
+   {"mflo",      op_func(0, 18), op_func(0x3f, 0x03ff07ff),      "d"},
+   {"mtlo",      op_func(0, 19), op_func(0x3f, 0x1fffff),        "s"},
+   {"mult",	op_func(0, 24),	op_func(0x3f, 0xffff),		"s,t"},
+   {"multu",	op_func(0, 25),	op_func(0x3f, 0xffff),		"s,t"},
+   {"div",	op_func(0, 26),	op_func(0x3f, 0xffff),		"s,t"},
+   {"divu",	op_func(0, 27),	op_func(0x3f, 0xffff),		"s,t"},
+   {"add",	op_func(0, 32),	op_func(0x3f, 0x7ff),		"d,s,t"},
+   {"addu",	op_func(0, 33),	op_func(0x3f, 0x7ff),		"d,s,t"},
+   {"sub",	op_func(0, 34),	op_func(0x3f, 0x7ff),		"d,s,t"},
+   {"subu",	op_func(0, 35),	op_func(0x3f, 0x7ff),		"d,s,t"},
+   {"and",	op_func(0, 36),	op_func(0x3f, 0x7ff),		"d,s,t"},
+   {"or",	op_func(0, 37),	op_func(0x3f, 0x7ff),		"d,s,t"},
+   {"xor",	op_func(0, 38),	op_func(0x3f, 0x7ff),		"d,s,t"},
+   {"nor",	op_func(0, 39),	op_func(0x3f, 0x7ff),		"d,s,t"},
+   {"slt",	op_func(0, 42),	op_func(0x3f, 0x7ff),		"d,s,t"},
+   {"sltu",	op_func(0, 43),	op_func(0x3f, 0x7ff),		"d,s,t"},
+ 
+   {"bltz",	op_cond (1, 0),	op_cond(0x3f, 0x1f),		"s,b"},
+   {"bgez",	op_cond (1, 1),	op_cond(0x3f, 0x1f),		"s,b"},
+   {"bltzal",	op_cond (1, 16),op_cond(0x3f, 0x1f),		"s,b"},
+   {"bgezal",	op_cond (1, 17),op_cond(0x3f, 0x1f),		"s,b"},
+ 
+ 
+   {"j",		one(2),		one(0x3f),			"a"},
+   {"jal",	one(3),		one(0x3f),			"a"},
+   {"beq",	one(4),		one(0x3f),			"s,t,b"},
+   {"bne",	one(5),		one(0x3f),			"s,t,b"},
+   {"blez",	one(6),		one(0x3f) | 0x1f0000,		"s,b"},
+   {"bgtz",	one(7),		one(0x3f) | 0x1f0000,		"s,b"},
+   {"addi",	one(8),		one(0x3f),			"t,s,j"},
+   {"addiu",	one(9),		one(0x3f),			"t,s,j"},
+   {"slti",	one(10),	one(0x3f),			"t,s,j"},
+   {"sltiu",	one(11),	one(0x3f),			"t,s,j"},
+   {"andi",	one(12),	one(0x3f),			"t,s,i"},
+   {"ori",	one(13),	one(0x3f),			"t,s,i"},
+   {"xori",	one(14),	one(0x3f),			"t,s,i"},
+ 	/* rs field is don't care field? */
+   {"lui",	one(15),	one(0x3f),			"t,i"},
+ 
+ /* co processor 0 instruction */
+   {"mfc0",	op_rs_b11 (16, 0, 0),	op_rs_b11(0x3f, 0x1f, 0x7ff),
"t,d"},
+   {"cfc0",	op_rs_b11 (16, 2, 0),	op_rs_b11(0x3f, 0x1f, 0x7ff),
"t,d"},
+   {"mtc0",	op_rs_b11 (16, 4, 0),	op_rs_b11(0x3f, 0x1f, 0x7ff),
"t,d"},
+   {"ctc0",	op_rs_b11 (16, 6, 0),	op_rs_b11(0x3f, 0x1f, 0x7ff),
"t,d"},
+ 
+   {"bc0f",	op_o16(16, 0x100),	op_o16(0x3f, 0x3ff),	"b"},
+   {"bc0f",	op_o16(16, 0x180),	op_o16(0x3f, 0x3ff),	"b"},
+   {"bc0t",	op_o16(16, 0x101),	op_o16(0x3f, 0x3ff),	"b"},
+   {"bc0t",	op_o16(16, 0x181),	op_o16(0x3f, 0x3ff),	"b"},
+ 
+   {"tlbr",	op_rs_func(16, 0x10, 1),
+ 				op_rs_func(0x3f, 0x1f, 0x1f), ""},
+   {"tlbwi",	op_rs_func(16, 0x10, 2),
+ 				op_rs_func(0x3f, 0x1f, 0x1f), ""},
+   {"tlbwr",	op_rs_func(16, 0x10, 6),
+ 				op_rs_func(0x3f, 0x1f, 0x1f), ""},
+   {"tlbp",	op_rs_func(16, 0x10, 8),
+ 				op_rs_func(0x3f, 0x1f, 0x1f), ""},
+   {"rfe",	op_rs_func(16, 0x10, 16),
+ 				op_rs_func(0x3f, 0x1f, 0x1f), ""},
+ 
+   {"mfc1",	op_rs_b11 (17, 0, 0),	op_rs_b11(0x3f, 0x1f, 0x7ff),
"t,S"},
+   {"cfc1",	op_rs_b11 (17, 2, 0),	op_rs_b11(0x3f, 0x1f, 0x7ff),
"t,S"},
+   {"mtc1",	op_rs_b11 (17, 4, 0),	op_rs_b11(0x3f, 0x1f, 0x7ff),
"t,S"},
+   {"ctc1",	op_rs_b11 (17, 6, 0),	op_rs_b11(0x3f, 0x1f, 0x7ff),
"t,S"},
+ 
+   {"bc1f",	op_o16(17, 0x100),	op_o16(0x3f, 0x3ff),	"b"},
+   {"bc1f",	op_o16(17, 0x180),	op_o16(0x3f, 0x3ff),	"b"},
+   {"bc1t",	op_o16(17, 0x101),	op_o16(0x3f, 0x3ff),	"b"},
+   {"bc1t",	op_o16(17, 0x181),	op_o16(0x3f, 0x3ff),	"b"},
+ 
+ /* fpu instruction */
+   {"add.s",	op_rs_func(17, 0x10, 0),
+ 				op_rs_func(0x3f, 0x1f, 0x3f),	"D,S,T"},
+   {"add.d",	op_rs_func(17, 0x11, 0),
+ 				op_rs_func(0x3f, 0x1f, 0x3f),	"D,S,T"},
+   {"sub.s",	op_rs_func(17, 0x10, 1),
+ 				op_rs_func(0x3f, 0x1f, 0x3f),	"D,S,T"},
+   {"sub.d",	op_rs_func(17, 0x11, 1),
+ 				op_rs_func(0x3f, 0x1f, 0x3f),	"D,S,T"},
+   {"mul.s",	op_rs_func(17, 0x10, 2),
+ 				op_rs_func(0x3f, 0x1f, 0x3f),	"D,S,T"},
+   {"mul.d",	op_rs_func(17, 0x11, 2),
+ 				op_rs_func(0x3f, 0x1f, 0x3f),	"D,S,T"},
+   {"div.s",	op_rs_func(17, 0x10, 3),
+ 				op_rs_func(0x3f, 0x1f, 0x3f),	"D,S,T"},
+   {"div.d",	op_rs_func(17, 0x11, 3),
+ 				op_rs_func(0x3f, 0x1f, 0x3f),	"D,S,T"},
+   {"abs.s",	op_rs_func(17, 0x10, 5),
+ 				op_rs_func(0x3f, 0x1f, 0x1f003f),	"D,S"},
+   {"abs.d",	op_rs_func(17, 0x11, 5),
+ 				op_rs_func(0x3f, 0x1f, 0x1f003f),	"D,S"},
+   {"mov.s",	op_rs_func(17, 0x10, 6),
+ 				op_rs_func(0x3f, 0x1f, 0x1f003f),	"D,S"},
+   {"mov.d",	op_rs_func(17, 0x11, 6),
+ 				op_rs_func(0x3f, 0x1f, 0x1f003f),	"D,S"},
+   {"neg.s",	op_rs_func(17, 0x10, 7),
+ 				op_rs_func(0x3f, 0x1f, 0x1f003f),	"D,S"},
+   {"neg.d",	op_rs_func(17, 0x11, 7),
+ 				op_rs_func(0x3f, 0x1f, 0x1f003f),	"D,S"},
+   {"cvt.s.s",	op_rs_func(17, 0x10, 32),
+ 				op_rs_func(0x3f, 0x1f, 0x1f003f),	"D,S"},
+   {"cvt.s.d",	op_rs_func(17, 0x11, 32),
+ 				op_rs_func(0x3f, 0x1f, 0x1f003f),	"D,S"},
+   {"cvt.s.w",	op_rs_func(17, 0x14, 32),
+ 				op_rs_func(0x3f, 0x1f, 0x1f003f),	"D,S"},
+   {"cvt.d.s",	op_rs_func(17, 0x10, 33),
+ 				op_rs_func(0x3f, 0x1f, 0x1f003f),	"D,S"},
+   {"cvt.d.d",	op_rs_func(17, 0x11, 33),
+ 				op_rs_func(0x3f, 0x1f, 0x1f003f),	"D,S"},
+   {"cvt.d.w",	op_rs_func(17, 0x14, 33),
+ 				op_rs_func(0x3f, 0x1f, 0x1f003f),	"D,S"},
+   {"cvt.w.s",	op_rs_func(17, 0x10, 36),
+ 				op_rs_func(0x3f, 0x1f, 0x1f003f),	"D,S"},
+   {"cvt.w.d",	op_rs_func(17, 0x11, 36),
+ 				op_rs_func(0x3f, 0x1f, 0x1f003f),	"D,S"},
+   {"c.f.s",	op_rs_func(17, 0x10, 48),
+ 				op_rs_func(0x3f, 0x1f, 0x7ff),	"S,T"},
+   {"c.f.d",	op_rs_func(17, 0x11, 48),
+ 				op_rs_func(0x3f, 0x1f, 0x7ff),	"S,T"},
+   {"c.un.s",	op_rs_func(17, 0x10, 49),
+ 				op_rs_func(0x3f, 0x1f, 0x7ff),	"S,T"},
+   {"c.un.d",	op_rs_func(17, 0x11, 49),
+ 				op_rs_func(0x3f, 0x1f, 0x7ff),	"S,T"},
+   {"c.eq.s",	op_rs_func(17, 0x10, 50),
+ 				op_rs_func(0x3f, 0x1f, 0x7ff),	"S,T"},
+   {"c.eq.d",	op_rs_func(17, 0x11, 50),
+ 				op_rs_func(0x3f, 0x1f, 0x7ff),	"S,T"},
+   {"c.ueq.s",	op_rs_func(17, 0x10, 51),
+ 				op_rs_func(0x3f, 0x1f, 0x7ff),	"S,T"},
+   {"c.ueq.d",	op_rs_func(17, 0x11, 51),
+ 				op_rs_func(0x3f, 0x1f, 0x7ff),	"S,T"},
+   {"c.olt.s",	op_rs_func(17, 0x10, 52),
+ 				op_rs_func(0x3f, 0x1f, 0x7ff),	"S,T"},
+   {"c.olt.d",	op_rs_func(17, 0x11, 52),
+ 				op_rs_func(0x3f, 0x1f, 0x7ff),	"S,T"},
+   {"c.ult.s",	op_rs_func(17, 0x10, 53),
+ 				op_rs_func(0x3f, 0x1f, 0x7ff),	"S,T"},
+   {"c.ult.d",	op_rs_func(17, 0x11, 53),
+ 				op_rs_func(0x3f, 0x1f, 0x7ff),	"S,T"},
+   {"c.ole.s",	op_rs_func(17, 0x10, 54),
+ 				op_rs_func(0x3f, 0x1f, 0x7ff),	"S,T"},
+   {"c.ole.d",	op_rs_func(17, 0x11, 54),
+ 				op_rs_func(0x3f, 0x1f, 0x7ff),	"S,T"},
+   {"c.ule.s",	op_rs_func(17, 0x10, 55),
+ 				op_rs_func(0x3f, 0x1f, 0x7ff),	"S,T"},
+   {"c.ule.d",	op_rs_func(17, 0x11, 55),
+ 				op_rs_func(0x3f, 0x1f, 0x7ff),	"S,T"},
+   {"c.sf.s",	op_rs_func(17, 0x10, 56),
+ 				op_rs_func(0x3f, 0x1f, 0x7ff),	"S,T"},
+   {"c.sf.d",	op_rs_func(17, 0x11, 56),
+ 				op_rs_func(0x3f, 0x1f, 0x7ff),	"S,T"},
+   {"c.ngle.s",	op_rs_func(17, 0x10, 57),
+ 				op_rs_func(0x3f, 0x1f, 0x7ff),	"S,T"},
+   {"c.ngle.d",	op_rs_func(17, 0x11, 57),
+ 				op_rs_func(0x3f, 0x1f, 0x7ff),	"S,T"},
+   {"c.seq.s",	op_rs_func(17, 0x10, 58),
+ 				op_rs_func(0x3f, 0x1f, 0x7ff),	"S,T"},
+   {"c.seq.d",	op_rs_func(17, 0x11, 58),
+ 				op_rs_func(0x3f, 0x1f, 0x7ff),	"S,T"},
+   {"c.ngl.s",	op_rs_func(17, 0x10, 59),
+ 				op_rs_func(0x3f, 0x1f, 0x7ff),	"S,T"},
+   {"c.ngl.d",	op_rs_func(17, 0x11, 59),
+ 				op_rs_func(0x3f, 0x1f, 0x7ff),	"S,T"},
+   {"c.lt.s",	op_rs_func(17, 0x10, 60),
+ 				op_rs_func(0x3f, 0x1f, 0x7ff),	"S,T"},
+   {"c.lt.d",	op_rs_func(17, 0x11, 60),
+ 				op_rs_func(0x3f, 0x1f, 0x7ff),	"S,T"},
+   {"c.nge.s",	op_rs_func(17, 0x10, 61),
+ 				op_rs_func(0x3f, 0x1f, 0x7ff),	"S,T"},
+   {"c.nge.d",	op_rs_func(17, 0x11, 61),
+ 				op_rs_func(0x3f, 0x1f, 0x7ff),	"S,T"},
+   {"c.le.s",	op_rs_func(17, 0x10, 62),
+ 				op_rs_func(0x3f, 0x1f, 0x7ff),	"S,T"},
+   {"c.le.d",	op_rs_func(17, 0x11, 62),
+ 				op_rs_func(0x3f, 0x1f, 0x7ff),	"S,T"},
+   {"c.ngt.s",	op_rs_func(17, 0x10, 63),
+ 				op_rs_func(0x3f, 0x1f, 0x7ff),	"S,T"},
+   {"c.ngt.d",	op_rs_func(17, 0x11, 63),
+ 				op_rs_func(0x3f, 0x1f, 0x7ff),	"S,T"},
+ 
+ /* co processor 2 instruction */
+   {"mfc2",	op_rs_b11 (18, 0, 0),	op_rs_b11(0x3f, 0x1f, 0x7ff),
"t,d"},
+   {"cfc2",	op_rs_b11 (18, 2, 0),	op_rs_b11(0x3f, 0x1f, 0x7ff),
"t,d"},
+   {"mtc2",	op_rs_b11 (18, 4, 0),	op_rs_b11(0x3f, 0x1f, 0x7ff),
"t,d"},
+   {"ctc2",	op_rs_b11 (18, 6, 0),	op_rs_b11(0x3f, 0x1f, 0x7ff),
"t,d"},
+   {"bc2f",	op_o16(18, 0x100),	op_o16(0x3f, 0x3ff),	"b"},
+   {"bc2f",	op_o16(18, 0x180),	op_o16(0x3f, 0x3ff),	"b"},
+   {"bc2t",	op_o16(18, 0x101),	op_o16(0x3f, 0x3ff),	"b"},
+   {"bc2t",	op_o16(18, 0x181),	op_o16(0x3f, 0x3ff),	"b"},
+ 
+ /* co processor 3 instruction */
+   {"mtc3",	op_rs_b11 (19, 0, 0),	op_rs_b11(0x3f, 0x1f, 0x7ff),
"t,d"},
+   {"cfc3",	op_rs_b11 (19, 2, 0),	op_rs_b11(0x3f, 0x1f, 0x7ff),
"t,d"},
+   {"mtc3",	op_rs_b11 (19, 4, 0),	op_rs_b11(0x3f, 0x1f, 0x7ff),
"t,d"},
+   {"ctc3",	op_rs_b11 (19, 6, 0),	op_rs_b11(0x3f, 0x1f, 0x7ff),
"t,d"},
+   {"bc3f",	op_o16(19, 0x100),	op_o16(0x3f, 0x3ff),	"b"},
+   {"bc3f",	op_o16(19, 0x180),	op_o16(0x3f, 0x3ff),	"b"},
+   {"bc3t",	op_o16(19, 0x101),	op_o16(0x3f, 0x3ff),	"b"},
+   {"bc3t",	op_o16(19, 0x181),	op_o16(0x3f, 0x3ff),	"b"},
+ 
+   {"lb",	one(32),	one(0x3f),		"t,j(s)"},
+   {"lh",	one(33),	one(0x3f),		"t,j(s)"},
+   {"lwl",	one(34),	one(0x3f),		"t,j(s)"},
+   {"lw",	one(35),	one(0x3f),		"t,j(s)"},
+   {"lbu",	one(36),	one(0x3f),		"t,j(s)"},
+   {"lhu",	one(37),	one(0x3f),		"t,j(s)"},
+   {"lwr",	one(38),	one(0x3f),		"t,j(s)"},
+   {"sb",	one(40),	one(0x3f),		"t,j(s)"},
+   {"sh",	one(41),	one(0x3f),		"t,j(s)"},
+   {"swl",	one(42),	one(0x3f),		"t,j(s)"},
+   {"swr",       one(46),        one(0x3f),              "t,j(s)"},
+   {"sw",	one(43),	one(0x3f),		"t,j(s)"},
+   {"lwc0",	one(48),	one(0x3f),		"t,j(s)"},
+ /* for fpu */
+   {"lwc1",	one(49),	one(0x3f),		"T,j(s)"},
+   {"lwc2",	one(50),	one(0x3f),		"t,j(s)"},
+   {"lwc3",	one(51),	one(0x3f),		"t,j(s)"},
+   {"swc0",	one(56),	one(0x3f),		"t,j(s)"},
+ /* for fpu */
+   {"swc1",	one(57),	one(0x3f),		"T,j(s)"},
+   {"swc2",	one(58),	one(0x3f),		"t,j(s)"},
+   {"swc3",	one(59),	one(0x3f),		"t,j(s)"},
+ };
*** mips-pinsn.c.orig	Mon Nov  5 10:27:50 1990
--- mips-pinsn.c	Mon Nov  5 10:28:32 1990
***************
*** 0 ****
--- 1,149 ----
+ /* Print mips instructions for GDB, the GNU debugger.
+    Copyright (C) 1989 Free Software Foundation, Inc.
+    Contributed by Nobuyuki Hikichi(hikichi@sra.co.jp)
+ 
+ This file is part of GDB.
+ 
+ GDB is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+ 
+ GDB is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+ 
+ You should have received a copy of the GNU General Public License
+ along with GDB; see the file COPYING.  If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
*/
+ 
+ #include <stdio.h>
+ 
+ #include "defs.h"
+ #include "param.h"
+ #include "symtab.h"
+ #include "mips-opcode.h"
+ 
+ /* Mips instructions are never longer than this many bytes.  */
+ #define MAXLEN 4
+ 
+ /* Number of elements in the opcode table.  */
+ #define NOPCODES (sizeof mips_opcodes / sizeof mips_opcodes[0])
+ 
+ #define MKLONG(p)  *(unsigned long*)p
+ 
+ extern char *reg_names[];
+ 
+ 
+ /* subroutine */
+ static unsigned char *
+ print_insn_arg (d, l, stream, pc)
+      char *d;
+      register unsigned long int *l;
+      FILE *stream;
+      CORE_ADDR pc;
+ {
+   switch (*d)
+     {
+     case ',':
+     case '(':
+     case ')':
+       fputc (*d, stream);
+       break;
+ 
+     case 's':
+       fprintf (stream, "$%s", reg_names[((struct op_i_fmt *)
l)->rs]);
+       break;
+ 
+     case 't':
+       fprintf (stream, "$%s", reg_names[((struct op_i_fmt *)
l)->rt]);
+       break;
+ 
+     case 'i':
+       fprintf (stream, "%d", ((struct op_i_fmt *) l)->immediate);
+       break;
+ 
+     case 'j': /* same as i, but sign-extended */
+       fprintf (stream, "%d", ((struct op_b_fmt *) l)->delta);
+       break;
+ 
+     case 'a':
+       print_address ((pc & 0xC0000000) | (((struct op_j_fmt
*)l)->target << 2),
+ 		     stream);
+       break;
+ 
+     case 'b':
+       print_address ((((struct op_b_fmt *) l)->delta << 2) + pc + 4,
stream);
+       break;
+ 
+     case 'd':
+       fprintf (stream, "%s", reg_names[((struct op_r_fmt *) l)->rd]);
+       break;
+ 
+     case 'h':
+       fprintf (stream, "0x%x", ((struct op_r_fmt *) l)->shamt);
+       break;
+ 
+     case 'S':
+       fprintf (stream, "$f%d", ((struct fop_r_fmt *) l)->fs);
+       break;
+ 
+     case 'T':
+       fprintf (stream, "$f%d", ((struct fop_r_fmt *) l)->ft);
+       break;
+ 
+     case 'D':
+       fprintf (stream, "$f%d", ((struct fop_r_fmt *) l)->fd);
+       break;
+ 
+     default:
+       fprintf (stream, "# internal error, undefined modifier(%c)",
*d);
+       break;
+     }
+ }
+ 
+ /* Print the mips instruction at address MEMADDR in debugged memory,
+    on STREAM.  Returns length of the instruction, in bytes, which
+    is always 4.  */
+ 
+ int
+ print_insn (memaddr, stream)
+      CORE_ADDR memaddr;
+      FILE *stream;
+ {
+   unsigned char buffer[MAXLEN];
+   register int i;
+   register char *d;
+   unsigned long int l;
+ 
+   read_memory (memaddr, buffer, MAXLEN);
+ 
+   for (i = 0; i < NOPCODES; i++)
+     {
+       register unsigned int opcode = mips_opcodes[i].opcode;
+       register unsigned int match = mips_opcodes[i].match;
+       if ((*(unsigned int*)buffer & match) == opcode)
+ 	break;
+     }
+ 
+   l = MKLONG (buffer);
+   /* Handle undefined instructions.  */
+   if (i == NOPCODES)
+     {
+       fprintf (stream, "0x%x",l);
+       return 4;
+     }
+ 
+   fprintf (stream, "%s", mips_opcodes[i].name);
+ 
+   if (!(d = mips_opcodes[i].args))
+     return 4;
+ 
+   fputc (' ', stream);
+ 
+   while (*d)
+     print_insn_arg (d++, &l, stream, memaddr);
+ 
+   return 4;
+ }
*** mipscoff.c.orig	Mon Nov  5 10:27:50 1990
--- mipscoff.c	Mon Nov  5 11:21:44 1990
***************
*** 0 ****
--- 1,2044 ----
+ /* Read coff symbol tables and convert to internal format, for GDB.
+    Design and support routines derived from dbxread.c, and UMAX COFF
+    specific routines written 9/1/87 by David D. Johnson, Brown
University.
+    Revised 11/27/87 ddj@cs.brown.edu
+    Copyright (C) 1987, 1988, 1989 Free Software Foundation, Inc.
+ 
+ This file is part of GDB.
+ 
+ GDB is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+ 
+ GDB is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+ 
+ You should have received a copy of the GNU General Public License
+ along with GDB; see the file COPYING.  If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
*/
+ 
+ 
+ #include <a.out.h>
+ #include <stdio.h>
+ #include "symtab.h"
+ #include <sys/file.h>
+ 
+ PDR *proc_desc_table = NULL;
+ long proc_desc_length = 0;
+ 
+ static void add_symbol_to_list ();
+ static int read_coff_symtab ();
+ static void patch_opaque_types ();
+ static struct type *decode_function_type ();
+ static struct type *decode_type ();
+ static struct type *decode_base_type ();
+ static struct type *read_enum_type ();
+ static struct type *read_struct_type ();
+ static struct type *read_type ();
+ static void finish_block ();
+ static struct blockvector *make_blockvector ();
+ static struct symbol *process_coff_symbol ();
+ static char *getfilename ();
+ static char *getsymname ();
+ 
+ extern int fclose ();
+ extern void close ();
+ extern void free_all_symtabs ();
+ extern void free_all_psymtabs ();
+ 
+ 
+ /* Name of source file whose symbol data we are now processing.
+    This comes from a symbol named ".file".  */
+ 
+ static char *last_source_file;
+ 
+ /* Core address of the end of the first object file.  */
+ static CORE_ADDR first_object_file_end;
+ 
+ /* End of the text segment of the executable file,
+    as found in the symbol _etext.  */
+ 
+ static CORE_ADDR end_of_text_addr;
+ 
+ /* The end address of the last seen procedure. */
+ 
+ static CORE_ADDR last_end_addr;
+ 
+ /* The file, a.out  and text section headers of the symbol file */
+ 
+ static FILHDR file_hdr;
+ static SCNHDR text_hdr;
+ static AOUTHDR aout_hdr;
+ 
+ /* The index in the symbol table of the last coff symbol that was
processed.  */
+ 
+ static int symnum;
+ 
+ /* Vector of types defined so far, indexed by their coff symnum.  */
+ 
+ static struct typevector *type_vector;
+ 
+ /* Number of elements allocated for type_vector currently.  */
+ 
+ static int type_vector_length;
+ 
+ /* Chain of typedefs of pointers to empty struct/union types.
+    They are chained thru the SYMBOL_VALUE.  */
+ 
+ #define HASHSIZE 127
+ static struct symbol *opaque_type_chain[HASHSIZE];
+ 
+ /* Record the symbols defined for each context in a list.
+    We don't create a struct block for the context until we
+    know how long to make it.  */
+ 
+ struct pending
+ {
+   struct pending *next;
+   struct symbol *symbol;
+ };
+ 
+ /* Here are the three lists that symbols are put on.  */
+ 
+ struct pending *file_symbols;	/* static at top level, and types */
+ 
+ struct pending *global_symbols;	/* global functions and variables */
+ 
+ struct pending **global_symbols_all, **file_symbols_all;
+ 
+ struct pending *local_symbols;	/* everything local to lexical context
*/
+ 
+ /* List of unclosed lexical contexts
+    (that will become blocks, eventually).  */
+ 
+ struct context_stack
+ {
+   struct context_stack *next;
+   struct pending *locals;
+   struct pending_block *old_blocks;
+   struct symbol *name;
+   CORE_ADDR start_addr;
+ };
+ 
+ struct context_stack *context_stack;
+ 
+ /* Nonzero if within a function (so symbols should be local,
+    if nothing says specifically).  */
+ 
+ int within_function;
+ 
+ /* List of blocks already made (lexical contexts already closed).
+    This is used at the end to make the blockvector.  */
+ 
+ struct pending_block
+ {
+   struct pending_block *next;
+   struct block *block;
+ };
+ 
+ struct pending_block *pending_blocks;
+ 
+ extern CORE_ADDR startup_file_start;	/* From blockframe.c */
+ extern CORE_ADDR startup_file_end;	/* From blockframe.c */
+ 
+ /* File name symbols were loaded from.  */
+ 
+ static char *symfile;
+ 
+ /* Look up a coff type-number index.  Return the address of the slot
+    where the type for that index is stored.
+    The type-number is in INDEX. 
+ 
+    This can be used for finding the type associated with that index
+    or for associating a new type with the index.  */
+ 
+ static struct type **
+ coff_lookup_type (index)
+      register int index;
+ {
+   if (index >= type_vector_length)
+     {
+       int old_vector_length = type_vector_length;
+ 
+       type_vector_length *= 2;
+       if (type_vector_length < index) {
+ 	type_vector_length = index * 2;
+       }
+       type_vector = (struct typevector *)
+ 	xrealloc (type_vector, sizeof (struct typevector)
+ 				+ type_vector_length * sizeof (struct type *));
+       bzero (&type_vector->type[ old_vector_length ],
+ 	     (type_vector_length - old_vector_length) * sizeof(struct type
*));
+     }
+   return &type_vector->type[index];
+ }
+ 
+ /* Make sure there is a type allocated for type number index
+    and return the type object.
+    This can create an empty (zeroed) type object.  */
+ 
+ static struct type *
+ coff_alloc_type (index)
+      int index;
+ {
+   register struct type **type_addr = coff_lookup_type (index);
+   register struct type *type = *type_addr;
+ 
+   /* If we are referring to a type not known at all yet,
+      allocate an empty type for it.
+      We will fill it in later if we find out how.  */
+   if (type == 0)
+     {
+       type = (struct type *) obstack_alloc (symbol_obstack,
+ 					    sizeof (struct type));
+       bzero (type, sizeof (struct type));
+       *type_addr = type;
+     }
+   return type;
+ }
+ 
+ /* maintain the lists of symbols and blocks */
+ 
+ /* Add a symbol to one of the lists of symbols.  */
+ static void
+ add_symbol_to_list (symbol, listhead)
+      struct symbol *symbol;
+      struct pending **listhead;
+ {
+   register struct pending *link
+     = (struct pending *) xmalloc (sizeof (struct pending));
+ 
+   link->next = *listhead;
+   link->symbol = symbol;
+   *listhead = link;
+ }
+ 
+ /* Take one of the lists of symbols and make a block from it.
+    Put the block on the list of pending blocks.  */
+ 
+ static void
+ finish_block (symbol, listhead, old_blocks, start, end)
+      struct symbol *symbol;
+      struct pending **listhead;
+      struct pending_block *old_blocks;
+      CORE_ADDR start, end;
+ {
+   register struct pending *next, *next1;
+   register struct block *block;
+   register struct pending_block *pblock;
+   struct pending_block *opblock;
+   register int i;
+ 
+   /* Count the length of the list of symbols.  */
+ 
+   for (next = *listhead, i = 0; next; next = next->next, i++);
+ 
+   block = (struct block *)
+ 	    obstack_alloc (symbol_obstack, sizeof (struct block) + (i - 1) *
sizeof (struct symbol *));
+ 
+   /* Copy the symbols into the block.  */
+ 
+   BLOCK_NSYMS (block) = i;
+   for (next = *listhead; next; next = next->next)
+     BLOCK_SYM (block, --i) = next->symbol;
+ 
+   BLOCK_START (block) = start;
+   BLOCK_END (block) = end;
+   BLOCK_SUPERBLOCK (block) = 0;	/* Filled in when containing block is
made */
+ 
+   /* Put the block in as the value of the symbol that names it.  */
+ 
+   if (symbol)
+     {
+       SYMBOL_BLOCK_VALUE (symbol) = block;
+       BLOCK_FUNCTION (block) = symbol;
+     }
+   else
+     BLOCK_FUNCTION (block) = 0;
+ 
+   /* Now free the links of the list, and empty the list.  */
+ 
+   for (next = *listhead; next; next = next1)
+     {
+       next1 = next->next;
+       free (next);
+     }
+   *listhead = 0;
+ 
+   /* Install this block as the superblock
+      of all blocks made since the start of this scope
+      that don't have superblocks yet.  */
+ 
+   opblock = 0;
+   for (pblock = pending_blocks; pblock != old_blocks; pblock =
pblock->next)
+     {
+       if (BLOCK_SUPERBLOCK (pblock->block) == 0)
+ 	BLOCK_SUPERBLOCK (pblock->block) = block;
+       opblock = pblock;
+     }
+ 
+   /* Record this block on the list of all blocks in the file.
+      Put it after opblock, or at the beginning if opblock is 0.
+      This puts the block in the list after all its subblocks.  */
+ 
+   pblock = (struct pending_block *) xmalloc (sizeof (struct
pending_block));
+   pblock->block = block;
+   if (opblock)
+     {
+       pblock->next = opblock->next;
+       opblock->next = pblock;
+     }
+   else
+     {
+       pblock->next = pending_blocks;
+       pending_blocks = pblock;
+     }
+ }
+ 
+ static struct blockvector *
+ make_blockvector ()
+ {
+   register struct pending_block *next, *next1;
+   register struct blockvector *blockvector;
+   register int i;
+ 
+   /* Count the length of the list of blocks.  */
+ 
+   for (next = pending_blocks, i = 0; next; next = next->next, i++);
+ 
+   blockvector = (struct blockvector *)
+ 		  obstack_alloc (symbol_obstack, sizeof (struct blockvector) + (i -
1) * sizeof (struct block *));
+ 
+   /* Copy the blocks into the blockvector.
+      This is done in reverse order, which happens to put
+      the blocks into the proper order (ascending starting address).
+      finish_block has hair to insert each block into the list
+      after its subblocks in order to make sure this is true.  */
+ 
+   BLOCKVECTOR_NBLOCKS (blockvector) = i;
+   for (next = pending_blocks; next; next = next->next)
+     BLOCKVECTOR_BLOCK (blockvector, --i) = next->block;
+ 
+   /* Now free the links of the list, and empty the list.  */
+ 
+   for (next = pending_blocks; next; next = next1)
+     {
+       next1 = next->next;
+       free (next);
+     }
+   pending_blocks = 0;
+ 
+   return blockvector;
+ }
+ 
+ /* Manage the vector of line numbers.  */
+ 
+ static
+ record_line (line, pc)
+      int line;
+      CORE_ADDR pc;
+ {
+ }
+ 
+ /* Start a new symtab for a new source file.
+    This is called when a COFF ".file" symbol is seen;
+    it indicates the start of data for one original source file.  */
+ 
+ static void
+ start_symtab ()
+ {
+   context_stack = 0;
+   within_function = 0;
+   last_source_file = 0;
+ 
+   /* Initialize the source file information for this file.  */
+ 
+ }
+ 
+ /* Finish the symbol definitions for one main source file,
+    close off all the lexical contexts for that file
+    (creating struct block's for them), then make the
+    struct symtab for that file and put it in the list of all such.
+ 
+    END_ADDR is the address of the end of the file's text.  */
+ 
+ static void
+ end_symtab (start_addr, end_addr, linetable)
+      CORE_ADDR start_addr, end_addr;
+      struct linetable *linetable;
+ {
+   register struct symtab *symtab;
+   register struct context_stack *cstk;
+   register struct blockvector *blockvector;
+   struct partial_symtab *psymtab;
+ 
+   if (aout_hdr.entry < end_addr
+       && aout_hdr.entry >= start_addr)
+     {
+       startup_file_start = start_addr;
+       startup_file_end = end_addr;
+     }
+ 
+   /* Finish the lexical context of the last function in the file.  */
+ 
+   if (context_stack)
+     {
+       cstk = context_stack;
+       context_stack = 0;
+       /* Make a block for the local symbols within.  */
+       finish_block (cstk->name, &local_symbols, cstk->old_blocks,
+ 		    cstk->start_addr, end_addr);
+       free (cstk);
+     }
+ 
+   /* Create the two top-level blocks for this file.  */
+   finish_block (0, &file_symbols, 0, start_addr, end_addr);
+   finish_block (0, &global_symbols, 0, start_addr, end_addr);
+ 
+   /* Create the blockvector that points to all the file's blocks.  */
+   blockvector = make_blockvector ();
+ 
+   /* Now create the symtab object for this source file.  */
+   symtab = (struct symtab *) xmalloc (sizeof (struct symtab));
+   symtab->free_ptr = 0;
+ 
+   /* Fill in its components.  */
+   symtab->blockvector = blockvector;
+   symtab->free_code = free_linetable;
+   symtab->filename = last_source_file;
+   symtab->linetable = linetable;
+   symtab->nlines = 0;
+   symtab->line_charpos = 0;
+ 
+   /* Link the new symtab into the list of such.  */
+   symtab->next = symtab_list;
+   symtab_list = symtab;
+ 
+   /* Reinitialize for beginning of new file. */
+   last_source_file = 0;
+ 
+   /* Create a fake partial_symtab, so that find_pc_partial_function
+    * will do the right thing. */
+   psymtab = (struct partial_symtab *)
+       obstack_alloc (psymbol_obstack,
+ 		     sizeof (struct partial_symtab));
+   bzero (psymtab, sizeof (struct partial_symtab));
+   psymtab->next = partial_symtab_list;
+   partial_symtab_list = psymtab;
+   psymtab->textlow = start_addr;
+   psymtab->texthigh = end_addr;
+   psymtab->filename = symtab->filename ? symtab->filename : "";
+   psymtab->readin = 1;
+ 
+ }
+ 
+ /* Accumulate the misc functions in bunches of 127.
+    At the end, copy them all into one newly allocated structure.  */
+ 
+ #define MISC_BUNCH_SIZE 127
+ 
+ struct misc_bunch
+ {
+   struct misc_bunch *next;
+   struct misc_function contents[MISC_BUNCH_SIZE];
+ };
+ 
+ /* Bunch currently being filled up.
+    The next field points to chain of filled bunches.  */
+ 
+ static struct misc_bunch *misc_bunch;
+ 
+ /* Number of slots filled in current bunch.  */
+ 
+ static int misc_bunch_index;
+ 
+ /* Total number of misc functions recorded so far.  */
+ 
+ static int misc_count;
+ 
+ static void
+ init_misc_functions ()
+ {
+   misc_count = 0;
+   misc_bunch = 0;
+   misc_bunch_index = MISC_BUNCH_SIZE;
+ }
+ 
+ static void
+ record_misc_function (name, address)
+      char *name;
+      CORE_ADDR address;
+ {
+   register struct misc_bunch *new;
+ 
+   if (misc_bunch_index == MISC_BUNCH_SIZE)
+     {
+       new = (struct misc_bunch *) xmalloc (sizeof (struct
misc_bunch));
+       misc_bunch_index = 0;
+       new->next = misc_bunch;
+       misc_bunch = new;
+     }
+   misc_bunch->contents[misc_bunch_index].name = savestring (name,
strlen (name));
+   misc_bunch->contents[misc_bunch_index].address = address;
+   misc_bunch->contents[misc_bunch_index].type = (char)mf_unknown;
+   misc_bunch_index++;
+   misc_count++;
+ }
+ 
+ /* if we see a function symbol, we do record_misc_function.
+  * however, if it turns out the next symbol is '.bf', then
+  * we call here to undo the misc definition
+  */
+ static void
+ unrecord_misc_function ()
+ {
+   if (misc_bunch_index == 0)
+     error ("Internal error processing symbol table, at symbol %d.",
+ 	   symnum);
+   misc_bunch_index--;
+   misc_count--;
+ }
+ 
+ 
+ static int
+ compare_misc_functions (fn1, fn2)
+      struct misc_function *fn1, *fn2;
+ {
+   /* Return a signed result based on unsigned comparisons
+      so that we sort into unsigned numeric order.  */
+   if (fn1->address < fn2->address)
+     return -1;
+   if (fn1->address > fn2->address)
+     return 1;
+   return 0;
+ }
+ 
+ static void
+ discard_misc_bunches ()
+ {
+   register struct misc_bunch *next;
+ 
+   while (misc_bunch)
+     {
+       next = misc_bunch->next;
+       free (misc_bunch);
+       misc_bunch = next;
+     }
+ }
+ 
+ static void
+ condense_misc_bunches ()
+ {
+   register int i, j;
+   register struct misc_bunch *bunch;
+ #ifdef NAMES_HAVE_UNDERSCORE
+   int offset = 1;
+ #else
+   int offset = 0;
+ #endif
+ 
+   misc_function_vector
+     = (struct misc_function *)
+       xmalloc (misc_count * sizeof (struct misc_function));
+ 
+   j = 0;
+   bunch = misc_bunch;
+   while (bunch)
+     {
+       for (i = 0; i < misc_bunch_index; i++)
+ 	{
+ 	  register char *tmp;
+ 
+ 	  misc_function_vector[j] = bunch->contents[i];
+ 	  tmp = misc_function_vector[j].name;
+ 	  misc_function_vector[j].name = (tmp[0] == '_' ? tmp + offset :
tmp);
+ 	  j++;
+ 	}
+       bunch = bunch->next;
+       misc_bunch_index = MISC_BUNCH_SIZE;
+     }
+ 
+   misc_function_count = j;
+ 
+   /* Sort the misc functions by address.  */
+ 
+   qsort (misc_function_vector, j, sizeof (struct misc_function),
+ 	 compare_misc_functions);
+ }
+ 
+ /* Call sort_syms to sort alphabetically
+    the symbols of each block of each symtab.  */
+ 
+ static int
+ compare_symbols (s1, s2)
+      struct symbol **s1, **s2;
+ {
+   /* Names that are less should come first.  */
+   register int namediff = strcmp (SYMBOL_NAME (*s1), SYMBOL_NAME
(*s2));
+   if (namediff != 0) return namediff;
+   /* For symbols of the same name, registers should come first.  */
+   return ((SYMBOL_CLASS (*s2) == LOC_REGISTER)
+ 	  - (SYMBOL_CLASS (*s1) == LOC_REGISTER));
+ }
+ 
+ static void
+ sort_syms ()
+ {
+   register struct symtab *s;
+   register int i, nbl;
+   register struct blockvector *bv;
+   register struct block *b;
+ 
+   for (s = symtab_list; s; s = s->next)
+     {
+       bv = BLOCKVECTOR (s);
+       nbl = BLOCKVECTOR_NBLOCKS (bv);
+       for (i = 0; i < nbl; i++)
+ 	{
+ 	  b = BLOCKVECTOR_BLOCK (bv, i);
+ 	  if (BLOCK_SHOULD_SORT (b))
+ 		  qsort (&BLOCK_SYM (b, 0), BLOCK_NSYMS (b),
+ 			 sizeof (struct symbol *), compare_symbols);
+ 	}
+     }
+ }
+ 
+ /* Call sort_proc_descs to sort the procedure descriptors by address. 
*/
+ 
+ static int
+ compare_proc_descs (p1, p2)
+ PDR *p1, *p2;
+ {
+   unsigned int a1, a2;
+ 
+   a1 = PROC_LOW_ADDR (p1);
+   a2 = PROC_LOW_ADDR (p2);
+   if (a1 < a2)
+     return -1;
+   if (a1 > a2)
+     return 1;
+   return 0;
+ }
+ 
+ static void
+ sort_proc_descs ()
+ {
+   qsort (proc_desc_table, proc_desc_length,
+ 	 sizeof (PDR), compare_proc_descs);
+ }
+ 
+ 
+ /* This is the symbol-file command.  Read the file, analyze its
symbols,
+    and add a struct symtab to symtab_list.  */
+ 
+ /* !!! !!! */
+ int dump_stuff=0;
+ 
+ static void free_proc_descs ()
+ {
+     if (proc_desc_table != NULL) {
+ 	free (proc_desc_table);
+ 	proc_desc_table = NULL;
+ 	proc_desc_length = 0;
+     }
+ }
+ 
+ void
+ symbol_file_command (name)
+      char *name;
+ {
+   int desc;
+   int num_symbols;
+   int num_sections;
+   int symtab_offset;
+   register int val;
+   struct cleanup *old_chain;
+ 
+   dont_repeat ();
+ 
+   if (name == 0)
+     {
+       if (symtab_list && !query ("Discard symbol table? ", 0))
+ 	error ("Not confirmed.");
+       if (symfile)
+ 	free (symfile);
+       symfile = 0;
+       free_all_symtabs ();
+       free_proc_descs ();
+       return;
+     }
+ 
+   name = tilde_expand (name);
+   make_cleanup (free, name);
+ 
+   if (symtab_list && !query ("Load new symbol table from \"%s\"? ",
name))
+     error ("Not confirmed.");
+ 
+   if (symfile)
+     free (symfile);
+   symfile = 0;
+ 
+   {
+     char *absolute_name;
+ 
+     desc = openp (getenv ("PATH"), 1, name, O_RDONLY, 0,
&absolute_name);
+     if (desc < 0)
+       perror_with_name (name);
+     else
+       name = absolute_name;
+   }
+ 
+   old_chain = make_cleanup (close, desc);
+   make_cleanup (free_current_contents, &name);
+ 
+   if ((num_symbols = read_file_hdr (desc, &file_hdr)) < 0)
+     error ("File \"%s\" not in executable format.", name);
+ 
+   /* If an a.out header is present, read it in.  If not (e.g. a .o
file)
+      deal with its absence.  */
+   if (file_hdr.f_opthdr == 0
+       || read_aout_hdr (desc, &aout_hdr, file_hdr.f_opthdr) < 0)
+     {
+       /* We will not actually be able to run code, since backtraces
would
+ 	 fly off the bottom of the stack (there is no way to reliably
+ 	 detect bottom of stack), but that's fine since the kernel won't
+ 	 run something without an a.out header anyway.  Passive examination
+ 	 of .o files is one place this might make sense.  */
+       /* ~0 will not be in any file.  */
+       aout_hdr.entry = ~0;
+       /* set the startup file to be an empty range.  */
+       startup_file_start = 0;
+       startup_file_end = 0;
+     }
+ 
+   if (num_symbols == 0)
+     {
+       free_all_symtabs ();
+       free_proc_descs ();
+       printf ("%s does not have a symbol-table.\n", name);
+       fflush (stdout);
+       do_cleanups (old_chain);
+       return;
+     }
+ 
+   printf ("Reading symbol data from %s...", name);
+   fflush (stdout);
+ 
+   /* Throw away the old symbol table.  */
+ 
+   free_all_symtabs ();
+   free_proc_descs ();
+   free_all_psymtabs ();		/* Make sure that partial_symtab_list */
+ 				/* is 0 also. */
+ 
+   num_sections = file_hdr.f_nscns;
+   symtab_offset = file_hdr.f_symptr;
+ 
+   if (read_section_hdr (desc, _TEXT, &text_hdr, num_sections) < 0)
+     error ("\"%s\": can't read text section header", name);
+ 
+   /* Position to read the symbol table.  Do not read it all at once.
*/
+   val = lseek (desc, (long)symtab_offset, 0);
+   if (val < 0)
+     perror_with_name (name);
+ 
+   init_misc_functions ();
+   make_cleanup (discard_misc_bunches, 0);
+ 
+   /* Now that the executable file is positioned at symbol table,
+      process it and define symbols accordingly.  */
+ 
+   val = read_coff_symtab (desc, num_symbols, symtab_offset);
+   if (val < 0) error("Bad symbol table format");
+ 
+   patch_opaque_types ();
+ 
+   /* Sort symbols alphabetically within each block.  */
+ 
+   sort_syms ();
+ 
+   /* Go over the misc functions and install them in vector.  */
+ 
+   condense_misc_bunches ();
+ 
+   /* Sort the procedure descriptor table.  */
+ 
+   sort_proc_descs ();
+ 
+   /* Don't allow char * to have a typename (else would get caddr_t.) 
*/
+ 
+   TYPE_NAME (lookup_pointer_type (builtin_type_char)) = 0;
+ 
+   /* Make a default for file to list.  */
+ 
+   symfile = savestring (name, strlen (name));
+ 
+   do_cleanups (old_chain);
+ 
+   printf ("done.\n");
+   fflush (stdout);
+ }
+ 
+ /* Return name of file symbols were loaded from, or 0 if none..  */
+ 
+ char *
+ get_sym_file ()
+ {
+   return symfile;
+ }
+ 
+ /* Simplified internal version of coff symbol table information */
+ 
+ struct coff_symbol {
+   char *c_name;
+   int c_symnum;		/* symbol number of this entry */
+   int c_nsyms;		/* 1 if syment only, 2 if syment + auxent */
+   long c_value;
+   int c_sclass;
+   int c_secnum;
+   unsigned int c_type;
+ };
+ 
+ static char *
+ read_table(desc, size, offset)
+     long offset;
+ {
+     char *buf;
+     if (lseek(desc, offset, 0) < 0)
+       error("Bad symbol table format [seek]");
+     buf = xmalloc(size);
+     if (buf == NULL) error("Not enough memory");
+     if (myread (desc, buf, size) != size)
+       error("Bad symbol table format [read]");
+     return buf;
+ }
+ 
+ static char * (MapStNames[]) = { /* symbol type names */
+     "Nil", "Global", "Static", "Param", "Local", "Label", "Proc",
"Block",
+     "End", "Member", "Typedef", "File", "RegReloc", "Forward",
"StaticProc",
+     "Constant", "BlockPatched"
+ };
+ 
+ long stNameSize = sizeof(MapStNames)/sizeof(MapStNames[0]);
+ 
+ static char * MapScNames[] = {    /* storage class names */
+     "Nil", "Text", "Data", "Bss", "Register", "Abs", "Undefined",
"CdbLocal",
+     "Bits", "Dbx", "RegImage", "Info", "UserStruct", "SData", "SBss",
"RData",
+     "Var", "Common", "SCommon", "VarRegister", "Variant",
"SUndefined", "Init"
+ };
+ 
+ 
+ long scNameSize = sizeof(MapScNames)/sizeof(MapScNames[0]);
+ 
+ static char *(MapBtNames[]) = {    /* base type names */
+     "Nil", "Adr", "Char", "UChar", "Short", "UShort", "Int", "UInt",
"Long",
+     "ULong", "Float", "Double", "Struct", "Union", "Enum", "Typedef",
"Range",
+     "Set", "Complex", "DComplex", "Indirect", "FixedDec", "FloatDec",
"String",
+     "Bit", "Picture"
+ };
+ 
+ long btNameSize = sizeof(MapBtNames)/sizeof(MapBtNames[0]);
+ 
+ /* Given pointers to a symbol table in coff style exec file,
+    analyze them and create struct symtab's describing the symbols.
+    NSYMS is the number of symbols in the symbol table.
+    We read them one at a time using read_one_sym ().  */
+ 
+ /* stBlockPatched indicates an stBlock symbol which has been patched
+  * so that the value points to s struct type */
+ 
+ #define stBlockPatched 16
+ 
+ static FDR *file_descriptor_table;
+ static RFDT *rel_file_table;
+ static SYMR *local_symbol_table;
+ static char *local_string_table;
+ static AUXU *aux_symbol_table;
+ static FDR *cur_file_descriptor;
+ static int file_descriptor_count;
+ /* Note that PDR is also used for frame chaining, and is defined above
*/
+ 
+ static int cur_proc_number; /* number of procedure within current file
*/
+ static CORE_ADDR cur_proc_addr;
+ static int cur_file_number;
+ static int cur_isymBase;
+ static int cur_issBase;
+ 
+ static void
+ select_file(i)
+     int i;
+ {
+     global_symbols_all[cur_file_number] = global_symbols;
+     file_symbols_all[cur_file_number] = file_symbols;
+     global_symbols = global_symbols_all[i];
+     file_symbols = file_symbols_all[i];
+     cur_file_number = i;
+     cur_file_descriptor = &file_descriptor_table[i];
+     cur_isymBase = cur_file_descriptor->isymBase;
+     cur_issBase = cur_file_descriptor->issBase;
+ }
+ 
+ /* side-effect: changes cur_file_descriptor */
+ 
+ static SYMR *
+ get_type_context(auxp)
+     AUXU** auxp;
+ {
+   SYMR *sym;
+   FDR *sym_file_desc;
+   int rfi;
+   int rfd = (*auxp)->rndx.rfd;
+   int sym_index = (*auxp)->rndx.index;
+   (*auxp)++;
+   if (rfd == ST_RFDESCAPE) { rfd = (*auxp)->isym; (*auxp)++; }
+   if (rfd == ST_EXTIFD || sym_index == ST_ANONINDEX) return NULL;
+   rfi = rel_file_table[cur_file_descriptor->rfdBase + rfd];
+   if (rfi >= file_descriptor_count) return NULL;
+   sym_file_desc = &file_descriptor_table[rfi];
+   if (sym_index >= sym_file_desc->csym || sym_index == 0) return
NULL;
+   sym = &local_symbol_table[sym_file_desc->isymBase + sym_index];
+   if (sym->index == 0) return NULL;
+   select_file(rfi);
+   if (dump_stuff)
+     printf("rfd(%d,%d)->[%s,%x,st%s,sc%s,inx:%d (%x)]\n",
+ 	 rfi, sym_index,
+ 	 &local_string_table[cur_issBase+sym->iss],
+ 	 sym->value,
+ 		   MapStNames[sym->st], MapScNames[sym->sc],
+ 		   sym->index, sym);
+   return sym;
+ }
+ 
+ static struct type *
+ get_struct_type(sym, kind)
+      SYMR *sym;
+      int kind; /* either btStruct or btUnion or btNil (unknown) */
+ {
+   struct type *type;
+   if (sym->st == stBlockPatched)
+     {
+       type = (struct type*)sym->value;
+       /* Patch up possibly-wrong guess about struct vs. union */
+       if (kind == btStruct) TYPE_CODE(type) = TYPE_CODE_STRUCT;
+       else if (kind == btUnion) TYPE_CODE(type) = TYPE_CODE_UNION;
+     }
+   else if (sym->st != stBlock)
+     {
+       fprintf(stderr,"Bad symbol table: struct/union points to
non-stBlock\n");
+       type = builtin_type_void;
+     }
+   else
+     {
+       int nfields = 0;
+       SYMR *first_field = sym+1;
+       register struct field *cur_field;
+       char *sym_name = &local_string_table[cur_issBase+sym->iss];
+       int iauxBase = cur_file_descriptor->iauxBase;
+       type = (struct type *) obstack_alloc (symbol_obstack,
+ 					    sizeof (struct type));
+       bzero (type, sizeof (struct type));
+       TYPE_LENGTH (type) = sym->value;
+ 
+       /* we "remember" the type generated from this block */
+       sym->st = stBlockPatched;
+       sym->value = (long)type;
+ 
+       /* first count the number of fields */
+       for (sym = first_field; sym->st != stEnd; sym++)
+ 	if (sym->st == stMember) nfields++;
+ 	else if (sym->st == stBlock || sym->st == stBlockPatched)
+ 	  {
+ 	    if (sym->sc == scVariant) ; /* UNIMPLEMENTED */
+ 	    if (sym->index != 0)
+ 	      sym = &local_symbol_table[cur_isymBase + sym->index - 1];
+ 	  }
+ 
+       TYPE_NFIELDS (type) = nfields;
+       TYPE_FIELDS (type) = cur_field = (struct field*)
+ 	obstack_alloc (symbol_obstack, nfields * sizeof (struct field));
+       for (sym = first_field; sym->st != stEnd; sym++)
+ 	if (sym->st == stMember)
+ 	  {
+ 	    AUXU *aux = &aux_symbol_table[iauxBase + sym->index];
+ 	    char *name = &local_string_table[cur_issBase+sym->iss];
+ 	    cur_field->name =
+ 	      obstack_copy0 (symbol_obstack, name, strlen (name));
+ 
+ 	    cur_field->type = read_type(sym->index, &cur_field->bitsize);
+ 	    cur_field->bitpos = sym->value;
+ 	    cur_field++;
+ 	  }
+ 	else if (sym->st == stTypedef) ; /* just ignore it */
+ 	else if (sym->st == stBlock || sym->st == stBlockPatched)
+ 	  {
+ 	    if (sym->sc == scVariant) ; /* UNIMPLEMENTED */
+ 	    if (sym->index != 0)
+ 	      sym = &local_symbol_table[cur_isymBase + sym->index - 1];
+ 	  }
+ 	else
+ 	  fprintf(stderr, "[Bad member in struct/union field list]\n");
+       /*
+        * Heuristic: if 2nd field has offset 0, this is a union,
+        * otherwise, a struct definition.
+        * If nfields <= 1, we guess struct.
+        * If the type is used later, we fix it up.
+        * (This is done in the stBlockPatched case at the top of this
routine).
+        */
+       if (kind == btNil && nfields > 1)
+ 	{
+ 	  if (TYPE_FIELDS(type)[1].bitpos > 0) kind = btStruct;
+ 	  else kind = btUnion;
+ 	}
+       TYPE_CODE (type) = kind == btUnion ? TYPE_CODE_UNION :
TYPE_CODE_STRUCT;
+       TYPE_NAME (type) = concat ("",
+ 				 (kind == btUnion ? "union " : "struct "),
+ 				 sym_name);
+     }
+     return type;
+ }
+ 
+ static struct type *
+ read_struct_type(auxp, kind)
+      AUXU** auxp;
+      int kind; /* either btStruct or btUnion */
+ {
+   struct type *type;
+   int save_file_number = cur_file_number;
+   SYMR *sym = get_type_context(auxp);
+   if (sym == NULL) {
+     printf(stderr, "Bad symbol for struct/union definition");
+     return builtin_type_void;
+   }
+   if (sym->st == stTypedef)
+       type = read_type(sym->index, NULL);
+   else
+       type = get_struct_type(sym, kind);
+   select_file (save_file_number);
+   return type;
+ }
+ 
+ static struct type *
+ get_enum_type(sym)
+     SYMR *sym;
+ {
+   struct type *type;
+   if (sym->st == stBlockPatched)
+     type = (struct type*)sym->value;
+   else if (sym->st != stBlock)
+     {
+       fprintf(stderr,"Bad symbol table: enum points to
non-stBlock\n");
+       type = builtin_type_void;
+     }
+   else
+     {
+       int nfields = 0;
+       SYMR *first_field = sym+1;
+       register struct field *cur_field;
+       type = (struct type *) obstack_alloc (symbol_obstack,
+ 					    sizeof (struct type));
+       bzero (type, sizeof (struct type));
+       TYPE_LENGTH (type) = sym->value;
+ 
+       /* we "remember" the type generated from this block */
+       sym->st = stBlockPatched;
+       sym->value = (long)type;
+ 
+       TYPE_CODE (type) = TYPE_CODE_ENUM;
+       TYPE_LENGTH (type) = sizeof (int);
+       TYPE_NAME (type) = concat ("", "enum ",
+ 				 &local_string_table[cur_issBase+sym->iss]);
+ 
+       nfields = &local_symbol_table[cur_isymBase+sym->index] -
first_field - 1;
+ 
+       TYPE_NFIELDS (type) = nfields;
+       TYPE_FIELDS (type) = cur_field = (struct field*)
+ 	obstack_alloc (symbol_obstack, nfields * sizeof (struct field));
+       for (sym = first_field; sym->st != stEnd; sym++)
+ 	if (sym->st == stMember)
+ 	  {
+ 	    char *name = &local_string_table[cur_issBase+sym->iss];
+ 	    cur_field->name =
+ 	      obstack_copy0 (symbol_obstack, name, strlen (name));
+ 
+ 	    cur_field->bitpos = sym->value;
+ 	    cur_field->bitsize = 0;
+ 	    cur_field++;
+ 	  }
+ 	else
+ 	  fprintf(stderr, "[Bad member in enum list]\n");
+     }
+   return type;
+ }
+ 
+ static struct type *
+ read_enum_type(auxp)
+      AUXU** auxp;
+ {
+   struct type *type;
+   int save_file_number = cur_file_number;
+   SYMR *sym = get_type_context(auxp);
+   if (sym == NULL) {
+     printf(stderr, "Bad symbol for enum definition");
+     return builtin_type_int;
+   }
+   if (sym->st == stTypedef)
+       type = read_type(sym->index, NULL);
+   else
+       type = get_enum_type (sym);
+   select_file (save_file_number);
+   return type;
+ }
+ 
+ static struct type *
+ read_range_type(auxp)
+      AUXU** auxp;
+ {
+   struct type *range_type;
+   int save_file_number = cur_file_number;
+   SYMR *sym = get_type_context(auxp);
+   /* sym (if non-NULL) may point at an stBlock/scInfo, but ignore it
*/
+    range_type = (struct type *) obstack_alloc (symbol_obstack,
+ 					      sizeof (struct type));
+   TYPE_CODE (range_type) = TYPE_CODE_RANGE;
+   TYPE_TARGET_TYPE (range_type) = builtin_type_int;
+   TYPE_LENGTH (range_type) = sizeof (int);
+   TYPE_NFIELDS (range_type) = 2;
+   TYPE_FIELDS (range_type) =
+       (struct field *) obstack_alloc (symbol_obstack,
+ 				      2 * sizeof (struct field));
+   TYPE_FIELD_BITPOS (range_type, 0) = (*auxp)++->dnLow;
+   TYPE_FIELD_BITPOS (range_type, 1) = (*auxp)++->dnHigh;
+ 
+   select_file (save_file_number);
+   return range_type;
+ }
+ 
+ static struct type *
+ modify_type(type, qualifier, auxp)
+      struct type *type;
+      int qualifier;
+      AUXU** auxp;
+ {
+     switch (qualifier) {
+       case tqPtr: return lookup_pointer_type(type);
+       case tqNil: return type;
+       case tqArray:
+ 	{
+ 	    struct type *range_type = read_range_type(auxp);
+ 	    long lower = TYPE_FIELD_BITPOS (range_type, 0);
+ 	    long upper = TYPE_FIELD_BITPOS (range_type, 1);
+ 	    int elem_size = (*auxp)++->width; /* not used */
+ 	    struct type *atype;
+ 
+ 	    atype = (struct type *)
+ 		obstack_alloc (symbol_obstack, sizeof (struct type));
+ 	    bzero (atype, sizeof (struct type));
+ 
+ 	    TYPE_CODE (atype) = TYPE_CODE_ARRAY;
+ 	    TYPE_TARGET_TYPE (atype) = type;
+ 	    TYPE_LENGTH (atype) = (upper - lower + 1) * TYPE_LENGTH (type);
+ 	    TYPE_NFIELDS (atype) = 1;
+ 	    TYPE_FIELDS (atype) =
+ 		(struct field *) obstack_alloc (symbol_obstack,
+ 						sizeof (struct field));
+ 	    TYPE_FIELD_TYPE (atype, 0) = range_type;
+ 	    return atype;
+ 	}
+       case tqVol: return type;
+       case tqProc: return lookup_function_type(type);
+       default:
+ 	fprintf(stderr, "[Unimplemented type qualifier: %d]\n", qualifier);
+ 	return type;
+     }
+ }
+ 
+ static struct type *
+ apply_type_modifiers(type, tip, auxp)
+      struct type *type;
+      TIR *tip;
+      AUXU** auxp;
+ {
+     for (;;) {   
+ 	if (tip->tq0 == tqNil) return type;
+ 	type = modify_type(type, tip->tq0, auxp);
+ 	if (tip->tq1 == tqNil) return type;
+ 	type = modify_type(type, tip->tq1, auxp);
+ 	if (tip->tq2 == tqNil) return type;
+ 	type = modify_type(type, tip->tq2, auxp);
+ 	if (tip->tq3 == tqNil) return type;
+ 	type = modify_type(type, tip->tq3, auxp);
+ 	if (tip->tq4 == tqNil) return type;
+ 	type = modify_type(type, tip->tq4, auxp);
+ 	if (tip->tq5 == tqNil) return type;
+ 	type = modify_type(type, tip->tq5, auxp);
+ 	if (!tip->continued) return type;
+ 	tip++;
+     }
+ }
+ 
+ static struct type *
+ read_type(index, widthp)
+      int index;
+      int *widthp; /* if non-NULL: set to (if bit field: width, else:
0) */
+ {
+     TIR *tip;
+     AUXU *aux;
+     struct type *base_type;
+     int width;
+     if (index == 0xfffff) return builtin_type_int; /* no type info */
+ /*    if (index < 0 || index > ) ...; */
+ 
+     aux = &aux_symbol_table[cur_file_descriptor->iauxBase + index];
+     tip = &aux->ti;
+     for ( ; aux->ti.continued; aux++) ;
+     aux++; /* skip last TIR field */
+ 
+     /* sym.h claims that width comes after RNDX, but seems to be wrong
*/
+     width = tip->fBitfield ? (aux++)->width : 0;
+     if (widthp) *widthp = width;
+ 
+     switch (tip->bt) {
+       case btVoid:
+       case btNil: base_type = builtin_type_void; break;
+       case btAdr: base_type = lookup_pointer_type(builtin_type_void);
break;
+       case btChar: base_type = builtin_type_char; break;
+       case btUChar: base_type = builtin_type_unsigned_char; break;
+       case btShort: base_type = builtin_type_short; break;
+       case btUShort: base_type = builtin_type_unsigned_short; break;
+       case btInt: base_type = builtin_type_int; break;
+       case btUInt: base_type = builtin_type_unsigned_int; break;
+       case btLong: base_type = builtin_type_long; break;
+       case btULong: base_type = builtin_type_unsigned_long; break;
+       case btFloat: base_type = builtin_type_float; break;
+       case btDouble: base_type = builtin_type_double; break;
+       case btStruct: case btUnion:
+ 	base_type = read_struct_type(&aux, tip->bt); break;
+       case btEnum:
+ 	base_type = read_enum_type(&aux); break;
+       case btRange:
+ 	base_type = read_range_type(&aux); break;
+       case btTypedef:
+       case btSet: case btComplex: case btDComplex:
+       case btIndirect:
+       case btFixedDec: case btFloatDec: case btString:
+       case btBit: case btPicture:
+       default:
+ 	fprintf(stderr, "[Unimplemented kind of type: %d]\n", tip->bt);
+ 	base_type = builtin_type_void;
+     }
+     return apply_type_modifiers(base_type, tip, &aux);   
+ }
+ 
+ static struct symbol *
+ alloc_symbol(name, value)
+   char *name;
+   int value;
+ {
+   register struct symbol *sym;
+   sym = (struct symbol *)obstack_alloc (symbol_obstack, sizeof(struct
symbol));
+ #ifdef NAMES_HAVE_UNDERSCORE
+   if (name[0] == '_') name++;
+ #endif
+ 
+   bzero (sym, sizeof (struct symbol));
+   SYMBOL_NAME (sym) = obstack_copy0 (symbol_obstack, name, strlen
(name));
+ 
+   /* default assumptions */
+   SYMBOL_VALUE (sym) = value;
+   SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+   SYMBOL_TYPE (sym) = builtin_type_void;
+ 
+   return sym;
+ }
+ 
+ static
+ read_symbol(csym, name)
+   SYMR *csym;
+   char *name;
+ {
+   register struct symbol *sym = alloc_symbol(name, csym->value);
+ 
+   switch (csym->st)
+     {
+     case stNil: break;
+     case stFile:
+       last_source_file = obstack_copy0 (symbol_obstack, name, strlen
(name));
+       break;
+     case stGlobal:
+       SYMBOL_TYPE (sym) = read_type(csym->index, NULL);
+       SYMBOL_CLASS (sym) = LOC_STATIC;
+       add_symbol_to_list (sym, &global_symbols);
+       break;
+     case stStatic:
+       SYMBOL_TYPE (sym) = read_type(csym->index, NULL);
+       SYMBOL_CLASS (sym) = LOC_STATIC;
+       if (within_function) {
+ 	  /* Static symbol of local scope */
+ 	  add_symbol_to_list (sym, &local_symbols);
+       }
+       else {
+ 	  /* Static symbol at top level of file */
+ 	  add_symbol_to_list (sym, &file_symbols);
+       }
+       break;
+ 
+     case stLocal:
+       SYMBOL_TYPE (sym) = read_type(csym->index, NULL);
+       switch (csym->sc) {
+ 	case scRegister: SYMBOL_CLASS (sym) = LOC_REGISTER; break;
+ 	case scAbs:    SYMBOL_CLASS (sym) = LOC_LOCAL; break;
+ 
+       }
+       add_symbol_to_list (sym, &local_symbols);
+       break;
+ 
+     case stParam:
+       SYMBOL_TYPE (sym) = read_type(csym->index, NULL);
+       switch (csym->sc) {
+ 	case scAbs:	  SYMBOL_CLASS (sym) = LOC_ARG; break;
+ 	case scRegister:  SYMBOL_CLASS (sym) = LOC_REGPARM; break;
+ 	case scVar:	  SYMBOL_CLASS (sym) = LOC_REF_ARG; break;
+ 	case scVarRegister: SYMBOL_CLASS (sym) = LOC_REGPARM; break;
/*WRONG!*/
+       }
+       add_symbol_to_list (sym, &local_symbols);
+       break;
+ 
+     case stTypedef:
+       SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+       SYMBOL_TYPE (sym) = read_type(csym->index, NULL);
+       if (within_function) {
+ 	  /* Static symbol of local scope */
+ 	  add_symbol_to_list (sym, &local_symbols);
+       }
+       else {
+ 	  /* Static symbol at top level of file */
+ 	  add_symbol_to_list (sym, &file_symbols);
+       }
+       break;
+     
+     case stEnd:
+     default: break;
+     }
+   return 1;
+ }
+ 
+ static int
+ read_tagged_block (index)
+ {
+   SYMR *csym = &local_symbol_table[cur_isymBase+index];
+   char *name = &local_string_table[cur_issBase+csym->iss];
+   struct pending **symlist = within_function ? &local_symbols:
&file_symbols;
+   register struct symbol *sym;
+ 
+   /* A kludge to decide if this is an enum definition. */
+   if ((csym[1].st == stMember
+        && read_type(csym[1].index, 0) == builtin_type_void)
+    || (csym->st == stBlockPatched
+        && TYPE_CODE((struct type*)(csym->value)) == TYPE_CODE_ENUM))
+ 	{
+ 	  struct type *type = get_enum_type (csym);
+ 	  if (type && TYPE_CODE(type) == TYPE_CODE_ENUM)
+ 	    {
+ 	      int nfields = TYPE_NFIELDS (type);
+ 	      register int i;
+ 	      register struct field *cur_field = TYPE_FIELDS(type);
+ 	      if (name && name[0] && name[0] != '.')
+ 		{
+ 		  sym = alloc_symbol(name, 0);
+ 		  SYMBOL_TYPE (sym) = type;
+ 		  SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+ 		  SYMBOL_NAMESPACE (sym) = STRUCT_NAMESPACE;
+ 		  add_symbol_to_list (sym, symlist);
+ 		}
+ 	      for (i = nfields; --i >= 0; cur_field++)
+ 		{
+ 		  sym = alloc_symbol(cur_field->name, cur_field->bitpos);
+ 		  SYMBOL_CLASS (sym) = LOC_CONST;
+ 		  SYMBOL_TYPE (sym) = type;
+ 		  add_symbol_to_list (sym, symlist);
+ 		}
+ 	      return nfields + 2;
+ 	  }
+       }
+   else
+     {
+       if (name && name[0] && name[0] != '.')
+ 	{
+ 	  struct type *type = get_struct_type (csym, btNil);
+ 	  sym = alloc_symbol(name, 0);
+ 	  SYMBOL_TYPE (sym) = type;
+ 	  SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+ 	  SYMBOL_NAMESPACE (sym) = STRUCT_NAMESPACE;
+ 	  add_symbol_to_list (sym, symlist);
+ 	}
+       return read_symbols (index + 1) + 2; 
+     }
+ }
+ 
+ /* Read symbols until an stEnd symbol is encountered. Return count.
*/
+ 
+ static int
+ read_symbols(index)
+      int index; /* relative to current file */
+ {
+   register struct context_stack *new;
+   static int blocks_seen = 0;
+   int index0 = index;
+   SYMR *start_symbol;
+   for (;;)
+       {
+ 	SYMR *csym = &local_symbol_table[cur_isymBase+index];
+ 	char *name = &local_string_table[cur_issBase+csym->iss];
+ 
+ 	if (dump_stuff)
+ 	    printf("[%s,%x,st%s,sc%s,inx:%d (%x)]\n", name, csym->value,
+ 		   MapStNames[csym->st], MapScNames[csym->sc],
+ 		   csym->index, csym);
+ 
+ 	switch (csym->st)
+ 	    {
+ 	    case stFile:
+ 	      last_source_file =
+ 		  obstack_copy0 (symbol_obstack, name, strlen (name));
+ 	      index++;
+ 	      index += read_symbols(index) + 1;
+ 	      return index - index0;
+ 	    case stBlock:
+ 	    case stBlockPatched:
+ 	      if (csym->sc == scText)
+ 		{ /* lexical block */
+ 		  if (!local_symbol_table[cur_isymBase+csym->index-1].value)
+ 		    {
+ 		      new = 0;
+ 		    }
+ 		  else
+ 		    {
+ 		      new = (struct context_stack *)
+ 			xmalloc (sizeof (struct context_stack));
+ 		      new->next = context_stack;
+ 		      context_stack = new;
+ 		      new->locals = local_symbols;
+ 		      new->old_blocks = pending_blocks;
+ 		      new->start_addr = cur_proc_addr + csym->value;
+ 		      new->name = 0;
+ 		      local_symbols = 0;
+ 		    }
+ 		  blocks_seen++;
+ 		  start_symbol=csym;
+ 		  index++;
+ 		  index += read_symbols (index);
+ 		  csym = &local_symbol_table[cur_isymBase+index];  /* stEnd */
+ 		  index++;
+ 
+ if (csym->st != stEnd ||
+    start_symbol != &local_symbol_table[cur_isymBase+csym->index])
+ abort();
+ 		  if (new)
+ 		    {
+ 		      if (local_symbols && context_stack->next)
+ 			{
+ 			  /* Make a block for the local symbols within.  */
+ 			  finish_block (0, &local_symbols, new->old_blocks,
+ 					new->start_addr,
+ 					cur_proc_addr + csym->value);
+ 			}
+ 		      local_symbols = new->locals;
+ 		      context_stack = new->next;
+ 		      free (new);
+ 		    }
+ 		  }
+ 	      else if (csym->sc == scInfo)
+ 		  index += read_tagged_block (index);
+ 	      break;
+ 	    case stProc:
+ 	    case stStaticProc:
+ 	      {
+ 		PDR *proc = &proc_desc_table
+ 		    [cur_file_descriptor->ipdFirst+cur_proc_number++];
+ 		CORE_ADDR saved_cur_proc_addr = cur_proc_addr;
+ 		struct symbol *sym = alloc_symbol(name, csym->value);
+ 		struct context_stack *saved_context_stack = context_stack;
+ 		int save_blocks_seen = blocks_seen;
+ 		SYMBOL_CLASS (sym) = LOC_BLOCK;
+ 		/* Add one to csym->index, to the skip the isymMac value
+ 		 * (which is there only for st*Proc). */
+ 		SYMBOL_TYPE (sym) = 
+ 		    lookup_function_type (read_type(csym->index+1, NULL));
+ 		if (csym->st == stStaticProc)
+ 		    add_symbol_to_list (sym, &file_symbols);
+ 		else
+ 		    add_symbol_to_list (sym, &global_symbols);
+ 		cur_proc_addr = csym->value;
+ 		within_function++;
+ 		new = (struct context_stack *)
+ 		    xmalloc (sizeof (struct context_stack));
+ 		new->next = 0;
+ 		context_stack = new;
+ 		new->locals = 0;
+ 		new->old_blocks = pending_blocks;
+ 		new->start_addr = csym->value;
+ 		new->name = sym;
+ 		if (dump_stuff)
+ 		   
printf("[PROC:%s,@%x,framereg:%d,froff:%d,rmsk:%d,fmsk:%d,floff:%d,regof
ff:%d,iline:%d,lnLo:%d,lnHi:%d (%x)]\n",
+ 			   name, proc->adr,
+ 		   proc->framereg, proc->frameoffset, proc->regmask,
+ 		   proc->fregmask, proc->fregoffset,
+ 			   proc->regoffset,
+ 			   proc->iline,proc->lnLow,proc->lnHigh, proc);
+ 
+ 		start_symbol = csym;
+ 		index++;
+ 		index += read_symbols(index);
+ 
+ 		csym = &local_symbol_table[cur_isymBase+index];/*stEnd symbol*/
+ 
+ if (csym->st != stEnd ||
+    start_symbol != &local_symbol_table[cur_isymBase+csym->index])
+ abort();
+ 
+ 		index++;
+ 		PROC_SYMBOL(proc) =
+ 		    blocks_seen == save_blocks_seen ? NULL : sym;
+ 		PROC_LOW_ADDR(proc) = start_symbol->value;
+ 		PROC_HIGH_ADDR(proc) = last_end_addr =
+ 		    start_symbol->value + csym->value;
+ 
+ 		finish_block (new->name, &local_symbols, new->old_blocks,
+ 			      start_symbol->value, last_end_addr);
+ 		context_stack = saved_context_stack;
+ 		cur_proc_addr = saved_cur_proc_addr;
+ 		within_function--;
+ 		free (new);
+ 		break;
+ 	      }
+ 
+ 	    case stEnd:
+ #if 1
+ 		    return index - index0;
+ #else
+ 	      start_symbol = &local_symbol_table[cur_isymBase+csym->index];
+ 	      switch (start_symbol->st)
+ 		  {
+ 		  case stProc:
+ 		  case stStaticProc:
+ 		  case stFile:
+ 		  case stBlock:
+ 		  case stBlockPatched:
+ 		    return index - index0;
+ 		  default:
+ 		    index++;
+ 		  }
+ 	      break;
+ #endif
+ 	    default:
+ 	      read_symbol(csym, name);
+ 	      index++;
+ 	    }
+       }
+ }
+ 
+ static int
+ read_coff_symtab (desc, nsyms, symtab_offset)
+      int desc;
+      int nsyms;
+      int symtab_offset;
+ {
+   HDRR hdrr;
+   struct coff_symbol coff_symbol;
+   register struct coff_symbol *cs = &coff_symbol;
+   struct coff_symbol fcn_cs_saved;
+ 
+   int num_object_files = 0;
+   int next_file_symnum = -1;
+   char *filestring;
+   int fcn_first_line;
+   int fcn_last_line;
+   int fcn_start_addr;
+   long fcn_line_ptr;
+   struct cleanup *file_chain, *ext_chain, *old_chain;
+   int isym, ifile;
+ 
+   char *line_number_table;
+   EXTR *external_symbol_table;
+   char *external_string_table;
+   struct linetable **line_vector_all;
+ 
+   if (myread (desc, (char *)&hdrr, sizeof hdrr) != sizeof hdrr)
+     return -1;
+ 
+   file_descriptor_count = hdrr.ifdMax;
+   line_vector_all = (struct linetable**)
+       alloca (file_descriptor_count * sizeof(struct linetable *));
+   global_symbols_all = (struct pending**)
+       alloca (file_descriptor_count * sizeof(struct pending *));
+   file_symbols_all = (struct pending**)
+       alloca (file_descriptor_count * sizeof(struct pending *));
+   proc_desc_length = hdrr.ipdMax;
+   proc_desc_table = (PDR*)
+     read_table(desc, hdrr.ipdMax * sizeof(PDR), hdrr.cbPdOffset);
+   old_chain = make_cleanup (free_all_symtabs, 0);
+   make_cleanup (free_proc_descs, 0);
+   file_descriptor_table = (FDR*)
+     read_table(desc, hdrr.ifdMax * sizeof(FDR), hdrr.cbFdOffset);
+   file_chain = make_cleanup (free, file_descriptor_table);
+ 
+   line_number_table = read_table(desc, hdrr.cbLine,
hdrr.cbLineOffset);
+   ext_chain = make_cleanup (free, line_number_table);
+ 
+   for (ifile = 0; ifile < hdrr.ifdMax; ifile++)
+     {
+       int iproc, ipdMax;
+       char *cur_line_entry;
+       int cur_addr_offset = 0;
+       int cur_addr;
+ 
+       /* Vector of line number information.  */
+       struct linetable *line_vector;
+ 
+       /* Index of next entry to go in line_vector_index.  */
+       int line_vector_index;
+ 
+       /* Number of elements allocated for line_vector currently.  */
+       int line_vector_length;
+ 
+       select_file (ifile);
+       global_symbols_all[ifile] = 0;
+       file_symbols_all[ifile] = 0;
+ 
+       /* read line numbers */
+       cur_addr = cur_file_descriptor->adr;
+       iproc = cur_file_descriptor->ipdFirst;
+ 
+       line_vector_index = 0;
+       line_vector_length = 1000;
+       line_vector = (struct linetable *)
+ 	  xmalloc (sizeof (struct linetable)
+ 		   + line_vector_length * sizeof (struct linetable_entry));
+ 
+       /* we read the line numbers first, since read_symbol
over-writes
+ 	 some of the fields in a proc descriptor */
+       ipdMax = iproc + cur_file_descriptor->cpd;
+       cur_line_entry = line_number_table +
cur_file_descriptor->cbLineOffset;
+       for ( ; iproc < ipdMax; iproc++) {
+ 	PDR *proc = &proc_desc_table[iproc];
+ 	int nlines = (iproc+1 < ipdMax ? (proc+1)->iline :
cur_file_descriptor->cline)
+ 	    - proc->iline;
+ 	int cur_source_line = proc->lnLow;
+ 	if (dump_stuff)
+ 	    printf(
+ 	   
"[proc:%x,framereg:%d,ofset:%d,rmask:%d,flmask:%d,floff:%d,iline:%d,lnLo
o:%d,lnHi:%d,csl:%d]\n",
+ 	       proc->adr,
+ 		   proc->framereg, proc->frameoffset, proc->regmask,
+ 		   proc->fregmask, proc->fregoffset,
+ 	       proc->iline,proc->lnLow,proc->lnHigh, cur_source_line);
+ 	if (proc->iline == -1) continue;
+ 	for (isym = proc->iline; nlines > 0; isym++) {
+ 	  struct linetable_entry *e;
+ 	  int code = *cur_line_entry++;
+ 	  int delta = code >> 4;
+ 	  int count = (code & 15) + 1;
+ 	  if (dump_stuff & 1) printf("%2x", 0xFF & code);
+ 	  if (delta == -8)
+ 	    {
+ 	      if (dump_stuff & 1)
+ 	        printf(" %2x%2x", 0xff & cur_line_entry[0],
+ 		     0xff & cur_line_entry[1]);
+ 	      delta = *cur_line_entry++;
+ 	      delta = (delta << 8) | (unsigned)*cur_line_entry++;
+ 	      isym += 2;
+ 	    }
+ 	  cur_source_line += delta;
+ 	  if (dump_stuff & 1)
+ 	    printf("\t%2d.%2d li:%d %X", delta, count,
+ 		 cur_source_line,
+ 		 cur_file_descriptor->adr + 4 * cur_addr_offset);
+ 
+ 	  e = &line_vector->item[line_vector_index];
+ 	  if (line_vector_index == 0 || e[-1].line != cur_source_line)
+ 	    {
+ 
+ 	      /* Make sure line vector is big enough.  */
+ 	      if (line_vector_index + 2 >= line_vector_length)
+ 		{
+ 		  line_vector_length *= 2;
+ 		  line_vector = (struct linetable *)
+ 		    xrealloc (line_vector, sizeof (struct linetable)
+ 			      + (line_vector_length
+ 				 * sizeof (struct linetable_entry)));
+ 		  e = &line_vector->item[line_vector_index];
+ 		}
+ 
+ 	      e->line = cur_source_line;
+ 	      e->pc = cur_file_descriptor->adr + 4 * cur_addr_offset;
+ 	      line_vector_index++;
+ 	    }
+ 
+ 	  if (delta != 0)
+ 	    {
+ 	      int save_addr = cur_addr;
+ 	      if (cur_addr_offset != 0)
+ 		{
+ 		  int toffset = (cur_addr_offset - 1) * 4;
+ 		  if (dump_stuff & 1)
+ 		  printf(" [li: %d %x-%x]",
+ 			 cur_source_line, cur_addr, cur_addr+toffset);
+ 		}
+ 	      cur_addr = save_addr + cur_addr_offset * 4;
+ 	    }
+ 	  cur_addr_offset += count;
+ 	  nlines -= count;
+ 	  if (dump_stuff & 1) putchar('\n');
+ 	/*  if (delta != 0) { } */
+         }
+       }
+ 
+       line_vector->nitems = line_vector_index;
+       line_vector_all[ifile] = (struct linetable *)
+ 	  xrealloc (line_vector, (sizeof (struct linetable)
+ 		       + line_vector_index * sizeof (struct linetable_entry)));
+     }
+   do_cleanups (ext_chain);
+ 
+   aux_symbol_table = (AUXU*)
+     read_table(desc, hdrr.iauxMax * sizeof(AUXU), hdrr.cbAuxOffset);
+   make_cleanup (free, aux_symbol_table);
+   rel_file_table = (RFDT*)
+     read_table(desc, hdrr.crfd * sizeof(RFDT), hdrr.cbRfdOffset);
+   make_cleanup (free, rel_file_table);
+   local_symbol_table = (SYMR*)
+     read_table(desc, hdrr.isymMax * sizeof(SYMR), hdrr.cbSymOffset);
+   make_cleanup (free, local_symbol_table);
+   local_string_table = read_table(desc, hdrr.issMax,
hdrr.cbSsOffset);
+   make_cleanup (free, local_string_table);
+ 
+   external_symbol_table = (EXTR*)
+     read_table(desc, hdrr.iextMax * sizeof(EXTR), hdrr.cbExtOffset);
+   ext_chain = make_cleanup (free, external_symbol_table);
+   external_string_table = read_table(desc, hdrr.issExtMax,
hdrr.cbSsExtOffset);
+   make_cleanup (free, external_string_table);
+ 
+   /* do the external symbols first */
+   /* The reason is that each file's end_symtab is done with the locals
*/
+ 
+   for (isym = 0; isym < hdrr.iextMax; isym++)
+     {
+       EXTR *ext = &external_symbol_table[isym];
+       SYMR *csym = &ext->asym;
+       char *name = external_string_table+csym->iss;
+       if ((unsigned)ext->ifd >= hdrr.ifdMax) return -1;
+       select_file (ext->ifd);
+       record_misc_function (name, csym->value);
+       if (csym->st != stProc && csym->st != stStaticProc)
+ 	  read_symbol(csym, name);
+ #if 1
+ if (dump_stuff)
+       printf("EXT[%s,%x,st%s,sc%s,inx:%d,ifd:%d]\n",
+ 	     name, csym->value, MapStNames[csym->st],
+ 	     MapScNames[csym->sc], csym->index, ext->ifd);
+ #endif
+     }
+ 
+   do_cleanups (ext_chain);
+ 
+   for (ifile = 0; ifile < hdrr.ifdMax; ifile++)
+     {
+       select_file (ifile);
+ 
+       cur_proc_number = 0;
+       last_end_addr = cur_file_descriptor->adr;
+ 
+       start_symtab ();
+ 
+ if (dump_stuff)
+
printf("<FILE.adr:%x,ilB:%d,cb:%d,cbLO:%d,cbL:%d,iSB:%d,cS:%d,nProcs:%d,
,first:%d>\n",
+        cur_file_descriptor->adr,
+        cur_file_descriptor->ilineBase, cur_file_descriptor->cline,
+        cur_file_descriptor->cbLineOffset,
cur_file_descriptor->cbLine,
+        cur_isymBase, cur_file_descriptor->csym,
+        cur_file_descriptor->cpd,
+        cur_file_descriptor->ipdFirst);
+ 
+       for (isym = 0; isym < cur_file_descriptor->csym; )
+ 	  {
+ 	    int count = read_symbols(isym);
+ 	    if (count == 0)
+ 		{ /* handle un-handled stEnd */
+ 		  SYMR *sym = &local_symbol_table[cur_isymBase+isym];
+ 		  char *name = &local_string_table[cur_issBase+sym->iss];
+ printf("stEnd confusion!");
+ 		  read_symbol(sym, name);
+ 		  count = 1;
+ 		}
+ 	    isym += count;
+ 	  }
+       end_symtab (cur_file_descriptor->adr, last_end_addr,
+ 		  line_vector_all[ifile]);
+     }
+ 
+   do_cleanups (file_chain);
+ 
+   last_source_file = 0;
+   bzero (opaque_type_chain, sizeof opaque_type_chain);
+ 
+   type_vector_length = 160;
+   type_vector = (struct typevector *)
+ 		xmalloc (sizeof (struct typevector)
+ 				+ type_vector_length * sizeof (struct type *));
+   bzero (type_vector->type, type_vector_length * sizeof (struct type
*));
+ 
+   if (last_source_file)
+     end_symtab ();
+   discard_cleanups (old_chain);
+   return 0;
+ }
+ 
+ /* Routines for reading headers and symbols from executable.  */
+ 
+ /* Read COFF file header, check magic number,
+    and return number of symbols. */
+ read_file_hdr (chan, file_hdr)
+     int chan;
+     FILHDR *file_hdr;
+ {
+   lseek (chan, 0L, 0);
+   if (myread (chan, (char *)file_hdr, FILHSZ) < 0)
+     return -1;
+ 
+   switch (file_hdr->f_magic)
+     {
+ #ifdef MIPSEBMAGIC
+     case MIPSEBMAGIC:
+ #endif
+ #ifdef MIPSELMAGIC
+     case MIPSELMAGIC:
+ #endif
+ #ifdef MC68MAGIC
+     case MC68MAGIC:
+ #endif
+ #ifdef NS32GMAGIC
+       case NS32GMAGIC:
+       case NS32SMAGIC:
+ #endif
+ #ifdef I386MAGIC
+     case I386MAGIC:
+ #endif
+ #ifdef CLIPPERMAGIC
+     case CLIPPERMAGIC:
+ #endif      
+ 	return file_hdr->f_nsyms;
+ 
+       default:
+ #ifdef BADMAG
+ 	if (BADMAG(file_hdr))
+ 	  return -1;
+ 	else
+ 	  return file_hdr->f_nsyms;
+ #else
+ 	return -1;
+ #endif
+     }
+ }
+ 
+ read_aout_hdr (chan, aout_hdr, size)
+     int chan;
+     AOUTHDR *aout_hdr;
+     int size;
+ {
+   lseek (chan, (long)FILHSZ, 0);
+   if (size != sizeof (AOUTHDR))
+     return -1;
+   if (myread (chan, (char *)aout_hdr, size) != size)
+     return -1;
+   return 0;
+ }
+ 
+ read_section_hdr (chan, section_name, section_hdr, nsects)
+     register int chan;
+     register char *section_name;
+     SCNHDR *section_hdr;
+     register int nsects;
+ {
+   register int i;
+ 
+   if (lseek (chan, FILHSZ + sizeof (AOUTHDR), 0) < 0)
+     return -1;
+ 
+   for (i = 0; i < nsects; i++)
+     {
+       if (myread (chan, (char *)section_hdr, SCNHSZ) < 0)
+ 	return -1;
+       if (strncmp (section_hdr->s_name, section_name, 8) == 0)
+ 	return 0;
+     }
+     return -1;
+ }
+ 
+ 
+ /* Support for string table handling */
+ 
+ static char *stringtab = NULL;
+ 
+ 
+ #if 0
+ static char *
+ getsymname (symbol_entry)
+     SYMENT *symbol_entry;
+ {
+   static char buffer[SYMNMLEN+1];
+   char *result;
+ 
+   if (symbol_entry->n_zeroes == 0)
+     {
+       result = stringtab + symbol_entry->n_offset;
+     }
+   else
+     {
+       strncpy (buffer, symbol_entry->n_name, SYMNMLEN);
+       buffer[SYMNMLEN] = '\0';
+       result = buffer;
+     }
+   return result;
+ }
+ #endif
+ 
+ /* Support for line number handling */
+ static char *linetab = NULL;
+ static long linetab_offset;
+ static int linetab_count;
+ 
+ static int
+ hashname (name)
+      char *name;
+ {
+   register char *p = name;
+   register int total = p[0];
+   register int c;
+ 
+   c = p[1];
+   total += c << 2;
+   if (c)
+     {
+       c = p[2];
+       total += c << 4;
+       if (c)
+ 	total += p[3] << 6;
+     }
+   
+   return total % HASHSIZE;
+ }
+ 
+ static void
+ patch_type (type, real_type)
+     struct type *type;
+     struct type *real_type;
+ {
+   register struct type *target = TYPE_TARGET_TYPE (type);
+   register struct type *real_target = TYPE_TARGET_TYPE (real_type);
+   int field_size = TYPE_NFIELDS (real_target) * sizeof (struct
field);
+ 
+   TYPE_LENGTH (target) = TYPE_LENGTH (real_target);
+   TYPE_NFIELDS (target) = TYPE_NFIELDS (real_target);
+   TYPE_FIELDS (target) = (struct field *)
+ 				obstack_alloc (symbol_obstack, field_size);
+ 
+   bcopy (TYPE_FIELDS (real_target), TYPE_FIELDS (target),
field_size);
+ 
+   if (TYPE_NAME (real_target))
+     {
+       if (TYPE_NAME (target))
+ 	free (TYPE_NAME (target));
+       TYPE_NAME (target) = concat (TYPE_NAME (real_target), "", "");
+     }
+ }
+ 
+ /* Patch up all appropriate typdef symbols in the opaque_type_chains
+    so that they can be used to print out opaque data structures
properly */
+ 
+ static void
+ patch_opaque_types ()
+ {
+   struct symtab *s;
+ 
+   /* Look at each symbol in the per-file block of each symtab.  */
+   for (s = symtab_list; s; s = s->next)
+     {
+       register struct block *b;
+       register int i;
+ 
+       /* Go through the per-file symbols only */
+       b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), 1);
+       for (i = BLOCK_NSYMS (b) - 1; i >= 0; i--)
+ 	{
+ 	  register struct symbol *real_sym;
+ 
+ 	  /* Find completed typedefs to use to fix opaque ones.
+ 	     Remove syms from the chain when their types are stored,
+ 	     but search the whole chain, as there may be several syms
+ 	     from different files with the same name.  */
+ 	  real_sym = BLOCK_SYM (b, i);
+ 	  if (SYMBOL_CLASS (real_sym) == LOC_TYPEDEF &&
+ 	      SYMBOL_NAMESPACE (real_sym) == VAR_NAMESPACE &&
+ 	      TYPE_CODE (SYMBOL_TYPE (real_sym)) == TYPE_CODE_PTR &&
+ 	      TYPE_LENGTH (TYPE_TARGET_TYPE (SYMBOL_TYPE (real_sym))) != 0)
+ 	    {
+ 	      register char *name = SYMBOL_NAME (real_sym);
+ 	      register int hash = hashname (name);
+ 	      register struct symbol *sym, *prev;
+ 
+ 	      prev = 0;
+ 	      for (sym = opaque_type_chain[hash]; sym;)
+ 		{
+ 		  if (name[0] == SYMBOL_NAME (sym)[0] &&
+ 		      !strcmp (name + 1, SYMBOL_NAME (sym) + 1))
+ 		    {
+ 		      if (prev)
+ 			SYMBOL_VALUE (prev) = SYMBOL_VALUE (sym);
+ 		      else
+ 			opaque_type_chain[hash]
+ 			  = (struct symbol *) SYMBOL_VALUE (sym);
+ 
+ 		      patch_type (SYMBOL_TYPE (sym), SYMBOL_TYPE (real_sym));
+ 
+ 		      if (prev)
+ 			sym = (struct symbol *) SYMBOL_VALUE (prev);
+ 		      else
+ 			sym = opaque_type_chain[hash];
+ 		    }
+ 		  else
+ 		    {
+ 		      prev = sym;
+ 		      sym = (struct symbol *) SYMBOL_VALUE (sym);
+ 		    }
+ 		}
+ 	    }
+ 	}
+     }
+ }
+ 
+ /* This function is really horrible, but to avoid it, there would
need
+    to be more filling in of forward references.  THIS SHOULD BE MOVED
+    OUT OF COFFREAD.C AND DBXREAD.C TO SOME PLACE WHERE IT CAN BE
SHARED. */
+ int
+ fill_in_vptr_fieldno (type)
+      struct type *type;
+ {
+   if (TYPE_VPTR_FIELDNO (type) < 0)
+     TYPE_VPTR_FIELDNO (type) =
+       fill_in_vptr_fieldno (TYPE_BASECLASS (type, 1));
+   return TYPE_VPTR_FIELDNO (type);
+ }
+ 
+ /* partial symbol tables are not implemented in coff, therefore
+    block_for_pc() (and others) will never decide to call this. */
+ 
+ extern struct symtab *
+ psymtab_to_symtab ()
+ {
+   fatal ("error: Someone called psymtab_to_symtab\n");
+ }
+ 
+ /* These will stay zero all the time */
+ struct psymbol_allocation_list global_psymbols, static_psymbols;
*** munch.orig	Wed Jul  5 15:46:28 1989
--- munch	Mon Nov  5 10:28:33 1990
***************
*** 8,17 ****
  if test "$1" = "-DSYSV" ; then
      shift;
      nm $* | egrep '^(.*[^a-zA-Z_]_|_)initialize_' | \
  	sed -e 's/^.*\(_initialize_[a-zA-Z0-9_]*\)[^a-zA-Z0-9_].*$/   \1
();/'
  else
!     nm -p $* | egrep 'T *__initialize_' | \
  	sed -e 's/^.*T *_*\(.*\)/    _\1 ();/'
  fi
  
  echo '}'
--- 8,17 ----
  if test "$1" = "-DSYSV" ; then
      shift;
      nm $* | egrep '^(.*[^a-zA-Z_]_|_)initialize_' | \
  	sed -e 's/^.*\(_initialize_[a-zA-Z0-9_]*\)[^a-zA-Z0-9_].*$/   \1
();/'
  else
!     nm -p $* | egrep 'T *_?_initialize_' | \
  	sed -e 's/^.*T *_*\(.*\)/    _\1 ();/'
  fi
  
  echo '}'
*** valops.c.orig	Thu Dec 28 16:28:29 1989
--- valops.c	Mon Nov  5 10:28:34 1990
***************
*** 653,662 ****
--- 653,665 ----
  	struct_addr = sp;
  	sp += TYPE_LENGTH (value_type);
  #endif
        }
      
+ #ifdef PUSH_ARGUMENTS
+   PUSH_ARGUMENTS(nargs, args, sp, struct_return, struct_addr);
+ #else /* !PUSH_ARGUMENTS */
    for (i = nargs - 1; i >= 0; i--)
      sp = value_arg_push (sp, args[i]);
  
  #ifdef CALL_DUMMY_STACK_ADJUST
  #if 1 INNER_THAN 2
***************
*** 675,684 ****
--- 678,688 ----
       Also note that on some machines (like the sparc) pcc uses this
       convention in a slightly twisted way also.  */
  
    if (struct_return)
      STORE_STRUCT_RETURN (struct_addr, sp);
+ #endif /* !PUSH_ARGUMENTS */
  
    /* Write the stack pointer.  This is here because the statement
above
       might fool with it */
    write_register (SP_REGNUM, sp);
  
*** valprint.c.orig	Thu Feb  1 17:48:29 1990
--- valprint.c	Mon Nov  5 10:28:35 1990
***************
*** 530,541 ****
  			}
  		      else
  			string[i++] = c;
  		    }
  
! 		  if (i != 0)
! 		    print_string (stream, string, i, force_ellipses);
  		  if (out_of_bounds)
  		    fprintf_filtered (stream,
  				      " <Address 0x%x out of bounds>",
  				      (*(int *) valaddr) + i);
  		}
--- 530,540 ----
  			}
  		      else
  			string[i++] = c;
  		    }
  
! 		  print_string (stream, string, i, force_ellipses);
  		  if (out_of_bounds)
  		    fprintf_filtered (stream,
  				      " <Address 0x%x out of bounds>",
  				      (*(int *) valaddr) + i);
  		}

bush@evax.arl.utexas.edu (Joe Bush) (11/08/90)

	Speaking of GNU's gdb and other such tools, does anyone know
of a debugger that will run under Ultrix and allows the user to debug
across a fork boundry. By that I mean, automatically suspend both the
parent and child processes a the fork and allow the user to select,
say, a child process and trace its source code. Perhaps stepping back
and forth between the parent and child a will. 
	We recently acquired a Sequent Symmetry with a parallel
debugger called pdbx that allows this function. It is real handy.
GNU's gdb has an "attach" function but it does seem to work under
Ultrix 3.1 on a uVAX 3900. Is this a limitation of the debugger, the
"ptrace" system call, or the underlying architecture?

	





-- 
	  bush@evax.arl.utexas.edu		  Vax Systems Manager
	  (817) 273 - 3333			  CSE Dept. UT-Arlington
	  Office Rm 221 EB2			  403 South Cooper
	  P.O. Box 19015			  Arlington, Texas 76019