]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Initial revision
authorK. Richard Pixley <rich@cygnus>
Thu, 28 Mar 1991 16:26:26 +0000 (16:26 +0000)
committerK. Richard Pixley <rich@cygnus>
Thu, 28 Mar 1991 16:26:26 +0000 (16:26 +0000)
71 files changed:
gdb/COPYING [new file with mode: 0644]
gdb/ChangeLog [new file with mode: 0644]
gdb/ChangeLog-3.x [new file with mode: 0644]
gdb/Makefile.in [new file with mode: 0644]
gdb/README [new file with mode: 0644]
gdb/arm-tdep.c [new file with mode: 0644]
gdb/blockframe.c [new file with mode: 0644]
gdb/breakpoint.c [new file with mode: 0644]
gdb/breakpoint.h [new file with mode: 0644]
gdb/coffread.c [new file with mode: 0644]
gdb/command.h [new file with mode: 0644]
gdb/copying.awk [new file with mode: 0644]
gdb/copying.c [new file with mode: 0644]
gdb/dbxread.c [new file with mode: 0644]
gdb/defs.h [new file with mode: 0644]
gdb/environ.c [new file with mode: 0644]
gdb/environ.h [new file with mode: 0644]
gdb/eval.c [new file with mode: 0644]
gdb/exec.c [new file with mode: 0644]
gdb/expprint.c [new file with mode: 0644]
gdb/expression.h [new file with mode: 0644]
gdb/findvar.c [new file with mode: 0644]
gdb/frame.h [new file with mode: 0644]
gdb/gdb-int.texinfo [new file with mode: 0755]
gdb/gdbcmd.h [new file with mode: 0644]
gdb/gdbcore.h [new file with mode: 0644]
gdb/i386-tdep.c [new file with mode: 0644]
gdb/infcmd.c [new file with mode: 0644]
gdb/inferior.h [new file with mode: 0644]
gdb/inflow.c [new file with mode: 0644]
gdb/infptrace.c [new file with mode: 0644]
gdb/infrun.c [new file with mode: 0644]
gdb/inftarg.c [new file with mode: 0644]
gdb/m68k-tdep.c [new file with mode: 0644]
gdb/main.c [new file with mode: 0644]
gdb/mem-break.c [new file with mode: 0644]
gdb/mips-tdep.c [new file with mode: 0644]
gdb/mipsread.c [new file with mode: 0644]
gdb/printcmd.c [new file with mode: 0644]
gdb/remote-sa.m68k.shar [new file with mode: 0755]
gdb/remote.c [new file with mode: 0644]
gdb/solib.c [new file with mode: 0644]
gdb/source.c [new file with mode: 0644]
gdb/sparc-tdep.c [new file with mode: 0644]
gdb/stack.c [new file with mode: 0644]
gdb/symfile.c [new file with mode: 0644]
gdb/symfile.h [new file with mode: 0644]
gdb/symmisc.c [new file with mode: 0644]
gdb/symtab.c [new file with mode: 0644]
gdb/symtab.h [new file with mode: 0644]
gdb/target.c [new file with mode: 0644]
gdb/target.h [new file with mode: 0644]
gdb/terminal.h [new file with mode: 0644]
gdb/utils.c [new file with mode: 0644]
gdb/valarith.c [new file with mode: 0644]
gdb/valops.c [new file with mode: 0644]
gdb/valprint.c [new file with mode: 0644]
gdb/value.h [new file with mode: 0644]
readline/COPYING [new file with mode: 0644]
readline/Makefile.in [new file with mode: 0644]
readline/chardefs.h [new file with mode: 0644]
readline/emacs_keymap.c [new file with mode: 0644]
readline/funmap.c [new file with mode: 0644]
readline/history.c [new file with mode: 0644]
readline/history.h [new file with mode: 0644]
readline/keymaps.c [new file with mode: 0644]
readline/keymaps.h [new file with mode: 0644]
readline/readline.c [new file with mode: 0644]
readline/readline.h [new file with mode: 0644]
readline/vi_keymap.c [new file with mode: 0644]
readline/vi_mode.c [new file with mode: 0644]

diff --git a/gdb/COPYING b/gdb/COPYING
new file mode 100644 (file)
index 0000000..9a17037
--- /dev/null
@@ -0,0 +1,249 @@
+
+                   GNU GENERAL PUBLIC LICENSE
+                    Version 1, February 1989
+
+ Copyright (C) 1989 Free Software Foundation, Inc.
+                    675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The license agreements of most software companies try to keep users
+at the mercy of those companies.  By contrast, our General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  The
+General Public License applies to the Free Software Foundation's
+software and to any other program whose authors commit to using it.
+You can use it for your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Specifically, the General Public License is designed to make
+sure that you have the freedom to give away or sell copies of free
+software, that you receive source code or can get it if you want it,
+that you can change the software or use pieces of it in new free
+programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of a such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must tell them their rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any program or other work which
+contains a notice placed by the copyright holder saying it may be
+distributed under the terms of this General Public License.  The
+"Program", below, refers to any such program or work, and a "work based
+on the Program" means either the Program or any work containing the
+Program or a portion of it, either verbatim or with modifications.  Each
+licensee is addressed as "you".
+
+  1. You may copy and distribute verbatim copies of the Program's source
+code as you receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice and
+disclaimer of warranty; keep intact all the notices that refer to this
+General Public License and to the absence of any warranty; and give any
+other recipients of the Program a copy of this General Public License
+along with the Program.  You may charge a fee for the physical act of
+transferring a copy.
+
+  2. You may modify your copy or copies of the Program or any portion of
+it, and copy and distribute such modifications under the terms of Paragraph
+1 above, provided that you also do the following:
+
+    a) cause the modified files to carry prominent notices stating that
+    you changed the files and the date of any change; and
+
+    b) cause the whole of any work that you distribute or publish, that
+    in whole or in part contains the Program or any part thereof, either
+    with or without modifications, to be licensed at no charge to all
+    third parties under the terms of this General Public License (except
+    that you may choose to grant warranty protection to some or all
+    third parties, at your option).
+
+    c) If the modified program normally reads commands interactively when
+    run, you must cause it, when started running for such interactive use
+    in the simplest and most usual way, to print or display an
+    announcement including an appropriate copyright notice and a notice
+    that there is no warranty (or else, saying that you provide a
+    warranty) and that users may redistribute the program under these
+    conditions, and telling the user how to view a copy of this General
+    Public License.
+
+    d) You may charge a fee for the physical act of transferring a
+    copy, and you may at your option offer warranty protection in
+    exchange for a fee.
+
+Mere aggregation of another independent work with the Program (or its
+derivative) on a volume of a storage or distribution medium does not bring
+the other work under the scope of these terms.
+\f
+  3. You may copy and distribute the Program (or a portion or derivative of
+it, under Paragraph 2) in object code or executable form under the terms of
+Paragraphs 1 and 2 above provided that you also do one of the following:
+
+    a) accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of
+    Paragraphs 1 and 2 above; or,
+
+    b) accompany it with a written offer, valid for at least three
+    years, to give any third party free (except for a nominal charge
+    for the cost of distribution) a complete machine-readable copy of the
+    corresponding source code, to be distributed under the terms of
+    Paragraphs 1 and 2 above; or,
+
+    c) accompany it with the information you received as to where the
+    corresponding source code may be obtained.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form alone.)
+
+Source code for a work means the preferred form of the work for making
+modifications to it.  For an executable file, complete source code means
+all the source code for all modules it contains; but, as a special
+exception, it need not include source code for modules which are standard
+libraries that accompany the operating system on which the executable
+file runs, or for standard header files or definitions files that
+accompany that operating system.
+
+  4. You may not copy, modify, sublicense, distribute or transfer the
+Program except as expressly provided under this General Public License.
+Any attempt otherwise to copy, modify, sublicense, distribute or transfer
+the Program is void, and will automatically terminate your rights to use
+the Program under this License.  However, parties who have received
+copies, or rights to use copies, from you under this General Public
+License will not have their licenses terminated so long as such parties
+remain in full compliance.
+
+  5. By copying, distributing or modifying the Program (or any work based
+on the Program) you indicate your acceptance of this license to do so,
+and all its terms and conditions.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the original
+licensor to copy, distribute or modify the Program subject to these
+terms and conditions.  You may not impose any further restrictions on the
+recipients' exercise of the rights granted herein.
+\f
+  7. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of the license which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+the license, you may choose any version ever published by the Free Software
+Foundation.
+
+  8. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+       Appendix: How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to humanity, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these
+terms.
+
+  To do so, attach the following notices to the program.  It is safest to
+attach them to the start of each source file to most effectively convey
+the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 1, or (at your option)
+    any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19xx name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the
+appropriate parts of the General Public License.  Of course, the
+commands you use may be called something other than `show w' and `show
+c'; they could even be mouse-clicks or menu items--whatever suits your
+program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  program `Gnomovision' (a program to direct compilers to make passes
+  at assemblers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
new file mode 100644 (file)
index 0000000..12ec9cc
--- /dev/null
@@ -0,0 +1,4297 @@
+Sat Mar 23 10:02:21 1991  John Gilmore  (gnu at cygint.cygnus.com)
+
+       Cleanup for release 3.94.2:
+
+       * Makefile.dist: Pull REMOTE_OBS.  Fix saber includes for BFD
+       include files.  Roll version to 3.94.2.
+       
+       * coffread.c (init_stringtab):  Read length into unsigned char
+       array before swapping; don't assume 32-bit longs.
+
+       * target.c (target_info): Don't bother with get_sym_file, just use
+       the symfile global variable.
+       * symtab.h, symfile.c (get_sym_file):  Delete it.
+
+       * dbxread.c (dbx_symfile_init):  Don't depend on long == 4 bytes.
+       (define_symbol):  Set symbol line number to 0 if not gcc-compiled.
+       (read_type):  Replace one more error() with complain().
+
+       * mipsread.c (parse_partial_symbols):  Replace printf with complain.
+
+       * i960-tdep.c:  Fix copyright attribution.
+
+       * config.gdb:  Quote all backquotes in doublequotes.  You can
+       quote me on that.  BSD 4.4 shell found this one.
+
+       * infptrace.c (throughout):  The third argument to ptrace is an
+       int *, not an int.
+
+       * infrun.c (wait_for_inferior):  When program has terminated, we
+       have to call target_terminal_ours before we pop that target off
+       the stack (e.g. before a call to target_kill or
+       target_mourn_inferior).  This fixes problem where a program
+       terminates, then GDB stops for (tty output) and you have to type
+       "fg" to the shell to resume it.  FIXME:  This code for what to
+       do after termination really should be in normal_stop instead.
+
+       * gdbcore.h (read_memory_check):  Change declaration; it changed
+       names months ago.
+
+       * terminal.h:  Include <sgtty.h> before <sys/ioctl.h>, since in BSD
+       4.4 prereleases, this avoids a bug in their sgtty compatability
+       support.
+       * remote.c:  Use terminal.h rather than hand-rolling the same.
+
+       * signame.c, signame.h (psignal):  Arg is unsigned, not int.
+       * utils.c (strsave, strstr):  Fix arg types.
+       * valprint.c (val_print):  lint
+
+       MIPS symbol table support from Per Bothner:
+
+       * symfile.c (symtab_fns):  Remove initializer table that needs to
+       be hacked for each new symbol file format supported.
+       (add_symtab_fns):  New function, chains symbol table
+       handlers into the global list.
+       (symfile_init):  Search this list.
+       * symfile.h:  Add next pointer, declare add_symtab_fns.
+       * coffread.c (_initialize_coffread): Call add_symtab_fns.
+       * dbxread.c (_initialize_dbxread):  Call add_symtab_fns.
+
+       * mipsread.c (psymtab_to_symtab_1): return void instead of (struct
+       symbol *).  Thus, we no longer need the hack to trash
+       pst->filename.  Good, since that hack confused code in symfile.c!
+
+       (reorder_symtabs, destroy_all_symtabs):  Removed static
+       all_symtabs, which was used to qsort symtabs in reorder_symtabs.
+       Instead, the latter now uses a temporary array (stack-allocated
+       from an obstack, and then freed).
+
+       (parse_symbol):  Added a hack to fix up BLOCK_{START,END} if they
+       haven't been set in the outermost stBlock of a procedure. This was
+       a problem with f77 binaries on Ultrix 4.?.
+
+       (new_symtab, new_symbol, new_type):  Continue changing code to use
+       obstacks more and otherwise conform to dbxread internal style.
+       Made the free_code of symtabs be free_linetable (as in dbxread)
+       instead of free_contents.  This implies memory leaks when reading
+       a new symbol table, until the conversion is finished. Did change
+       (struct symbol) and (struct type) to be allocated on the
+       symbol_obstack.  Blocks and blockvectors are among the things
+       still "leaking."
+
+       * mipsread.c (parse_partial_symbols, parse_fdr):  It hasn't been
+       tested much, but it solved one problem (reported by Meissner), and
+       cleans up some other things.  The problem happened when an
+       included file contains actual code (functions) and not just
+       definitions. The mips coff is a little inconvenient there, since
+       it may cause a procedure to be mapped to the wrong psymtab.
+
+       * mips-tdep.c (heuristic_proc_desc):  Minor cleanup.
+       * mips-xdep.c (fetch_core_registers):  Minor cleanup.  FIXME,
+       this will need work for the new core paradigm.
+
+       Opcode patches from the net:
+
+       * mips-opcode.h: fix incorrect disassembly of the mfc1, cfc1, and
+       ctc1 instructions. Also, the cvt.d.w and cvt.s.w instructions were
+       missing altogether - they are added here.  From Bruce Bauman.
+       * mips-opcode.h:  The low mask for C0 instructions was too small.
+       From Garrett Lau.  I modified the fix to check the entire 32-bit
+       opcode.
+
+       * ns32k-opcode.h:  Fix opcodes for deiw and deid.  From Bruce
+       Bauman.
+
+Thu Mar 21 12:56:46 1991  John Gilmore  (gnu at cygint.cygnus.com)
+
+       Roll in changes from Per Bothner (Tue, 25 Sep 90 11:11:04):
+
+       * dbxread.c (read_type): Pointer subtraction (value_sub in
+       valarith.c) sometimes failed because the types of the
+        pointers being subtracted were not identical.
+       These differed because dbxread.c was allocating pointer types
+       using dbx_alloc_type+smash_to_pointer_type instead of
+       lookup_pointer_type. I failed to find a justification for the
+       former, so I changed it to use the latter. Similarly, I
+       replaced smash_to_function_type by lookup_function_type,
+       and smash_to_reference_type by lookup_reference_type.
+
+       * mipsread.c (parse_symbol, upgrade_type, parse_procedure, 
+       _initialize_mipsread):  corresponding changes.
+
+       * symtab.c (smash_to_{pointer,reference,function}_type): eliminate.
+
+       * source.c (mod_path): Do tilde_expand on each component of the path,
+       rather than on the (list of) paths as a whole.
+       (print_source_lines):  Set first_line_listed in addition to
+       current_source_symtab and current_source_line.  If the source was
+       not findable, after a "dir" command to fix the problem,
+       a "list" would get the wrong lines.
+
+       While I was there... (gnu):
+
+       * dbxread.c (read_type):  Change error to complaint.
+
+Thu Mar 21 12:56:46 1991  John Gilmore  (gnu at cygint.cygnus.com)
+
+       First attempt at detailed understanding of symbol table memory alloc.
+
+       * dbxread.c (dbx_symfile_read):  Free our string table if we
+       aren't the mainline.  Free the "info" struct since we're done with
+       it. 
+       (init_psymbol_list):  Free any previously allocated psymbol lists.
+       (): FIXME: Should realloc-down the psymbol lists when done reading
+       the main symbol file?
+
+       * symmisc.c (free_symtab):  Free fullname field too.
+
+       * xm-hp300hpux.h (USG):  #undef then #define so Makefile can -D.
+       (REGISTER_ADDR):  Make result type unsigned int.
+
+       * xconfig/{i386*,hp300hpux,altosgas,altos}:  All config files that
+       define REGEX must also define REGEX1 (its dependency).
+
+Tue Mar 19 21:28:57 1991  John Gilmore  (gnu at cygint.cygnus.com)
+
+       * tconfig/i960:  No longer works, points you at vxworks960 or
+       nindy960.
+
+       * xgdb.c, XGDB-README:  Remove file.  Users can get the much
+       better xxgdb.
+       * Makefile.dist:  Remove all trace of xgdb.
+
+       * breakpoint.c (breakpoint_1):  Pass demangle arg to
+       print_address_symbolic.
+       (clear_breakpoints):  Remove unused function.
+       (breakpoint_re_set_one):  Guts of breakpoint_re_set.
+       (breakpoint_re_set):  Use catch_errors to do them all anyway.
+
+       * gdb-int.texinfo (Host versus Target):  Add section on what is
+       a "host" feature versus what is a "target" feature.
+
+       * infcmd.c (path_command, path_info):  Handle the PATH variable
+       (object search path) as conveniently as the source search path.
+       * environ.c (set_in_environ):  Set some vars in GDB's environment,
+       in addition to the child's.  PATH, G960BASE, G960BIN for starters.
+       * source.c (mod_path):  New function, from guts of
+       directory_command, modifies a path.  Used by path_command.
+       (directory_command):  Call it.
+       * defs.h (strsave):  Declare.
+
+       * utils.c (sevenbit_strings):  Add new printing option.
+       (printchar):  Use it.
+       (strsave):  Provide this handy helper routine.
+       (set_width_command):  Rename set_screen_width_command.
+       (_initialize_utils):  "set screen-width" => "set width";
+       "set screen-height" => "set height"; add sevenbit-strings.
+
+       * infcmd.c (do_registers_info):  Print floating point registers
+       in raw hex as well as float format, regardless of whether it is
+       a "virtual" convertible register.
+       * tm-sparc.h (PRINT_REGISTER_HOOK):  Print every pair of float
+       regs as a double, just in case it's being used that way.        
+       * values.c (unpack_long):  Comment on array/function coercion.
+       (unpack_double):  Argument is in target byte order now.  For
+       integer arguments, just call unpack_long and float the result.
+       * m68k-tdep.c: include defs.h for "const" handling.
+       * remote-nindy.c:  Use ieee-float stuff.
+       (nindy_fetch_registers):  Unpack double regs to host double, then
+       to extended.
+       (nindy_store_registers):  Pack extendeds to host double, flip
+       around by misusing unpack_double, send as target double.
+
+       * tm-vxworks68.h (FRAME_CHAIN):  Handle current frame pointer of
+       zero, as when stopped at the first instruction of a process.
+
+       * blockframe.c:  Fix filename in comment (param.h => tm.h).
+       * sparc-tdep.c (skip_prologue):  More explicit nudging comments.
+       * tm-68k.h:  Fix typos.
+
+Fri Mar 15 01:09:34 1991  John Gilmore  (gnu at cygint.cygnus.com)
+
+       Changes from a bringup on the DEC Vax under Ultrix 4.0.
+
+       * coredep.c (fetch_core_registers):  Pass end-address of register
+       section to register_addr as expected.  Don't call supply_register
+       if we'd just pass it garbage.
+
+       * dbxread.c (read_dbx_symtab):  Skip N_NSYMS on Ultrix.
+
+       * exec.c (xfer_memory):  Use boolean xfer_fn result, not int.
+
+       * target.c (push_target, target_info):  Cast enums to int for < or
+       > comparison.
+
+       * stack.c (print_frame_info):  Identify source file & line
+       even if we can't print it.
+
+       * xm-vax.h (MISSING_VPRINTF):  No longer missing in Ultrix V4.0.
+
+Sat Mar  9 10:08:20 1991  John Gilmore  (gnu at cygint.cygnus.com)
+
+       Clean up IEEE floating point support.
+
+       * ieee-float.h:  New file.
+       * ieee-float.c:  Write real routines to convert between host
+       doubles and various target IEEE extendeds.
+       * m68k-xdep.c:  Eliminate assembler code for extended floats.
+       * xconfig/{3b1,altos,altosgas,hp300bsd,isi,news,news1000,sun2os3,
+       sun2os4,sun3,sun3os3,sun3os4}:  Eliminate use of m68k-xdep.o.
+       * tm-i960.h, tm-68k.h (REGISTER_CONVERT_TO_VIRTUAL,
+       REGISTER_CONVERT_TO_RAW):  Use ieee_extended_to_double and
+       double_to_ieee_extended.
+       * i960-tdep.c:  Define ext_format_i960.
+       * m68k-tdep.c:  Define ext_format_68881.
+       * sparc-tdep.c:  Define ext_format_sparc, though unused.
+       * Makefile.dist (HFILES):  Add ieee-float.h.
+       * inftarg.c: #include "ieee-float.h" for the REGISTER_CONVERT
+       macros.
+
+       Obsolete the "coffstrip" program in favor of using BFD's strip.
+
+       * nindy-share/coffstrip.c:  Remove file.
+       * nindy-share/nindy.c (coffstrip):  Routine to run bfd_strip.
+       * Makefile.dist:  Remove references to nindy-share/coffstrip.c.
+       * tconfig/nindy960:  Remove reference to coffstrip.o.
+
+       * Makefile.dist:  Roll version number to 3.94.1 (not yet final).
+
+Wed Mar  6 09:56:45 1991  John Gilmore  (gnu at cygint.cygnus.com)
+
+       * symfile.h:  Add symfile_bfd, common between dbxread and coffread.
+       * dbxread.c:  Remove static symfile_bfd.
+       * infcmd.c (do_registers_info):  Add PRINT_REGISTER_HOOK, though
+       it is not used yet.
+       * inftarg.c (child_detach):  Pop the child_ops vector if the
+       detach is successful.
+       * remote-nindy.c (nindy_create_inferior):  Don't push a new
+       nindy_ops since nindy uses the same one for execution and memory
+       examination anyway.
+       * core.c (core_ops):  Use child_attach and child_create_inferior
+       rather than default attach and create_inferior functions.
+
+       Handle floating point registers in core files.
+
+       * sparc-xdep.c (fetch_core_registers):  Rewrite for float support.
+       * sun3-xdep.c (fetch_core_registers):  Rewrite for float support.
+       This version untested since BFD doesn't yet support sun3 core
+       files.
+       * hp300hpux-xdep.c:  Rewrite fetch_core_registers to new calling
+       conventions.  Fix comments and style.  This version has not
+       been compiled yet, since we have no HP inhouse.
+       * core.c (get_core_registers):  Look for two sections, ".reg"
+       and ".reg2", and pass both to fetch_core_registers sequentially.
+
+       Revise directory path yet again.
+
+       * source.c (forget_cached_source_info):  Not static any more.
+       (init_source_path):  New default source path is "$cdir:$cwd".
+       (dir_command):  Handle variable arguments ($cdir, $cwd).
+       (source_info):  Print "Compilation directory" rather than
+       "Originally compiled in" to remind people of $cdir.
+       (openp):  If the path contains $cwd, use current directory.
+       (open_source_file):  If compilation directory is known, replace
+       first $cdir in path with the compilation directory.
+       (print_source_lines):  Even if we can't print the lines, set the
+       current symtab and line for future commands like "info source" or
+       "breakpoint".  Also, error message now contains the file name,
+       line number, and file access error message.
+       (_initialize_source):  Fix help text to describe changes.
+       * main.c (cd_command):  Forget cached source info when we chdir.
+       * utils.c (strstr):  Add simple implementation.
+
+Tue Mar  5 01:41:40 1991  John Gilmore  (gnu at fowanton.cygnus.com)
+
+       * coffread.c (read_one_sym, init_linetable, init_stringtab):
+       Byte-swap COFF symbol tables if necessary when reading them in.
+       Use complain() to replace error message in one spot.  Needs
+       corresponding change in bfd/coff-code.h to make some symbol
+       swapping routines non-static.
+
+Mon Mar  4 00:53:40 1991  John Gilmore  (gnu at cygint.cygnus.com)
+
+       Merge changes from Eirik Fuller, for UTek.
+
+       * defs.h (errno):  Add declaration.
+       * altos-xdep.c, arm-xdep.c, convex-xdep.c, gould-xdep.c,
+       hp300hpux-xdep.c, infrun.c, inflow.c, infptrace.c, i386-tdep.c,
+       i386-xdep.c, pyr-xdep.c, mips-xdep.c, remote-eb.c, remote-nindy.c,
+       remote-vx.c, source.c, standalone.c, stuff.c, sun386-xdep.c,
+       symmetry-tdep.c, symmetry-xdep.c, umax-xdep.c, utils.c:  Eliminate
+       declarations of errno.
+
+       * remote-eb.c:  Define B19200 and B38400 as EXTA and EXTB.
+
+       * remote-vx.c:  Include <sys/time.h> for UTek; Sun gets it via
+       <rpc/rpc.h> and <rpc/types.h>.
+
+Sat Mar  2 15:47:55 1991  John Gilmore  (gnu at cygint.cygnus.com)
+
+       * i960-tdep.c (examine_prologue):  Add new argument limit,
+       which stops the scan at the end of the prologue, or at the PC.
+       This fixes a problem where it walks down into the code for the
+       user's statements if that code looks like function prologues.
+       Mark Fox and I have been bouncing this code back and forth, making
+       small changes to it.  Callers changed to match.
+
+Tue Feb 26 01:47:07 1991  Cygnus John Gilmore  (cygnus at yuba)
+
+       Cleanup for gdb-3.94 release final:
+
+       * Makefile.dist:  Remove remote-vx.c, remote-nindy.c, and all
+       the .c files from vx-share and nindy-share, from the various 
+       macros, since they are not found via ALLDEPFILES.
+       (SFILES):  Add tm-i960.h.
+       (alldeps.mak rule):  Break out ALLDEPFILES_MAINDIR and
+       ALLDEPFILES_SUBDIR.  List all the nindy and vxworks subdir files
+       in the SUBDIR list.
+       (TAGFILES_MAINDIR):  Change ALLDEPFILES to ALLDEPFILES_MAINDIR.
+       (gdb.tar.Z):  Use ALLDEPFILES_SUBDIR as well as SFILES_SUBDIR.
+
+Mon Feb 25 16:02:35 1991  Cygnus John Gilmore  (cygnus at oldman)
+
+       * am29k-tdep.c:  Add contribution line.
+       (examine_prologue):  Cache information about function prologues in
+       the misc-function-vector to avoid lots of references over the
+       serial line while examining instructions.
+
+       * core.c (core_close):  New function made from cleanup_core.
+
+       * core.c, exec.c, inftarg.c, remote-eb.c, remote-nindy.c,
+       remote-vx.c, remote.c, target.c, target.h, 
+       Update target_ops vector to add attach, close, and load entries.
+       Use add_syms_addr_command, not add_file_addr_command, for
+       add_file.  Break out close routine from existing code.
+
+       * dbxread.c (really_free_pendings):  Don't free pending_blocks;
+       they are in an obstack.
+       (read_dbx_symtab):  Relocate end_of_text_addr in the psymtab.
+       Lint.
+       (define_symbol):  Add symbol type parameter; change callers;
+       pass type parameter to DBX_PARM_SYMBOL_CLASS macro to allow
+       it to influence the symbol class on the i960.
+       (define_symbol):  Swap LOC_CONST's into target byte order.
+
+       * exec.c (exec_close):  New function.
+       (exec_file_command):  Call it.
+
+       * findvar.c (read_relative_register_raw_bytes):  Doc byte order,
+       Fix byte order of frame pointer.
+       (read_var_value):  Result of 0 if var's value can't be found,
+       e.g. missing FRAME_ARGS_ADDRESS.  Byte-swap LOC_CONST and
+       LOC_LABEL values to target order.  Add LOC_LOCAL_ARG.
+       (locate_var_value):  Use read_var_value and use its lazy address
+       as the location of the var's value.  Lint.
+
+       * i960-pinsn.c (next_insn):  Add routine from vxgdb for scanning
+       instructions.       
+
+       * i960-tdep.c (arg_address, i960_frame_find_saved_regs):  Remove
+       obsolete Intel versions in favor of vxgdb versions.
+       (check_host, byteswap, byteswap_val, reorder_val):  Eliminate
+       code dealing with byte order of values, which Intel did in host byte
+       order rather than gdb-4's target byte order.
+       (i960_frame_chain_valid):  Move to nindy-tdep.c.
+       (examine_prologue, skip_prologue, frame_find_saved_regs,
+       frame_args_address, leafproc_return, saved_pc_after_call,
+       pop_frame):  Add vxgdb versions from Mark Fox.
+       (examine_prologue, frame_struct_result_address):  Add code
+       to deal with the saved value of G13 (struct return address
+       pointer).
+       (frame_args_address):  Modify Mark's version to prefer the
+       saved value over the current value in the topmost frame.
+       Cache result in the frame info to avoid performance hair in
+       callers.
+       (print_fault):  Add gdb960 code for printing faults.
+       (_initialize_i960):  Actually call check_host.
+
+       * ieee-float.c (ieee_extended_to_double, ieee_double_to_extended):
+       add stub routines.  FIXME, these currently just return zero!
+
+       * infcmd.c (program_info):  Use PRINT_RANDOM_SIGNAL.
+       (attach_command):  Call target_attach, not target_open, now.
+
+       * infrun.c (normal_stop):  Make global, not static, for vx_attach.
+       (child_attach):  Rename from child_open.
+       (wait_for_inferior): Use PRINT_RANDOM_SIGNAL.  If stop_pc is zero,
+       don't confuse it with a zero step_resume_break_address. 
+
+       * inftarg.c (child_detach):  Eliminate inferior_pid test.
+       (child_files_info):  Clean up message a bit.
+       (child_ops):  Use child_attach, not child_open, to attach.
+
+       * mem-break.c:  #ifdef out the whole file if BREAKPOINT is not
+       set (e.g. on VxWorks or NINDY).  Move read_memory_nobpt from
+       findvar.c to here, since it depends on the contents of the
+       shadow_contents of breakpoints, but keep if #if 0 since it is
+       never called.
+
+       * nindy-tdep.c:  New file, contains nindy_frame_chain_valid, moved
+       from i960-tdep.c.
+
+       * printcmd.c (address_info):  Handle LOC_LOCAL_ARG.  Lint.
+       (ptype_command, display_command):  Eliminate have_inferior_p and
+       have_core_file_p in favor of target_has_stack or
+       target_has_execution.
+       (print_frame_args):  Handle LOC_LOCAL_ARG.  Eliminate duplicate
+       code for actually finding the values of arguments, though we still
+       keep track of the maximum stack offset for use in printing unnamed
+       arguments.  Handle missing FRAME_ARGS_ADDRESS.
+
+       * remote-nindy.c (i960_print_fault):  Move to i960-tdep.c.
+       (struct nindy_regs):  Define registers passed to/from nindy.
+       (nindy_fetch_registers, nindy_store-registers):  Translate between
+       nindy and GDB formats for the registers.
+       (dcache_init):  Statically allocate the cache, since it was being
+       allocated by a malloc that was never freed anyway.
+       (nindy_create_inferior):  Error, not core dump, if no exec file.
+       (nindy_before_main_loop):  Use target_load, not target_add_file.
+
+       * remote-vx.c (net_load):  Specify large timeout for load
+       requests.  Allow user to break out with INTERRUPT.
+       (net_break):  Remove useless code, clean up.  Change callers.
+       (parse-args, skip_white_space, find_white_space):  Clean up arg
+       parsing to cope with quoted strings.
+       (net_wait, net_quit):  Never call error, just return status.
+       (vx_read_register, vx_write_register):  Cleanup status checking.
+       #ifdef the code based on which CPU we are using (960 or 68k),
+       FIXME, this should be completely general but it isn't yet.
+       (vx_xfer_memory, vx_resume):  Cleanup status checking.
+       (vx_run_files_info):  Improve message.
+       (vx_load_command):  Renamed from vx_add_file_command.  Allow load
+       to be interrupted.
+       (net_ptrace):  Remove unused routine.
+       (vx_wait):  Adopt code from vxgdb960 to cope with broken
+       connections to target machine and prompt to disconnect.  Remove
+       debug printouts.  Map some EVENT_'s to SIGnals.
+       (add_symbol_stub, vx_open):  Print names of object files we found,
+       and "ok" if we read their symbols OK.  Clarify output in general.
+       (vx_attach, vx_detach, vx_kill):  Add these commands.
+       (vx_convert_from_virtual, vx_convert_to_virtual):  Simplify.
+       (vx_run_ops):  Turn off all_mem, to avoid spurious msg in the
+       "info files" output, and create_inferior, since we already have
+       an inferior.
+
+       * stack.c (frame_info):  Replace Frame_unknown with 0.
+       (print_frame_arg_vars):  Handle LOC_LOCAL_ARG.
+       (return_command):  Pop until the PC matches as well as the FP,
+       so it works even if the FP is shared with another function,
+       as in "frameless" or "leaf" procedures.
+
+       * symfile.c (load_command):  renamed from add_file_target_command.
+       (add_syms_addr_command):  renamed from add_file_addr_command.
+       (add_syms_command):  Stub to call target_add_syms.
+       (_initialize_symfile):  Change command names and descriptions,
+       add-file => add-syms, and load from alias to its own command.
+
+       * target.c (kill_or_be_killed, maybe_kill_then_attach,
+       maybe_kill_then_create_inferior):  Default for attempts to start
+       a process, if one is already running, is to ask about killing
+       it and retry if yes.
+       (upstack_create_inferior):  #if-0 it, strata obsolete it.
+       (push_target, unpush_target, pop_target):  to_close() a target
+       before unstacking it. 
+       (target_info):  Renamed from target_files_info.
+       (_initialize_targets):  Rename "i files" as "i target", accessible
+       under both names.
+
+       * target.h:  Improve comments about the target_ vectored routines.
+
+       * tm-i960.h:  Remove NINDY-specific stuff to tm-nindy960.h.
+       Convert commenting style to standard GNU style.
+       (DBX_PARM_SYMBOL_CLASS): allow LOC_LOCAL_ARG's to be recognized.
+       (SKIP_PROLOGUE):  No longer a no-op.
+       (SAVED_PC_AFTER_CALL):  Now handles leaf procedures.
+       (*_REGNUM):  Sort register numbers.
+       (REGISTER_BYTES, REGISTER_BYTE, REGISTER_RAW_SIZE,
+       MAX_REGISTER_RAW_SIZE, REGISTER_CONVERTIBLE,
+       REGISTER_CONVERT_TO_VIRTUAL, REGISTER_CONVERT_TO_RAW):  Float regs
+       are now 10 byte extendeds, not 8 byte doubles.
+       (FRAME_CHAIN_VALID):  Make this config-dependent, since it differs
+       for nindy versus vxworks targets.  FIXME, this should possibly go
+       in the target vector.
+       (EXTRA_FRAME_INFO, INIT_EXTRA_FRAME_INFO):  Cache both
+       frame_saved_regs and arg pointer with each frame.
+       (FRAMELESS_FUNCTION_INVOCATION):  New leafproc support.
+       (FRAME_ARGS_ADDRESS):  Use cached result.
+       (FRAME_ARGS_ADDRESS_CORRECT):  New, avoids g14 guessing.
+       (FRAME_FIND_SAVED_REGS):  Change arg to subsidiary fn.
+       (PRINT_RAMDON_SIGNAL):  Call print_fault.
+       (POP_FRAME):  Now works.
+
+       * tm-nindy960.h:  Break this off tm-i960.h.  NINDY-specific
+       option parsing and startup; STACK_END_ADDR, FRAME_CHAIN_VALID,
+       BREAKPOINT, and DECR_PC_AFTER_BREAK are here.
+       (ADDITIONAL_OPTION_HANDLER):  use target_load, not
+       target_add_file.
+       
+       * tm-vxworks960.h:  Break this off tm-i960.h.  VxGDB specific
+       startup; DECR_PC_AFTER_BREAK, and FRAME_CHAIN_VALID are here.
+
+       * valarith.c (value_subscripted_rvalue):  Avoid handling
+       floats and doubles specially; it gave alignment errors.  Lint.
+
+       * valops.c (value_of_variable, value_of_this):  Error if unknown
+       value.
+
+       * valprint.c (print_floating):  Bcopy rather than pointer-deref,
+       to avoid alignment problems.
+       (value_print):  Handle unknown value address.
+       (cplus_val_print):  Two args are ignored; remove them.  Change caller.
+       (val_print):  Use unpack_long rather than pointer-deref.
+
+       * values.c:  Lint.
+       (unpack_long, unpack_double):  Use bcopy rather than pointer-deref
+       to avoid alignment problems.
+       (value_being_returned):  Error if return value unknown.
+       (set_return_value):  Add bogosity warning, FIXME.        *
+
+       * TODO:  A woman's work is never done.
+
+       * Makefile.dist:  Distribute REMOTE_OBS into tconfig files.
+       Separate INCLUDE_CFLAGS for use with lint.  Add LINTFILES.
+       Add ieee-float.o to OBS.
+       * tconfig/{nindy960,vxworks68,vxworks960}:  Include the desired
+       REMOTE_OBS remote-interface files in the TDEPFILES and TM_FILE.
+       * tconfig/i960:  FIXME.  Half-merge, produce warning if config'd.
+
+       Changes to generalize the VxWorks RPC protocol slightly, to handle
+       i960 as well as 68000.
+
+       * vx-share/dbgRpcLib.h (VX_SOURCE_STEP):  Add.
+       * vx-share/reg.h:  Produce i960 regs #ifdef I80960
+       * vx-share/xdr_ptrace.c:  Skip FPA registers if 960.
+       * vx-share/xdr_rdb.h:  Add SOURCE_STEP struct and xdr decl.
+       * vx-share/xdr_rdb.c:  Add xdr_SOURCE_STEP routine.
+       * vx-share/xdr_regs.c:  Add xdr_regs, xdr_fp_status, xdr_ext_fp
+       for i960.  Change xdr_vectors to xdr_opaques for 68k registers,
+       so they will move in target byte order rather than network
+       byte order (happens to be the same).    
+
+Mon Feb 25 03:41:44 1991  John Gilmore  (gnu at cygint.cygnus.com)
+
+       * tm-convex.h (END_OF_TEXT_DEFAULT):  Remove #if 0'd block.
+
+Sun Feb 24 00:55:53 1991  John Gilmore  (gnu at cygint.cygnus.com)
+
+       * am29k-pinsn.c, 
+       Add contribution lines to various files, showing where they
+       came from.
+
+       * breakpoint.c (break_insn, check_break_insn_size,
+       read_memory_nobpt):  Remove to mem-break.c.
+
+       * xm-*.h, param-no-tm.h, tm-29k.h, valprint.c:  Change BYTE_ORDER to
+       HOST_BYTE_ORDER.
+
+       * tm-29k.h (STAB_REG_TO_REGNUM):  Warn user if symbol table
+       entry has bad register number.  This change is not
+       tested in this release, FIXME.
+
+       * frame.h:  Eliminate Frame_unknown in favor of a simple zero.
+       tm-vax.h:  Ditto.
+
+       * value.h:  Force value's contents field to be aligned to hold
+       at least a double or a long long (if supported).  This avoids
+       doing bcopy's in and out of the contents field.
+
+       (step_1):  Avoid coredump under obscure circumstances when we
+       have no frame.
+
+       * symtab.h (misc_info):  Add field to misc function vector for
+       any kind of cached information the target code desires.  AMD
+       29000 uses this to avoid repeating examine_function_prologue's.
+
+       * coffread.c:  Lint.  Remove static symfile, read_section_header.
+       core.c (have_core_file_p):  Lint: remove.
+       expprint.c (print_subexp):  Lint.
+       infptrace.c, valops.c, valprint.c:  lint.
+
+       Roll in changes from vxgdb-5.0.1:
+
+       * symtab.h:  Comment byte order of each address class.  Add
+       LOC_LOCAL_ARG for frame-relative args (960).
+       expread.y:  Use LOC_LOCAL_ARG where LOC_ARG is used.
+       symtab.c, symmisc.c:  ditto.
+       
+       * infrun.c (init_wait_for_inferior):  Clear stop_signal.
+
+       * remote.c (remote_resume):  Error if resume with a signal.
+
+       * symfile.c (prim_record_misc_function):  Clear misc_info.
+       (fill_in_vptr_fieldno):  Check stub type of arg.
+
+       * valops.c (value_cast):  Avoid looking up names of types whose
+       name we don't know, to prevent coredump.  Sun CC produces typedef
+       rtx and the name of *rtx is zero...
+
+Mon Feb 18 21:16:25 1991  John Gilmore  (gnu at cygint.cygnus.com)
+
+       Roll in changes from final AMD 29000 port (Tiemann).
+
+       tconfig/am29k:  Add COFF_ENCAPSULATE and TARGET=TARGET_AM29K
+       for ../include/a.out.encap.h.  This might not work now that BFD
+       is separately compiled.  Instead, BFD support for encap will have
+       to translate machine type 29k into the right COFF_MAGIC.
+       
+       * infcmd.c: Remove references to inferior_pid that aren't used
+       in actual ptrace calls; use target_has_execution, etc.
+       (have_inferior_p):  Remove function.
+       (program_info):  Print target info rather than "process number";
+       avoid gratuitous messages unless from_tty.
+       (run_stack_dummy, finish_command):  Set proceed_to_finish.
+       infrun.c: Remove inferior_pid refs.  Decl & init proceed_to_finish.
+       main.c:  Lint.  Lose have_inferior_p().
+       inferior.h (have_inferior_p):  Remove, lint.
+       (proceed_to_finish):  Add flag to ask that all regs be saved
+       by normal_stop, for the few commands that need it, speeding up
+       serial I/O.  Add comments to stop_registers.
+
+       * remote-eb.c:  Remove newline from breakpoint message we grep
+       for.  Never time out when running the user program.
+       
+
+
+Wed Feb 13 15:34:40 1991  John Gilmore  (gnu at cygint.cygnus.com)
+
+       Roll in changes from vxgdb-5.0.1:
+
+       * dbxread.c (read_dbx_symtab): If we encounter a "FORTRAN COMMON"
+       symbol in its raw form, we are processing an unlinked ".o" file.
+       See if the target environment has assigned it an address, using
+       target_lookup_symbol (VxWorks does), and enter it into the symtab
+       that way.
+
+       * tm-vxworks.h (FRAME_CHAIN, FRAME_CHAIN_VALID):  Override usual
+       68k versions for a simpler version that assumes zero FP at bottom.
+       Fixes bug of truncated stack reports.
+
+       * target.h (target_lookup_symbol):  Define this routine's args
+       and result, finally.
+
+       * target.c (nosymbol):  Default routine for target_lookup_symbol.
+       (target_default):  Default lookup_symbol and call_function too.
+       (files_info):  Only print has_all_memory warning if a non-dummy
+       target follows.
+
+       * remote-vx.c (vx_read_register, vx_convert_to_virtual,
+       vx_convert_from_virtual): If target does not have floating point,
+       zero register "values", and avoid doing cross-net conversions.
+       (vx_lookup_symbol):  Rename net_lookup_symbol, add to vectors.
+       (vx_open):  Rearrange code that attaches to target and reads
+       symbols for all loaded modules, to work if some of the modules
+       are not accessible.  Add symbol_stub() and add_symbol_stub()
+       as callbacks from catch_errors().  Allow connect attempt to be
+       interrupted painlessly with ^C (FIXME, there are still some bugs
+       if the interrupt happens during symbol reading.).  Print
+       final message with puts_filtered, since symbol messages are
+       now filtered too.
+
+       Misc cleanup:
+
+       * main.c (catch_errors):  Only print errstring if non-null.
+       (command_loop):  Avoid an ioctl per command to test ISATTY.
+
+       * remote-vx.c (net_load):  make static; avoid sophomoric msg.
+       (vx_xfer_memory):  Return correct result!
+       (vx_files_info):  Indicate whether target has float or not.
+       (vx_lookup_symbol):  Complain, not error, if target gone.
+       (vx_open):  Print "Connected" msg before disabling immediate-quit.
+       [FIXME:  lookup_symbol and vx_open changes need testing.]
+
+       target.c, remote-eb.c, inftarg.c, am29k-opcode.h, target.h,
+       tm-29k.h, tmm-vxworks68.h, symfile.c, gdb-int.texinfo: Add
+       contributor lines and update copyrights to 1991.
+
+       Changes from an attempted H-PUX host port:
+
+       * infptrace.c (PT_ATTACH, PT_DETACH):  Handle HP/UX, which 
+       defines PT_ATTACH and PT_DETACH but not PT_KILL.
+       * remote-eb.c (eb_open):  Misplaced endif kills sysv H/PUX.
+       * remote-vx.c: include <sys/time.h> for HPUX.
+       * hp300hpux-xdep.c (fetch_core_registers):  Rewrite old
+       "core_file_command" routine to BFD regime.  May not work yet.
+
+       Attempted port of "gdb-3.4 Van Jacobson xgdb" to modern gdb.
+
+       * xgdb.c: Replace X10 version with some VJ version.
+       (FIXME:  Its copyright assignment is not on record.)
+       * xgdb.c:  Update include files to X11R4 (Xaw crud).
+       (xgdb_display_source, create_text_widget): fix call to
+       get_filename_and_charpos.  Rewack source window stuff for X11R4
+       (gleaned from include files, and "nm's" of binary libraries, since
+       I had no doc available).
+       (append_selection, append_selection_word): Disable with FIXME
+       since R4 changed interface here.
+       (create_buttons):  Add back the old set of buttons.
+       (xgdb_create_window):  Fix call to XtInitialize (&argc not argc).
+
+       * Makefile.dist (xgdb, xgdb-init.c):  Update for X11R4 on Suns.
+       Roll VERSION to 3.94 (not yet final though).
+
+Sat Feb  9 09:46:25 1991  John Gilmore  (gnu at cygint.cygnus.com)
+
+       * obstack.h (obstack_ptr_grow, obstack_ptr_grow_fast,
+       obstack_int_grow, obstack_int_grow_fast):  Eliminate
+       cast on left of assignment, which gives MIPS cc fits and is
+       not Standard C.
+
+       * sparc-pinsn.c (print_insn): Eliminate 'set' test, subsumed by
+       F_ALIAS.  Use printf, not fprintf, when not passing a file
+       pointer...
+       (compare_opcodes): Check that identical instructions have
+       identical opcodes, complain otherwise.
+
+       * sparc-opcode.h (st %fsr):  Fix opcode "lose" mask.  This
+       was reported by Roland McGrath.
+       (unimp): Only match if exactly zero instruction.  (Roland)
+       (branches and traps):  Generate all variations of these
+       instructions with macros, based on a single call that defines
+       each condition name and its binary representation.
+       (set):  Turn on alias bit, to avoid test in sparc-pinsn.c.
+
+       * valprint.c (val_print_fields):  Take, and use, format parameter.
+       This means that "p/x struct" again prints the elements in the
+       desired format.  Changed callers.
+
+       * stack.c (frame_info):  Use filtered output, and indicate wrap
+       points.  Remove kludgy formatting designed to avoid line wrap.
+
+       * utils.c (wrap_here):  If the line is already full (because
+       we had printed a long indent or long wrapped string), do an
+       immediate newline-and-indent.
+
+       * m68k-pinsn.c (print_insn_arg): Bugfix from
+       ntmtv!thompson@ames.arc.nasa.gov (Mike Thompson): 'bkpt #0'
+       instruction is incorrectly disassembled as bkpt #8.
+
+       * dbxread.c (end_psymtab): Bugfix from Peter Schauer
+       <pesrem@regent.e-technik.tu-muenchen.de>: If you want to set a
+       breakpoint in a *.y file gdb will say Reading in symbols for *.y...
+       and then will dump core (sometimes). I traced it back to an
+       uninitialized symfile_name in psymtab_to_symtab.
+       (const_vol_complaint):  Add quotes to message.
+       (define_symbol):  Only believe line number if gcc_compiled.
+       Avoid allocating symbol if we will not return it.
+
+       Add target strata support so that newly established targets go
+       into their right place in the target stack (e.g. a new exec file
+       doesn't wipe out the ability to access the running process).
+
+       * target.h, core.c, exec.c, inftarg.c, remote-eb.c,
+       remote-nindy.c, remote-vx.c, remote.c, target.c:  Add to_stratum
+       and initialize it properly in all the targets.
+
+       * target.h:  Document strata.  Change return type of push_target.
+
+       * target.c (nomemory):  new function for dummy memory access.
+       (tcomplain):  Rename complain, now also used in symfile.c.
+       (push_target):  Push targets within strata.  New return value shows
+       whether new target is on top of stack or not.  Always keep dummy
+       target on stack.
+       (target_files_info):  Ignore dummy target.
+
+       * core.c (core_open):  Warn user, and skip accessing file, if the
+       core target is not the topmost target in the stack.
+       * remote-nindy.c (nindy_create_inferior):  Avoid unpush_target, now
+       already handled.
+
+       * remote-vx.c:  Remove vx_prepare_to_store from vxworks memory
+       target_ops, it doesn't belong there since we have no regs there.
+       Change name of target from machine => memory to clarify.
+
+Thu Feb  7 16:32:09 1991  John Gilmore  (gnu at spiff.cygnus.com)
+
+       * Freeze version 3.93 for release.
+
+       * Makefile.dist:  Handle vx-share and nindy-share subdirs
+       properly when building gdb.tar.Z.
+
+       * symtab.c:  lint; add no_symtab_msg to consolidate the messages
+       printed in various places, so I could change just one copy.
+
+       * dbxread.c, coffread.c:  Change references to bfd->iostream
+       to cast to FILE *, now that BFD avoids needing types defined
+       in other header files.
+
+Tue Feb  5 21:39:35 1991  John Gilmore  (gnu at cygint.cygnus.com)
+
+       * command.c, dbxread.c, expprint.c, infcmd.c, infptrace.c,
+       infrun.c, printcmd.c, remote-nindy.c, source.c, sparc-tdep.c,
+       sparc-xdep.c, symfile.h, symmisc.c, utils.c, valprint.c: Lint
+       (actually gcc -Wall).
+
+       * dbxread.c:  Remove first_global_sym, last_global_sym, since
+       they are never referenced.
+
+       * defs.h (baud_rate):  Declare.
+       main.c: Define it, and add the -b option to set it.
+
+       * gdb-int.texinfo:  Add text on how to define a new host or target
+       architecture, prompted by Per Bothner's questions about MIPS
+       support.
+
+       * gdb.texinfo:  Document "complaints".  Change doc of -q since
+       gdb no longer prints the copyright and blurb if you specify a file
+       name to be debugged (just like Emacs).  Add doc for Nindy-specific
+       command line flags for specifying target serial port and such.
+       Update copyright to 1991.
+
+       * gdbcore.h:  Remove a large mass of now-useless crud, since BFD
+       has taken over for us the job of ripping up executable files.  The
+       crud caused Per Bothner's port to not compile.
+
+       * infrun.c (normal_stop):  Avoid printing "Program exited
+       normally" if we are in batch mode.  This allows a GDB which
+       executes a program on a target system, to behave like a Unix
+       command (input from stdin, output to stdout, no extraneous
+       output).
+
+       * main.c (main):  Allow additional machine-dependent command line
+       options to be specified with the ADDITIONAL_OPTIONS,
+       ADDITIONAL_OPTION_CASES, ADDITIONAL_OPTION_HELP, and
+       ADDITIONAL_OPTION_HANDLER macros.  Also allow machine-dependent
+       processing to occur just before the main loop with
+       BEFORE_MAIN_LOOP_HOOK.  
+       (main):  If a "core file" argument is specified, and it is not a
+       core file, try it as a process ID to attach.  
+       (symbol_completion_function):  Attempt to cope with 
+       "show screen-" TAB, not very successfully.  This needs more work,
+       FIXME.
+       (batch_file):  New function, returns whether we are reading
+       commands from an interactive tty on stdin, or from somewhere else.
+       Called by normal_stop since it doesn't get from_tty passed down
+       to it like many commands do.
+
+       * remote-nindy.c:  Handle command line options for nindy
+       connection.
+       (nindy_before_main_loop):  Prompt user for tty name if they
+       don't specify it before getting to the interactive command loop.
+
+       * tm-i960.c:  Add ADDITIONAL_OPTIONS, etc, to handle -O, -brk,
+       and -r command line options.  Also add hook before main loop
+       to make it easy to specify a tty.
+
+       * TODO:  More things to do, one done.
+
+Mon Feb  4 23:57:39 1991  John Gilmore and Mike Tiemann  (at cygint.cygnus.com)
+
+       * dbxread.c:  Make complaint() calls pass pointer, not struct.
+       Add complaints about badly formatted C++ type information
+       (const/volatile indicator, and parse errors resulting in
+       error_type).  Fix C++ virtual member fn comment.
+       (read_struct_type):  Avoid bumping pointer if we got a parse
+       error; this prevents our walking beyond the end of a string.
+       Terminate loop on null char as well as semicolon.
+       (process_one_symbol):  Fix the LBRAC fix so that it uses the
+       last previous SLINE, FUN, or SO record's PC address.  C++ debug
+       symbols did not have SLINE records in a useful order compared
+       to the LBRAC records.
+       (define_symbol):  Handle "catch" records.
+
+       * symtab.c (check_stub_type):  Added new complain
+       `stub_noname_complain' and added a consistency check to
+       keep the debugger from crashing when finishing from an
+       exception frame.  A real fix will be needed later.
+
+Sat Feb  2 10:43:05 1991  John Gilmore  (gnu at cygint.cygnus.com)
+
+       * infcmd.c (attach_command):  Make global.
+
+       * Makefile.dist (REMOTE_OBS):  Make these compile by default,
+       but make them easy to comment out.  Perhaps later they should
+       be enabled by what CPU you configure for?  FIXME.
+       (VERSION):  Roll to 3.93.
+       (pinsn.o):  Remove rule for obsolete file.
+       (dbxread.o,coffread.o,mipsread.o):  Use ${srcdir} explicitly.
+
+       Run down a problem that manifested by printing the wrong function
+       name in stack traces of read_ofile_symtab.  Turned out that the 
+       problem was the SunOS 4.1.1 (and previous) C compiler outputs
+       the LBRAC symbol with an address in the *data* segment, which
+       blew our binary search through the blocks.
+
+       * dbxread.c: Use the complain() facility consistently to bitch
+       about problems in the symbol file we are reading.
+       (finish_block):  Add code to check the nesting of the blocks;
+       complain and Procrust them to fit if wrong.
+       (make_blockvector):  Check the order of the blocks, complain 
+       [but don't cope] if wrong.
+       (process_one_symbol):  ifndef SUN_FIXED_LBRAC_BUG, check LBRAC
+       symbols to be sure their PC value is greater than the last SLINE
+       (line number) symbol we've seen, complaining and adopting the
+       SLINE PC value if wrong.
+
+       * symfile.h (struct complaint, complaint_root, complain, 
+       clear_complaints):  Add.
+       * symfile.c (complain, complaint_root, clear_complaints):  Add
+       facility to deal with non-fatal complaints and to regularize their
+       suppression.
+       (symbol_file_add):  Clear complaint counters to allow new complaints.
+       (initialize_symfile):  Add 'set complaints' and 'show complaints'.
+
+       * dbxread.c (dbx_symfile_read):  Remember the address and size
+       of the string table for the main symbol file, so we won't read it
+       more than once.
+       (dbx_psymtab_to_symtab):  Fix the check for main symbol file,
+       to avoid reading the string table yet again.  Lint.
+       (throughout):  Improve filtered output, including word wrap.
+       (read_range_type):  Improve Bothner's fix to handle other types too.
+
+       * utils.c:  Improve line wrap implementation.  Handle unlimited
+       width by making chars_per_line unsigned.
+       (puts_filtered):  New, easy, function.  
+
+       * defs.h (puts_filtered):  add.
+
+       * mipsread.c (compare_symbols, sort_symtab):  Remove these fns,
+       call the identical sort_symtab_syms() in symfile.c instead.
+
+       * expread.y:  Suggest the `file' command rather than `symbol-file'.
+
+       * command.h (enum var_types):  Add zinteger for seroable
+       unsigned integer.
+       * command.c (do_setshow_command):  Handle var_zinteger.  Restructure
+       nested if's into a switch.
+
+       * breakpoint.c (bpstat_print): If bpstat "print" flag is not set,
+       we did not stop because of a breakpoint (it must have been for
+       some other reason, like a "stepi"), so don't print anything.
+
+       * symtab.c: Include <sys/types.h> all the time.  Now that BFD
+       doesn't include <sys/types.h>, old SunOS's require it for
+       <sys/stat.h>.
+
+Sat Feb  2 10:39:15 1991  Per Bothner  (bothner@cs.wisc.edu)
+
+       A test port of gdb-3.92.6 to the Sony NEWS.
+
+       * Makefile.dist
+       Don't normally link in remote- or vx stuff.
+       Some of it doesn't compile, and it wastes space for 99% of the users.
+       Remove reference to no-longer-used HAVE_VPRINTF.
+       Fixed BFD_DEP typo to BFD_DIR.
+       * dbxread.c
+       Fix cast in arg to bfd_h_getlong.
+       Make char *prefix be const.
+       Fix how certain range types are mapped into builtin unsigned int types.
+       * infrun.c
+       Remove 2 #includes. They cause errors (on Sony, at least),
+       and aren't needed (they wern't in earlier versions).
+       * printcmd.c
+       print_address_symbolic should never demangle labels
+       (since it prints *assembler-level* labels).
+
+              [This was superseded by the change to printcmd below.]
+
+       * utils.c
+       Add some "volatile" return types to avoid warnings.
+       If MISSING_VPRINTF add vprintf function and not just macro
+       (since vprintf is used in printcmd.c).
+       * valprint.c
+       Unless __GNUC__, use obstack_grow instead of obstack_ptr_grow.
+       (The latter isn't grokked by some PCC-based compilers.)
+
+            [This change is in abeyance, we prefer to fix obstack_ptr_grow.]
+
+       Make chunk size of dont_print_obstack 32*4 instead of default 4096.
+       * nindy-share/coffstrip.c
+       Added some forward declarations (otherwise, gcc complains
+       about implicit extern redefined as static).
+
+Sun Jan 20 02:38:19 1991  John Gilmore  (gnu at cygint.cygnus.com)
+
+       Changes inspired by Per Bothner:
+       * printcmd.c (print_address_symbolic):  Take additional parameter
+       specifying whether to demangle.
+       (print_address):  Pass in asm_demangle to control demangling.
+       (print_address_demangle):  New fn, takes explicit arg to control
+       demangling.
+       * utils.c:  Add new vars demangle and asm_demangle, and let them
+       be set and shown.
+       (fputs_demangled):  If !demangle, just print the argument.
+       (fprint_symbol):  If !demangle, just print raw symbol.
+       * valprint.c (val_print):  Call print_address_demangle rather than
+       print_address, to cause demangling to depend on the global
+       rather than assembler-level demangling setting.
+       * WHATS.NEW, gdb.texinfo:  Document.
+
+       * main.c (show_command):  Show all settings if no arg.
+       (initialize_main):  Make "info set" the same as naked "show".
+       * command.c (cmd_show_list):  Handle prefix commands in the
+       list, and print the name of the setting as well as its English
+       description and value.
+
+       Allow gdb functions to specify where a line should wrap if it
+       exceeds the size of a terminal line.  Use it to make the output
+       prettier.
+       * utils.c (set_screen_width_command):  New fn, mallocs a buffer
+       of the right size when screen width changes.
+       (set_screensize_command, screensize_info):  Remove #if 0'd fns.
+       (wrap_here):  New fn, indicates a point in the output where we
+       should wrap the line rather than just letting it overflow at a
+       random place.
+       (fputs_filtered):  Implement wrapping.
+       (n_spaces):  New fn, returns a pointer to N spaces.
+       (print_spaces_filtered):  Use n_spaces.
+       * defs.h (n_spaces):  Declare.
+       * stack.c (print_frame_info):  Wrap with 4-space indent after
+       fn name and before filename and line number.
+       * printcmd.c (print_frame_args):  Wrap with 4-space indent
+       before each argument name is printed.
+       * valprint.c (value_print):  Wrap with no indentation before
+       each repetition.
+       (val_print_fields):  Wrap with indentation relative to nesting
+       level before each field name.
+       (val_print):  Wrap with nesting indentation before array elements.
+       * command.c (do_setshow_command):  Avoid extra newlines,
+       wrap with 4-space indent around values printed, end with period.
+       * WHATS.NEW, gdb.texinfo, gdb-int.texinfo:  Document.
+
+       * breakpoint.c (breakpoint_1):  Implement addressprint for
+       "info breakpoints" display.  Change file name and line number
+       format to " at file:nnn" rather than " (file line nnn)".
+       * gdb.texinfo:  Document.
+
+
+Fri Jan 18 07:21:25 1991  John Gilmore  (gnu at cygint.cygnus.com)
+
+       Frozen for gdb-3.92.6 release.
+
+       README, WHATS.NEW:  Update for 3.92.6 release.
+
+       tconfig/{altos, i386v, i386v32, m88k, umax}:  Eliminate
+       coffread.o from configs since it is now built by default.
+       tconfig/{3b1, altosgas, arm, convex, hp300bsd, hp300hpux,
+       i386v-g, i386v32-g, isi, merlin, news, news1000, np1, pn,
+       pyramid, symmetry, vax, vxworks68}:  Eliminate dbxread.o
+       from configs since it is now built by default.
+
+       Makefile.dist: Update for release 3.92.6.  Handle files that
+       have been moved to ../include, ../getopt, or ../bfd.  Add
+       saber.suppress and tests directory.  Add config.status to
+       the release (it will say "none").
+
+       coredep.c:  Minor formatting fixes.
+
+       These changes were made in early December but only checked in now:
+       * nindy-share/Onindy.c, nindy-share/coffstrip.c,
+       nindy-share/nindy.c:  lint
+       * nindy-share/nindy.c (ninStopWhy):  Don't byteswap the 
+       register values coming back from the target; we store values
+       in target byte order everywhere.
+
+Wed Jan 16 19:01:37 1991  John Gilmore  (gnu at cygint.cygnus.com)
+
+       * am29k-opcode.h, am29k-pinsn.c:  Add 29050 opcodes.
+
+       * valprint.c (cplus_val_print, val_print_fields):  New functions,
+       which print C++ objects.  They conspire to avoid printing a
+       virtual base class more than once, following all the twists and
+       turns of C++ virtual base rules.
+       (val_print):  Call the above rather than do it by hand.
+
+       * symfile.c (symbol_file_add):  Only reset symfile_mtime for main
+       symbol file, not for added files like shared libs.  This really
+       needs to be generalized to a timestamp per file.
+
+       * core.c (cleanup_core):  Avoid coredump if no core file.
+       
+       * config.gdb:  Accept -host or -target in place of +host or
+       +target.
+
+       * coffread.c (find_linenos):  Avoid desupported BFD interface
+       to line numbers.  We still read them manually rather than using
+       BFD's "generic" features.
+
+       * gdbrc.tex, threecol.tex:  Add GDB reference card and its
+       formatting code.
+       Makefile.dist:  Add refcard to OTHERS list for creating tar files.
+
+       * Makefile.dist:  Eliminate use of $< in explicit targets.
+
+       * readline/Makefile:  Use $< rather than $*.c, which does not
+       include the VPATH in GNU Make.
+
+       * tconfig/i960-bout, tconfig/i960-coff:  These are identical
+       copies of tconfig/i960, added for global configuration
+       compatability.  All i960 versions can read both coff and b.out.
+
+       * tm-88k.h:  Fix multiline macro that lacked \'s.  Remove
+       COFF_FORMAT and COFF_CHECK_X_ZEROES since these are now handled
+       automaticaly.
+
+       * TODO:  Think of more things to do.
+
+Wed Jan  2 19:09:29 1991  John Gilmore  (gnu at spiff.cygnus.com)
+
+       tconfig/{am29k,i960,sun2*,sun3*,sun4*}:  Eliminate config
+       of sdb versus dbx debug symbols.  Add kludge for 68881 80-bit to
+       64-bit float conversion.
+
+       tconfig/sun4, tconfig/sun3, xconfig/sun4, xconfig/sun3:  Make
+       equivalent to sun?os4 so global config works.
+
+Wed Jan  2 18:20:51 1991  John Gilmore  (gnu at spiff.cygnus.com)
+
+       Fix from Eberhard Mattes <mattes@azu.informatik.uni-stuttgart.de>
+       
+       * main.c:  Only declare linesize once; declare pagesize not at
+       all, since it is never used.
+       (main):  Clear newly allocated line before it is used.
+
+Fri Dec 28 00:13:42 1990  John Gilmore  (gnu at cygint)
+
+       Further stabilization for the Intel 960.
+
+       * Makefile.dist: Parameterize the location of the "include"
+       and "bfd" directories, as well as "getopt".  Add symfile.c.
+       Link in both dbxread and coffread.  Fix up "make depend" to
+       rewack the locations of include, bfd, and getopt in its output.
+
+       * README:  Document moving include files, improve some of
+       the other doc.
+
+       * coffread.c:  Move common code out to symfile.c.  Change
+       symbol_file_command style interface to use new *_symfile_init
+       and *_symfile_read interface under BFD.  Use BFD internal
+       info to locate line table, symbols, etc.
+
+       * core.c (core_fetch_registers):  Rename to get_core_registers
+       to avoid confusion with fetch_core_registers.
+       (register_addr):  Move to coredep.c, which is already machine
+       dependent.  This leaves core.c pretty clean of dependencies.
+
+       * coredep.c (register_addr):  Accept this routine from core.c.
+
+       * dbxread.c: Move common code (with coffread.c, etc) into new
+       symfile.c.  Each psymtab now contains a pointer to the
+       format-dependent function that knows how to read it in.  Make
+       some things static.  
+       (dbx_psymtab_to_symtab): Renamed from psymtab_to_symtab_2.
+       (process_one_symbol): Add code to complain about a "compiler bug
+       we muzzle here", if we actually see it.
+
+       * eval.c (evaluate_subexp):  Insert missing "break" statements
+       in code that determines whether a variable is an lvalue in
+       memory, register, or whatever.  I detected this via a compiler
+       bug in which it *almost* mashed out the whole switch statement.
+
+       * gdb-int.texinfo:  Add minor sections on configuring gdb for
+       release, and about the README file.
+
+       * infcmd.c (registers_info):  Fix formatting somewhat.  Still
+       not as pretty as before, but it handles byte swapping.
+
+       * remote-nindy.c: If data cache routines are interrupted while
+       waiting for the remote end, be sure that any uninitialized cache
+       blocks are on the free list, not on the valid list!
+
+       * symfile.h: Flesh out this header file with all the various
+       routines and variables that have been merged in from dbxread.c
+       coffread.c, and symtab.c to symfile.c.
+
+       * symfile.c: New file, containing code common to dbxread.c,
+       coffread.c, and some code from symtab.c.  All generic code for
+       reading symbol files should be in here now.
+       (unrecord_misc_function):  Remove unused function.
+
+       * symtab.h:  Remove file-reading things to symfile.h.
+
+       * symtab.c:  Remove file-reading things to symfile.c.
+
+       * tm-i960.h:  Fix FRAME_CHAIN types; define PRINT_RANDOM_SIGNAL
+       to decode i960 fault types.
+
+       * target.h, remote.c, remote-eb.c, remote-vx.c, remote-nindy.c,
+       target.c: Change type of the "resume" function from int to void,
+       since its result was never used.
+
+Sat Dec 22 02:51:40 1990  John Gilmore  (gnu at cygint)
+
+       * main.c:  Replace "stupid" with "caution"; you now "set caution
+       on or off".
+
+       * printcmd.c (print_scalar_formatted):  Fix typo in 'g' format
+
+       * infcmd.c (do_registers_info):  Call val_print to deal with the
+       byte order of the registers being printed.  FIXME, this makes
+       the formatting of the output uglier.
+
+       * infcmd.c (wait_for_inferior):  If PRINT_RANDOM_SIGNAL is
+       defined, call it for signals the debugger doesn't itself use.
+       The i960 uses this for more detailed fault information.
+
+       * remote.c (remote_open):  If arg is null, print help rather than
+       dumping core.
+
+       * sparc-xdep.c (register_valid):  Avoid declaring size, since
+       various modules will think of various sizes depending on the
+       architecture of their tm-file.  FIXME, we need protection against
+       actually entering one of those modules, which would clobber
+       storage if not for the target architecture compiled into gdb.
+
+       * stack.c (up_command, down_command):  Always print the frame
+       you arrive at.
+       (up_silently_command, down_silently_command):  New commands
+       for use in scripts.
+
+       * i960-pinsn.c (reg), i960-tdep.c:  Lint.
+
+       * i960-tdep.c (i960_frame_chain_valid): Lookup_symbol now takes
+       more parameters than it used to.
+
+       * findvar.c (registers):  Increase slop to 256 bytes, which should
+       protect us against even most RISC machines with large register
+       sets.
+       (locate_var_value):  Move declaration inside related ifdef.
+
+       * remote-nindy.c ():  Use TIOCSETN rather than TIOCSETP
+       throughout, to avoid throwing away buffered input from the board.
+       (nindy_wait):  Supply_register takes addr_of_value, not value.
+       (i960_print_fault):  Renamed from i80960_fault.
+       (nindy_fetch_registers):  Avoid have_regs stuff, just get them.
+       (nindy_store_registers):  Avoid regs_changed stuff, just stuff
+       them.
+       (nindy_create_inferior):  Don't bother to write PC_REGNUM since
+       we can set the PC in the call to proceed().  Unpush nindy_ops
+       before pushing it on top, to avoid message to user.  Eliminate
+       commentary from Unix machines that just misleads here.
+       (reset_command):  Fix error message to suggest target command.
+       
+Wed Dec 19 11:03:56 1990  John Gilmore  (gnu at cygint)
+
+       Release 3.92.5 as frozen.
+
+       Stabilize the merged release...with help from lint, Saber C,
+       gcc -W, etc.
+
+       Everywhere:  Add include files needed to declare return types
+       of functions called.
+
+       * gdb.texinfo:  Roland Pesch is documenting gdb, glory be!
+
+       * breakpoint.h:  Add undeclared breakpoint functions, and some
+       functions for display handling since I couldn't think of a better
+       .h to put them in.
+
+       * breakpoint.c (insert_breakpoints):  Make code for disabling
+       shared library bkpts more likely to work.  It's used when we
+       rerun a program and stop before the shared library has been
+       mapped in.
+       (breakpoint_cond_eval, bpstat_stop_status):  Pass arg as int,
+       cast from pointer, so it squeezes through catch_errors.
+       (bpstat_stop_status):  Fix logic broken some time ago.  We now
+       always create a bpstat if the stop address matches a breakpoint,
+       even if we don't stop there -- just like the old code used to do
+       before I got my fingers into it (sigh).
+       (breakpoint_1):  Print "ignore count" after "stop only if"
+       condition, since that's how it actually works.
+       (mention):  Handle watchpoints as well as breakpoints.
+       (watch_command):  use set_raw_breakpoint and mention to do most 
+       of the work (and initialize all the fields!).  Only pass one
+       arg to parse_c_expression, since that's all it takes.
+
+       * command.c (not_just_help_class_command):  Rename arg to args
+       since we ignore "unused argument" warnings on vars named "args".
+       inflow.c (child_terminal_info):  ditto.
+       infptrace.c (kill_inferior):  ditto
+       main.c (catch_errors, version_info, quit_command, pwd_command,
+       source_command, dump_me_command, editing_info,
+       set_history_size_command, set_history, show_history,
+       set_verbose): ditto
+       stack.c (locals_info):  ditto
+       target.c (target_files_info):  ditto
+       valprint.c (set_input_radix, set_output_radix):  ditto
+
+       * core.c:  Remove old variables for handling core and exec file
+       sections (data_start, data_end, stack_start, stack_end,
+       reg_stack_start, reg_stack_end, reg_stack_offset, text_start,
+       text_end, exec_data_start, exec_data_end, text_offset,
+       exec_data_offset, data_offset, stack_offset).  They're
+       superseded the more general build_section_table and
+       xfer_memory.
+       (get_exec_file):  Mention the `file' command.
+       (read_memory_check):  Rename to memory_error, and only call it
+       in the case of an actual error.
+       (read_memory, write_memory):  call memory_error.
+       (core_fetch_registers):  Register section name is ".reg".
+
+       coredep.c:  Remove a bunch of crud now that all this file does
+       is pull the registers out of a core file.
+       (fetch_core_registers):  Rewrite to actually work, I hope.
+
+       dbxread.c:  Use a.out.gnu.h, not system a.out, now.
+       Replace index() with strchr().  Remove all the pre-BFD macro
+       definitions for accessing the symbol file.
+       (struct dbx_symfile_info):  Encapsulate the information that
+       dbx_symfile_init needs to pass to dbx_symfile_read in this
+       struct.
+
+       (dbx_new_init, dbx_symfile_init, dbx_symfile_read,
+       dbx_symfile_discard): Rearrange symbol file reading to divide
+       the format-specific part from the format-independent part,
+       leaving the format-independent part such as file name expansion
+       and opening in symtab.c.  This replaces
+       partial_symbol_file_open and partial_symbol_file_read.
+       Symbol_file_read, add_file, add_file_target_command,
+       add_file_addr_command move to symtab.c.  Pass an explicit
+       "mainline" flag for when reading the main symbol table, rather
+       than relying on the offset address to be zero or nonzero.
+
+       (dbx_symfile_read): Don't allow void *'s to be printed as
+       typedefs.
+       (SWAP_SYMBOL):  Use bfd routines to byte-swap the symbols.
+       (ADD_PSYMBOL_TO_LIST):  Make the "function call rather than
+       macro" debug version really work.
+       (read_dbx_symtab):  Remove unref'd parameter inclink.
+       Avoid swapping N_SLINE symbols, for speed.
+       Merge N_TEXT!N_EXT case with the other external symbol
+       definitions' case. Add comments.
+       (start_psymtab):  Allocate the symfile name in the psymtab on
+       the psymbol_obstack, rather than using the caller's storage.
+       (end_psymtab): Only allocate a dependencies list if there are
+       more than zero.
+       (psymtab_to_symtab_2):  Use BFD when reopening file to read
+       its symbols for real.
+       (read_struct_type):  Add FIXME comments where it needs work
+       for C++ bogosity.
+       (read_huge_number):  Add FIXME about overflows.
+       (read_range_type):  Add FIXME about comparing a long to 1<<32.
+
+       * coffread.c:  Minor changes to move things closer to the new
+       regime with symtab.c and dbxread.c   Major work is still needed
+       here.
+
+       * exec.c (exec_file_command):  Remove old variables (see core.c
+       above).
+       (xfer_memory): If memory transfer is right at the end of a
+       section, don't lose.
+
+       * findvar.c (get_saved_register):  If value is in a real
+       register, LVAL is lval_register, not lval_memory.
+
+       frame.h:  Declare print_sel_frame and record_selected_frame.
+
+       gdb-int.texinfo:  New file, for GDB internals documentation.
+       Very simple, unformatted doc of cleanups is there for now.
+
+       gdbcore.h:  Remove obsolete variables that described a.out
+       section addresses and offsets.  (See core.c above.)
+       Declare fetch_core_registers and registers_fetched.
+
+       getopt.c:  Declare char *alloca(); even on SPARC.
+
+       infcmd.c (run_command):  Call target_kill rather than
+       kill_inferior. 
+       (step_command, next_command, stepi_command, nexti_command):
+       Declare from_tty parameter even though we don't use it.
+       (run_stack_dummy):  argument BUFFER is a char array, not
+       a pointer to REGISTER_TYPE.
+       (finish_command):  using_struct_return needed a value *, 
+       not a struct symbol *.
+
+       * infptrace.c (child_xfer_memory):  To avoid dependency on
+       where sections are in memory, try PT_WRITE_D and if that fails,
+       try PT_WRITE_I.  Most Unixes don't care which you use.
+
+       * infrun.c (step_resume_break_shadow):  Change to array to
+       match other breakpoint shadow storage.
+       (clear_proceed_status):  Pass address of bpstat to
+       bpstat_clear, not the bpstat itself.
+       (child_create_inferior):  FIXME comment about if the child
+       exits.
+       (start_inferior):  Remove old function.
+       (child_open):  Use target_kill rather than kill_inferior.
+       (wait_for_inferior):  Ditto.
+       (insert_step_breakpoint, remote_step_breakpoint):  Use
+       new step_resume_break_shadow.
+
+       * inftarg.c (child_wait):  If all child processes die,
+       pretend that the one being waited for exited with signal 42.
+
+       * main.c (command_line_input):  When scanning for comments,
+       don't coredump on unclosed quotes.
+       (quit_command):  Use target_kill rther than kill_inferior.
+       (_initialize_main):  Rename class_user from "user" to
+       "user-defined".
+
+       * printcmd.c (print_command_1):  Initialize "fmt" if no format
+       is specified by the user.
+       (print_frame_args):  Only add to args_printed if we are
+       actually fetching args from the stack (avoiding undefined
+       arg_size).
+       (_initialize_printcmd):  Remove bogus \{ from string.
+
+       * remote-eb.c (eb_open):  Avoid coredump on no argument.
+
+       * remote-nindy.c:  Bring out of Intel environment into new
+       target environment.  Remove all conditional compilation on
+       I80960.  Massive hacking throughout.
+       (nindy_xfer_inferior_memory):  New routine stolen from
+       infptrace.c.
+       (nindy_create_inferior):  New routine pieced together, probably
+       not quite working yet.
+       (nindy_ops):  New target_ops struct for nindy.
+
+       * remote-vx.c:  Use write_memory rather than target_write_memory
+       to get error checking.
+       (vx_add_file_command, vx_open): Use symbol_file_add rather than
+       add_file.
+       (vx_create_inferior):  Use target_terminal_ours...
+
+       * signame.c (_initialize_signame):  Always initialize, since
+       we need the table for things other than psignal.
+       
+       * solib.c (solib_add):  Use symbol_file_add, not add_file.
+       (solib_address):  Return boolean result rather than struct
+       pointer which nobody else knows the type of.
+
+       * sparc-tdep.c, valops.c:  Use write_memory rather than
+       target_write_memory, to get error checking.
+
+       * stack.c (locals_info, catch_info, args_info,
+       get_selected_block, frame_command, up_command): Use
+       target_has_stack, rather than have_inferior_p or
+       have_core_file_p.
+
+       * sun3-xdep.c (fetch_core_registers):  Rewrite for new BFD regime.
+
+       * symfile.h:  New file, defining the interface between the
+       generic and object-file-specific symbol reading code.
+
+       * symtab.c:  Move generic symbol-reading interface to symtab.c,
+       from dbxread.c, coffread.c, mipsread.c, etc.  Add symtab_fns
+       table to map BFD targets to symbol-reading modules in GDB.
+       Change index to strchr.
+       (lookup_struct_elt_type):  Use error() rather than hand-made
+       simulations thereof.
+       (lookup_partial_symbol):  Speedup slightly when length == 0.
+       (symbol_file_add):  New function.
+       (symbol_file_command):  Call it.
+       (symfile_open, symfile_init):  New function.
+       (add_file_target_command, add_file_addr_command): moved from
+       dbxread.c.
+
+       * target.c (target_command):  use target_kill.
+
+       * target.h (target_files_info):  Don't declare, never called
+       from outside.
+
+       * tm-sun2.h, tm-sun3.h (STACK_END_ADDR): Use system include
+       files to determine stack end address.
+
+       * valarith.c (value_x_binop, value_x_unop): Change error message
+       to be more useful.  Pass proper argument to value_struct_elt.
+
+       * valops.c (value_assign):  FIXME comment that long long 
+       bitfields will break here.
+
+       * Makefile.dist:  Add symfile.h, remote-nindy.c, remote-eb.c.
+       Update `make saber_gdb' to work better.
+
+       * TODO:  A woman's work is never done.
+
+       * cplus-dem.c, environ.c, inferior.h, infrun.c, inftarg.c,
+       main.c, obstack.c, printcmd.c, remote-eb.c, remote-nindy.c,
+       remote-vx.c, remote.c, solib.c, source.c, sparc-pinsn.c,
+       sparc-tdep.c, sparc-xdep.c, symmisc.c, symtab.c, symtab.h
+       target.c, terminal.h, tm-sparc.h, tm-sunos.h, utils.c,
+       valops.c, valprint.c, exec.c:  Lint.
+
+
+Wed Dec 12 23:44:15 1990  John Gilmore  (gnu at cygnus.com)
+
+       Continuing Intel 960 port merge of GDB.
+
+       * Makefile.dist:  Merge i960 "nindy-share" files.  Rename
+       malloc.h to gmalloc.h to avoid name conflicts in /usr/include.
+       Don't ship gdb.dvi in tar file.  Link gdb with init.o, not init.c.
+       Wack over "make depend" so it handles files in subdirectories
+       vx-share, nindy-share, bfd, and in the current directory.
+
+       * blockframe.c (get_prev_frame_info):  Remove fatal error
+       if stack not defined.
+
+       * core.c (core_open, core_detach):  New functions that handle
+       the old "core-file" command as "target core" and "detach" instead.
+       (core_file_command):  Call them.
+       (core_xfer_memory):  Use common routine xfer_memory.
+
+       * dbxread.c:  Include a.out.gnu.h, not system a.out.h.
+       dbxread now uses bfd for everything but symbol reading itself.
+       BFD internals are used to drag out the relevant file offsets.
+       (partial_symbol_file_open):  Change args all around for BFD.
+
+       * symtab.c: Rename "value" to "val" everywhere, so we can
+       #include "value.h".
+       (symbol_file_command):  New command, moved from dbxread.c
+       and coffread.c.  It uses BFD to read the file, then vectors
+       based on its type, to dbx or coff symbol readers.
+       * symtab.h:  Extern a few vars for symbol_file_command.
+
+       * target.h:  Breakpoint takes a char * save area, not a char **.
+
+       * valprint.c (val_print):  When unpacking bitfields, offset
+       the address in gdb of the value, if it is declared with a shorter
+       type.  Remove the last "runtime kludge test" of host byte order.
+
+       * utils.c:  Remove old my_bfd_read routine.
+
+       * stack.c (frame_info):  Use target_has_stack.  Print program counter
+       register's actual name rather than "pc", since it's called the
+       "ip" (instruction pointer) on the i960 (sigh).
+
+       * target.c (target_command):  Add command for selecting a target
+       type and calling its open routine.  This is used for initiating
+       communication with a particular target, in a generic way.
+
+       * tm-i960.h:  Update for modern gdb.  Remove semicolons from
+       various macros.  Handle reading struct return convention, and
+       error-out attempts to return structs with the "return" command.
+       Be sure gdb doesn't think we know how to call functions in the
+       inferior.
+
+       * i960-tdep.c:  Rename FRAME_CHAIN_VALID and FRAME_FIND_SAVED_REGS
+       to i960_xxx in lower case.
+       (arg_address):  Circumvent errors due to LOC_ARG_BLOCK
+       not being defined yet.
+
+       * remote.c (remote_open):  Call start_remote to initialize 
+       wait_for_inferior during open.
+       (remote_xfer_inferior_memory):  Return length written rather
+       than errno value.
+
+       * remote-vx.c (target_command -> vx_open):  Use new generic
+       target command.
+       * remote-eb.c, inftarg.c, exec.c: ditto.
+
+       * infrun.c:  Fix comments.
+       (attach_program -> child_open):  Use new generic target command.
+       (wait_for_inferior):  Clear saved register values before target_wait,
+       so target_wait can set some of them if convenient.
+
+       * infptrace.c (fetch_inferior_registers, store_inferior_registers):
+       Return success indicator, not void.
+       (child_xfer_memory):  Avoid fetching initial word if we'll
+       overwrite it anyway.
+
+       * infcmd.c (attach_command):  Use new generic target open routine.
+       (_initialize_infcmd):  Update doc on attach and detach commands.
+       (do_registers_info):  Merge in a byte-order problem as a FIXME
+       comment.
+
+       * findvar.c (find_saved_register):  Avoid problem in current frame.
+       (read_relative_register):  Ditto.
+       (write_register):  Convert byte order on the way out.
+
+       * exec.c (file_command):  Add.
+       (add_to_section_table, exec_command):  Use new bfd_map_over_sections.
+       (xfer_memory):  Common function between core_xfer_memory and
+       exec_xfer_memory.
+       (exec_xfer_memory):  Use it.
+
+       * pn-opcode.h:  Document that a "PN" is a Gould PowerNode.
+
+       * breakpoint.c, breakpoint.h, symtab.h, value.h, frame.h, utils.c,
+       valops.c, stack.c, target.c, sparc-xdep.c, source.c, printcmd.c,
+       infcmd.c, i960-pinsn.c, eval.c, defs.h:  lint and gcc -Wall.
+
+Sun Dec  2 16:45:06 1990  John Gilmore  (gnu at cygnus.com)
+
+       Merge Intel 960 port of gdb, continuing...
+
+       * dbxread.c (partial_symbol_file_open, partial_symbol_file_read,
+       symbol_file_command):  Pass from_tty arg to hush 'em up.
+
+       * coffread.c (symbol_file_command):  Avoid output if from_tty != 1.
+       Add magic numbers for 960 COFF format.
+
+Fri Nov 30 09:18:20 1990  John Gilmore  (gnu at cygnus.com)
+
+       Merge Intel 960 port of gdb, from Intel "1.2" release.
+
+       CHANGE_LOG entries from their port, which was based on
+       gdb+-2.8.0:
+
+    Thu Sep  6 11:02:22 PDT 1990
+       Remove temp file if download is interrupted.
+
+    Wed Aug  1 09:08:33 PDT 1990
+       Now uses binary protocol to talk to NINDY.
+       Old hex protocol (NINDY 2.13 and older) supported with -O switch.
+       Times out after 5 seconds when trying to talk to NINDY.
+
+    Tue May 29 12:54:49 PDT 1990
+       Added variable baud rate (-b switch).
+       Source code reorganization.
+
+    Thu Apr 26 11:09:55 PDT 1990
+       More cleanup of batch mode;  specifically, execute "-s", "-e", and
+       "-se" switches as soon as they are encountered on the invocation line.
+
+    Fri Apr 20 13:47:15 PDT 1990
+       Add -brk switch.
+
+    Thu Apr 19 09:54:28 PDT 1990
+       Add 'reset' command.
+
+    Wed Apr 18 09:48:07 PDT 1990
+       After opening remote tty, wait for 1 second to go by without input
+       from it before trying to talk to NINDY (fixes problems with the
+       Heurikon HK80/V960E).
+
+    Mon Apr  4 16:33:05 PDT 1990
+       Some output was not being suppressed in 'batch' mode.
+
+    Thu Mar 22 15:31:11 PST 1990
+       Ask user if old symbol table should be deleted when new file is
+       downloaded.
+
+       Allow user to run a program downloaded before gdb960 was brought up.
+
+       Correct "exec-file" help message for i80960 context.
+
+       Correct bug in calculating user space address:  could occasionally
+       corrupt user program.
+
+       Make sure to zero low-order bits in rip's because of bug in 960CA
+       A-step part:  could cause operation faults when "next"ing across
+       a function call.
+
+       Correct bug that made it impossible to get source line numbers for
+       code loaded at addresses higher than 0x7fffffff.
+
+    Wed Jan 10 12:43:22 PST 1990
+       Open remote tty for exclusive use.
+
+    Fri Jan  5 12:14:42 PST 1990
+       Correct disassembly (CA manual was right after all):
+       opcode for sysctl is 0x659
+
+    Mon Oct 23 12:03:04 PDT 1989
+       Use G960BASE and G960BIN environment variables to find 'sx' utility.
+
+    Mon Oct 16 14:15:09 PDT 1989
+       "sfr0"-"sfr31" should have been named "sf0"-"sf31"
+
+    Mon Oct  2 15:56:31 PDT 1989
+
+       Added 960CA disassembly support.
+
+       To simplify maintenance:
+               - eliminated use of symblic links on pinsn.c: use i960-pinsn.c
+                       directly instead.
+               - eliminated opcode.h: incorporates tables into i960-pinsn.c
+               - moved 960-specific routines from i960-pinsn.c to i960-md.c
+               - made disassembly interface identical to that in gdmp960.
+
+
+
+Wed Nov 28 21:32:48 1990  John Gilmore  (gnu at cygint)
+
+       * target.h: Allow targets to stack.  Add target_has_memory,
+       _registers, etc.  Restructure memory access and "info files"
+       to walk the target stack.
+       * exec.c, core.c, inftarg.c, remote.c, remote-vx.c, remote-eb.c,
+       target.c:  Change tables to match target.h.
+       * inflow.c (child_mourn_inferior):  pop child_ops.
+       (generic_mourn_inferior):  Use new has_stack flag.
+       * infptrace.c (child_xfer_memory): New memory regime.
+       * inftarg.c (child_files_info): New "info files" regime.
+       * remote-eb.c: New memory regime, new info files.
+       * remote-vx.c: New memory regime, new info files.  Now use
+       separate targets for VxWorks attachment to machine, and 
+       actually running a process under VxWorks, since one has
+       stack & execution & regs and the other doesn't.
+       * remote.c: New memory regime, new info files.
+       * sparc-xdep.c (fetch_core-registers):  New memory regime.
+       * target.c:  New routines and support for stacked targets,
+       new memory regime, new info files regime.
+       
+
+       Generalize section handling for an arbitrary number of sections,
+       including use of the new BFD (binary file) library.
+       * gdbcore.h: Add struct section_table.
+       * exec.c (build_section_table):  Iterate all sections and
+       record what gdb needs to know about them.
+       (exec_command):  Use it.
+       (exec_xfer_memory):  Use the table.
+       (exec_files_info):  Print the table.
+       * core.c (core_file_command, core_xfer_memory, core_files_info):
+       Likewise.       
+       * source.c (find_source_lines):  Use bfd_get_mtime.
+       * dbxread.c:  Quick changes to make it compile with new BFD.
+       * utils.c (error):  Avoid using bfd_error in generic routines.
+       
+       * core.c (core_fetch_registers):  Get from the ".regs" section of
+       the BFD core file.
+       * sparc-xdep.c (fetch_core_registers):  Use the .regs info.
+
+       * inferior.h (attach_flag):  Export.
+       * infcmd.c (run_command):  use new target_create_inferior.
+       * infrun.c (child_create_inferior):  Don't return result.
+       * Makefile.dist (VERSION):  3.91.4.
+
+Fri Nov 23 28:15:38 1990  John Gilmore  (gnu at cygint)
+
+       * breakpoint.c (bpstat_num):  Handle breakpoints which have
+       since been deleted, such as temporary breakpoints.
+       infcmd.c (program_info):  ditto.
+
+       * core.c (core_file_command):  Display the frame where the core
+       dump occurred.
+
+       * main.c:  lint.
+
+       * remote-vx.c (target_command):  Merge in target command from
+       targ-vx.c.  A few other cleanups.
+
+       * TODO, Projects:  Lots more stuff to do...
+
+Fri Nov 23 18:15:38 1990  John Gilmore  (gnu at cygint)
+
+       Massive changes to wall off the remote-debugging interface
+       behind a function vector.  The port to handle VxWorks targets
+       is also part of this.
+
+       All files:  Replace references to renamed functions,
+       remove references to remote_debugging, remove references to
+       have_include_file, have_core_file in favor of target_has_stack,
+       target_has_memory, etc.
+
+       * Modularize the breakpoint interface.
+       breakpoint.h (BREAKPOINT_MAX):  New define sets max length of
+       a breakpoint instruction.
+       breakpoint.c: struct breakpoint's shadow_contents now sized as
+       BREAKPOINT_MAX.
+       (insert_breakpoints):  Vector to target to install breakpoints.
+       (remove_breakpoints):  Vector to target here too.
+       Remove REMOTE_SA_SPARC kludges and other remote_debugging.
+       sparc-tdep.c (single_step):  Use new breakpoint interface for
+       the single-step breakpoints.
+       mem-break.c (memory_insert_breakpoint, memory_remove_breakpoint):
+       New file, contains routines to insert and remove breakpoints by
+       reading out the old contents and later replacing them.  This is
+       how ptrace breakpoints work, and many remote systems as well.
+
+       * tm-vxworks68.h:  New config file, overrides a few things for
+       Wind River's preferences.
+
+       * target.h:  New file, for transfer vector used to talk to the
+       inferior (child, attached, core, exec, remote, etc).  All accesses
+       to the thing being debugged should come through these vectors.
+       target.c:  New file, routines to handle transfer vector.
+       (various files):  Add transfer vectors XXX_ops for the various
+       targets and pseudo-targets (core files, etc) we support.
+
+       * breakpoint.c (bpstat_stop_status):  Further explorations of
+       watchpoints and why things don't work all the time.
+       (bpstat_alloc):  New fn to allocate a bpstat and chain it.
+
+       * config.gdb:  Only add "source ${srcdir}/.gdbinit" to
+       the local gdbinit if it doesn't already have it.
+
+       * core.c (core_ops):  add and install.
+       Allow core debugging without exec file.
+
+       * dbxread.c (free_and_init_header_files):  Merge two fns.
+       (end_symtab):  Free named symbol table when a new version comes in.
+       (read_dbx_symtab):  Relocate all kinds of symbols with base
+       address.  First step toward handling different text, data, bss
+       reloc.
+       (add_file_addr_command):  Renamed add_file_command.
+       (add_file_command):  Vector to remote handler.
+       Add "load" as an alias for "add-file" command.
+
+       * defs.h:  Allow "volatile" to be used in non-ANSI; use it for
+       non-returning functions.
+
+       * exec.c:  Add exec_ops, and push it as a target when an exec
+       file is specified.
+
+       * infcmd.c (run_command):  Pass executable file name and arg list
+       separately when starting an inferior.  Permit "run" when no exec
+       file is specified, for VxWorks.
+       (detach_command):  Move to child_detach in inftarg.c.
+
+       * inftarg.c:  New file.  Unix-child-specific routines, and the
+       child_ops structure.
+
+       * inferior.h (registers):  Export "registers" as the way for
+       target dependent register handlers to find gdb's local copy of
+       the registers.  Rename "stop_after_attach" to "stop_soon_quietly"
+       since it is now used by places that want wait_for_inferior to
+       handle the grunge but want to see every trap from the inferior.
+
+       * inflow.c (create_inferior):  Pull out, and merge into infrun.c.
+       Eliminate remote_debugging hooks in terminal handling.
+
+       * infrun.c:  Replace start_inferior with child_create_inferior.
+       Move all the hair of Unix shells and ptrace idiosyncracies into
+       child_create_inferior, so remote handlers don't have to deal.
+       Remove running_in_shell.  Rename stop_after_attach to
+       stop_soon_quietly, and use it in a few other places where we want
+       to just call wait_for_inferior and get control back on the first
+       trap.  trap_expected now never takes a value > 1.
+       (init_wait_for_inferior):  Initialize static vars when a new
+       process is created.
+
+       main.c (gdbinit):  Add new hook for .gdbinit file name, let
+       it be overridden by config files as GDBINIT_FILENAME.
+       (DEFAULT_PROMPT):  Add new hook for overriding (gdb) prompt.
+       Both of these are used for VxWorks gdb.
+
+       mcheck.c:  rename include file "gmalloc.c" to avoid problems
+       with system include file "malloc.c".
+
+       param-no-tm.h:  New include file, same as param.h but does not
+       include the default "tm.h" file.  This is used in files where
+       the target is known, e.g. remote-eb.c or sparc-xdep.c.
+
+       param.h:  Now just a shell that includes tm.h and param-no-tm.h.
+
+       remote-vx.c:  New file, VxWorks remote debugging support.  Uses
+       RPC routines that are shared with the target system, in directory
+       ${srcdir}/vx-share.
+
+       remote.c:  Vectorize remote interface.
+
+       source.c:  Globalize source_path, and make an alias "l" for "list"
+       since we now have the "load" command.
+
+       sparc-xdep.c:  Use new param-no-tm.h.
+
+       symmisc.c (free_named_symtab):  Add new function from Wind River.
+       However, ifdef it out for now while we think about what it should
+       really be doing.
+
+       tm-sun3.h, xm-sparc.h, xm-sun3.h, xm-symmetry.h: Move
+       PREPARE_TO_STORE to
+       the xm- file, and change its name to CHILD_PREPARE_TO_STORE, since
+       non-Unix-children handle this with their own code in the target
+       transfer vector.
+
+       Makefile.dist:  Roll version to 3.92.3.  Add vx-share stuff to
+       source and target lists.  Add vx-share to default list of include
+       directories.  Add new files to src and target lists: mem-break,
+       target, inftarg, remote-eb, remote-vx, targ-vx.  Be sure the
+       ${srcdir} versions of munch and createtags are used.
+
+       * valops.c (find_function_addr):  Split out of call_function.
+       (call_function_by_hand):  Rename call_function; this function 
+       calls functions in the target by laboriously patching the target
+       word-by-word with the right stack, args, regs, etc.
+
+
+Mon Nov  5 17:29:10 1990  John Gilmore  (gnu at cygint)
+
+       Handle AMD 29000 a bit better.
+
+       * remote-eb.c (readchar):  Mask received char log to make it readable.
+       (remote_start):  Pass arguments down to executing program.
+       Make startaddr unsigned.
+       infrun.c (start_inferior):  Accept args, pass them to
+       remote_start.
+       infcmd.c (run_command):  Pass args down to start_inferior.
+
+       * tconfig/am29k-aout, tconfig/am29k-coff:  New files specifying
+       the target object file format.
+       tm-29k.h:  Pay heed to COFF_ENCAPSULATE.
+
+       * am29k-pinsn.c (print_insn):  Print 0x on hex numbers in disassembly.
+       am29k-tdep.c (examine_prologue):  Better checking of function prefixes.
+
+Sun Oct  7 18:20:45 1990  John Gilmore  (gnu at cygint)
+
+       * Makefile.dist (VERSION):  Roll version to 3.91.9 and freeze.
+       * TODO:  We did a few things, we have more to do though.
+
+       * xm-sparc.h (CLEAR_DEFERRED_STORES):  Define.
+       * inflow.c (inferior_died):  Clear deferred stores.
+       
+       * Debug problems with dummy frames and calls to the inferior.
+       * tm-sparc.h (PUSH_DUMMY_FRAME, POP_FRAME):  Move to sparc-tdep.c.
+       * sparc-tdep.c (do_restore_insn):  Simplify.
+       (sparc_frame_find_saved_regs):  Simplify and fix what we find.
+       (sparc_push_dummy_frame):  Simplify and fix what we push.
+       (sparc_pop_frame):  Slightly more hair here, deciding whether
+       we are restoring a saved PC or returning to a return address in %i7.
+       * sparc-xdep.c (read_inferior_registers):  Debug if valid reg is read.
+
+       * utils.c (xmalloc, xrealloc):  Return type depends on __STDC__.
+       * symtab.h (xmalloc): ditto, for obstack_chunk_alloc.
+       * obstack.h (chunkfun): ditto.
+       * defs.h (xmalloc, xrealloc): ditto
+
+       * utils.c (quit):  Grab the terminal from the child if necessary. 
+
+       * inflow.c (term_status_command): Rename to term_info, change
+       to "info terminal".
+
+       * sparc-pinsn.c (print_insn):  Disassembly prefers real instructions.
+       (is_delayed_branch):  Speed up.
+       * sparc-opcode.h: Add ALIAS bit to aliases.  Fix up opcode tables.
+       Still missing some float ops, and needs testing.
+
+       * Support for input and output radixes other than base 10
+       * defs.h (input_radix, output_radix):  Declare.
+       * expread.y (yyparse, parse_number):  Handle changes of input
+       radix, and ambiguous names-or-numbers in radixes >10.
+       * printcmd.c (print_scalar_formatted):  Print formatted hex
+       numbers in varying column widths.
+       * valprint.c (val_print):  Use output_format to print scalar ints.
+       (set_input_radix, set_output_radix, set_radix):  Create.
+       (set_output_radix):  Set output_format from output_radix.
+       (_initialize_valprint):  add `set radix' but leave the others off.
+       
+       * main.c (execute_command): Let stupid questions be turned off.
+       (_initialize_main): Handle "set stupidity", etc.
+
+       * main.c, inflow.c, inferior.h, frame.h, command.c, defs.h, 
+       sparc-pinsn.c, sparc-xdep.c, value.h, valops.c, values.c:  Lint.
+
+Tue Oct  2 11:20:02 1990  John Gilmore  (gnu at cygint)
+
+       * TODO, Makefile.dist, ChangeLog:  Freeze for 3.91.8 release.
+       bfd stuff is still screwed up, but with some manual work, it
+       compiles.
+
+       * breakpoint.c (bpstat_do_actions):  Start over if a command
+       proceeds the inferior, since the inferior will have stopped and
+       will need to have its new stop-actions taken care of.
+
+       * dbxread.c (read_struct_type):  Expression gives Sun3 4.0.3
+       compiler fits, simplify it.
+
+       * gdb.texinfo (directory command): Doc new dir command.
+       source.c (directory_command):  "dir" now puts things on the front
+       of the path, moves dups up front, and handles multiple names
+       on the command line, inserting each one in order.  It also
+       blows away cached line and full_filename info.
+
+       * stack.c (backtrace_command):  Skip "more stack frames follow"
+       unless interactive.
+
+       * Change #ifndef HAVE_VPRINTF to #define MISSING_VPRINTF in
+       xm-convex.h, xm-hp300bsd.h, xm-isi.h, xm-merlin.h, xm-news.h, 
+       xm-np1.h, xm-pn.h, xm-pyr.h, xm-symmetry.h, xm-umax.h, xm-vax.h.
+       The only odd one was Gould NP1, which had defined vprintf to
+       "printf"!!!
+
+       * Merge Ted Goldstein <tedg@Eng.sun.com>'s changes for epoch.
+       printcmd.c (print_command_1): Pass 'inspect' flag down as a global
+       variable, inspect_it.
+       valprint.c (print_string, val_print): Use the global inspect_it
+       to indicate whether to print in Epoch style or normal style.    
+
+Mon Oct  1 23:55:26 1990  John Gilmore  (gnu at cygint)
+
+       * printcmd.c (call_command):  add an alias for the "print" command
+       which runs expressions and doesn't print the result if void.
+       (print_command_1): implement it.
+
+       * command.c: Remove #if 0'd code.  Initialize all the fields
+       in add_cmd ().  Rename do_nothing_command to
+       not_just_help_class_command, and make it externally visible.
+       command.h: add user_commands to struct.
+       * main.c (define_command):  Don't overload c->function with a char
+       string as well as a function pointer.
+
+       * eval.c (evaluate_subexp):  Reinstall tiemann changes to
+       calling convention of value_struct_elt () that got dropped in
+       merge.
+
+       * tm-sparc.h (FRAME_FIND_SAVED_REGS):  move to sparc-xdep.c.
+       sparc-tdep.c (sparc_frame_find_saved_regs):  ditto.
+
+       * tm-sparc.h (POP_FRAME): replace some constants with defines.
+
+       * sparc-xdep.c (store_inferior_registers):  defer stores to regs
+       until a good time (e.g. when we are about to run the child),
+       saving ptrace calls.
+       * infrun.c (proceed):  handle DO_DEFERRED_STORES.
+       * tm-sparc.h: define DO_DEFERRED_STORES.
+
+       * sparc-xdep.c (store_inferior_registers): when storing float
+       registers, don't store stack regs too.  When storing the SP,
+       however, DO store the stack regs too.  This fixes a bug in which
+       the dummy frame is not recognized when a call_function finishes,
+       because its frame pointer (in the stack regs) was never
+       initialized.
+       (read_inferior_registers):  Mark WIM and TBR and FPS and CPS valid
+       even though we don't know how to read them from an inferior.
+       valops.c (call_function):  Comment about storing SP.
+
+       * infrun.c (save_inferior_status): Save away the original bpstat
+       chain so it can be restored later.  Install the copied version for
+       use by whoever saved the status.  It will be blow away by
+       restore_inferior_status, and the original chain restored.  This is
+       important for people who have pointers into the original.
+
+       * breakpoint.c, command.h, copying.awk, dbxread.c, defs.h,
+       findvar.c, frame.h, obstack.h, obstack.c, inflow.c, value.h,
+       main.c, printcmd.c, sparc-tdep.c, symtab.c, valprint.c: lint
+
+
+Fri Sep 28 20:32:46 1990  John Gilmore  (gnu at cygnus.com)
+
+       * Makefile.dist: Roll version to 3.91.8.  Add bfd.h and bfdconfig.h
+       temporarily to the makefile.  Add am29k-opcode.h and WHATS.NEW.
+       Add stuff.c and kdb-start.c to the OTHERS list for tar files.
+
+Fri Sep 28 19:12:12 1990  John Gilmore  (gnu at cygint)
+
+       * Merge Mike Tiemann's multiple inheritance changes from Sun.
+       Store the baseclasses in a type struct starting from array element
+       0 rather than from the unusual array element 1.
+
+       dbxread.c: the above.
+       (virtual_context): Add
+       Read new debug information about which virtual function table
+       a virtual function is from, and store it in fn_field.fcontext.
+       
+       symtab.h: Add fcontextt.  Fix baseclass indices.  Typo in
+       TYPE_FN_FIELD_STATIC_P.
+
+       symtab.c: the above.
+       valops.c: the above.  Handle pointer casts of object *'s.
+       (search_struct_method): Add.
+       (value_struct_elt): First arg is now a pointer to a value, and is
+       modified on return.
+
+       valprint.c: the above.
+       values.c (value_virtual_fn_field): Add type arg.  Handle
+       offsetting to the proper object when calling virtual fns.
+       The above.
+       (baseclass_addr): Add valuep arg.
+
+       * README:  Document the current state of BFD config (missing).
+       * TODO, ChangeLog, Makefile.dist: Roll version.
+       * WHATS.NEW: Add summary of changes since 3.5.
+
+Thu Sep 27 16:23:12 1990  John Gilmore  (gnu at cygint)
+
+       * dbxread.c (read_struct_type): Clear bit vectors whenever
+       we allocate one.
+       symtab.c (B_CLRALL): define.
+
+       * tm-sparc.h (STORE_RETURN_VALUE): Avoid clobbering types by
+       using == rather than =.  Huh...  This fixes the dreaded problem
+       wherein builtin_type_int becomes TYPE_CODE_FLT.
+
+       * core.c (info_files): Show the inferior pid.
+
+       * config.gdb: Avoid putting "dir" command into .gdbinit.  GDB
+       already knows how to look in the source directory.
+
+       * Remove psymtab hair from many places.  Remove duplicated code
+       for searching symbol tables.  Hide psymtabs from most places.
+       Make it fast to get from a psymtab to its symtab.
+
+       blockframe.c (blockvector_for_pc): Remove psymtab hair.
+       coffread.c (psymtab_to_symtab): Rename to psymtab_to_symtab2.
+       mipsread.c (psymtab_to_symtab): Rename to psymtab_to_symtab2.
+       dbxread.c: export psymtab_to_symtab, make it work if called N times.
+       (psymtab_to_symtab): Rename to psymtab_to_symtab2.  Initialize
+       new symtab completely.  New psymtabs get symtab pointer
+       initialized to zero.  Remove MI warning printf.  
+       symtab.h: Comments.  Add psymtab to symtab pointer.
+       (PSYMTAB_TO_SYMTAB): New macro.
+       symtab.c: use PSYMTAB_TO_SYMTAB.  Add psymtab_to_symtab and export it.
+       source.c: use PSYMTAB_TO_SYMTAB.  Remove symtab version and
+       compilation fields.
+       stack.c (backtrace_command): Avoid pre-pass to read symbols, if
+       verbose is not set.
+       (print_frame_info): Avoid special-casing symbols that have not yet
+       been read in.
+
+       * source.c (open_source_file): Quick path if we have already
+       located the source file by its full name.
+
+       * symtab.c (lookup_symbol): Use find_pc_symtab rather than
+       find_pc_psymtab.  When a name is found in the misc function
+       vector, search the symbol table for its mangled name, not the
+       name that the user typed.
+
+       * bfd.h: Fix missing comment terminators, make #endifs match.
+
+       * valarith.c (value_less): Handle unsigned int comparisons.
+       Add FIXME about pointer compares, which assume host and target
+       pointers are the same.
+
+       * command.c (do_nothing_command): lint
+       dbxread.c: lint.  Remove sort_syms.  Document C++ visibility info,
+       fix comments on debug symbol format for visibility.  Actually set
+       visibility of symbols.
+       main.c (echo_command): lint; use <readline/history.h>.
+       tm-sparc.h (FRAME_FIND_SAVED_REGS): lint
+       obstack.h (_obstack_blank): Rearrange pointer math to avoid
+       pointing past end of allocated memory; saber complains.
+       obstack.h: Declare the external functions that we use.
+       valarith.h: use <string.h>
+       solib.c (solib_add): lint.
+
+Fri Sep 21 17:05:19 1990  John Gilmore  (gnu at cygint)
+
+       * main.c (initialize_main):  Default info_verbose to off, now that
+       symbol reading is fast.
+       (quit_command):  Avoid clobbering exec_bfd while quitting.
+
+       * Initial BFD (binary file diddling library) merger:
+       coffread.c: Change AOUTHDR to struct exe_hdr.
+       dbxread.c: ditto.
+       core.c: initialize initialized data at compile time.
+       (core_file_command):  Move from coredep.c, convert to bfd.
+       (xfer_core_file): Convert to bfd.
+       exec.c (exec_file_command): use bfd routines.
+       gdbcore.h: BFD.
+       mips-tdep.c: Remove exec_file_command and friends.
+       source.c: bfd.
+       
+       * coredep.c: (fetch_core_registers) Convert core_file_command to
+       fetch_core_registers.
+       mips-xdep.c, sparc-xdep.c, sun3-xdep.c: ditto.
+       
+       * utils.c: (error): Bogus crap, FIXME, to print bfd errors.
+       (my_bfd_read): More bogosity, which I don't think we call.
+       (program_name): Remove this atrocity asap!
+
+Wed Sep 19 13:36:41 1990  John Gilmore  (gnu at cygint)
+
+       * From Per Bothner:
+       values.c: allocate_repeat_value was not clearing the
+       optimized_out field.
+       (value_static_field): minor stylistic fix (wrong macro was used).
+       valops.c (value_struct_elt_for_address): didn't work for C++
+       static fields.
+
+       * signame.c (_initialize_signame):  Initialize signal names once.
+
+       * breakpoint.h, command.c, copying.awk, defs.h, environ.c,
+       exec.c, frame.h, infcmd.c, inferior.h, main.c, munch, sun3-xdep.c,
+       symtab.h, tm-29k.h, valprint.c, value.h, values.c:  Lint.
+
+       * remote-eb.c:  Support user-settable baud rates on the serial port.
+
+       * tm-sun3.h (PREPARE_TO_STORE): fix typo.
+
+Fri Sep 14 13:28:29 1990  John Gilmore  (gnu at cygint)
+
+       * tconfig/sun3os4: Remove warning about native assembler,
+       since it also occurs in the xconfig file.
+
+       * findvar.c (registers): Allocate some slop after `registers'
+       to prevent stray accesses from trashing the next variable.
+
+       * tm-68k.h (REGISTER_BYTES):  Allocate the right number of bytes
+       on the sun-3, by changing the #ifdef from `sun3' (which is not
+       defined by cc) to `sun'.  Symptom was trashed builtin_type_XXX
+       vars, which happened to follow `registers' in the executable.
+
+       * readline/history.c (history_search): Heed gcc-2's advice
+       and parenthesize && inside ||).
+
+       * am29k-opcode.h, am29k-pinsn.c, am29k-tdep.c, remote-eb.c,
+       tm-29k.c:  Insert FSF copyright headers.
+
+       * remote-eb.c:  Better comments.
+
+       * Makefile.dist:  Update to 3.91.6.
+       * TODO: note PREPARE_TO_STORE problem.
+
+Thu Sep 13 09:52:33 1990  Jim Kingdon  (kingdon at cygint)
+
+       * stack.c (frame_info): Only use FRAME_FIND_SAVED_REGS if defined.
+
+       * remote.c:  Wrap the whole file in #if !defined (SPECIAL_REMOTE).
+
+       * infrun.c (wait_for_inferior, at end): Don't set up
+       prev_* if the inferior no longer exists.
+
+       * inferior.h (CALL_DUMMY_LOCATION): New macro, to replace
+       CANNOT_EXECUTE_STACK.
+       valops.c (call_function): Use it.
+
+       * tm-convex.h: Add CALL_DUMMY_LENGTH for use by PC_IN_CALL_DUMMY.
+
+       * inferior.h (PC_IN_CALL_DUMMY): New macro.
+       infrun.c (wait_for_inferior, 2 places): Use it.
+
+       * values.c (value_being_returned): Only use
+       EXTRACT_STRUCT_VALUE_ADDRESS if defined.
+
+       * Move PREPARE_TO_STORE from xm-sun3.h to tm-sun3.h to do the
+       right thing for remote-eb.c.  
+
+       * sun3-xdep.c:  Remove extraneous call to remote_store_registers.
+       * sun386-xdep.c, hp300hpux-xdep.c, sparc-xdep.c:  Ditto.
+
+       * blockframe.c:  Put get_frame_saved_regs inside #if !defined
+       (FRAME_FIND_SAVED_REGS).
+
+       * findvar.c ({fetch,store}_registers): Check for
+       REMOTE_{FETCH_STORE}_REGISTER macro.
+
+       * findvar.c (get_saved_register): Add argument lval and
+       change meaning of argument addr.
+       findvar.c:  Change calls to get_saved_register to reflect
+       new calling convention.
+       valops.c (value_assign): Use get_saved_register instead of
+       find_saved_register.
+
+Sun Sep  2 12:40:20 1990  Jim Kingdon  (kingdon at cygint.cygnus.com)
+
+       * coffread.c (read_one_sym): Make temp_aux an AUXENT, not
+       an (uninitialized) pointer to one.  Use "&" when passing it
+       to fread.
+
+Fri Aug 31 22:57:54 1990  Jim Kingdon  (kingdon at cygint.cygnus.com)
+
+       * coffread.c (getfilename): Use DGUX x_offset and x_name if
+       defined.
+
+       * coffread.c (symbol_file_command): Put semicolon after
+       "int from_tty".
+       Put safe_to_init_tdesc_context in #if defined (TDESC).
+       Put #ifdef TDESCs in 1st column for non-ANSI cpp's.
+       coffread.c: #include <sys/stat.h>.
+       (read_coff_symtab): Typo: in_source_files -> in_source_file.
+       Add missing ')' in check for "lc%" and friends.  Remove
+       extraneous '}'.
+       Declare read_one_sym() at top of file.
+       (read_file_hdr): Put in extra #ifdefs so MC68MAGIC and
+       MC68WRMAGIC can have the same value without causing a duplicate
+       case.
+
+Thu Sep 13 15:55:36 1990  John Gilmore  (gnu at cygint)
+
+       * Allow a Makefile to be built without building the
+       tm and xm file links that screw up builds in subdirectories.
+       This is done with `config.gdb none', then you can do things
+       like `make gdb.tar.Z'.
+       * tconfig/none: Config file for no target system
+       * xconfig/none: Config file for no host system
+       * config.gdb: If no TM or XM files are called out by the
+       host or target file, don't make links for them.
+
+       * cplus-dem.c: Add documentation.
+
+       * dbxread.c (read_ofile_symtab): Turn a fatal error into a
+       simple error, so the user's gdb doesn't crash due to some object
+       file problem (e.g. somebody is rebuilding the file out from under
+       gdb).
+
+       * printcmd.c (print_address_symbolic): demangle the symbol.
+
+       * Makefile.dist (OTHERS): Remove tdesc-lib because it has 
+       Motorola copyrights in it.  Make "make gdb.tar.Z" work.
+       (alldeps.mak): sort and uniq all results from this; duplicates
+       hose gdb.tar.Z link building.  Remove RCS files from
+       tconfig and xconfig.  Add config files for sun386.  Add
+       a few odd files to OTHERS and HFILES.
+
+Mon Sep 10 21:20:24 1990  John Gilmore  (gnu at cygint)
+
+       * Makefile.dist: Pull solib.c to tconfig/sun?os4.
+       Roll version number to 3.91.5.  Make lint work in bindir.
+
+       * README:  Document cross-debugging and new file structure.
+
+       * blockframe.c: Lint.  Include "value.h" to declare read_register.
+       (find_pc_partial_function): remove duplicate line.
+
+       * command.h: Lint.  Declare error_no_arg and dont_repeat.
+
+       * tm-news.h: Remove inadvertently duplicated stuff.
+
+       * mipsread.c: Remove cache_pc_function stuff, now done cleanly.
+       Clean up usage of misc_function_type.  Declare some CORE_ADDRs.
+
+       * config.gdb: Allow `config.gdb host target' form.  Clean
+       up previous change that printed bogus messages when you just said
+       `config.gdb'.
+
+       * core.c: #include "command.h" for lint.
+       * dbxread.c: lint
+       * eval.c: lint
+       * main.c: Remove some casts of enums.  Lint.
+       * source.c: lint
+       * symtab.c: lint
+       * symtab.h: lint
+       * expread.y: lint
+       * valarith.c: lint
+
+       * printcmd.c (initialize_printcmd): Fix thinko in inspect cmd.
+       
+       * sparc-tdep.c (isannulled): Take instruction as parameter, don't
+       read it from memory.  This will allow us to save ptrace calls
+       eventually.   Changed caller single_step too.
+
+       * sparc-xdep.c (fetch_inferior_registers): Avoid reading regs
+       that we aren't going to use, saving many ptrace calls, especially
+       when watchpointing or single stepping.  Use some #define's for
+       constants.
+       (store_inferior_registers): Ditto.
+       (core_file_command): Use some #define's for constants.
+
+       * tm-sparc.h: Add #define's for some register numbers, so we
+       can eliminate the use of random constants in sparc-xdep.c.
+
+       * stack.c (frame_command, print_frame_info, up_command,
+       down_command) Remove frame_changed, since it
+       causes a bug and doesn't seem to do anything useful.  In some
+       places it was used as a flag, in others as a stack level (?).
+
+       * utils.c: Use MISSING_VPRINTF rather than HAVE_VPRINTF, so the
+       default is to use the portable (vprintf) version rather than the
+       kludge version.
+       * xm-news.h (MISSING_VPRINTF): Add.
+
+       * valprint.c (val_print): Demangle fancy vtbl printouts.  Lint.
+
+Sat Sep  8 00:24:12 1990  John Gilmore  (gnu at cygint)
+
+       * Remove stuff that forces -Bstatic linking of gdb, and warnings
+       about linking debugged programs -Bstatic in the sun?os4 config
+       files in tconfig and xconfig subdirectories.
+
+       * main.c (main):  Remove unreached exit(0) now that we exit
+       via quit_command().
+
+       * Create TODO file for online bug list.  There are too many
+       "little" bugs to keep track of on paper.
+
+       * Change Projects file to refer to bug-gdb@cygnus.com
+       rather than kingdon@ai.
+
+Fri Sep  7 23:35:15 1990  John Gilmore  (gnu at cygint)
+
+       * Makefile.dist (VERSION): 3.91.4 now.
+
+       * symtab.c (init_misc_bunches): Rename from init_misc_functions.
+       (condense_misc_bunches): Add sanity check that misc_count is
+       the same as the number of symbols in the bunch.
+       
+       * coffread.c: rename init_misc_bunches.  Pass an argument 
+       to condense_misc_bunches (a zero).
+
+       * dbxread.c (partial_symbol_file_read): Call init_misc_bunches
+       every time we are called; don't rely on our caller to do it.
+       (add_file): Remove call to init_misc_bunches.
+
+       * mipsread.c: Only warn, don't error, if unknown symbol types.
+       This keeps an old gdb from falling on its face if it sees newly
+       extended symbol info.  Rename init_misc_bunches.
+
+Fri Sep  7 22:58:15 1990  John Gilmore  (gnu at cygint)
+
+       * Merge in changes from Per Bothner for DECstations and other
+       MIPS stuff.  The rest is Bothner speaking:
+
+       The next message is a merger of Alessando Forin's mips port with
+       mine.  I've tried to use my good if biased judgment to get
+       the best of both. It *does* need testing.
+
+       Some of the changes are general, *not* mips-specific.
+
+       param.h:
+       Didn't believe in little-endian bit order.
+       There are still inconsistencies about whether flags
+       like BITS_BIG_ENDIAN are integer (#if ...) or
+       boolean (#ifdef ...). I tried to paper over them.
+
+       dbxread.c,coffread.c,mipsread.c,symtab.c,symtab.h:
+       Moved some misc_function code that was common to
+       {dbx,coff,mips}read.c to symtab.c.
+       In the process, I think I cleaned things up a bit.
+       At the same time, moved obsavestring and obconcat to symtab.c.
+
+       dbxread.c:
+       Removed obsolete condense_addl_misc_bunches (use
+       condense_misc_bunches(1) instead).
+
+       exec.c:
+       Needed to include <sys/dir>, at least on DECstations.
+
+       valops.c, mips-tdep.c, tm-mips.h:
+       Added PUSH_ARGUMENTS macro to support funny argument-pushing
+       conventions (when STACK_ALIGN is insufficient).
+       Needed on mips, where doubles need 8-byte alignment,
+       but ints only need 4.
+
+       mips-opcode.h:
+       Removed cruft that was not being used.
+       Merged in many fixes (most from Frank Yellin, fy@lucid.com).
+
+       mips-pinsn.c:
+       Print $ before register-names (I think that makes things a little
+       more consistent).
+       Never print two instructions, even if one delays.
+       Removed hex-disassemble set_cmd.  (This is not mips-specific,
+       so I think the argument is whether it is generally worthwhile or not.
+       I'm inclined to think not, given how easy it is to
+       convert between radixes in gdb.)
+
+       mipsread.c:
+       This is basically Alessando's code.
+       It doesn't use obstacks; I changed it to use obstacks
+       in a few minor places where using malloc causes a
+       memory leak. (Probably, more places could/should be changed.)
+       I added record_misc_function where it was missing.
+       In symbol_file_command and add_file_command, I tried
+       to make the code consistent with more recent versions.
+       Minor sylistic changes in parse_procedure.
+       Make a .gdbinfo. psuedo-symbol point back to the real
+       procedure symbol (using the isym field).
+
+       mips-tdep.c:
+       This is basically from my port, but with a lot of details
+       and a number of routines merged in from Alessando's version.
+       I basically used my code "raw" backtrace (use heuristics
+       from the actual code, rather than symbol table info) - though
+       the idea is Alessandro's. I feel my code is a little cleaner
+       here, particularly in being a little more flexible, such as being
+       able to handle gcc-produced code (which it now can).
+       It also doesn't do frame caching (which is not useful
+       more recent gdb versions).
+       I also used my code for push_/pop_dummy, more or less.
+       I tried to incorporate AF's code for testing sigtramp
+       while backtracing; I probably got it wrong.
+       Added mips_print_register, which tries to scrunch as much
+       information as possible on a screen...
+       Removed the skip-prologue set_cmd. As with hex-disassemble (see
+       under mips-pinsn.c), I don't see anything mips-specific here,
+       and I don't see it being all that useful anyway.
+       
+       tm-mips.h:
+       Added a $fp psuedo-reg distinct from $fp (nice for gcc).
+       Use more register names (rather than hard-cases numbers).
+       
+Thu Sep  6 18:33:15 1990  John Gilmore  (gnu at cygint)
+
+       * Hack up 3.90.11 changes:
+
+       * Makefile.dist (depend): parameterize $(GCC).
+       Add solib.c and solib.o.
+       (readline): Fix vpath for both absolute or relative SRCDIR.
+
+       * blockframe.c: Fix from Schaefer@asc.slb.com for shared libs.
+       Also, let the part I didn't understand at least compile so
+       I can test the rest.  FIXME.
+
+       * dbxread.c: Fix thinko using strcmp.
+       (init_psymbol_list): declare static.
+       (partial_symbol_file_open): Comment cleanups better, avoid
+       cleaning up the string table since the caller will do that.
+       Move the stat for mod time into symbol_file_command, temporarily.
+       (There should be a mod time for each symbol file, eventually,
+       to control its rereading.  FIXME.)
+
+       * infptrace.c (PT_WRITE_D): use same value as PT_WRITE_I for
+       SunOS, which gives error for shared libs otherwise.  (From
+       Schaefer, probably FIXME needs work for portability.)
+
+       * solib.c:  Move #include "param.h" to work.
+       Lowercase all the Uppercase Letters In the Messages.
+       (find_solib): Clean up inferior_so_name for debug printouts.
+       Allow no argument, to mean all shared libraries.
+
+       * symmisc.c: include param.h to get CLEAR_SOLIB.        
+
+Wed Sep  5 18:00:08 1990  John Gilmore  (gnu at cygint)
+
+       * Merge in Kingdon's changes from FSF: the diffs from 3.90.9
+         to 3.90.11.  ChangeLog entries below are from this.
+
+Wed Jun 13 09:17:39 1990  Jim Kingdon  (kingdon at mole.ai.mit.edu)
+
+       * Version 3.90.11.
+
+       * Makefile.dist (HFILES): Add tm-sunos.h.
+
+Tue Jun 12 16:15:26 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * Version 3.90.10.
+
+       * Makefile.dist (gdb.tar.Z): Change linking of config so it works.
+
+Thu Jun  7 16:22:27 EDT 1990  Jay Fenlason (hack@ai.mit.edu)
+
+       * sparc-opcode.h  Added single-operand version of rett.
+
+Mon Jun  4 18:12:31 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * m-sparc.h (REG_STRUCT_HAS_ADDR, STRUCT_ARG_SYM_GARBAGE):
+       Put parens around gcc_p in expansion.
+
+Thu May 24 15:44:51 1990  Jim Kingdon  (kingdon at mole.ai.mit.edu)
+
+       * utils.c (lines_to_list): Return 10 if lines_per_page == 0.
+
+Wed May 23 16:36:04 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * Changes for Sun shared libraries:
+       blockframe.c (find_pc_partial_function): If a non-text symbol
+       is found, set *address = pc - FUNCTION_START_OFFSET.
+       breakpoint.c (insert_breakpoints) [DISABLE_UNSETTABLE_BREAK]:
+       Disable breakpoints instead of giving an error.
+       source.c (select_source_symtab): Initialize cs_pst.
+       symmisc.c: Call CLEAR_SOLIB if defined.
+       symtab.h: Make text{low,high} CORE_ADDR not int.
+       (psymtab): New field addr.
+       solib.c: New file.
+       dbxread.c: Move DECLARE_FILE_HEADERS outside functions.
+       (record_misc_function): Give correct type for N_DATA symbols.
+       (condense_misc_bunches): do "misc_function_count = j" regardless
+       of inclink.
+       Take code which is shared between symbol_file_command and
+       add_file_command and put it into partial_symbol_file_{open,read}.
+       Split add_file_command into add_file_command and add_file.
+       Make psymtab_to_symtab read in the string table if the file
+       is not symfile.
+       Two new parameters to read_dbx_symtab and start_psymtab.
+       tm-sunos.h: New file.
+
+Tue May 22 17:43:03 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * infcmd.c: Change cont_command to continue_command and "cont"
+       to "continue".
+
+Mon May 21 14:41:41 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * breakpoint.c (enable_breakpoint): Get value of watchpoint.
+
+       * defs.h [sparc]: Use <alloca.h> regardless of __GNUC__.
+
+       * values.c (USE_STRUCT_CONVENTION): Check for structures of
+       size 1,2,4,8 rather than size < 8.
+
+       * dbxread.c (dbx_lookup_type): Do f->length *= 2 as many times
+       as necessary, not just once.
+
+       * sparc-opcode.h: Add a bunch of new opcodes which Sun as supports.
+
+Thu May 17 15:04:09 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * {t,x}m-sun386.h, sun386-xdep.c, {x,t}config/sun386
+
+       * tm-news.h: Add CALL_DUMMY_*.
+
+       * tm-68k.h: Remove duplicate comment at FRAME_FIND_SAVED_REGS.
+
+       * config.gdb: In list_host, list_target, use ${i}, not $i.
+
+Tue May 15 21:27:12 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * source.c (find_source_lines) [BROKEN_LARGE_ALLOCA]: Use xmalloc.
+
+       * sparc-opcode.h: Change all store floating-point state register
+       instructions to have the right match & lose fields.
+
+Sat May  5 12:39:18 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * Makefile.dist: Move -I${srcdir} to GLOBAL_CFLAGS and pass
+       VPATH to readline.
+       config.gdb: If srcdir != ., create readline directory and
+       copy a makefile into it.
+
+       * wait.h, infrun.c: Change WRETCODE to WEXITSTATUS for
+       consistency with POSIX.
+
+       * breakpoint.c (bpstat_stop_status): Disable watchpoint
+       when we exit its exp_valid_block.
+
+Tue Sep  4 11:46:46 1990  John Gilmore  (gnu at cygint)
+
+       * Makefile.dist: Bump version to 3.91.3.
+
+       * Clean up handling of breakpoint commands (somewhat).
+         Prompted by Tiemann bug report "cont 10" doesn't work any more.
+
+         inferior.h: Add breakpoint_proceeded to inferior status struct
+         and globals; save it and restore it.
+         (clear_breakpoint_commands): Cleanup, remove old #define.
+
+         infrun.c (clear_proceed_status): Set breakpoint_proceeded.
+         (save_inferior_status, restore_inferior_status): handle it also.
+         (proceed): Remove earlier code that set breakpoint_proceeded.
+         It is now set only in clear_proceed_status.
+         (clear_proceed_status): Cleanup, use bpstat_clear rather
+         than clear_breakpoint_commands.  No callers need the stop_bpstat
+         between clear_proceed_status and proceed.
+
+         infcmd.c: Add breakpoint_proceeded definition and comment.
+         (cont_command, jump_command, signal_command): Move call to
+         clear_proceed_status right next to call to proceed.
+
+         breakpoint.c (bpstat_do_actions): Avoid clobbering our
+         caller's argument while running down the chain of breakpoints.
+         Use new variable "breakpoint_proceeded" to determine when
+         a command that it executes moves the inferior past the
+         breakpoint.
+         (bpstat_clear): Handle NULL argument.
+         (bpstat_clear_actions): Avoid useless call to
+         breakpoint_auto_delete.
+         (delete_breakpoint):  Clean up bpstat's that are pointing to
+         the deleted breakpoint from the stop_bpstat chain.
+         (breakpoint_auto_delete): Simplify.
+
+       * Clean up handling of EOF, error on stdin, etc.  This was
+         prompted by a network problem that caused gdb to go into an
+         infinite loop filling up its malloc'd memory.
+
+         main.c (return_to_top_level): Cleanup: call bpstat_clear_actions,
+         not clear_breakpoints_commands, which is now gone.
+         (main): If command_loop returns (e.g. from EOF on stdin), do
+         a quit_command (looping back to command_loop if quit_command
+         doesn't really quit).
+         (command_loop): check result from command_line_input and
+         exit if it returns NULL, rather than passing the NULL to
+         execute_command.
+         (gdb_readline):  Free malloc'd result space before returning
+         NULL for EOF.
+
+       * utils.c (query): Handle C-d to mean "yes", just as if the
+         input was not a terminal.  Also avoid infinite loop if EOF
+         occurs in mid-input-line before newline.  This allows
+         query to be used at EOF on stdin with reasonable results.
+
+       * infrun.c (proceed): Set breakpoint_proceeded.
+
+       * values.c (value_as_long): Avoid infinite recursion for enums.
+         (_initialize_values): Fix typo in help msg (kingdon).
+
+       * Makefile.dist (RL_LIB): Use RL_LIB_DEP for dependencies,
+         RL_LIB for linking.  This allows -lreadline for linking
+         and nothing for dependencies, once readline is a real library.
+
+       * config.gdb: Jim Kingdon: give useful error message if the
+         host or target type is not recognized.
+
+       * defs.h (alloca): SPARC <alloca.h> does not declare alloca,
+         it just defines it.  Dumb, but deal with it.
+
+       * Jim Kingdon suggests:
+         in xconfig/sun3os4, CFLAGS should be XM_CFLAGS.
+
+Wed Aug 29 18:03:27 1990  John Gilmore  (gnu at cygint)
+
+       * Makefile.dist (VERSION): Bump version # to 3.91.2.
+
+       * Clean up Bothner's changes.
+
+       * blockframe.c (clear_pc_function_cache): New function.
+       * blockframe.c: remake cache_pc_function_* static.
+       * dbxread.c (symbol_file_command): remove references to
+                   cache_pc_function_* variables.
+       * dbxread.c (read_struct_type): Use VOFFSET_STATIC.
+       * printcmd.c: Avoid kludging a global variable (addressprint)
+         to avoid printing the address of a string twice.  Instead,
+         pass the format letter 's' down low enough that it can be seen
+         to avoid this problem.
+         (print_formatted): Pass format arg to value_print.
+         (restore_addressprint): Remove function.
+         (do_examine):  Avoid hacking addressprint, cleanups and such.
+         (print_frame_args):  Add a comment to a Bothner change.
+       * symtab.h: define VOFFSET_STATIC and use it instead of "-1".
+       * symmisc.c (free_all_symtabs): Call clear_pc_function_cache
+         to wipe out the values cached in blockframe.c.
+       * symtab.c (find_method): Add comment saying how big you must
+         allocate to be "big enough".  Per being terse again.
+       * valprint.c (val_print): Handle format letter "s" to print
+         strings without addresses.  Add comment to vtbl printing code
+         which casts with wild abandon.  Rearrange reference-printing
+         code so it prints:
+              @0xaddr: value           (print w/addressprint)
+              value                    (print w/~addressprint)
+              @0xaddr                  (parameter lists w/addressprint)
+         or   nothing                  (parameter lists w/o addressprint)
+
+Tue Aug 28 10:47:18 1990  John Gilmore  (gnu at cygint)
+
+       * Merge more changes from Per Bothner:
+
+Gdb's handling of TYPE_CODE_REF was so counter-C++ (and otherwise
+annoying) that I tried to improve it. Here are my suggestions.
+
+       These patches all attempt to handle TYPE_CODE_REF (as in C++) better.
+
+       findvar.c:
+       Do automatic de-reference when taking the address of a reference.
+       printcmd.c:
+       Don't deref_ref when printing parameter lists.
+       valops.c:
+       More attempts at treating refernences properly.
+       valprint.c:
+       In val_print, if deref_ref==0, don't print dangling " = ".
+       value.h:
+       Add COERCE_REF macro, which de-references an REF.
+
+       * Merge changes from Per Bothner:
+
+* Fixed (Sony news)-specific configuration problems.
+* Fixed other problems with using vanilla pcc and libc (enum problems;
+assumption that vsprintf exists).
+* Some major speed-ups (finc_pc_partial_function now caches a match;
+parsing avoids duplicate symbol_lookup calls).
+* Changed handling of baseclasses (no longer use baseclasses field
+of struct type, use the first n_baseclasses fields instead).
+* Various minor changes/fixes, most C++-related.
+
+blockframe.c:
+Cache the most previous match from find_pc_partial_function.
+(Save both low and high ends of matching function's pc range.)
+This speeds up the loop of infrun.c:wait_for_inferior quite
+a bit, and makes step/next commands much zippier.
+command.c:
+Added an enum->int cast (otherwise, some compilers barf).
+dbxread.c:
+No longer set baseclass offset to 0, since multiple
+inheritance now mostly works.
+Added a number of casts, to shut up compiler warnings
+(after stabs where made enums, not ints).
+When discarding a symbol table (in symbol_file_command),
+must clear the cache introduced in blockframe.c.
+Don't convert $vtbl_ptr_type to vtbl any more.
+Get rid of TYPE_BASECLASEES and  baseclass_vec (see also symtab.h).
+Mask off sign bit emitted by g++ for virtual table offset.
+Set voffset to -1 (not 1) for static member functions.
+expread.y:
+Changed parsing/lexing of names to avoid doing symbol lookup twice
+(once when lexing to determine symbol class, once for real).
+Now only call symbol_lookup once. Fields of 'this' win especially big.
+printcmd.c:
+Subpress printing addr twice in the case of 'x/s addr'.
+symtab.c:
+lookup_basetype_type is no longer used.
+Add find_methods as recursive helper function to decode_line_1.
+This allows multiple inheritance to work.
+Also, once one or more matches has been found, do not look in
+base-classes. (Baseclass methods would be overridden, anyway.)
+symtab.h:
+Removed baseclasses array in struct type.
+Instead of using baseclasses[i], use fields[i-1].
+Added virtual_field_bits[i] to indicate if the i'th baseclass is virtual.
+Changed sign convention of voffset (previous was inconsistent).
+tm-news.h:
+Some macros (CALL_DUMMY and relatives) were missing. Put them back.
+utils.c:
+Used to assume existence of vsprintf. Re-written to not need it
+if HAVE_VPRINTF is undefined.
+valops.c:
+typecmp was too pessimistic. Made it less so.
+valprint.c:
+Don't print space after address.
+If vtable points to a misc symbol (with 0 offset), print it,
+since that indicates the actual class of the object.
+Changed ype_print_derivation_info to use new inheritance
+scheme (without baseclasses vector).
+values.c:
+In value_primitive_field, fixed some bugs left over from previous set of fixes.
+Also, changes needed because TYPE_BASECLASSES were removed.
+xm-news.h:
+REGISTER_U_ADDR didn't work for PC. Rewrote to use an array.
+
+Tue Aug 21 20:08:54 1990  John Gilmore  (gnu at cygint)
+
+       * source.c:
+  If there is no path set, and the symbols don't indicate what directory
+  a file was compiled in, look in the current directory.  But either
+  a path or a known compilation directory will prevent this.
+
+       * dbxread.c:
+  Three independent bug fixes:
+   * Remove the #if 0 block that breaks some stuff.
+   * SunOS 4.1 fixed the promoted-parameter-wrong-addr bug in Sun C;
+     adapt gdb to either SunOS 4.0.* or 4.1.
+   * MAX_OF_TYPE and MIN_OF_TYPE thinko.  By tedg@sun, I think.
+       * symtab.c:
+  Instantiate the class T when looking for methods in it.  (Tiemann@sun)
+
+       * valprint.c:
+  (type_print) Demangle the name being printed.
+  (type_print_base) Handle botched demangling without coredump (tiemann).
+
+       * values.c:
+  (check_stub_method):  Document routine.
+                       (tiemann) fix bug for no-arg functions
+                       Avoid clobbering beyond end of malloc'd storage.
+                       Terminate the argument list properly.
+
+Sat Aug 18 01:29:59 1990  Per Bothner (bothner@cs.wisc.edu)
+
+       * Changes merged by John Gilmore:
+    
+breakpoint.c:
+  In breakpoint_1, use new print_address_symbolic instead
+  of find_pc_partial_function. (This forces use of assembler-level
+  addresses, and avoids misleading non-mangled source-level names.)
+cplus-dem.c:
+  Generalize ansi argument such that -1 means skip arglist totally.
+  Removed global variable print_ansi_qualifiers (which made
+  code non-reentrant), in favor of extra explicit arguments
+  to internal routines.
+printcmd.c:
+  Add new helper function print_address_symbolic.
+  Use find_pc_misc_function instead of find_pc_partial_function
+  (since we want assembler-level symbols here).
+stack.c:
+  Print unknown function as just "f (...)", not "f (...) (...)".
+  Use new fputs_demangled explicitly.
+symtab.c:
+  Fixed a typing violation (problem: value.h cannot be imported
+  without renaming many variable in this file).
+  lookup_symbol: If no matching misc_func, look for a C++-mangled name.
+  decode_line_1: Moved forward some never-reached code.
+  Made decode_line_2 skip function prologues correctly.
+utils.c:
+  fputs_filtered should not demangle by default.
+  Add new fputs_demangled to demangle on demand..
+valops.c:
+  Change value_struct_elt to use value_primitive_field (using recursive
+  utility function search_struct_field). This allows foo.bar to work
+  for multiple inheritance (so far only for data fields).
+  Change check_field in the same way (recursive helper function
+  to support multiple inheritance).
+  (Note: there are more of these problems that I haven't fixed.
+  Any code that says TYPE_BASECLASS (t, 1) is probably wrong.)
+  value_of_this: 'this' symbol name is now just "this", note "$this".
+valprint.c:
+  Don't print static members.
+  Avoid printing "members of <type>" if there are none.
+  Simplified type_print_derivation_info by merging duplicate code.
+  Remove useless blank lines in type_print_base (ptype command).
+value.h:
+  Added declaration of new routine value_primitive_field.
+values.c:
+  Added value_primitive_field which is generalized version of
+  value_field that can handle multiple inheritance (non-zero offsets etc).
+  Re-implemented value_field to call value_primitive_field.
+
+Fri Aug 17 23:33:44 1990  John Gilmore  (gnu at cygint)
+
+       * infcmd.c -- insert else to avoid 'delete env' coredump when you
+       delete the whole environment.  Karl Berry reported the bug.
+       * source.c - fix openp to avoid //'s in filenames, which
+       trigger an Emacs bug causing it to not be able to find files
+       when running gdb in a window.
+       * dbxread.c - zap the #if 0 that botches the add-file code.
+       It seems to work a lot better without all the code commented out.
+
+Fri Jul 20 16:58:46 1990  John Gilmore  (gnu at cygnus.com)
+
+       * Merge Tiemann's and Ted Goldstein's changes, detailed below,
+       into gdb-3.90.9.
+
+Tue Jul 17 19:34:33 1990  Ted Goldstein  (tedg at golem)
+
+       * Makefile - added a ${CFLAGS} to a couple of entries,
+       added remote-sa.sparc.c
+       * added remote.sa-sparc.c, a modification of remote.c
+       which conducts a dialog directly with the SparcStation prom.
+       * breakpoint.c, infrun.c, sparcdep.c  added 
+       remote_insert_breakpoint(), and remote_remove_breakpoint() 
+       to breakpoint.c instead of directly writing breakpoint instructions.
+       * sparcdep.c on remote_debugging,there is no need 
+       to remove signle step breakpoint instructions.
+       * main.c added "-epoch" flag and "int epoch_interface" to main.c
+       global variable
+       * printcmd.c - epoch interface sends lisp expressions to open up
+       epoch windows on inspection.
+       * valprint.c - added arrayprint, and addressprint and made adding
+       format controls easier
+       * wait.h added a couple of undef's because we were getting
+       complaints about WSTOPSIG and WTERMSIG begin redefined.
+
+
+Wed Jul  4 05:27:51 1990  Michael Tiemann  (tiemann at masham)
+
+       * symtab.c (decode_line_1): Add support for handling method stubs
+       in the type information.
+
+Tue Jul  3 09:39:18 1990  Michael Tiemann  (tiemann at masham)
+
+       * values.c (baseclass_addr): Run loop from INDEX+1 to
+       N_BASECLASSES; otherwise, we can still get into a loop.
+       @@ This should be restructured to use a cleaner search strategy.
+
+Sun Jul  1 12:28:51 1990  Michael Tiemann  (tiemann at masham)
+
+       * dbxread.c (define_symbol,read_type): Grok GNU C++'s new
+       abbreviation "Tt" for tags which have the same name as their
+       typedecls.
+
+Fri Jun 29 01:03:46 1990  Michael Tiemann  (tiemann at masham)
+
+       * symtab.c (list_symbols): add ability to set breakpoints on all
+       the functions which match a particular regular expression.
+
+Tue Jun 26 04:26:29 1990  Michael Tiemann  (tiemann at masham)
+
+       * cplus-dem.c (cplus_demangle): New parameter ANSI says whether we
+       should print ANSI qualifiers (such as `const' and `volatile').
+       All callers changed to call with ANSI == 1, except from
+       `check_method_stub', which uses old-style syntax.
+
+       * symseg.h (struct fn_field): Remove unneccessary `args' field.
+       * symtab.h (TYPE_FN_FIELD_ARGS): Redefined.
+
+       * values.c (check_stub_method): New function.
+
+       * cplus-dem.c (do_type): Handle "long long" (encoded as 'x').
+
+       * dbxread.c (read_type): Handle new GNU C++ method type stubs.
+       * valprint (type_print_base): Ditto.
+
+       * symtab.c (gdb_mangle_typename): New function.
+
+Tue Jun  5 00:18:43 1990  Michael Tiemann  (tiemann at gzilla)
+
+       * breakpoint.c (catch_command): New function.  Provides a
+       mechanism to set breakpoints based on catch clauses.
+       (disable_catch): Similar, but disables breakpoints on catch
+       clauses.
+       (delete_catch): Similar, but deleted breakpoints on catch clauses.
+
+Sun Jun  3 22:54:08 1990  Michael Tiemann  (tiemann at gzilla)
+
+       * blockframe.c (blockvector_for_pc): New function.
+       * blockframe.c (block_for_pc): Changed to call
+       `blockvector_for_pc' and get the block itself.
+
+       * stack.c (catch_info): New function.  Prints info about
+       exceptions which can be caught in the current frame.
+       * stack.c (print_frame_label_vars): New function.  Similar to
+       `print_frame_local_vars'.
+       * stack.c (print_block_frame_labels): Prints out labels that are
+       defined in this frame.  These labels are exceptions that can be
+       caught.
+
+       * dbxread.c: Updated to handle N_CATCH symtab types.
+
+Thu May  3 22:10:00 1990  Michael Tiemann  (tiemann at teacake)
+
+       * valprint.c (everywhere): TYPE_NAME (TYPE) no longer comes in the
+       form "struct ..." for GNU C++.  Don't flush any part of TYPE_NAME
+       when printing the type.
+
+Wed May  2 22:43:04 1990  Michael Tiemann  (tiemann at teacake)
+
+       * valprint.c (val_print): Use `baseclass_addr' to access the
+       baseclasses pointed to via the derived class object at VALADDR.
+
+       * values.c (baseclass_addr): New function.  Casts derived pointers
+       to baseclass pointers taking virtual baseclasses and multiple
+       inheritance into account.
+
+Sat May  5 12:39:18 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * Version 3.90.9.
+
+Fri May  4 12:12:55 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * breakpoint.c (watch_command, bpstat_stop_status): Deal with
+       exp_valid_block field correctly.
+
+       * infrun.c (wait_for_inferior): When checking "don't even think
+       about breakpoints" if stop_signal == SIGTRAP && trap_expected,
+       also check step_resume_breakpoint.
+       Insert breakpoints and continue (not step) if
+       step_resume_break_address != NULL, even if another_trap.
+       If trap_expected and we enter sigtramp, then set up a
+       step_resume_break.
+       If trap_expected is set when we hit the step_resume_break,
+       set another_trap.
+       When calling resume and trap_expected says tell resume to step
+       (2 places), also check step_resume_break_address.
+
+       * infrun.c (wait_for_inferior): Don't set
+       prev_{pc,sp,func_{start,name}} before calling wait ().
+       Do set them after exiting loop.
+       Move their declarations outside functions.
+       (start_inferior): Initialize them.
+
+Thu May  3 00:15:11 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * infrun.c (wait_for_inferior, after check for trap_expected > 1):
+       Restore old code which distinguishes between trap_expected and
+       running_in_shell, just make the latter take any non-TRAP signal,
+       not just SEGV.
+
+       * values.c (allocate_value): Zero VALUE_OPTIMIZED_OUT flag.
+
+       * Makefile.dist (pinsn.o): Use PINSN_CC to compile.
+       xconfig/3b1 (CC,PINSN_CC): Define.
+
+       * xconfig/altos, altos-dep.c: Rename altos-dep.c to altos-xdep.c.
+
+       * Version 3.90.8
+
+       * breakpoint.c (bpstat_stop_status),
+       infrun.c (wait_for_inferior) [SHIFT_INST_REGS]: New code.
+
+       * param.h, tm-88k.h: Define ADDR_BITS_*.
+       infcmd.c (jump_command, read_pc), infrun.c (wait_for_inferior),
+       printcmd.c (do_one_display): Use them.
+
+       * utils.c: Split #ifdef USG into a USG_UTILS and a QUEUE_MISSING.
+       xm-88k.h: Define USG_UTILS.
+
+Wed May  2 00:05:33 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * printcmd.c (printf_command) [__INT_VARARGS_H]: New code.
+       (printf_command): Add from_tty parameter.
+
+       * valprint.c (value_print): Check VALUE_OPTIMIZED_OUT flag.
+
+       * value.h: Add optimized_out field and change lazy field to
+       char.  Add macro VALUE_OPTIMIZED_OUT.
+
+       * i386-pinsn.c: Change from Eirik Fuller to write to stream directly
+       instead of stuffing things in buffers (oappend, etc).
+
+       * breakpoint.c (bpstat_do_actions): If *BSP is set to NULL by
+       execute_command, exit both loops.
+
+       * Makefile.dist: Don't set TARGET_ARCH.  Add .c.o rule.
+
+Tue May  1 17:07:23 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * Makefile.dist (RAPP_OBS, rapp),
+       rgdb.c, rserial.c, rudp.c, serial.c, udp.c, xdep.h,
+       remote.h: Added.
+       m68k-xdep.c, coredep.c: Wrap in #if !defined (RDB).
+
+       * valops.c (value_struct_elt), values.c (value_static_field):
+       Change error messages to remove references to `info methods'.
+
+Tue Apr 24 10:25:10 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * More 88k changes:
+       infrun.c (start_inferior): Add START_INFERIOR_HOOK.
+       infcmd.c [SHIFT_INST_REGS]: New code.
+       findvar.c (read_relative_register_raw_bytes): Return a value.
+       infcmd.c (do_registers_info): Check value from
+       read_relative_register_raw_bytes.
+
+       * command.c (delete_cmd): Free the struct cmd_list_element(s)
+       we are removing.
+
+Mon Apr 23 10:42:21 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * More 88k changes:
+       findvar.c (get_saved_register): New function.
+       findvar.c: Rewrite code which called find_saved_register to
+       call get_saved_register instead.
+
+Sun Apr 22 14:47:51 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * valprint.c (val_print): Change error message printed when
+       the type has TYPE_FLAG_STUB set.
+
+       * valprint.c (val_print): Check for TYPE_CODE_UNDEF.
+
+       * findvar.c (write_register): Set register_valid (regno).
+
+       * valops.c (call_function): Check for NULL return from block_for_pc.
+
+Fri Apr 20 11:31:23 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * findvar.c (write_register): Add PREPARE_TO_STORE.
+       {sun3,sparc,symmetry}-xdep.c (PREPARE_TO_STORE): Add.
+       infptrace.c, {mips,pyr,symmetry,sun3,arm,hp300hpux}-xdep.c
+       (store_inferior_registers): Don't call read_register_bytes.
+       symmetry-xdep.c (store_inferior_registers):
+       #if 0 out code to fetch registers.
+
+       * values.c (value_as_long): Call COERCE_ARRAY.
+
+       * tm-sun3.h: Include tm-68k.h not m-68k.h
+
+       * sparc-tdep.c (single_step): Set next_pc, npc4 within
+       if (!one_stepped), not outside it.
+
+       * Changes from Data General for 88k:
+       * coffread.c (read_file_hdr): Add *88*MAGIC.
+       * coffread.c (have_symbol_file_p): New function.
+       * coffread.c [COFF_CHECK_X_ZEROES] [TDESC]: New code.
+       * coffread.c (read_one_sym): If there is more than one
+       aux entry, don't give an error message, just ignore the
+       extra ones.
+       * coffread.c (process_coff_symbol): Replace clipper with
+       BELIEVE_PCC_PROMOTION in #ifdef's.
+       * coffread.c: Define L_LNNO32 if not defined.
+       (enter_linenos): Use it.
+       * blockframe.c: Add INIT_FRAME_PC hook and use it in
+       get_prev_frame_info.
+       m-m88k.h: Use INIT_{FRAME_PC,EXTRA_FRAME_INFO} to do tdesc stuff.
+       Use dummy versions of FRAME_CHAIN_*.
+       * Makefile.dist, xconfig/i386*: Rename M_CLIBS to XM_CLIBS and add
+       TM_CLIBS and CDEPS.
+       tdesc/libdc.o: New target.
+       tdesc.{c,h}, tdesc/*, {t,x}config/m88k: New files.
+
+Thu Apr 12 15:47:00 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * m68k-opcode.h (bras, bsrs): Use "Bw" not "Bg".
+
+Tue Apr 10 20:50:25 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * Version 3.90.7.
+
+       * xm-mips.h (BYTE_ORDER): If not defined, make it LITTLE_ENDIAN.
+
+       * mips-xdep.c ({fetch,store}_inferior_registers): Remove variable
+       offset and just use register_addr (regno, 1).
+       (core_file_command): Remove variable reg_offset and just use
+       register_addr (regno, 0).
+
+       * gdbcore.h [COFF_FORMAT]: #undef a_magic before redefining it.
+
+       * infrun.c ("if (trap_expected && stop_signal != SIGTRAP)", near end
+       of wait_for_inferior): Always pass 0 as first arg to resume.
+       #if 0 out "SIGSEGV in shell" test right above it (now redundant).
+
+       * i386-pinsn.c (oappend_address): New function.
+       (oappend): Make it "static void" and declare at top of file.
+       (OP_J, OP_DIR): Use oappend_address.
+
+Mon Apr  9 15:22:09 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * mips-xdep.c: Include <mips/inst.h> not "mips/inst.h".
+
+       * wait.h [HAVE_WAIT_STRUCT]: Put #defines in #if !defined so that
+       it's OK if they are defined in <sys/wait.h>.
+
+       * findvar.c (fetch_registers): Pass "registers", not "&registers",
+       to remote_fetch_registers.
+
+       * mips-tdep.c (_initialize_mipsdep): Remove hex_disassembler
+       and re-write skip_prologue to use add_set_cmd.
+
+       * Makefile.dist (alldeps.mak): Don't put \ after the last
+       filename in each list.
+
+Sun Apr  8 01:59:19 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * Version 3.90.6.
+
+       * Makefile.dist (alldeps.mak): "XM_FILE" -> "XM_FILE=".
+
+       * valarith.c (value_x_{un,bin}op): use "operator" not "operator "
+       to match dbxread.c change of 16 Mar 90.
+
+       * valarith.c (value_x_unop): Pass &static_memfuncp,
+       not static_memfuncp.
+
+       * breakpoint.c: Add watchpoint stuff.
+       breakpoint.h: Add bpstat_should_step.
+       infrun.c (proceed, wait_for_inferior): Use it.
+       breakpoint.h: Add bpstat_print (and rename old bpstat_print
+       to bpstat_should_print).
+       infrun.c (normal_stop): Use it.
+
+       * value.h: Add value_free.  Declare a few functions.
+
+Sat Apr  7 21:43:43 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * dbxread.c (read_dbx_symtab): Remove PROFILE_TYPES code and
+       insert comment suggesting easy shell script equivalents.
+
+       * values.c (unpack_long): Give better error messages for
+       unrecognized sizes of ints and floats.
+
+Fri Apr  6 00:32:21 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * dbxread.c, gdbcore.h (IS_OBJECT_FILE): Check for a_drsize
+       nonzero as well as a_trsize.
+
+       * More places: Use SWAP_TARGET_AND_HOST.
+
+       * valops.c (destructor_name_p): Only skip "struct " if present.
+
+       * main.c (gdb_readline): Return NULL on end of file.
+
+       * sparc-opcode.h: Add jmp 1+2, jmp 1+i, jmp i+1.
+
+       * Makefile.dist: Make expread.tab.c unambiguously be in srcdir.
+
+       * main.c: Split source_command into source_command and
+       read_command_file.
+       (main): Accept "-" as arg to +command for stdin.
+
+       * dbxread.c (psymtab_to_symtab): Don't read string table.
+       (symbol_file_command): Save string table size.
+
+       * Version 3.90.5
+
+       * symtab.c: Remove declaration of lookup_misc_func.
+
+       * mips-pinsn.c: Add use_hex_p stuff (re-worked from Forin stuff).
+
+       * mips-opcode.h: Add bdelay field.
+       mips-pinsn.c: Various changes from Forin, I think to make it look
+       like the MIPS assembler format.
+       mips-tdep.c, mips-xdep.c, mipsread.c: Various changes from Forin.
+
+       * gdbcore.h: Declare register_addr.
+
+       * gdbcore.h: Include <a.out.h>, before trying to redefine N_TXTADDR
+       and friends.
+       various: Don't include both a.out.h and gdbcore.h.
+
+       * Makefile.dist (HFILES): Add param.h
+
+       * utils.c (init_malloc): Moved here from mcheck.c and modified
+       to use the standard mcheck.c
+       Makefile.dist: Modify to reflect new mcheck.
+
+Thu Apr  5 16:38:28 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * valprint.c (val_print, print_hex_chars): Print integers
+       larger than LONGEST.
+
+       * valarith.c (value_sub): Give error message if attempt to
+       subtract something of the wrong type from a pointer.
+
+       * breakpoint.c (bpstat_stop_status): Initialize retval to NULL.
+
+       * i386-tdep.c (i386_pop_frame): Change addr to adr.
+
+Wed Apr  4 05:21:50 1990  Jim Kingdon  (kingdon at teenage-mutant)
+
+       * main.c (command_line_input): return NULL on end of file.
+       (execute_command): If p is NULL, return almost right away.
+       (read_command_lines): Treat end of file like "end".
+
+       * printcmd.c (print_frame_args): Change it so num is number
+       of ints of args, not number of args.
+
+       * xm-*.h: Make sure BYTE_ORDER is defined.
+       Also fix various #includes of old names of things.
+
+       * main.c (command_line_input): Fix comment code of 2 Apr.
+
+       * values.c (value_from_long, unpack_long): SWAP_TARGET_AND_HOST.
+       various: Replace {BYTES,WORDS}_BIG_ENDIAN with TARGET_BYTE_ORDER.
+       valarith.c various: SWAP_TARGET_AND_HOST.
+       dbxread.c (READ_FILE_HEADERS): SWAP_TARGET_AND_HOST.
+       (SWAP_SYMBOL): New macro.  Use it wherever symbuf_idx is incremented.
+       exec.c (exec_file_command): SWAP_TARGET_AND_HOST.
+
+       * valarith.c (value_subscripted_rvalue): Just bcopy() the
+       appropriate bytes rather than playing strange games with
+       value_from_long.
+
+       * param.h (SWAP_TARGET_AND_HOST): New macro.
+
+       * tm-np1.h (V7_REGNUM): Change from 27 to 26.
+       (REGISTER_VIRTUAL_TYPE): Return correct result for vector regs.
+       gould-tdep.c: New file.
+
+       * Move reading of register before store from
+       findvar.c (write_register) to
+       infptrace.c, *-xdep.c (store_inferior_register).
+
+       * findvar.c (fetch_registers, store_registers): New functions.
+       write_register{,_bytes}: Use store_registers regardless of
+       have_inferior_p.
+       registers_valid: New variable.
+       (supply_register, read_register, etc.): Use it.
+       (read_register_gen): New variable.
+       various: Use read_register_gen rather than read_register_bytes
+       where appropriate.
+       *-xdep.c (fetch_inferior_registers): Remove remote_debugging check.
+       infrun.c (wait_for_inferior, start_inferior): Call registers_changed
+       not fetch_inferior_registers.
+       *-xdep.c (fetch_inferior_registers): Call registers_fetched if
+       not setting registers via supply_register, and if fetching
+       all registers.
+       infptrace.c, *-xdep.c (fetch_inferior_registers): Add param,
+       # of register to fetch (-1 for all).
+       infptrace.c, hp300hpux-xdep.c (fetch_inferior_registers):
+       Actually fetch only those registers needed.
+       value.h: Declare all the extern register functions from findvar.c.
+
+       * coffread.c (read_coff_symtab): Test for specific kinds of GCC
+       labels (LI%.*, LPB%.*, etc), not just ??%.*.
+
+       * coffread.c (record_misc_function): Use mf_text not mf_unknown.
+
+       * utils.c,defs.h (lines_to_list): New function.
+       source.c (select_source_symtab, list_command, forward_search_command,
+       reverse_search_command), stack.c (print_frame_info):
+       Use it instead of 10.
+
+       * munch: If MUNCH_NM variable exists, use it.
+
+       * main.c (initialize_main): Set rl_readline_name.
+       main.c: #include readline.h and #undef savestring.
+       Remove declarations of things declared in readline.h.
+
+       * main.c (gdb_readline): If instream == 0, read from stdin.
+
+       * main.c (main): Only call clearerr if ISATTY.  Exit loop if
+       feof (instream).
+
+       * infcmd.c (detach_command): Set inferior_pid to 0 after
+       calling remote_close.
+
+       * main.c (main): If exec and sym files are the same, and there
+       is an error reading execfile, don't try to read sym file.
+
+       * infcmd.c (detach_command) [ATTACH_DETACH]: Don't try to detach
+       from inferior when remote debugging.
+
+       * source.c (reverse_search_command): Change while test from 1 to
+       line > 1.
+
+Tue Apr  3 18:14:14 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * Version 3.90.4.
+
+       * Makefile.dist (gdb.tar.Z): Use -z option to tar rather than
+       creating gdb.tar and calling compress separately.
+
+       * breakpoint.c (read_memory_nobpt): Do not treat bcopy as if it
+       returned an "errno" value.
+
+       * various: Make sure gdbcore.h is not included before a.out.h.
+
+       * Makefile.dist (OPCODES): Add mips-opcode.h.
+
+       * config.gdb: Print lists of {hosts,targets} after finding srcdir.
+       When parsing +{host,target}=, strip off +{host,target}=, not +{x,t}m=.
+
+       * Makefile.dist (gdb.tar): Do {t,x}config not just config.
+
+Mon Apr  2 02:42:23 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * sparc-opcode.h (inc): Fix incorrect lose field.
+
+       * valarith.c (value_subscripted_rvalue): Use TARGET_BYTE_ORDER,
+       rather than checking endianness at runtime.
+
+       * main.c (comand_line_input): Accept comments anywhere, not
+       just at starts of lines.
+
+Sat Mar 31 21:59:35 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * symtab.c (check_stub_type): Call lookup_symbol with 5 args.
+
+Fri Mar 30 15:23:52 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * frame.h: #include param.h.
+       param.h: Protect against multiple inclusion.
+
+       * i386-tdep.c (i386_get_frame_setup): Fix comment about what
+       opcode 0x55 is.
+       If 0x81 or 0x83 is followed by something besides 0xec,
+       put codestream back where it was and return 0.
+       [USE_MACHINE_REG_H]: Include <machine/reg.h> not <sys/reg.h>
+       Move include of a.out.h above <sys/user.h>.
+       (i386_frame_find_saved_regs): Make locals signed.
+       (i386_frame_find_saved_regs, i386_push_dummy_frame, i386_pop_frame):
+       Use REGISTER_BYTES, REGISTER_RAW_SIZE, etc. to deal with floating
+       point registers.
+
+Wed Mar 28 18:33:40 1990  Jim Kingdon  (kingdon at mole.ai.mit.edu)
+
+       * Makefile.dist (OTHERS): Add gdb.dvi.
+       (gdb.dvi): New rule.
+
+       * breakpoint.c (_initialize_breakpoint): Clean up docstrings so
+       as not to mention subcommands (e.g. auto-display).
+       Call add_cmd not add_abbrev_cmd for "disable breakpoint" and
+       put it in class_alias.
+
+       * breakpoint.c (set_breakpoint_count): New function.
+       (set_breakpoint, break_command_1): Use it.
+
+       * breakpoint.c (get_number): New function.
+       (*_command, map_breakpoint_numbers): Use it.
+
+       * infptrace.c (write_inferior_memory): Remove remote_debugging
+       stuff (is handled in core.c).
+       (read_inferior_memory): Remove #if 0'd out remote_debugging code.
+
+Tue Mar 27 16:51:27 1990  Jim Kingdon  (kingdon at mole.ai.mit.edu)
+
+       * inferior.h: Include frame.h.
+
+       * findvar.c (write_register): Replace sun4 #ifdef with
+       check of CANNOT_STORE_REGISTER.
+       xm-sparc.h: Define CANNOT_STORE_REGISTER.
+
+       * sparc-tdep.c: Remove superfluous declaration of
+       get_breakpoint_commands.
+
+       * breakpoint.{c,h}: Add bpstat stuff.
+       bpstat_do_action: Re-work do_breakpoint_commands into this.
+       main.c (command_loop): Call bpstat_do_action not
+       do_breakpoint_commands.
+       inferior.h, infrun.c, breakpoint.c, infcmd.c:
+       Rework breakpoint_commands and stop_breakpoint
+       stuff to use bpstat instead.
+
+       * infcmd.c (program_info): "info reg"->"info registers".
+
+       * np1-opcode.h: Renamed from npl-opcode.h.
+       gould-pinsn.c: Include np1-opcode.h.
+       Makefile.dist (OPCODES): Change npl-opcode.h to np1-opcode.h
+
+       * coffread.c (read_enum_type): Stop reading when we hit .eos.
+
+Mon Mar 26 15:52:35 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * Version 3.90.3.
+
+       * breakpoint.c (read_memory_nobpt): New function.
+       gdbcore.h: Declare read_memory_{nobpt,check}.
+       mips-tdep.c: Use read_memory_nobpt not breakpoint_shadow_val.
+
+Fri Mar 23 14:26:38 1990  Jim Kingdon  (kingdon at mole.ai.mit.edu)
+
+       * inflow.c (terminal_inferior): Reenable commented out
+       inferior_thisrun_terminal check.
+       (terminal_ours_1): If inferior_thisrun_terminal is nonzero,
+       return immediately.
+
+       * Makefile.dist: Rewrite DEPFILES, M_FILE, etc. stuff to deal
+       with host & target separation.
+
+       * config/*: Split into xconfig/* and tconfig/*.
+       *-dep.c: Split into *-xdep.c and *-tdep.c.
+
+       * main.c (main): Always pass two args to xrealloc.
+
+Thu Mar 22 20:29:25 1990  Jim Kingdon  (kingdon at mole.ai.mit.edu)
+
+       * Makefile.dist ({,dist}clean): rm {x,t}m.h not param.h
+       xgdb.o: Remove obsolete dependency (now in depend).
+
+       * arm-pinsn.c: Include arm-opcode.h not opcode.h.
+
+       * mips-pinsn.c, mips-opcode.h: New files from Bothner (from
+       release of 24 Jan 90 with mips-opcode.h patch from 1 Feb 90).
+
+       * utils.c (xmalloc): Return NULL on request for 0 bytes.
+
+Wed Mar 21 13:30:08 1990  Jim Kingdon  (kingdon at mole.ai.mit.edu)
+
+       * config.gdb: Re-write machine stuff to deal with host & target.
+
+       * xm-altos.h: Don't define HAVE_WAIT_STRUCT.
+
+       * m-*.h: Split into xm-*.h and tm-*.h.
+
+       * infrun.c (wait_for_inferior): Put #ifdef sony_news code
+       in regardless of machine.
+
+       * symtab.c (decode_line_1): Add quotes and capitalize error
+       message "no class, struct, or union named".
+
+       * Makefile.dist (cplus-dem.o): Compile with -Dnounderscore.
+
+       * stack.c (print_frame_info): Use print_symbol to print function name.
+
+       * symtab.c (output_source_filename): Don't print a comma if
+       we are skipping a filename already printed.
+
+Tue Mar 20 10:48:54 1990  Jim Kingdon  (kingdon at mole.ai.mit.edu)
+
+       * symtab.c (output_source_filename): Don't print a filename
+       more than once.
+
+       * utils.c (fprint_symbol): New function.
+       defs.h: Decalare it.
+       various: Use fprint_symbol to print symbol names.
+       Makefile.dist (SFILES, OBS): Add cplus-dem.{c,o}.
+
+Mon Mar 19 17:11:03 1990  Jim Kingdon  (kingdon at mole.ai.mit.edu)
+
+       * coffread.c (read_file_hdr): Add MC68K??MAGIC.
+
+       * coffread.c (read_coff_symtab): Ignore swbeg and string label
+       symbols.
+
+       * coffread.c (read_coff_symtab): Increment num_object_files
+       in case C_STAT not C_FILE.
+       New variable in_source_file.  Set it in case C_FILE.
+       Check it in case C_STAT.
+
+       * coffread.c [FUNCTION_EPILOGUE_SIZE]: New code.
+       m-umax.h (FUNCTION_EPILOGUE_SIZE): Define.
+
+       * config/3b1: New file.
+
+       * config/sun*: Print message warning people to use GAS with GCC.
+
+Sun Mar 18 02:56:40 1990  Jim Kingdon  (kingdon at mole.ai.mit.edu)
+
+       * infcmd.c (run_stack_dummy): Change error message.
+
+       * m-68k.h (REGISTER_VIRTUAL_TYPE): Make pc, fp, sp char *.
+
+       * m-mips.h (LONGEST, BUILTIN_TYPE_LONGEST): Remove.
+
+Sat Mar 17 21:27:49 1990  Jim Kingdon  (kingdon at mole.ai.mit.edu)
+
+       * mips-dep.c: Remove infptrace.c stuff.
+
+       * m-bigmips.h: New file.
+       m-mips.h [MIPSEB]: Remove *_BIG_ENDIAN stuff.
+
+       * m-sparc.h (FIX_CALL_DUMMY): Do not insert unimp instruction
+       if function was compiled with gcc.
+
+       * m-mips.h: Remove FIX_CALL_DUMMY_ALIGNED and make FIX_CALL_DUMMY
+       use new args.
+
+       * valops.c (call_function): New args to FIX_CALL_DUMMY.
+       m-*.h (FIX_CALL_DUMMY): Take new args.
+
+       * values.c (using_struct_return): New parameter gcc_p.
+       valops.c (call_function): New variable using_gcc.
+       valops.c (call_function) [REG_STRUCT_HAS_ADDR]: New code.
+
+       * m-mips.h, mips-dep.c: New files from Forin.
+       m-mips.h: Replace RETURN_STRUCT_BY_REF with USE_STRUCT_CONVENTION.
+
+Fri Mar 16 13:17:19 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * Makefile.dist: Add some dependencies of m-*.h files.
+       (HFILES): Add m-68k.h.
+
+       * dbxread.c (read_struct_type): Put "operator+" not "operator +"
+       in symtab.
+
+       * core.c: Split read_memory into read_memory_check and read_memory.
+       breakpoint.c (insert_breakpoints): If can't read memory,
+       tell user that error was due to seting breakpoints.
+
+Thu Mar 15 11:47:19 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * infrun.c [COFF_ENCAPSULATE]: Include a.out.encap.h.
+
+       * blockframe.c (FRAMELESS_LOOK_FOR_PROLOGUE): Make it a function.
+       various m-*.h: Call function not macro.
+       frame.h: Declare the function.
+
+Wed Mar 14 02:44:51 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * sparc-dep.c: Include signame.h.
+
+       * sparc-pinsn.c (print_insn): When looking for sethi before
+       delayed branch, call read_memory_noerr not read_memory.
+
+       * m-isi.h, m-sun3.h, m-news.h, m-hp300bsd.h, m-altos.h,
+       m-hp300hpux.h, m-sun2.h: Merge machine stuff except inferior
+       function call stuff into new file m-68k.h.  Create m-3b1.h.
+
+Tue Mar 13 21:34:33 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * inflow.c (new_tty): If can't open tty, print error message
+       before exiting.
+
+       * blockframe.c: Remove declaration of psymtab_to_symtab.
+       symtab.h: Declare psymtab_to_symtab.
+       blockframe.c: Remove declarations of block_for_pc and
+       find_pc_function_start.
+       frame.h: Add declarations of block_for_pc and find_pc_function_start.
+       Remove declaration of nonexistent function find_pc_function.
+       values.c: include frame.h instead of declaring block_for_pc.
+
+       * Version 3.90.2.
+
+Mon Mar 12 14:20:06 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * main.c (main): Delete superfluous "e" from long_options.
+
+Sat Mar 10 15:47:23 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * valprint.c (val_print): Print <%d bit integer> not just
+       <large integer>.
+
+       * dbxread.c (error_type): Fix loop that finds '\0' so that on
+       exit, *pp points to the '\0', not the character after.
+       (read_type): Make sure that places which call read_type and then
+       try to read more input stop immediately with another error
+       upon encountering '\0'.
+
+       * dbxread.c (read_range_type): Fix check for large signed
+       integral type to match comment and reality.  Set TYPE_LENGTH based
+       on n2bits for signed, n3bits for unsigned.
+
+       * infcmd.c (cont_command): Print warning message if we
+       decide to ignore the argument.
+
+       * gdb.texinfo (attach): @xref{Attach} -> @xref{Remote}.
+
+Fri Mar  9 16:26:47 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * symtab.h (address_class): Reinstate LOC_EXTERNAL with rewritten
+       comment.
+
+       * expread.y (yyerror, parse_c_1): Make yyerror take a char * arg.
+
+       * main.c (symbol_completion_function): Don't call error() on
+       "info jkldskf".
+
+       * m-npl.h (USE_STRUCT_CONVENTION): Change >= to >.
+
+Thu Mar  8 00:19:01 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * symseg.h: Nuke more symseg references including LOC_EXTERNAL.
+       Put contents of symseg.h into symtab.h and remove symseg.h.
+
+Wed Mar  7 18:02:15 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * symtab.h (SYMBOL_LINE): New macro.
+       symtab.c (decode_line_1): Accept variable as well as function.
+       Lookup variable/function in selected block if no file specified.
+       printcmd.c: #if 0 out whereis_command.
+
+       * command.c (do_setshow_command): Call function with additional
+       argument C.
+       main.c (set_history_size_command): Take argument C.
+       (set_verbose): New function to set docstring.
+       (initialize_main): Put set_verbose in command list.
+       command.c (lookup_cmd_1): Accept result_list NULL.
+
+       * valprint.c (_initialize_valprint): Change docstring for
+       "set unionprint" to normal set/show form.
+
+       * command.c (add_show_from_set): Check that docstring starts with
+       "Set " before assuming it does.
+
+       * main.c (show_history): Call cmd_show_list.
+       command.{c,h} (cmd_show_list): New function.
+       command.h: Declare do_setshow_command.
+
+       * command.h (cmd_list_element): New field completer.
+       main.c (symbol_completion_function): Use it.
+       symtab.h: Declare make_symbol_completion_list.
+       command.c (add_cmd): Set completer.
+       main.c, gdbcmd.h (noop_completer): New function.
+       infcmd.c: Set completer for environment functions.
+
+       * symtab.c (types_info, _initialize_symtab): #if 0 out.
+       various: Use fputs_filtered, not fprintf_filtered(%s).
+
+       * valprint.c (type_print_base): Check for integers larger than
+       LONGEST.
+
+       * sun3-dep.c: Include "signame.h" instead of directly declaring
+       sys_siglist.
+
+Tue Mar  6 14:59:34 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * infrun.c (signals_info): Allow argument to be a signal name
+       as well as an expression.
+       (handle_command): Check for error from sig_number.
+
+       * main.c (float_handler): Change error message.
+
+       * inflow.c (create_inferior): If getenv ("SHELL") exists, use it
+       instead of /bin/sh.
+
+       * dbxread.c (read_dbx_symtab, case N_SO): New variable first_symnum.
+       Pass it to {start,end}_psymtab.
+
+       * dbxread.c (read_ofile_symtab): Increment symbuf_idx and symnum
+       when calling process_symbol_pair.
+
+       * symtab.c (sources_info, output_source_filename):
+       Re-write so output_source_filename takes a first parameter
+       instead of a next one.
+
+       * dbxread.c (read_dbx_symtab, case N_SO): When incrementing
+       symbuf_idx, increment symnum also.
+
+       * values.c (set_internalvar_component): Use VALUE_CONTENTS,
+       not VALUE_CONTENTS_RAW.
+
+       * symmisc.c (free_symtab): Don't free filename (now in symbol_obstack).
+
+       * environ.c (init_environ): Copy entire string, including
+       terminating '\0'.
+
+       * value.h, values.c: Rename value_lazy to value_fetch_lazy.
+       values.c (value_of_internalvar): Call value_fetch_lazy.
+
+       * dbxread.c (read_huge_number): Return an error on encountering
+       a large decimal number.
+
+       * dbxread.c (read_huge_number): Reverse sense of overflow test.
+
+       * valprint.c (val_print, case TYPE_CODE_INT): Check for integers
+       larger than LONGEST.
+
+       * dbxread.c (read_ofile_symtab): When calling process_one_symbol,
+       call it with desc and value rather than with bufp->n_{desc,value}.
+
+       * defs.h (LONG_MAX): Define.
+
+       * sun3-dep.c: Declare sys_siglist.
+
+       * infptrace.c: Move include of gdbcore.h after a.out.h
+
+       * Makefile.dist (expread.o, mcheck.o): Remove leading "./" not
+       leading ".".
+
+       * m-hp300hpux.h [!HPUX_VERSION_5]: Define KERNEL_U_ADDR_HPUX.
+       infptrace.c [KERNEL_U_ADDR_HPUX] [KERNEL_U_ADDR_BSD]:
+       Set kernel_u_addr using nlist().
+       m-hp300bsd.h: Define KERNEL_U_ADDR_BSD.
+
+Mon Mar  5 16:52:41 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * dbxread.c (read_dbx_symtab): If value of .o symbol is crazy,
+       don't end psymtab.
+
+       * dbxread.c (read_dbx_symtab): Ignore first of a pair of N_SO
+       when both appear.
+       (start_subfile, start_symtab): Extra parameter dirname.
+       (start_subfile): Use obsavestring, not savestring, for name.
+       various: Call start_{subfile,symtab} with extra argument.
+       (end_symtab): Set dirname field in symtab.
+       (read_ofile_symtab): Call process_symbol_pair on pair of N_SO.
+       (process_symbol_pair): New function.
+       symtab.h (symtab): New field dirname.
+       source.c (open_source_file): New function.
+       source.c: Use open_source_file instead of openp where appropriate.
+
+       * defs.h (TARGET_CHAR_BIT): Define.
+
+Sun Mar  4 13:11:48 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * dbxread.c (fill_symbuf): Print error messages nicely.
+
+       * Makefile.dist (SFILES): Put standalone.c at end.
+
+       * Makefile.dist (alldeps.mak): Put out backslash after arm-convert.s.
+
+       * symtab.{c,h} (builtin_type_error): New type.
+       symseg.h (type_code): Add TYPE_CODE_ERROR.
+       valprint.c (val_print, type_print_base),
+       values.c (using_struct_return, set_return_value):
+       Check for and deal with TYPE_CODE_ERROR.
+       dbxread.c (error_type): New function
+       (read_type and subroutines): Call error_type instead of error.
+
+       * dbxread.c (read_huge_number): New function.
+       (read_range_type): Use read_huge_number and check results
+       to see if it is a large integral type.
+
+       * symmisc.c: Remove symseg stuff.
+
+       * Gould NP1 changes from (or inspired by) chpmjd@gdr.bath.ac.uk
+       dbxread.c (read_dbx_symtab) [N_NBSTS]:
+       Treat this and N_NBLCS like N_LCSYM, etc.
+       (process_one_symbol) [BLOCK_ADDRESS_ABSOLUTE]: New code.
+       m-npl.h (USE_STRUCT_CONVENTION): Add.
+       (IGNORE_SYMBOL): Add 0xa4.
+       (END_OF_TEXT_DEFAULT): Remove.
+       (STRING_TABLE_OFFSET): don't add sizeof(int).
+       [!HAVE_VPRINTF]: Define vprintf to be doprnt, not printf.
+       (BLOCK_ADDRESS_ABSOLUTE): Define.
+       (BREAKPOINT): Pad to size of machine word.
+       (SAVED_PC_AFTER_CALL): Remove ` at start of line (!).
+       (R2_REGNUM): Define.
+       (SP_REGNUM, FP_REGNUM): Switch definitions.
+       (REGISTER_U_ADDR): Use FP_REGNUM in place of SP_REGNUM.
+       (STORE_STRUCT_RETURN, EXTACT_RETURN_VALUE, STORE_RETURN_VALUE,
+       call function stuff):
+       Replace bogus definitions with correct ones for NP1.
+       (CANNOT_EXECUTE_STACK): Define.
+       (FRAME_LOCALS_ADDRESS): Don't add 80.
+       (FRAME_FIND_SAVED_REGS): Also get SP.
+       gould-pinsn.c (findframe): Move framechain declaration outside #if 0.
+       infptrace.c (write_inferior_memory): Check addr against text_end
+       and use PT_WRITE_I or PT_WRITE_D as appropriate.
+       (store_inferior_registers): Don't try to write registers in
+       CANNOT_STORE_REGISTER.
+       m-npl.h (CANNOT_STORE_REGISTER): Define.
+       npl-opcode.h (lil): 0xf8080000 -> 0xf80b0000.
+       
+       * munch: Distinguish between BSD and System V nm by actually
+       seeing what output from nm looks like.
+
+Fri Mar  2 13:43:36 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * printcmd.c (print_frame_args): Change highest_offset to point
+       to next unprinted arg.
+
+       * main.c (main): Print "type help for list of commands" along
+       with the version.  Follow it with a blank line.
+
+Thu Mar  1 14:49:26 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * valprint.c: Move print_address for function from value_print
+       to val_print.
+
+Wed Feb 28 15:06:12 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * Makefile.dist (m-sun4os4.h): Depend on m-sparc.h
+
+       * Makefile.dist (version.c): Depend on Makefile.dist, not Makefile.
+
+       * Makefile.dist: Change MAKEFILES to Makefiles.
+
+       * symtab.h: Declare get_sym_file.
+       core.c: Include symtab.h.
+
+       * Move signal name stuff from utils.c to signame.c
+       Move signal name stuff from defs.h to signame.h.
+       Makefile.dist (SFILES, HFILES, OBS): Add signame.{c,h,o}.
+
+Mon Feb 26 12:03:12 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * command.c (add_cmd): Don't call savestring on name.
+
+Sun Feb 25 15:52:18 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * printcmd.c (print_frame_args): Make highest_offset an int.
+       New variable args_printed.
+       (print_frame_nameless_args): Remove parameter end and add num
+       and first.
+       (print_frame_args): Change call to print_frame_nameless_args.
+
+Fri Feb 23 21:40:15 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * stack.c (up_command, down_command):
+       Only print stack frame if from_tty.
+
+Thu Feb 22 12:01:36 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * expread.y: Inlcude value.h and don't cast return value from
+       lookup_internalvar.
+
+       * infrun.c: Remove code in #ifdef UMAX_PTRACE.
+
+       * values.c (convenience_info): Print in form "$foo = 5".
+       Don't print "Debugger convenience variables:" before first one.
+
+       * Makefile.dist: Remove ADD_FILES from CLIBS.
+       (gdb, kdb, xgdb): Put in ADD_FILES as well as CLIBS.
+
+       * m-pyr.h: #if 0 out call dummy stuff.
+       Put in POP_FRAME which just calls error().
+       valops.c: If CALL_DUMMY is not defined, put in dummy call_function
+       which just prints an error message.
+
+Tue Feb 20 22:11:40 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * breakpoint.c (commands_command): Add arg from_tty.
+
+       * main.c (main): Put if (!setjmp (to_top_level)) around calls
+       to *_command made in response to command line arguments.
+
+Mon Feb 19 13:58:28 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * main.c (main): Use getopt_long_only.  Move one-character options
+       to long_options.  Remove entries which are just unambiguous
+       abbreviations of other options.
+
+       * command.h: Add types cmd_types and var_types.
+       Add fields type, var_type, and var to struct cmd_list_element.
+       command.c (add_set_cmd, add_set_from_show): New functions.
+       (add_cmd): Set c->var_type.
+       (add_abbrev_cmd): Call add_cmd instead of duplicating code.
+       main.c: Add showlist.
+       Move parse_binary_operation from main.c to command.c.
+       command.c (do_setshow_command): New function.
+       gdbcmd.h: New file.
+       Makefile.dist: Add gdbcmd.h.
+       many files: Include gdbcmd.h, use add_set_cmd and add_show_from_set.
+       Replace info * with show * where appropriate.
+       utils.c (fputs_filtered): Use UINT_MAX in lines_per_page to mean
+       no paging.
+       defs.h: Define UINT_MAX.
+       infcmd.c (run_command): Use execute_command, not set_args_command.
+       main.c (execute_command): Call do_setshow_command if necessary.
+       main.c (show_command, show_history): New functions.
+       main.c (initialize_main): Call add_prefix_cmd
+       for show and show history.
+
+       * coffread.c (enter_linenos): Print error if
+       file_offset < linetab_offset.
+
+Sun Feb 18 15:37:05 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * convex-dep.c (comm_registers_info): Fix typo.  ("argc"->"arg").
+
+Wed Feb 14 20:45:14 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * config.gdb: Create Makefile with make.
+
+       * Makefile.dist, config.gdb: Move "srcdir=" line from Makefile.dist
+       to new file Makefile.srcdir.
+
+       * valprint.c: Include <errno.h>.
+
+       * value.h: Declare value_coerce_function.
+
+       * findvar.c: Add missing " after #include "gdbcore.h
+
+       * main.c (main): Re-write command parsing to use getopt.
+       On "gdb +help" print options with '+' not '-'.
+       Makefile.dist: Add getopt.
+
+Tue Feb 13 00:08:27 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * Makefile.dist: Add "srcdir=."
+       config.gdb: Edit srcdir= rather than adding it to the beginning.
+
+       * pyr-dep.c: Make global_reg_offset, last_frame_offset not static.
+       Move definition of reg_stack_offset to core.c [REG_STACK_SEGMENT].
+
+       * config/pyramid: Print message about alloca.
+
+       * breakpoint.c (clear_command): When printing "no breakpoint"
+       error, only use arg if non-NULL.
+
+       * core.c (read_memory): Rename to read_memory_noerr.
+       (read_memory): New function which calls read_memory and checks for err.
+       gdbcore.h: Declare all extern core.c functions.
+       move myread from core.c to utils.c.
+       declare it in defs.h.
+       (read_memory_integer): move from infcmd.c to core.c.
+       gdbcore.h: Declare it.
+       Many places: Remove error checking on read_memory, or call
+       read_memory_noerr instead.  Include "gdbcore.h" if calling either.
+
+       * value.h (COERCE_ARRAY): Coerce functions to function pointers.
+       valops.c (value_coerce_function): New function.
+
+       * core.c, convex-dep.c, arm-dep.c (xfer_core_file): Return EIO
+       if address out of bounds.
+
+       * m-arm.h, arm-dep.c arm-pinsn.c arm-opcode.h: New files.
+       dbxread.c, m-convex.h (VARIABLES_INSIDE_BLOCK): Add gcc_p parameter.
+       Makefile.dist (alldeps.mak): Special case for arm-convert.s.
+       dbxread.c (define_symbol): Check for local based on it not
+       being any one of the known deftypes.
+       values.c (using_struct_return): Use new macro USE_STRUCT_CONVENTION.
+
+       * Makefile.dist, config.gdb: Put in srcdir stuff.
+
+Mon Feb 12 22:46:16 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * breakpoint.c: Add addr_string and cond_string fields to
+       struct breakpoint.
+       (break_command_1): Set them.  Use mention ().
+       (mention): Create with code from break_command_1.
+       (breakpoint_re_set): New function.
+       (breakpoint_clear): Remove.
+       (condition_command): Set cond_string.
+       (breakpoint_delete): Free cond_string and addr_string.
+       Declare parse_c_1's type and remove casts to struct expression *.
+       symmisc.c (free_all_symtabs): Don't call breakpoint_clear.
+       dbxread.c, coffread.c (reread_symbols): Call breakpoint_re_set,
+       Include breakpoint.h.
+       breakpoint.h: New file.
+       dbxread.c: Move declaration of symmisc.c functions to symtab.h.
+
+Sun Feb 11 17:29:23 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * symtab.c: Make lookup_block_symtab extern.
+       symtab.h: Declare it.
+       valops.c (value_of_this): Use it.
+
+Fri Feb  9 08:59:37 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * config/hp300hpux: Print message telling people to use gcc.
+
+       * value.h: Declare print_floating.
+       printcmd.c (print_scalar_formatted, case 'f'): Use print_floating.
+       valprint.c (val_print, case TYPE_CODE_FLT): Use print_floating.
+       valprint.c (print_floating): Make this function out of is_nan
+       and the code which was in val_print.
+       Put parentheses around high & 0xfffff.
+       Print sign and fraction for NaN's.
+       Print 17 digits not 16 for doubles.
+       (is_nan): Remove.
+       m-news.h, m-sun3.h: Define IEEE_FLOAT.
+
+       * Rename gld-pinsn.c to gould-pinsn.c.
+       config/{pn,npl}: Change name of gld-pinsn.c
+
+Tue Feb  6 00:25:36 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * infptrace.c: Define PT_ATTACH if not defined.
+       m-hp300hpux.h: Define ATTACH_DETACH.
+
+       * main.c (initialize_main): Change alias class to aliases.
+
+       * dbxread.c: Search and destroy references to symsegs.
+       Also remove some #if 0'd code.
+
+       * core.c: Remove reread_exec.
+       dbxread.c (reread_symbols): New function.
+       dbxread.c (symbol_file_command): Set symfile_mtime.
+       coffread.c: Same.
+       infcmd.c (run_command): Call reread_symbols not reread_exec.
+
+       * valprint.c (val_print): When printing string after char *, print
+       it for "" just like any other string.
+
+       * core.c (reread_exec): New procedure.
+       infcmd.c (run_command): Call reread_exec.
+
+       * coffread.c (symbol_file_command): Add from_tty.
+
+       * dbxread.c (symbol_file_command): Only ask about loading new
+       symbol table if from_tty.
+
+Mon Feb  5 02:25:25 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * inflow.c (inferior_died): Call breakpoint_clear_ignore_counts.
+
+       * Makefile.dist (OBS): Remove dbxread.o and coffread.o.
+
+       * config.gdb: Ignore files ending in '#' in config.
+
+       * stack.c (backtrace_command): Add QUIT to get_prev_frame loops.
+
+Sat Feb  3 22:25:09 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * Makefile.dist (YACC): Don't use -v.
+
+Fri Feb  2 19:26:50 1990  Jim Kingdon  (kingdon at mole.ai.mit.edu)
+
+       * createtags: Only change .o to .c at end of name.
+
+       * Makefile.dist (alldeps.mak): new target.
+       (Makefile): add alldeps.mak.
+       (SOURCES): remove PINSNS.
+       (TAGFILES: use ALLPARAM.
+       (gdb.tar): add config/.
+
+       * config.gdb: Check for M_FILE= not #param.h
+       config/*: Make sure M_FILE= exists with space after M_FILE=.
+       Makefile.dist (TAGS): Pass M_FILE and DEPFILES.
+       createtags: Change .o to .c.  Remove special tests for dep.c etc.
+
+       * dbxread.c, coffread.c: Don't check COFF_FORMAT and READ_DBX_FORMAT.
+       Makefile.dist: Move {dbx,coff}read.c from SFILES to ALLDEPFILES.
+       config/*: add dbxread.o or coffread.o to depfiles.
+
+       * Makefile.dist (depend): Depend on $(SOURCES), not force.
+
+Thu Feb  1 17:43:54 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * symmisc.c (print_symbol): Print newline after label.
+
+Wed Jan 31 22:35:38 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * dbxread.c (read_addl_syms): Remove code that checks for
+       _etext.
+       Move end_of_text_addr into read_dbx_symtab.
+       (read_dbx_symtab): #if 0 out code which checks for _etext.
+
+Tue Jan 30 15:40:19 1990  Jim Kingdon  (kingdon at albert.ai.mit.edu)
+
+       * Makefile.dist (gdb.tar): Use readline's "make readline.tar"
+       instead of having a list of readline files.
+
+       * infrun.c (normal_stop): #if 0 out "you have found a bug in sh".
+
+       * munch (-DSYSV): Check for .text at end of name.
+       Optionally allow extra underscore before initialize.
+       Remove space between #! and /bin/sh.
+
+       * m-merlin.h: Put in clarifying comments about SHELL_FILE.
+       Makefile.dist (install): Execute M_INSTALL.
+       config/merlin: Define M_INSTALL.
+
+Mon Jan 29 04:32:09 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * inflow.c: Change all references to signal handlers from
+       int (*)() to void (*)().
+
+       * main.c: Declare init_signals before use & make it void.
+       Declare initialize_all_files.
+
+       * Makefile.dist (config.status): New target.
+
+Sat Jan 27 00:19:50 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * defs.h (enum command_class): Remove comma after last element.
+
+       * Makefile.dist (gdb.tar.Z): Use compress <foo >bar rather
+       than deleting gdb.tar.Z before starting.
+
+       * dbxread.c (process_one_symbol): Compare context_stack_depth
+       with !VARIABLES_INSIDE_BLOCK, not VARIABLES_INSIDE_BLOCK.
+
+       * mcheck.c: Put whole file in #if defined MALLOC_RANGE_CHECK.
+
+       * mcheck.c (checkhdr): Call fatal_dump_core not abort.
+
+       * mcheck.c: Copy from malloc distribution.
+
+       * main.c (main): Call init_malloc ().
+
+       * main.c (initialize_signals): Rename to init_signals.
+
+Fri Jan 26 00:53:23 1990  Jim Kingdon  (kingdon at mole.ai.mit.edu)
+
+       * *dep.c: Make core_file_command return void.
+
+       * gdbcore.h [!KERNEL_U_ADDR]: Declare kernel_u_addr.
+       infptrace.c [!KERNEL_U_ADDR]: Make it extern.
+
+       * altos-dep.c (NBPG, UPAGES): Wrap #define in #if !defined.
+
+       * m-pn.h (GOULD_PN): Define.
+       *-pinsn.c: Include actual opcode table not just opcode.h
+
+       * main.c [ALIGN_STACK_ON_STARTUP]: New code.
+       m-i386.h: Define ALIGN_STACK_ON_STARTUP.
+
+       * m-merlin.h (NO_SIGINTERRUPT, SHELL_FILE): Define.
+
+       * Move code from infptrace [USE_PTRACE_GETREGS] to sun3-dep.c.
+       m-sun{2,3}.h, m-sparc.h: Define FETCH_INFERIOR_REGISTERS.
+
+       * Makefile.dist, config.gdb, config/*:
+       Re-write to use machine-dependent makefiles instead of cpp.
+
+       * m-hp300hpux.h: Define FETCH_INFERIOR_REGISTERS.
+       infptrace.c: Put {fetch,store}_inferior_registers inside
+       #if !defined FETCH_INFERIOR_REGISTERS.
+
+       * Split execcore.c into exec.c and coredep.c.
+       Move a bunch of stuff from coredep.c and *dep.c to gdbcore.h.
+
+       * infptrace.c ({fetch,store}_inferior_registers):
+       Use U_REGS_OFFSET to set offset.
+       m-umax.h: Define U_REGS_OFFSET.
+
+       * m-umax.h: Define PTRACE_{ATTACH,DETACH}.
+
+       * m-i386.h (N_SET_MAGIC): Define.
+       m-i386gas.h: add #undef N_SET_MAGIC.
+
+Thu Jan 25 18:39:45 1990  Jim Kingdon  (kingdon at mole.ai.mit.edu)
+
+       * m-hp300bsd.h: Remove KERNEL_U_ADDR.
+
+       * infptrace.c [!KERNEL_U_ADDR]: Get address of kernel u area
+       at runtime.
+
+       * infptrace.c: Replace numbers with PT_KILL, etc.
+       (store_inferior_registers): Loop for as many words are in the register.
+
+       * infptrace.c [NO_SINGLE_STEP]: Call single_step().
+
+       * kill_inferior{,_fast}: Declare as returning void.
+
+       * m-sun3.h (USE_PTRACE_GETREGS): Define.
+
+       * execcore.c: Add IS_OBJECT_FILE & related stuff.
+
+       * infptrace.c: Include <sys/ptrace.h>.
+       [ATTACH_DETACH] [USE_PTRACE_GETREGS]: New code.
+
+       * Split default-dep.c into infptrace.c and execcore.c.
+
+       * valprint.c [IEEE_FLOAT]: Change void * to char *.
+
+       * breakpoint.c: Change printf_filtered(%s) to fputs_filtered.
+
+Wed Jan 24 00:35:52 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * dbxread.c (symbol_file_command): When freeing everything, free
+       the string table too.
+
+       * Makefile.dist (gdb1): add "rm -f gdb1".
+
+       * printcmd.c (print_scalar_formatted): If size is 0, use 'b'
+       'h', 'w', or 'g' depending on the type.
+
+       * stack.c (backtrace_command): Read in symbols for frames we'll
+       print before printing them.
+
+       * valops.c (value_at): Don't print "I/O error" on EIO from
+       ptrace.  Don't print "out of bounds" for any ptrace error
+       except EIO.
+
+       * valprint.c (type_print_base, case TYPE_CODE_ENUM):
+       Print "FOO = 5" not "FOO : 5".
+
+       * symtab.{c,h}: Make lookup_misc_func extern.
+
+       * Makefile.dist: Define VERSION in makefile, and generate
+       version.c automatically.
+       (gdb.tar): Use gdb-$(VERSION), not dist-gdb.
+
+       * expread.y (yylex): Use lookup_primitive_typename to
+       cut down on calls to lookup_symbol.
+       symtab.{c,h} (lookup_primitive_typename): New function.
+       (lookup_typename): Use it.
+
+       * symtab.{c,h} (check_stub_type): New function.
+       valprint.c (type_print_base, val_print, type_print_derivation_info),
+       values.c (allocate_value): Call it.
+
+       * printcmd.c (whereis_command): New function.
+       symtab.c (lookup_symbol): Add symtab parameter.
+       various: Pass additional argument to lookup_symbol.
+       symseg.h (struct symbol): Add line field.
+       dbxread.c (define_symbol): Set sym->line.
+
+       * dbxread.c (symbol_file_command): Read string table into
+       malloc'd memory (symfile_string_table) and leave it there.
+       (psymtab_to_symtab): Use symfile_string_table.
+
+       * utils.c (sig_abbrev): Return NULL if not found.
+       infrun.c (sig_print_{header,info}): Consolidate duplicated
+       code from handle_command, signals_info.
+       (sig_print_info): Just print number if no name from sig_abbrev.
+
+       * Makefile.dist (OTHERS): Add ChangeLog-3.x
+
+       * infrun.c (restore_inferior_status): #if 0 out
+       "Unable to restore previously selected frame" error message.
+
+       * infrun.c (signals_info, handle_command): Print signal
+       abbrevs along with numbers.
+
+       * infrun.c (handle_command): Accept symbol signal names.
+
+       * utils.c (sig_{number,abbrev}, init_sig): New functions.
+       _initialize_utils: Call init_sig for each signal.
+       defs.h: Declare them.
+
+       * default-dep.c (read_inferior_memory): Check quit_flag in
+       fetch loop.
+
+       * Changes for lazy fetching (speeds things up for big objects):
+       value.h (struct value): New field lazy.
+       VALUE_CONTENTS_RAW, VALUE_LAZY, value_at_lazy: New.
+       findvar.c (read_var_value): Set lazy instead of fetching.
+       various: Copy into VALUE_CONTENTS_RAW, not VALUE_CONTENTS.
+       valops.c: Add value_at_lazy, value_lazy.
+       various: Call value_at_lazy instead of value_at.
+
+       * symtab.h (LONGEST): Define.
+
+       * m-*.h (LONGEST, BUILTIN_TYPE_LONGEST): Delete (in symtab.h).
+
+       * infrun.c (wait_for_inferior): #if 0 out stop if ABOUT_TO_RETURN
+
+       * version.c: Change version number to 4.0development
+
+For older changes see ChangeLog-3.x
+\f
+Local Variables:
+mode: indented-text
+left-margin: 8
+fill-column: 74
+version-control: never
+End:
diff --git a/gdb/ChangeLog-3.x b/gdb/ChangeLog-3.x
new file mode 100644 (file)
index 0000000..e8dbcd8
--- /dev/null
@@ -0,0 +1,4846 @@
+Tue Jan 23 15:49:47 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
+
+       * dbxread.c (define_symbol): Deal with deftype 'X'.
+
+       * convex-dep.c (wait): Make it pid_t.
+
+       * convex-dep.c (comm_registers_info): accept decimal comm register
+       specification, as "i comm 32768".
+
+       * dbxread.c (process_one_symbol): Make VARIABLES_INSIDE_BLOCK
+       macro say by itself where variables are.  Pass it desc.
+       m-convex.h (VARIABLES_INSIDE_BLOCK): Nonzero for native compiler.
+
+       * m-convex.h (SET_STACK_LIMIT_HUGE): Define.
+       (IGNORE_SYMBOL): Take out #ifdef N_MONPT and put in 0xc4.
+
+Fri Jan 19 20:04:15 1990  Jim Kingdon  (kingdon at albert.ai.mit.edu)
+
+       * printcmd.c (print_frame_args): Always set highest_offset to
+       current_offset when former is -1.
+
+       * dbxread.c (read_struct_type): Print nice error message
+       when encountering multiple inheritance.
+
+Thu Jan 18 13:43:30 1990  Jim Kingdon  (kingdon at mole.ai.mit.edu)
+
+       * dbxread.c (read_dbx_symtab): Always treat N_FN as a potential
+       source for a x.o or -lx symbol, ignoring OFILE_FN_FLAGGED.
+
+       * printcmd.c (print_frame_args): Cast -1 to (CORE_ADDR).
+
+       * hp300bsd-dep.c (_initialize_hp300_dep): Get kernel_u_addr.
+       m-hp300bsd.h (KERNEL_U_ADDR): Use kernel_u_addr.
+
+       * infcmd.c (run_command): #if 0 out call to
+       breakpoint_clear_ignore_counts.
+
+Thu Jan 11 12:58:12 1990  Jim Kingdon  (kingdon at mole)
+
+       * printcmd.c (print_frame_args) [STRUCT_ARG_SYM_GARBAGE]:
+       Try looking up name of var before giving up & printing '?'.
+
+Wed Jan 10 14:00:14 1990  Jim Kingdon  (kingdon at pogo)
+
+       * many files: Move stdio.h before param.h.
+
+       * sun3-dep.c (store_inferior_registers): Only try to write FP
+       regs #ifdef FP0_REGNUM.
+
+Mon Jan  8 17:56:15 1990  Jim Kingdon  (kingdon at pogo)
+
+       * symtab.c: #if 0 out "info methods" code.
+
+Sat Jan  6 12:33:04 1990  Jim Kingdon  (kingdon at pogo)
+
+       * dbxread.c (read_struct_type): Set TYPE_NFN_FIELDS_TOTAL
+       from all baseclasses; remove vestigial variable baseclass.
+
+       * findvar.c (read_var_value): Check REG_STRUCT_HAS_ADDR.
+       printcmd.c (print_frame_args):  Check STRUCT_ARG_SYM_GARBAGE.
+       m-sparc.h: Define REG_STRUCT_HAS_ADDR and STRUCT_ARG_SYM_GARBAGE.
+
+       * blockframe.c (get_frame_block): Subtract one from pc if not
+       innermost frame.
+
+Fri Dec 29 15:26:33 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * printcmd.c (print_frame_args): check highest_offset != -1, not i.
+
+Thu Dec 28 16:21:02 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * valops.c (value_struct_elt): Clean up error msg.
+
+       * breakpoint.c (describe_other_breakpoints):
+       Delete extra space before "also set at" and add period at end.
+
+Tue Dec 19 10:28:42 1989  Jim Kingdon  (kingdon at pogo)
+
+       * source.c (print_source_lines): Tell user which line number
+       was out of range when printing error message.
+
+Sun Dec 17 14:14:09 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * blockframe.c (find_pc_partial_function): Use
+       BLOCK_START (SYMBOL_BLOCK_VALUE (f)) instead of
+       SYMBOL_VALUE (f) to get start of function.
+
+       * dbxread.c: Make xxmalloc just a #define for xmalloc.
+
+Thu Dec 14 16:13:16 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * m68k-opcode.h (fseq & following fp instructions):
+       Change @ to $.
+
+Fri Dec  8 19:06:44 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * breakpoint.c (breakpoint_clear_ignore_counts): New function.
+       infcmd.c (run_command): Call it.
+
+Wed Dec  6 15:03:38 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * valprint.c: Change it so "array-max 0" means there is
+       no limit.
+
+       * expread.y (yylex): Change error message "invalid token in
+       expression" to "invalid character '%c' in expression".
+
+Mon Dec  4 16:12:54 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * blockframe.c (find_pc_partial_function): Always return 1
+       for success, 0 for failure, and set *NAME and *ADDRESS to
+       match the return value.
+
+       * dbxread.c (symbol_file_command): Use perror_with_name on
+       error from stat.
+       (psymtab_to_symtab, add_file_command),
+       core.c (validate_files), source.c (find_source_lines),
+       default-dep.c (exec_file_command): Check for errors from stat,
+       fstat, and myread.
+
+Fri Dec  1 05:16:42 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * valops.c (check_field): When following pointers, just get
+       their types; don't call value_ind.
+       
+Thu Nov 30 14:45:29 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * config.gdb (pyr): New machine.
+       core.c [REG_STACK_SEGMENT]: New code.
+       dbxread.c (process_one_symbol): Cast return from copy_pending
+       to long before casting to enum namespace.
+       infrun.c: Split registers_info into DO_REGISTERS_INFO
+       and registers_info.
+       m-pyr.h, pyr-{dep.c,opcode.h,pinsn.c}: New files.
+
+       * hp300bsd-dep.c: Stay in sync with default-dep.c.
+
+       * m-hp300bsd.h (IN_SIGTRAMP): Define.
+
+Mon Nov 27 23:48:21 1989  Jim Kingdon  (kingdon at apple-gunkies.ai.mit.edu)
+
+       * m-sparc.h (EXTRACT_RETURN_VALUE, STORE_RETURN_VALUE):
+       Return floating point values in %f0.
+
+Tue Nov 21 00:34:46 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * dbxread.c (read_type): #if 0 out code which skips to
+       comma following x-ref.
+
+Sat Nov 18 20:10:54 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * valprint.c (val_print): Undo changes of Nov 11 & 16.
+       (print_string): Add parameter force_ellipses.
+       (val_print): Pass force_ellipses true when we stop fetching string
+       before we get to the end, else pass false.
+
+Thu Nov 16 11:59:50 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * infrun.c (restore_inferior_status): Don't try to restore
+       selected frame if the inferior no longer exists.
+
+       * valprint.c (val_print): Rewrite string printing code not to
+       call print_string.
+
+       * Makefile.dist (clean): Remove xgdb and xgdb.o.
+
+Tue Nov 14 12:41:47 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * Makefile.dist (XGDB, bindir, xbindir, install, all): New stuff.
+
+Sat Nov 11 15:29:38 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * valprint.c (val_print): chars_to_get: New variable.
+
+Thu Nov  9 12:31:47 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * main.c (main): Process "-help" as a switch that doesn't
+       take an argument.
+
+Wed Nov  8 13:07:02 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * Makefile.dist (gdb.tar.Z): Add "else true".
+
+Tue Nov  7 12:25:14 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * infrun.c (restore_inferior_status): Don't dereference fid if NULL.
+
+       * config.gdb (sun3, sun4): Accept "sun3" and "sun4".
+
+Mon Nov  6 09:49:23 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * Makefile.dist (Makefile): Move comments after commands.
+
+       * *-dep.c [READ_COFF_SYMTAB]: Pass optional header size to
+       read_section_hdr().
+
+       * inflow.c: Include <fcntl.h> regardless of USG.
+
+       * coffread.c (read_section_hdr): Add optional_header_size.
+       (symbol_file_command): Pass optional header size to
+       read_section_hdr().
+       (read_coff_symtab): Initialize filestring.
+
+       * version.c: Change version to 3.4.xxx.
+
+       * GDB 3.4 released.
+
+Sun Nov  5 11:39:01 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * version.c: Change version to 3.4.
+
+       * symtab.c (decode_line_1): Only skip past "struct" if it
+       is there.
+
+       * valops.c (value_ind), eval.c (evaluate_subexp, case UNOP_IND):
+       Have "*" <int-valued-exp> return an int, not a LONGEST.
+
+       * utils.c (fprintf_filtered): Pass arg{4,5,6} to sprintf.
+
+       * printcmd.c (x_command): Use variable itself rather
+       than treating it as a pointer only if it is a function.
+       (See comment "this makes x/i main work").
+
+       * coffread.c (symbol_file_command): Use error for
+       "%s does not have a symbol-table.\n".
+
+Wed Nov  1 19:56:18 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * dbxread.c [BELIEVE_PCC_PROMOTION_TYPE]: New code.
+       m-sparc.h: Define BELIEVE_PCC_PROMOTION_TYPE.
+
+Thu Oct 26 12:45:00 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * infrun.c: Include <sys/dir.h>.
+
+       * dbxread.c (read_dbx_symtab, case N_LSYM, case 'T'):
+       Check for enum types and put constants in psymtab.
+
+Mon Oct 23 15:02:25 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * dbxread.c (define_symbol, read_dbx_symtab): Handle enum
+       constants (e.g. "b:c=e6,0").
+
+Thu Oct 19 14:57:26 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * stack.c (frame_info): Use FRAME_ARGS_ADDRESS_CORRECT
+       m-vax.h (FRAME_ARGS_ADDRESS_CORRECT): New macro.
+       (FRAME_ARGS_ADDRESS): Restore old meaning.
+
+       * frame.h (Frame_unknown): New macro.
+       stack.c (frame_info): Check for Frame_unknown return from
+       FRAME_ARGS_ADDRESS.
+       m-vax.h (FRAME_ARGS_ADDRESS): Sometimes return Frame_unknown.
+
+       * utils.c (fatal_dump_core): Add "internal error" to message.
+
+       * infrun.c (IN_SIGTRAMP): New macro.
+       (wait_for_inferior): Use IN_SIGTRAMP.
+       m-vax.h (IN_SIGTRAMP): New macro.
+
+Wed Oct 18 15:09:22 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * config.gdb, Makefile.dist: Shorten m-i386-sv32.h.
+
+       * coffread.c (symbol_file_command): Pass 0 to select_source_symtab.
+
+Tue Oct 17 12:24:41 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * i386-dep.c (i386_frame_num_args): Take function from m-i386.h
+       file.  Check for pfi null.
+       m-i386.h (FRAME_NUM_ARGS): Use i386_frame_num_args.
+
+       * infrun.c (wait_for_inferior): set stop_func_name to 0
+       before calling find_pc_partial_function.
+
+Thu Oct 12 01:08:50 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * breakpoint.c (_initialize_breakpoint): Add "disa".
+
+       * Makefile.dist: Add GLOBAL_CFLAGS and pass to readline.
+
+       * config.gdb (various): "$machine =" -> "machine =".
+
+Wed Oct 11 11:54:31 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * inflow.c (try_writing_regs): #if 0 out this function.
+
+       * main.c (main): Add "-help" option.
+
+       * dbxread.c (read_dbx_symtab): Merge code for N_FUN with
+       N_STSYM, etc.
+
+Mon Oct  9 14:21:55 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * inflow.c (try_writing_regs_command): Don't write past end
+       of struct user.
+
+       * dbxread.c (read_struct_type): #if 0 out code which checks for
+       bitpos and bitsize 0.
+
+       * config.gdb: Accept sequent-i386 (not seq386).
+       (symmetry): Set depfile and paramfile.
+
+       * m-convex.h (IGNORE_SYMBOL): Check for N_MONPT if defined.
+
+Thu Oct  5 10:14:26 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * default-dep.c (read_inferior_memory): Put #if 0'd out comment
+       within /* */.
+
+Wed Oct  4 18:44:41 1989  Jim Kingdon  (kingdon at apple-gunkies.ai.mit.edu)
+
+       * config.gdb: Change /dev/null to m-i386.h for various
+       386 machine "opcodefile" entries.
+
+       * config.gdb: Accept seq386 for sequent symmetry.
+
+Mon Oct  2 09:59:50 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * hp300bsd-dep.c:  Fix copyright notice.
+
+Sun Oct  1 16:25:30 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * Makefile.dist (DEPFILES): Add isi-dep.c.
+
+       * default-dep.c (read_inferior_memory): Move #endif after else.
+
+Sat Sep 30 12:50:16 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * version.c: Change version number to 3.3.xxx.
+
+       * GDB 3.3 released.
+
+       * version.c: Change version number to 3.3.
+
+       * Makefile.dist (READLINE): Add vi_mode.c
+
+       * config.gdb (i386): Change /dev/null to m-i386.h
+
+       * config.gdb: Add ';;' before 'esac'.
+
+       * Makefile.dist (gdb.tar.Z): Move comment above dependency.
+
+       * dbxread.c (read_ofile_symtab): Check symbol before start
+       of source file for GCC_COMPILED_FLAG_SYMBOL.
+       (start_symtab): Don't clear processing_gcc_compilation.
+
+Thu Sep 28 22:30:23 1989  Roland McGrath  (roland at hobbes.ai.mit.edu)
+
+       * valprint.c (print_string): If LENGTH is zero, print "".
+
+Wed Sep 27 10:15:10 1989  Jim Kingdon  (kingdon at apple-gunkies.ai.mit.edu)
+
+       * config.gdb: "rm tmp.c" -> "rm -f tmp.c".
+
+Tue Sep 26 13:02:10 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * utils.c (_initialize_utils): Use termcap to set lines_per_page
+       and chars_per_line.
+
+Mon Sep 25 10:06:43 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * dbxread.c (read_dbx_symtab, N_SOL): Do not add the same file
+       more than once.
+
+Thu Sep 21 12:43:18 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * infcmd.c (unset_environment_command): Delete all variables
+       if called with no arg.
+
+       * remote.c, inferior.h (remote_{read,write}_inferior_memory):
+       New functions.
+       core.c ({read,write}_memory): Use remote_{read,write}_inferior_memory.
+
+       * valops.c (call_function): When reserving stack space for
+       arguments, call value_arg_coerce.
+
+       * m-hp9k320.h: define BROKEN_LARGE_ALLOCA.
+
+       * breakpoint.c (delete_command): Ask for confirmation only
+       when there are breakpoints.
+
+       * dbxread.c (read_struct_type): If lookup_basetype_type has
+       copied a stub type, call add_undefined_type.
+
+       * sparc_pinsn.c (compare_opcodes): Check for "1+i" anywhere
+       in args.
+
+       * val_print.c (type_print_base): Print stub types as
+       "<incomplete type>".
+
+Wed Sep 20 07:32:00 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * sparc-opcode.h (swapa): Remove i bit from match.
+       (all alternate space instructions): Delete surplus "foo rs1+0"
+       patterns.
+
+       * Makefile.dist (LDFLAGS): Set to $(CFLAGS).
+
+       * remote-multi.shar (remote_utils.c, putpkt): Change csum to unsigned.
+
+Tue Sep 19 14:15:16 1989  Jim Kingdon  (kingdon at apple-gunkies.ai.mit.edu)
+
+       * sparc-opcode.h: Set i bit in lose for many instructions which
+       aren't immediate.
+
+       * stack.c (print_frame_info): add "func = 0".
+
+Mon Sep 18 16:19:48 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * sparc-opcode.h (mov): Add mov to/from %tbr, %psr, %wim.
+
+       * sparc-opcode.h (rett): Fix notation to use suggested assembler
+       syntax from architecture manual.
+
+       * symmetry-dep.c (I386_REGNO_TO_SYMMETRY): New macro.
+       (i386_frame_find_saved_regs): Use I386_REGNO_TO_SYMMETRY.
+
+Sat Sep 16 22:21:17 1989  Jim Kingdon  (kingdon at spiff)
+
+       * remote.c (remote_close): Set remote_desc to -1.
+
+       * gdb.texinfo (Output): Fix description of echo to match
+       reality and ANSI C.
+
+Fri Sep 15 14:28:59 1989  Jim Kingdon  (kingdon at apple-gunkies.ai.mit.edu)
+
+       * symtab.c (lookup_symbol): Add comment about "asm".
+
+       * sparc-pinsn.c: Use NUMOPCODES.
+
+       * sparc-opcode.h (NUMOPCODES): Use sparc_opcodes[0] not *sparc_opcodes.
+
+Thu Sep 14 15:25:20 1989  Jim Kingdon  (kingdon at apple-gunkies.ai.mit.edu)
+
+       * dbxread.c (xxmalloc): Print error message before calling abort().
+
+       * infrun.c (wait_for_inferior): Check for {stop,prev}_func_name
+       null before passing to strcmp.
+
+Wed Sep 13 12:34:15 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * sparc-opcode.h: New field delayed.
+       sparc-pinsn.c (is_delayed_branch): New function.
+       (print_insn): Check for delayed branches.
+
+       * stack.c (print_frame_info): Use misc_function_vector in
+       case where ar truncates file names.
+
+Tue Sep 12 00:16:14 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * convex-dep.c (psw_info): Move "struct pswbit *p" with declarations.
+
+Mon Sep 11 14:59:57 1989  Jim Kingdon  (kingdon at spiff)
+
+       * convex-dep.c (core_file_command): Delete redundant printing
+       of "Program %s".
+
+       * m-convex.h (ENTRY_POINT): New macro.
+
+       * m-convex.h (FRAME_CHAIN_VALID): Change outside_first_object_file
+       to outside_startup_file
+
+       * main.c: #if 0 out catch_termination and related code.
+
+       * command.c (lookup_cmd_1): Consider underscores part of
+       command names.
+
+Sun Sep 10 09:20:12 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * printcmd.c: Change asdump_command to disassemble_command
+       (_initialize_printcmd): Change asdump to diassemble.
+
+       * main.c (main): Exit with code 0 if we hit the end of a batch
+       file.
+
+       * Makefile.dist (libreadline.a): Fix syntax of "CC=${CC}".
+
+Sat Sep  9 01:07:18 1989  Jim Kingdon  (kingdon at apple-gunkies.ai.mit.edu)
+
+       * values.c (history_info): Renamed to value_history_info.
+       Command renamed to "info value" (with "info history" still
+       accepted).
+
+       * sparc-pinsn.c (print_insn): Extend symbolic address printing
+       to cover "sethi" following by an insn which uses 1+i.
+
+Fri Sep  8 14:24:01 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * m-hp9k320.h, m-hp300bsd.h, m-altos.h, m-sparc.h, m-sun3.h
+       (READ_GDB_SYMSEGS): Remove.
+       dbxread.c [READ_GDB_SYMSEGS]: Remove code to read symsegs.
+
+       * sparc-pinsn.c (print_insn): Detect "sethi-or" pairs and
+       print symbolic address.
+
+       * sparc-opcode.h (sethi, set): Change lose from 0xc0000000 to
+       0xc0c00000000. 
+
+       * remote.c (remote_desc): Initialize to -1.
+
+       * Makefile.dist (libreadline.a): Pass CC='${CC}' to readline makefile.
+
+Thu Sep  7 00:07:17 1989  Jim Kingdon  (kingdon at apple-gunkies.ai.mit.edu)
+
+       * dbxread.c (read_struct_type): Check for static member functions.
+       values.c, eval.c, valarith.c, valprint.c, valops.c: Merge changes
+       from Tiemann for static member functions.
+
+       * sparc-opcode.h (tst): Fix all 3 patterns.
+
+       * Makefile.dist (gdb1): New rule.
+
+       * sparc-opcode.h: Change comment about what the disassembler
+       does with the order of the opcodes.
+
+       * sparc-pinsn.c (compare_opcodes): Put 1+i before i+1.
+       Also fix mistaken comment about preserving order of original table.
+
+       * sparc-opcode.h (clr, mov): Fix incorrect lose entries.
+
+       * m-symmetry.h (FRAME_NUM_ARGS): Add check to deal with code that
+       GCC sometimes generates.
+
+       * config.gdb: Change all occurances of "skip" to "/dev/null".
+
+       * README (about languages other than C): Update comments about
+       Pascal and FORTRAN.
+
+       * sparc-opcode.h (nop): Change lose from 0xae3fffff to 0xfe3fffff.
+
+       * values.c (value_virtual_fn_field): #if 0-out assignment to
+       VALUE_TYPE(vtbl).
+
+Wed Sep  6 12:19:22 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * utils.c (fatal_dump_core): New function.
+       Makefile.dist (MALLOC_FLAGS): use -Dbotch=fatal_dump_core
+
+Tue Sep  5 15:47:18 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * breakpoint.c (enable_command): With no arg, enable all bkpts.
+
+       * Makefile.dist (Makefile): Remove \"'s around $(MD).
+
+       * Makefile.dist: In "cd readline; make . . ." change first
+       SYSV_DEFINE to SYSV.
+
+       * m68k-pinsn.c (_initialize_pinsn): Use alternate assembler
+       syntax #ifdef HPUX_ASM
+
+Sat Sep  2 23:24:43 1989  Jim Kingdon  (kingdon at apple-gunkies.ai.mit.edu)
+
+       * values.c (history_info): Don't check num_exp[0] if num_exp
+       is nil (just like recent editing_info change).
+
+Fri Sep  1 19:19:01 1989  Jim Kingdon  (kingdon at apple-gunkies.ai.mit.edu)
+
+       * gdb.texinfo (inc-history, inc-readline): Copy in the inc-* files
+       because people might not have makeinfo.
+
+       * README (xgdb): Strengthen nasty comments.
+
+       * gdb.texinfo: Change @setfilename to "gdb.info".
+
+Thu Aug 31 17:23:50 1989  Jim Kingdon  (kingdon at apple-gunkies.ai.mit.edu)
+
+       * main.c (editing_info): Don't check arg[0] if arg is null.
+
+       * m-vax.h: Add comment about known sigtramp bug.
+
+       * sun3-dep.c, sparc-dep.c (IS_OBJECT_FILE, exec_file_command):
+       Get right text & data addresses for .o files.
+
+Wed Aug 30 13:54:19 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * utils.c (tilde_expand): Remove function (it's in readline).
+
+       * sparc-opcode.h (call): Change "8" to "9" in first two
+       patterns (%g7->%o7).
+
+Tue Aug 29 16:44:41 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * printcmd.c (whatis_command): Change 4th arg to type_print
+       from 1 to -1.
+
+Mon Aug 28 12:22:41 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * dbxread.c (psymtab_to_symtab_1): In "and %s ..." change
+       pst->filename to pst->dependencies[i]->filename.
+
+       * blockframe.c (FRAMELESS_LOOK_FOR_PROLOGUE): New macro
+       made from FRAMELESS_FUNCTION_INVOCATION from m-sun3.h except
+       that it checks for zero return from get_pc_function_start.
+       m-hp9k320.h, m-hp300bsd.h, m-i386.h, m-isi.h, m-altos.h,
+       m-news.h, m-sparc.h, m-sun2.h, m-sun3.h, m-symmetry.h
+       (FRAMELESS_FUNCTION_INVOCATION): Use FRAMELESS_LOOK_FOR_PROLOGUE.
+
+       * dbxread.c (read_struct_type): Give warning and ignore field
+       if bitpos and bitsize are zero.
+
+Sun Aug 27 04:55:20 1989  Jim Kingdon  (kingdon at apple-gunkies.ai.mit.edu)
+
+       * dbxread.c (psymtab_to_symtab{,_1}): Print message about
+       reading in symbols before reading stringtab, not after.
+
+Sat Aug 26 02:01:53 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * dbxread.c (IS_OBJECT_FILE, ADDR_OF_TEXT_SEGMENT): New macros.
+       (read_dbx_symtab): Use text_addr & text_size to set end_of_text_addr.
+       (symbol_file_command): pass text_addr & text_size to read_dbx_symtab.
+
+Fri Aug 25 23:08:13 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * valprint.c (value_print): Try to give the name of function
+       pointed to when printing a function pointer.
+
+Thu Aug 24 23:18:40 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * core.c (xfer_core_file): In cases where MEMADDR is above the
+       largest address that makes sense, set i to len.
+
+Thu Aug 24 16:04:17 1989  Roland McGrath  (roland at hobbes.ai.mit.edu)
+
+       * valprint.c (print_string): New function to print a character
+       string, doing array-max limiting and repeat count processing.
+       (val_print, value_print): Use print_string.
+       (REPEAT_COUNT_THRESHOLD): New #define, the max number of elts to print
+       without using a repeat count.  Set to ten.
+       (value_print, val_print): Use REPEAT_COUNT_THRESHOLD.
+
+       * utils.c (printchar): Use {fputs,fprintf}_filtered.
+
+       * valprint.c (val_print): Pass the repeat count arg to the
+       fprintf_filtered call for "<repeats N times>" messages.
+
+Wed Aug 23 22:53:47 1989  Roland McGrath  (roland at hobbes.ai.mit.edu)
+
+       * utils.c: Include <pwd.h>.
+
+       * main.c: Declare free.
+
+Wed Aug 23 05:05:59 1989  Jim Kingdon  (kingdon at apple-gunkies.ai.mit.edu)
+
+       * utils.c, defs.h: Add tilde_expand.
+       source.c (directory_command),
+       main.c (cd_command),
+       main.c (set_history_filename),
+       dbxread.c (symbol_file_command),
+       coffread.c (symbol_file_command),
+       dbxread.c (add_file_command),
+       symmisc.c (print_symtabs),
+       *-dep.c (exec_file_command, core_file_command),
+       main.c (source_command): Use tilde_expand.
+
+       * dbxread.c (read_type): When we get a cross-reference, resolve
+       it immediately if possible, only calling add_undefined_type if
+       necessary.
+
+       * gdb.texinfo: Uncomment @includes and put comment at start
+       of file telling people to use makeinfo.
+
+       * valprint.c (type_print_base): Print the right thing for
+       bitfields.
+
+       * config.gdb (sun3os3): Set paramfile and depfile.
+
+Tue Aug 22 05:38:36 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * dbxread.c (symbol_file_command):  Pass string table size to
+       read_dbx_symtab().
+       (read_dbx_symtab): Before indexing into string table, check
+       string table index for reasonableness.
+       (psymtab_to_symtab{,_1}, read_ofile_symtab): Same.
+
+Tue Aug 22 04:04:39 1989  Roland McGrath  (roland at hobbes.ai.mit.edu)
+
+       * m68k-pinsn.c: Replaced many calls to fprintf and fputs with
+       calls to fprintf_filtered and fputs_filtered.
+       (print_insn_arg): Use normal MIT 68k syntax for postincrement,
+       predecrement, and register indirect addressing modes.
+
+Mon Aug 21 10:08:02 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * main.c (initialize_signals): Set signal handler for SIGQUIT
+       and SIGHUP to do_nothing.
+
+       * ns32k-opcode.h (ord): Change 1D1D to 1D2D.
+
+       * ns32k-pinsn.c (print_insn_arg, print_insn): Handle index
+       bytes correctly.
+
+       * ns32k-opcode.h: Add comments.
+
+       * dbxread.c (read_type): Put enum fields in type.fields in order
+       that they were found in the debugging symbols (not reverse order).
+
+Sun Aug 20 21:17:13 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * main.c (source_command): Read .gdbinit if run without argument.
+
+       * source.c (directory_command): Only print "foo already in path"
+       if from_tty.
+
+       * version.c: Change version number to 3.2.xxx
+
+Sat Aug 19 00:24:08 1989  Jim Kingdon  (kingdon at apple-gunkies.ai.mit.edu)
+
+       * m-news.h: Define HAVE_WAIT_STRUCT.
+
+       * m-isi.h, isi-dep.c: Replace with new version from Adam de Boor.
+       config.gdb: Remove isibsd43.
+
+       * main.c (catch_termination): Don't say we have written
+       .gdb_history until after we really have.
+
+       * convex-dep.c (attach): Add "sleep (1)".
+       (write_vector_register): Use "LL" with long long constant.
+       (wait): Close comment.
+       (wait): Change "unix 7.1 bug" to "unix 7.1 feature" & related
+       changes in comment.
+       (scan_stack): And fp with 0x80000000 in while loop test.
+       (core_file_command): Move code to set COREFILE.
+       (many places): Change printf to printf_filtered.
+       (psw_info): Allow argument giving value to print as a psw.
+       (_initialize_convex_dep): Update docstrings.
+
+       * m-convex.h (WORDS_BIG_ENDIAN): Correct typo ("WRODS")
+       define NO_SIGINTERRUPT.
+       define SET_STACK_LIMIT_HUGE.
+       add "undef BUILTIN_TYPE_LONGEST" before defining it.
+       Use "LL" after constants in CALL_DUMMY.
+
+       * dbxread.c: In the 3 places it says error "ridiculous string
+       table size"... delete extra parameter to error.
+
+       * dbxread.c (scan_file_globals): Check for FORTRAN common block.
+       Allow multiple references for the sake of common blocks.
+
+       * main.c (initialize_main): Set history_filename to include
+       current directory.
+
+       * valprint.c (decode_format): Don't return a defaulted size
+       field if osize is zero.
+
+       * gdb.texinfo (Compilation): Update information on -gg symbols.
+       Document problem with ar.
+
+Fri Aug 18 19:45:20 1989  Jim Kingdon  (kingdon at apple-gunkies.ai.mit.edu)
+
+       * valprint.c (val_print, value_print): Add "<repeats %d times>" code.
+       Also put "..." outside quotes for strings.
+
+       * main.c (initialize_main): Add comment about history output file
+       being different from history input file.
+
+       * m-newsos3.h: Undefine NO_SIGINTERRUPT.  Rearrange a few comments.
+
+       * m-newsos3.h (REGISTER_U_ADDR): Use new version from Hikichi.
+
+       * sparc-opcode.h: Add comment clarifying meaning of the order of
+       the entries in sparc_opcodes.
+
+       * eval.c (evaluate_subexp, case UNOP_IND): Deal with deferencing
+       things that are not pointers.
+
+       * valops.c (value_ind): Make dereferencing an int give a LONGEST.
+
+       * expprint.c (print_subexp): Add (int) cast in OP_LAST case.
+
+       * dbxread.c (read_array_type): Set lower and upper if adjustable.
+
+       * symtab.c (lookup_symbol): Don't abort if symbol found in psymtab
+       but not in symtab.
+
+Thu Aug 17 15:51:20 1989  Randy Smith  (randy at hobbes.ai.mit.edu)
+
+       * config.gdb: Changed "Makefile.c" to "Makefile.dist".
+
+Thu Aug 17 01:58:04 1989  Roland McGrath  (roland at apple-gunkies.ai.mit.edu)
+
+       * sparc-opcode.h (or): Removed incorrect lose bit 0x08000000.
+       [many]: Changed many `lose' entries to have the 0x10 bit set, so
+       they don't think %l0 is %g0.
+
+Wed Aug 16 00:30:44 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * m-symmetry.h (STORE_STRUCT_RETURN): Also write reg 0.
+       (EXTRACT_RETURN_VALUE): Call symmetry_extract_return_value.
+       symmetry-dep.c (symmetry_extract_return_value): New fn.
+
+       * main.c (symbol_completion_function): Deal with changed
+       result_list from lookup_cmd_1 for ambiguous return.
+       command.c (lookup_cmd): Same.
+
+       * inflow.c [TIOCGETC]: Move #include "param.h" back before
+       system #includes.  Change all #ifdef TIOCGETC to
+       #if defined(TIOCGETC) && !defined(TIOCGETC_BROKEN)
+       m-i386-sysv3.2.h, m-i386gas-sysv3.2.h: Remove "#undef TIOCGETC"
+       and add "#define TIOCGETC_BROKEN".
+
+       * command.c (lookup_cmd_1): Give the correct result_list in the
+       case of an ambiguous return where there is a partial match
+       (e.g. "info a").  Add comment clarifying what is the correct
+       result_list.
+
+       * gdb.texinfo (GDB History): Document the two changes below.
+
+       * main.c (command_line_input): Make history expansion not
+       just occur at the beginning of a line.
+
+       * main.c (initialize_main): Make history expansion off by default.
+
+       * inflow.c: Move #include "param.h" after system #includes.
+
+       * i386-dep.c (i386_float_info): Use U_FPSTATE macro.
+
+       * m-i386-sysv3.2.h, m-i386gas-sysv3.2.h: New files.
+       Makefile.dist, config.gdb: Know about these new files.
+
+Tue Aug 15 21:36:11 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * symtab.c (lookup_struct_elt_type): Use type_print rather
+       than assuming type has a name.
+
+Tue Aug 15 02:25:43 1989  Roland McGrath  (roland at apple-gunkies.ai.mit.edu)
+
+       * sparc-opcode.h (mov): Removed bogus "or i,0,d" pattern.
+
+       * sparc-opcode.h (mov, or): Fixed incorrect `lose' members.
+
+       * sparc-dep.c: Don't include "sparc-opcode.h".
+       (skip_prologue, isanulled): Declare special types to recognize
+       instructions, and use them.
+
+       * sparc-pinsn.c (print_insn): Sign-extend 13-bit immediate args.
+       If they are less than +9, print them in signed decimal instead
+       of unsigned hex.
+
+       * sparc-opcode.h, sparc-pinsn.c: Completely rewritten to share an
+       opcode table with gas, and thus produce disassembly that looks
+       like what the assembler accepts.
+
+Tue Aug 15 16:20:52 1989  Jim Kingdon  (kingdon at apple-gunkies.ai.mit.edu)
+
+       * symtab.c (find_pc_psymbol): Move best_pc=psymtab->textlow-1
+       after test for psymtab null.
+
+       * main.c (editing_info): Remove variable retval.
+
+       * config.gdb (sun3, isi): Comment out obsolete message about telling
+       it whether you have an FPU (now that it detects it).
+
+       * config.gdb (sun3): Accept sun3os3.
+
+       * m68k-insn.h: Include <signal.h>.
+
+       * m68k-pinsn.h (convert_{to,from}_68881): Add have_fpu code
+
+       * m-newsos3.h: Undefine USE_PCB.  That code didn't seem to work.
+
+       * sparc-dep.c: Put in insn_fmt and other stuff from the old
+       sparc-opcode.h.
+
+       * sparc-opcode.h, sparc-pinsn.c: Correct copyright notice.
+
+       * sparc-opcode.h, sparc-pinsn.c: Replace the old ones with the new
+       ones by roland.
+
+Tue Aug 15 02:25:43 1989  Roland McGrath  (roland at apple-gunkies.ai.mit.edu)
+
+       * Makefile.dist: Don't define CC at all.
+
+       * Makefile.dist (Makefile): Remove tmp.c after preprocessing.
+       Use $(MD) instead of M_MAKEDEFINE in the cc command.
+
+       * Makefile.dist: Don't define RL_LIB as
+       "${READLINE}/libreadline.a", since READLINE is a list of files.
+
+Mon Aug 14 23:49:29 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * main.c (print_version): Change 1988 to 1989.
+
+       * main.c (copying_info, initialize_main): Remove #if 0'd code.
+
+Tue Aug  1 14:44:56 1989  Hikichi  (hikichi at sran203)
+
+       * m-newsos3.h
+           (NO_SIGINTERRUPT): have SIGINTERRUPT on NEWS os 3.
+
+       * m-news.h(FRAME_FIND_SAVED_REGS): use the sun3's instead of old
+       one.
+
+Mon Aug 14 15:27:01 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * m-news.h, m-newsos3.h, news-dep.c: Merge additional changes
+       by Hikichi (ChangeLog entries above).
+
+       * Makefile.dist (READLINE): List readline files individually
+       so we don't accidently get random files from the readline
+       directory.
+
+       * m-news.h (STORE_RETURN_VALUE, EXTRACT_RETURN_VALUE):
+       Expect floating point returns to be in fp0.
+
+       * gdb.texinfo (Format options): New node.
+
+       * gdb.texinfo: Comment out "@include"s until bfox fixes the
+       readline & history docs.
+
+       * dbxread.c (read_addl_syms): Set startup_file_* if necessary at
+       the end (as well as when we hit ".o").
+
+       * printcmd.c (decode_format): Set val.format & val.size to '?' at
+       start and set defaults at end.
+
+       * symtab.c (decode_line_1): Check for class_name null.
+
+       * valops.c: Each place where it compares against field names,
+       check for null field names.  (new t_field_name variables).
+
+       * utils.c (fputs_filtered): Check for linebuffer null before
+       checking whether to call fputs.  Remove later check for linebuffer
+       null.  
+
+Sun Aug 13 15:56:50 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * m-isi.h, m-sun3.h ({PUSH,POP}_FP_REGS):  New macros.
+       m-sun3.h (NUM_REGS): Conditionalize on FPU.
+       config.gdb (sun3, isi): Add message about support for machines
+       without FPU.
+
+       * main.c (catch_termination, initialize_signals): new functions.
+
+       * main.c (editing_info): Add "info editing n" and "info editing +".
+       Rewrite much of this function.
+       gdb.texinfo (GDB Readline): Document it.
+
+       * values.c (history_info): Add "info history +".  Also add code to
+       do "info history +" when command is repeated.
+       gdb.texinfo (Value History): Document "info history +".
+
+       * expprint.c (print_subexp): Add OP_THIS to case stmt.
+
+       * config.gdb (sun4os4): Put quotes around make define.
+
+       * config.gdb: Canonicalize machine name at beginning.
+
+Sat Aug 12 00:50:59 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * config.gdb: define M_MAKEDEFINE
+       Makefile (Makefile, MD): Be able to re-make Makefile.
+
+       * main.c (command_line_input): Add comments to
+       the command history.
+
+       * Makefile.dist (Makefile): Add /bin/false.
+
+Fri Aug 11 14:35:33 1989  Jim Kingdon  (kingdon at spiff)
+
+       * Makefile.dist: Comment out .c.o rule and add TARGET_ARCH.
+
+       * m-altos.h: Include sys/page.h & sys/net.h
+
+       * m-altos.h (FRAME_CHAIN{,_VALID}):  Use outside_startup_file.
+
+       * config.gdb (altos, altosgas): Add M_SYSV & M_BSD_NM and remove
+       M_ALLOCA=alloca.o from makedefine.
+
+       * coffread.c (complete_symtab): Change a_entry to entry.
+
+       * m-altosgas.h: New file.
+
+       * m-symmetry (REGISTER_BYTE): Fix dumb mistake.
+
+Fri Aug 11 06:39:49 1989  Roland McGrath  (roland at hobbes.ai.mit.edu)
+
+       * utils.c (set_screensize_command): Check for ARG being nil, since
+       that's what execute_command will pass if there's no argument.
+
+       * expread.y (yylex): Recognize "0x" or "0X" as the beginning of a
+       number.
+
+Thu Aug 10 15:43:12 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * config.gdb, Makefile.dist: Rename Makefile.c to Makefile.dist.
+
+       * m-altos.h: Add comment about porting to USGR2.
+
+       * config.gdb (sparc): Add -Usparc.
+
+Wed Aug  9 14:20:39 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * m-sun3os4.h: Define BROKEN_LARGE_ALLOCA.
+
+       * values.c (modify_field): Check for value too large to fit in
+       bitfield. 
+
+       * utils.c (fputs_filtered): Allow LINEBUFFER to be NULL.
+
+       * breakpoint.c (condition_command): Check for attempt to specify
+       non-numeric breakpoint number.
+
+       * config.gdb, Makefile, m-altos.h, altos-dep.c: Merge Altos
+       port.
+
+       * README: Change message about editing Makefile.
+
+       * config.gdb: Edit Makefile.
+       Copied Makefile to Makefile.c and changed to let config.gdb
+       run us through the C preprocessor.
+
+       * expread.y (yylex): Test correctly for definition of number.
+
+Wed Aug  9 11:56:05 1989  Randy Smith  (randy at hobbes.ai.mit.edu)
+
+       * dbxread.c (read_dbx_symtab): Put bracketing of entry point in
+       test case for .o symbols so that it will be correct even without
+       debugging symbols.
+       (end_psymtab): Took bracketing out.
+
+       * blockframe.c (outside_startup_file): Reverse the sense of the
+       return value to make the functionality implied by the name
+       correct. 
+
+Tue Aug  8 11:48:38 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * coffread.c (symbol_file_command): Do  not assume presence of a.out
+       header. 
+
+       * blockframe.c: Replace first_object_file_end with
+       startup_file_{start,end}
+       (outside_startup_file): New function.
+       dbxread.c (read_addl_syms, read_dbx_symtab, end_psymbol): set
+       startup_file_*.  Delete first_object_file_end code.
+       Add entry_point and ENTRY_POINT
+       coffread.c (complete_symtab): Set startup_file_*.
+       (first_object_file_end): Add as static.
+       m-*.h (FRAME_CHAIN, FRAME_CHAIN_VALID): Call outside_startup_file
+       instead of comparing with first_object_file_end.
+
+       * breakpoint.c (breakpoint_1): Change -1 to (CORE_ADDR)-1.
+
+       * config.gdb (i386, i386gas): Add missing quotes at end of "echo"
+
+       * source.c (directory_command): Add dont_repeat ();
+
+Mon Aug  7 18:03:51 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * dbxread.c (read_addl_syms): Change strcmp to strncmp and put 3rd
+       arg back.
+
+       * command.h (struct cmd_list_element): Add comment clarifying
+       purpose of abbrev_flag.
+
+Mon Aug  7 12:51:03 1989  Randy Smith  (randy at hobbes.ai.mit.edu)
+
+       * printcmd.c (_initialize_printcmd): Changed "undisplay" not to
+       have abbrev flag set; it isn't an abbreviation of "delete
+       display", it's an alias.
+
+Mon Aug  7 00:25:15 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * symtab.c (lookup_symtab_1): Remove filematch (never used).
+
+       * expread.y [type]: Add second argument to 2 calls to
+       lookup_member_type which were missing them.
+
+       * dbxread.c (symbol_file_command): Add from_tty arg.
+       Check it before calling query.
+
+       * infcmd.c (tty_command): Add from_tty arg.
+
+       * eval.c (evaluate_subexp): Remove 3rd argument from
+       calls to value_x_unop.
+
+       * dbxread.c (read_addl_syms): Remove 3rd argument from
+       call to strcmp.
+
+       * gdb.texinfo (Command editing): @include inc-readline.texinfo
+       and inc-history.texinfo and reorganize GDB-specific stuff.
+
+       * Makefile: Add line MAKE=make.
+
+       * README (second paragraph): Fix trivial errors.
+
+       * dbxread.c (read_struct_type): Make sure p is initialized.
+
+       * main.c (symbol_completion_function): Complete correctly
+       on the empty string.
+
+Sun Aug  6 21:01:59 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * symmetry-dep.c: Remove "long" from definition of i386_follow_jump.
+
+       * gdb.texinfo (Backtrace): Document "where" and "info stack".
+
+       * dbxread.c (cleanup_undefined_types): Strip off "struct "
+       or "union " from type names before doing comparison
+
+Sat Aug  5 02:05:36 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * config.gdb (i386, i386gas): Improve makefile editing instructions.
+
+       * Makefile: Fix typo in CLIBS for SYSV.
+
+       * dbxread.c (read_dbx_symtab): Deal with N_GSYM typedefs.
+
+       * dbxread.c (add_file_command): Do not free name.  We didn't
+       allocate it; it just points into arg_string.
+
+       * Makefile, m-*.h: Change LACK_VPRINTF to HAVE_VPRINTF.
+
+Fri Jul 28 00:07:48 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * valprint.c (val_print): Made sure that all returns returned a
+       value (usually 0, indicating no memory printed).
+
+       * core.c (read_memory): Changed "return" to "return 0".
+
+       * expread.y (parse_number): Handle scientific notation when the
+       string does not contain a '.'.
+
+Thu Jul 27 15:14:03 1989  Randy Smith  (randy at hobbes.ai.mit.edu)
+
+       * infrun.c (signals_info): Error if signal number passed is out of
+       bounds. 
+
+       * defs.h: Define alloca to be __builtin_alloca if compiling with
+       gcc and localized inclusion of alloca.h on the sparc with the
+       other alloca stuff.
+       * command.c: Doesn't need to include alloca.h on the sparc; defs.h
+       does it for you.
+
+       * printcmd.c (print_frame_args): Changed test for call to
+       print_frame_nameless_args to check i to tell if any args had been
+       printed.
+
+Thu Jul 27 04:40:56 1989  Roland McGrath  (roland at hobbes.ai.mit.edu)
+
+       * blockframe.c (find_pc_partial_function): Always check that NAME
+       and/or ADDRESS are not nil before storing into them.
+
+Wed Jul 26 23:41:21 1989  Roland McGrath  (roland at hobbes.ai.mit.edu)
+
+       * m-newsos3.h: Define BROKEN_LARGE_ALLOCA.
+       * dbxread.c (symbol_file_command, psymtab_to_symtab):
+       Use xmalloc #ifdef BROKEN_LARGE_ALLOCA.
+
+Tue Jul 25 16:28:18 1989  Jay Fenlason  (hack at apple-gunkies.ai.mit.edu)
+
+       * m68k-opcode.h: moved some of the fmovem entries so they're
+       all consecutive.  This way the assembler doesn't bomb.
+
+Mon Jul 24 22:45:54 1989  Randy Smith  (randy at hobbes.ai.mit.edu)
+
+       * symtab.c (lookup_symbol): Changed error to an informational (if
+       not very comforting) message about internal problems.  This will
+       get a null symbol returned to decode_line_1, which should force
+       things to be looked up in the misc function vector.
+
+Wed Jul 19 13:47:34 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * symtab.c (lookup_symbol): Changed "fatal" to "error" in
+       external symbol not found in symtab in which it was supposed to be
+       found.  This can be reached because of a bug in ar.
+
+Tue Jul 18 22:57:43 1989  Randy Smith  (roland at hobbes.ai.mit.edu)
+
+       * m-news.h [REGISTER_U_ADDR]: Decreased the assumed offset of fp0
+       by 4 to bring it into (apparently) appropriate alignment with
+       reality. 
+
+Tue Jul 18 18:14:42 1989  Randy Smith  (randy at hobbes.ai.mit.edu)
+
+       * Makefile: pinsn.o should depend on opcode.h
+
+       * m68k-opcode.h: Moved fmovemx with register lists to before other
+       fmovemx. 
+
+Tue Jul 18 11:21:42 1989  Jim Kingdon  (kingdon at susie)
+
+       * Makefile, m*.h: Only #define vprintf (to _doprnt or printf,
+       depends on the system) if the library lacks it (controlled by
+       LACK_VPRINTF_DEFINE in makefile).  Unpleasant, but necessary to
+       make this work with the GNU C library.
+
+Mon Jul 17 15:17:48 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * breakpoint.c (breakpoint_1): Change addr-b->address to
+       b->address-addr.
+
+Sun Jul 16 16:23:39 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * eval.c (evaluate_subexp): Change error message printed when
+       right operand of '@' is not an integer to English.
+
+       * infcmd.c (registers_info): Fix call to print_spaces_filtered
+       to specify right # of arguments.
+
+       * gdb.texinfo (Command Editing): Document info editing command.
+
+       * coffread.c (read_file_hdr): Add MC68MAGIC.
+
+       * source.c (select_source_symtab): Change MAX to max.
+
+Fri Jul 14 21:19:11 1989  Jim Kingdon  (kingdon at apple-gunkies.ai.mit.edu)
+
+       * infcmd.c (registers_info): Clean up display to look good with long
+       register names, to say "register" instead of "reg", and to put the
+       "relative to selected stack frame" bit at the top.
+
+Fri Jul 14 18:23:09 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * dbxread.c (record_misc_function): Put parens around | to force
+       correct evaluation.
+
+Wed Jul 12 12:25:53 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * m-newsos3, m-news, infrun.c, Makefile, config.gdb, news-dep.c:
+       Merge in Hikichi's changes for Sony/News-OS 3 support.
+
+Tue Jul 11 21:41:32 1989  Jim Kingdon  (kingdon at apple-gunkies.ai.mit.edu)
+
+       * utils.c (fputs_filtered): Don't do any filtering if output is
+       not to stdout, or if stdout is not a tty.
+       (fprintf_filtered): Rely on fputs_filtered's check for whether to
+       do filtering.
+
+Tue Jul 11 00:33:58 1989  Randy Smith  (randy at hobbes.ai.mit.edu)
+
+       * GDB 3.2 Released.
+
+       * valprint.h: Deleted.
+
+       * utils.c (fputs_filtered): Don't do any filtering if filtering is
+       disabled (lines_per_page == 0).
+
+Mon Jul 10 22:27:53 1989  Randy Smith  (roland at hobbes.ai.mit.edu)
+
+       * expread.y [typebase]: Added "unsigned long int" and "unsigned
+       short int" to specs.
+
+Mon Jul 10 21:44:55 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * main.c (main): Make -cd use cd_command to avoid
+       current_directory with non-absolute pathname.
+
+Mon Jul 10 00:34:29 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * dbxread.c (symbol_file_command): Catch errors from stat (even
+       though they should never happen).
+
+       * source.c (openp): If the path is null, use the current
+       directory. 
+
+       * dbxread.c (read_dbx_symtab): Put N_SETV symbols into the misc
+       function vector ...
+       (record_misc_function): ... as data symbols.
+
+       * utils.c (fprintf_filtered): Return after printing if we aren't
+       going to do filtering.
+
+       * Makefile: Added several things for make clean to take care of.
+
+       * expread.y: Lowered "@" in precedence below +,-,*,/,%.
+
+       * eval.c (evaluate_subexp): Return an error if the rhs of "@"
+       isn't integral.
+
+       * Makefile: Added removal of core and gdb[0-9] files to clean
+       target. 
+
+       * Makefile: Made a new target "distclean", which cleans things up
+       correctly for making a distribution.
+
+Sun Jul  9 23:21:27 1989  Randy Smith  (randy at hobbes.ai.mit.edu)
+
+       * dbxread.c: Surrounded define of gnu symbols with an #ifndef
+       NO_GNU_STABS in case you don't want them on some machines.
+       * m-npl.h, m-pn.h: Defined NO_GNU_STABS.
+
+Sun Jul  9 19:25:22 1989  Jim Kingdon  (kingdon at apple-gunkies.ai.mit.edu)
+
+       * utils.c (fputs_filtered): New function.
+       (fprintf_filtered): Use fputs_filtered.
+       utils.c (print_spaces_filtered),
+       command.c (help_cmd,help_cmd_list),
+       printcmd.c (print_frame_args),
+       stack.c (print_block_frame_locals, print_frame_arg_vars),
+       valprint.c (many functions): Use fputs_filtered instead of
+       fprintf_filtered to avoid arbitrary limit.
+
+       * utils.c (fprintf_filtered): Fix incorrect comment.
+
+Sat Jul  8 18:12:01 1989  Randy Smith  (randy at hobbes.ai.mit.edu)
+
+       * valprint.c (val_print): Changed assignment of pretty to use
+       prettyprint as a conditional rather than rely on values of the
+       enum. 
+
+       * Projects: Cleaned up a little for release.
+
+       * main.c (initialize_main): Initialize
+       rl_completion_entry_function instead of completion_entry_function. 
+
+       * Makefile: Modified to use the new readline library setup.
+
+       * breakpoint.c (break_command_1, delete_breakpoint,
+       enable_breakpoint, disable_breakpoint): Put in new printouts for
+       xgdb usage triggered off of xgdb_verbose.
+       * main.c (main): Added check for flag to set xgdb_verbose.
+       * stack.c (frame_command): Set frame_changed when frame command
+       used. 
+
+Fri Jul  7 16:20:58 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * Remove valprint.h and move contents to value.h (more logical).
+
+Fri Jul  7 02:28:06 1989  Randall Smith  (randy at rice-chex)
+
+       * m68k-pinsn.c (print_insn): Included a check for register list;
+       if there is one, make sure to start p after it.
+
+       * breakpoint.c (break_command_1, delete_breakpoint,
+       enable_breakpoint, disable_breakpoint): #ifdef'd out changes
+       below; they produce unwanted output in gdb mode in gnu-emacs.
+
+       * gdb.texinfo: Spelled.  Also removed index references from
+       command editing section; the relevance/volume ratio was too low.
+       Removed all references to the function index.
+
+       * ns32k-opcode.h, ns32k-pinsn.c: Backed out changes of June 24th;
+       haven't yet received legal papers.
+
+       * .gdbinit: Included message telling the user what it is doing.
+
+       * symmetry-dep.c: Added static decls for i386_get_frame_setup,
+       i386_follow_jump.
+       * values.c (unpack_double): Added a return (double)0 at the end to
+       silence a compiler warning.
+
+       * printcmd.c (containing_function_bounds, asdump_command): Created
+       to dump the assembly code of a function (support for xgdb and a
+       useful hack).
+       (_initialize_printcmd): Added this to command list.
+       * gdb.texinfo [Memory]: Added documentation for the asdump
+       command.
+       * breakpoint.c (break_command_1, delete_breakpoint,
+       enable_breakpoint, disable_breakpoint): Added extra verbosity for
+       xgdb conditionalized on the new external frame_full_file_name.
+       * source.c (identify_source_line): Increase verbosity of fullname
+       prointout to include pc value.
+       * stack.c: Added a new variable; "frame_changed" to indicate when
+       a frame has been changed so that gdb can print out a frame change
+       message when the frame only changes implicitly.
+       (print_frame_info): Check the new variable in determining when to
+       print out a new message and set it to zero when done.
+       (up_command): Increment it.
+       (down_command): Decrement it.
+
+       * m68k-pinsn.c (print_insn_arg [lL]): Modified cases for register
+       lists to reset the point to point to after the word from which the
+       list is grabbed *if* that would cause point to point farther than
+       it currently is.
+
+Thu Jul  6 14:28:11 1989  Jim Kingdon  (kingdon at apple-gunkies.ai.mit.edu)
+
+       * valprint.c (val_print, value_print): Add parameter to control
+       prettyprinting.
+       valprint.h: New file containing constants used for passing
+       prettyprinting parameter to val{,ue}_print.
+       expprint.c, infcmd.c, printcmd.c, valprint.c, values.c:
+       Change all calls to val{,ue}_print to use new parameter.
+       
+Mon Jul  3 22:38:11 1989  Randy Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * dbxread.c (,process_one_symbol): Moved extern declaration for
+       index out of function to beginning of file.
+
+Mon Jul  3 18:40:14 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
+
+       * gdb.texinfo (Registers): Add "ps" to list of standard registers.
+
+Sun Jul  2 23:13:03 1989  Jim Kingdon  (kingdon at apple-gunkies.ai.mit.edu)
+
+       * printcmd.c (enable_display): Change d->next to d = d->next so
+       that "enable display" without args works.
+
+Fri Jun 30 23:42:04 1989  Jim Kingdon  (kingdon at apple-gunkies.ai.mit.edu)
+
+       * source.c (list_command):  Made error message given when no
+       symtab is loaded clearer.
+
+       * valops.c (value_assign): Make it so that when assigning to an
+       internal variable, the type of the assignment exp is the type of
+       the value being assigned.
+
+Fri Jun 30 12:12:43 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * main.c (verbose_info): Created.
+       (initialize_main): Put "info verbose" into command list.
+
+       * utils.c (screensize_info): Created.
+       (_initialize_utils): Defined "info screensize" as a normal command.
+
+       * valprint.c (format_info): Added information about maximum number
+       of array elements to function.
+
+       * blockframe.c (find_pc_partial_function): Again.
+
+       * blockframe.c (find_pc_partial_function): Replaced a "shouldn't
+       happen" (which does) with a zero return.
+
+       * main.c (dont_repeat): Moved ahead of first use.
+
+Thu Jun 29 19:15:08 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * vax-opcode.h: Made minor modifications (moved an instruction and
+       removed a typo) to bring this into accord with gas' table; also
+       changed copyright to reflect it being part of both gdb and gas.
+
+       * m68k-opcode.h: Added whole scads and bunches of new stuff for
+       the m68851 and changed the coptyrightto recognize that the file
+       was shared between gdb and gas.
+
+       * main.c (stop_sig): Use "dont_repeat ()" instead of *line = 0;
+
+       * core.c (read_memory): Don't do anything if length is 0.
+
+       * Makefile: Added readline.c to the list of files screwed by
+       having the ansi ioctl.h compilation with gcc.
+
+       * config.gdb: Added sun4os3 & sun4-os3 as availible options.
+
+Wed Jun 28 02:01:26 1989  Jim Kingdon  (kingdon at apple-gunkies.ai.mit.edu)
+
+       * command.c (lookup_cmd): Add ignore_help_classes argument.
+       (lookup_cmd_1): Add ignore_help_classes argument.
+       command.c, main.c: Change callers of lookup_cmd{,_1} to supply
+        value for ignore_help_classes.
+
+Tue Jun 27 18:01:31 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * utils.c (print_spaces_filtered): Made more efficient.
+       * defs.h: Declaration.
+       * valprint.c (val_print): Used in a couple of new places.
+
+Mon Jun 26 18:27:28 1989  Randall Smith  (randy at gluteus.ai.mit.edu)
+
+       * m68k-pinsn.c (print_insn_arg ['#', '^']): Combined them into one
+       case which always gets the argument from the word immediately
+       following the instruction.
+       (print_insn_arg ["[lL]w"]): Make sure to always get the register
+       mask from the word immediately following the instruction.
+
+Sun Jun 25 19:14:56 1989  Randall Smith  (randy at galapas.ai.mit.edu)
+
+       * Makefile: Added hp-include back in as something to distribute.
+
+       * stack.c (print_block_frame_locals): Return value changed from
+       void to int; return 1 if values printed.  Use _filtered.
+       (print_frame_local_vars): Use return value from
+       print_block_frame_locals to mention if nothing printed; mention
+       lack of symbol table, use _filtered.
+       (print_frame_arg_vars): Tell the user if no symbol table
+       or no values printed.  Use fprintf_filtered instead of fprintf.
+       * blockframe.c (get_prev_frame_info): Check for no inferior or
+       core file before crashing.
+
+       * inflow.c (inferior_died): Set current frame to zero to keep from
+       looking like we're in start.
+
+Sat Jun 24 15:50:53 1989  Randall Smith  (randy at gluteus.ai.mit.edu)
+
+       * stack.c (frame_command): Added a check to make sure that there
+       was an inferior or a core file.
+
+       * expread.y (yylex): Allow floating point numbers of the form ".5"
+       to be parsed.
+
+        Changes by David Taylor at TMC:
+       * ns32k-pinsn.c: Added define for ?floating point coprocessor? and
+       tables for register names to be used for each of the possibilities.
+       (list_search): Created; searches a list of options for a specific
+       value.
+       (print_insn_arg): Added 'Q', 'b', 'M', 'P', 'g', and 'G' options
+       to the value location switch.
+       * ns32k-opcode.h: Added several new location flags.
+       [addr, enter, exit, ext[bwd], exts[bwd], lmr, lpr[bwd], restore,
+       rett, spr[bwd], smr]: Improved insn format output.
+
+       * symtab.c (list_symbols): Rearrange printing to produce readable
+       output for "info types".
+
+       * eval.c (evaluate_subexp_for_address): Fixed typo.
+
+       * dbxread.c (read_type): Don't output an error message when
+       there isn't a ',' after a cross-reference.
+
+       * dbxread.c (read_dbx_symtab): #if'd out N_FN case in
+       read_dbx_symtab if it has the EXT bit set (otherwise multiple
+       cases with the same value).
+
+Fri Jun 23 13:12:08 1989  Randall Smith  (randy at plantaris.ai.mit.edu)
+
+       * symmisc.c: Changed decl of print_spaces from static to extern
+       (since it's defined in utils.c).
+
+       * remote.c (remote_open): Close remote_desc if it's already been
+       opened. 
+
+       * Remote_Makefile, remote_gutils.c, remote_inflow.c,
+       remote_server.c, remote_utils.c: Combined into remote-multi.shar.
+       * remote-multi.shar: Created (Vikram Koka's remote stub).
+       * remote-sa.m68k.shar: Created (Glenn Engel's remcom.c).
+       * README: Updated to reflect new organization of remote stubs.
+
+       * dbxread.c (read_dbx_symtab): Put an N_FN in with N_FN | N_EXT to
+       account for those machines which don't use the external bit here.
+       Sigh. 
+
+       * m-symmetry.h: Defined NO_SIGINTERRUPT.
+
+Thu Jun 22 12:51:37 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * printcmd.c (decode_format): Make sure characters are printed
+       using a byte size.
+
+       * utils.c (error): Added a terminal_ours here.
+
+       * stack.c (locals_info): Added check for selected frame.
+
+       * dbxread.c (read_type): Checked to make sure that a "," was
+       actually found in the symbol to end a cross reference.
+
+Wed Jun 21 10:30:01 1989  Randy Smith  (randy at tartarus.uchicago.edu)
+
+       * expread.y (parse_number, [exp]): Allowed for the return of a
+       number marked as unsigned; this will allow inclusion of unsigned
+       constants. 
+
+       * symtab.h: Put in default definitions for BUILTIN_TYPE_LONGEST
+       and BUILTIN_TYPE_UNSIGNED_LONGEST.
+
+       * expread.y (parse_number): Will now accept integers suffixed with
+       a 'u' (though does nothing special with it).
+
+       * valarith.c (value_binop): Added cases to deal with unsigned
+       arithmetic correctly.
+
+Tue Jun 20 14:25:54 1989  Randy Smith  (randy at tartarus.uchicago.edu)
+
+       * dbxread.c (psymtab_to_symtab_1): Changed reading in info message
+       to go through printf_filtered.
+
+       * symtab.c (list_symbols): Placed header message after all calls
+       to psymtab_to_symtab. 
+
+       * symtab.c (smash_to_{function, reference, pointer}_type): Carried
+       attribute of permanence for the type being smashed over the bzero
+       and allowed any type to point at this one if it is permanent.
+
+       * symtab.c (smash_to_{function, reference, pointer}_type): Fix
+       typo: check flags of to_type instead of type.
+
+       * m-hp9k320.h: Changed check on __GNU__ predefine to __GNUC__.
+
+       * Makefile: Made MUNCH_DEFINE seperate and based on SYSV_DEFINE;
+       they aren't the same on hp's.
+
+Mon Jun 19 17:10:16 1989  Randy Smith  (randy at tartarus.uchicago.edu)
+
+       * Makefile: Fixed typo.
+
+       * valops.c (call_function): Error if the inferior has not been
+       started. 
+
+       * ns32k-opcode.h [check[wc], cmpm[bwd], movm[bwd], skpsb]: Fixed
+       typos. 
+
+Fri Jun  9 16:23:04 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * m-news.h [NO_SIGINTERRUPT]: Defined.
+
+       * dbxread.c (read_type): Start copy of undefined structure name
+       past [sue] defining type of cross ref.
+
+       * dbxread.c (process_one_symbol): Changed strchr to index.
+
+       * ns32k-opcode.h, ns32k-pinsn.c: More changes to number of
+       operands, addition of all of the set condition opcodes, addition
+       of several flag letters, all patterned after the gas code.
+
+       * ns32k-opcode.h [mov{su,us}[bwd], or[bwd]]: Changed number of
+       operands from 1 to 2.
+
+Wed Jun  7 15:04:24 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * symseg.h [TYPE_FLAG_STUB]: Created.
+       * dbxread.c (read_type): Set flag bit if type is stub.
+       (cleanup_undefined_types): Don't mark it as a stub if it's been
+       defined since we first learned about it.
+       * valprint.c (val_print): Print out a message to that effect if
+       this type is encountered.
+
+       * symseg.h, symtab.h: Moved the definition of TYPE_FLAG_PERM over
+       to symseg.h so that all such definitions would be in the same place.
+
+       * valprint.c (val_print): Print out <No data fields> for a
+       structure if there aren't any.
+
+       * dbxread.c (read_type): Set type name of a cross reference type
+       to "struct whatever" or something.
+
+Tue Jun  6 19:40:52 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * breakpoint.c (breakpoint_1): Print out symbolic location of
+       breakpoints for which there are no debugging symbols.
+
+Mon Jun  5 15:14:51 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * command.c (help_cmd_list): Made line_size static.
+
+Sat Jun  3 17:33:45 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * Makefile: Don't include the binutils hp-include directory in the
+       distribution anymore; refer the users to the binutils distribution.
+
+Thu Jun  1 16:33:07 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * printcmd.c (disable_display_command): Fixed loop iteration for
+       no arg case.
+
+       * printcmd.c (disable_display_command): Added from_tty parameter
+       to function.
+
+       * valops.c (value_of_variable): Call read_var_value with 0 cast to
+       FRAME instead of CORE_ADDR.
+
+       * eval.c (evaluate_subexp): Corrected number of args passed to
+       value_subscript (to 2).
+
+       * infrun.c (wait_for_inferior), symtab.c (decode_line_1),
+       m-convex.h: Changed name of FIRSTLINE_DEBUG_BROKEN to
+       PROLOGUE_FIRSTLINE_OVERLAP. 
+
+       * m-merlin.h: Fixed typo.
+       * ns32k-opcode.h: Added ns32381 opcodes and "cinv" insn, and fixed
+       errors in movm[wd], rett, and sfsr.
+
+       * eval.c (evaluate_subexp, evaluate_subexp_for_address), valops.c
+       (value_zero): Change value_zero over to taking two arguments
+       instead of three.
+
+       * eval.c (evaluate_subexp)
+         [OP_VAR_VALUE]: Get correct lval type for AVOID_SIDE_EFFECTS for
+         all types of symbols.
+         [BINOP_DIV]: Don't divide if avoiding side effects; just return
+         an object of the correct type.
+         [BINOP_REPEAT]: Don't call value_repeat, just allocate a
+         repeated value.
+       (evaluete_subexp_for_address) [OP_VAR_VALUE]: Just return a thing
+       of the right type (after checking to make sure that we are allowed
+       to take the address of whatever variable has been passed).
+
+Mon May 29 11:01:02 1989  Randall Smith  (randy at galapas.ai.mit.edu)
+
+       * breakpoint.c (until_break_command): Set the breakpoint with a
+       frame specification so that it won't trip in inferior calls to the
+       function.  Also set things up so that it works based on selected
+       frame, not current one.
+
+Sun May 28 15:05:33 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * eval.c (evalue_subexp): Change subscript case to use value_zero
+       in EVAL_AVOID_SIDE_EFFECTS case.
+
+Fri May 26 12:03:56 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * dbxread.c (read_addl_syms, psymtab_to_symtab): Removed
+       cleanup_undefined_types; this needs to be done on a symtab basis.
+       (end_symtab): Called cleanup_undefined_types from here.
+       (cleanup_undefined_types): No longer uses lookup_symbol (brain
+       dead idea; oh, well), now it searches through file_symbols.
+
+Wed May 24 15:52:43 1989  Randall Smith  (randy at galapas)
+
+       * source.c (select_source_symtab): Only run through
+       partial_symtab_list if it exists.
+
+       * coffread.c (read_coff_symtab): Don't unrecord a misc function
+       when a function symbol is seen for it.
+
+       * expread.y [variable]: Make sure to write a type for memvals if
+       you don't get a mft you recognize.
+
+Tue May 23 12:15:57 1989  Randall Smith  (randy at plantaris.ai.mit.edu)
+
+       * dbxread.c (read_ofile_symtab, psymtab_to_symtab): Moved cleanup
+       of undefined types to psymtab_to_symtab.  That way it will be
+       called once for all readins (which will, among other things,
+       help reduce infinite loops).
+
+       * symtab.h [misc_function_type]: Forced mf_unknown to 0.
+       * dbxread.c (record_misc_function): Cast enum to unsigned char (to
+       fit).
+       * expread.y [variable]: Cast unsigned char back to enum to test.
+
+Mon May 22 13:08:25 1989  Randall Smith  (randy at gluteus.ai.mit.edu)
+
+        Patches by John Gilmore for dealing well with floating point:
+       * findvar.c (value_from_register, locate_var_value): Used
+       BYTES_BIG_ENDIAN instead of an inline test.
+       * m-sparc.h [IEEE_FLOAT]: Created to indicate that the sparc is
+       IEEE compatible.
+       * printcmd.c (print_scalar_formatted): Use BYTES_BIG_ENDIAN and
+       the stream argument for printing; also modify default type for
+       'f'.  Change handling of invalid floats; changed call syntax for
+       is_nan.
+       (print_command): Don't print out anything indicating that
+       something was recorded on the history list if it wasn't.
+       * valprint.c (val_print): Fixed to deal properley with new format
+       of is_nan and unpacking doubles without errors occuring.
+       (is_nan): Changed argument list and how it figures big endianness
+       (uses macros).
+       * values.c (record_latest_value): Return -1 and don't record if
+       it's an invalid float.
+       (value_as_double): Changed to use new unpack_double calling
+       convention.
+       (unpack_double): Changed not to call error if the float was
+       invalid; simply to set invp and return.  Changed calling syntax.
+       (unpack_field_as_long, modify_field): Changed to use
+       BITS_BIG_ENDIAN to determine correct action.
+
+       * m-hp9k320.h [HP_OS_BUG]: Created; deals with problem where a
+       trap happens after a continue.
+       * infrun.c (wait_for_inferior): Used.
+
+       * m-convex.h [FIRSTLINE_DEBUG_BROKEN]: Defined a flag to indicate
+       that the debugging symbols output by the compiler for the first
+       line of a function were broken.
+       * infrun.c (wait_for_inferior), symtab.c (decode_line_1): Used.
+       
+       * gdb.texinfo [Data, Memory]: Minor cleanups of phrasing.
+
+Fri May 19 00:16:59 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * dbxread.c (add_undefined_type, cleanup_undefined_types): Created
+       to keep a list of cross references to as yet undefined types.
+       (read_type): Call add_undefined_type when we run into such a case.
+       (read_addl_syms, read_ofile_symtab): Call cleanup_undefined_types
+       when we're done.
+
+       * dbxread.c (psymtab_to_symtab, psymtab_to_symtab_1): Broke
+       psymtab_to_symtab out into two routines; made sure the string
+       table was only readin once and the globals were only scanned once,
+       for any number of dependencies.
+
+Thu May 18 19:59:18 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * m-*.h: Defined (or not, as appropriate per machine)
+       BITS_BIG_ENDIAN, BYTES_BIG_ENDIAN, and WORDS_BIG_ENDIAN.
+
+Wed May 17 13:37:45 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * main.c (symbol_completion_function): Always complete on result
+       command list, even if exact match found.  If it's really an exact
+       match, it'll find it again; if there's something longer than it,
+       it'll get the right result.
+
+       * symtab.c (make_symbol_completion_function): Fixed typo; strcmp
+       ==> strncmp.
+
+       * dbxread.c (read_dbx_symtab): Change 'G' case to mark symbols as
+       LOC_EXTERNAL. 
+
+       * expread.y [variables]: Changed default type of text symbols to
+       function returning int so that one can use, eg. strcmp.
+
+       * infrun.c (wait_for_inferior): Include a special flag indicating
+       that one shouldn't insert the breakpoints on the next step for
+       returning from a sigtramp and forcing at least one move forward. 
+
+       * infrun.c (wait_for_inferior): Change test for nexting into a
+       function to check for current stack pointer inner than previous
+       stack pointer.
+
+       * infrun.c (wait_for_inferior): Check for step resume break
+       address before dealing with normal breakpoints.
+
+       * infrun.c (wait_for_inferior): Added a case to deal with taking
+       and passing along a signal when single stepping past breakpoints
+       before inserting breakpoints.
+
+       * infrun.c (wait_for_inferior): Inserted special case to keep
+       going after taking a signal we are supposed to be taking.  
+
+Tue May 16 12:49:55 1989  Randall Smith  (randy at gluteus.ai.mit.edu)
+
+       * inflow.c (terminal_ours_1): Cast result of signal to (int
+       (*)()). 
+
+       * gdb.texinfo: Made sure that references to the program were in
+       upper case.  Modify description of the "set prompt" command.
+       [Running]: Cleaned up introduction.
+       [Attach]: Cleaned up.
+       [Stepping]: Change "Proceed" to "Continue running" or "Execute".
+       Minor cleanup.
+       [Source Path]: Cleaned up intro.  Cleared up distinction between
+       the executable search path and the source path.  Restated effect
+       of the "directory" command with no arguments.
+       [Data]: Fixed typos and trivial details.
+       [Stepping]: Fixed up explanation of "until".
+
+       * source.c (print_source_lines): Print through filter.
+
+       * printcmd.c (x_command): If the format with which to print is
+       "i", use the address of anything that isn't a pointer instead of
+       the value.  This is for, eg. "x/10i main".
+
+       * gdb.texinfo: Updated last modification date on manual.
+
+Mon May 15 12:11:33 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * symtab.c (lookup_symtab): Fixed typo (name ==> copy) in call to
+       lookup_symtab_1. 
+
+       * gdb.texinfo: Added documentation for "break [+-]n" and for new
+       actions of "directory" command (taking multiple directory names at
+       the same time).
+
+       * m68k-opcode.h: Replaced the version in gdb with an up-to-date
+       version from the assembler directory.
+       * m68k-pinsn.c (print_insn_arg): Added cases 'l' & 'L' to switch
+       to print register lists for movem instructions.
+
+       * dbxread.c, m-convex.h: Moved convex dependent include files over
+       from dbxread.c to m-convex.h.
+
+       * printcmd.c (disable_display, disable_display_command): Changed
+       name of first to second, and created first which takes an int as
+       arg rather than a char pointer.  Changed second to use first.
+       (_initialize_printcmd): Changed to use second as command to call.
+       (delete_current_display, disable_current_display): Changed name of
+       first to second, and changed functionality to match.
+       * infrun.c (normal_stop), main.c (return_to_top_level): Changed to 
+       call disable_current_display.
+
+       * dbxread.c (process_one_symbol, read_dbx_symtab): Changed N_FN to
+       be N_FN | N_EXT to deal with new Berkeley define; this works with
+       either the old or the new.
+
+       * Remote_Makefile, remote_gutils.c, remote_inflow.c,
+       remote_server.c, remote_utils.c: Created.
+       * Makefile: Included in tag and tar files.
+       * README: Included a note about them.
+
+       * printcmd.c (print_address): Use find_pc_partial_function to
+       remove need to readin symtabs for symbolic addresses.  
+
+       * source.c (directory_command): Replaced function with new one
+       that can accept lists of directories seperated by spaces or :'s.
+
+       * inflow.c (new_tty): Replaced calls to dup2 with calls to dup.
+
+Sun May 14 12:33:16 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * stack.c (args_info): Make sure that you have an inferior or core
+       file before taking action.
+
+       * ns32k-opcode.h [deiw, deid]: Fixed machine code values for these
+       opcodes.
+
+       * dbxread.c (scan_file_globals): Modified to use misc function
+       vector instead of file itself.  Killed all arguments to the
+       funciton; no longer needed.
+       (psymtab_to_symtab): Changed call for above to reflect new (void)
+       argument list.
+
+       * dbxread.c (read_dbx_symtab, ): Moved HASH_OFFSET define out of
+       read_dbx_symtab. 
+
+       * expread.y [variable]: Changed default type of misc function in
+       text space to be (void ()).
+
+       * Makefile: Modified for proper number of s/r conflicts (order is
+       confusing; the mod that necessitated this change was on May 12th,
+       not today). 
+
+       * expread.y (yylex): Added SIGNED, LONG, SHORT, and INT keywords.
+       [typename]: Created.
+       [typebase]: Added rules for LONG, LONG INT, SHORT, SHORT INT,
+       SIGNED name, and UNSIGNED name (a good approximation of ansi
+       standard).      
+
+       * Makefile: Included .c.o rule to avoid sun's make from throwing
+       any curves at us.
+
+       * blockframe.c: Included <obstack.h>
+
+       * command.c (lookup_cmd): Clear out trailing whitespace.
+
+       * command.c (lookup_cmd_1): Changed malloc to alloca.  
+       
+Fri May 12 12:13:12 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * printcmd.c (print_frame_args): Only print nameless args when you
+       know how many args there are supposed to be and when you've
+       printed fewer than them.  Don't print nameless args between
+       printed args.
+
+       * symtab.c (make_symbol_completion_function): Fixed typo (= ==>
+       ==). 
+
+       * remote.c (remote_open): ifdef'd out siginterrupt call by #ifndef
+       NO_SIGINTERRUPT.
+       * m-umax.h: Defined NO_SIGINTERRUPT.
+
+       * expread.y [ptype, array_mod, func_mod, direct_abs_decl,
+       abs_decl]:  Added rules for parsing and creating arbitrarily
+       strange types for casts and sizeofs.
+
+       * symtab.c, symtab.h (create_array_type): Created.  Some minor
+       misfeatures; see comments for details (main one being that you
+       might end up creating two arrays when you only needed one).
+
+Thu May 11 13:11:49 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * valops.c (value_zero): Add an argument for type of lval.
+       * eval.c (evaluate_subexp_for_address): Take address properly in
+       the avoid side affects case (ie. keep track of whether we have an
+       lval in memory and we can take the address).
+       (evaluate_subexp): Set the lval type of expressions created with
+       value_zero properley.
+
+       * valops.c, value.h (value_zero): Created--will return a value of
+       any type with contents filled with zero.
+       * symtab.c, symtab.h (lookup_struct_elt_type): Created.
+       * eval.c (evaluate_subexp): Modified to not read memory when
+       called with EVAL_AVOID_SIDE_EFFECTS.
+
+       * Makefile: Moved dbxread.c ahead of coffread.c in the list of
+       source files. 
+
+Wed May 10 11:29:19 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * munch: Make sure that sysv version substitutes for the whole
+       line. 
+
+       * symtab.h: Created an enum misc_function_type to hold the type of
+       the misc function being recorded.
+       * dbxread.c (record_misc_function): Branched on dbx symbols to
+       decide which type to assign to a misc function.
+       * coffread.c (record_misc_function): Always assign type unknown.
+       * expread.y [variable]: Now tests based on new values.
+
+Tue May  9 13:03:54 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * symtab.c: Changed inclusion of <strings.h> (doesn't work on
+       SYSV) to declaration of index.
+
+       * Makefile: Changed last couple of READLINE_FLAGS SYSV_DEFINE
+
+       * source.c ({forward, reverse}_search_command): Made a default
+       search file similar to for the list command.
+
+Mon May  8 18:07:51 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * printcmd.c (print_frame_args): If we don't know how many
+       arguments there are to this function, don't print the nameless
+       arguments.  We don't know enough to find them.
+
+       * printcmd.c (print_frame_args): Call print_frame_nameless_args
+       with proper arguments (start & end as offsets from addr).
+
+       * dbxread.c (read_addl_syms): Removed cases to deal with global
+       symbols; this should all be done in scan_global_symbols.
+
+Sun May  7 11:36:23 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * Makefile: Added copying.awk to ${OTHERS}.
+
+Fri May  5 16:49:01 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * valprint.c (type_print_varspec_prefix): Don't pass
+       passed_a_pointer onto children.
+
+       * valprint.c (type_print_varspec_suffix): Print "array of" with
+       whatever the "of" is after tha array brackets.
+
+       * valprint.c (type_print_varspec_{prefix,suffix}): Arrange to
+       parenthesisze pointers to arrays as well as pointers to other
+       objects. 
+
+       * valprint.c (type_print_varspec_suffix): Make sure to print
+       subscripts of multi-dimensional arrays in the right order.
+
+       * infcmd.c (run_command): Fixed improper usages of variables
+       within remote debugging branch.
+
+       * Makefile: Added Convex.notes to the list of extra files to carry
+       around. 
+
+       * dbxread.c (symbol_file_command): Made use of alloca or malloc
+       dependent on macro define.
+
+Thu May  4 15:47:04 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * Makefile: Changed READLINE_FLAGS to SYSV_DEFINE and called munch
+       with it also.
+       * munch: Check first argument for -DSYSV and be looser about
+       picking up init routines if you find it.
+
+       * coffread.c: Made fclose be of type int.
+
+       * breakpoint.c (_initialize_breakpoint): Put "unset" into class
+       alias. 
+
+Wed May  3 14:09:12 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * m-sparc.h [STACK_END_ADDR]: Parameterized off of
+       machine/vmparam.h (as per John Gilmore's suggestion).
+
+       * blockframe.c (get_prev_frame_info): Changed this function back
+       to checking frameless invocation first before checking frame
+       chain.  This means that a backtrace up from start will produce the
+       wrong value, but that a backtrace from a frameless function called
+       in main will show up correctly.
+
+       * breakpoint.c (_initialize_breakpoint): Added entry in help for
+       delete that indicates that unset is an alias for it.
+
+       * main.c (symbol_completion_function): Modified recognition of
+       being within a single command.
+
+Tue May  2 15:13:45 1989  Randy Smith  (randy at gnu)
+
+       * expread.y [variable]: Add some parens to get checking of the
+       misc function vector right.
+
+Mon May  1 13:07:03 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * default-dep.c (core_file_command): Made reg_offset unsigned.
+
+       * default-dep.c (core_file_command): Improved error messages for
+       reading in registers.
+
+       * expread.y: Allowed a BLOCKNAME to be ok for a variable name (as
+       per C syntax). 
+
+       * dbxread.c (psymtab_to_symtab): Flushed stdout after printing
+       starting message about reading in symbols.
+
+       * printcmd.c (print_frame_args): Switched starting place for
+       printing of frameless args to be sizeof int above last real arg
+       printed. 
+
+       * printcmd.c (print_frame_args): Modified final call to
+       print_nameless_args to not use frame slots used array if none had
+       been used. 
+
+       * infrun.c (wait_for_inferior):  Take FUNCTION_START_OFFSET into
+       account when dealing with comparison of pc values to function
+       addresses. 
+
+       * Makefile: Added note about compiling gdb on a Vax running 4.3.
+
+Sun Apr 30 12:59:46 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * command.c (lookup_cmd): Got correct error message on bad
+       command.  
+
+       * m-sun3.h [ABOUT_TO_RETURN]: Modified to allow any of the return
+       instructions, including trapv and return from interupt.
+
+       * command.c (lookup_cmd): If a command is found, use it's values
+       for error reporting and determination of needed subcommands.
+
+       * command.c (lookup_cmd): Use null string for error if cmdtype is
+       null; pass *line to error instead of **.
+
+       * command.c (lookup_cmd_1): End of command marked by anything but
+       alpha numeric or '-'.  Included ctype.h.
+
+Fri Apr 28 18:30:49 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * source.c (select_source_symtab): Kept line number from ever
+       being less than 1 in main decode.
+
+Wed Apr 26 13:03:20 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * default-dep.c (core_file_command): Fixed typo.
+
+       * utils.c (fprintf_filtered): Don't use return value from
+       numchars. 
+
+       * main.c, command.c (complete_on_cmdlist): Moved function to
+       command.c. 
+
+       * command.c (lookup_cmd): Modified to use my new routine.  Old
+       version is still there, ifdef'd out.
+
+       * command.c, command.h (lookup_cmd_1): Added a routine to do all
+       of the work of lookup_cmd with no error reporting and full return
+       of information garnered in search.
+
+Tue Apr 25 12:37:54 1989  Randall Smith  (randy at gluteus.ai.mit.edu)
+
+       * breakpoint.c (_initialize_breakpoint): Change "delete
+       breakpionts" to be in class alias and not have the abbrev flag
+       set. 
+
+       * main.c (symbol_completion_function): Fix to correctly complete
+       things that correspond to multiword aliases.
+
+       * main.c (complete_on_cmdlist): Don't complete on something if it
+       isn't a command or prefix (ie. if it's just a help topic).
+
+       * main.c (symbol_completion_function): Set list index to be 0 if
+       creating a list with just one element.
+
+       * main.c (complete_on_cmdlist): Don't allow things with
+       abbrev_flag set to be completion values.
+       (symbol_completion_function): Don't accept an exact match if the
+       abbrev flag is set.
+
+       * dbxread.c (read_type): Fixed typo in comparision to check if
+       type number existed.
+
+       * dbxread.c (read_type): Made sure to only call dbx_lookup_type on
+       typenums if typenums were not -1.
+
+Mon Apr 24 17:52:12 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * symtab.c: Added strings.h as an include file.
+
+Fri Apr 21 15:28:38 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * symtab.c (lookup_partial_symtab): Changed to only return a match
+       if the name match is exact (which is what I want in all cases in
+       which this is currently used.
+
+Thu Apr 20 11:12:34 1989  Randall Smith  (randy at gluteus.ai.mit.edu)
+
+       * m-isi.h [REGISTER_U_ADDR]: Installed new version from net.
+       * default-dep.c: Deleted inclusion of fcntl.h; apparently not
+       necessary.
+       * Makefile: Added comment about compiling on isi under 4.3.
+
+       * breakpoint.c (break_command_1): Only give decode_line_1 the
+       default_breakpoint_defaults if there's nothing better (ie. make
+       the default be off of the current_source notes if at all
+       possible). 
+
+       * blockframe.c (get_prev_frame_info): Clean up comments and
+       delete code ifdefed out around FRAMELESS_FUNCTION_INVOCATION test. 
+
+       * remote.c: Added a "?" message to protocol.
+       (remote_open): Used at startup.
+       (putpkt): Read whatever garbage comes over the line until we see a
+       '+' (ie. don't treat garbage as a timeout).
+
+       * valops.c (call_function): Eliminated no longer appropriate
+       comment.
+
+       * infrun.c (wait_for_inferior): Changed several convex conditional
+       compilations to be conditional on CANNOT_EXECUTE_STACK.
+
+Wed Apr 19 10:18:17 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * printcmd.c (print_frame_args): Added code to attempt to deal
+       with arguments that are bigger than an int.
+
+       Continuation of Convex/Fortran changes:
+       * printcmd.c (print_scalar_formatted): Added leading zeros to
+       printing of large integers.
+       (address_info, print_frame_args): Added code to deal with
+       LOC_REF_ARG.
+       (print_nameless_args): Allow param file to specify a routine with
+       which to print typeless integers.
+       (printf_command): Deal with long long values well.
+       * stack.c (print_frame_arg_vars): Change to deal with LOC_REF_ARG.
+       * symmisc.c (print_symbol): Change to deal with LOC_REF_ARG.
+       * symseg.h: Added LOC_REF_ARG to enum address_class.
+       * symtab.c (lookup_block_symbol): Changed to deal with
+       LOC_REF_ARG.
+       * valarith.c (value_subscripted_rvalue): Created.
+       (value_subscript): Used above when app.
+       (value_less, value_equal): Change to cast to (char *) before doing
+       comparison, for machines where that casting does something.
+       * valops.c (call_function): Setup to deal with machines where you
+       cannot execute code on the stack segment.
+       * valprint.c (val_print): Make sure that array element size isn't
+       zero before printing.  Set address of default array to address of
+       first element.  Put in a couple of int cast.  Removed some convex
+       specific code. Added check for endianness of machine in case of a
+       packed structure.  Added code for printing typeless integers and
+       for LONG LONG's.
+       (set_maximum_command): Change to use parse_and_eval_address to get
+       argument (so can use expressions there).
+       * values.c (value_of_internalvar, set_internalvar_component,
+       set_internalvar, convenience_info): Add in hooks for trapped
+       internal vars.
+       (unpack_long): Deal with LONG_LONG.
+       (value_field): Remove LONGEST cast.
+       (using_struct_return): Fixed typo ENUM ==> UNION.
+       * xgdb.c (_initialize_xgdb): Make sure that specify_exec_file_hook
+       is not called unless we are setting up a windowing environ.
+
+Tue Apr 18 13:43:37 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       Various changes involved in 1) getting gdb to work on the convex,
+       and 2) Getting gdb to work with fortran (due to convex!csmith):
+       * convex-dep.c, convex-opcode.h, m-convex.h, convex-pinsn.c:
+       Created (or replaced with new files).
+       * Makefile: Add convex dependent files.  Changed default flags to
+       gnu malloc to be CFLAGS.
+       * config.gdb: Added convex to list of machines.
+       * core.c (files_info): Added a FILES_INFO_HOOK to be used if
+       defined.
+       (xfer_core_file): Conditionalized compilation of xfer_core_file on
+       the macro XFER_CORE_FILE.
+       * coffread.c (record_misc_function): Made sure it zerod type field
+       (which is now being used; see next).
+       * dbxread.c: Included some convex dependent include files.
+       (copy_pending, fix_common_blocks): Created.
+       [STAB_REG_REGNUM, BELIEVE_PCC_PROMOTION]: Created default values;
+       may be overridden in m-*.h.
+       Included data structures for keeping track of common blocks.
+       (dbx_alloc_type): Modified; if called with negative 1's will
+       create a type without putting it into the type vector.
+       (read_dbx_symtab, read_addl_syms): Modified calls to
+       record_misc_function to include the new information.
+       (symbol_file_command, psymtab_to_symtab, add_file_command):
+       Modified reading in of string table to adapt to machines which
+       *don't* store the size of the string table in the first four bytes
+       of the string table.
+       (read_dbx_symtab, scan_file_globals, read_ofile_symtab,
+       read_addl_syms): Modified assignment of namestring to accept null
+       index into symtab as ok.
+       (read_addl_syms): Modified readin of a new object file to fiddle
+       with common blocks correctly.
+       (process_one_symbol): Fixed incorrect comment about convex.  Get
+       symbols local to a lexical context from correct spot on a per
+       machine basis.  Catch a bug in pcc which occaisionally puts an SO
+       where there should be an SOL.  Seperate sections for N_BCOMM &
+       N_ECOMM.
+       (define_symbol): Ignore symbols with no ":".  Use
+       STAB_REG_TO_REGNUM.  Added support for function args calling by
+       reference.
+       (read_type): Only read type number if one is there.  Remove old
+       (#if 0'd out) array code.
+       (read_array_type): Added code for dealing with adjustable (by
+       parameter) arrays half-heartedly.
+       (read_enum_type): Allow a ',' to end a list of values.
+       (read_range_type): Added code to check for long long.
+       * expread.y: Modified to use LONGEST instead of long where
+       necessary.  Modified to use a default type of int for objects that
+       weren't in text space.
+       * findvar.c (locate_var_value, read_var_value): Modified to deal
+       with args passed by reference.
+       * inflow.c (create_inferior): Used CREATE_INFERIOR_HOOK if it
+       exists.
+       * infrun.c (attach_program): Run terminal inferior when attaching.
+       (wait_for_inferior): Removed several convex dependencies.
+       * main.c (float_handler): Created.
+       Made whatever signal indicates a stop configurable (via macro
+       STOP_SIGNAL).
+       (main): Setup use of above as a signal handler.  Added check for
+       "-nw" in args already processed.
+       (command_line_input): SIGTSTP ==>STOP_SIGNAL.
+
+       * expread.y: Added token BLOCKNAME to remove reduce/reduce
+       conflict.
+       * Makefile: Change message to reflect new grammar.
+
+Mon Apr 17 13:24:59 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * printcmd.c (compare_ints): Created.
+       (print_frame_args): Modified to always print arguments in the
+       order in which they were found in the symbol table.  Figure out
+       what apots are missing on the fly.
+
+       * stack.c (up_command): Error if no inferior or core file.
+
+       * m-i386.h, m-symmetry.h [FRAMELESS_FUNCTION_INVOCATION]: Created;
+       same as m68k.
+
+       * dbxread.c (define_symbol): Changed "desc==0" test to
+       "processing_gcc_compilation", which is the correct way to do it.
+
+Sat Apr 15 17:18:38 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * expread.y: Added precedence rules for arglists, ?:, and sizeof
+       to eliminate some shift-reduce conflicts.
+       * Makefile: Modified "Expect" message to conform to new results.
+
+Thu Apr 13 12:29:26 1989  Randall Smith  (randy at plantaris.ai.mit.edu)
+
+       * inflow.c (terminal_init_inferior): Fixed typo in recent diff
+       installation; TIOGETC ==> TIOCGETC.
+
+       * m-vax.h, m-sun2.h, m-sun3.h, m-sparc.h, m-hp*.h, m-isi.h,
+       m-news.h [FRAMELESS_FUNCTION_INVOCATION]: Created macro with
+       appropriate definition.
+
+Wed Apr 12 15:30:29 1989  Randall Smith  (randy at plantaris.ai.mit.edu)
+
+       * blockframe.c (get_prev_frame_info): Added in a macro to specify
+       when a "frame" is called without a frame pointer being setup.
+
+       * Makefile [clean]: Made sure to delete gnu malloc if it was being
+       used. 
+
+Mon Apr 10 12:43:49 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * dbxread.c (process_one_symbol): Reset within_function to 0 after
+       last RBRAC of a function.
+
+       * dbxread.c (read_struct_type): Changed check for filling in of
+       TYPE_MAIN_VARIANT of type.
+
+       * inflow.c (create_inferior): Conditionalized fork so that it
+       would be used if USG was defined and HAVE_VFORK was not defined.
+
+       * defs.h: Added comment about enum command_class element
+       class_alias. 
+
+       * dbxread.c (process_one_symbol): Fixed a typo with interesting
+       implications for associative processing in the brain (':' ==> 'c').
+
+       * sparc-dep.c (isabranch): Changed name to isannulled, modified to
+       deal with coprocessor branches, and improved comment.
+       (single_step): Changed to trap at npc + 4 instead of pc +8 on
+       annulled branches.  Changed name in call to isabranch as above.
+
+       * m-sun4os4.h (STACK_END_ADDRESS): Changed it to 0xf8000000 under
+       os 4.0.
+
+Sat Apr  8 17:04:07 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * dbxread.c (process_one_symbol): In the case N_FUN or N_FNAME the
+       value being refered to is sometimes just a text segment variable.
+       Catch this case.
+
+       * infrun.c (wait_for_inferior), breakpoint.c
+       (breakpoint_stop_status): Move the selection of the frame to
+       inside breakpoint_stop_status so that the frame only gets selected
+       (and the symbols potentially read in) if the symbols are needed.
+
+       * symtab.c (find_pc_psymbol): Fixed minor misthough (pc >=
+       fucntion start, not >).
+
+       * breakpoint.c (_initialize_breakpoint): Change "delete" internal
+       help entry to simply refer to it being a prefix command (since the
+       list of subcommands is right there on a "help delete").
+
+Fri Apr  7 15:22:18 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * blockframe.c (find_pc_partial_function): Created; figures out
+       what function pc is in (name and address) without reading in any
+       new symbols.
+       * symtab.h: Added decl for above.
+       * infrun.c (wait_for_inferior): Used instead of
+       find_pc_function_start.
+       * stack.c (print_frame_info): Used instead of hand coding for same
+       thing. 
+
+       * dbxread.c (psymtab_to_symtab): No longer patch readin pst's out
+       of the partial_symtab_list; need them there for some checks.
+       * blockframe.c (block_for_pc), source.c (select_source_symtab),
+       symtab.c (lookup_symbol, find_pc_symtab, list_symbols): Made extra
+       sure not to call psymtab_to_symtab with ->readin == 1, since these
+       psymtab now stay on the list.
+       * symtab.c (sources_info): Now distinguishes between psymtabs with
+       readin set and those with it not set.
+
+       * symtab.c (lookup_symtab): Added check through partial symtabs
+       for name with .c appended.
+
+       * source.c (select_source_symtab): Changed semantics a little so
+       that the argument means something.
+       * source.c (list_command), symtab.c (decode_line_1): Changed call
+       to select_source_symtab to match new conventions.
+
+       * dbxread.c (add_file_command): This command no longer selects a
+       symbol table to list from.
+
+       * infrun.c (wait_for_inferior): Only call find_pc_function (to
+       find out if we have debugging symbols for a function and hence if
+       we should step over or into it) if we are doing a "step".
+
+Thu Apr  6 12:42:28 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * main.c (command_line_input): Added a local buffer and only
+       copied information into the global main.c buffer when it is
+       appropriate for it to be saved (and repeated).
+       (dont_repeat): Only nail line when we are reading from stdin
+       (otherwise null lines won't repeat and what's in line needs to be
+       saved).
+       (read_command_lines): Fixed typo; you don't what to repeat when
+       reading command lines from the input stream unless it's standard
+       input. 
+
+        John Gilmore's (gnu@toad.com) mods for USG gdb:
+       * inflow.c: Removed inclusion of sys/user.h; no longer necessary.
+       (, terminal_init_inferior, terminal_inferior, terminal_ours_1,
+       term_status_command, _initialize_inflow) Seperated out declaration
+       and usage of terminal mode structures based on the existence of
+       the individual ioctls.
+       * utils.c (request_quit): Restore signal handler under USG.  If
+       running under USG initialize sys_siglist at run time (too much
+       variation between systems).
+
+Wed Apr  5 13:47:24 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+        John Gilmore's (gnu@toad.com) mods for USG gdb:
+       * default-dep.c: Moved include of sys/user.h to after include of
+       a.out.h.
+       (store_inferior_registers): Fixed error message.
+       (core_file_command): Improved error messages from reading in of
+       u area in core file.  Changed calculation of offset of registers
+       to account for some machines putting it in as an offset rather
+       than an absolute address.  Changed error messages for reading of
+       registers from core file.
+
+       * coffread.c (read_file_hdr): Added final check for BADMAG macro
+       to use if couldn't recognize magic number.
+       * Makefile: Added explicit directions for alloca addition.
+       Included alloca.c in list of possible library files. Cleaned up
+       possible library usage.  Included additional information on gcc
+       and include files.  
+
+       * source.c, remote.c, inflow.c, dbxread.c, core.c, coffread.c:
+       Changed include of sys/fcntl.h to an include of fcntl.h (as per
+       posix; presumably this will break fewer machines.  I hopw).
+       * README: Added a pointer to comments at top of Makefile.
+       * Makefile: Added a comment about machines which need fcntl.h in
+       sys. 
+
+Tue Apr  4 11:29:04 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * valprint.c (set_prettyprint_command, set_unionprint_command,
+       format_info): Created.
+       (_initialize_valprint): Added to lists of commands.
+
+       * gdb.texinfo [Backtrace]: Added a section describing the format
+       if symbols have not yet been read in.
+
+       * valprint.c (val_print): Added code to prettyprint structures if
+       "prettyprint" is set and only to print unions below the top level
+       if "unionprint" is set.
+
+       * infcmd.c (registers_info), valprint.c (value_print, val_print):
+       Added argument to call to val_print indicating deptch of recursion.
+
+       * symtab.[ch] (find_pc_psymbol): Created; finds static function
+       psymbol with value nearest to but under value passed.
+       * stack.c (print_frame_info): Used above to make sure I have best
+       fit to pc value.
+
+       * symseg.h (struct partial_symbol): Added value field.
+       * dbxread.c (read_dbx_symtab): Set value field for partial symbols
+       saved (so that we can lookup static symbols).
+
+       * symtab.[ch] (find_pc_symtab): Changed to external.
+       * stack.c (select_frame): Call above to make sure that symbols for
+       a selected frame is readin.
+
+Mon Apr  3 12:48:16 1989  Randall Smith  (randy at plantaris.ai.mit.edu)
+
+       * stack.c (print_frame_info): Modified to only print out full
+       stack frame info on symbols whose tables have been read in.
+       * symtab.c, symtab.h (find_pc_psymtab): Made function external;
+       above needed it.
+
+       * main.c (,set_verbose_command, initialize_main): Created a
+       variable "info_verbose" which says to talk it up in various and
+       sundry places.  Added command to set this variable.
+       * gdb.texinfo (GDB Output): Added documentation on "set verbose"
+       and changed the name of the "Screen Output" section to "GDB
+       Output".
+       * dbxread.c (psymtab_to_symtab): Added information message about
+       symbol readin.  Conditionalized on above.
+
+       * dbxread.c (define_symbol): Made an "i" constant be of class
+       LOC_CONST and an "r" constant be of class LOC_CONST_BYTES.
+
+       * README: Made a note about modifications which may be necessary
+       to the manual for this version of gdb.
+
+       * blockframe.c (get_prev_frame_info): Now we get saved address and
+       check for validity before we check for leafism.  This means that
+       we will catch the fact that we are in start, but we will miss any
+       fns that start calls without an fp.  This should be fine.
+
+       * m-*.h (FRAME_CHAIN): Modified to return 0 if we are in start.
+       This is usually a test for within the first object file.
+       * m-sparc.h (FRAME_CHAIN): The test here is simply if the fp saved
+       off the the start sp is 0.
+
+       * blockframe.c (get_prev_frame_info): Removed check to see if we
+       were in start.  Screws up sparc.  
+
+       * m-sparc.h (FRAME_FIND_SAVED_REGISTERS): Changed test for dummy
+       frame to not need frame to be innermost.
+
+       * gdb.texinfo: Added section on frameless invocations of functions
+       and when gdb can and can't deal with this.
+
+       * stack.c (frame_info): Disallowed call if no inferior or core
+       file; fails gracefully if truely bad stack specfication has been
+       given (ie. parse_frame_specification returns 0).
+
+Fri Mar 31 13:59:33 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * infrun.c (normal_stop): Changed references to "unset-env" to
+       "delete env".
+
+       * infcmd.c (_initialize_infcmd): Change reference to set-args in
+       help run to "set args".
+
+       * remote.c (getpkt): Allow immediate quit when reading from
+       device; it could be hung.
+
+       * coffread.c (process_coff_symbol): Modify handling of REG
+       parameter symbols.
+
+Thu Mar 30 15:27:23 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * dbxread.c (symbol_file_command): Use malloc to allocate the
+       space for the string table in symbol_file_command (and setup a
+       cleanup for this).  This allows a more graceful error failure if
+       there isn't any memory availible (and probably allows more memory
+       to be avail, depending on the machine).
+
+       Additional mods for handling GNU C++ (from Tiemann):
+       * dbxread.c (read_type): Added case for '#' type (method type, I
+       believe).
+       (read_struct_type): If type code is undefined, make the main
+       variant for the type be itself.  Allow recognition of bad format
+       in reading of structure fields.
+       * eval.c (evaluate_subexp): Modify evaluation of a member of a
+       structure and pointer to same to make sure that the syntax is
+       being used correctly and that the member is being accessed correctly.
+       * symseg.h: Added TYPE_CODE_METHOD to enum type_code.  Add a
+       pointer to an array of argument types to the type structure.
+       * symtab.c (lookout_method_type, smash_to_method_type): Created.
+       * symtab.h (TYPE_ARG_TYPES): Created.
+       * valops.c (call_function): Modified handling of methods to be the
+       same as handling of functions; no longer check for members.
+       * valprint.c (val_print, type_print_varspec_{prefix,suffix},
+       type_print_base): Added code to print method args correctly.
+       * values.c (value_virtual_fn_field): Modify access to virtual
+       function table.
+
+Wed Mar 29 13:19:34 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * findvar.c: Special cases for REGISTER_WINDOWS: 1) Return 0 if we
+       are the innermost frame, and 2) return the next frame in's value
+       if the SP is being looked for.
+
+       * blockframe.c (get_next_frame): Created; returns the next (inner)
+       frame of the called frame.
+       * frame.h: Extern delcaration for above.
+
+       * main.c (command_line_input): Stick null at end before doing
+       history expansion.
+
+Tue Mar 28 17:35:50 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * dbxread.c (read_dbx_symtab): Added namestring assignment to
+       N_DATA/BSS/ABS case.  Sigh.
+
+Sat Mar 25 17:49:07 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * expread.y: Defined YYDEBUG.
+
+Fri Mar 24 20:46:55 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * symtab.c (make_symbol_completion_list): Completely rewrote to
+       never call psymtab_to_symtab, to do a correct search (no
+       duplicates) through the visible symbols, and to include structure
+       and union fields in the things that it can match.
+
+Thu Mar 23 15:27:44 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * dbxread.c (dbx_create_type): Created; allocates and inits space
+       for a type without putting it on the type vector lists.
+       (dbx_alloc_type): Uses above.
+
+       * Makefile: xgdb.o now produced by default rules for .o.c.
+
+Fri Mar 17 14:27:50 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * infrun.c: Fixed up inclusion of aouthdr.h on UMAX_PTRACE.
+
+       * Makefile, config.gdb: Added hp300bsd to potential
+       configurations.
+       * hp300bsd-dep.c, m-hp300bsd.h: Created.
+
+       * infrun.c (wait_for_inferior): Rewrote to do no access to
+       inferior until we make sure it's still there.
+
+       * inflow.c (inferior_died): Added a select to force the selected
+       frame to null when inferior dies.
+
+       * dbxread.c (symbol_file_command): free and zero symfile when
+       discarding symbols.
+
+       * core.c (xfer_core_file): Extended and cleaned up logic in
+       interpeting memory address.
+
+       * core.c (xfer_core_file): Extended opening comment.
+
+Thu Mar 16 15:39:42 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * coffread.c (symbol_file_command): Free symfile name when freeing
+       contents.
+
+       * blockframe.c (get_prev_frame_info): Added to fatal error message
+       to indicate that it should never happen.
+
+       * stack.c (frame_info): Printed out value of "saved" sp seperately
+       to call attention to the fact that it isn't stored in memory
+       anywhere; the actual previous frames address is printed.
+
+       * m-sparc.h (FRAME_FIND_SAVED_REGS): Set address of sp saved in
+       frame to value of fp (rather than value of sp in current frame).
+
+       * expread.y: Allow "unsigned" as a type itself, as well as a type
+       modifier. 
+
+       * coffread.c: Added declaration for fclose
+
+Fri Mar 10 17:22:31 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * main.c (command_line_input): Checked for -1 return from
+       readline; indicates EOF.
+
+Fri Mar  3 00:31:27 1989  Randall Smith  (randy at gluteus.ai.mit.edu)
+
+       * remote.c (remote_open): Cast return from signal to (void (*)) to
+       avoid problems on machines where the return type of signal is (int
+       (*)). 
+
+       * Makefile: Removed deletion of version control from it (users
+       will need it for their changes).
+
+Thu Mar  2 15:32:21 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * symmetry-dep.c (print_1167_regs): Print out effective doubles on
+       even number regs.
+       (fetch_inferior_registers): Get the floating point regs also.
+
+       * xgdb.c (do_command): Copied command before calling execute
+       command (so that execute_command wouldn't write into text space).
+
+       * copying.awk: Created (will produce copying.c as output when
+       given COPYING as input).
+       * Makefile: Used above to create copying.c.
+       * main.c: Took out info_warranty and info_copying.
+
+       * *.*: Changed copyright notice to use new GNU General Public
+       License (includes necessary changes to manual).
+
+       * xgdb.c (create_text_widget): Created text_widget before I create
+       the source and sink.
+       (print_prompt): Added fflush (stdout).
+
+       * Makefile: Added -lXmu to the compilation line for xgdb.  Left
+       the old one there incase people still had R2.
+
+       * README: Added note about -gg format.
+
+       * remote.c (getpkt): Fixed typo; && ==> &.
+
+       * Makefile: Added new variable READLINE_FLAGS so that I could
+       force compilation of readline.c and history.c with -DSYSV on
+       system V machines.  Mentioned in Makefile comments at top.
+
+Wed Mar  1 17:01:01 1989  Randall Smith  (randy at gluteus.ai.mit.edu)
+
+       * hp9k320-dep.c (store_inferior_registers): Fixed typo.
+
+Fri Feb 24 14:58:45 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * hp9k320-dep.c (store_inferior_registers,
+       fetch_inferior_registers): Added support for remote debugging. 
+
+       * remote.c (remote_timer): Created.
+       (remote_open, readchar): Setup to timeout reads if they take
+       longer than "timeout".  This allows one to debug how long such
+       things take.
+       (putpkt): Modified to print a debugging message (if such things
+       are enabled) each time it resends a packet.
+       (getpkt): Modified to make the variable CSUM unsigned and read it
+       CSUM with an & 0xff (presumably to deal with poor sign extension
+       on some machines).  Also made c1 and c2 unsigned.
+       (remote_wait): Changed buffer to unsigned status.
+       (remote_store_registers, remote_write_bytes): Puts a null byte at
+       the end of the control string.
+
+       * infcmd.c (attach_command, detach_command, _initialize_infcmd):
+       Made attach_command and detach_command always availible, but
+       modified them to only allow device file attaches if ATTACH_DETACH
+       is not defined.
+
+       * gdb.texinfo: Added cross reference from attach command to remote
+       debugging. 
+
+Thu Feb 23 12:37:59 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * remote.c (remote_close): Created to close the remote connection
+       and set the remote_debugging flag to 0.
+       * infcmd.c (detach_command): Now calls the above when appropriate. 
+
+       * gdb.texinfo: Removed references to the ``Distribution'' section
+       in the copyright.
+
+       * main.c, utils.c (ISATTY): Created default defintions of this
+       macro which use isatty and fileno.
+       * utils.c (fprintf_filtered, print_spaces_filtered), main.c
+       (command_loop, command_line_input): Used this macro.
+       * m-news.h: Created a definition to override this one.
+
+       * utils.c (fprintf_filtered): Made line_size static (clueless).
+
+       * utils.c (fprintf_filtered): Changed max length of line printed
+       to be 255 chars or twice the format length.
+
+       * symmetry-dep.c, m-symmetry: Fixed typo (^L ==> \f).
+
+       * printcmd.c (do_examine): Fixed typo (\n ==> \t).
+
+Wed Feb 22 16:00:33 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+        Contributed by Jay Vosburgh (jay@mentor.cc.purdue.edu)
+       * m-symmetry.h, symmetry-dep.c: Created.
+       * Makefile: Added above in appropriate lists.
+       * config.gdb: Added "symmetry" target.
+
+       * utils.c (prompt_for_continue): Zero'd chars_printed also.
+
+       * utils.c (fprintf_filtered): Call prompt for continue instead of
+       doing it yourself.
+
+       * dbxread.c (read_dbx_symtab): Added code to conditionalize what
+       symbol type holds to "x.o" or "-lx" symbol that indicates the
+       beginning of a new file.
+
+Tue Feb 21 16:22:13 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * gdb.texinfo: Deleted @ignore block at end of file.
+
+       * findvar.c, stack.c: Changed comments that refered to "frame
+       address" to "frame id".
+
+       * findvar.c (locate_var_value): Modified so that taking the
+       address of an array generates an object whose type is a pointer to
+       the elements of the array.
+
+Sat Feb 18 16:35:14 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * gdb.texinfo: Removed reference to "!" as a shell escape
+       character.  Added a section on controling screen output
+       (pagination); changing "Input" section to "User Interface"
+       section.  Changed many inappropriate subsubsection nodes into
+       subsections nodes (in the readline and history expansion
+       sections). 
+
+Fri Feb 17 11:10:54 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * utils.c (set_screensize_command): Created.
+       (_initialize_utils): Added above to setlist.
+
+       * main.c (main): Added check to see if ~/.gdbinit and .gdbinit
+       were the same file; only one gets read if so.  Had to include
+       sys/stat.h for this.
+
+       * valprint.c (type_print_base): Changed calls to print_spaces to
+       print_spaces_filtered. 
+
+       * main.c (command_line_input): Chaned test for command line
+       editing to check for stdin and isatty.
+
+       * main.c (command_loop): Call reinitialize_more_filter before each
+       command (if reading from stdin and it's a tty).
+       utils.c (initialize_more_filter): Changed name to
+       reinitialize_more_filter; killed arguments.
+       utils.c (_initialize_utils): Created; initialized lines_per_page
+       and chars_per_line here.
+
+       * utils.c (fprintf_filtered): Removed printing of "\\\n" after
+       printing linesize - 1 chars; assume that the screen display will
+       take care of that.  Still watching that overflow.
+
+       * main.c: Created the global variables linesize and pagesize to
+       describe the number of chars per line and lines per page.
+
+Thu Feb 16 17:27:43 1989  Randall Smith  (randy at gluteus.ai.mit.edu)
+
+       * printcmd.c (do_examine, print_scalar_formatted, print_address,
+       whatis_command, do_one_display, ptype_command), valprint.c
+       (value_print, val_print, type_print_method_args, type_print_1,
+       type_print_derivation_info, type_print_varspec_suffix,
+       type_print_base), breakpoint.c (breakpoints_info, breakpoint_1),
+       values.c (history_info), main.c (editing_info, warranty_info,
+       copying_info), infcmd.c (registers_info), inflow.c
+       (term_status_command), infrun.c (signals_info), stack.c
+       (backtrace_command, print_frame_info), symtab.c (list_symbols,
+       output_source_filename), command.c (help_cmd, help_list,
+       help_command_list): Replaced calls to printf, fprintf, and putc
+       with calls to [f]printf_filtered to handle more processing.
+       Killed local more emulations where I noticed them.
+
+Wed Feb 15 15:27:36 1989  Randall Smith  (randy at gluteus.ai.mit.edu)
+
+       * defs.h, utils.c (initialize_more_filter, fprintf_filtered,
+       printf_filtered): Created a printf that will also act as a more
+       filter, prompting the user for a <return> whenever the page length
+       is overflowed.
+
+       * symtab.c (list_symbols): Elminated some code inside of an #if 0. 
+
+Tue Feb 14 11:11:24 1989  Randall Smith  (randy at gluteus.ai.mit.edu)
+
+       * Makefile: Turned off backup versions for this file; it changes
+       too often.
+
+       * command.c (lookup_cmd, _initialize_command): Changed '!' so that
+       it was no longer a shell escape.  "sh" must be used.
+
+       * main.c (command_line_input, set_history_expansion,
+       initialize_main): Turned history expansion on, made it the
+       default, and only execute it if the first character in the line is
+       a '!'.
+
+       * version.c, gdb.texinfo: Moved version to 3.2 (as usual, jumping
+       the gun some time before release).
+
+       * gdb.texinfo: Added sections (adapted from Brian's notes) on
+       command line editing and history expansion.
+
+       * main.c (set_command_editing, initialize_main): Modified name to
+       set_editing and modified command to "set editing".
+
+       * Makefile: Put in dependencies for READLINEOBJS.
+
+       * main.c (history_info, command_info): Combined into new command
+       info; deleted history_info.
+       (initialize_main): Deleted "info history" command; it was
+       interfering with the value history.
+
+       * coffread.c (enter_linenos): Modified to do bit copy instead of
+       pointer dereference, since the clipper machine can't handle having
+       longs on short boundaries.
+       (read_file_hdr): Added code to get number of syms for clipper.
+
+       * stack.c (return_command): Fixed method for checking when all of
+       the necessary frames had been popped.
+
+       * dbxread.c (read_dbx_symtab (ADD_PSYMBOL_TO_LIST)): Fixed typo in
+       allocation length.
+
+Mon Feb 13 10:03:27 1989  Randall Smith  (randy at gluteus.ai.mit.edu)
+
+       * dbxread.c (read_dbx_symtab): Split assignment to namestring into
+       several different assignments (so that it wouldn't be done except
+       when it had to be).  Shortened switches and duplicated code to
+       produce the lowest possible execution time.  Commented (at top of
+       switch) which code I duplicated.
+
+       * dbxread.c (read_dbx_symtab): Modified which variables were
+       register and deleted several variables which weren't used.  Also
+       eliminated 'F' choice from subswitch, broke out strcmp's, reversed
+       compare on line 1986, and elminated test for !namestring[0]; it is
+       caught by following test for null index of ':'.
+
+Sun Feb 12 12:57:56 1989  Randall Smith  (randy at plantaris.ai.mit.edu)
+
+       * main.c (gdb_completer_word_break_characters): Turned \~ into ~.
+
+Sat Feb 11 15:39:06 1989  Randall Smith  (randy at plantaris.ai.mit.edu)
+
+       * symtab.c (find_pc_psymtab): Created; checks all psymtab's till
+       it finds pc.
+       (find_pc_symtab): Used; fatal error if psymtab found is readin
+       (should have been caught in symtab loop).
+       (lookup_symbol): Added check before scan through partial symtab
+       list for symbol name to be on the misc function vector (only if in
+       VAR_NAMESPACE).  Also made sure that psymtab's weren't fooled with
+       if they had already been read in.
+       (list_symbols): Checked through misc_function_vector for matching
+       names if we were looking for functions.
+       (make_symbol_completion_list): Checked through
+       misc_function_vector for matching names.
+       * dbxread.c (read_dbx_symtab): Don't bother to do processing on
+       global function types; this will be taken care of by the
+       misc_function hack.
+
+       * symtab.h: Modified comment on misc_function structure.
+
+Fri Feb 10 18:09:33 1989  Randall Smith  (randy at plantaris.ai.mit.edu)
+
+       * symseg.h, dbxread.c (read_dbx_symtab, init_psymbol_list,
+       start_psymtab, end_psymtab), coffread.c (_initialize_coff),
+       symtab.c (lookup_partial_symbol, list_symbols,
+       make_symbol_completion_list): Changed separate variables for
+       description of partial symbol allocation into a specific kind of
+       structure.
+
+       (read_dbx_symtab, process_symbol_for_psymtab): Moved most of
+       process_symbol_for_psymtab up into read_dbx_symtab, moved a couple
+       of symbol types down to the ingore section, streamlined (I hope)
+       code some, modularized access to psymbol lists.
+
+Thu Feb  9 13:21:19 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * main.c (command_line_input): Made sure that it could recognize
+       newlines as indications to repeat the last line.
+
+       * symtab.c (_initialize_symtab): Changed size of builtin_type_void
+       to be 1 for compatibility with gcc.
+
+       * main.c (initialize_main): Made history_expansion the default
+       when gdb is compiled with HISTORY_EXPANSION.
+
+       * readline.c, readline.h, history.c, history.h, general.h,
+       emacs_keymap.c, vi_keymap.c, keymaps.c, funmap.c: Made all of
+       these links to /gp/gnu/bash/* to keep them updated.
+       * main.c (initialize_main): Made default be command editing on. 
+
+Wed Feb  8 13:32:04 1989  & Smith  (randy at hobbes)
+
+       * dbxread.c (read_dbx_symtab): Ignore N_BSLINE on first
+       readthrough. 
+
+       * Makefile: Removed convex-dep.c from list of distribution files.
+
+Tue Feb  7 14:06:25 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * main.c: Added command lists sethistlist and unsethistlist to
+       accesible command lists.
+       (parse_binary_operation): Created to parse a on/1/yes vs. off/0/no
+       spec.
+       (set_command_edit, set_history, set_history_expansion,
+       set_history_write, set_history_size, set_history_filename,
+       command_info, history_info): Created to allow users to control
+       various aspects of command line editing.
+
+       * main.c (symbol_creation_function): Created.
+       (command_line_input, initialize_main): Added rest of stuff
+       necessary for calling bfox' command editing routines under
+       run-time control.
+       * Makefile: Included readline and history source files for command
+       editing; also made arrangements to make sure that the termcap
+       library was available.
+       * symtab.c (make_symbol_completion_list): Created.
+
+Mon Feb  6 16:25:25 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * main.c: Invented variables to control command editing.
+       command_editing_p, history_expansion_p, history_size,
+       write_history_p, history_filename.  Initialized them to default
+       values in initialize_main.
+
+       * infcmd.c (registers_info), infrun.c (signals_info), 
+       * main.c (gdb_read_line): Changed name to command_line_input.
+       (readline): Changed name to gdb_readline; added second argument
+       indicating that the read value shouldn't be saved (via malloc).
+       * infcmd.c (registers_info), infrun.c (signals_info), main.c
+       (copying_info), symtab.c (output_source_filename, MORE,
+       list_symbols): Converted to use gdb_readline in place of
+       gdb_read_line. 
+
+
+Sun Feb  5 17:34:38 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * blockframe.c (get_frame_saved_regs): Removed macro expansion
+       that had accidentally been left in the code.
+
+Sat Feb  4 17:54:14 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * main.c (gdb_read_line, readline): Added function readline and
+       converted gdb_read_line to use it.  This was a conversion to the
+       line at a time style of input, in preparation for full command
+       editing. 
+
+Fri Feb  3 12:39:03 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * dbxread.c (read_dbx_symtab): Call end_psymtab at the end of
+       read_dbx_symtab if any psymtab still needs to be completed.
+
+       * config.gdb, sun3-dep.c: Brought these into accord with the
+       actual sun2 status (no floating point period; sun3-dep.c unless
+       has os > 3.0).
+       * m-sun2os2.h: Deleted; not needed.
+
+       * config.gdb: Added a couple of aliases for machines in the
+       script. 
+
+       * infrun.c: Added inclusion of aouthdr.h inside of #ifdef UMAX
+       because ptrace needs to know about the a.out header.
+
+       * Makefile: Made dep.o depend on dep.c and config.status only.
+
+       * expread.y: Added declarations of all of the new write_exp_elt
+       functions at the include section in the top.
+
+       * Makefile: Added a YACC definition so that people can use bison
+       if they wish.
+
+       * Makefile: Added rms' XGDB-README to the distribution.
+
+       * Makefile: Added removal of init.o on a "make clean".
+
+Thu Feb  2 16:27:06 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * *-dep.c: Deleted definition of COFF_FORMAT if AOUTHDR was
+       defined since 1) We *may* (recent mail message) want to define
+       AOUTHDR under a basically BSD system, and 2) AOUTHDR is sometimes
+       a typedef in coff encapsulation setups.  Also removed #define's of
+       AOUTHDR if AOUTHDR is already defined (inside of coff format).  
+       * core.c, dbxread.c: Removed #define's of AOUTHDR if AOUTHDR is
+       already defined (inside of coff format).
+
+Tue Jan 31 12:56:01 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * GDB 3.1 released.
+
+       * values.c (modify_field): Changed test for endianness to assign
+       to integer and reference character (so that all bits would be
+       defined). 
+
+Mon Jan 30 11:41:21 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * news-dep.c: Deleted inclusion of fcntl.h; just duplicates stuff
+       found in sys/file.h.
+
+       * i386-dep.c: Included default definition of N_SET_MAGIC for
+       COFF_FORMAT.
+
+       * config.gdb: Added checks for several different operating
+       systems. 
+
+       * coffread.c (read_struct_type): Put in a flag variable so that
+       one could tell when you got to the end of a structure.
+
+       * sun3-dep.c (core_file_command): Changed #ifdef based on SUNOS4
+       to ifdef based on FPU.
+
+       * infrun.c (restore_inferior_status): Changed error message to
+       "unable to restore previously selected frame".
+
+       * dbxread.c (read_dbx_symtab): Used intermediate variable in error
+       message reporting a bad symbol type.  (scan_file_globals,
+       read_ofile_symtab, read_addl_syms): Data type of "type" changed to
+       unsigned char (which is what it is).
+       * i386-dep.c: Removed define of COFF_FORMAT if AOUTHDR is defined.
+       Removed define of a_magic to magic (taken care of by N_MAGIC).
+       (core_file_command): Zero'd core_aouthdr instead of setting magic
+       to zero.
+       * i386-pinsn.c: Changed jcxz == jCcxz in jump table.
+       (putop): Added a case for 'C'.
+       (OP_J): Added code to handle possible masking of PC value on
+       certain kinds of data.
+       m-i386gas.h: Moved COFF_ENCAPSULATE to before inclusion of
+       m-i386.h and defined NAMES_HAVE_UNDERSCORE.
+
+       * coffread.c (unrecrod_misc_function, read_coff_symtab): Added
+       symbol number on which error occured to error output.
+
+Fri Jan 27 11:55:04 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * Makefile: Removed init.c in make clean.  Removed it without -f
+       and with leading - in make ?gdb.
+
+Thu Jan 26 15:08:03 1989  Randall Smith  (randy at gluteus.ai.mit.edu)
+
+       Changes to get it to work on gould NP1.
+       * dbxread.c (read_dbx_symtab): Included cases for N_NBDATA and
+       N_NBBSS.
+       (psymtab_to_symtab): Changed declaration of hdr to
+       DECLARE_FILE_HEADERS.  Changed access to use STRING_TABLE_SIZE and
+       SYMBOL_TABLE_SIZE.
+       * gld-pinsn.c (findframe): Added declaration of framechain() as
+       FRAME_ADDR. 
+
+       * coffread.c (read_coff_symtab): Avoided treating typedefs as
+       external symbol definitions.
+
+Wed Jan 25 14:45:43 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * Makefile: Removed reference to alloca.c.  If they need it, they
+       can pull alloca.o from the gnu-emacs directory.
+
+       * version.c, gdb.texinfo: Updated version to 3.1 (jumping the gun
+       a bit so that I won't forget when I release).
+
+       * m-sun2.h, m-sun2os2.h, m-sun3os4.h, config.gdb: Modified code so
+       that default includes new sun core, ptrace, and attach-detach.
+       Added defaults for sun 2 os 2.
+
+       Modifications to reset stack limit back to what it used to be just
+       before exec.  All mods inside of #ifdef SET_STACK_LIMIT_HUGE.
+       * main.c: Added global variable original_stack_limit.
+       (main): Set original_stack_limit to original stack limit.
+       * inflow.c: Added inclusion of necessary files and external
+       reference to original_stack_limit.
+       (create_inferior): Reset stack limit to original_stack_limit.
+
+       * dbxread.c (read_dbx_symtab): Killed PROFILE_SYMBOLS ifdef.
+
+       * sparc-dep.c (isabranch): Multiplied offset by 4 before adding it
+       to addr to get target.
+
+       * Makefile: Added definition of SHELL to Makefile.
+
+       * m-sun2os4.h: Added code to define NEW_SUN_PTRACE, NEW_SUN_CORE,
+       and ATTACH_DETACH.
+       * sun3-dep.c: Added code to avoid fp regs if we are on a sun2.
+
+Tue Jan 24 17:59:14 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * dbxread.c (read_array_type): Added function.
+       (read_type): Added call to above instead of inline code.
+
+       * Makefile: Added ${GNU_MALLOC} to the list of dependencies for
+       the executables.
+
+Mon Jan 23 15:08:51 1989  Randall Smith  (randy at plantaris.ai.mit.edu)
+
+       * gdb.texinfo: Added paragraph to summary describing languages
+       with which gdb can be run.  Also added descriptions of the
+       "info-methods" and "add-file" commands.
+
+       * symseg.h: Commented a range type as having TYPE_TARGET_TYPE
+       pointing at the containing type for the range (often int).
+       * dbxread.c (read_range_type): Added code to do actual range types
+       if they are defined.  Assumed that the length of a range type is
+       the length of the target type; this is a lie, but will do until
+       somebody gets back to me as to what these silly dbx symbols mean.
+       
+       * dbxread.c (read_range_type): Added code to be more picky about
+       recognizing builtins as range types, to treat types defined as
+       subranges of themselves to be subranges of int, and to recognize
+       the char type idiom from dbx as a special case.
+
+Sun Jan 22 01:00:13 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * m-vax.h: Removed definition of FUNCTION_HAS_FRAME_POINTER.
+       * blockframe.c (get_prev_frame_info): Removed default definition
+       and use of above.  Instead conditionalized checking for leaf nodes
+       on FUNCTION_START_OFFSET (see comment in code).
+
+Sat Jan 21 16:59:19 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * dbxread.c (read_range_type): Fixed assumption that integer was
+       always type 1.
+
+       * gdb.texinfo: Fixed spelling mistake and added a note in the
+       running section making it clear that users may invoke subroutines
+       directly from gdb.
+
+       * blockframe.c: Setup a default definition for the macro
+       FUNCTION_HAS_FRAME_POINTER.
+       (get_prev_frame_info): Used this macro instead of checking
+       SKIP_PROLOGUE directly.
+       * m-vax.h: Overroad definition; all functions on the vax have
+       frame pointers.
+
+Fri Jan 20 12:25:35 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * core.c: Added default definition of N_MAGIC for COFF_FORMAT.
+
+       * xgdb.c: Installed a fix to keep the thing from dying when there
+       isn't any frame selected.
+
+       * core.c: Made a change for the UMAX system; needs a different
+       file included if using that core format. 
+
+       * Makefile: Deleted duplicate obstack.h in dbxread.c dependency.
+
+       * munch: Modified (much simpler) to cover (I hope) all cases.
+
+       * utils.c (save_cleanups, restore_cleanups): Added functions to
+       allow you to push and pop the chain of cleanups to be done.
+       * defs.h: Declared the new functions.
+       * main.c (catch_errors): Made sure that the only cleanups which
+       would be done were the ones put on the chain *after* the current
+       location. 
+
+       * m-*.h (FRAME_CHAIN_VALID): Removed check on pc in the current
+       frame being valid.
+       * blockframe.c (get_prev_frame_info): Made the assumption that if
+       a frame's pc value was within the first object file (presumed to
+       be /lib/crt0.o), that we shouldn't go any higher.
+
+       * infrun.c (wait_for_inferior): Do *not* execute check for stop pc
+       at step_resume_break if we are proceeding over a breakpoint (ie.
+       if trap_expected != 0).
+
+       * Makefile: Added -g to LDFLAGS.
+
+       * m-news.h (POP_FRAME) Fixed typo.
+
+       * printcmd.c (print_frame_args): Modified to print out register
+       params in order by .stabs entry, not by register number.
+
+       * sparc-opcode.h: Changed declaration of (struct
+       arith_imm_fmt).simm to be signed (as per architecture manual).
+       * sparc-pinsn.c (fprint_addr1, print_insn): Forced a cast to an
+       int, so that we really would get signed behaivior (default for sun
+       cc is unsigned).
+
+       * i386-dep.c (i386_get_frame_setup): Replace function with new
+       function provided by pace to fix bug in recognizing prologue.
+
+Thu Jan 19 11:01:22 1989  Randall Smith  (randy at plantaris.ai.mit.edu)
+
+       * infcmd.c (run_command): Changed error message to "Program not
+       restarted." 
+
+       * value.h: Changed "frame" field in value structure to be a
+       FRAME_ADDR (actually CORE_ADDR) so that it could survive across
+       calls. 
+
+       * m-sun.h (FRAME_FIND_SAVED_REGS): Fixed a typo.
+
+       * value.h: Added lval: "lval_reg_frame_relative" to indicate a
+       register that must be interpeted relative to a frame.  Added
+       single entry to value structure: "frame", used to indicate which
+       frame a relative regnum is relative to.
+       * findvar.c (value_from_register): Modified to correctly setup
+       these fields when needed.  Deleted section to fiddle with last
+       register copied on little endian machine; multi register
+       structures will always occupy an integral number of registers.
+       (find_saved_register): Made extern.
+       * values.c (allocate_value, allocate_repeat_value): Zero frame
+       field on creation.
+       * valops.c (value_assign): Added case for lval_reg_frame_relative;
+       copy value out, modify it, and copy it back.  Desclared
+       find_saved_register as being external.
+       * value.h: Removed addition of kludgy structure; thoroughly
+       commented file.
+       * values.c (free_value, free_all_values, clear_value_history,
+       set_internalvar, clear_internavars): Killed free_value.
+
+Wed Jan 18 20:09:39 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * value.h: Deleted struct partial_storage; left over from
+       yesterday. 
+
+       * findvar.c (value_from_register): Added code to create a value of
+       type lval_reg_partsaved if a value is in seperate registers and
+       saved in different places.
+
+Tue Jan 17 13:50:18 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * value.h: Added lval_reg_partsaved to enum lval_type and
+       commented enum lval_type.  Commented value structure.
+       Added "struct partial_register_saved" to value struct; added
+       macros to deal with structure to value.h.
+       * values.c (free_value): Created; special cases lval_reg_partsaved
+       (which has a pointer to an array which also needs to be free).
+       (free_all_values, clear_value_history, set_internalvar,
+       clear_internalvars): Modified to use free_values.
+
+       * m-sunos4.h: Changed name to sun3os4.h.
+       * m-sun2os4.h, m-sun4os4.h: Created.
+       * config.gdb: Added configuration entries for each of the above.
+       * Makefile: Added into correct lists.
+
+       * Makefile: Added dependencies on a.out.encap.h.  Made
+       a.out.encap.h dependent on a.out.gnu.h and dbxread.c dependent on
+       stab.gnu.h. 
+
+       * infrun.c, remote.c: Removed inclusion of any a.out.h files in
+       these files; they aren't needed.
+
+       * README: Added comment about bug reporting and comment about
+       xgdb. 
+
+       * Makefile: Added note to HPUX dependent section warning about
+       problems if compiled with gcc and mentioning the need to add
+       -Ihp-include to CFLAGS if you compile on those systems.  Added a
+       note about needing the GNU nm with compilers *of gdb* that use the
+       coff encapsulate feature also.  * hp-include: Made symbolic link
+       over to /gp/gnu/binutils.
+
+       * Makefile: Added TSOBS NTSOBS OBSTACK and REGEX to list of things
+       to delete in "make clean".  Also changed "squeakyclean" target as
+       "realclean". 
+
+       * findvar.c (value_from_register): Added assignment of VALUE_LVAL
+       to be lval_memory when that is appropriate (original code didn't
+       bother because it assumed that it was working with a pre lval
+       memoried value).
+
+       * expread.y (yylex): Changed to only return type THIS if the
+       symbol "$this" is defined in some block superior or equal to the
+       current expression context block.
+
+Mon Jan 16 13:56:44 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * m-*.h (FRAME_CHAIN_VALID): On machines which check the relation
+       of FRAME_SAVED_PC (thisframe) to first_object_file_end (all except
+       gould), make sure that the pc of the current frame also passes (in
+       case someone stops in _start).
+
+       * findvar.c (value_of_register): Changed error message in case of
+       no inferior or core file.
+
+       * infcmd.c (registers_info): Added a check for inferior or core
+       file; error message if not.
+
+       * main.c (gdb_read_line): Modified to take prompt as argument and
+       output it to stdout.
+       * infcmd.c (registers_info, signals_info), main.c (command_loop,
+       read_command_lines, copying_info), symtab.c (decode_line_2,
+       output_source_filename, MORE, list_symbols): Changed calling
+       convention used to call gdb_read_line.
+
+       * infcmd.c, infrun.c, main.c, symtab.c: Changed the name of the
+       function "read_line" to "gdb_read_line".
+       * breakpoint.c: Deleted external referenced to function
+       "read_line" (not needed by code).
+
+Fri Jan 13 12:22:05 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * i386-dep.c: Include a.out.encap.h if COFF_ENCAPSULATE.
+       (N_SET_MAGIC): Defined if not defined by include file.
+       (core_file_command): Used N_SET_MAGIC instead of assignment to
+       a_magic.
+       (exec_file_command): Stuck in a HEADER_SEEK_FD.
+
+       * config.gdb: Added i386-dep.c as depfile for i386gas choice.
+
+       * munch: Added -I. to cc to pick up things included by the param
+       file. 
+
+       * stab.gnu.def: Changed name to stab.def (stab.gnu.h needs this name).
+       * Makefile: Changed name here also.
+       * dbxread.c: Changed name of gnu-stab.h to stab.gnu.h.
+
+       * gnu-stab.h: Changed name to stab.gnu.h.
+       * stab.gnu.def: Added as link to binutils.
+       * Makefile: Put both in in the distribution.
+
+Thu Jan 12 11:33:49 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * dbxread.c: Made which stab.h is included dependent on
+       COFF_ENCAPSULATE; either <stab.h> or "gnu-stab.h".
+       * Makefile: Included gnu-stab.h in the list of files to include in
+       the distribution.
+       * gnu-stab.h: Made a link to /gp/gnu/binutils/stab.h
+
+       * Makefile: Included a.out.gnu.h and m-i386gas.h in list of
+       distribution files.
+       * m-i386gas.h: Changed to include m-i386.h and fiddle with it
+       instead of being a whole new file.
+       * a.out.gnu.h: Made a link to /gp/gnu/binutils/a.out.gnu.h.
+
+       Chris Hanson's changes to gdb for hp Unix.
+       * Makefile: Modified comments on hpux.
+       * hp9k320-dep.c: #define'd WOPR & moved inclusion of signal.h
+       * inflow.c: Moved around declaratiosn of <sys/fcntl.h> and
+       <sys/ioctl.h> inside of USG depends and deleted all SYSV ifdef's
+       (use USG instead).
+       * munch: Modified to accept any number of spaces between the T and
+       the symbol name.
+
+       Pace's changes to gdb to work with COFF_ENCAPSULATE (robotussin):
+       * config.gdb: Added i386gas to targets.
+       * default-dep.c: Include a.out.encap.h if COFF_ENCAPSULATE.
+       (N_SET_MAGIC): Defined if not defined by include file.
+       (core_file_command): Used N_SET_MAGIC instead of assignment to a_magic.
+       (exec_file_command): Stuck in a HEADER_SEEK_FD.
+       * infrun.c, remote.c: Added an include of a.out.encap.h if
+       COFF_ENCAPSULATE defined.  This is commented out in these two
+       files, I presume because the definitions aren't used.
+       * m-i386gas.h: Created.
+       * dbxread.c: Included defintions for USG.
+       (READ_FILE_HEADERS): Now uses HEADER_SEEK_FD if it exists.
+       (symbol_file_command): Deleted use of HEADER_SEEK_FD.
+       * core.c: Deleted extra definition of COFF_FORMAT.
+       (N_MAGIC): Defined to be a_magic if not already defined.
+       (validate_files): USed N_MAGIC instead of reading a_magic.
+
+Wed Jan 11 12:51:00 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * remote.c: Upped PBUFSIZ.
+       (getpkt): Added zeroing of c inside loop in case of error retry.
+
+       * dbxread.c (read_dbx_symtab, process_symbol_for_psymtab): Removed
+       code to not put stuff with debugging symbols in the misc function
+       list.  Had been ifdef'd out.
+
+       * gdb.texinfo: Added the fact that the return value for a function
+       is printed if you use return.
+
+       * infrun.c (wait_for_inferior): Removed test in "Have we hit
+       step_resume_breakpoint" for sp values in proper orientation.  Was
+       in there for recursive calls in functions without frame pointers
+       and it was screwing up calls to alloca.  
+
+       * dbxread.c: Added #ifdef COFF_ENCAPSULATE to include
+       a.out.encap.h.
+       (symbol_file_command): Do HEADER_SEEK_FD when defined.
+       * dbxread.c, core.c: Deleted #ifdef ROBOTUSSIN stuff.
+       * robotussin.h: Deleted local copy (was symlink).
+       * a.out.encap.h: Created symlink to
+       /gp/gnu/binutils/a.out.encap.h.
+       * Makefile: Removed robotussin.h and included a.out.encap.h in
+       list of files.
+
+       * valprint.c (val_print, print_scalar_formatted): Changed default
+       precision of printing float value; now 6 for a float and 16 for a
+       double.
+
+       * findvar.c (value_from_register): Added code to deal with the
+       case where a value is spread over several registers.  Still don't
+       deal with the case when some registers are saved in memory and
+       some aren't.
+
+Tue Jan 10 17:04:04 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * xgdb.c (xgdb_create_window): Removed third arg (XtDepth) to
+       frameArgs.  
+
+       * infrun.c (handle_command): Error if signal number is less or
+       equal to 0 or greater or equal to NSIG or a signal number is not
+       provided.
+
+       * command.c (lookup_cmd): Modified to not convert command section
+       of command line to lower case in place (in case it isn't a
+       subcommand, but an argument to a command).
+
+Fri Jan  6 17:57:34 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * dbxread.c: Changed "text area" to "data area" in comments on
+       N_SETV. 
+
+Wed Jan  4 12:29:54 1989  Randall Smith  (randy at gluteus.ai.mit.edu)
+
+       * dbxread.c: Added definitions of gnu symbol types after inclusion
+       of a.out.h and stab.h.
+
+Mon Jan  2 20:38:31 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * eval.c (evaluate_subexp): Binary logical operations needed to
+       know type to determine whether second value should be evaluated.
+       Modified to discover type before binup_user_defined_p branch.
+       Also commented "enum noside".
+
+       * Makefile: Changed invocations of munch to be "./munch".
+
+       * gdb.texinfo: Updated to refer to current version of gdb with
+       January 1989 last update.
+
+       * coffread.c (end_symtab): Zero context stack when finishing
+       lexical contexts.
+       (read_coff_symtab): error if context stack 0 in ".ef" else case.
+
+       * m-*.h (FRAME_SAVED_PC): Changed name of argument from "frame" to
+       "FRAME" to avoid problems with replacement of "->frame" part of
+       macro. 
+
+       * i386-dep.c (i386_get_frame_setup): Added codestream_get() to
+       move codestream pointer up to the correct location in "subl $X,
+       %esp" case.
+
+Sun Jan  1 14:24:35 1989  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * valprint.c (val_print): Rewrote routine to print string pointed
+       to by char pointer; was producing incorrect results when print_max
+       was 0.
+
+Fri Dec 30 12:13:35 1988  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * dbxread.c (read_dbx_symtab, process_symbol_for_psymtab): Put
+       everything on the misc function list.
+
+       * Checkpointed distribution.
+
+       * Makefile: Added expread.tab.c to the list of things slated for
+       distribution. 
+
+Thu Dec 29 10:06:41 1988  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * stack.c (set_backtrace_limit_command, backtrace_limit_info,
+       bactrace_command, _initialize_stack): Removed modifications for
+       limit on backtrace.  Piping the backtrace through an interuptable
+       "more" emulation is a better way to do it.
+
+Wed Dec 28 11:43:09 1988  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * stack.c
+       (set_backtrace_limit_command): Added command to set a limit to the
+       number of frames for a backtrace to print by default.
+       (backtrace_limit_info): To print the current limit.
+       (backtrace_command): To use the limit.
+       (_initialize_stack): To initialize the limit to its default value
+       (30), and add the set and info commands onto the appropriate
+       command lists.
+
+       * gdb.texinfo: Documented changes to "backtrace" and "commands"
+       commands.
+
+       * stack.c (backtrace_command): Altered so that a negative argument
+       would show the last few frames on the stack instead of the first
+       few.
+       (_initialize_stack): Modified help documentation.
+
+       * breakpoint.c (commands_command): Altered so that "commands" with
+       no argument would refer to the last breakpoint set.
+       (_initialize_breakpoint): Modified help documentation.
+
+       * infrun.c (wait_for_inferior): Removed ifdef on Sun4; now you can
+       single step through compiler generated sub calls and will die if
+       you next off of the end of a function.
+
+       * sparc-dep.c (single_step): Fixed typo; "break_insn" ==> "sizeof
+       break_insn". 
+
+       * m-sparc.h (INIT_EXTRA_FRAME_INFO): Set the bottom of a stack
+       frame to be the bottom of the stack frame inner from this, if that
+       inner one is a leaf node.
+
+       * dbxread.c (read_dbx_symtab): Check to make sure we don't add a
+       psymtab to it's own dependency list.
+
+       * dbxread.c (read_dbx_symtab): Modified check for duplicate
+       dependencies to catch them correctly.
+
+Tue Dec 27 17:02:09 1988  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * m-*.h (FRAME_SAVED_PC): Modified macro to take frame info
+       pointer as argument.
+       * stack.c (frame_info), blockframe.c (get_prev_frame_info),
+       gld-pinsn.c (findframe), m-*.h (SAVED_PC_AFTER_CALL,
+       FRAME_CHAIN_VALID, FRAME_NUM_ARGS): Changed usage of macros to
+       conform to above.
+       * m-sparc.h (FRAME_SAVED_PC), sparc-dep.c (frame_saved_pc):
+       Changed frame_saved_pc to have a frame info pointer as an
+       argument. 
+
+       * m-vax.h, m-umax.h, m-npl.h, infrun.c (wait_for_inferior),
+       blockframe.c (get_prev_frame_info): Modified SAVED_PC_AFTER_CALL
+       to take a frame info pointer as an argument.
+
+       * blockframe.c (get_prev_frame_info): Altered the use of the
+       macros FRAME_CHAIN, FRAME_CHAIN_VALID, and FRAME_CHAIN_COMBINE to
+       use frame info pointers as arguments instead of frame addresses.
+       * m-vax.h, m-umax.h, m-sun3.h, m-sun3.h, m-sparc.h, m-pn.h,
+       m-npl.h, m-news.h, m-merlin.h, m-isi.h, m-hp9k320.h, m-i386.h:
+       Modified definitions of the above macros to suit.
+       * m-pn.h, m-npl.h, gould-dep.c (findframe): Modified findframe to
+       use a frame info argument; also fixed internals (wouldn't work
+       before).
+
+       * m-sparc.h: Cosmetic changes; reordered some macros and made sure
+       that nothing went over 80 lines.
+
+Thu Dec 22 11:49:15 1988  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * Version 3.0 released.
+
+       * README: Deleted note about changing -lobstack to obstack.o.
+
+Wed Dec 21 11:12:47 1988  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * m-vax.h (SKIP_PROLOGUE): Now recognizes gcc prologue also.
+
+       * blockframe.c (get_prev_frame_info): Added FUNCTION_START_OFFSET
+       to result of get_pc_function_start.
+       * infrun.c (wait_for_inferior): Same.
+
+       * gdb.texinfo: Documented new "step" and "next" behavior in
+       functions without line number information.
+
+Tue Dec 20 18:00:45 1988  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * infcmd.c (step_1): Changed behavior of "step" or "next" in a
+       function witout line number information.  It now sets the step
+       range around the function (to single step out of it) using the
+       misc function vector, warns the user, and continues.
+
+       * symtab.c (find_pc_line): Zero "end" subsection of returned
+       symtab_and_line if no symtab found.
+
+Mon Dec 19 17:44:35 1988  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * i386-pinsn.c (OP_REG): Added code from pace to streamline
+       disassembly and corrected types.
+       * i386-dep.c
+       (i386_follow_jump): Code added to follow byte and word offset
+       branches.
+       (i386_get_frame_setup): Expanded to deal with more wide ranging
+       function prologue.
+       (i386_frame_find_saved_regs, i386_skip_prologue): Changed to use
+       i386_get_frame_setup. 
+       
+
+Sun Dec 18 11:15:03 1988  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * m-sparc.h: Deleted definition of SUN4_COMPILER_BUG; was designed
+       to avoid something that I consider a bug in our code, not theirs,
+       and which I fixed earlier.  Also deleted definition of
+       CANNOT_USE_ARBITRARY_FRAME; no longer used anywhere.
+       FRAME_SPECIFICATION_DYADIC used instead.
+
+       * infrun.c (wait_for_inferior): On the sun 4, if a function
+       doesn't have a prologue, a next over it single steps into it.
+       This gets around the problem of a "call .stret4" at the end of
+       functions returning structures.
+       * m-sparc.h: Defined SUN4_COMPILER_FEATURE.
+
+       * main.c (copying_info): Seperated the last printf into two
+       printfs.  The 386 compiler will now handle it.
+
+       * i386-pinsn.c, i386-dep.c: Moved print_387_control_word,
+       print_387_status_word, print_387_status, and i386_float_info to
+       dep.c  Also included reg.h in dep.c.
+
+Sat Dec 17 15:31:38 1988  Randall Smith  (randy at gluteus.ai.mit.edu)
+
+       * main.c (source_command): Don't close instream if it's null
+       (indicating execution of a user-defined command).
+                (execute_command): Set instream to null before executing
+                commands and setup clean stuff to put it back on error.
+
+       * inflow.c (terminal_inferior): Went back to not checking the
+       ioctl returns; there are some systems when this will simply fail.
+       It seems that, on most of these systems, nothing bad will happen
+       by that failure.
+
+       * values.c (value_static_field): Fixed dereferencing of null
+       pointer. 
+
+       * i386-dep.c (i386_follow_jump): Modified to deal with
+       unconditional byte offsets also.
+
+       * dbxread.c (read_type): Fixed typo in function type case of switch.
+
+       * infcmd.c (run_command): Does not prompt to restart if command is
+       not from a tty.
+
+Fri Dec 16 15:21:58 1988  Randy Smith  (randy at calvin)
+
+       * gdb.texinfo: Added a third option under the "Cannot Insert
+       Breakpoints" workarounds.
+
+       * printcmd.c (display_command): Don't do the display unless there
+       is an active inferior; only set it.
+
+       * findvar.c (value_of_register): Added an error check for calling
+       this when the inferior isn't active and a core file isn't being
+       read. 
+
+       * config.gdb: Added reminder about modifying REGEX in the
+       makefile for the 386.
+
+       * i386-pinsn.c, i386-dep.c: Moved m-i386.h helper functions over
+       to i386-dep.c.b
+
+Thu Dec 15 14:04:25 1988  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * README: Added a couple of notes about compiling gdb with itself.
+
+       * breakpoint.c (set_momentary_breakpoint): Only takes FRAME_FP of
+       frame if frame is non-zero.
+
+       * printcmd.c (print_scalar_formatted): Implemented /g size for
+       hexadecimal format on machines without an 8 byte integer type.  It
+       seems to be non-trivial to implement /g for other formats.
+       (decode_format): Allowed hexadecimal format to make it through /g
+       fileter. 
+
+Wed Dec 14 13:27:04 1988  Randall Smith  (randy at gluteus.ai.mit.edu)
+
+       * expread.y: Converted all calls to write_exp_elt from the parser
+       to calls to one of write_exp_elt_{opcode, sym, longcst, dblcst,
+       char, type, intern}.  Created all of these routines.  This gets
+       around possible problems in passing one of these things in one ear
+       and getting something different out the other.  Eliminated
+       SUN4_COMPILER_BUG ifdef's; they are now superfluous.
+
+       * symmisc.c (free_all_psymtabs): Reinited partial_symtab_list to 0.
+                   (_initialize_symmisc): Initialized both symtab_list and
+                   partial_symtab_list.
+
+       * dbxread.c (start_psymtab): Didn't allocate anything on
+       dependency list.
+       (end_psymtab): Allocate dependency list on psymbol obstack from
+       local list.
+       (add_psymtab_dependency): Deleted.
+       (read_dbx_symtab): Put dependency on local list if it isn't on it
+       already.
+
+       * symtab.c: Added definition of psymbol_obstack.
+       * symtab.h: Added declaration of psymbol_obstack.
+       * symmisc.c (free_all_psymtabs): Added freeing and
+       reinitionaliztion of psymbol_obstack.
+       * dbxread.c (free_all_psymbols): Deleted.
+                   (start_psymtab, end_psymtab,
+                   process_symbol_for_psymtab):  Changed most allocation
+                   of partial symbol stuff to be off of psymbol_obstack.
+
+       * symmisc.c (free_psymtab, free_all_psymtabs): Deleted
+       free_psymtab subroutine.
+
+       * symtab.h: Removed num_includes and includes from partial_symtab
+       structure; no longer needed now that all include files have their
+       own psymtab.
+       * dbxread.c (start_psymtab): Eliminated initialization of above.
+                   (end_psymtab): Eliminated finalization of above; get
+                   includes from seperate list.
+                   (read_dbx_symtab): Moved includes from psymtab list to
+                   their own list; included in call to end_psymtab.
+       * symmisc.c (free_psymtab): Don't free includes.
+
+Tue Dec 13 14:48:14 1988  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * i386-pinsn.c: Reformatted entire file to correspond to gnu
+       software indentation conventions.
+
+       * sparc-dep.c (skip_prologue): Added capability of recognizign
+       stores of input register parameters into stack slots. 
+
+       * sparc-dep.c: Added an include of sparc-opcode.h.
+       * sparc-pinsn.c, sparc-opcode.h: Moved insn_fmt structures and
+       unions from pinsn.c to opcode.h.
+       * sparc-pinsn.c, sparc-dep.c (isabranch, skip_prologue): Moved
+       this function from pinsn.c to dep.c.
+
+       * Makefile: Put in warnings about compiling with gcc (non-ansi
+       include files) and compiling with shared libs on Sunos 4.0 (can't
+       debug something that's been compiled that way).
+
+       * sparc-pinsn.c: Put in a completely new file (provided by
+       Tiemann) to handle floating point disassembly, load and store
+       instructions, and etc. better.  Made the modifications this file
+       (ChangeLog) list for sparc-pinsn.c again.
+
+       * symtab.c (output_source_filename): Included "more" emulation hack.
+
+       * symtab.c (output_source_filename): Initialized COLUMN to 0.
+                  (sources_info): Modified to not print out a line for
+                  all of the include files within a partial symtab (since
+                  they have pst's of their own now).  Also modified to
+                  make a distinction between those pst's read in and
+                  those not.
+
+       * infrun.c: Included void declaration of single_step() if it's
+       going to be used.
+       * sparc-dep.c (single_step): Moved function previous to use of it.
+
+       * Makefile: Took removal of expread.tab.c out of make clean entry
+       and put it into a new "squeakyclean" entry.
+
+Mon Dec 12 13:21:02 1988  Randall Smith  (randy at gluteus.ai.mit.edu)
+
+       * sparc-pinsn.c (skip_prologue): Changed a struct insn_fmt to a
+       union insn_fmt.
+
+       * inflow.c (terminal_inferior): Checked *all* return codes from
+       ioctl's and fcntl's in routine.
+
+       * inflow.c (terminal_inferior): Added check for sucess of
+       TIOCSPGRP ioctl call.  Just notifies if bad.
+
+       * dbxread.c (symbol_file_command): Close was getting called twice;
+       once directly and once through cleanup.  Killed the direct call.  
+
+Sun Dec 11 19:40:40 1988  & Smith  (randy at hobbes.ai.mit.edu)
+
+       * valprint.c (val_print): Deleted spurious printing of "=" from
+       TYPE_CODE_REF case.
+
+Sat Dec 10 16:41:07 1988  Randall Smith  (randy at gluteus.ai.mit.edu)
+
+       * dbxread.c: Changed allocation of psymbols from using malloc and
+       realloc to using obstacks.  This means they aren't realloc'd out
+       from under the pointers to them.
+
+Fri Dec  9 10:33:24 1988  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * sparc-dep.c inflow.c core.c expread.y command.c infrun.c
+       infcmd.c dbxread.c symmisc.c symtab.c printcmd.c valprint.c
+       values.c source.c stack.c findvar.c breakpoint.c blockframe.c
+       main.c: Various cleanups inspired by "gcc -Wall" (without checking
+       for implicit declarations).
+
+       * Makefile: Cleaned up some more.
+
+       * valops.c, m-*.h (FIX_CALL_DUMMY): Modified to take 5 arguments
+       as per what sparc needs (programming for a superset of needed
+       args).
+
+       * dbxread.c (process_symbol_for_psymtab): Modified to be slightly
+       more picky about what it puts on the list of things *not* to be
+       put on the misc function list.  When/if I shift everything over to
+       being placed on the misc_function_list, this will go away.
+
+       * inferior.h, infrun.c: Added fields to save in inferior_status
+       structure. 
+
+       * maketarfile: Deleted; functionality is in Makefile now.
+
+       * infrun.c (wait_for_inferior): Modified algorithm for determining
+       whether or not a single-step was through a subroutine call.  See
+       comments at top of file.
+
+       * dbxread.c (read_dbx_symtab): Made sure that the IGNORE_SYMBOL
+       macro would be checked during initial readin.
+
+       * dbxread.c (read_ofile_symtab): Added macro GCC_COMPILED_FLAG_SYMBOL
+       into dbxread.c to indicate what string in a local text symbol will
+       indicate a file compiled with gcc.  Defaults to "gcc_compiled.".
+
+Thu Dec  8 11:46:22 1988  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * m-sparc.h (FRAME_FIND_SAVED_REGS): Cleaned up a little to take
+       advantage of the new frame cache system.
+
+       * inferior.h, infrun.c, valops.c, valops.c, infcmd.c:  Changed
+       mechanism to save inferior status over calls to inferior (eg.
+       call_function); implemented save_inferior_info and
+       restore_inferior_info.
+
+       * blockframe.c (get_prev_frame): Simplified this by a direct call
+       to get_prev_frame_info.
+
+       * frame.h, stack.c, printcmd.c, m-sparc.h, sparc-dep.c: Removed
+       all uses of frame_id_from_addr.  There are short routines like it
+       still in frame_saved_pc (m-sparc.h) and parse_frame_spec
+       (stack.c).  Eventually the one in frame_saved_pc will go away.
+
+       * infcmd.c, sparc-dep.c: Implemented a new mechanism for
+       re-selecting the selected frame on return from a call.
+
+       * blockframe.c, stack.c, findvar.c, printcmd.c, m-*.h:  Changed
+       all routines and macros that took a "struct frame_info" as an
+       argument to take a "struct frame_info *".  Routines: findarg,
+       framechain, print_frame_args, FRAME_ARGS_ADDRESS,
+       FRAME_STRUCT_ARGS_ADDRESS, FRAME_LOCALS_ADDRESS, FRAME_NUM_ARGS,
+       FRAME_FIND_SAVED_REGS.
+
+       * frame.h, stack.c, printcmd.c, infcmd.c, findvar.c, breakpoint.c,
+       blockframe.c, xgdb.c, i386-pinsn.c, gld-pinsn.c, m-umax.h,
+       m-sun2.h, m-sun3.h, m-sparc.h, m-pn.h, m-npl.h, m-news.h,
+       m-merlin.h, m-isi.h, m-i386.h, m-hp9k320.h:  Changed routines to
+       use "struct frame_info *" internally.
+
+Wed Dec  7 12:07:54 1988  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * frame.h, blockframe.c, m-sparc.h, sparc-dep.c: Changed all calls
+       to get_[prev_]frame_cache_item to get_[prev_]frame_info.
+
+       * blockframe.c: Elminated get_frame_cache_item and
+       get_prev_frame_cache_item; functionality now taken care of by
+       get_frame_info and get_prev_frame_info.
+
+       * blockframe.c: Put allocation on an obstack and eliminated fancy
+       reallocation routines, several variables, and various nasty
+       things. 
+
+       * frame.h, stack.c, infrun.c, blockframe.c, sparc-dep.c: Changed
+       type FRAME to be a typedef to "struct frame_info *".  Had to also
+       change routines that returned frame id's to return the pointer
+       instead of the cache index.
+
+       * infcmd.c (finish_command): Used proper method of getting from
+       function symbol to start of function.  Was treating a symbol as a
+       value. 
+
+       * blockframe.c, breakpoint.c, findvar.c, infcmd.c, stack.c,
+       xgdb.c, i386-pinsn.c, frame.h, m-hp9k320.h, m-i386.h, m-isi.h,
+       m-merlin.h, m-news.h, m-npl.h, m-pn.h, m-sparc.h, m-sun2.h,
+       m-sun3.h, m-umax.h: Changed get_frame_info and get_prev_frame_info
+       to return pointers instead of structures.
+
+       * blockframe.c (get_pc_function_start): Modified to go to misc
+       function table instead of bombing if pc was in a block without a
+       containing function.
+
+       * coffread.c: Dup'd descriptor passed to read_coff_symtab and
+       fdopen'd it so that there wouldn't be multiple closes on the same
+       fd.  Also put (fclose, stream) on the cleanup list.
+
+       * printcmd.c, stack.c: Changed print_frame_args to take a
+       frame_info struct as argument instead of the address of the args
+       to the frame.
+
+       * m-i386.h (STORE_STRUCT_RETURN): Decremented sp by sizeof object
+       to store (an address) rather than 1.
+
+       * dbxread.c (read_dbx_symtab): Set first_object_file_end in
+       read_dbx_symtab (oops).
+
+       * coffread.c (fill_in_vptr_fieldno): Rewrote TYPE_BASECLASS as
+       necessary. 
+
+Tue Dec  6 13:03:43 1988  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * coffread.c: Added fake support for partial_symtabs to allow
+       compilation and execution without there use.
+       * inflow.c: Added a couple of minor USG mods.
+       * munch: Put in appropriate conditionals so that it would work on
+       USG systems.
+       * Makefile: Made regex.* handled same as obstack.*; made sure tar
+       file included everything I wanted it to include (including
+       malloc.c).
+
+       * dbxread.c (end_psymtab): Create an entry in the
+       partial_symtab_list for each subfile of the .o file just read in.
+       This allows a "list expread.y:10" to work when we haven't read in
+       expread.o's symbol stuff yet.
+
+       * symtab.h, dbxread.c (psymtab_to_symtab): Recognize pst->ldsymlen
+       == 0 as indicating a dummy psymtab, only in existence to cause the
+       dependency list to be read in.
+
+       * dbxread.c (sort_symtab_syms): Elminated reversal of symbols to
+       make sure that register debug symbol decls always come before
+       parameter symbols.  After mod below, this is not needed.
+
+       * symtab.c (lookup_block_symbol): Take parameter type symbols
+       (LOC_ARG or LOC_REGPARM) after any other symbols which match.
+
+       * dbxread.c (read_type): When defining a type in terms of some
+       other type and the other type is supposed to have a pointer back
+       to this specific kind of type (pointer, reference, or function),
+       check to see if *that* type has been created yet.  If it has, use
+       it and fill in the appropriate slot with a pointer to it.
+
+Mon Dec  5 11:25:04 1988  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * symmisc.c: Eliminated existence of free_inclink_symtabs and
+       init_free_inclink_symtabs; they aren't called from anywhere, and
+       if they were they could disrupt gdb's data structure badly
+       (elimination of struct type's which values that stick around past
+       elimination of inclink symtabs).
+
+       * dbxread.c (symbol_file_command): Fixed a return pathway out of
+       the routine to do_cleanups before it left.
+
+       * infcmd.c (set_environment_command), gdb.texinfo: Added
+       capability to set environmental variable values to null.
+
+       * gdb.texinfo: Modified doc on "break" without args slightly.
+
+Sun Dec  4 17:03:16 1988  Randall Smith  (randy at gluteus.ai.mit.edu)
+
+       * dbxread.c (symbol_file_command): Added check; if there weren't
+       any debugging symbols in the file just read, the user is warned.
+
+       * infcmd.c: Commented set_environment_command (a little).
+
+       * createtags: Cleaned up and commented.
+
+       * Makefile: Updated depen_memory and write_inferior_memory in that errno is
+       checked after each ptrace and returned to the caller.  Used in
+       value_at to detect references to addresses which are out of
+       bounds.  Also core.c (xfer_core_file): return 1 if invalid
+       address, 0 otherwise.
+
+       * inflow.c, <machine>-infdep.c: removed all calls to ptrace from
+       inflo, m-sun3.h:  Cleaned up dealings with
+       functions returning structu0 19:19:36 1988  Peter TerMaat  (pete at corn-chex.ai.mit.edu)
+
+       * symmisc.c: (read_symsegs) Accept only format number 2.  Since
+       the size of the type structure changed when C++ support was added,
+       format 1 can no longer be used.
+
+       * core.c, m-sunos4.h: (core_file_command) support for SunOS 4.0.
+       Slight change in the core structure.  #ifdef SUNOS4.  New file
+       m-sunos4.h.  May want to change config.gdb also.
+
+Fri Jul  8 19:59:49 1988  Peter TerMaat  (pete at corn-chex.ai.mit.edu)
+
+       * breakpoint.c: (break_command_1) Allow `break if condition'
+       rather than parsing `if' as a function name and returning an
+       error.
+
+Thu Jul  7 22:22:47 1988  Peter TerMaat  (pete at corn-chex.ai.mit.edu)
+
+       * C++: valops.c, valprint.c, value.h, values.c: merged code to deal
+       with C++ expressions.
+
+Wed Jul  6 03:28:18 1988  Peter TerMaat  (pete at corn-chex.ai.mit.edu)
+
+        * C++: dbxread.c: (read_dbx_symtab, condense_misc_bunches,
+       add_file_command)  Merged code to read symbol information from
+       an incrementally linked file.  symmisc.c:
+       (init_free_inclink_symtabs, free_inclink_symtabs) Cleanup
+       routines.
+
+Tue Jul  5 02:50:41 1988  Peter TerMaat  (pete at corn-chex.ai.mit.edu)
+
+       * C++: symtab.c, breakpoint.c, source.c:  Merged code to deal with
+       ambiguous line specifications.  In C++ one can have overloaded
+       function names, so that `list classname::overloadedfuncname'
+       refers to several different lines, possibly  sure currently configured machine
+       dependent files come first in e at corn-chex.ai.mit.edu)
+
+       * C++: symtab.c: replaced lookup_symtab_1 and lookup_symtab_2 with
+       a modified lookup_symbol which checks for fields of the current
+       implied argument `this'.  printcmd.c, source.c, symtab.c,
+       valops.c: Need to change callers once callers are
+       installed. 
+
+Wed Jun 29 01:26:56 1988  Peter TerMaat  (pete at frosted-flakes.ai.mit.edu)
+
+       * C++: eval.c, expprint.c, expread.y, expression.h, valarith.c, 
+       Merged code to deal with evaluation of user-defined operators,
+       member functions, and virtual functions.
+       binop_must_be_user_defined tests for user-defined binops, 
+       value_x_binop calls the appropriate operator function. 
+
+Tue Jun 28 02:56:42 1988  Peter TerMaat  (pete at frosted-flakes.ai.mit.edu)
+
+       * C++: Makefile: changed the echo: expect 101 shift/reduce conflicts 
+       and 1 reduce/reduce conflict.
+
+\f
+Local Variables:
+mode: indented-text
+eval: (auto-fill-mode 1)
+left-margin: 8
+fill-column: 74
+version-control: never
+End:
+\0ng destructors and
+               constructors, and flags being defined via public and via
+               virtual paths.  Added fields NEXT_VARIANT, N_BASECLASSES,
+               and BASECLASSES to this type (tr: Changed types from
+               having to be derived from a single baseclass to a multiple
+               base class).
+       * symtab.h: Added macros to access new fields defined in symseg.h.
+               Added decl for lookup_basetype_type.
+       * dbxread.c 
+       (condense_addl_misc_bunches): Function added to condense the misc
+               function bunches added by reading in a new .o file.
+       (read_addl_syms): Function added to read in symbols
+               from a new .o file (incremental linking).
+       (add_file_command): Command interface function to indicate
+               incrmental linking of a new .o file; this now calls
+               read_addl_syms and condense_addl_misc_bunches.
+       (define_symbol): Modified code to handle types defined from base
+               types which were not known when the derived class was
+               output.
+       (read_struct_type): Modified to better handle description of
+               struct types as derived types.  Possibly derived from
+               several different base classes.  Also added new code to
+               mark definitions via virtual paths or via public paths.
+               Killed seperate code to handle classes with destructors
+               but without constructors and improved marking of classes
+               as having destructors and constructors.
+       * infcmd.c: Modified call to val_print (one more argument).
+       * symtab.c (lookup_member_type): Modified to deal with new
+               structure in symseg.h.
+       (lookup_basetype_type): Function added to find or construct a type
+               ?derived? from the given type.
+       (decode_line_1): Modified to deal with new type data structures.
+               Modified to deal with new number of args for
+               decode_line_2.
+       (decode_line_2): Changed number of args (?why?).
+       (init_type): Added inits for new C++ fields from
+               symseg.h.
+       *valarith.c
+       (value_x_binop, value_binop): Added cases for BINOP_MIN &
+               BINOP_MAX.
+       * valops.c
+       (value_struct_elt, check_field, value_struct_elt_for_address):
+               Changed to deal with multiple possible baseclasses.
+       (value_of_this): Made SELECTED_FRAME an extern variable.
+       * valprint.c
+       (val_print): Added an argument DEREF_REF to dereference references
+               automatically, instead of printing them like pointers.
+               Changed number of arguments in recursive calls to itself.
+               Changed to deal with varibale numbers of base classes.
+       (value_print): Changed number of arguments to val_print.  Print
+               type of value also if value is a reference.
+       (type_print_derivation_info): Added function to print out
+               derivation info a a type.
+       (type_print_base): Modified to use type_print_derivation_info and
+               to handle multiple baseclasses.
+       
+Mon Nov 21 10:32:07 1988  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * inflow.c (term_status_command): Add trailing newline to output. 
+
+       * sparc-dep.c (do_save_insn, do_restore_insn): Saved
+       "stop_registers" over the call for the sake of normal_stop and
+       run_stack_dummy.
+
+       * m-sparc.h (EXTRACT_RETURN_VALUE): Put in parenthesis to force
+       addition of 8 to the int pointer, not the char pointer.
+
+       * sparc-pinsn.c (print_addr1): Believe that I have gotten the
+       syntax right for loads and stores as adb does it.
+
+       * symtab.c (list_symbols): Turned search for match on rexegp into
+       a single loop.
+
+       * dbxread.c (psymtab_to_symtab): Don't read it in if it's already
+       been read in.
+
+       * dbxread.c (psymtab_to_symtab): Changed error to fatal in
+       psymtab_to_symtab. 
+
+       * expread.y (parse_number): Fixed bug which treated 'l' at end of
+       number as '0'.
+
+Fri Nov 18 13:57:33 1988  Randall Smith  (randy at gluteus.ai.mit.edu)
+
+       * dbxread.c (read_dbx_symtab, process_symbol_for_psymtab): Was
+       being foolish and using pointers into an array I could realloc.
+       Converted these pointers into integers.
+
+Wed Nov 16 11:43:10 1988  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * m-sparc.h (POP_FRAME): Made the new frame be PC_ADJUST of the
+       old frame.
+
+       * i386-pinsn.c, m-hp9k320.h, m-isi.h, m-merlin.h, m-news.h,
+       m-npl.h, m-pn.h, m-sparc.h, m-sun2.h, m-sun3.h, m-umax.h, m-vax.h:
+       Modified POP_FRAME to use the current frame instead of
+       read_register (FP_REGNUM) and to flush_cached_frames before
+       setting the current frame.  Also added a call to set the current
+       frame in those POP_FRAMEs that didn't have it.
+
+       * infrun.c (wait_for_inferior): Moved call to set_current_frame up
+       to guarrantee that the current frame will always be set when a
+       POP_FRAME is done.  
+
+       * infrun.c (normal_stop): Added something to reset the pc of the
+       current frame (was incorrect because of DECR_PC_AFTER_BREAK).
+
+       * valprint.c (val_print): Changed to check to see if a string was
+       out of bounds when being printed and to indicate this if so.
+
+       * convex-dep.c (read_inferior_memory): Changed to return the value
+       of errno if the call failed (which will be 0 if the call
+       suceeded). 
+
+Tue Nov 15 10:17:15 1988  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * infrun.c (wait_for_inferior): Two changes: 1) Added code to
+       not trigger the step breakpoint on recursive calls to functions
+       without frame info, and 2) Added calls to distinguish recursive
+       calls within a function without a frame (which next/nexti might
+       wish to step over) from jumps to the beginning of a function
+       (which it generally doesn't).
+
+       * m-sparc.h (INIT_EXTRA_FRAME_INFO): Bottom set correctly for leaf
+       parents. 
+
+       * blockframe.c (get_prev_frame_cache_item): Put in mod to check
+       for a leaf node (by presence or lack of function prologue).  If
+       there is a leaf node, it is assumed that SAVED_PC_AFTER_CALL is
+       valid.  Otherwise, FRAME_SAVED_PC or read_pc is used.
+
+       * blockframe.c, frame.h: Did final deletion of unused routines and
+       commented problems with getting a pointer into the frame cache in
+       the frame_info structure comment.
+
+       * blockframe.c, frame.h, stack.c: Killed use of
+       frame_id_from_frame_info; used frame_id_from_addr instead.
+
+       * blockframe.c, frame.h, stack.c, others (oops): Combined stack
+       cache and frame info structures.
+
+       * blockframe.c, sparc-dep.c, stack.c: Created the function
+       create_new_frame and used it in place of bad calls to
+       frame_id_from_addr. 
+
+       * blockframe.c, inflow.c, infrun.c, i386-pinsn.c, m-hp9k320.h,
+       m-npl.h, m-pn.h, m-sparc.h, m-sun3.h, m-vax.h, default-dep.c,
+       convex-dep.c, gould-dep.c, hp9k320-dep.c, news-dep.c, sparc-dep.c,
+       sun3-dep.c, umax-dep.c: Killed use of
+       set_current_Frame_by_address.  Used set_current_frame
+       (create_new_frame...) instead.
+
+       * frame.h: Killed use of FRAME_FP_ID.
+
+       * infrun.c, blockframe.c: Killed select_frame_by_address.  Used
+       select_frame (get_current_frame (), 0) (which was correct in all
+       cases that we need to worry about.
+
+Mon Nov 14 14:19:32 1988  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * frame.h, blockframe.c, stack.c, m-sparc.h, sparc-dep.c: Added
+       mechanisms to deal with possible specification of frames
+       dyadically. 
+
+Sun Nov 13 16:03:32 1988  Richard Stallman  (rms at sugar-bombs.ai.mit.edu)
+
+       * ns32k-opcode.h: Add insns acbw, acbd.
+
+Sun Nov 13 15:09:58 1988  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * breakpoint.c: Changed breakpoint structure to use the address of
+       a given frame (constant across inferior runs) as the criteria for
+       stopping instead of the frame ident (which varies across inferior
+       calls). 
+
+Fri Nov 11 13:00:22 1988  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * gld-pinsn.c (findframe): Modified to work with the new frame
+       id's.  Actually, it looks as if this routine should be called with
+       an address anyway.
+
+       * findvar.c (find_saved_register): Altered bactrace loop to work
+       off of frames and not frame infos.
+
+       * frame.h, blockframe.c, stack.c, sparc-dep.c, m-sparc.h: Changed
+       FRAME from being the address of the frame to being a simple ident
+       which is an index into the frame_cache_item list.
+       * convex-dep.c, default-dep.c, gould-dep.c, hp9k320-dep.c,
+       i386-pinsn.c, inflow.c, infrun.c, news-dep.c, sparc-dep.c,
+       sun3-dep.c, umax-dep.c, m-hp9k320.h, m-npl.h, m-pn.h, m-sparc.h,
+       m-sun3.h, m-vax.h: Changed calls of the form set_current_frame
+       (read_register (FP_REGNUM)) to set_current_frame_by_address (...). 
+
+Thu Nov 10 16:57:57 1988  Randall Smith  (randy at gluteus.ai.mit.edu)
+
+       * frame.h, blockframe.c, gld-pinsn.c, sparc-dep.c, stack.c,
+       infrun.c, findvar.c, m-sparc.h: Changed the FRAME type to be
+       purely an identifier, using FRAME_FP and FRAME_FP_ID to convert
+       back and forth between the two.  The identifier is *currently*
+       still the frame pointer value for that frame.
+
+Wed Nov  9 17:28:14 1988  Chris Hanson  (cph at kleph)
+
+       * m-hp9k320.h (FP_REGISTER_ADDR): Redefine this to return
+       difference between address of given FP register, and beginning of
+       `struct user' that it occurs in.
+
+       * hp9k320-dep.c (core_file_command): Fix sign error in size
+       argument to myread.  Change buffer argument to pointer; was
+       copying entire structure.
+       (fetch_inferior_registers, store_inferior_registers): Replace
+       occurrences of `FP_REGISTER_ADDR_DIFF' with `FP_REGISTER_ADDR'.
+       Flush former definition.
+
+Wed Nov  9 12:11:37 1988  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * xgdb.c: Killed include of initialize.h.
+
+       * Pulled in xgdb.c from the net.
+
+       * Checkpointed distribution (to provide to 3b2 guy).
+
+       * coffread.c, dbxread.c, symmisc.c, symtab.c, symseg.h: Changed
+       format of table of line number--pc mapping information.  Can
+       handle negative pc's now.
+
+       * command.c: Deleted local copy of savestring; code in utils.c is
+       identical. 
+
+Tue Nov  8 11:12:16 1988  Randall Smith  (randy at plantaris.ai.mit.edu)
+
+       * gdb.texinfo: Added documentation for shell escape.
+
+Mon Nov  7 12:27:16 1988  Randall Smith  (randy at sugar-bombs.ai.mit.edu)
+
+       * command.c: Added commands for shell escape.
+
+       * core.c, dbxread.c: Added ROBOTUSSIN mods.
+
+       * Checkpointed distribution.
+
+       * printcmd.c (x_command): Yanked error if there is no memory to
+       examine (could be looking at executable straight).
+
+       * sparc-pinsn.c (print_insn): Amount to leftshift sethi imm by is
+       now 10 (matches adb in output).
+
+       * printcmd.c (x_command): Don't attempt to set $_ & $__ if there
+       is no last_examine_value (can happen if you did an x/0).
+
+Fri Nov  4 13:44:49 1988  Randall Smith  (randy at gluteus.ai.mit.edu)
+
+       * printcmd.c (x_command): Error if there is no memory to examine.
+
+       * gdb.texinfo: Added "cont" to the command index.
+
+       * sparc-dep.c (do_save_insn): Fixed typo in shift amount.
+
+       * m68k-opcode.h: Fixed opcodes for 68881.
+
+       * breakpoint.c, infcmd.c, source.c: Changed defaults in several
+       places for decode_line_1 to work off of the default_breakpoint_*
+       values instead of current_source_* values (the current_source_*
+       values are off by 5 or so because of listing defaults).
+
+       * stack.c (frame_info): ifdef'd out FRAME_SPECIFCATION_DYADIC in
+       the stack.c module.  If I can't do this right, I don't want to do
+       it at all.  Read the comment there for more info.
+
+Mon Oct 31 16:23:06 1988  Randall Smith  (randy at gluteus.ai.mit.edu)
+
+       * gdb.texinfo: Added documentation on the "until" command.
+
+Sat Oct 29 17:47:10 1988  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * breakpoint.c, infcmd.c: Added UNTIL_COMMAND and subroutines of
+       it. 
+
+       * breakpoint.c, infcmd.c, infrun.c: Added new field to breakpoint
+       structure (silent, indicating a silent breakpoint), and modified
+       breakpoint_stop_status and things that read it's return value to
+       understand it.
+
+Fri Oct 28 17:45:33 1988  Randall Smith  (randy at gluteus.ai.mit.edu)
+
+       * dbxread.c, symmisc.c: Assorted speedups for readin, including
+       special casing most common symbols, and doing buffering instead of
+       calling malloc.  
+
+Thu Oct 27 11:11:15 1988  Randall Smith  (randy at gluteus.ai.mit.edu)
+
+       * stack.c, sparc-dep.c, m-sparc.h: Modified to allow "info frame"
+       to take two arguments on the sparc and do the right thing with
+       them. 
+
+       * dbxread.c (read_dbx_symtab, process_symbol_for_psymtab): Put
+       stuff to put only symbols that didn't have debugging info on the
+       misc functions list back in.
+
+Wed Oct 26 10:10:32 1988  Randall Smith  (randy at gluteus.ai.mit.edu)
+
+       * valprint.c (type_print_varspec_suffix): Added check for
+       TYPE_LENGTH(TYPE_TARGET_TYPE(type)) > 0 to prevent divide by 0.
+
+       * printcmd.c (print_formatted): Added check for VALUE_REPEATED;
+       value_print needs to be called for that.
+
+       * infrun.c (wait_for_inferior): Added break when you decide to
+       stop on a null function prologue rather than continue stepping.
+
+       * m-sun3.h: Added explanatory comment to REGISTER_RAW_SIZE.
+
+       * expread.y (parse_c_1): Initialized paren_depth for each parse.
+
+Tue Oct 25 14:19:38 1988  Randall Smith  (randy at gluteus.ai.mit.edu)
+
+       * valprint.c, coffread.c, dbxread.c: Enum constant values in enum
+       type now accessed through TYPE_FIELD_BITPOS.
+
+       * dbxread.c (process_symbol_for_psymtab): Added code to deal with
+       possible lack of a ":" in a debugging symbol (do nothing).
+
+       * symtab.c (decode_line_1): Added check in case of all numbers for
+       complete lack of symbols.
+
+       * source.c (select_source_symtab): Made sure that this wouldn't
+       bomb on complete lack of symbols.
+
+Mon Oct 24 12:28:29 1988  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * m-sparc.h, findvar.c: Ditched REGISTER_SAVED_UNIQUELY and based
+       code on REGISTER_IN_WINDOW_P and HAVE_REGISTER_WINDOWS.  This will
+       break when we find a register window machine which saves the
+       window registers within the context of an inferior frame.
+
+       * sparc-dep.c (frame_saved_pc): Put PC_ADJUST return back in for
+       frame_saved_pc.  Seems correct.
+
+       * findvar.c, m-sparc.h: Created the macro REGISTER_SAVED_UNIQUELY
+       to handle register window issues (ie. that find_saved_register
+       wasn't checking the selected frame itself for shit). 
+
+       * sparc-dep.c (core_file_command): Offset target of o & g register
+       bcopy by 1 to hit correct registers.
+
+       * m-sparc.h: Changed STACK_END_ADDR.
+
+Sun Oct 23 19:41:51 1988  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * sparc-dep.c (core_file_command): Added in code to get the i & l
+       registers from the stack in the corefile, and blew away some wrong
+       code to get i & l from inferior.
+
+Fri Oct 21 15:09:19 1988  Randall Smith  (randy at apple-gunkies.ai.mit.edu)
+
+       * m-sparc.h (PUSH_DUMMY_FRAME): Saved the value of the RP register
+       in the location reserved for i7 (in the created frame); this way
+       the rp value won't get lost.  The pc (what we put into the rp in
+       this routine) gets saved seperately, so we loose no information.
+
+       * sparc-dep.c (do_save_insn & do_restore_insn): Added a wrapper to
+       preserve the proceed status state variables around each call to
+       proceed (the current frame was getting munged because this wasn't
+       being done).
+
+       * m-sparc.h (FRAME_FIND_SAVED_REGS): Fix bug: saved registers
+       addresses were being computed using absolute registers number,
+       rather than numbers relative to each group of regs.
+
+       * m-sparc.h (POP_FRAME): Fixed a bug (I hope) in the context
+       within which saved reg numbers were being interpetted.  The
+       values to be restored were being gotten in the inferior frame, and
+       the restoring was done in the superior frame.  This means that i
+       registers must be restored into o registers.
+
+       * sparc-dep.c (do_restore_insn): Modified to take a pc as an
+       argument, instead of a raw_buffer.  This matches (at least it
+       appears to match) usage from POP_FRAME, which is the only place
+       from which do_restore_insn is called.
+
+       * sparc-dep.c (do_save_insn and do_restore_insn): Added comments.
+
+       * m-sparc.h (FRAME_FIND_SAVED_REGS): Modified my code to find the
+       save addresses of out registers to use the in regs off the stack
+       pointer when the current frame is 1 from the innermost.
+
+Thu Oct 20 13:56:15 1988  & Smith  (randy at hobbes.ai.mit.edu)
+
+       * blockframe.c, m-sparc.h: Removed code associated with
+       GET_PREV_FRAME_FROM_CACHE_ITEM.  This code was not needed for the
+       sparc; you can always find the previous frames fp from the fp of
+       the current frame (which is the sp of the previous).  It's getting
+       the information associated with a given frame (ie. saved
+       registers) that's a bitch, because that stuff is saved relative to
+       the stack pointer rather than the frame pointer.
+
+       * m-sparc.h (GET_PREV_FRAME_FROM_CACHE_ITEM): Modified to return
+       the frame pointer of the previous frame instead of the stack
+       pointer of same.
+
+       * blockframe.c (flush_cached_frames): Modified call to
+       obstack_free to free back to frame_cache instead of back to zero.
+       This leaves the obstack control structure in finite state (and
+       still frees the entry allocated at frame_cache).
+
+Sat Oct 15 16:30:47 1988  & Smith  (randy at tartarus.uchicago.edu)
+
+       * valops.c (call_function): Suicide material here.  Fixed a typo;
+       CALL_DUMMY_STACK_ADJUST was spelled CAll_DUMMY_STACK_ADJUST on
+       line 530 of the file.  This cost me three days.  I'm giving up
+       typing for lent.
+
+Fri Oct 14 15:10:43 1988  & Smith  (randy at tartarus.uchicago.edu)
+
+       * m-sparc.h: Corrected a minor mistake in the dummy frame code
+       that was getting the 5th argument and the first argument from the
+       same place.
+
+Tue Oct 11 11:49:33 1988  & Smith  (randy at tartarus.uchicago.edu)
+
+       * infrun.c: Made stop_after_trap and stop_after_attach extern
+       instead of static so that code which used proceed from machine
+       dependent files could fiddle with them.
+
+       * blockframe.c, frame.h, sparc-dep.c, m-sparc.h: Changed sense of
+       ->prev and ->next in struct frame_cache_item to fit usage in rest
+       of gdb (oops).
+
+Mon Oct 10 15:32:42 1988  Randy Smith  (randy at gargoyle.uchicago.edu)
+
+       * m-sparc.h, sparc-dep.c, blockframe.c, frame.h: Wrote
+       get_frame_cache_item.  Modified FRAME_SAVED_PC and frame_saved_pc
+       to take only one argument and do the correct thing with it.  Added
+       the two macros I recently defined in blockframe.c to m-sparc.h.
+       Have yet to compile this thing on a sparc, but I've now merged in
+       everything that I received from tiemann, either exactly, or simply
+       effectively. 
+
+       * source.c: Added code to allocated space to sals.sals in the case
+       where no line was specified.
+
+       * blockframe.c, infrun.c: Modified to cache stack frames requested
+       to minimize accesses to subprocess.
+
+Tue Oct  4 15:10:39 1988  Randall Smith  (randy at cream-of-wheat.ai.mit.edu)
+
+       * config.gdb: Added sparc.
+
+Mon Oct  3 23:01:22 1988  Randall Smith  (randy at cream-of-wheat.ai.mit.edu)
+
+       * Makefile, blockframe.c, command.c, core.c, dbxread.c, defs.h,
+       expread.y, findvar.c, infcmd.c, inflow.c, infrun.c, sparc-pinsn.c,
+       m-sparc.h, sparc-def.c, printcmd.c, stack.c, symmisc.c, symseg.h,
+       valops.c, values.c: Did initial merge of sparc port.  This will
+       not compile; have to do stack frame caching and finish port.
+
+       * inflow.c, gdb.texinfo: `tty' now resets the controling terminal. 
+
+Fri Sep 30 11:31:16 1988  Randall Smith  (randy at gluteus.ai.mit.edu)
+
+       * inferior.h, infcmd.c, infrun.c: Changed the variable
+       stop_random_signal to stopped_by_random signal to fit in better
+       with name conventions (variable is not a direction to the
+       proceed/resume set; it is information from it).
+
+Thu Sep 29 13:30:46 1988  Randall Smith  (randy at cream-of-wheat.ai.mit.edu)
+
+       * infcmd.c (finish_command): Value type of return value is now
+       whatever the function returns, not the type of the function (fixed
+       a bug in printing said value).
+
+       * dbxread.c (read_dbx_symtab, process_symbol_for_psymtab):
+       Put *all* global symbols into misc_functions.  This is what was
+       happening anyway, and we need it for find_pc_misc_function.
+
+       ** This was eventually taken out, but I didn't mark it in the
+       ChangeLog.  Oops.
+
+       * dbxread.c (process_symbol_for_psymtab): Put every debugger
+       symbol which survives the top case except for constants on the
+       symchain.  This means that all of these *won't* show up in misc
+       functions (this will be fixed once I make sure it's broken the way
+       it's supposed to be).
+
+       * dbxread.c: Modified placement of debugger globals onto the hash
+       list; now we exclude the stuff after the colon and don't skip the
+       first character (debugger symbols don't have underscores).
+
+       * dbxread.c: Killed debuginfo stuff with ifdef's.
+
+Wed Sep 28 14:31:51 1988  Randall Smith  (randy at cream-of-wheat.ai.mit.edu)
+
+       * symtab.h, dbxread.c: Modified to deal with BINCL, EINCL, and
+       EXCL symbols produced by the sun loader by adding a list of
+       pre-requisite partial_symtabs that each partial symtab needs.
+
+       * symtab.h, dbxread.c, symtab.c, symmisc.c: Modified to avoid
+       doing a qsort on the local (static) psymbols for each file to
+       speed startup.  This feature is not completely debugged, but it's
+       inclusion has forced the inclusion of another feature (dealing
+       with EINCL's, BINCL's and EXCL's) and so I'm going to go in and
+       deal with them.
+
+       * dbxread.c (process_symbol_for_psymtab): Made sure that the class
+       of the symbol made it into the partial_symbol entry.
+
+Tue Sep 27 15:10:26 1988  Randall Smith  (randy at gluteus.ai.mit.edu)
+
+       * dbxread.c: Fixed bug; init_psymbol_list was not being called
+       with the right number of arguments (1).
+
+       * dbxread.c: Put ifdef's around N_MAIN, N_M2C, and N_SCOPE to
+       allow compilation on a microvax.
+
+       * config.gdb: Modified so that "config.gdb vax" would work.
+
+       * dbxread.c, symtab.h, symmisc.h, symtab.c, source.c: Put in many
+       and varied hacks to speed up gdb startup including: A complete
+       rewrite of read_dbx_symtab, a modification of the partial_symtab
+       data type, deletion of select_source_symtab from
+       symbol_file_command, and optimiztion of the call to strcmp in
+       compare_psymbols. 
+
+Thu Sep 22 11:08:54 1988  Randall Smith  (randy at gluteus.ai.mit.edu)
+
+       * dbxread.c (psymtab_to_symtab): Removed call to
+       init_misc_functions. 
+
+       * dbxread.c: Fixed enumeration type clash (used enum instead of
+       integer constant).
+
+       * breakpoint.c: Fixed typo; lack of \ at end of line in middle of
+       string constant. 
+
+       * symseg.h: Fixed typo; lack of semicolon after structure
+       definition. 
+
+       * command.c, breakpoint.c, printcmd.c: Added cmdlist editing
+       functions to add commands with the abbrev flag set.  Changed
+       help_cmd_list to recognize this flag and modified unset,
+       undisplay, and enable, disable, and delete breakpoints to have
+       this flag set.
+
+Wed Sep 21 13:34:19 1988  Randall Smith  (randy at plantaris.ai.mit.edu)
+
+       * breakpoint.c, infcmd.c, gdb.texinfo: Created "unset" as an alias
+       for delete, and changed "unset-environment" to be the
+       "environment" subcommand of "delete".
+
+       * gdb.texinfo, valprint.c: Added documentation in the manual for
+       breaking the set-* commands into subcommands of set.  Changed "set
+       maximum" to "set array-max".
+
+       * main.c, printcmd.c, breakpoint.c: Moved the declaration of
+       command lists into main and setup a function in main initializing
+       them to guarrantee that they would be initialized before calling
+       any of the individual files initialize routines.
+
+       * command.c (lookup_cmd): A null string subcommand is treated as
+       an unknown subcommand rather than an ambiguous one (eg. "set $x =
+       1" will now work).
+
+       * infrun.c (wait_for_inferior): Put in ifdef for Sony News in
+       check for trap by INNER_THAN macro.
+
+       * eval.c (evaluate_subexp): Put in catch to keep the user from
+       attempting to call a non function as a function.
+
+Tue Sep 20 10:35:53 1988  Randall Smith  (randy at oatmeal.ai.mit.edu)
+
+       * dbxread.c (read_dbx_symtab): Installed code to keep track of
+       which global symbols did not have debugger symbols refering to
+       them, and recording these via record_misc_function.
+
+       * dbxread.c: Killed code to check for extra global symbols in the
+       debugger symbol table.
+
+       * printcmd.c, breakpoint.c: Modified help entries for several
+       commands to make sure that abbreviations were clearly marked and
+       that the right commands showed up in the help listings.
+
+       * main.c, command.c, breakpoint.c, infcmd.c, printcmd.c,
+       valprint.c, defs.h: Modified help system to allow help on a class
+       name to show subcommands as well as commands and help on a command
+       to show *all* subcommands of that command.
+
+Fri Sep 16 16:51:19 1988  Randall Smith  (randy at gluteus.ai.mit.edu)
+
+       * breakpoint.c (_initialize_breakpoint): Made "breakpoints"
+       subcommands of enable, disable, and delete use class 0 (ie. they
+       show up when you do a help xxx now).
+
+       * infcmd.c,printcmd,c,main.c,valprint.c: Changed the set-*
+       commands into subcommands of set.  Created "set variable" for use
+       with variables whose names might conflict with other subcommands.
+
+       * blockframe.c, dbxread.c, coffread.c, expread.y, source.c:
+       Fixed mostly minor (and one major one in block_for_pc) bugs
+       involving checking the partial_symtab_list when a scan through the
+       symtab_list fails.
+
+Wed Sep 14 12:02:05 1988  Randall Smith  (randy at sugar-smacks.ai.mit.edu)
+
+       * breakpoint.c, gdb.texinfo: Added enable breakpoints, disable
+       breakpoints and delete breakpoints as synonyms for enable,
+       disable, and delete.  This seemed reasonable because of the
+       immeninent arrival of watchpoints & etc.
+
+       * gdb.texinfo: Added enable display, disable display, and delete
+       display to manual.
+
+Tue Sep 13 16:53:56 1988  Randall Smith  (randy at sugar-smacks.ai.mit.edu)
+
+       * inferior.h, infrun.c, infcmd.c: Added variable
+       stop_random_signal to indicate when a proceed had been stopped by
+       an unexpected signal.  Used this to determine (in normal_stop)
+       whether the current display point should be deleted.
+
+       * valops.c: Fix to value_ind to check for reference before doing a
+       COERCE_ARRAY.
+
+Sun Jul 31 11:42:36 1988  Richard Stallman  (rms at frosted-flakes.ai.mit.edu)
+
+       * breakpoint.c (_initialize_breakpoint): Clean up doc for commands
+       that can now apply also to auto-displays.
+
+       * coffread.c (record_line): Corrected a spazz in editing.
+       Also removed the two lines that assume line-numbers appear
+       only in increasing order.
+
+Tue Jul 26 22:19:06 1988  Peter TerMaat  (pete at corn-chex.ai.mit.edu)
+
+       * expression.h, eval.c, expprint.c, printcmd.c, valarith.c,
+       valops.c, valprint.c, values.c, m-*.h: Changes for evaluating and
+       displaying 64-bit `long long' integers.  Each machine must define
+       a LONGEST type, and a BUILTIN_TYPE_LONGEST.
+
+       * symmisc.c: (print_symtab) check the status of the fopen and call
+       perror_with_name if needed.
+
+Thu Jul 21 00:56:11 1988  Peter TerMaat  (pete at corn-chex.ai.mit.edu)
+
+       * Convex: core.c: changes required by Convex's SOFF format were
+       isolated in convex-dep.c.
+
+Wed Jul 20 21:26:10 1988  Peter TerMaat  (pete at corn-chex.ai.mit.edu)
+
+       * coffread.c, core.c, expread.y, i386-pinsn.c, infcmd.c, inflow.c,
+       infrun.c, m-i386.h, main.c, remote.c, source.c, valops.c:
+       Improvements for the handling of the i386 and other machines
+       running USG.  (Several of these files just needed extra header files
+       such as types.h.) utils.c: added bcopy, bcmp, bzero, getwd, list
+       of signals, and queue routines for USG systems.  Added vfork macro
+       to i386
+
+       * printcmd.c, breakpoint.c: New commands to enable/disable
+       auto-displays.  Also `delete display displaynumber' works like
+       `undisplay displaynumber'.
+
+Tue Jul 19 02:17:18 1988  Peter TerMaat  (pete at corn-chex.ai.mit.edu)
+
+       * coffread.c: (coff_lookup_type)  Wrong portion of type_vector was
+       being bzero'd after type_vector was reallocated.
+
+       * printcmd.c: (delete_display) Check for a display chain before
+       attempting to delete a display.
+
+       * core.c, *-dep.c (*-infdep moved to *-dep): machine-dependent
+       parts of core.c (core_file_command, exec_file_command) moved to
+       *-dep.c. 
+
+Mon Jul 18 19:45:51 1988  Peter TerMaat  (pete at corn-chex.ai.mit.edu)
+
+       * dbxread.c: typo in read_struct_type (missing '=') was causing a
+       C struct to be parsed as a C++ struct, resulting in a `invalid
+       character' message.
+
+Sun Jul 17 22:27:32 1988  Peter TerMaat  (pete at corn-chex.ai.mit.edu)
+
+       * printcmd.c, symtab.c, valops.c, expread.y: When an expression is
+       read, the innermost block required to evaluate the expression is
+       saved in the global variable `innermost_block'.  This information
+       is saved in the `block' field of an auto-display so that
+       expressions with inactive variables can be skipped.  `info display'
+       tells the user which displays are active and which are not.  New
+       fn `contained_in' returns nonzero if one block is contained within
+       another. 
+
+Fri Jul 15 01:53:14 1988  Peter TerMaat  (pete at corn-chex.ai.mit.edu)
+
+       * infrun.c, m-i386.h: Use macro TRAPS_EXPECTED to set number of
+       traps to skip when sh execs the program.  Default is 2, m-i386.h
+       overrides this and sets to 4.
+
+       * coffread.c, infrun.c: minor changes for the i386.  May be able
+       to eliminate them with more general code.
+
+       * default-infdep.c: #ifdef SYSTEMV, include header file types.h.
+       Also switched the order of signal.h and user.h, since System 5
+       requires signal.h to come first.
+
+       * core.c main.c, remote,c, source.c, inflow.c: #ifdef SYSTEMV,
+       include various header files.  Usually types.h and fcntl.h.
+
+       * utils.c: added queue routines needed by the i386 (and other sys
+       5 machines).
+
+       * sys5.c, regex.c, regex.h: new files for sys 5 systems.  (The
+       regex files are simply links to /gp/gnu/lib.)
+
+Thu Jul 14 01:47:14 1988  Peter TerMaat  (pete at corn-chex.ai.mit.edu)
+
+       * config.gdb, README: Provide a list of known machines when user
+       enters an invalid machine.  New second arg is operating system,
+       currently only used with `sunos4' or `os4'. Entry for i386 added.
+
+       * news-infdep.c: new file.
+
+       * m-news.h: new version which deals with new bugs in news800's OS.
+
+Tue Jul 12 19:52:16 1988  Peter TerMaat  (pete at corn-chex.ai.mit.edu)
+
+       * Makefile, *.c, munch, config.gdb, README: New initialization
+       scheme uses nm to find functions whose names begin with
+       `_initialize_'.  Files `initialize.h', `firstfile.c',
+       `lastfile.c', `m-*init.h' no longer needed. 
+
+       * eval.c, symtab.c, valarith.c, valops.c, value.h, values.c: Bug
+       fixes from gdb+ 2.5.4.  evaluate_subexp takes a new arg, type
+       expected. New fn value_virtual_fn_field.
+
+Mon Jul 11 00:48:49 1988  Peter TerMaat  (pete at corn-chex.ai.mit.edu)
+
+       * core.c (read_memory): xfer_core_file was being called with an
+       extra argument (0) by read_memory.
+
+       * core.c (read_memory), *-infdep.c (read_inferior_memory),
+       valops.c (value_at): read_memory and read_inferior_memory now work
+       like write_memory and write_inferior_memory in that errno is
+       checked after each ptrace and returned to the caller.  Used in
+       value_at to detect references to addresses which are out of
+       bounds.  Also core.c (xfer_core_file): return 1 if invalid
+       address, 0 otherwise.
+
+       * inflow.c, <machine>-infdep.c: removed all calls to ptrace from
+       inflow.c and put them in machine-dependent files *-infdep.c.
+
+Sun Jul 10 19:19:36 1988  Peter TerMaat  (pete at corn-chex.ai.mit.edu)
+
+       * symmisc.c: (read_symsegs) Accept only format number 2.  Since
+       the size of the type structure changed when C++ support was added,
+       format 1 can no longer be used.
+
+       * core.c, m-sunos4.h: (core_file_command) support for SunOS 4.0.
+       Slight change in the core structure.  #ifdef SUNOS4.  New file
+       m-sunos4.h.  May want to change config.gdb also.
+
+Fri Jul  8 19:59:49 1988  Peter TerMaat  (pete at corn-chex.ai.mit.edu)
+
+       * breakpoint.c: (break_command_1) Allow `break if condition'
+       rather than parsing `if' as a function name and returning an
+       error.
+
+Thu Jul  7 22:22:47 1988  Peter TerMaat  (pete at corn-chex.ai.mit.edu)
+
+       * C++: valops.c, valprint.c, value.h, values.c: merged code to deal
+       with C++ expressions.
+
+Wed Jul  6 03:28:18 1988  Peter TerMaat  (pete at corn-chex.ai.mit.edu)
+
+        * C++: dbxread.c: (read_dbx_symtab, condense_misc_bunches,
+       add_file_command)  Merged code to read symbol information from
+       an incrementally linked file.  symmisc.c:
+       (init_free_inclink_symtabs, free_inclink_symtabs) Cleanup
+       routines.
+
+Tue Jul  5 02:50:41 1988  Peter TerMaat  (pete at corn-chex.ai.mit.edu)
+
+       * C++: symtab.c, breakpoint.c, source.c:  Merged code to deal with
+       ambiguous line specifications.  In C++ one can have overloaded
+       function names, so that `list classname::overloadedfuncname'
+       refers to several different lines, possibly in different files.
+
+Fri Jul  1 02:44:20 1988  Peter TerMaat  (pete at corn-chex.ai.mit.edu)
+
+       * C++: symtab.c: replaced lookup_symtab_1 and lookup_symtab_2 with
+       a modified lookup_symbol which checks for fields of the current
+       implied argument `this'.  printcmd.c, source.c, symtab.c,
+       valops.c: Need to change callers once callers are
+       installed. 
+
+Wed Jun 29 01:26:56 1988  Peter TerMaat  (pete at frosted-flakes.ai.mit.edu)
+
+       * C++: eval.c, expprint.c, expread.y, expression.h, valarith.c, 
+       Merged code to deal with evaluation of user-defined operators,
+       member functions, and virtual functions.
+       binop_must_be_user_defined tests for user-defined binops, 
+       value_x_binop calls the appropriate operator function. 
+
+Tue Jun 28 02:56:42 1988  Peter TerMaat  (pete at frosted-flakes.ai.mit.edu)
+
+       * C++: Makefile: changed the echo: expect 101 shift/reduce conflicts 
+       and 1 reduce/reduce conflict.
+\f
+Local Variables:
+mode: indented-text
+left-margin: 8
+fill-column: 74
+version-control: never
+End:
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
new file mode 100644 (file)
index 0000000..7b4e3ce
--- /dev/null
@@ -0,0 +1,506 @@
+##Copyright (C) 1989-1991 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.
+
+# Place to install binaries. 
+bindir=/usr/local/bin
+
+# System V: If you compile gdb with a compiler which uses the coff
+# encapsulation feature (this is a function of the compiler used, NOT
+# of the m-?.h file selected by config.gdb), you must make sure that
+# the GNU nm is the one that is used by munch.
+
+# If you are compiling with GCC, make sure that either 1) You use the
+# -traditional flag, or 2) You have the fixed include files where GCC
+# can reach them.  Otherwise the ioctl calls in inflow.c and readline.c 
+# will be incorrectly compiled.  The "fixincludes" script in the gcc
+# distribution will fix your include files up.
+#CC=cc
+#CC=gcc -traditional
+GCC=gcc
+
+VPATH=$(srcdir)
+
+# It is also possible that you will need to add -I/usr/include/sys to the
+# CFLAGS section if your system doesn't have fcntl.h in /usr/include (which 
+# is where it should be according to Posix).
+
+YACC=bison -y
+# YACC=yacc
+SHELL=/bin/sh
+MAKE=make
+
+# Set this up with gcc if you have gnu ld and the loader will print out
+# line numbers for undefinded refs.
+#CC-LD=gcc -static
+CC-LD=${CC}
+
+# define this to be "gmalloc.o" if you want to use the gnu malloc routine
+# (useful for debugging memory allocation problems in gdb).  To use your
+# system malloc, uncomment the following two lines.
+#GNU_MALLOC =
+#MALLOC_CFLAGS = -DNO_MALLOC_CHECK
+GNU_MALLOC = gmalloc.o mcheck.o
+MALLOC_CFLAGS =
+
+# Where is the "include" directory?  Traditionally ../include or ./include
+INCLUDE_DIR =  ${srcdir}/../include
+INCLUDE_DEP = $$(INCLUDE_DIR)
+
+# Where is the BFD library?  Traditionally ../bfd or ./bfd
+BFD_DIR =  ${srcdir}/../bfd
+BFD_DEP = $$(BFD_DIR)
+
+# All the includes used for CFLAGS and for lint.
+# -I. for config files.
+# -I${srcdir} for <obstack.h>, possibly regex.h also.
+INCLUDE_CFLAGS = -I. -I${srcdir} -I$(INCLUDE_DIR) -I${srcdir}/vx-share
+
+# {X,T}M_CFLAGS, if defined, has system-dependent CFLAGS.
+# CFLAGS for both GDB and readline.
+GLOBAL_CFLAGS = -g ${TM_CFLAGS} ${XM_CFLAGS}
+#PROFILE_CFLAGS = -pg
+
+CFLAGS = ${GLOBAL_CFLAGS} ${PROFILE_CFLAGS} ${MALLOC_CFLAGS} ${INCLUDE_CFLAGS}
+# None of the things in CFLAGS will do any harm, and on some systems
+#  (e.g. SunOS4) it is important to use the M_CFLAGS.
+LDFLAGS = $(CFLAGS)
+
+# define this to be "obstack.o" if you don't have the obstack library installed
+# so that the dependencies work right.  
+OBSTACK = obstack.o
+
+# Requires GNU getopt_long features.
+GETOPT = getopt.o getopt1.o
+# Where is the getopt directory?  Traditionally ../getopt or ./getopt
+GETOPT_DIR =  ${srcdir}/../getopt
+GETOPT_DEP = $$(GETOPT_DIR)
+
+# Flags that describe where you can find the termcap library.
+# You may need to make other arrangements for USG.
+TERMCAP = -ltermcap
+
+# You must define REGEX and REGEX1 on USG machines.
+# If your sysyem is missing alloca(), or, more likely, it's there but
+# it doesn't work, define ALLOCA & ALLOCA1
+
+# {X,T}M_CLIBS, if defined, has system-dependent libs
+# For example, -lPW for System V to get alloca().
+# FIXME STOPGAP FOR BFD LIBRARY: BFD stuff
+CLIBS = ${TERMCAP} $(XM_CLIBS) ${TM_CLIBS} ${BFD_DIR}/libbfd.a
+CDEPS = ${XM_CDEPS} ${TM_CDEPS} ${BFD_DIR}/libbfd.a
+
+ADD_FILES = ${OBSTACK} ${REGEX} ${ALLOCA} ${GNU_MALLOC} ${GETOPT}
+ADD_DEPS = ${OBSTACK} ${REGEX1} ${ALLOCA1} ${GNU_MALLOC} ${GETOPT}
+
+VERSION = 3.94.2
+DIST=gdb-$(VERSION)
+
+LINT=/usr/5bin/lint
+LINTFLAGS=
+
+# Source files in the main directory.
+# Files which are included via a tconfig/* or xconfig/* file 
+# should *not* be specified here; they're in "ALLDEPFILES".
+SFILES_MAINDIR = \
+        blockframe.c breakpoint.c command.c core.c \
+        environ.c eval.c expprint.c findvar.c infcmd.c inflow.c infrun.c \
+        main.c printcmd.c \
+        remote.c source.c stack.c symmisc.c symtab.c symfile.c \
+        utils.c valarith.c valops.c valprint.c values.c expread.y \
+        signame.c cplus-dem.c mem-break.c target.c inftarg.c \
+        dbxread.c coffread.c \
+        ieee-float.c 
+
+# Source files in subdirectories (which will be handled separately by
+#  'make gdb.tar.Z').
+# Files which are included via a tconfig/* or xconfig/* file 
+# should *not* be specified here; they're in "ALLDEPFILES".
+SFILES_SUBDIR = \
+        ${srcdir}/vx-share/dbgRpcLib.h \
+        ${srcdir}/vx-share/ptrace.h \
+        ${srcdir}/vx-share/reg.h \
+        ${srcdir}/vx-share/vxTypes.h \
+        ${srcdir}/vx-share/vxWorks.h \
+        ${srcdir}/vx-share/wait.h \
+        ${srcdir}/vx-share/xdr_ld.h \
+        ${srcdir}/vx-share/xdr_ptrace.h \
+        ${srcdir}/vx-share/xdr_rdb.h \
+        ${srcdir}/vx-share/xdr_regs.h \
+        ${srcdir}/nindy-share/Makefile \
+        ${srcdir}/nindy-share/VERSION \
+        ${srcdir}/nindy-share/b.out.h \
+        ${srcdir}/nindy-share/block_io.h \
+        ${srcdir}/nindy-share/coff.h \
+        ${srcdir}/nindy-share/demux.h \
+        ${srcdir}/nindy-share/env.h \
+        ${srcdir}/nindy-share/stop.h \
+        ${srcdir}/nindy-share/ttycntl.h
+
+# All source files that go into linking GDB, except config-specified files.
+SFILES = $(SFILES_MAINDIR) $(SFILES_SUBDIR)
+
+# All source files that lint should look at
+LINTFILES = $(SFILES) expread.tab.c init.c
+
+# Any additional files specified on these lines should also be added to
+# the OTHERS = definition below, so they go in the tar files.
+SFILES_STAND = $(SFILES) standalone.c
+SFILES_KGDB  = $(SFILES) stuff.c kdb-start.c
+
+# Header files that are not named in tconfig/* or xconfig/* go here.
+HFILES=        breakpoint.h command.h defs.h environ.h \
+       expression.h frame.h gdbcmd.h gdbcore.h \
+       getpagesize.h ieee-float.h inferior.h param-no-tm.h param.h \
+       signals.h signame.h symfile.h symtab.h \
+       target.h tdesc.h terminal.h tm-68k.h tm-i960.h tm-sunos.h \
+       value.h
+
+OPCODES = pn-opcode.h np1-opcode.h sparc-opcode.h vax-opcode.h m68k-opcode.h \
+         ns32k-opcode.h convex-opcode.h pyr-opcode.h mips-opcode.h \
+         am29k-opcode.h
+
+REMOTE_EXAMPLES = remote-sa.m68k.shar remote-multi.shar
+
+MALLOCSRC = gmalloc.c mcheck.c ansidecl.h stdlib.h gmalloc.h stddef.h
+GETOPTSRC = $(GETOPT_DIR)/getopt.c $(GETOPT_DIR)/getopt1.c
+
+POSSLIBS_MAINDIR = obstack.h obstack.c regex.c regex.h alloca.c \
+       $(MALLOCSRC)
+POSSLIBS = $(POSSLIBS_MAINDIR) $(GETOPTSRC)
+
+TESTS = testbpt.c testfun.c testrec.c testreg.c testregs.c
+
+# tdesc-lib cannot be named simply tdesc, because if if it were GNU make
+# would try to make it from tdesc.c.
+# tdesc-lib removed from the list due to Motorola copyrights...gnu@cygnus.com
+OTHERS = Makefile.dist depend alldeps.mak Makefile.srcdir \
+        createtags munch config.gdb config.status \
+        ChangeLog ChangeLog-3.x \
+        README TODO TAGS WHATS.NEW \
+        gdb.texinfo gdb-int.texinfo gdbrc.tex threecol.tex \
+       .gdbinit COPYING expread.tab.c stab.def \
+        copying.c Projects Convex.notes copying.awk \
+        saber.suppress standalone.c stuff.c kdb-start.c \
+        hp-include # tests
+
+DEPFILES= ${TDEPFILES} ${XDEPFILES}
+
+SOURCES=$(SFILES) $(ALLDEPFILES)
+TAGFILES = $(SOURCES) ${HFILES} ${OPCODES} ${ALLPARAM} ${POSSLIBS} 
+TAGFILES_MAINDIR = $(SFILES_MAINDIR) $(ALLDEPFILES_MAINDIR) \
+             ${HFILES} ${OPCODES} ${ALLPARAM} ${POSSLIBS_MAINDIR} 
+TARFILES = ${TAGFILES_MAINDIR} ${OTHERS} ${REMOTE_EXAMPLES}
+
+OBS = main.o blockframe.o breakpoint.o findvar.o stack.o source.o \
+    values.o eval.o valops.o valarith.o valprint.o printcmd.o \
+    symtab.o symfile.o symmisc.o infcmd.o infrun.o remote.o \
+    command.o utils.o expread.o expprint.o environ.o version.o \
+    copying.o $(DEPFILES) signame.o cplus-dem.o mem-break.o target.o \
+    inftarg.o ieee-float.o \
+    dbxread.o coffread.o # mipsread.o
+
+RAPP_OBS = rgdb.o rudp.o rserial.o serial.o udp.o $(XDEPFILES)
+
+TSOBS = core.o inflow.o
+
+NTSOBS = standalone.o
+
+TSSTART = /lib/crt0.o
+
+NTSSTART = kdb-start.o
+
+RL_LIB = readline/libreadline.a
+RL_LIB_DEP = $(RL_LIB)
+
+# Prevent Sun make from putting in the machine type.  Setting
+# TARGET_ARCH to nothing works for SunOS 3, 4.0, but not for 4.1.
+.c.o:
+       ${CC} -c ${CFLAGS} $<
+
+all: gdb
+
+install: gdb
+       cp gdb $(bindir)/gdb.new
+       mv $(bindir)/gdb.new $(bindir)/gdb
+       $(M_INSTALL)
+
+init.c: $(srcdir)/munch $(MUNCH_DEFINE) $(OBS) $(TSOBS)
+       $(srcdir)/munch ${MUNCH_DEFINE} $(OBS) $(TSOBS) > init.c
+
+gdb: $(OBS) $(TSOBS) ${ADD_DEPS} ${RL_LIB_DEP} ${CDEPS} init.o
+       ${CC-LD} $(LDFLAGS) -o gdb init.o $(OBS) $(TSOBS) $(ADD_FILES) \
+       ${RL_LIB} $(CLIBS)
+
+saber_gdb: $(SFILES) $(GETOPTSRC) $(DEPFILES) copying.c obstack.c version.c
+       #setopt load_flags $(CFLAGS) -I$(BFD_DIR)
+       #load ./init.c $(SFILES)
+       #unload ${srcdir}/expread.y
+       #load ${srcdir}/expread.tab.c readline/libreadline.a
+       #load copying.c version.c
+       #load obstack.c $(GETOPTSRC)
+       #load `echo " "$(DEPFILES) | sed -e 's/\.o/.c/g' -e 's, , ../,g'`
+       #load ${BFD_DIR}/libbfd.a -ltermcap 
+       ##void mcheck(a) void (*a)(); { }
+
+
+
+# This is useful when debugging GDB, because some Unix's don't let you run GDB
+# on itself without copying the executable.  So "make gdb1" will make
+# gdb and put a copy in gdb1, and you can run it with "gdb gdb1".
+# Removing gdb1 before the copy is the right thing if gdb1 is open
+# in another process.
+gdb1: gdb
+       rm -f gdb1
+       cp gdb gdb1
+
+# This is a remote stub which runs under unix and starts up an
+# inferior process.  This is at least useful for debugging GDB's
+# remote support.
+rapp: $(RAPP_OBS)
+       rm -f rapp_init.c
+       ${srcdir}/munch ${RAPP_OBS} > rapp_init.c
+       ${CC-LD} $(LDFLAGS) -o $@ rapp_init.c $(RAPP_OBS)
+       
+Makefiles= Makefile.srcdir $(M_MAKEFILE) \
+       ${srcdir}/alldeps.mak ${srcdir}/Makefile.dist
+
+MAKE_MAKEFILE= echo "M_MAKEFILE=$(M_MAKEFILE)" | \
+       cat - ${Makefiles} ${srcdir}/depend >Makefile
+
+Makefile: $(Makefiles)
+       $(MAKE_MAKEFILE)
+
+alldeps.mak: ${srcdir}/tconfig ${srcdir}/xconfig
+       rm -f alldeps.mak alldeps.tmp allparam.tmp allconfig.tmp
+       for i in `ls -d ${srcdir}/tconfig/*[0-9A-Za-z] \
+          ${srcdir}/xconfig/*[0-9A-Za-z] | grep -v RCS` ; do \
+         echo $$i >>allconfig.tmp; \
+         awk <$$i ' \
+           $$1 == "TDEPFILES=" || $$1 == "XDEPFILES=" { \
+             for (i = 2; i <= NF; i++) \
+               print $$i >> "alldeps.tmp" ; \
+            } \
+           $$1 == "TM_FILE=" || $$1 == "XM_FILE=" { \
+             print $$2 >> "allparam.tmp" }' ; \
+       done
+       sort <alldeps.tmp | uniq | \
+         sed -e 's/arm-convert.o/arm-convert.s/' \
+             -e 's!^Onindy.o!nindy-share/Onindy.c!' \
+             -e 's!^nindy.o!nindy-share/nindy.c!' \
+             -e 's!ttybreak.o!nindy-share/ttybreak.c!' \
+             -e 's!ttyflush.o!nindy-share/ttyflush.c!' \
+             -e 's!xdr_ld.o!vx-share/xdr_ld.c!' \
+             -e 's!xdr_ptrace.o!vx-share/xdr_ptrace.c!' \
+             -e 's!xdr_rdb.o!vx-share/xdr_rdb.c!' \
+             -e 's!xdr_regs.o!vx-share/xdr_regs.c!' \
+             -e 's/\.o/.c/' \
+           >alldeps2.tmp
+       echo 'ALLDEPFILES = $$(ALLDEPFILES_MAINDIR) $$(ALLDEPFILES_SUBDIR)' \
+           >>alldeps.mak;
+       grep -v / alldeps2.tmp | \
+         awk 'BEGIN {printf "ALLDEPFILES_MAINDIR="} \
+           NR == 0 {printf $$0;} \
+           NR != 0 {printf "\\\n" $$0} \
+           END {printf "\n\n"}' >>alldeps.mak;
+       grep / alldeps2.tmp | \
+         awk 'BEGIN {printf "ALLDEPFILES_SUBDIR="} \
+           NR == 0 {printf $$0;} \
+           NR != 0 {printf "\\\n" $$0} \
+           END {printf "\n\n"}' >>alldeps.mak;
+       sort <allparam.tmp | uniq | awk 'BEGIN {printf "ALLPARAM="} \
+           NR == 0 {printf $$0;} \
+           NR != 0 {printf "\\\n" $$0} \
+           END {printf "\n\n"}' >>alldeps.mak;
+       sort <allconfig.tmp | uniq | awk 'BEGIN {printf "ALLCONFIG="} \
+           NR == 0 {printf $$0;} \
+           NR != 0 {printf "\\\n" $$0} \
+           END {printf "\n\n"}' >>alldeps.mak;
+       rm -f alldeps.tmp alldeps2.tmp allparam.tmp allconfig.tmp
+
+# The sed script makes everything which depends on {x,t}m.h depend on
+# config.status as well, in case someone reconfigures gdb out from
+# under an already compiled gdb.
+depend: $(SOURCES) Makefile.dist
+       @echo Ignore errors about non-existent system-supplied include files
+       @echo for systems other than the one you are using.
+       @echo "If xm.h and tm.h don't exist, the error messages saying so"
+       @echo can safely be ignored.
+       @echo Also ignore parse errors in valops.c, and any errors in
+       @echo arm-convert.s.
+       -$(GCC) -MM $(CFLAGS) -I$(BFD_DIR) \
+           `ls $(SOURCES) | sort -u` >depend.tmp
+       <depend.tmp sed -e 's/ [xt]m.h/& config.status/g'  \
+         -e 's; vx-share/; $${srcdir}/vx-share/;g'  \
+         -e 's; nindy-share/; $${srcdir}/nindy-share/;g'  \
+         -e 's; $(INCLUDE_DIR)/; $(INCLUDE_DEP)/;g'  \
+         -e 's; [a-z0-9./]*bfd/; $(BFD_DEP)/;g'  \
+         -e 's; [a-z0-9./]*getopt/; $(GETOPT_DEP)/;g'  \
+         -e 's; \./; $${srcdir}/;g'  \
+         >depend
+       $(MAKE_MAKEFILE)
+       rm depend.tmp
+
+config.status:
+       @echo "You must configure gdb.  Look at the README file for details."
+       @false
+
+# These are not generated by "make depend" because they only are there
+# for some machines.
+tm-isi.h tm-sun3.h tm-news.h tm-hp300bsd.h tm-altos.h : tm-68k.h
+tm-hp300hpux.h tm-sun2.h tm-3b1.h : tm-68k.h
+xm-news1000.h : xm-news.h
+xm-i386-sv32.h : xm-i386.h
+tm-i386gas.h: tm-i386.h
+xm-sun4os4.h : xm-sparc.h
+tm-sun4os4.h : tm-sparc.h
+
+kdb : $(NTSSTART) $(OBS) $(NTSOBS) ${ADD_DEPS} ${RL_LIB_DEP}
+       rm -f init.c
+       $(srcdir)/munch ${MUNCH_DEFINE} $(OBS) $(NTSOBS) > init.c
+       $(CC) $(LDFLAGS) -c init.c $(CLIBS) 
+       ld -o kdb $(NTSSTART) $(OBS) $(NTSOBS) init.o $(ADD_FILES) \
+       ${RL_LIB} -lc $(CLIBS)
+
+# Put the proper machine-specific files first.
+# createtags will edit the .o in DEPFILES into .c
+TAGS: ${TAGFILES}
+       $(srcdir)/createtags $(TM_FILE) ${XM_FILE} $(DEPFILES) ${TAGFILES}
+tags: TAGS
+
+# FIXME: Get alldeps.mak up to date, config.gdb none, THEN make gdb.tar.Z!
+gdb.tar.Z: ${TARFILES}
+       rm -f gdb.tar; rm -rf $(DIST)
+       cd readline ; make readline.tar
+       mkdir $(DIST)
+       cd $(DIST) ; for i in ${TARFILES} ; do ln -s ../$$i . ; done
+       mkdir $(DIST)/readline
+       cd $(DIST)/readline ; tar xf ../../readline/readline.tar
+       mkdir $(DIST)/xconfig ${DIST}/tconfig
+       cd $(DIST)/tconfig ; \
+         for i in $(ALLCONFIG) ; do ln -s ../../$$i ../$$i ; done
+       mkdir $(DIST)/vx-share $(DIST)/nindy-share
+       cd $(DIST)/tconfig ; \
+         for i in $(SFILES_SUBDIR) $(ALLDEPFILES_SUBDIR); \
+           do ln -s ../../$$i ../$$i ; done
+       tar chf - $(DIST) | compress >gdb.tar.Z
+       rm -rf $(DIST)
+
+clean:
+       rm -f ${OBS} ${TSOBS} ${NTSOBS} ${ADD_FILES}
+       rm -f init.c init.o version.c
+       rm -f gdb core gdb.tar gdb.tar.Z make.log
+       rm -f gdb[0-9]
+       cd readline ; make clean
+
+distclean: clean expread.tab.c TAGS
+       rm -f tm.h xm.h config.status
+       rm -f y.output yacc.acts yacc.tmp
+       rm -f ${TESTS} Makefile
+
+realclean: clean
+       rm -f expread.tab.c TAGS
+       rm -f tm.h xm.h config.status
+       rm -f Makefile
+
+gdb.dvi : gdb.texinfo
+       tex gdb.texinfo
+       texindex gdb.??
+       tex gdb.texinfo
+
+# Make copying.c from COPYING
+copying.c : COPYING copying.awk
+       awk -f copying.awk < COPYING > copying.c
+
+version.c : Makefile.dist
+       echo 'char *version = "$(VERSION)";' >version.c
+
+${srcdir}/expread.tab.c : $(srcdir)/expread.y
+       @echo 'Expect 4 shift/reduce conflict.'
+       ${YACC} $(srcdir)/expread.y
+       mv y.tab.c ${srcdir}/expread.tab.c
+
+expread.o : ${srcdir}/expread.tab.c defs.h param.h symtab.h \
+            frame.h expression.h
+       $(CC) -c ${CFLAGS} `echo ${srcdir}/expread.tab.c | sed 's,^\./,,'`
+       mv expread.tab.o expread.o
+
+# dbxread, coffread, mipsread have dependencies on BFD header files.
+dbxread.o: ${srcdir}/dbxread.c
+       ${CC} -c ${CFLAGS} -I$(BFD_DIR) ${srcdir}/dbxread.c
+
+coffread.o: ${srcdir}/coffread.c
+       ${CC} -c ${CFLAGS} -I$(BFD_DIR) ${srcdir}/coffread.c
+
+mipsread.o: ${srcdir}/mipsread.c
+       ${CC} -c ${CFLAGS} -I$(BFD_DIR) ${srcdir}/mipsread.c
+
+# Drag in the files that are in another directory.
+
+getopt1.o: $(GETOPT_DIR)/getopt1.c
+       ${CC} -c ${CFLAGS} $(GETOPT_DIR)/getopt1.c
+
+getopt.o: $(GETOPT_DIR)/getopt.c
+       ${CC} -c ${CFLAGS} $(GETOPT_DIR)/getopt.c
+
+xdr_ld.o: ${srcdir}/vx-share/xdr_ld.c
+       ${CC} -c ${CFLAGS} ${srcdir}/vx-share/xdr_ld.c
+
+xdr_ptrace.o: ${srcdir}/vx-share/xdr_ptrace.c
+       ${CC} -c ${CFLAGS} ${srcdir}/vx-share/xdr_ptrace.c
+
+xdr_rdb.o: ${srcdir}/vx-share/xdr_rdb.c
+       ${CC} -c ${CFLAGS} ${srcdir}/vx-share/xdr_rdb.c
+
+xdr_regs.o: ${srcdir}/vx-share/xdr_regs.c
+       ${CC} -c ${CFLAGS} ${srcdir}/vx-share/xdr_regs.c
+
+nindy.o: ${srcdir}/nindy-share/nindy.c
+       ${CC} -c ${CFLAGS} ${srcdir}/nindy-share/nindy.c
+
+Onindy.o: ${srcdir}/nindy-share/Onindy.c
+       ${CC} -c ${CFLAGS} ${srcdir}/nindy-share/Onindy.c
+
+ttybreak.o: ${srcdir}/nindy-share/ttybreak.c
+       ${CC} -c ${CFLAGS} ${srcdir}/nindy-share/ttybreak.c
+
+ttyflush.o: ${srcdir}/nindy-share/ttyflush.c
+       ${CC} -c ${CFLAGS} ${srcdir}/nindy-share/ttyflush.c
+
+tdesc-lib/libdc.o : force_update
+       cd tdesc-lib ; ${MAKE} "SYSV_DEFINE=${SYSV_DEFINE}"
+
+# In LOCAL_INCLUDES, -I${srcdir} is right if srcdir is an absolute path,
+# and -I../${srcdir} is right if it is relative (e.g. ".."), so search both.
+readline/libreadline.a : force_update
+       cd readline ; ${MAKE} "SYSV=${SYSV_DEFINE}"\
+               "VPATH=${srcdir}/readline:../${srcdir}/readline"\
+               "LOCAL_INCLUDES=-I../ -I${srcdir}/ -I../${srcdir}/"\
+               "DEBUG_FLAGS=${GLOBAL_CFLAGS}" "CC=${CC}" libreadline.a
+
+lint: $(LINTFILES)
+       $(LINT) $(INCLUDE_CFLAGS) $(LINTFLAGS) $(LINTFILES)
+
+gdb.cxref: $(SFILES)
+       cxref -I. $(SFILES) >gdb.cxref
+
+force_update :
+
+# When used with GDB, the demangler should never look for leading underscores
+# because GDB strips them off during symbol read-in.  Thus -Dnounderscore.
+cplus-dem.o : cplus-dem.c
+       ${CC} -c -Dnounderscore `echo ${srcdir}/cplus-dem.c | sed 's,^\./,,'`
diff --git a/gdb/README b/gdb/README
new file mode 100644 (file)
index 0000000..999db4a
--- /dev/null
@@ -0,0 +1,259 @@
+This is GDB, the GNU source-level debugger, presently running under
+un*x.  This is a pre-alpha version of GDB version 4, and has NOT been
+extensively tested.  It surely has some bugs, both bugs that were
+present in version 3 and new bugs.  I have filed all the bug reports
+and fixes mailed to bug-gdb, and the fixes in particular will move
+into these sources as I find the time.
+
+             => THIS VERSION IS PARTICULARLY FRAGILE! <=
+
+       It depends on a preliminary version of a new "binary file
+       descriptor" library and a new global "include" directory, which
+       are packaged separately from GDB.  You must obtain, configure
+       and build this library manually, then configure and build gdb.
+       When building gdb's for multiple platforms, you must manually
+       rebuild the bfd library separately for each platform.  Yes, of
+       course, we are working on this!  FIXME!
+
+       Configure bfd for your host system by:
+
+               cd ../bfd
+               edit Makefile
+               make
+
+       Then you can cd ../gdb-whatever, and config and build gdb.
+
+This release moves the generic GNU include files, the BFD library,
+and the getopt routines into the parent directory of gdb.  The idea
+is that a variety of GNU tools can share a common copy of these things.
+
+A summary of features new since gdb-3.5 is in the file `WHATS.NEW'.
+
+The best way to build GDB, in my opinion, is in a subdirectory.  I use
+a naming convention "=XXX" where XXX is the machine type I'm building
+for.  Nothing depends on this, it's just how I remember which
+subdirectories are what.  So, once you have the BFD library built for
+that machine, you can do:
+
+       cd gdb-x.yy     (the directory where this README is)
+       mkdir =XXX      (e.g. mkdir =vax)
+       cd =XXX
+       ../config.gdb machine
+       make
+
+Machine is like "vax" or "sun4".  For more information type `../config.gdb'.
+
+Once you have done that, just `make' will do everything, producing an
+executable `gdb' in this directory.
+
+You can also build gdb binaries in a completely different directory from its 
+sources, by specifying "srcdir=YYY" to config.gdb, giving it an absolute
+or relative path to the source directory.  
+
+GDB can be used as a cross-debugger, running on a machine of one type
+while debugging a program running on a machine of another type.  You
+configure it this way by specifying `config.gdb host target' where host
+is where GDB runs, and target is where your program runs.
+
+If you want a new (current to this release) version of the manual, you
+will have to use the gdb.texinfo file provided with this distribution.
+For details see the texinfo manual (distributed with emacs and as a
+printed manual).
+
+About languages other than C...
+
+C++ support has been integrated into gdb.  GDB should work with FORTRAN
+programs (if you have problem, please send a bug report; note that you
+may have to refer to some FORTRAN variables with a trailing
+underscore), but I am not aware of anyone who is working on getting it
+to use the syntax of any language other than C or C++.  Pascal programs
+which use sets, subranges, file variables, or nested functions will not
+currently work.
+
+About kernel debugging...
+
+I have't done this myself so I can't really offer any advice.
+Remote debugging over serial lines is more like to be in a currently
+functioning state than the standalone gdb (kdb).  FIXME.
+
+About remote debugging...
+
+[This section seems to be out of date, I have never seen the "rapp"
+program, though I would like to.  FIXME.]
+`rapp' runs under unix and acts as a remote stub (like remote-multi.shar
+distributed with GDB version 3).  Currently it just works over UDP
+(network), not over a serial line.  To get it running
+* Compile GDB on the host machine as usual
+* Compile rapp on the target machine, giving for both host and target
+  the type of the target machine
+* Install "gdb" in /etc/services on both machines.
+
+This will get reworked before the initial release of 4.x.  FIXME.
+
+The two files remote-multi.shar and remote-sa.m68k.shar contain two
+examples of a remote stub to be used with remote.c.  The the -multi
+file is a general stub that can probably be running on various
+different flavors of unix to allow debugging over a serial line from
+one machine to another.  The remote-sa.m68k.shar is designed to run
+standalone on a 68k type cpu and communicate properley with the
+remote.c stub over a serial line.
+
+The files remote-eb.c and remote-nindy.c are two examples of remote
+interfaces for talking to existing ROM monitors (for the AMD 29000 and the
+Intel 960 repsectively).  There is also a remote interface for the
+VxWorks realtime kernel, which communicates over TCP/IP, in remote-vx.c
+and the vx-share subdirectory.
+
+About reporting bugs...
+
+The correct address for reporting bugs found with gdb is
+"bug-gdb@prep.ai.mit.edu".  Please email all bugs to that address.
+
+About xgdb...
+
+Hopefully a new xgdb will be in 4.x.
+
+xgdb.c was provided to us by the user community; it is not an integral
+part of the gdb distribution.  The problem of providing visual
+debugging support on top of gdb is peripheral to the GNU project and
+(at least right now) we can't afford to put time into it.  So while we
+will be happy to incorporate user fixes to xgdb.c, we do not guarantee
+that it will work and we will not fix bugs reported in it.  See
+XGDB-README for one person's opinion about what is wrong with the
+current xgdb.  Someone is working on writing a new XGDB, so improving
+(e.g. by fixing it so that it will work, if it doesn't currently) the
+current one is not worth it.
+
+For those intersted in auto display of source and the availability of
+an editor while debugging I suggest trying gdb-mode in gnu-emacs
+(Try typing M-x gdb RETURN).  Comments on this mode are welcome.
+
+About the machine-dependent files...
+
+tconfig/<machine>
+This contains Makefile stuff for when the target system is <machine>.
+It also specifies the name of the tm-XXX.h file for this machine.
+
+xconfig/<machine>
+This contains Makefile stuff for when the host system is <machine>.
+It also specifies the name of the xm-XXX.h file for this machine.
+
+tm-XXX.h (tm.h is a link to this file, created by config.gdb).
+This file contains macro definitions that express information
+about the target machine's registers, stack frame format and instructions.
+
+xm-XXX.h (xm.h is a link to this file, created by config.gdb).
+This contains macro definitions describing the host system environment,
+such as byte order, host C compiler and library, ptrace support,
+and core file structure.
+
+<machine>-opcode.h
+<machine>-pinsn.c
+These files contain the information necessary to print instructions
+for your cpu type.  <machine>-opcode.h includes some large initialized
+data structures, which is strange for a ".h" file, but it's OK since
+it is only included in one place.  <machine>-opcode.h is shared
+between the debugger and the assembler (if the GNU assembler has been
+ported to that machine), whereas <machine>-pinsn.c is specific to GDB.
+
+<machine>-tdep.c
+This file contains any miscellaneous code required for this machine
+as a target.  On some machines it doesn't exist at all.  Its existence
+is specified in the tconfig/XXX file.
+
+<machine>-xdep.c
+This file contains any miscellaneous code required for this machine
+as a host.  On some machines it doesn't exist at all.  Its existence
+is specified in the xconfig/XXX file.
+
+infptrace.c
+This is the low level interface to inferior processes for systems
+using the Unix ptrace call in a vanilla way.  Some systems have their
+own routines in <machine>-xdep.c.  Whether or not it is used
+is specified in the xconfig/XXX file.
+
+coredep.c
+Machine and system-dependent aspects of reading core files.  Some
+machines use coredep.c; some have the routines in <machine>-xdep.c.
+Whether or not it is used is specified in the xconfig/XXX file.
+Now that BFD is used to read core files, virtually all machines should
+use coredep.c and should just provide fetch_core_registers in
+<machine>-xdep.c.
+
+exec.c 
+Machine and system-dependent aspects of reading executable files.
+Some machines use exec.c; some have the routines in <machine>-tdep.c
+Since BFD, virtually all machines should use exec.c.
+
+About writing code for GDB...
+
+We appreciate having users contribute code that is of general use, but
+for it to be included in future GDB releases it must be cleanly
+written.  We do not want to include changes that will needlessly make
+future maintainance difficult.  It is not much harder to do things
+right, and in the long term it is worth it to the GNU project, and
+probably to you individually as well.
+
+Please code according to the GNU coding standards.  If you do not have
+a copy, you can request one by sending mail to gnu@prep.ai.mit.edu.
+
+If you make substantial changes, you'll have to file a copyright
+assignment with the Free Software Foundation before we can produce a
+release that includes your changes.  Send mail requesting the copyright
+assignment to gnu@prep.ai.mit.edu.  Do this early, like before the
+changes actually work, or even before you start them, because a manager
+or lawyer on your end will probably make this a slow process.
+
+Please try to avoid making machine-specific changes to
+machine-independent files.  If this is unavoidable, put a hook in the
+machine-independent file which calls a (possibly) machine-dependent
+macro (for example, the IGNORE_SYMBOL macro can be used for any
+symbols which need to be ignored on a specific machine.  Calling
+IGNORE_SYMBOL in dbxread.c is a lot cleaner than a maze of #if
+defined's).  The machine-independent code should do whatever "most"
+machines want if the macro is not defined in param.h.  Using #if
+defined can sometimes be OK (e.g.  SET_STACK_LIMIT_HUGE) but should be
+conditionalized on a specific feature of an operating system (set in
+tm.h or xm.h) rather than something like #if defined(vax) or #if
+defined(SYSV).  If you use an #ifdef on some symbol that is defined
+in a header file (e.g. #ifdef TIOCSETP), *please* make sure that you
+have #include'd the relevant header file in that module!
+
+It is better to replace entire routines which may be system-specific,
+rather than put in a whole bunch of hooks which are probably not going
+to be helpful for any purpose other than your changes.  For example,
+if you want to modify dbxread.c to deal with DBX debugging symbols
+which are in COFF files rather than BSD a.out files, do something
+along the lines of a macro GET_NEXT_SYMBOL, which could have
+different definitions for COFF and a.out, rather than trying to put
+the necessary changes throughout all the code in dbxread.c that
+currently assumes BSD format.
+
+Please avoid duplicating code.  For example, in GDB 3.x all the stuff
+in infptrace.c was duplicated in *-dep.c, and so changing something
+was very painful.  Thus in GDB 4.x these have all been consolidated
+into infptrace.c.  infptrace.c can deal with variations between
+systems the same way any system-independent file would (hooks, #if
+defined, etc.), and machines which are radically different don't need
+to use infptrace.c at all.  The same was true of core_file_command
+and exec_file_command.
+
+About debugging gdb with itself...
+
+You probably want to do a "make TAGS" after you configure your
+distribution; this will put the machine dependent routines for your
+local machine where they will be accessed first by a M-period .
+
+Also, make sure that you've compiled gdb with your local cc or taken
+appropriate precautions regarding ansification of include files.  See
+the Makefile for more information.
+
+When you run gdb in this directory, it will read a ".gdbinit" file that
+sets up some simple things to make debugging gdb easier.  The "info"
+command, when executed without a subcommand in a gdb being debugged by
+gdb, will pop you back up to the top level gdb.  See .gdbinit for details.
+\f
+(this is for editing this file with GNU emacs)
+Local Variables:
+mode: text
+End:
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
new file mode 100644 (file)
index 0000000..b4fe1b5
--- /dev/null
@@ -0,0 +1,406 @@
+/* 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.  */
+
+#include "defs.h"
+#include "param.h"
+#include "frame.h"
+#include "inferior.h"
+#include "arm-opcode.h"
+
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/dir.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <sys/ptrace.h>
+#include <machine/reg.h>
+
+#define N_TXTADDR(hdr) 0x8000
+#define N_DATADDR(hdr) (hdr.a_text + 0x8000)
+
+#include "gdbcore.h"
+#include <sys/user.h>          /* After a.out.h  */
+#include <sys/file.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+
+\f
+/* Work with core dump and executable files, for GDB. 
+   This code would be in core.c if it weren't machine-dependent. */
+
+/* Structure to describe the chain of shared libraries used
+   by the execfile.
+   e.g. prog shares Xt which shares X11 which shares c. */
+
+struct shared_library {
+    struct exec_header header;
+    char name[SHLIBLEN];
+    CORE_ADDR text_start;      /* CORE_ADDR of 1st byte of text, this file */
+    long data_offset;          /* offset of data section in file */
+    int chan;                  /* file descriptor for the file */
+    struct shared_library *shares; /* library this one shares */
+};
+static struct shared_library *shlib = 0;
+
+/* Hook for `exec_file_command' command to call.  */
+
+extern void (*exec_file_display_hook) ();
+   
+static CORE_ADDR unshared_text_start;
+
+/* extended header from exec file (for shared library info) */
+
+static struct exec_header exec_header;
+
+void
+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;
+  unshared_text_start = 0;
+  text_end = 0;
+  exec_data_start = 0;
+  exec_data_end = 0;
+  if (execchan >= 0)
+    close (execchan);
+  execchan = -1;
+  if (shlib) {
+      close_shared_library(shlib);
+      shlib = 0;
+  }
+
+  /* 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);
+
+      {
+       struct stat st_exec;
+
+#ifdef HEADER_SEEK_FD
+       HEADER_SEEK_FD (execchan);
+#endif
+       
+       val = myread (execchan, &exec_header, sizeof exec_header);
+       exec_aouthdr = exec_header.a_exec;
+
+       if (val < 0)
+         perror_with_name (filename);
+
+       text_start = 0x8000;
+
+       /* Look for shared library if needed */
+       if (exec_header.a_exec.a_magic & MF_USES_SL)
+           shlib = open_shared_library(exec_header.a_shlibname, text_start);
+
+       text_offset = N_TXTOFF (exec_aouthdr);
+       exec_data_offset = N_TXTOFF (exec_aouthdr) + exec_aouthdr.a_text;
+
+       if (shlib) {
+           unshared_text_start = shared_text_end(shlib) & ~0x7fff;
+           stack_start = shlib->header.a_exec.a_sldatabase;
+           stack_end = STACK_END_ADDR;
+       } else
+           unshared_text_start = 0x8000;
+       text_end = unshared_text_start + exec_aouthdr.a_text;
+
+       exec_data_start = unshared_text_start + exec_aouthdr.a_text;
+        exec_data_end = exec_data_start + exec_aouthdr.a_data;
+
+       data_start = exec_data_start;
+       data_end += exec_data_start;
+
+       fstat (execchan, &st_exec);
+       exec_mtime = st_exec.st_mtime;
+      }
+
+      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);
+}
+
+/* Read from the program's memory (except for inferior processes).
+   This function is misnamed, since it only reads, never writes; and
+   since it will use the core file and/or executable file as necessary.
+
+   It should be extended to write as well as read, FIXME, for patching files.
+
+   Return 0 if address could be read, EIO if addresss out of bounds.  */
+
+int
+xfer_core_file (memaddr, myaddr, len)
+     CORE_ADDR memaddr;
+     char *myaddr;
+     int len;
+{
+  register int i;
+  register int val;
+  int xferchan;
+  char **xferfile;
+  int fileptr;
+  int returnval = 0;
+
+  while (len > 0)
+    {
+      xferfile = 0;
+      xferchan = 0;
+
+      /* Determine which file the next bunch of addresses reside in,
+        and where in the file.  Set the file's read/write pointer
+        to point at the proper place for the desired address
+        and set xferfile and xferchan for the correct file.
+
+        If desired address is nonexistent, leave them zero.
+
+        i is set to the number of bytes that can be handled
+        along with the next address.
+
+        We put the most likely tests first for efficiency.  */
+
+      /* Note that if there is no core file
+        data_start and data_end are equal.  */
+      if (memaddr >= data_start && memaddr < data_end)
+       {
+         i = min (len, data_end - memaddr);
+         fileptr = memaddr - data_start + data_offset;
+         xferfile = &corefile;
+         xferchan = corechan;
+       }
+      /* Note that if there is no core file
+        stack_start and stack_end define the shared library data.  */
+      else if (memaddr >= stack_start && memaddr < stack_end)
+       {
+           if (corechan < 0) {
+               struct shared_library *lib;
+               for (lib = shlib; lib; lib = lib->shares)
+                   if (memaddr >= lib->header.a_exec.a_sldatabase &&
+                       memaddr < lib->header.a_exec.a_sldatabase +
+                         lib->header.a_exec.a_data)
+                       break;
+               if (lib) {
+                   i = min (len, lib->header.a_exec.a_sldatabase +
+                            lib->header.a_exec.a_data - memaddr);
+                   fileptr = lib->data_offset + memaddr -
+                       lib->header.a_exec.a_sldatabase;
+                   xferfile = execfile;
+                   xferchan = lib->chan;
+               }
+           } else {
+               i = min (len, stack_end - memaddr);
+               fileptr = memaddr - stack_start + stack_offset;
+               xferfile = &corefile;
+               xferchan = corechan;
+           }
+       }
+      else if (corechan < 0
+              && memaddr >= exec_data_start && memaddr < exec_data_end)
+       {
+         i = min (len, exec_data_end - memaddr);
+         fileptr = memaddr - exec_data_start + exec_data_offset;
+         xferfile = &execfile;
+         xferchan = execchan;
+       }
+      else if (memaddr >= text_start && memaddr < text_end)
+       {
+           struct shared_library *lib;
+           for (lib = shlib; lib; lib = lib->shares)
+               if (memaddr >= lib->text_start &&
+                   memaddr < lib->text_start + lib->header.a_exec.a_text)
+                   break;
+           if (lib) {
+               i = min (len, lib->header.a_exec.a_text +
+                        lib->text_start - memaddr);
+               fileptr = memaddr - lib->text_start + text_offset;
+               xferfile = &execfile;
+               xferchan = lib->chan;
+           } else {
+               i = min (len, text_end - memaddr);
+               fileptr = memaddr - unshared_text_start + text_offset;
+               xferfile = &execfile;
+               xferchan = execchan;
+           }
+       }
+      else if (memaddr < text_start)
+       {
+         i = min (len, text_start - memaddr);
+       }
+      else if (memaddr >= text_end
+              && memaddr < (corechan >= 0? data_start : exec_data_start))
+       {
+         i = min (len, data_start - memaddr);
+       }
+      else if (corechan >= 0
+              && memaddr >= data_end && memaddr < stack_start)
+       {
+         i = min (len, stack_start - memaddr);
+       }
+      else if (corechan < 0 && memaddr >= exec_data_end)
+       {
+         i = min (len, - memaddr);
+       }
+      else if (memaddr >= stack_end && stack_end != 0)
+       {
+         i = min (len, - memaddr);
+       }
+      else
+       {
+         /* Address did not classify into one of the known ranges.
+            This shouldn't happen; we catch the endpoints.  */
+         fatal ("Internal: Bad case logic in xfer_core_file.");
+       }
+
+      /* Now we know which file to use.
+        Set up its pointer and transfer the data.  */
+      if (xferfile)
+       {
+         if (*xferfile == 0)
+           if (xferfile == &execfile)
+             error ("No program file to examine.");
+           else
+             error ("No core dump file or running program to examine.");
+         val = lseek (xferchan, fileptr, 0);
+         if (val < 0)
+           perror_with_name (*xferfile);
+         val = myread (xferchan, myaddr, i);
+         if (val < 0)
+           perror_with_name (*xferfile);
+       }
+      /* If this address is for nonexistent memory,
+        read zeros if reading, or do nothing if writing.
+        Actually, we never right.  */
+      else
+       {
+         bzero (myaddr, i);
+         returnval = EIO;
+       }
+
+      memaddr += i;
+      myaddr += i;
+      len -= i;
+    }
+  return returnval;
+}
+\f
+/* APCS (ARM procedure call standard) defines the following prologue:
+
+   mov         ip, sp
+  [stmfd       sp!, {a1,a2,a3,a4}]
+   stmfd       sp!, {...,fp,ip,lr,pc}
+  [stfe                f7, [sp, #-12]!]
+  [stfe                f6, [sp, #-12]!]
+  [stfe                f5, [sp, #-12]!]
+  [stfe                f4, [sp, #-12]!]
+   sub         fp, ip, #nn     // nn == 20 or 4 depending on second ins
+*/
+
+CORE_ADDR
+skip_prologue(pc)
+CORE_ADDR pc;
+{
+    union insn_fmt op;
+    CORE_ADDR skip_pc = pc;
+
+    op.ins = read_memory_integer(skip_pc, 4);
+    /* look for the "mov ip,sp" */
+    if (op.generic.type != TYPE_ARITHMETIC ||
+       op.arith.opcode != OPCODE_MOV ||
+       op.arith.dest != SPTEMP ||
+       op.arith.operand2 != SP) return pc;
+    skip_pc += 4;
+    /* skip the "stmfd sp!,{a1,a2,a3,a4}" if its there */
+    op.ins = read_memory_integer(skip_pc, 4);
+    if (op.generic.type == TYPE_BLOCK_BRANCH &&
+       op.generic.subtype == SUBTYPE_BLOCK &&
+       op.block.mask == 0xf &&
+       op.block.base == SP &&
+       op.block.is_load == 0 &&
+       op.block.writeback == 1 &&
+       op.block.increment == 0 &&
+       op.block.before == 1) skip_pc += 4;
+    /* skip the "stmfd sp!,{...,fp,ip,lr,pc} */
+    op.ins = read_memory_integer(skip_pc, 4);
+    if (op.generic.type != TYPE_BLOCK_BRANCH ||
+       op.generic.subtype != SUBTYPE_BLOCK ||
+       /* the mask should look like 110110xxxxxx0000 */
+       (op.block.mask & 0xd800) != 0xd800 ||
+       op.block.base != SP ||
+       op.block.is_load != 0 ||
+       op.block.writeback != 1 ||
+       op.block.increment != 0 ||
+       op.block.before != 1) return pc;
+    skip_pc += 4;
+    /* check for "sub fp,ip,#nn" */
+    op.ins = read_memory_integer(skip_pc, 4);
+    if (op.generic.type != TYPE_ARITHMETIC ||
+       op.arith.opcode != OPCODE_SUB ||
+       op.arith.dest != FP ||
+       op.arith.operand1 != SPTEMP) return pc;
+    return skip_pc + 4;
+}
+
+static void
+print_fpu_flags(flags)
+int flags;
+{
+    if (flags & (1 << 0)) fputs("IVO ", stdout);
+    if (flags & (1 << 1)) fputs("DVZ ", stdout);
+    if (flags & (1 << 2)) fputs("OFL ", stdout);
+    if (flags & (1 << 3)) fputs("UFL ", stdout);
+    if (flags & (1 << 4)) fputs("INX ", stdout);
+    putchar('\n');
+}
+
+void
+arm_float_info()
+{
+    register unsigned long status = read_register(FPS_REGNUM);
+    int type;
+
+    type = (status >> 24) & 127;
+    printf("%s FPU type %d\n",
+          (status & (1<<31)) ? "Hardware" : "Software",
+          type);
+    fputs("mask: ", stdout);
+    print_fpu_flags(status >> 16);
+    fputs("flags: ", stdout);
+    print_fpu_flags(status);
+}
diff --git a/gdb/blockframe.c b/gdb/blockframe.c
new file mode 100644 (file)
index 0000000..7971166
--- /dev/null
@@ -0,0 +1,650 @@
+/* Get info from stack frames;
+   convert between frames, blocks, functions and pc values.
+   Copyright (C) 1986, 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 "defs.h"
+#include "param.h"
+#include "symtab.h"
+#include "frame.h"
+#include "gdbcore.h"
+#include "value.h"             /* for read_register */
+#include "target.h"            /* for target_has_stack */
+
+/* Required by INIT_EXTRA_FRAME_INFO on 88k.  */
+#include <setjmp.h>
+#include <obstack.h>
+
+CORE_ADDR read_pc ();          /* In infcmd.c */
+
+/* Start and end of object file containing the entry point.
+   STARTUP_FILE_END is the first address of the next file.
+   This file is assumed to be a startup file
+   and frames with pc's inside it
+   are treated as nonexistent.
+
+   Setting these variables is necessary so that backtraces do not fly off
+   the bottom of the stack.  */
+CORE_ADDR startup_file_start;
+CORE_ADDR startup_file_end;
+
+/* Is ADDR outside the startup file?  Note that if your machine
+   has a way to detect the bottom of the stack, there is no need
+   to call this function from FRAME_CHAIN_VALID; the reason for
+   doing so is that some machines have no way of detecting bottom
+   of stack.  */
+int
+outside_startup_file (addr)
+     CORE_ADDR addr;
+{
+  return !(addr >= startup_file_start && addr < startup_file_end);
+}
+
+/* Address of innermost stack frame (contents of FP register) */
+
+static FRAME current_frame;
+
+/*
+ * Cache for frame addresses already read by gdb.  Valid only while
+ * inferior is stopped.  Control variables for the frame cache should
+ * be local to this module.
+ */
+struct obstack frame_cache_obstack;
+
+/* Return the innermost (currently executing) stack frame.  */
+
+FRAME
+get_current_frame ()
+{
+  /* We assume its address is kept in a general register;
+     param.h says which register.  */
+
+  return current_frame;
+}
+
+void
+set_current_frame (frame)
+     FRAME frame;
+{
+  current_frame = frame;
+}
+
+FRAME
+create_new_frame (addr, pc)
+     FRAME_ADDR addr;
+     CORE_ADDR pc;
+{
+  struct frame_info *fci;      /* Same type as FRAME */
+
+  fci = (struct frame_info *)
+    obstack_alloc (&frame_cache_obstack,
+                  sizeof (struct frame_info));
+
+  /* Arbitrary frame */
+  fci->next = (struct frame_info *) 0;
+  fci->prev = (struct frame_info *) 0;
+  fci->frame = addr;
+  fci->next_frame = 0;         /* Since arbitrary */
+  fci->pc = pc;
+
+#ifdef INIT_EXTRA_FRAME_INFO
+  INIT_EXTRA_FRAME_INFO (fci);
+#endif
+
+  return fci;
+}
+
+/* Return the frame that called FRAME.
+   If FRAME is the original frame (it has no caller), return 0.  */
+
+FRAME
+get_prev_frame (frame)
+     FRAME frame;
+{
+  /* We're allowed to know that FRAME and "struct frame_info *" are
+     the same */
+  return get_prev_frame_info (frame);
+}
+
+/* Return the frame that FRAME calls (0 if FRAME is the innermost
+   frame).  */
+
+FRAME
+get_next_frame (frame)
+     FRAME frame;
+{
+  /* We're allowed to know that FRAME and "struct frame_info *" are
+     the same */
+  return frame->next;
+}
+
+/*
+ * Flush the entire frame cache.
+ */
+void
+flush_cached_frames ()
+{
+  /* Since we can't really be sure what the first object allocated was */
+  obstack_free (&frame_cache_obstack, 0);
+  obstack_init (&frame_cache_obstack);
+
+  current_frame = (struct frame_info *) 0; /* Invalidate cache */
+}
+
+/* Return a structure containing various interesting information
+   about a specified stack frame.  */
+/* How do I justify including this function?  Well, the FRAME
+   identifier format has gone through several changes recently, and
+   it's not completely inconceivable that it could happen again.  If
+   it does, have this routine around will help */
+
+struct frame_info *
+get_frame_info (frame)
+     FRAME frame;
+{
+  return frame;
+}
+
+/* If a machine allows frameless functions, it should define a macro
+   FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS) in param.h.  FI is the struct
+   frame_info for the frame, and FRAMELESS should be set to nonzero
+   if it represents a frameless function invocation.  */
+
+/* Return nonzero if the function for this frame has a prologue.  Many
+   machines can define FRAMELESS_FUNCTION_INVOCATION to just call this
+   function.  */
+
+int
+frameless_look_for_prologue (frame)
+     FRAME frame;
+{
+  CORE_ADDR func_start, after_prologue;
+  func_start = (get_pc_function_start (frame->pc) +
+               FUNCTION_START_OFFSET);
+  if (func_start)
+    {
+      after_prologue = func_start;
+      SKIP_PROLOGUE (after_prologue);
+      return after_prologue == func_start;
+    }
+  else
+    /* If we can't find the start of the function, we don't really
+       know whether the function is frameless, but we should be able
+       to get a reasonable (i.e. best we can do under the
+       circumstances) backtrace by saying that it isn't.  */
+    return 0;
+}
+
+#if !defined (INIT_FRAME_PC)
+#define INIT_FRAME_PC(fromleaf, prev) \
+  prev->pc = (fromleaf ? SAVED_PC_AFTER_CALL (prev->next) : \
+             prev->next ? FRAME_SAVED_PC (prev->next) : read_pc ());
+#endif
+
+/* Return a structure containing various interesting information
+   about the frame that called NEXT_FRAME.  Returns NULL
+   if there is no such frame.  */
+
+struct frame_info *
+get_prev_frame_info (next_frame)
+     FRAME next_frame;
+{
+  FRAME_ADDR address;
+  struct frame_info *prev;
+  int fromleaf = 0;
+
+  /* If the requested entry is in the cache, return it.
+     Otherwise, figure out what the address should be for the entry
+     we're about to add to the cache. */
+
+  if (!next_frame)
+    {
+      if (!current_frame)
+       {
+         error ("You haven't set up a process's stack to examine.");
+       }
+
+      return current_frame;
+    }
+
+  /* If we have the prev one, return it */
+  if (next_frame->prev)
+    return next_frame->prev;
+
+  /* On some machines it is possible to call a function without
+     setting up a stack frame for it.  On these machines, we
+     define this macro to take two args; a frameinfo pointer
+     identifying a frame and a variable to set or clear if it is
+     or isn't leafless.  */
+#ifdef FRAMELESS_FUNCTION_INVOCATION
+  /* Still don't want to worry about this except on the innermost
+     frame.  This macro will set FROMLEAF if NEXT_FRAME is a
+     frameless function invocation.  */
+  if (!(next_frame->next))
+    {
+      FRAMELESS_FUNCTION_INVOCATION (next_frame, fromleaf);
+      if (fromleaf)
+       address = next_frame->frame;
+    }
+#endif
+
+  if (!fromleaf)
+    {
+      /* Two macros defined in tm.h specify the machine-dependent
+        actions to be performed here.
+        First, get the frame's chain-pointer.
+        If that is zero, the frame is the outermost frame or a leaf
+        called by the outermost frame.  This means that if start
+        calls main without a frame, we'll return 0 (which is fine
+        anyway).
+
+        Nope; there's a problem.  This also returns when the current
+        routine is a leaf of main.  This is unacceptable.  We move
+        this to after the ffi test; I'd rather have backtraces from
+        start go curfluy than have an abort called from main not show
+        main.  */
+      address = FRAME_CHAIN (next_frame);
+      if (!FRAME_CHAIN_VALID (address, next_frame))
+       return 0;
+      address = FRAME_CHAIN_COMBINE (address, next_frame);
+    }
+
+  prev = (struct frame_info *)
+    obstack_alloc (&frame_cache_obstack,
+                  sizeof (struct frame_info));
+
+  if (next_frame)
+    next_frame->prev = prev;
+  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. */
+  INIT_FRAME_PC(fromleaf, prev);
+
+  return prev;
+}
+
+CORE_ADDR
+get_frame_pc (frame)
+     FRAME frame;
+{
+  struct frame_info *fi;
+  fi = get_frame_info (frame);
+  return fi->pc;
+}
+
+#if defined (FRAME_FIND_SAVED_REGS)
+/* Find the addresses in which registers are saved in FRAME.  */
+
+void
+get_frame_saved_regs (frame_info_addr, saved_regs_addr)
+     struct frame_info *frame_info_addr;
+     struct frame_saved_regs *saved_regs_addr;
+{
+  FRAME_FIND_SAVED_REGS (frame_info_addr, *saved_regs_addr);
+}
+#endif
+
+/* Return the innermost lexical block in execution
+   in a specified stack frame.  The frame address is assumed valid.  */
+
+struct block *
+get_frame_block (frame)
+     FRAME frame;
+{
+  struct frame_info *fi;
+  CORE_ADDR pc;
+
+  fi = get_frame_info (frame);
+
+  pc = fi->pc;
+  if (fi->next_frame != 0)
+    /* We are not in the innermost frame.  We need to subtract one to
+       get the correct block, in case the call instruction was the
+       last instruction of the block.  If there are any machines on
+       which the saved pc does not point to after the call insn, we
+       probably want to make fi->pc point after the call insn anyway.  */
+    --pc;
+  return block_for_pc (pc);
+}
+
+struct block *
+get_current_block ()
+{
+  return block_for_pc (read_pc ());
+}
+
+CORE_ADDR
+get_pc_function_start (pc)
+     CORE_ADDR pc;
+{
+  register struct block *bl = block_for_pc (pc);
+  register struct symbol *symbol;
+  if (bl == 0 || (symbol = block_function (bl)) == 0)
+    {
+      register int misc_index = find_pc_misc_function (pc);
+      if (misc_index >= 0)
+       return misc_function_vector[misc_index].address;
+      return 0;
+    }
+  bl = SYMBOL_BLOCK_VALUE (symbol);
+  return BLOCK_START (bl);
+}
+
+/* Return the symbol for the function executing in frame FRAME.  */
+
+struct symbol *
+get_frame_function (frame)
+     FRAME frame;
+{
+  register struct block *bl = get_frame_block (frame);
+  if (bl == 0)
+    return 0;
+  return block_function (bl);
+}
+\f
+/* Return the blockvector immediately containing the innermost lexical block
+   containing the specified pc value, or 0 if there is none.
+   PINDEX is a pointer to the index value of the block.  If PINDEX
+   is NULL, we don't pass this information back to the caller.  */
+
+struct blockvector *
+blockvector_for_pc (pc, pindex)
+     register CORE_ADDR pc;
+     int *pindex;
+{
+  register struct block *b;
+  register int bot, top, half;
+  register struct symtab *s;
+  struct blockvector *bl;
+
+  /* First search all symtabs for one whose file contains our pc */
+  s = find_pc_symtab (pc);
+  if (s == 0)
+    return 0;
+
+  bl = BLOCKVECTOR (s);
+  b = BLOCKVECTOR_BLOCK (bl, 0);
+
+  /* Then search that symtab for the smallest block that wins.  */
+  /* Use binary search to find the last block that starts before PC.  */
+
+  bot = 0;
+  top = BLOCKVECTOR_NBLOCKS (bl);
+
+  while (top - bot > 1)
+    {
+      half = (top - bot + 1) >> 1;
+      b = BLOCKVECTOR_BLOCK (bl, bot + half);
+      if (BLOCK_START (b) <= pc)
+       bot += half;
+      else
+       top = bot + half;
+    }
+
+  /* Now search backward for a block that ends after PC.  */
+
+  while (bot >= 0)
+    {
+      b = BLOCKVECTOR_BLOCK (bl, bot);
+      if (BLOCK_END (b) > pc)
+       {
+         if (pindex)
+           *pindex = bot;
+         return bl;
+       }
+      bot--;
+    }
+
+  return 0;
+}
+
+/* Return the innermost lexical block containing the specified pc value,
+   or 0 if there is none.  */
+
+struct block *
+block_for_pc (pc)
+     register CORE_ADDR pc;
+{
+  register struct blockvector *bl;
+  int index;
+
+  bl = blockvector_for_pc (pc, &index);
+  if (bl)
+    return BLOCKVECTOR_BLOCK (bl, index);
+  return 0;
+}
+
+/* Return the function containing pc value PC.
+   Returns 0 if function is not known.  */
+
+struct symbol *
+find_pc_function (pc)
+     CORE_ADDR pc;
+{
+  register struct block *b = block_for_pc (pc);
+  if (b == 0)
+    return 0;
+  return block_function (b);
+}
+
+/* These variables are used to cache the most recent result
+ * of find_pc_partial_function. */
+
+static CORE_ADDR cache_pc_function_low = 0;
+static CORE_ADDR cache_pc_function_high = 0;
+static char *cache_pc_function_name = 0;
+
+/* Clear cache, e.g. when symbol table is discarded. */
+
+void
+clear_pc_function_cache()
+{
+  cache_pc_function_low = 0;
+  cache_pc_function_high = 0;
+  cache_pc_function_name = (char *)0;
+}
+
+/* Finds the "function" (text symbol) that is smaller than PC
+   but greatest of all of the potential text symbols.  Sets
+   *NAME and/or *ADDRESS conditionally if that pointer is non-zero.
+   Returns 0 if it couldn't find anything, 1 if it did.  On a zero
+   return, *NAME and *ADDRESS are always set to zero.  On a 1 return,
+   *NAME and *ADDRESS contain real information.  */
+
+int
+find_pc_partial_function (pc, name, address)
+     CORE_ADDR pc;
+     char **name;
+     CORE_ADDR *address;
+{
+  struct partial_symtab *pst;
+  struct symbol *f;
+  int miscfunc;
+  struct partial_symbol *psb;
+
+  if (pc >= cache_pc_function_low && pc < cache_pc_function_high)
+    {
+       if (address)
+           *address = cache_pc_function_low;
+       if (name)
+           *name = cache_pc_function_name;
+       return 1;
+    }
+
+  pst = find_pc_psymtab (pc);
+  if (pst)
+    {
+      if (pst->readin)
+       {
+         /* The information we want has already been read in.
+            We can go to the already readin symbols and we'll get
+            the best possible answer.  */
+         f = find_pc_function (pc);
+         if (!f)
+           {
+           return_error:
+             /* No available symbol.  */
+             if (name != 0)
+               *name = 0;
+             if (address != 0)
+               *address = 0;
+             return 0;
+           }
+
+         cache_pc_function_low = BLOCK_START (SYMBOL_BLOCK_VALUE (f));
+         cache_pc_function_high = BLOCK_END (SYMBOL_BLOCK_VALUE (f));
+         cache_pc_function_name = SYMBOL_NAME (f);
+         if (name)
+           *name = cache_pc_function_name;
+         if (address)
+           *address = cache_pc_function_low;
+         return 1;
+       }
+
+      /* Get the information from a combination of the pst
+        (static symbols), and the misc function vector (extern
+        symbols).  */
+      miscfunc = find_pc_misc_function (pc);
+      psb = find_pc_psymbol (pst, pc);
+
+      if (!psb && miscfunc == -1)
+       {
+         goto return_error;
+       }
+      if (psb
+         && (miscfunc == -1
+             || (SYMBOL_VALUE_ADDRESS (psb)
+                 >= misc_function_vector[miscfunc].address)))
+       {
+         /* This case isn't being cached currently. */
+         if (address)
+           *address = SYMBOL_VALUE_ADDRESS (psb);
+         if (name)
+           *name = SYMBOL_NAME (psb);
+         return 1;
+       }
+    }
+  else
+    /* Must be in the misc function stuff.  */
+    {
+      miscfunc = find_pc_misc_function (pc);
+      if (miscfunc == -1)
+       goto return_error;
+    }
+
+  {
+    if (misc_function_vector[miscfunc].type == mf_text)
+      cache_pc_function_low = misc_function_vector[miscfunc].address;
+    else
+      /* It is a transfer table for Sun shared libraries.  */
+      cache_pc_function_low = pc - FUNCTION_START_OFFSET;
+  }
+  cache_pc_function_name = misc_function_vector[miscfunc].name;
+  if (miscfunc < misc_function_count && 1 /* FIXME mf_text again? */ )
+    cache_pc_function_high = misc_function_vector[miscfunc+1].address;
+  else
+    cache_pc_function_high = cache_pc_function_low + 1;
+  if (address)
+    *address = cache_pc_function_low;
+  if (name)
+    *name = cache_pc_function_name;
+  return 1;
+}
+
+/* Find the misc function whose address is the largest
+   while being less than PC.  Return its index in misc_function_vector.
+   Returns -1 if PC is not in suitable range.  */
+
+int
+find_pc_misc_function (pc)
+     register CORE_ADDR pc;
+{
+  register int lo = 0;
+  register int hi = misc_function_count-1;
+  register int new;
+
+  /* Note that the last thing in the vector is always _etext.  */
+  /* Actually, "end", now that non-functions
+     go on the misc_function_vector.  */
+
+  /* Above statement is not *always* true - fix for case where there are */
+  /* no misc functions at all (ie no symbol table has been read). */
+  if (hi < 0) return -1;        /* no misc functions recorded */
+
+  /* trivial reject range test */
+  if (pc < misc_function_vector[0].address ||
+      pc > misc_function_vector[hi].address)
+    return -1;
+
+  /* Note that the following search will not return hi if
+     pc == misc_function_vector[hi].address.  If "end" points to the
+     first unused location, this is correct and the above test
+     simply needs to be changed to
+     "pc >= misc_function_vector[hi].address".  */
+  do {
+    new = (lo + hi) >> 1;
+    if (misc_function_vector[new].address == pc)
+      return new;              /* an exact match */
+    else if (misc_function_vector[new].address > pc)
+      hi = new;
+    else
+      lo = new;
+  } while (hi-lo != 1);
+
+  /* if here, we had no exact match, so return the lower choice */
+  return lo;
+}
+
+/* Return the innermost stack frame executing inside of the specified block,
+   or zero if there is no such frame.  */
+
+FRAME
+block_innermost_frame (block)
+     struct block *block;
+{
+  struct frame_info *fi;
+  register FRAME frame;
+  register CORE_ADDR start = BLOCK_START (block);
+  register CORE_ADDR end = BLOCK_END (block);
+
+  frame = 0;
+  while (1)
+    {
+      frame = get_prev_frame (frame);
+      if (frame == 0)
+       return 0;
+      fi = get_frame_info (frame);
+      if (fi->pc >= start && fi->pc < end)
+       return frame;
+    }
+}
+
+void
+_initialize_blockframe ()
+{
+  obstack_init (&frame_cache_obstack);
+}
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
new file mode 100644 (file)
index 0000000..6bc621d
--- /dev/null
@@ -0,0 +1,2259 @@
+/* Everything about breakpoints, for GDB.
+   Copyright (C) 1986, 1987, 1989, 1990 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 <stdio.h>
+#include <ctype.h>
+#include "defs.h"
+#include "param.h"
+#include "symtab.h"
+#include "frame.h"
+#include "breakpoint.h"
+#include "expression.h"
+#include "gdbcore.h"
+#include "gdbcmd.h"
+#include "value.h"
+#include "ctype.h"
+#include "command.h"
+#include "inferior.h"
+#include "target.h"
+#include <string.h>
+
+extern int addressprint;               /* Print machine addresses? */
+extern int demangle;                   /* Print de-mangled symbol names? */
+
+extern int catch_errors ();
+extern void set_next_address ();       /* ...for x/ command */
+
+/* Are we executing breakpoint commands?  */
+static int executing_breakpoint_commands;
+
+/* States of enablement of breakpoint.
+   `temporary' means disable when hit.
+   `delete' means delete when hit.  */
+
+enum enable { disabled, enabled, temporary, delete};
+
+/* Not that the ->silent field is not currently used by any commands
+   (though the code is in there if it was to be and set_raw_breakpoint
+   does set it to 0).  I implemented it because I thought it would be
+   useful for a hack I had to put in; I'm going to leave it in because
+   I can see how there might be times when it would indeed be useful */
+
+/* This is for a breakpoint or a watchpoint.  */
+
+struct breakpoint
+{
+  struct breakpoint *next;
+  /* Number assigned to distinguish breakpoints.  */
+  int number;
+  /* Address to break at, or NULL if not a breakpoint.  */
+  CORE_ADDR address;
+  /* Line number of this address.  Redundant.  Only matters if address
+     is non-NULL.  */
+  int line_number;
+  /* Symtab of file of this address.  Redundant.  Only matters if address
+     is non-NULL.  */
+  struct symtab *symtab;
+  /* Zero means disabled; remember the info but don't break here.  */
+  enum enable enable;
+  /* Non-zero means a silent breakpoint (don't print frame info
+     if we stop here). */
+  unsigned char silent;
+  /* Number of stops at this breakpoint that should
+     be continued automatically before really stopping.  */
+  int ignore_count;
+  /* "Real" contents of byte where breakpoint has been inserted.
+     Valid only when breakpoints are in the program.  Under the complete
+     control of the target insert_breakpoint and remove_breakpoint routines.
+     No other code should assume anything about the value(s) here.  */
+  char shadow_contents[BREAKPOINT_MAX];
+  /* Nonzero if this breakpoint is now inserted.  Only matters if address
+     is non-NULL.  */
+  char inserted;
+  /* Nonzero if this is not the first breakpoint in the list
+     for the given address.  Only matters if address is non-NULL.  */
+  char duplicate;
+  /* Chain of command lines to execute when this breakpoint is hit.  */
+  struct command_line *commands;
+  /* Stack depth (address of frame).  If nonzero, break only if fp
+     equals this.  */
+  FRAME_ADDR frame;
+  /* Conditional.  Break only if this expression's value is nonzero.  */
+  struct expression *cond;
+
+  /* String we used to set the breakpoint (malloc'd).  Only matters if
+     address is non-NULL.  */
+  char *addr_string;
+  /* String form of the breakpoint condition (malloc'd), or NULL if there
+     is no condition.  */
+  char *cond_string;
+
+  /* The expression we are watching, or NULL if not a watchpoint.  */
+  struct expression *exp;
+  /* The largest block within which it is valid, or NULL if it is
+     valid anywhere (e.g. consists just of global symbols).  */
+  struct block *exp_valid_block;
+  /* Value of the watchpoint the last time we checked it.  */
+  value val;
+};
+
+#define ALL_BREAKPOINTS(b)  for (b = breakpoint_chain; b; b = b->next)
+
+/* Chain of all breakpoints defined.  */
+
+struct breakpoint *breakpoint_chain;
+
+/* Number of last breakpoint made.  */
+
+static int breakpoint_count;
+
+/* Set breakpoint count to NUM.  */
+static void
+set_breakpoint_count (num)
+     int num;
+{
+  breakpoint_count = num;
+  set_internalvar (lookup_internalvar ("bpnum"),
+                  value_from_long (builtin_type_int, (LONGEST) num));
+}
+
+/* Default address, symtab and line to put a breakpoint at
+   for "break" command with no arg.
+   if default_breakpoint_valid is zero, the other three are
+   not valid, and "break" with no arg is an error.
+
+   This set by print_stack_frame, which calls set_default_breakpoint.  */
+
+int default_breakpoint_valid;
+CORE_ADDR default_breakpoint_address;
+struct symtab *default_breakpoint_symtab;
+int default_breakpoint_line;
+
+static void delete_breakpoint ();
+void breakpoint_auto_delete ();
+
+/* Flag indicating extra verbosity for xgdb.  */
+extern int xgdb_verbose;
+\f
+/* *PP is a string denoting a breakpoint.  Get the number of the breakpoint.
+   Advance *PP after the string and any trailing whitespace.
+
+   Currently the string can either be a number or "$" followed by the name
+   of a convenience variable.  Making it an expression wouldn't work well
+   for map_breakpoint_numbers (e.g. "4 + 5 + 6").  */
+static int
+get_number (pp)
+     char **pp;
+{
+  int retval;
+  char *p = *pp;
+
+  if (p == NULL)
+    /* Empty line means refer to the last breakpoint.  */
+    return breakpoint_count;
+  else if (*p == '$')
+    {
+      /* Make a copy of the name, so we can null-terminate it
+        to pass to lookup_internalvar().  */
+      char *varname;
+      char *start = ++p;
+      value val;
+
+      while (isalnum (*p) || *p == '_')
+       p++;
+      varname = (char *) alloca (p - start + 1);
+      strncpy (varname, start, p - start);
+      varname[p - start] = '\0';
+      val = value_of_internalvar (lookup_internalvar (varname));
+      if (TYPE_CODE (VALUE_TYPE (val)) != TYPE_CODE_INT)
+       error (
+"Convenience variables used to specify breakpoints must have integer values."
+              );
+      retval = (int) value_as_long (val);
+    }
+  else
+    {
+      while (*p >= '0' && *p <= '9')
+       ++p;
+      if (p == *pp)
+       /* There is no number here.  (e.g. "cond a == b").  */
+       error_no_arg ("breakpoint number");
+      retval = atoi (*pp);
+    }
+  if (!(isspace (*p) || *p == '\0'))
+    error ("breakpoint number expected");
+  while (isspace (*p))
+    p++;
+  *pp = p;
+  return retval;
+}
+\f
+/* condition N EXP -- set break condition of breakpoint N to EXP.  */
+
+static void
+condition_command (arg, from_tty)
+     char *arg;
+     int from_tty;
+{
+  register struct breakpoint *b;
+  char *p;
+  register int bnum;
+
+  if (arg == 0)
+    error_no_arg ("breakpoint number");
+
+  p = arg;
+  bnum = get_number (&p);
+
+  ALL_BREAKPOINTS (b)
+    if (b->number == bnum)
+      {
+       if (b->cond)
+         {
+           free (b->cond);
+           b->cond = 0;
+         }
+       if (b->cond_string != NULL)
+         free (b->cond_string);
+
+       if (*p == 0)
+         {
+           b->cond = 0;
+           b->cond_string = NULL;
+           if (from_tty)
+             printf ("Breakpoint %d now unconditional.\n", bnum);
+         }
+       else
+         {
+           arg = p;
+           /* I don't know if it matters whether this is the string the user
+              typed in or the decompiled expression.  */
+           b->cond_string = savestring (arg, strlen (arg));
+           b->cond = parse_c_1 (&arg, block_for_pc (b->address), 0);
+           if (*arg)
+             error ("Junk at end of expression");
+         }
+       return;
+      }
+
+  error ("No breakpoint number %d.", bnum);
+}
+
+static void
+commands_command (arg, from_tty)
+     char *arg;
+     int from_tty;
+{
+  register struct breakpoint *b;
+  char *p;
+  register int bnum;
+  struct command_line *l;
+
+  /* If we allowed this, we would have problems with when to
+     free the storage, if we change the commands currently
+     being read from.  */
+
+  if (executing_breakpoint_commands)
+    error ("Can't use the \"commands\" command among a breakpoint's commands.");
+
+  p = arg;
+  bnum = get_number (&p);
+  if (p && *p)
+    error ("Unexpected extra arguments following breakpoint number.");
+      
+  ALL_BREAKPOINTS (b)
+    if (b->number == bnum)
+      {
+       if (input_from_terminal_p ())
+         {
+           printf ("Type commands for when breakpoint %d is hit, one per line.\n\
+End with a line saying just \"end\".\n", bnum);
+           fflush (stdout);
+         }
+       l = read_command_lines ();
+       free_command_lines (&b->commands);
+       b->commands = l;
+       return;
+      }
+  error ("No breakpoint number %d.", bnum);
+}
+\f
+/* insert_breakpoints is used when starting or continuing the program.
+   remove_breakpoints is used when the program stops.
+   Both return zero if successful,
+   or an `errno' value if could not write the inferior.  */
+
+int
+insert_breakpoints ()
+{
+  register struct breakpoint *b;
+  int val = 0;
+  int disabled_breaks = 0;
+
+  ALL_BREAKPOINTS (b)
+    if (b->address != NULL
+       && b->enable != disabled
+       && ! b->inserted
+       && ! b->duplicate)
+      {
+       val = target_insert_breakpoint(b->address, b->shadow_contents);
+       if (val)
+         {
+           /* Can't set the breakpoint.  */
+#if defined (DISABLE_UNSETTABLE_BREAK)
+           if (DISABLE_UNSETTABLE_BREAK (b->address))
+             {
+               val = 0;
+               b->enable = disabled;
+               if (!disabled_breaks)
+                 {
+                   fprintf (stderr,
+                        "Cannot insert breakpoint %d:\n", b->number);
+                   printf_filtered ("Disabling shared library breakpoints:\n");
+                 }
+               disabled_breaks = 1;
+               printf_filtered ("%d ", b->number);
+             }
+           else
+#endif
+             {
+               fprintf (stderr, "Cannot insert breakpoint %d:\n", b->number);
+               memory_error (val, b->address); /* which bombs us out */
+             }
+         }
+       else
+         b->inserted = 1;
+      }
+  if (disabled_breaks)
+    printf_filtered ("\n");
+  return val;
+}
+
+int
+remove_breakpoints ()
+{
+  register struct breakpoint *b;
+  int val;
+
+#ifdef BREAKPOINT_DEBUG
+  printf ("Removing breakpoints.\n");
+#endif /* BREAKPOINT_DEBUG */
+
+  ALL_BREAKPOINTS (b)
+    if (b->address != NULL && b->inserted)
+      {
+       val = target_remove_breakpoint(b->address, b->shadow_contents);
+       if (val)
+         return val;
+       b->inserted = 0;
+#ifdef BREAKPOINT_DEBUG
+       printf ("Removed breakpoint at 0x%x, shadow 0x%x, 0x%x.\n",
+               b->address, b->shadow_contents[0], b->shadow_contents[1]);
+#endif /* BREAKPOINT_DEBUG */
+      }
+
+  return 0;
+}
+
+/* Clear the "inserted" flag in all breakpoints.
+   This is done when the inferior is loaded.  */
+
+void
+mark_breakpoints_out ()
+{
+  register struct breakpoint *b;
+
+  ALL_BREAKPOINTS (b)
+    b->inserted = 0;
+}
+
+/* breakpoint_here_p (PC) returns 1 if an enabled breakpoint exists at PC.
+   When continuing from a location with a breakpoint,
+   we actually single step once before calling insert_breakpoints.  */
+
+int
+breakpoint_here_p (pc)
+     CORE_ADDR pc;
+{
+  register struct breakpoint *b;
+
+  ALL_BREAKPOINTS (b)
+    if (b->enable != disabled && b->address == pc)
+      return 1;
+
+  return 0;
+}
+\f
+/* bpstat stuff.  External routines' interfaces are documented
+   in breakpoint.h.  */
+void
+bpstat_clear (bsp)
+     bpstat *bsp;
+{
+  bpstat p;
+  bpstat q;
+
+  if (bsp == 0)
+    return;
+  p = *bsp;
+  while (p != NULL)
+    {
+      q = p->next;
+      if (p->old_val != NULL)
+       value_free (p->old_val);
+      free (p);
+      p = q;
+    }
+  *bsp = NULL;
+}
+
+bpstat
+bpstat_copy (bs)
+     bpstat bs;
+{
+  bpstat p = NULL;
+  bpstat tmp;
+  bpstat retval;
+
+  if (bs == NULL)
+    return bs;
+
+  for (; bs != NULL; bs = bs->next)
+    {
+      tmp = (bpstat) xmalloc (sizeof (*tmp));
+      bcopy (bs, tmp, sizeof (*tmp));
+      if (p == NULL)
+       /* This is the first thing in the chain.  */
+       retval = tmp;
+      else
+       p->next = tmp;
+      p = tmp;
+    }
+  p->next = NULL;
+  return retval;
+}
+
+int
+bpstat_num (bsp)
+     bpstat *bsp;
+{
+  struct breakpoint *b;
+
+  if ((*bsp) == NULL)
+    return 0;                  /* No more breakpoint values */
+  else
+    {
+      b = (*bsp)->breakpoint_at;
+      *bsp = (*bsp)->next;
+      if (b == NULL)
+       return -1;              /* breakpoint that's been deleted since */
+      else
+        return b->number;      /* We have its number */
+    }
+}
+
+void
+bpstat_clear_actions (bs)
+     bpstat bs;
+{
+  for (; bs != NULL; bs = bs->next)
+    {
+      bs->commands = NULL;
+      if (bs->old_val != NULL)
+       {
+         value_free (bs->old_val);
+         bs->old_val = NULL;
+       }
+    }
+}
+
+/* Execute all the commands associated with all the breakpoints at this
+   location.  Any of these commands could cause the process to proceed
+   beyond this point, etc.  We look out for such changes by checking
+   the global "breakpoint_proceeded" after each command.  */
+void
+bpstat_do_actions (bsp)
+     bpstat *bsp;
+{
+  bpstat bs;
+
+top:
+  bs = *bsp;
+
+  executing_breakpoint_commands = 1;
+  breakpoint_proceeded = 0;
+  for (; bs != NULL; bs = bs->next)
+    {
+      while (bs->commands)
+       {
+         char *line = bs->commands->line;
+         bs->commands = bs->commands->next;
+         execute_command (line, 0);
+         /* If the inferior is proceeded by the command, bomb out now.
+            The bpstat chain has been blown away by wait_for_inferior.
+            But since execution has stopped again, there is a new bpstat
+            to look at, so start over.  */
+         if (breakpoint_proceeded)
+           goto top;
+       }
+    }
+  clear_momentary_breakpoints ();
+
+  executing_breakpoint_commands = 0;
+}
+
+int
+bpstat_print (bs)
+     bpstat bs;
+{
+  /* bs->breakpoint_at can be NULL if it was a momentary breakpoint
+     which has since been deleted.  */
+  if (bs == NULL || bs->breakpoint_at == NULL)
+    return 0;
+  
+  /* If bpstat_stop_status says don't print, OK, we won't.  An example
+     circumstance is when we single-stepped for both a watchpoint and
+     for a "stepi" instruction.  The bpstat says that the watchpoint
+     explains the stop, but we shouldn't print because the watchpoint's
+     value didn't change -- and the real reason we are stopping here
+     rather than continuing to step (as the watchpoint would've had us do)
+     is because of the "stepi".  */
+  if (!bs->print)
+    return 0;
+
+  if (bs->breakpoint_at->address != NULL)
+    {
+      /* I think the user probably only wants to see one breakpoint
+        number, not all of them.  */
+      printf_filtered ("\nBreakpoint %d, ", bs->breakpoint_at->number);
+      return 0;
+    }
+      
+  if (bs->old_val != NULL)
+    {
+      printf_filtered ("\nWatchpoint %d, ", bs->breakpoint_at->number);
+      print_expression (bs->breakpoint_at->exp, stdout);
+      printf_filtered ("\nOld value = ");
+      value_print (bs->old_val, stdout, 0, Val_pretty_default);
+      printf_filtered ("\nNew value = ");
+      value_print (bs->breakpoint_at->val, stdout, 0,
+                  Val_pretty_default);
+      printf_filtered ("\n");
+      value_free (bs->old_val);
+      bs->old_val = NULL;
+      return 1;
+    }
+
+  fprintf_filtered (stderr, "gdb internal error: in bpstat_print\n");
+  return 0;
+}
+
+/* Evaluate the expression EXP and return 1 if value is zero.
+   This is used inside a catch_errors to evaluate the breakpoint condition. 
+   The argument is a "struct expression *" that has been cast to int to 
+   make it pass through catch_errors.  */
+
+static int
+breakpoint_cond_eval (exp)
+     int exp;
+{
+  return value_zerop (evaluate_expression ((struct expression *)exp));
+}
+
+/* Allocate a new bpstat and chain it to the current one.  */
+
+static bpstat
+bpstat_alloc (b, cbs)
+     register struct breakpoint *b;
+     bpstat cbs;                       /* Current "bs" value */
+{
+  bpstat bs;
+
+  bs = (bpstat) xmalloc (sizeof (*bs));
+  cbs->next = bs;
+  bs->breakpoint_at = b;
+  /* If the condition is false, etc., don't do the commands.  */
+  bs->commands = NULL;
+  bs->momentary = b->number == -3;
+  bs->old_val = NULL;
+  return bs;
+}
+
+/* Determine whether we stopped at a breakpoint, etc, or whether we
+   don't understand this stop.  Result is a chain of bpstat's such that:
+
+       if we don't understand the stop, the result is a null pointer.
+
+       if we understand why we stopped, the result is not null, and
+       the first element of the chain contains summary "stop" and
+       "print" flags for the whole chain.
+
+       Each element of the chain refers to a particular breakpoint or
+       watchpoint at which we have stopped.  (We may have stopped for
+       several reasons.)
+
+       Each element of the chain has valid next, breakpoint_at,
+       commands, FIXME??? fields.
+
+ */
+
+       
+bpstat
+bpstat_stop_status (pc, frame_address)
+     CORE_ADDR *pc;
+     FRAME_ADDR frame_address;
+{
+  register struct breakpoint *b;
+  int stop = 0;
+  int print = 0;
+  CORE_ADDR bp_addr;
+  /* True if we've hit a breakpoint (as opposed to a watchpoint).  */
+  int real_breakpoint = 0;
+  /* Root of the chain of bpstat's */
+  struct bpstat__struct root_bs[1];
+  /* Pointer to the last thing in the chain currently.  */
+  bpstat bs = root_bs;
+
+  /* Get the address where the breakpoint would have been.  */
+  bp_addr = *pc - DECR_PC_AFTER_BREAK;
+
+  ALL_BREAKPOINTS (b)
+    {
+      int this_bp_stop;
+      int this_bp_print;
+
+      if (b->enable == disabled)
+       continue;
+      if (b->address != NULL && b->address != bp_addr)
+       continue;
+
+      bs = bpstat_alloc (b, bs);       /* Alloc a bpstat to explain stop */
+
+      this_bp_stop = 1;
+      this_bp_print = 1;
+
+      if (b->exp != NULL)              /* Watchpoint */
+       {
+         int within_current_scope;
+         if (b->exp_valid_block != NULL)
+           within_current_scope =
+             contained_in (get_selected_block (), b->exp_valid_block);
+         else
+           within_current_scope = 1;
+
+         if (within_current_scope)
+           {
+             value new_val = evaluate_expression (b->exp);
+             release_value (new_val);
+             if (!value_equal (b->val, new_val))
+               {
+                 bs->old_val = b->val;
+                 b->val = new_val;
+                 /* We will stop here */
+               }
+             else
+               {
+                 /* Nothing changed, don't do anything.  */
+                 value_free (new_val);
+                 continue;
+                 /* We won't stop here */
+               }
+           }
+         else
+           {
+             /* This seems like the only logical thing to do because
+                if we temporarily ignored the watchpoint, then when
+                we reenter the block in which it is valid it contains
+                garbage (in the case of a function, it may have two
+                garbage values, one before and one after the prologue).
+                So we can't even detect the first assignment to it and
+                watch after that (since the garbage may or may not equal
+                the first value assigned).  */
+             b->enable = disabled;
+             printf_filtered ("\
+Watchpoint %d disabled because the program has left the block in\n\
+which its expression is valid.\n", b->number);
+             /* We won't stop here */
+             /* FIXME, maybe we should stop here!!! */
+             continue;
+           }
+       }
+      else
+       real_breakpoint = 1;
+
+      if (b->frame && b->frame != frame_address)
+       this_bp_stop = 0;
+      else
+       {
+         int value_zero;
+
+         if (b->cond)
+           {
+             /* Need to select the frame, with all that implies
+                so that the conditions will have the right context.  */
+             select_frame (get_current_frame (), 0);
+             value_zero
+               = catch_errors (breakpoint_cond_eval, (int)(b->cond),
+                               "Error occurred in testing breakpoint condition.");
+             free_all_values ();
+           }
+         if (b->cond && value_zero)
+           {
+             this_bp_stop = 0;
+           }
+         else if (b->ignore_count > 0)
+           {
+             b->ignore_count--;
+             this_bp_stop = 0;
+           }
+         else
+           {
+             /* We will stop here */
+             if (b->enable == temporary)
+               b->enable = disabled;
+             bs->commands = b->commands;
+             if (b->silent)
+               this_bp_print = 0;
+             if (bs->commands && !strcmp ("silent", bs->commands->line))
+               {
+                 bs->commands = bs->commands->next;
+                 this_bp_print = 0;
+               }
+           }
+       }
+      if (this_bp_stop)
+       stop = 1;
+      if (this_bp_print)
+       print = 1;
+    }
+
+  bs->next = NULL;             /* Terminate the chain */
+  bs = root_bs->next;          /* Re-grab the head of the chain */
+  if (bs)
+    {
+      bs->stop = stop;
+      bs->print = print;
+#if DECR_PC_AFTER_BREAK != 0 || defined (SHIFT_INST_REGS)
+      if (real_breakpoint)
+       {
+         *pc = bp_addr;
+#if defined (SHIFT_INST_REGS)
+         {
+           CORE_ADDR pc = read_register (PC_REGNUM);
+           CORE_ADDR npc = read_register (NPC_REGNUM);
+           if (pc != npc)
+             {
+               write_register (NNPC_REGNUM, npc);
+               write_register (NPC_REGNUM, pc);
+             }
+         }
+#else /* No SHIFT_INST_REGS.  */
+         write_pc (bp_addr);
+#endif /* No SHIFT_INST_REGS.  */
+       }
+#endif /* DECR_PC_AFTER_BREAK != 0.  */
+    }
+  return bs;
+}
+
+int 
+bpstat_should_step ()
+{
+  struct breakpoint *b;
+  ALL_BREAKPOINTS (b)
+    if (b->enable != disabled && b->exp != NULL)
+      return 1;
+  return 0;
+}
+\f
+/* Print information on breakpoint number BNUM, or -1 if all.
+   If WATCHPOINTS is zero, process only breakpoints; if WATCHPOINTS
+   is nonzero, process only watchpoints.  */
+
+static void
+breakpoint_1 (bnum, watchpoints)
+     int bnum;
+     int watchpoints;
+{
+  register struct breakpoint *b;
+  register struct command_line *l;
+  register struct symbol *sym;
+  CORE_ADDR last_addr = (CORE_ADDR)-1;
+  int header_printed = 0;
+  
+  ALL_BREAKPOINTS (b)
+    if (bnum == -1 || bnum == b->number)
+      {
+       if (b->address == NULL && !watchpoints)
+         {
+           if (bnum == -1)
+             continue;
+           error ("That is a watchpoint, not a breakpoint.");
+         }
+       if (b->address != NULL && watchpoints)
+         {
+           if (bnum == -1)
+             continue;
+           error ("That is a breakpoint, not a watchpoint.");
+         }
+
+       if (!header_printed)
+         {
+           if (watchpoints)
+             printf_filtered ("    Enb   Expression\n");
+           else if (addressprint)
+             printf_filtered ("    Enb   Address    Where\n");
+           else
+             printf_filtered ("    Enb   Where\n");
+           header_printed = 1;
+         }
+
+       printf_filtered ("#%-3d %c ", b->number, "nyod"[(int) b->enable]);
+       if (b->address == NULL)
+         print_expression (b->exp, stdout);
+       else
+         {
+           if (addressprint)
+             printf_filtered (" 0x%08x ", b->address);
+
+           last_addr = b->address;
+           if (b->symtab)
+             {
+               sym = find_pc_function (b->address);
+               if (sym)
+                 {
+                   fputs_filtered (" in ", stdout);
+                   fputs_demangled (SYMBOL_NAME (sym), stdout, 1);
+                   fputs_filtered (" at ", stdout);
+                 }
+               fputs_filtered (b->symtab->filename, stdout);
+               printf_filtered (":%d", b->line_number);
+             }
+           else
+             print_address_symbolic (b->address, stdout, demangle);
+         }
+
+       printf_filtered ("\n");
+
+       if (b->frame)
+         printf_filtered ("\tstop only in stack frame at 0x%x\n", b->frame);
+       if (b->cond)
+         {
+           printf_filtered ("\tstop only if ");
+           print_expression (b->cond, stdout);
+           printf_filtered ("\n");
+         }
+       if (b->ignore_count)
+         printf_filtered ("\tignore next %d hits\n", b->ignore_count);
+       if ((l = b->commands))
+         while (l)
+           {
+             fputs_filtered ("\t", stdout);
+             fputs_filtered (l->line, stdout);
+             fputs_filtered ("\n", stdout);
+             l = l->next;
+           }
+      }
+
+  if (!header_printed)
+    {
+      char *which = watchpoints ? "watch" : "break";
+      if (bnum == -1)
+       printf_filtered ("No %spoints.\n", which);
+      else
+       printf_filtered ("No %spoint numbered %d.\n", which, bnum);
+    }
+
+  /* Compare against (CORE_ADDR)-1 in case some compiler decides
+     that a comparison of an unsigned with -1 is always false.  */
+  if (last_addr != (CORE_ADDR)-1)
+    set_next_address (last_addr);
+}
+
+static void
+breakpoints_info (bnum_exp, from_tty)
+     char *bnum_exp;
+     int from_tty;
+{
+  int bnum = -1;
+
+  if (bnum_exp)
+    bnum = parse_and_eval_address (bnum_exp);
+
+  breakpoint_1 (bnum, 0);
+}
+
+static void
+watchpoints_info (bnum_exp, from_tty)
+     char *bnum_exp;
+     int from_tty;
+{
+  int bnum = -1;
+
+  if (bnum_exp)
+    bnum = parse_and_eval_address (bnum_exp);
+
+  breakpoint_1 (bnum, 1);
+}
+
+/* Print a message describing any breakpoints set at PC.  */
+
+static void
+describe_other_breakpoints (pc)
+     register CORE_ADDR pc;
+{
+  register int others = 0;
+  register struct breakpoint *b;
+
+  ALL_BREAKPOINTS (b)
+    if (b->address == pc)
+      others++;
+  if (others > 0)
+    {
+      printf ("Note: breakpoint%s ", (others > 1) ? "s" : "");
+      ALL_BREAKPOINTS (b)
+       if (b->address == pc)
+         {
+           others--;
+           printf ("%d%s%s ",
+                   b->number,
+                   (b->enable == disabled) ? " (disabled)" : "",
+                   (others > 1) ? "," : ((others == 1) ? " and" : ""));
+         }
+      printf ("also set at pc 0x%x.\n", pc);
+    }
+}
+\f
+/* Set the default place to put a breakpoint
+   for the `break' command with no arguments.  */
+
+void
+set_default_breakpoint (valid, addr, symtab, line)
+     int valid;
+     CORE_ADDR addr;
+     struct symtab *symtab;
+     int line;
+{
+  default_breakpoint_valid = valid;
+  default_breakpoint_address = addr;
+  default_breakpoint_symtab = symtab;
+  default_breakpoint_line = line;
+}
+
+/* Rescan breakpoints at address ADDRESS,
+   marking the first one as "first" and any others as "duplicates".
+   This is so that the bpt instruction is only inserted once.  */
+
+static void
+check_duplicates (address)
+     CORE_ADDR address;
+{
+  register struct breakpoint *b;
+  register int count = 0;
+
+  ALL_BREAKPOINTS (b)
+    if (b->enable != disabled && b->address == address)
+      {
+       count++;
+       b->duplicate = count > 1;
+      }
+}
+
+/* Low level routine to set a breakpoint.
+   Takes as args the three things that every breakpoint must have.
+   Returns the breakpoint object so caller can set other things.
+   Does not set the breakpoint number!
+   Does not print anything.  */
+
+static struct breakpoint *
+set_raw_breakpoint (sal)
+     struct symtab_and_line sal;
+{
+  register struct breakpoint *b, *b1;
+
+  b = (struct breakpoint *) xmalloc (sizeof (struct breakpoint));
+  bzero (b, sizeof *b);
+  b->address = sal.pc;
+  b->symtab = sal.symtab;
+  b->line_number = sal.line;
+  b->enable = enabled;
+  b->next = 0;
+  b->silent = 0;
+  b->ignore_count = 0;
+  b->commands = NULL;
+  b->frame = NULL;
+
+  /* Add this breakpoint to the end of the chain
+     so that a list of breakpoints will come out in order
+     of increasing numbers.  */
+
+  b1 = breakpoint_chain;
+  if (b1 == 0)
+    breakpoint_chain = b;
+  else
+    {
+      while (b1->next)
+       b1 = b1->next;
+      b1->next = b;
+    }
+
+  check_duplicates (sal.pc);
+
+  return b;
+}
+
+/* Set a breakpoint that will evaporate an end of command
+   at address specified by SAL.
+   Restrict it to frame FRAME if FRAME is nonzero.  */
+
+void
+set_momentary_breakpoint (sal, frame)
+     struct symtab_and_line sal;
+     FRAME frame;
+{
+  register struct breakpoint *b;
+  b = set_raw_breakpoint (sal);
+  b->number = -3;
+  b->enable = delete;
+  b->frame = (frame ? FRAME_FP (frame) : 0);
+}
+
+void
+clear_momentary_breakpoints ()
+{
+  register struct breakpoint *b;
+  ALL_BREAKPOINTS (b)
+    if (b->number == -3)
+      {
+       delete_breakpoint (b);
+       break;
+      }
+}
+\f
+/* Tell the user we have just set a breakpoint B.  */
+static void
+mention (b)
+     struct breakpoint *b;
+{
+  if (b->exp)
+    {
+      printf_filtered ("Watchpoint %d: ", b->number);
+      print_expression (b->exp, stdout);
+    }
+  else
+    {
+      printf_filtered ("Breakpoint %d at 0x%x", b->number, b->address);
+      if (b->symtab)
+       printf_filtered (": file %s, line %d.",
+                        b->symtab->filename, b->line_number);
+    }
+  printf_filtered ("\n");
+}
+
+#if 0
+/* Nobody calls this currently. */
+/* Set a breakpoint from a symtab and line.
+   If TEMPFLAG is nonzero, it is a temporary breakpoint.
+   ADDR_STRING is a malloc'd string holding the name of where we are
+   setting the breakpoint.  This is used later to re-set it after the
+   program is relinked and symbols are reloaded.
+   Print the same confirmation messages that the breakpoint command prints.  */
+
+void
+set_breakpoint (s, line, tempflag, addr_string)
+     struct symtab *s;
+     int line;
+     int tempflag;
+     char *addr_string;
+{
+  register struct breakpoint *b;
+  struct symtab_and_line sal;
+  
+  sal.symtab = s;
+  sal.line = line;
+  sal.pc = find_line_pc (sal.symtab, sal.line);
+  if (sal.pc == 0)
+    error ("No line %d in file \"%s\".\n", sal.line, sal.symtab->filename);
+  else
+    {
+      describe_other_breakpoints (sal.pc);
+
+      b = set_raw_breakpoint (sal);
+      set_breakpoint_count (breakpoint_count + 1);
+      b->number = breakpoint_count;
+      b->cond = 0;
+      b->addr_string = addr_string;
+      if (tempflag)
+       b->enable = temporary;
+
+      mention (b);
+    }
+}
+#endif
+\f
+/* Set a breakpoint according to ARG (function, linenum or *address)
+   and make it temporary if TEMPFLAG is nonzero. */
+
+static void
+break_command_1 (arg, tempflag, from_tty)
+     char *arg;
+     int tempflag, from_tty;
+{
+  struct symtabs_and_lines sals;
+  struct symtab_and_line sal;
+  register struct expression *cond = 0;
+  register struct breakpoint *b;
+
+  /* Pointers in arg to the start, and one past the end, of the condition.  */
+  char *cond_start = NULL;
+  char *cond_end;
+  /* Pointers in arg to the start, and one past the end,
+     of the address part.  */
+  char *addr_start = NULL;
+  char *addr_end;
+  
+  int i;
+  CORE_ADDR pc;
+
+  sals.sals = NULL;
+  sals.nelts = 0;
+
+  sal.line = sal.pc = sal.end = 0;
+  sal.symtab = 0;
+
+  /* If no arg given, or if first arg is 'if ', use the default breakpoint. */
+
+  if (!arg || (arg[0] == 'i' && arg[1] == 'f' 
+              && (arg[2] == ' ' || arg[2] == '\t')))
+    {
+      if (default_breakpoint_valid)
+       {
+         sals.sals = (struct symtab_and_line *) 
+           xmalloc (sizeof (struct symtab_and_line));
+         sal.pc = default_breakpoint_address;
+         sal.line = default_breakpoint_line;
+         sal.symtab = default_breakpoint_symtab;
+         sals.sals[0] = sal;
+         sals.nelts = 1;
+       }
+      else
+       error ("No default breakpoint address now.");
+    }
+  else
+    {
+      addr_start = arg;
+
+      /* Force almost all breakpoints to be in terms of the
+        current_source_symtab (which is decode_line_1's default).  This
+        should produce the results we want almost all of the time while
+        leaving default_breakpoint_* alone.  */
+      if (default_breakpoint_valid
+         && (!current_source_symtab
+             || (arg && (*arg == '+' || *arg == '-'))))
+       sals = decode_line_1 (&arg, 1, default_breakpoint_symtab,
+                             default_breakpoint_line);
+      else
+       sals = decode_line_1 (&arg, 1, (struct symtab *)NULL, 0);
+
+      addr_end = arg;
+    }
+  
+  if (! sals.nelts) 
+    return;
+
+  for (i = 0; i < sals.nelts; i++)
+    {
+      sal = sals.sals[i];
+      if (sal.pc == 0 && sal.symtab != 0)
+       {
+         pc = find_line_pc (sal.symtab, sal.line);
+         if (pc == 0)
+           error ("No line %d in file \"%s\".",
+                  sal.line, sal.symtab->filename);
+       }
+      else 
+       pc = sal.pc;
+      
+      while (arg && *arg)
+       {
+         if (arg[0] == 'i' && arg[1] == 'f'
+             && (arg[2] == ' ' || arg[2] == '\t'))
+           {
+             arg += 2;
+             cond_start = arg;
+             cond = parse_c_1 (&arg, block_for_pc (pc), 0);
+             cond_end = arg;
+           }
+         else
+           error ("Junk at end of arguments.");
+       }
+      sals.sals[i].pc = pc;
+    }
+
+  for (i = 0; i < sals.nelts; i++)
+    {
+      sal = sals.sals[i];
+
+      if (from_tty)
+       describe_other_breakpoints (sal.pc);
+
+      b = set_raw_breakpoint (sal);
+      set_breakpoint_count (breakpoint_count + 1);
+      b->number = breakpoint_count;
+      b->cond = cond;
+      
+      if (addr_start)
+       b->addr_string = savestring (addr_start, addr_end - addr_start);
+      if (cond_start)
+       b->cond_string = savestring (cond_start, cond_end - cond_start);
+                                    
+      if (tempflag)
+       b->enable = temporary;
+
+      mention (b);
+    }
+
+  if (sals.nelts > 1)
+    {
+      printf ("Multiple breakpoints were set.\n");
+      printf ("Use the \"delete\" command to delete unwanted breakpoints.\n");
+    }
+  free (sals.sals);
+}
+
+void
+break_command (arg, from_tty)
+     char *arg;
+     int from_tty;
+{
+  break_command_1 (arg, 0, from_tty);
+}
+
+static void
+tbreak_command (arg, from_tty)
+     char *arg;
+     int from_tty;
+{
+  break_command_1 (arg, 1, from_tty);
+}
+
+static void
+watch_command (arg, from_tty)
+     char *arg;
+     int from_tty;
+{
+  struct breakpoint *b;
+  struct symtab_and_line sal;
+
+  sal.pc = NULL;
+  sal.symtab = NULL;
+  sal.line = 0;
+  
+  b = set_raw_breakpoint (sal);
+  set_breakpoint_count (breakpoint_count + 1);
+  b->number = breakpoint_count;
+  innermost_block = NULL;
+  b->exp = parse_c_expression (arg);
+  b->exp_valid_block = innermost_block;
+  b->val = evaluate_expression (b->exp);
+  release_value (b->val);
+  b->cond = 0;
+  b->cond_string = NULL;
+  mention (b);
+}
+\f
+/*
+ * Helper routine for the until_command routine in infcmd.c.  Here
+ * because it uses the mechanisms of breakpoints.
+ */
+void
+until_break_command (arg, from_tty)
+     char *arg;
+     int from_tty;
+{
+  struct symtabs_and_lines sals;
+  struct symtab_and_line sal;
+  FRAME prev_frame = get_prev_frame (selected_frame);
+
+  clear_proceed_status ();
+
+  /* Set a breakpoint where the user wants it and at return from
+     this function */
+  
+  if (default_breakpoint_valid)
+    sals = decode_line_1 (&arg, 1, default_breakpoint_symtab,
+                         default_breakpoint_line);
+  else
+    sals = decode_line_1 (&arg, 1, (struct symtab *)NULL, 0);
+  
+  if (sals.nelts != 1)
+    error ("Couldn't get information on specified line.");
+  
+  sal = sals.sals[0];
+  free (sals.sals);            /* malloc'd, so freed */
+  
+  if (*arg)
+    error ("Junk at end of arguments.");
+  
+  if (sal.pc == 0 && sal.symtab != 0)
+    sal.pc = find_line_pc (sal.symtab, sal.line);
+  
+  if (sal.pc == 0)
+    error ("No line %d in file \"%s\".", sal.line, sal.symtab->filename);
+  
+  set_momentary_breakpoint (sal, selected_frame);
+  
+  /* Keep within the current frame */
+  
+  if (prev_frame)
+    {
+      struct frame_info *fi;
+      
+      fi = get_frame_info (prev_frame);
+      sal = find_pc_line (fi->pc, 0);
+      sal.pc = fi->pc;
+      set_momentary_breakpoint (sal, prev_frame);
+    }
+  
+  proceed (-1, -1, 0);
+}
+\f
+/* Set a breakpoint at the catch clause for NAME.  */
+static int
+catch_breakpoint (name)
+     char *name;
+{
+}
+
+static int
+disable_catch_breakpoint ()
+{
+}
+
+static int
+delete_catch_breakpoint ()
+{
+}
+
+static int
+enable_catch_breakpoint ()
+{
+}
+
+struct sal_chain
+{
+  struct sal_chain *next;
+  struct symtab_and_line sal;
+};
+
+/* For each catch clause identified in ARGS, run FUNCTION
+   with that clause as an argument.  */
+static struct symtabs_and_lines
+map_catch_names (args, function)
+     char *args;
+     int (*function)();
+{
+  register char *p = args;
+  register char *p1;
+  struct symtabs_and_lines sals;
+  struct sal_chain *sal_chain = 0;
+
+  if (p == 0)
+    error_no_arg ("one or more catch names");
+
+  sals.nelts = 0;
+  sals.sals = NULL;
+
+  while (*p)
+    {
+      p1 = p;
+      /* Don't swallow conditional part.  */
+      if (p1[0] == 'i' && p1[1] == 'f'
+         && (p1[2] == ' ' || p1[2] == '\t'))
+       break;
+
+      if (isalpha (*p1))
+       {
+         p1++;
+         while (isalnum (*p1) || *p1 == '_' || *p1 == '$')
+           p1++;
+       }
+
+      if (*p1 && *p1 != ' ' && *p1 != '\t')
+       error ("Arguments must be catch names.");
+
+      *p1 = 0;
+#if 0
+      if (function (p))
+       {
+         struct sal_chain *next
+           = (struct sal_chain *)alloca (sizeof (struct sal_chain));
+         next->next = sal_chain;
+         next->sal = get_catch_sal (p);
+         sal_chain = next;
+         goto win;
+       }
+#endif
+      printf ("No catch clause for exception %s.\n", p);
+    win:
+      p = p1;
+      while (*p == ' ' || *p == '\t') p++;
+    }
+}
+
+/* This shares a lot of code with `print_frame_label_vars' from stack.c.  */
+
+static struct symtabs_and_lines
+get_catch_sals (this_level_only)
+     int this_level_only;
+{
+  extern struct blockvector *blockvector_for_pc ();
+  register struct blockvector *bl;
+  register struct block *block = get_frame_block (selected_frame);
+  int index, have_default = 0;
+  struct frame_info *fi = get_frame_info (selected_frame);
+  CORE_ADDR pc = fi->pc;
+  struct symtabs_and_lines sals;
+  struct sal_chain *sal_chain = 0;
+  char *blocks_searched;
+
+  sals.nelts = 0;
+  sals.sals = NULL;
+
+  if (block == 0)
+    error ("No symbol table info available.\n");
+
+  bl = blockvector_for_pc (BLOCK_END (block) - 4, &index);
+  blocks_searched = (char *) alloca (BLOCKVECTOR_NBLOCKS (bl) * sizeof (char));
+  bzero (blocks_searched, BLOCKVECTOR_NBLOCKS (bl) * sizeof (char));
+
+  while (block != 0)
+    {
+      CORE_ADDR end = BLOCK_END (block) - 4;
+      int last_index;
+
+      if (bl != blockvector_for_pc (end, &index))
+       error ("blockvector blotch");
+      if (BLOCKVECTOR_BLOCK (bl, index) != block)
+       error ("blockvector botch");
+      last_index = BLOCKVECTOR_NBLOCKS (bl);
+      index += 1;
+
+      /* Don't print out blocks that have gone by.  */
+      while (index < last_index
+            && BLOCK_END (BLOCKVECTOR_BLOCK (bl, index)) < pc)
+       index++;
+
+      while (index < last_index
+            && BLOCK_END (BLOCKVECTOR_BLOCK (bl, index)) < end)
+       {
+         if (blocks_searched[index] == 0)
+           {
+             struct block *b = BLOCKVECTOR_BLOCK (bl, index);
+             int nsyms;
+             register int i;
+             register struct symbol *sym;
+
+             nsyms = BLOCK_NSYMS (b);
+
+             for (i = 0; i < nsyms; i++)
+               {
+                 sym = BLOCK_SYM (b, i);
+                 if (! strcmp (SYMBOL_NAME (sym), "default"))
+                   {
+                     if (have_default)
+                       continue;
+                     have_default = 1;
+                   }
+                 if (SYMBOL_CLASS (sym) == LOC_LABEL)
+                   {
+                     struct sal_chain *next = (struct sal_chain *)
+                       alloca (sizeof (struct sal_chain));
+                     next->next = sal_chain;
+                     next->sal = find_pc_line (SYMBOL_VALUE_ADDRESS (sym), 0);
+                     sal_chain = next;
+                   }
+               }
+             blocks_searched[index] = 1;
+           }
+         index++;
+       }
+      if (have_default)
+       break;
+      if (sal_chain && this_level_only)
+       break;
+
+      /* After handling the function's top-level block, stop.
+        Don't continue to its superblock, the block of
+        per-file symbols.  */
+      if (BLOCK_FUNCTION (block))
+       break;
+      block = BLOCK_SUPERBLOCK (block);
+    }
+
+  if (sal_chain)
+    {
+      struct sal_chain *tmp_chain;
+
+      /* Count the number of entries.  */
+      for (index = 0, tmp_chain = sal_chain; tmp_chain;
+          tmp_chain = tmp_chain->next)
+       index++;
+
+      sals.nelts = index;
+      sals.sals = (struct symtab_and_line *)
+       xmalloc (index * sizeof (struct symtab_and_line));
+      for (index = 0; sal_chain; sal_chain = sal_chain->next, index++)
+       sals.sals[index] = sal_chain->sal;
+    }
+
+  return sals;
+}
+
+/* Commands to deal with catching exceptions.  */
+
+void
+catch_command_1 (arg, tempflag, from_tty)
+     char *arg;
+     int tempflag;
+     int from_tty;
+{
+  /* First, translate ARG into something we can deal with in terms
+     of breakpoints.  */
+
+  struct symtabs_and_lines sals;
+  struct symtab_and_line sal;
+  register struct expression *cond = 0;
+  register struct breakpoint *b;
+  char *save_arg;
+  int i;
+  CORE_ADDR pc;
+
+  sal.line = sal.pc = sal.end = 0;
+  sal.symtab = 0;
+
+  /* If no arg given, or if first arg is 'if ', all active catch clauses
+     are breakpointed. */
+
+  if (!arg || (arg[0] == 'i' && arg[1] == 'f' 
+              && (arg[2] == ' ' || arg[2] == '\t')))
+    {
+      /* Grab all active catch clauses.  */
+      sals = get_catch_sals (0);
+    }
+  else
+    {
+      /* Grab selected catch clauses.  */
+      error ("catch NAME not implemeneted");
+      sals = map_catch_names (arg, catch_breakpoint);
+    }
+
+  if (! sals.nelts) 
+    return;
+
+  save_arg = arg;
+  for (i = 0; i < sals.nelts; i++)
+    {
+      sal = sals.sals[i];
+      if (sal.pc == 0 && sal.symtab != 0)
+       {
+         pc = find_line_pc (sal.symtab, sal.line);
+         if (pc == 0)
+           error ("No line %d in file \"%s\".",
+                  sal.line, sal.symtab->filename);
+       }
+      else 
+       pc = sal.pc;
+      
+      while (arg && *arg)
+       {
+         if (arg[0] == 'i' && arg[1] == 'f'
+             && (arg[2] == ' ' || arg[2] == '\t'))
+           cond = (struct expression *) parse_c_1 ((arg += 2, &arg),
+                                                   block_for_pc (pc), 0);
+         else
+           error ("Junk at end of arguments.");
+       }
+      arg = save_arg;
+      sals.sals[i].pc = pc;
+    }
+
+  for (i = 0; i < sals.nelts; i++)
+    {
+      sal = sals.sals[i];
+
+      if (from_tty)
+       describe_other_breakpoints (sal.pc);
+
+      b = set_raw_breakpoint (sal);
+      b->number = ++breakpoint_count;
+      b->cond = cond;
+      if (tempflag)
+       b->enable = temporary;
+
+      printf ("Breakpoint %d at 0x%x", b->number, b->address);
+      if (b->symtab)
+       printf (": file %s, line %d.", b->symtab->filename, b->line_number);
+      printf ("\n");
+    }
+
+  if (sals.nelts > 1)
+    {
+      printf ("Multiple breakpoints were set.\n");
+      printf ("Use the \"delete\" command to delete unwanted breakpoints.\n");
+    }
+  free (sals.sals);
+}
+
+/* Disable breakpoints on all catch clauses described in ARGS.  */
+static void
+disable_catch (args)
+     char *args;
+{
+  /* Map the disable command to catch clauses described in ARGS.  */
+}
+
+/* Enable breakpoints on all catch clauses described in ARGS.  */
+static void
+enable_catch (args)
+     char *args;
+{
+  /* Map the disable command to catch clauses described in ARGS.  */
+}
+
+/* Delete breakpoints on all catch clauses in the active scope.  */
+static void
+delete_catch (args)
+     char *args;
+{
+  /* Map the delete command to catch clauses described in ARGS.  */
+}
+
+static void
+catch_command (arg, from_tty)
+     char *arg;
+     int from_tty;
+{
+  catch_command_1 (arg, 0, from_tty);
+}
+\f
+static void
+clear_command (arg, from_tty)
+     char *arg;
+     int from_tty;
+{
+  register struct breakpoint *b, *b1;
+  struct symtabs_and_lines sals;
+  struct symtab_and_line sal;
+  register struct breakpoint *found;
+  int i;
+
+  if (arg)
+    {
+      sals = decode_line_spec (arg, 1);
+    }
+  else
+    {
+      sals.sals = (struct symtab_and_line *) xmalloc (sizeof (struct symtab_and_line));
+      sal.line = default_breakpoint_line;
+      sal.symtab = default_breakpoint_symtab;
+      sal.pc = 0;
+      if (sal.symtab == 0)
+       error ("No source file specified.");
+
+      sals.sals[0] = sal;
+      sals.nelts = 1;
+    }
+
+  for (i = 0; i < sals.nelts; i++)
+    {
+      /* If exact pc given, clear bpts at that pc.
+        But if sal.pc is zero, clear all bpts on specified line.  */
+      sal = sals.sals[i];
+      found = (struct breakpoint *) 0;
+      while (breakpoint_chain
+            && (sal.pc ? breakpoint_chain->address == sal.pc
+                : (breakpoint_chain->symtab == sal.symtab
+                   && breakpoint_chain->line_number == sal.line)))
+       {
+         b1 = breakpoint_chain;
+         breakpoint_chain = b1->next;
+         b1->next = found;
+         found = b1;
+       }
+
+      ALL_BREAKPOINTS (b)
+       while (b->next
+              && b->next->address != NULL
+              && (sal.pc ? b->next->address == sal.pc
+                  : (b->next->symtab == sal.symtab
+                     && b->next->line_number == sal.line)))
+         {
+           b1 = b->next;
+           b->next = b1->next;
+           b1->next = found;
+           found = b1;
+         }
+
+      if (found == 0)
+       {
+         if (arg)
+           error ("No breakpoint at %s.", arg);
+         else
+           error ("No breakpoint at this line.");
+       }
+
+      if (found->next) from_tty = 1; /* Always report if deleted more than one */
+      if (from_tty) printf ("Deleted breakpoint%s ", found->next ? "s" : "");
+      while (found)
+       {
+         if (from_tty) printf ("%d ", found->number);
+         b1 = found->next;
+         delete_breakpoint (found);
+         found = b1;
+       }
+      if (from_tty) putchar ('\n');
+    }
+  free (sals.sals);
+}
+\f
+/* Delete breakpoint in BS if they are `delete' breakpoints.
+   This is called after any breakpoint is hit, or after errors.  */
+
+void
+breakpoint_auto_delete (bs)
+     bpstat bs;
+{
+  for (; bs; bs = bs->next)
+    if (bs->breakpoint_at && bs->breakpoint_at->enable == delete)
+      delete_breakpoint (bs->breakpoint_at);
+}
+
+/* Delete a breakpoint and clean up all traces of it in the data structures. */
+
+static void
+delete_breakpoint (bpt)
+     struct breakpoint *bpt;
+{
+  register struct breakpoint *b;
+  register bpstat bs;
+
+  if (bpt->inserted)
+      target_remove_breakpoint(bpt->address, bpt->shadow_contents);
+
+  if (breakpoint_chain == bpt)
+    breakpoint_chain = bpt->next;
+
+  ALL_BREAKPOINTS (b)
+    if (b->next == bpt)
+      {
+       b->next = bpt->next;
+       break;
+      }
+
+  check_duplicates (bpt->address);
+
+  free_command_lines (&bpt->commands);
+  if (bpt->cond)
+    free (bpt->cond);
+  if (bpt->cond_string != NULL)
+    free (bpt->cond_string);
+  if (bpt->addr_string != NULL)
+    free (bpt->addr_string);
+
+  if (xgdb_verbose && bpt->number >=0)
+    printf ("breakpoint #%d deleted\n", bpt->number);
+
+  /* Be sure no bpstat's are pointing at it after it's been freed.  */
+  /* FIXME, how can we find all bpstat's?  We just check stop_bpstat for now. */
+  for (bs = stop_bpstat; bs; bs = bs->next)
+    if (bs->breakpoint_at == bpt)
+      bs->breakpoint_at = NULL;
+  free (bpt);
+}
+
+static void map_breakpoint_numbers ();
+
+static void
+delete_command (arg, from_tty)
+     char *arg;
+     int from_tty;
+{
+
+  if (arg == 0)
+    {
+      /* Ask user only if there are some breakpoints to delete.  */
+      if (!from_tty
+         || (breakpoint_chain && query ("Delete all breakpoints? ", 0, 0)))
+       {
+         /* No arg; clear all breakpoints.  */
+         while (breakpoint_chain)
+           delete_breakpoint (breakpoint_chain);
+       }
+    }
+  else
+    map_breakpoint_numbers (arg, delete_breakpoint);
+}
+
+static void
+breakpoint_re_set_one (bint)
+     int bint;
+{
+  struct breakpoint *b = (struct breakpoint *)bint;  /* get past catch_errs */
+  int i;
+  struct symtabs_and_lines sals;
+  struct symtab_and_line sal;
+  char *s;
+
+  if (b->address != NULL && b->addr_string != NULL)
+    {
+      s = b->addr_string;
+      sals = decode_line_1 (&s, 1, (struct symtab *)NULL, 0);
+      for (i = 0; i < sals.nelts; i++)
+       {
+         sal = sals.sals[i];
+         
+         b->symtab = sal.symtab;
+         b->line_number = sal.line;
+         if (sal.pc == 0 && sal.symtab != 0)
+           {
+             sal.pc = find_line_pc (sal.symtab, sal.line);
+             if (sal.pc == 0)
+               error ("No line %d in file \"%s\".",
+                      sal.line, sal.symtab->filename);
+           }
+         b->address = sal.pc;
+
+         if (b->cond_string != NULL)
+           {
+             s = b->cond_string;
+             b->cond = parse_c_1 (&s, block_for_pc (sal.pc), 0);
+           }
+         
+         check_duplicates (b->address);
+
+         mention (b);
+       }
+      free (sals.sals);
+    }
+  else
+    {
+      /* Anything without a string can't be re-set. */
+      delete_breakpoint (b);
+    }
+}
+
+/* Re-set all breakpoints after symbols have been re-loaded.  */
+void
+breakpoint_re_set ()
+{
+  struct breakpoint *b;
+  
+  ALL_BREAKPOINTS (b)
+    {
+      b->symtab = 0;           /* Be sure we don't point to old dead symtab */
+      (void) catch_errors (breakpoint_re_set_one, (int) b, 
+                          "Error in re-setting breakpoint");
+    }
+
+  /* Blank line to finish off all those mention() messages we just printed.  */
+  printf_filtered ("\n");
+}
+\f
+/* Set ignore-count of breakpoint number BPTNUM to COUNT.
+   If from_tty is nonzero, it prints a message to that effect,
+   which ends with a period (no newline).  */
+
+void
+set_ignore_count (bptnum, count, from_tty)
+     int bptnum, count, from_tty;
+{
+  register struct breakpoint *b;
+
+  if (count < 0)
+    count = 0;
+
+  ALL_BREAKPOINTS (b)
+    if (b->number == bptnum)
+      {
+       b->ignore_count = count;
+       if (!from_tty)
+         return;
+       else if (count == 0)
+         printf ("Will stop next time breakpoint %d is reached.", bptnum);
+       else if (count == 1)
+         printf ("Will ignore next crossing of breakpoint %d.", bptnum);
+       else
+         printf ("Will ignore next %d crossings of breakpoint %d.",
+                 count, bptnum);
+       return;
+      }
+
+  error ("No breakpoint number %d.", bptnum);
+}
+
+/* Clear the ignore counts of all breakpoints.  */
+void
+breakpoint_clear_ignore_counts ()
+{
+  struct breakpoint *b;
+
+  ALL_BREAKPOINTS (b)
+    b->ignore_count = 0;
+}
+
+/* Command to set ignore-count of breakpoint N to COUNT.  */
+
+static void
+ignore_command (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  char *p = args;
+  register int num;
+
+  if (p == 0)
+    error_no_arg ("a breakpoint number");
+  
+  num = get_number (&p);
+
+  if (*p == 0)
+    error ("Second argument (specified ignore-count) is missing.");
+
+  set_ignore_count (num, parse_and_eval_address (p), from_tty);
+  printf ("\n");
+}
+\f
+/* Call FUNCTION on each of the breakpoints
+   whose numbers are given in ARGS.  */
+
+static void
+map_breakpoint_numbers (args, function)
+     char *args;
+     void (*function) ();
+{
+  register char *p = args;
+  char *p1;
+  register int num;
+  register struct breakpoint *b;
+
+  if (p == 0)
+    error_no_arg ("one or more breakpoint numbers");
+
+  while (*p)
+    {
+      p1 = p;
+      
+      num = get_number (&p1);
+
+      ALL_BREAKPOINTS (b)
+       if (b->number == num)
+         {
+           function (b);
+           goto win;
+         }
+      printf ("No breakpoint number %d.\n", num);
+    win:
+      p = p1;
+    }
+}
+
+static void
+enable_breakpoint (bpt)
+     struct breakpoint *bpt;
+{
+  bpt->enable = enabled;
+
+  if (xgdb_verbose && bpt->number >= 0)
+    printf ("breakpoint #%d enabled\n", bpt->number);
+
+  check_duplicates (bpt->address);
+  if (bpt->val != NULL)
+    {
+      value_free (bpt->val);
+
+      bpt->val = evaluate_expression (bpt->exp);
+      release_value (bpt->val);
+    }
+}
+
+static void
+enable_command (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  struct breakpoint *bpt;
+  if (args == 0)
+    ALL_BREAKPOINTS (bpt)
+      enable_breakpoint (bpt);
+  else
+    map_breakpoint_numbers (args, enable_breakpoint);
+}
+
+static void
+disable_breakpoint (bpt)
+     struct breakpoint *bpt;
+{
+  bpt->enable = disabled;
+
+  if (xgdb_verbose && bpt->number >= 0)
+    printf ("breakpoint #%d disabled\n", bpt->number);
+
+  check_duplicates (bpt->address);
+}
+
+static void
+disable_command (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  register struct breakpoint *bpt;
+  if (args == 0)
+    ALL_BREAKPOINTS (bpt)
+      disable_breakpoint (bpt);
+  else
+    map_breakpoint_numbers (args, disable_breakpoint);
+}
+
+static void
+enable_once_breakpoint (bpt)
+     struct breakpoint *bpt;
+{
+  bpt->enable = temporary;
+
+  check_duplicates (bpt->address);
+}
+
+static void
+enable_once_command (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  map_breakpoint_numbers (args, enable_once_breakpoint);
+}
+
+static void
+enable_delete_breakpoint (bpt)
+     struct breakpoint *bpt;
+{
+  bpt->enable = delete;
+
+  check_duplicates (bpt->address);
+}
+
+static void
+enable_delete_command (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  map_breakpoint_numbers (args, enable_delete_breakpoint);
+}
+\f
+/*
+ * Use default_breakpoint_'s, or nothing if they aren't valid.
+ */
+struct symtabs_and_lines
+decode_line_spec_1 (string, funfirstline)
+     char *string;
+     int funfirstline;
+{
+  struct symtabs_and_lines sals;
+  if (string == 0)
+    error ("Empty line specification.");
+  if (default_breakpoint_valid)
+    sals = decode_line_1 (&string, funfirstline,
+                         default_breakpoint_symtab, default_breakpoint_line);
+  else
+    sals = decode_line_1 (&string, funfirstline, (struct symtab *)NULL, 0);
+  if (*string)
+    error ("Junk at end of line specification: %s", string);
+  return sals;
+}
+\f
+
+/* Chain containing all defined enable commands.  */
+
+extern struct cmd_list_element 
+  *enablelist, *disablelist,
+  *deletelist, *enablebreaklist;
+
+extern struct cmd_list_element *cmdlist;
+
+void
+_initialize_breakpoint ()
+{
+  breakpoint_chain = 0;
+  /* Don't bother to call set_breakpoint_count.  $bpnum isn't useful
+     before a breakpoint is set.  */
+  breakpoint_count = 0;
+
+  add_com ("ignore", class_breakpoint, ignore_command,
+          "Set ignore-count of breakpoint number N to COUNT.");
+
+  add_com ("commands", class_breakpoint, commands_command,
+          "Set commands to be executed when a breakpoint is hit.\n\
+Give breakpoint number as argument after \"commands\".\n\
+With no argument, the targeted breakpoint is the last one set.\n\
+The commands themselves follow starting on the next line.\n\
+Type a line containing \"end\" to indicate the end of them.\n\
+Give \"silent\" as the first line to make the breakpoint silent;\n\
+then no output is printed when it is hit, except what the commands print.");
+
+  add_com ("condition", class_breakpoint, condition_command,
+          "Specify breakpoint number N to break only if COND is true.\n\
+N is an integer; COND is a C expression to be evaluated whenever\n\
+breakpoint N is reached.  Actually break only when COND is nonzero.");
+
+  add_com ("tbreak", class_breakpoint, tbreak_command,
+          "Set a temporary breakpoint.  Args like \"break\" command.\n\
+Like \"break\" except the breakpoint is only enabled temporarily,\n\
+so it will be disabled when hit.  Equivalent to \"break\" followed\n\
+by using \"enable once\" on the breakpoint number.");
+
+  add_prefix_cmd ("enable", class_breakpoint, enable_command,
+                 "Enable some breakpoints.\n\
+Give breakpoint numbers (separated by spaces) as arguments.\n\
+With no subcommand, breakpoints are enabled until you command otherwise.\n\
+This is used to cancel the effect of the \"disable\" command.\n\
+With a subcommand you can enable temporarily.",
+                 &enablelist, "enable ", 1, &cmdlist);
+
+  add_abbrev_prefix_cmd ("breakpoints", class_breakpoint, enable_command,
+                 "Enable some breakpoints.\n\
+Give breakpoint numbers (separated by spaces) as arguments.\n\
+This is used to cancel the effect of the \"disable\" command.\n\
+May be abbreviated to simply \"enable\".\n",
+                 &enablebreaklist, "enable breakpoints ", 1, &enablelist);
+
+  add_cmd ("once", no_class, enable_once_command,
+          "Enable breakpoints for one hit.  Give breakpoint numbers.\n\
+If a breakpoint is hit while enabled in this fashion, it becomes disabled.\n\
+See the \"tbreak\" command which sets a breakpoint and enables it once.",
+          &enablebreaklist);
+
+  add_cmd ("delete", no_class, enable_delete_command,
+          "Enable breakpoints and delete when hit.  Give breakpoint numbers.\n\
+If a breakpoint is hit while enabled in this fashion, it is deleted.",
+          &enablebreaklist);
+
+  add_cmd ("delete", no_class, enable_delete_command,
+          "Enable breakpoints and delete when hit.  Give breakpoint numbers.\n\
+If a breakpoint is hit while enabled in this fashion, it is deleted.",
+          &enablelist);
+
+  add_cmd ("once", no_class, enable_once_command,
+          "Enable breakpoints for one hit.  Give breakpoint numbers.\n\
+If a breakpoint is hit while enabled in this fashion, it becomes disabled.\n\
+See the \"tbreak\" command which sets a breakpoint and enables it once.",
+          &enablelist);
+
+  add_prefix_cmd ("disable", class_breakpoint, disable_command,
+          "Disable some breakpoints.\n\
+Arguments are breakpoint numbers with spaces in between.\n\
+To disable all breakpoints, give no argument.\n\
+A disabled breakpoint is not forgotten, but has no effect until reenabled.",
+                 &disablelist, "disable ", 1, &cmdlist);
+  add_com_alias ("dis", "disable", class_breakpoint, 1);
+  add_com_alias ("disa", "disable", class_breakpoint, 1);
+
+  add_cmd ("breakpoints", class_alias, disable_command,
+          "Disable some breakpoints.\n\
+Arguments are breakpoint numbers with spaces in between.\n\
+To disable all breakpoints, give no argument.\n\
+A disabled breakpoint is not forgotten, but has no effect until reenabled.\n\
+This command may be abbreviated \"disable\".",
+          &disablelist);
+
+  add_prefix_cmd ("delete", class_breakpoint, delete_command,
+          "Delete some breakpoints or auto-display expressions.\n\
+Arguments are breakpoint numbers with spaces in between.\n\
+To delete all breakpoints, give no argument.\n\
+\n\
+Also a prefix command for deletion of other GDB objects.\n\
+The \"unset\" command is also an alias for \"delete\".",
+                 &deletelist, "delete ", 1, &cmdlist);
+  add_com_alias ("d", "delete", class_breakpoint, 1);
+  add_com_alias ("unset", "delete", class_alias, 1);
+
+  add_cmd ("breakpoints", class_alias, delete_command,
+          "Delete some breakpoints or auto-display expressions.\n\
+Arguments are breakpoint numbers with spaces in between.\n\
+To delete all breakpoints, give no argument.\n\
+This command may be abbreviated \"delete\".",
+          &deletelist);
+
+  add_com ("clear", class_breakpoint, clear_command,
+          "Clear breakpoint at specified line or function.\n\
+Argument may be line number, function name, or \"*\" and an address.\n\
+If line number is specified, all breakpoints in that line are cleared.\n\
+If function is specified, breakpoints at beginning of function are cleared.\n\
+If an address is specified, breakpoints at that address are cleared.\n\n\
+With no argument, clears all breakpoints in the line that the selected frame\n\
+is executing in.\n\
+\n\
+See also the \"delete\" command which clears breakpoints by number.");
+
+  add_com ("break", class_breakpoint, break_command,
+          "Set breakpoint at specified line or function.\n\
+Argument may be line number, function name, or \"*\" and an address.\n\
+If line number is specified, break at start of code for that line.\n\
+If function is specified, break at start of code for that function.\n\
+If an address is specified, break at that exact address.\n\
+With no arg, uses current execution address of selected stack frame.\n\
+This is useful for breaking on return to a stack frame.\n\
+\n\
+Multiple breakpoints at one place are permitted, and useful if conditional.\n\
+\n\
+Do \"help breakpoints\" for info on other commands dealing with breakpoints.");
+  add_com_alias ("b", "break", class_run, 1);
+  add_com_alias ("br", "break", class_run, 1);
+  add_com_alias ("bre", "break", class_run, 1);
+  add_com_alias ("brea", "break", class_run, 1);
+
+  add_info ("breakpoints", breakpoints_info,
+           "Status of all breakpoints, or breakpoint number NUMBER.\n\
+Second column is \"y\" for enabled breakpoint, \"n\" for disabled,\n\
+\"o\" for enabled once (disable when hit), \"d\" for enable but delete when hit.\n\
+Then come the address and the file/line number.\n\n\
+Convenience variable \"$_\" and default examine address for \"x\"\n\
+are set to the address of the last breakpoint listed.\n\n\
+Convenience variable \"$bpnum\" contains the number of the last\n\
+breakpoint set.");
+
+  add_com ("catch", class_breakpoint, catch_command,
+         "Set breakpoints to catch exceptions that are raised.\n\
+Argument may be a single exception to catch, multiple exceptions\n\
+to catch, or the default exception \"default\".  If no arguments\n\
+are given, breakpoints are set at all exception handlers catch clauses\n\
+within the current scope.\n\
+\n\
+A condition specified for the catch applies to all breakpoints set\n\
+with this command\n\
+\n\
+Do \"help breakpoints\" for info on other commands dealing with breakpoints.");
+
+  add_com ("watch", class_breakpoint, watch_command,
+          "Set a watchpoint for an expression.\n\
+A watchpoint stops execution of your program whenever the value of\n\
+an expression changes.");
+
+  add_info ("watchpoints", watchpoints_info,
+           "Status of all watchpoints, or watchpoint number NUMBER.\n\
+Second column is \"y\" for enabled watchpoints, \"n\" for disabled.");
+}
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
new file mode 100644 (file)
index 0000000..00ee8c5
--- /dev/null
@@ -0,0 +1,129 @@
+/* Copyright (C) 1990 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.  */
+
+#if !defined (BREAKPOINT_H)
+#define BREAKPOINT_H 1
+
+/* This is the maximum number of bytes a breakpoint instruction can take.
+   Feel free to increase it.  It's just used in a few places to size
+   arrays that should be independent of the target architecture.  */
+
+#define        BREAKPOINT_MAX  10
+
+extern void breakpoint_re_set ();
+extern void clear_momentary_breakpoints ();
+extern void set_momentary_breakpoint ();
+extern void set_ignore_count ();
+extern void set_default_breakpoint ();
+
+extern void mark_breakpoints_out ();
+extern void breakpoint_auto_delete ();
+extern void breakpoint_clear_ignore_counts ();
+
+/* The following are for displays, which aren't really breakpoints, but
+   here is as good a place as any for them.  */
+
+extern void disable_current_display ();
+extern void do_displays ();
+extern void disable_display ();
+extern void clear_displays ();
+
+\f
+/* The follow stuff is an abstract data type "bpstat" ("breakpoint status").
+   This provides the ability to determine whether we have stopped at a
+   breakpoint, and what we should do about it.  */
+
+typedef struct bpstat__struct *bpstat;
+
+/* Interface:  */
+
+/* Clear a bpstat so that it says we are not at any breakpoint.
+   Also free any storage that is part of a bpstat.  */
+void bpstat_clear();
+
+/* Return a copy of a bpstat.  Like "bs1 = bs2" but all storage that
+   is part of the bpstat is copied as well.  */
+bpstat bpstat_copy();
+
+/* Get a bpstat associated with having just stopped at address *PC
+   and frame address FRAME_ADDRESS.  Update *PC to point at the
+   breakpoint (if we hit a breakpoint).  */
+bpstat bpstat_stop_status (/* CORE_ADDR *pc; FRAME_ADDR frame_address */);
+
+/* Nonzero if we should print the frame.  */
+#define bpstat_should_print(bs) ((bs) != NULL && (bs)->print)
+
+/* Nonzero if we should stop.  */
+#define bpstat_stop(bs) ((bs) != NULL && (bs)->stop)
+
+/* Nonzero if we hit a momentary breakpoint.  */
+#define bpstat_momentary_breakpoint(bs) ((bs) != NULL && (bs)->momentary)
+
+/* Nonzero if a signal that we got in wait() was due to circumstances
+   explained by the BS.  */
+/* Currently that is true iff we have hit a breakpoint.  */
+#define bpstat_explains_signal(bs) ((bs) != NULL)
+
+/* Nonzero if we should step constantly (e.g. watchpoints on machines
+   without hardware support).  This isn't related to a specific bpstat,
+   just to things like whether watchpoints are set.  */
+int bpstat_should_step (/* void */);
+
+/* Print a message indicating what happened.  Returns nonzero to
+   say that only the source line should be printed after this (zero
+   return means print the frame as well as the source line).  */
+int bpstat_print (/* bpstat bs */);
+
+/* Return the breakpoint number of the first breakpoint we are stopped
+   at.  *BSP upon return is a bpstat which points to the remaining
+   breakpoints stopped at (but which is not guaranteed to be good for
+   anything but further calls to bpstat_num).
+   Return 0 if passed a bpstat which does not indicate any breakpoints.  */
+int bpstat_num (/* bpstat *bsp; */);
+
+/* Perform actions associated with having stopped at *BSP.  */
+void bpstat_do_actions (/* bpstat bs; */);
+
+/* Modify BS so that the actions will not be performed.  */
+void bpstat_clear_actions (/* bpstat bs; */);
+
+
+/* Implementation:  */
+#include "value.h"
+struct bpstat__struct
+{
+  /* Linked list because there can be two breakpoints at the
+     same place, and a bpstat reflects the fact that both have been hit.  */
+  bpstat next;
+  /* Breakpoint that we are at.  */
+  struct breakpoint *breakpoint_at;
+  /* Commands left to be done.  */
+  struct command_line *commands;
+  /* Old value associated with a watchpoint.  */
+  value old_val;
+  /* Nonzero if we should print the frame.  Only significant for the first
+     bpstat in the chain.  */
+  char print;
+  /* Nonzero if we should stop.  Only significant for the first bpstat in
+     the chain.  */
+  char stop;
+  /* Nonzero if we hit a momentary breakpoint.  Only significant for the
+     first bpstat in the chain.  */
+  char momentary;
+};
+#endif /* breakpoint.h not already included.  */
diff --git a/gdb/coffread.c b/gdb/coffread.c
new file mode 100644 (file)
index 0000000..0e6b2c7
--- /dev/null
@@ -0,0 +1,1969 @@
+/* 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-1991 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.  */
+\f
+#include <stdio.h>
+#include "defs.h"
+#include "param.h"
+#include "symtab.h"
+#include "breakpoint.h"
+#include "bfd.h"
+#include "libcoff.h"           /* FIXME secret internal data from BFD */
+#include "symfile.h"
+
+#include <intel-coff.h>
+#include <obstack.h>
+#include <string.h>
+
+static void add_symbol_to_list ();
+static void 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 void finish_block ();
+static struct blockvector *make_blockvector ();
+static struct symbol *process_coff_symbol ();
+static int init_stringtab ();
+static void free_stringtab ();
+static char *getfilename ();
+static char *getsymname ();
+static int init_lineno ();
+static void enter_linenos ();
+static void read_one_sym ();
+
+extern int fclose ();
+extern void free_all_symtabs ();
+extern void free_all_psymtabs ();
+
+/* external routines from the BFD library -- undocumented interface used
+   by GDB to read symbols.  Move to libcoff.h.  FIXME-SOMEDAY!  */
+extern void bfd_coff_swap_sym (/* symfile_bfd, &sym */);
+extern void bfd_coff_swap_aux (/* symfile_bfd, &aux, type, sclass */);
+extern void bfd_coff_swap_lineno (/* symfile_bfd, &lineno */);
+
+
+/* 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 start and end of text of current source file.
+   This comes from a ".text" symbol where x_nlinno > 0.  */
+
+static CORE_ADDR cur_src_start_addr;
+static CORE_ADDR cur_src_end_addr;
+
+/* 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 addresses of the symbol table stream and number of symbols
+   of the object file we are reading (as copied into core).  */
+
+static FILE *nlist_stream_global;
+static int nlist_nsyms_global;
+
+/* The entry point (starting address) of the file, if it is an executable.  */
+
+static CORE_ADDR entry_point;
+
+/* 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;
+
+/* Vector of line number information.  */
+
+static struct linetable *line_vector;
+
+/* Index of next entry to go in line_vector_index.  */
+
+static int line_vector_index;
+
+/* Last line number recorded in the line vector.  */
+
+static int prev_line_number;
+
+/* Number of elements allocated for line_vector currently.  */
+
+static int line_vector_length;
+
+#ifdef TDESC
+#define SEM
+int int_sem_val = 's' << 24 | 'e' << 16 | 'm' << 8 | '.';
+int temp_sem_val;
+int last_coffsem = 2;
+int last_coffsyn = 0;
+int debug_info = 0;    /*used by tdesc */
+extern int tdesc_handle;
+extern int safe_to_init_tdesc_context;
+#endif
+
+/* Chain of typedefs of pointers to empty struct/union types.
+   They are chained thru the SYMBOL_VALUE_CHAIN.  */
+
+#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 *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;
+  int depth;
+};
+
+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 */
+
+/* Complaints about various problems in the file being read  */
+
+struct complaint ef_complaint = 
+  {"Unmatched .ef symbol(s) ignored starting at symnum %d", 0, 0};
+
+\f
+/* 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;
+}
+\f
+/* 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;
+{
+  struct linetable_entry *e;
+  /* 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 = line; e->pc = pc;
+}
+\f
+/* 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 ()
+{
+  file_symbols = 0;
+  global_symbols = 0;
+  context_stack = 0;
+  within_function = 0;
+  last_source_file = 0;
+#ifdef TDESC
+  last_coffsem = 2;
+  last_coffsyn = 0;
+#endif
+
+  /* Initialize the source file information for this file.  */
+
+  line_vector_index = 0;
+  line_vector_length = 1000;
+  prev_line_number = -2;       /* Force first line number to be explicit */
+  line_vector = (struct linetable *)
+    xmalloc (sizeof (struct linetable)
+            + line_vector_length * sizeof (struct linetable_entry));
+}
+
+/* Save the vital information from when starting to read a file,
+   for use when closing off the current file.
+   NAME is the file name the symbols came from, START_ADDR is the first
+   text address for the file, and SIZE is the number of bytes of text.  */
+
+static void
+complete_symtab (name, start_addr, size)
+    char *name;
+    CORE_ADDR start_addr;
+    unsigned int size;
+{
+  last_source_file = savestring (name, strlen (name));
+  cur_src_start_addr = start_addr;
+  cur_src_end_addr = start_addr + size;
+
+  if (entry_point < cur_src_end_addr
+      && entry_point >= cur_src_start_addr)
+    {
+      startup_file_start = cur_src_start_addr;
+      startup_file_end = cur_src_end_addr;
+    }
+}
+
+/* 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. */
+
+static void
+end_symtab ()
+{
+  register struct symtab *symtab;
+  register struct context_stack *cstk;
+  register struct blockvector *blockvector;
+  register struct linetable *lv;
+
+  /* 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, cur_src_end_addr);
+      free (cstk);
+    }
+
+  /* Ignore a file that has no functions with real debugging info.  */
+  if (pending_blocks == 0 && file_symbols == 0 && global_symbols == 0)
+    {
+      free (line_vector);
+      line_vector = 0;
+      line_vector_length = -1;
+      last_source_file = 0;
+      return;
+    }
+
+  /* Create the two top-level blocks for this file.  */
+  finish_block (0, &file_symbols, 0, cur_src_start_addr, cur_src_end_addr);
+  finish_block (0, &global_symbols, 0, cur_src_start_addr, cur_src_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;
+  lv = line_vector;
+  lv->nitems = line_vector_index;
+  symtab->linetable = (struct linetable *)
+    xrealloc (lv, (sizeof (struct linetable)
+                  + lv->nitems * sizeof (struct linetable_entry)));
+  symtab->nlines = 0;
+  symtab->line_charpos = 0;
+
+#ifdef TDESC
+  symtab->coffsem = last_coffsem;
+  symtab->coffsyn = last_coffsyn;
+#endif
+
+  /* Link the new symtab into the list of such.  */
+  symtab->next = symtab_list;
+  symtab_list = symtab;
+
+  /* Reinitialize for beginning of new file. */
+  line_vector = 0;
+  line_vector_length = -1;
+  last_source_file = 0;
+}
+\f
+static void
+record_misc_function (name, address)
+     char *name;
+     CORE_ADDR address;
+{
+#ifdef TDESC
+  /* We don't want TDESC entry points on the misc_function_vector */
+  if (name[0] == '@') return;
+#endif
+  /* mf_text isn't true, but apparently COFF doesn't tell us what it really
+     is, so this guess is more useful than mf_unknown.  */
+  prim_record_misc_function (savestring (name, strlen (name)),
+                            address,
+                            (int)mf_text);
+}
+\f
+/* coff_symfile_init ()
+   is the coff-specific initialization routine for reading symbols.
+   It is passed a struct sym_fns which contains, among other things,
+   the BFD for the file whose symbols are being read, and a slot for
+   a pointer to "private data" which we fill with cookies and other
+   treats for coff_symfile_read ().
+
+   We will only be called if this is a COFF or COFF-like file.
+   BFD handles figuring out the format of the file, and code in symtab.c
+   uses BFD's determination to vector to us.
+
+   The ultimate result is a new symtab (or, FIXME, eventually a psymtab).  */
+
+struct coff_symfile_info {
+  file_ptr min_lineno_offset;          /* Where in file lowest line#s are */
+  file_ptr max_lineno_offset;          /* 1+last byte of line#s in file */
+};
+
+void
+coff_symfile_init (sf)
+     struct sym_fns *sf;
+{
+  bfd *abfd = sf->sym_bfd;
+
+  /* Allocate struct to keep track of the symfile */
+  /* FIXME memory leak */
+  sf->sym_private = xmalloc (sizeof (struct coff_symfile_info));
+
+#if defined (TDESC)
+  safe_to_init_tdesc_context  = 0;
+#endif
+
+  /* Save startup file's range of PC addresses to help blockframe.c
+     decide where the bottom of the stack is.  */
+  if (bfd_get_file_flags (abfd) & EXEC_P)
+    {
+      /* Executable file -- record its entry point so we'll recognize
+        the startup file because it contains the entry point.  */
+      entry_point = bfd_get_start_address (abfd);
+    }
+  else
+    {
+      /* Examination of non-executable.o files.  Short-circuit this stuff.  */
+      /* ~0 will not be in any file, we hope.  */
+      entry_point = ~0;
+      /* set the startup file to be an empty range.  */
+      startup_file_start = 0;
+      startup_file_end = 0;
+    }
+}
+
+/* This function is called for every section; it finds the outer limits
+   of the line table (minimum and maximum file offset) so that the
+   mainline code can read the whole thing for efficiency.  */
+
+static void
+find_linenos (abfd, asect, vpinfo)
+     bfd *abfd;
+     sec_ptr asect;
+     void *vpinfo;
+{
+  struct coff_symfile_info *info;
+  int size, count;
+  file_ptr offset, maxoff;
+
+/* WARNING WILL ROBINSON!  ACCESSING BFD-PRIVATE DATA HERE!  FIXME!  */
+  count = asect->lineno_count;
+/* End of warning */
+
+  if (count == 0)
+    return;
+  size = count * sizeof (struct lineno);
+
+  info = (struct coff_symfile_info *)vpinfo;
+/* WARNING WILL ROBINSON!  ACCESSING BFD-PRIVATE DATA HERE!  FIXME!  */
+  offset = asect->line_filepos;
+/* End of warning */
+
+  if (offset < info->min_lineno_offset || info->min_lineno_offset == 0)
+    info->min_lineno_offset = offset;
+
+  maxoff = offset + size;
+  if (maxoff > info->max_lineno_offset)
+    info->max_lineno_offset = maxoff;
+}
+
+
+/* Read a symbol file, after initialization by coff_symfile_init.  */
+/* FIXME!  Addr and Mainline are not used yet -- this will not work for
+   shared libraries or add_file!  */
+
+void
+coff_symfile_read (sf, addr, mainline)
+     struct sym_fns *sf;
+     CORE_ADDR addr;
+     int mainline;
+{
+  struct coff_symfile_info *info = (struct coff_symfile_info *)sf->sym_private;
+  bfd *abfd = sf->sym_bfd;
+  char *name = bfd_get_filename (abfd);
+  int desc;
+  register int val;
+  int num_symbols;
+  int symtab_offset;
+  int stringtab_offset;
+
+  symfile_bfd = abfd;                  /* Kludge for swap routines */
+
+/* WARNING WILL ROBINSON!  ACCESSING BFD-PRIVATE DATA HERE!  FIXME!  */
+   desc = fileno ((FILE *)(abfd->iostream));           /* File descriptor */
+   num_symbols = bfd_get_symcount (abfd);      /* How many syms */
+   symtab_offset = obj_sym_filepos (abfd);     /* Symbol table file offset */
+   stringtab_offset = symtab_offset + num_symbols * SYMESZ;  /* String tab */
+/* End of warning */
+
+#ifdef TDESC
+  debug_info = text_hdr.s_relptr;
+  if (tdesc_handle)
+    {
+       dc_terminate (tdesc_handle);
+       tdesc_handle = 0;
+    }
+#endif
+
+  /* Read the line number table, all at once.  */
+  info->min_lineno_offset = 0;
+  info->max_lineno_offset = 0;
+  bfd_map_over_sections (abfd, find_linenos, info);
+
+  val = init_lineno (desc, info->min_lineno_offset, 
+                    info->max_lineno_offset - info->min_lineno_offset);
+  if (val < 0)
+    error ("\"%s\": error reading line numbers\n", name);
+
+  /* Now read the string table, all at once.  */
+
+  val = init_stringtab (desc, stringtab_offset);
+  if (val < 0)
+    {
+      free_all_symtabs ();             /* FIXME blows whole symtab */
+      printf ("\"%s\": can't get string table", name);
+      fflush (stdout);
+      return;
+    }
+  make_cleanup (free_stringtab, 0);
+
+  /* Position to read the symbol table.  Do not read it all at once. */
+  val = lseek (desc, (long)symtab_offset, 0);
+  if (val < 0)
+    perror_with_name (name);
+
+  init_misc_bunches ();
+  make_cleanup (discard_misc_bunches, 0);
+
+  /* Now that the executable file is positioned at symbol table,
+     process it and define symbols accordingly.  */
+
+  read_coff_symtab (desc, num_symbols);
+
+  patch_opaque_types ();
+
+  /* Sort symbols alphabetically within each block.  */
+
+  sort_all_symtab_syms ();
+
+  /* Go over the misc symbol bunches and install them in vector.  */
+
+  condense_misc_bunches (0);
+
+  /* Make a default for file to list.  */
+
+  select_source_symtab (0);    /* FIXME, this might be too slow, see dbxread */
+}
+
+void
+coff_symfile_discard ()
+{
+  /* There seems to be nothing to do here.  */
+}
+
+void
+coff_new_init ()
+{
+  /* There seems to be nothing to do except free_all_symtabs and set
+     symfile to zero, which is done by our caller.  */
+}
+\f
+/* 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, etc */
+  long c_value;
+  int c_sclass;
+  int c_secnum;
+  unsigned int c_type;
+};
+
+/* 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 ().  */
+
+static void
+read_coff_symtab (desc, nsyms)
+     int desc;
+     int nsyms;
+{
+  int newfd;                   /* Avoid multiple closes on same desc */
+  FILE *stream; 
+  register struct context_stack *new;
+  struct coff_symbol coff_symbol;
+  register struct coff_symbol *cs = &coff_symbol;
+  static SYMENT main_sym;
+  static AUXENT main_aux;
+  struct coff_symbol fcn_cs_saved;
+  static SYMENT fcn_sym_saved;
+  static AUXENT fcn_aux_saved;
+
+  /* A .file is open.  */
+  int in_source_file = 0;
+  int num_object_files = 0;
+  int next_file_symnum = -1;
+
+  /* Name of the current file.  */
+  char *filestring = "";
+  int depth;
+  int fcn_first_line;
+  int fcn_last_line;
+  int fcn_start_addr;
+  long fcn_line_ptr;
+  struct cleanup *old_chain;
+
+
+  newfd = dup (desc);
+  if (newfd == -1)
+    fatal ("Too many open files");
+  stream = fdopen (newfd, "r");
+
+  old_chain = make_cleanup (free_all_symtabs, 0);
+  make_cleanup (fclose, stream);
+  nlist_stream_global = stream;
+  nlist_nsyms_global = nsyms;
+  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 *));
+
+  start_symtab ();
+
+  symnum = 0;
+  while (symnum < nsyms)
+    {
+      QUIT;                    /* Make this command interruptable.  */
+      read_one_sym (cs, &main_sym, &main_aux);
+
+#ifdef SEM
+      temp_sem_val = cs->c_name[0] << 24 | cs->c_name[1] << 16 |
+                     cs->c_name[2] << 8 | cs->c_name[3];
+      if (int_sem_val == temp_sem_val)
+        last_coffsem = (int) strtol (cs->c_name+4, (char **) NULL, 10);
+#endif
+
+      if (cs->c_symnum == next_file_symnum && cs->c_sclass != C_FILE)
+       {
+         if (last_source_file)
+           end_symtab ();
+
+         start_symtab ();
+         complete_symtab ("_globals_", 0, first_object_file_end);
+         /* done with all files, everything from here on out is globals */
+       }
+
+      /* Special case for file with type declarations only, no text.  */
+      if (!last_source_file && cs->c_type != T_NULL && cs->c_secnum == N_DEBUG)
+       complete_symtab (filestring, 0, 0);
+
+      /* Typedefs should not be treated as symbol definitions.  */
+      if (ISFCN (cs->c_type) && cs->c_sclass != C_TPDEF)
+       {
+         /* record as misc function.  if we get '.bf' next,
+          * then we undo this step
+          */
+         record_misc_function (cs->c_name, cs->c_value);
+
+         fcn_line_ptr = main_aux.x_sym.x_fcnary.x_fcn.x_lnnoptr;
+         fcn_start_addr = cs->c_value;
+         fcn_cs_saved = *cs;
+         fcn_sym_saved = main_sym;
+         fcn_aux_saved = main_aux;
+         continue;
+       }
+
+      switch (cs->c_sclass)
+       {
+         case C_EFCN:
+         case C_EXTDEF:
+         case C_ULABEL:
+         case C_USTATIC:
+         case C_LINE:
+         case C_ALIAS:
+         case C_HIDDEN:
+           printf ("Bad n_sclass = %d\n", cs->c_sclass);
+           break;
+
+         case C_FILE:
+           /*
+            * c_value field contains symnum of next .file entry in table
+            * or symnum of first global after last .file.
+            */
+           next_file_symnum = cs->c_value;
+           filestring = getfilename (&main_aux);
+           /*
+            * Complete symbol table for last object file
+            * containing debugging information.
+            */
+           if (last_source_file)
+             {
+               end_symtab ();
+               start_symtab ();
+             }
+           in_source_file = 1;
+           break;
+
+          case C_STAT:
+           if (cs->c_name[0] == '.') {
+                   if (strcmp (cs->c_name, _TEXT) == 0) {
+                           if (++num_object_files == 1) {
+                                   /* last address of startup file */
+                                   first_object_file_end = cs->c_value +
+                                           main_aux.x_scn.x_scnlen;
+                           }
+                           /* Check for in_source_file deals with case of
+                              a file with debugging symbols
+                              followed by a later file with no symbols.  */
+                           if (in_source_file)
+                             complete_symtab (filestring, cs->c_value,
+                                              main_aux.x_scn.x_scnlen);
+                           in_source_file = 0;
+                   }
+                   /* flush rest of '.' symbols */
+                   break;
+           }
+           else if (cs->c_type == T_NULL
+                    && cs->c_name[0] == 'L'
+                    && (strncmp (cs->c_name, "LI%", 3) == 0
+                        || strncmp (cs->c_name,"LC%",3) == 0
+                        || strncmp (cs->c_name,"LP%",3) == 0
+                        || strncmp (cs->c_name,"LPB%",4) == 0
+                        || strncmp (cs->c_name,"LBB%",4) == 0
+                        || strncmp (cs->c_name,"LBE%",4) == 0
+                        || strncmp (cs->c_name,"LPBX%",5) == 0))
+             /* At least on a 3b1, gcc generates swbeg and string labels
+                that look like this.  Ignore them.  */
+             break;
+           /* fall in for static symbols that don't start with '.' */
+         case C_EXT:
+           if (cs->c_sclass == C_EXT &&
+               cs->c_secnum == N_ABS &&
+               strcmp (cs->c_name, _ETEXT) == 0)
+                   end_of_text_addr = cs->c_value;
+           if (cs->c_type == T_NULL) {
+                   if (cs->c_secnum <= 1) {    /* text or abs */
+                           record_misc_function (cs->c_name, cs->c_value);
+                           break;
+                   } else {
+                           cs->c_type = T_INT;
+                   }
+           }
+           (void) process_coff_symbol (cs, &main_aux);
+           break;
+
+         case C_FCN:
+           if (strcmp (cs->c_name, ".bf") == 0)
+             {
+               within_function = 1;
+
+               /* value contains address of first non-init type code */
+               /* main_aux.x_sym.x_misc.x_lnsz.x_lnno
+                           contains line number of '{' } */
+               fcn_first_line = main_aux.x_sym.x_misc.x_lnsz.x_lnno;
+
+               new = (struct context_stack *)
+                 xmalloc (sizeof (struct context_stack));
+               new->depth = depth = 0;
+               new->next = 0;
+               context_stack = new;
+               new->locals = 0;
+               new->old_blocks = pending_blocks;
+               new->start_addr = fcn_start_addr;
+               fcn_cs_saved.c_name = getsymname (&fcn_sym_saved);
+               new->name = process_coff_symbol (&fcn_cs_saved,
+                                                &fcn_aux_saved);
+             }
+           else if (strcmp (cs->c_name, ".ef") == 0)
+             {
+                     /* the value of .ef is the address of epilogue code;
+                      * not useful for gdb
+                      */
+               /* { main_aux.x_sym.x_misc.x_lnsz.x_lnno
+                           contains number of lines to '}' */
+               new = context_stack;
+               if (new == 0)
+                 {
+                   complain (&ef_complaint, cs->c_symnum);
+                   within_function = 0;
+                   break;
+                 }
+               fcn_last_line = main_aux.x_sym.x_misc.x_lnsz.x_lnno;
+               enter_linenos (fcn_line_ptr, fcn_first_line, fcn_last_line);
+
+               finish_block (new->name, &local_symbols, new->old_blocks,
+                             new->start_addr,
+#if defined (FUNCTION_EPILOGUE_SIZE)
+                             /* This macro should be defined only on
+                                machines where the
+                                fcn_aux_saved.x_sym.x_misc.x_fsize
+                                field is always zero.
+                                So use the .bf record information that
+                                points to the epilogue and add the size
+                                of the epilogue.  */
+                             cs->c_value + FUNCTION_EPILOGUE_SIZE
+#else
+                             fcn_cs_saved.c_value +
+                                 fcn_aux_saved.x_sym.x_misc.x_fsize
+#endif
+                             );
+               context_stack = 0;
+               within_function = 0;
+               free (new);
+             }
+           break;
+
+         case C_BLOCK:
+           if (strcmp (cs->c_name, ".bb") == 0)
+             {
+               new = (struct context_stack *)
+                           xmalloc (sizeof (struct context_stack));
+               depth++;
+               new->depth = depth;
+               new->next = context_stack;
+               context_stack = new;
+               new->locals = local_symbols;
+               new->old_blocks = pending_blocks;
+               new->start_addr = cs->c_value;
+               new->name = 0;
+               local_symbols = 0;
+             }
+           else if (strcmp (cs->c_name, ".eb") == 0)
+             {
+               new = context_stack;
+               if (new == 0 || depth != new->depth)
+                 error ("Invalid symbol data: .bb/.eb symbol mismatch at symbol %d.",
+                        symnum);
+               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, cs->c_value);
+                 }
+               depth--;
+               local_symbols = new->locals;
+               context_stack = new->next;
+               free (new);
+             }
+           break;
+#ifdef TDESC
+          case C_VERSION:
+            if (strcmp (cs->c_name, ".coffsyn") == 0)
+               last_coffsyn = cs->c_value;
+           else if ((strcmp (cs->c_name, ".coffsem") == 0) &&
+                     (cs->c_value != 0))
+               last_coffsem = cs->c_value;
+            break;
+#endif
+
+         default:
+#ifdef TDESC
+           if ((strcmp (cs->c_name, ".coffsem") == 0) &&
+               (cs->c_value != 0))
+             last_coffsem = cs->c_value;
+            else
+#endif
+           (void) process_coff_symbol (cs, &main_aux);
+           break;
+       }
+    }
+
+  if (last_source_file)
+    end_symtab ();
+  fclose (stream);
+  discard_cleanups (old_chain);
+}
+\f
+/* Routines for reading headers and symbols from executable.  */
+
+#ifdef FIXME
+/* Move these XXXMAGIC symbol defns into BFD!  */
+
+/* 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 MC68MAGIC
+    case MC68MAGIC:
+#endif
+#ifdef NS32GMAGIC
+      case NS32GMAGIC:
+      case NS32SMAGIC:
+#endif
+#ifdef I386MAGIC
+    case I386MAGIC:
+#endif
+#ifdef CLIPPERMAGIC
+    case CLIPPERMAGIC:
+#endif
+#if defined (MC68KWRMAGIC) \
+  && (!defined (MC68MAGIC) || MC68KWRMAGIC != MC68MAGIC)
+    case MC68KWRMAGIC:
+#endif
+#ifdef MC68KROMAGIC
+    case MC68KROMAGIC:
+    case MC68KPGMAGIC:
+#endif
+#ifdef MC88DGMAGIC
+    case MC88DGMAGIC:
+#endif      
+#ifdef MC88MAGIC
+    case MC88MAGIC:
+#endif      
+#ifdef I960ROMAGIC
+    case I960ROMAGIC:          /* Intel 960 */
+#endif
+#ifdef I960RWMAGIC
+    case I960RWMAGIC:          /* Intel 960 */
+#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
+    }
+}
+#endif
+
+
+static void
+read_one_sym (cs, sym, aux)
+    register struct coff_symbol *cs;
+    register SYMENT *sym;
+    register AUXENT *aux;
+{
+  AUXENT temp_aux;
+  int i;
+
+  cs->c_symnum = symnum;
+  fread ((char *)sym, SYMESZ, 1, nlist_stream_global);
+  bfd_coff_swap_sym (symfile_bfd, sym);
+  cs->c_nsyms = (sym->n_numaux & 0xff) + 1;
+  if (cs->c_nsyms >= 2)
+    {
+    fread ((char *)aux, AUXESZ, 1, nlist_stream_global);
+    bfd_coff_swap_aux (symfile_bfd, aux, sym->n_type, sym->n_sclass);
+    /* If more than one aux entry, read past it (only the first aux
+       is important). */
+    for (i = 2; i < cs->c_nsyms; i++)
+      fread ((char *)&temp_aux, AUXESZ, 1, nlist_stream_global);
+    }
+  cs->c_name = getsymname (sym);
+  cs->c_value = sym->n_value;
+  cs->c_sclass = (sym->n_sclass & 0xff);
+  cs->c_secnum = sym->n_scnum;
+  cs->c_type = (unsigned) sym->n_type;
+
+  symnum += cs->c_nsyms;
+}
+\f
+/* Support for string table handling */
+
+static char *stringtab = NULL;
+
+static int
+init_stringtab (chan, offset)
+    int chan;
+    long offset;
+{
+  long length;
+  int val;
+  unsigned char lengthbuf[4];
+
+  if (stringtab)
+    {
+      free (stringtab);
+      stringtab = NULL;
+    }
+
+  if (lseek (chan, offset, 0) < 0)
+    return -1;
+
+  val = myread (chan, (char *)lengthbuf, sizeof lengthbuf);
+  length = bfd_h_getlong (symfile_bfd, lengthbuf);
+
+  /* If no string table is needed, then the file may end immediately
+     after the symbols.  Just return with `stringtab' set to null. */
+  if (val != sizeof length || length < sizeof length)
+    return 0;
+
+  stringtab = (char *) xmalloc (length);
+  if (stringtab == NULL)
+    return -1;
+
+  bcopy (&length, stringtab, sizeof length);
+  if (length == sizeof length)         /* Empty table -- just the count */
+    return 0;
+
+  val = myread (chan, stringtab + sizeof length, length - sizeof length);
+  if (val != length - sizeof length || stringtab[length - 1] != '\0')
+    return -1;
+
+  return 0;
+}
+
+static void
+free_stringtab ()
+{
+  if (stringtab)
+    free (stringtab);
+  stringtab = NULL;
+}
+
+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;
+}
+
+static char *
+getfilename (aux_entry)
+    AUXENT *aux_entry;
+{
+  static char buffer[BUFSIZ];
+  register char *temp;
+  char *result;
+  extern char *rindex ();
+
+#ifndef COFF_NO_LONG_FILE_NAMES
+  if (aux_entry->x_file.x_n.x_zeroes == 0)
+    strcpy (buffer, stringtab + aux_entry->x_file.x_n.x_offset);
+  else
+#endif /* COFF_NO_LONG_FILE_NAMES */
+    {
+#if defined (x_name)
+      /* Data General.  */
+      strncpy (buffer, aux_entry->x_name, FILNMLEN);
+#else
+      strncpy (buffer, aux_entry->x_file.x_fname, FILNMLEN);
+#endif
+      buffer[FILNMLEN] = '\0';
+    }
+  result = buffer;
+  if ((temp = rindex (result, '/')) != NULL)
+    result = temp + 1;
+  return (result);
+}
+\f
+/* Support for line number handling */
+static char *linetab = NULL;
+static long linetab_offset;
+static unsigned long linetab_size;
+
+/* Read in all the line numbers for fast lookups later.  */
+static int
+init_lineno (chan, offset, size)
+    int chan;
+    long offset;
+    int size;
+{
+  int val;
+  register char *p, *q;
+
+  if (lseek (chan, offset, 0) < 0)
+    return -1;
+  
+  linetab = (char *) xmalloc (size);
+
+  val = myread (chan, linetab, size);
+  if (val != size)
+    return -1;
+
+  /* Swap all entries */
+  q = linetab + size;
+  for (p = linetab; p < q; p += LINESZ)
+    bfd_coff_swap_lineno (symfile_bfd, (LINENO *)p);
+
+  linetab_offset = offset;
+  linetab_size = size;
+  make_cleanup (free, linetab);                /* Be sure it gets de-allocated. */
+  return 0;
+}
+
+#if !defined (L_LNNO32)
+#define L_LNNO32(lp) ((lp)->l_lnno)
+#endif
+
+static void
+enter_linenos (file_offset, first_line, last_line)
+    long file_offset;
+    register int first_line;
+    register int last_line;
+{
+  register char *rawptr;
+  struct lineno lptr;
+
+  if (file_offset < linetab_offset)
+    {
+      fprintf (stderr, "\nInvalid symbol file: file_offset < linetab_offset.");
+      return;
+    }
+  
+  rawptr = &linetab[file_offset - linetab_offset];
+
+  /* skip first line entry for each function */
+  rawptr += LINESZ;
+  /* line numbers start at one for the first line of the function */
+  first_line--;
+
+  /* Bcopy since occaisionally rawptr isn't pointing at long
+     boundaries.  FIXME we need to byteswap here!!!  */  
+  for (bcopy (rawptr, &lptr, LINESZ);
+       L_LNNO32 (&lptr) && L_LNNO32 (&lptr) <= last_line;
+       rawptr += LINESZ, bcopy (rawptr, &lptr, LINESZ))
+    {
+      record_line (first_line + L_LNNO32 (&lptr), lptr.l_addr.l_paddr);
+    }
+}
+\f
+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_CHAIN (prev) = SYMBOL_VALUE_CHAIN (sym);
+                     else
+                       opaque_type_chain[hash] = SYMBOL_VALUE_CHAIN (sym);
+
+                     patch_type (SYMBOL_TYPE (sym), SYMBOL_TYPE (real_sym));
+
+                     if (prev)
+                       sym = SYMBOL_VALUE_CHAIN (prev);
+                     else
+                       sym = opaque_type_chain[hash];
+                   }
+                 else
+                   {
+                     prev = sym;
+                     sym = SYMBOL_VALUE_CHAIN (sym);
+                   }
+               }
+           }
+       }
+    }
+}
+\f
+#if defined (clipper)
+#define BELIEVE_PCC_PROMOTION 1
+#endif
+
+static struct symbol *
+process_coff_symbol (cs, aux)
+     register struct coff_symbol *cs;
+     register AUXENT *aux;
+{
+  register struct symbol *sym
+    = (struct symbol *) obstack_alloc (symbol_obstack, sizeof (struct symbol));
+  char *name;
+#ifdef NAMES_HAVE_UNDERSCORE
+  int offset = 1;
+#else
+  int offset = 0;
+#endif
+
+  bzero (sym, sizeof (struct symbol));
+  name = cs->c_name;
+  name = (name[0] == '_' ? name + offset : name);
+  SYMBOL_NAME (sym) = obstack_copy0 (symbol_obstack, name, strlen (name));
+
+  /* default assumptions */
+  SYMBOL_VALUE (sym) = cs->c_value;
+  SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+
+  if (ISFCN (cs->c_type))
+    {
+      SYMBOL_TYPE (sym) = 
+       lookup_function_type (decode_function_type (cs, cs->c_type, aux));
+      SYMBOL_CLASS (sym) = LOC_BLOCK;
+      if (cs->c_sclass == C_STAT)
+       add_symbol_to_list (sym, &file_symbols);
+      else if (cs->c_sclass == C_EXT)
+       add_symbol_to_list (sym, &global_symbols);
+    }
+  else
+    {
+      SYMBOL_TYPE (sym) = decode_type (cs, cs->c_type, aux);
+      switch (cs->c_sclass)
+       {
+         case C_NULL:
+           break;
+
+         case C_AUTO:
+           SYMBOL_CLASS (sym) = LOC_LOCAL;
+           add_symbol_to_list (sym, &local_symbols);
+           break;
+
+         case C_EXT:
+           SYMBOL_CLASS (sym) = LOC_STATIC;
+           SYMBOL_VALUE_ADDRESS (sym) = (CORE_ADDR) cs->c_value;
+           add_symbol_to_list (sym, &global_symbols);
+           break;
+
+         case C_STAT:
+           SYMBOL_CLASS (sym) = LOC_STATIC;
+           SYMBOL_VALUE_ADDRESS (sym) = (CORE_ADDR) cs->c_value;
+           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 C_REG:
+           SYMBOL_CLASS (sym) = LOC_REGISTER;
+           add_symbol_to_list (sym, &local_symbols);
+           break;
+
+         case C_LABEL:
+           break;
+
+         case C_ARG:
+           SYMBOL_CLASS (sym) = LOC_ARG;
+           add_symbol_to_list (sym, &local_symbols);
+#if !defined (BELIEVE_PCC_PROMOTION)
+           /* If PCC says a parameter is a short or a char,
+              it is really an int.  */
+           if (SYMBOL_TYPE (sym) == builtin_type_char
+               || SYMBOL_TYPE (sym) == builtin_type_short)
+             SYMBOL_TYPE (sym) = builtin_type_int;
+           else if (SYMBOL_TYPE (sym) == builtin_type_unsigned_char
+                    || SYMBOL_TYPE (sym) == builtin_type_unsigned_short)
+             SYMBOL_TYPE (sym) = builtin_type_unsigned_int;
+#endif
+           break;
+
+         case C_REGPARM:
+           SYMBOL_CLASS (sym) = LOC_REGPARM;
+           add_symbol_to_list (sym, &local_symbols);
+#if !defined (BELIEVE_PCC_PROMOTION)
+           /* If PCC says a parameter is a short or a char,
+              it is really an int.  */
+           if (SYMBOL_TYPE (sym) == builtin_type_char
+               || SYMBOL_TYPE (sym) == builtin_type_short)
+             SYMBOL_TYPE (sym) = builtin_type_int;
+           else if (SYMBOL_TYPE (sym) == builtin_type_unsigned_char
+                    || SYMBOL_TYPE (sym) == builtin_type_unsigned_short)
+             SYMBOL_TYPE (sym) = builtin_type_unsigned_int;
+#endif
+           break;
+           
+         case C_TPDEF:
+           SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+           SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+
+           /* If type has no name, give it one */
+           if (TYPE_NAME (SYMBOL_TYPE (sym)) == 0 
+               && (TYPE_FLAGS (SYMBOL_TYPE (sym)) & TYPE_FLAG_PERM) == 0)
+             TYPE_NAME (SYMBOL_TYPE (sym))
+                                         = concat (SYMBOL_NAME (sym), "", "");
+
+           /* Keep track of any type which points to empty structured type,
+               so it can be filled from a definition from another file */
+           if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_PTR &&
+               TYPE_LENGTH (TYPE_TARGET_TYPE (SYMBOL_TYPE (sym))) == 0)
+             {
+               register int i = hashname (SYMBOL_NAME (sym));
+
+               SYMBOL_VALUE_CHAIN (sym) = opaque_type_chain[i];
+               opaque_type_chain[i] = sym;
+             }
+           add_symbol_to_list (sym, &file_symbols);
+           break;
+
+         case C_STRTAG:
+         case C_UNTAG:
+         case C_ENTAG:
+           SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+           SYMBOL_NAMESPACE (sym) = STRUCT_NAMESPACE;
+           if (TYPE_NAME (SYMBOL_TYPE (sym)) == 0
+               && (TYPE_FLAGS (SYMBOL_TYPE (sym)) & TYPE_FLAG_PERM) == 0)
+             TYPE_NAME (SYMBOL_TYPE (sym))
+               = concat ("",
+                         (cs->c_sclass == C_ENTAG
+                          ? "enum "
+                          : (cs->c_sclass == C_STRTAG
+                             ? "struct " : "union ")),
+                         SYMBOL_NAME (sym));
+           add_symbol_to_list (sym, &file_symbols);
+           break;
+
+         default:
+           break;
+       }
+    }
+  return sym;
+}
+\f
+/* Decode a coff type specifier;
+   return the type that is meant.  */
+
+static
+struct type *
+decode_type (cs, c_type, aux)
+     register struct coff_symbol *cs;
+     unsigned int c_type;
+     register AUXENT *aux;
+{
+  register struct type *type = 0;
+  unsigned int new_c_type;
+
+  if (c_type & ~N_BTMASK)
+    {
+      new_c_type = DECREF (c_type);
+      if (ISPTR (c_type))
+       {
+         type = decode_type (cs, new_c_type, aux);
+         type = lookup_pointer_type (type);
+       }
+      else if (ISFCN (c_type))
+       {
+         type = decode_type (cs, new_c_type, aux);
+         type = lookup_function_type (type);
+       }
+      else if (ISARY (c_type))
+       {
+         int i, n;
+         register unsigned short *dim;
+         struct type *base_type;
+
+         /* Define an array type.  */
+         /* auxent refers to array, not base type */
+         if (aux->x_sym.x_tagndx == 0)
+           cs->c_nsyms = 1;
+
+         /* shift the indices down */
+         dim = &aux->x_sym.x_fcnary.x_ary.x_dimen[0];
+         i = 1;
+         n = dim[0];
+         for (i = 0; *dim && i < DIMNUM - 1; i++, dim++)
+           *dim = *(dim + 1);
+         *dim = 0;
+
+         type = (struct type *)
+                   obstack_alloc (symbol_obstack, sizeof (struct type));
+         bzero (type, sizeof (struct type));
+
+         base_type = decode_type (cs, new_c_type, aux);
+
+         TYPE_CODE (type) = TYPE_CODE_ARRAY;
+         TYPE_TARGET_TYPE (type) = base_type;
+         TYPE_LENGTH (type) = n * TYPE_LENGTH (base_type);
+       }
+      return type;
+    }
+
+  /* Reference to existing type */
+  if (cs->c_nsyms > 1 && aux->x_sym.x_tagndx != 0)
+    {
+      type = coff_alloc_type (aux->x_sym.x_tagndx);
+      return type;
+    }
+
+  return decode_base_type (cs, BTYPE (c_type), aux);
+}
+
+/* Decode a coff type specifier for function definition;
+   return the type that the function returns.  */
+
+static
+struct type *
+decode_function_type (cs, c_type, aux)
+     register struct coff_symbol *cs;
+     unsigned int c_type;
+     register AUXENT *aux;
+{
+  if (aux->x_sym.x_tagndx == 0)
+    cs->c_nsyms = 1;   /* auxent refers to function, not base type */
+
+  return decode_type (cs, DECREF (c_type), aux);
+}
+\f
+/* basic C types */
+
+static
+struct type *
+decode_base_type (cs, c_type, aux)
+     register struct coff_symbol *cs;
+     unsigned int c_type;
+     register AUXENT *aux;
+{
+  struct type *type;
+
+  switch (c_type)
+    {
+      case T_NULL:
+        /* shows up with "void (*foo)();" structure members */
+       return builtin_type_void;
+
+#ifdef T_ARG
+      case T_ARG:
+       /* Shows up in DGUX, I think.  Not sure where.  */
+       return builtin_type_void;       /* shouldn't show up here */
+#endif
+
+#ifdef T_VOID
+      case T_VOID:
+       /* Intel 960 COFF has this symbol and meaning.  */
+       return builtin_type_void;
+#endif
+
+      case T_CHAR:
+       return builtin_type_char;
+
+      case T_SHORT:
+       return builtin_type_short;
+
+      case T_INT:
+       return builtin_type_int;
+
+      case T_LONG:
+       return builtin_type_long;
+
+      case T_FLOAT:
+       return builtin_type_float;
+
+      case T_DOUBLE:
+       return builtin_type_double;
+
+      case T_STRUCT:
+       if (cs->c_nsyms != 2)
+         {
+           /* anonymous structure type */
+           type = coff_alloc_type (cs->c_symnum);
+           TYPE_CODE (type) = TYPE_CODE_STRUCT;
+           TYPE_NAME (type) = concat ("struct ", "<opaque>", "");
+           TYPE_LENGTH (type) = 0;
+           TYPE_FIELDS (type) = 0;
+           TYPE_NFIELDS (type) = 0;
+         }
+       else
+         {
+           type = read_struct_type (cs->c_symnum,
+                                   aux->x_sym.x_misc.x_lnsz.x_size,
+                                   aux->x_sym.x_fcnary.x_fcn.x_endndx);
+         }
+       return type;
+
+      case T_UNION:
+       if (cs->c_nsyms != 2)
+         {
+           /* anonymous union type */
+           type = coff_alloc_type (cs->c_symnum);
+           TYPE_NAME (type) = concat ("union ", "<opaque>", "");
+           TYPE_LENGTH (type) = 0;
+           TYPE_FIELDS (type) = 0;
+           TYPE_NFIELDS (type) = 0;
+         }
+       else
+         {
+           type = read_struct_type (cs->c_symnum,
+                                   aux->x_sym.x_misc.x_lnsz.x_size,
+                                   aux->x_sym.x_fcnary.x_fcn.x_endndx);
+         }
+       TYPE_CODE (type) = TYPE_CODE_UNION;
+       return type;
+
+      case T_ENUM:
+       return read_enum_type (cs->c_symnum,
+                                   aux->x_sym.x_misc.x_lnsz.x_size,
+                                   aux->x_sym.x_fcnary.x_fcn.x_endndx);
+
+      case T_MOE:
+       /* shouldn't show up here */
+       break;
+
+      case T_UCHAR:
+       return builtin_type_unsigned_char;
+
+      case T_USHORT:
+       return builtin_type_unsigned_short;
+
+      case T_UINT:
+       return builtin_type_unsigned_int;
+
+      case T_ULONG:
+       return builtin_type_unsigned_long;
+    }
+  printf ("unexpected type %d at symnum %d\n", c_type, cs->c_symnum);
+  return builtin_type_void;
+}
+\f
+/* This page contains subroutines of read_type.  */
+
+/* Read the description of a structure (or union type)
+   and return an object describing the type.  */
+
+static struct type *
+read_struct_type (index, length, lastsym)
+     int index;
+     int length;
+     int lastsym;
+{
+  struct nextfield
+    {
+      struct nextfield *next;
+      struct field field;
+    };
+
+  register struct type *type;
+  register struct nextfield *list = 0;
+  struct nextfield *new;
+  int nfields = 0;
+  register int n;
+  char *name;
+#ifdef NAMES_HAVE_UNDERSCORE
+  int offset = 1;
+#else
+  int offset = 0;
+#endif
+  struct coff_symbol member_sym;
+  register struct coff_symbol *ms = &member_sym;
+  SYMENT sub_sym;
+  AUXENT sub_aux;
+  int done = 0;
+
+  type = coff_alloc_type (index);
+  TYPE_CODE (type) = TYPE_CODE_STRUCT;
+  TYPE_LENGTH (type) = length;
+
+  while (!done && symnum < lastsym && symnum < nlist_nsyms_global)
+    {
+      read_one_sym (ms, &sub_sym, &sub_aux);
+      name = ms->c_name;
+      name = (name[0] == '_' ? name + offset : name);
+
+      switch (ms->c_sclass)
+       {
+         case C_MOS:
+         case C_MOU:
+
+           /* Get space to record the next field's data.  */
+           new = (struct nextfield *) alloca (sizeof (struct nextfield));
+           new->next = list;
+           list = new;
+
+           /* Save the data.  */
+           list->field.name = savestring (name, strlen (name));
+           list->field.type = decode_type (ms, ms->c_type, &sub_aux);
+           list->field.bitpos = 8 * ms->c_value;
+           list->field.bitsize = 0;
+           nfields++;
+           break;
+
+         case C_FIELD:
+
+           /* Get space to record the next field's data.  */
+           new = (struct nextfield *) alloca (sizeof (struct nextfield));
+           new->next = list;
+           list = new;
+
+           /* Save the data.  */
+           list->field.name = savestring (name, strlen (name));
+           list->field.type = decode_type (ms, ms->c_type, &sub_aux);
+           list->field.bitpos = ms->c_value;
+           list->field.bitsize = sub_aux.x_sym.x_misc.x_lnsz.x_size;
+           nfields++;
+           break;
+
+         case C_EOS:
+           done = 1;
+           break;
+       }
+    }
+  /* Now create the vector of fields, and record how big it is.  */
+
+  TYPE_NFIELDS (type) = nfields;
+  TYPE_FIELDS (type) = (struct field *)
+               obstack_alloc (symbol_obstack, sizeof (struct field) * nfields);
+
+  /* Copy the saved-up fields into the field vector.  */
+
+  for (n = nfields; list; list = list->next)
+    TYPE_FIELD (type, --n) = list->field;
+
+  return type;
+}
+\f
+/* Read a definition of an enumeration type,
+   and create and return a suitable type object.
+   Also defines the symbols that represent the values of the type.  */
+
+static struct type *
+read_enum_type (index, length, lastsym)
+     int index;
+     int length;
+     int lastsym;
+{
+  register struct symbol *sym;
+  register struct type *type;
+  int nsyms = 0;
+  int done = 0;
+  struct pending **symlist;
+  struct coff_symbol member_sym;
+  register struct coff_symbol *ms = &member_sym;
+  SYMENT sub_sym;
+  AUXENT sub_aux;
+  struct pending *osyms, *syms;
+  register int n;
+  char *name;
+#ifdef NAMES_HAVE_UNDERSCORE
+  int offset = 1;
+#else
+  int offset = 0;
+#endif
+
+  type = coff_alloc_type (index);
+  if (within_function)
+    symlist = &local_symbols;
+  else
+    symlist = &file_symbols;
+  osyms = *symlist;
+
+  while (!done && symnum < lastsym && symnum < nlist_nsyms_global)
+    {
+      read_one_sym (ms, &sub_sym, &sub_aux);
+      name = ms->c_name;
+      name = (name[0] == '_' ? name + offset : name);
+
+      switch (ms->c_sclass)
+       {
+         case C_MOE:
+           sym = (struct symbol *) xmalloc (sizeof (struct symbol));
+           bzero (sym, sizeof (struct symbol));
+
+           SYMBOL_NAME (sym) = savestring (name, strlen (name));
+           SYMBOL_CLASS (sym) = LOC_CONST;
+           SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+           SYMBOL_VALUE (sym) = ms->c_value;
+           add_symbol_to_list (sym, symlist);
+           nsyms++;
+           break;
+
+         case C_EOS:
+           /* Sometimes the linker (on 386/ix 2.0.2 at least) screws
+              up the count of how many symbols to read.  So stop
+              on .eos.  */
+           done = 1;
+           break;
+       }
+    }
+
+  /* Now fill in the fields of the type-structure.  */
+
+  TYPE_LENGTH (type) = sizeof (int);
+  TYPE_CODE (type) = TYPE_CODE_ENUM;
+  TYPE_NFIELDS (type) = nsyms;
+  TYPE_FIELDS (type) = (struct field *)
+               obstack_alloc (symbol_obstack, sizeof (struct field) * nsyms);
+
+  /* Find the symbols for the values and put them into the type.
+     The symbols can be found in the symlist that we put them on
+     to cause them to be defined.  osyms contains the old value
+     of that symlist; everything up to there was defined by us.  */
+
+  for (syms = *symlist, n = nsyms; syms != osyms; syms = syms->next)
+    {
+      SYMBOL_TYPE (syms->symbol) = type;
+      TYPE_FIELD_NAME (type, --n) = SYMBOL_NAME (syms->symbol);
+      TYPE_FIELD_VALUE (type, n) = 0;
+      TYPE_FIELD_BITPOS (type, n) = SYMBOL_VALUE (syms->symbol);
+      TYPE_FIELD_BITSIZE (type, n) = 0;
+    }
+  return type;
+}
+
+/* Register our ability to parse symbols for coff BFD files */
+
+static struct sym_fns coff_sym_fns =
+{
+    "coff", 4,
+    coff_new_init, coff_symfile_init,
+    coff_symfile_read, coff_symfile_discard
+};
+
+void
+_initialize_coffread ()
+{
+  add_symtab_fns(&coff_sym_fns);
+}
diff --git a/gdb/command.h b/gdb/command.h
new file mode 100644 (file)
index 0000000..aa907fd
--- /dev/null
@@ -0,0 +1,151 @@
+/* Header file for command-reading library command.c.
+   Copyright (C) 1986, 1989, 1990 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 1, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#ifndef _COMMAND_H_INCLUDED
+#define _COMMAND_H_INCLUDED
+
+/* Not a set/show command.  Note that some commands which begin with
+   "set" or "show" might be in this category, if their syntax does
+   not fall into one of the following categories.  */
+typedef enum cmd_types {
+  not_set_cmd,
+  set_cmd,
+  show_cmd,
+} cmd_types;
+
+/* Types of "set" or "show" command.  */
+typedef enum var_types {
+  /* "on" or "off".  *VAR is an integer which is nonzero for on,
+     zero for off.  */
+  var_boolean,
+  /* Unsigned Integer.  *VAR is an unsigned int.  The user can type 0
+     to mean "unlimited", which is stored in *VAR as UINT_MAX.  */
+  var_uinteger,
+  /* String which the user enters with escapes (e.g. the user types \n and
+     it is a real newline in the stored string).
+     *VAR is a malloc'd string, or NULL if the string is empty.  */
+  var_string,
+  /* String which stores what the user types verbatim.
+     *VAR is a malloc'd string, or NULL if the string is empty.  */
+  var_string_noescape,
+  /* String which stores a filename.
+     *VAR is a malloc'd string, or NULL if the string is empty.  */
+  var_filename,
+  /* ZeroableInteger.  *VAR is an int.  Like Unsigned Integer except
+     that zero really means zero.  */
+  var_zinteger,
+} var_types;
+
+/* This structure records one command'd definition.  */
+
+struct cmd_list_element
+  {
+    /* Points to next command in this list.  */
+    struct cmd_list_element *next;
+
+    /* Name of this command.  */
+    char *name;
+
+    /* Command class; class values are chosen by application program.  */
+    enum command_class class;
+
+    /* Function definition of this command.
+       Zero for command class names and for help topics that
+       are not really commands.  */
+    void (*function) ();
+#   define NO_FUNCTION ((void (*)()) 0 )
+
+    /* Documentation of this command (or help topic).
+       First line is brief documentation; remaining lines form, with it,
+       the full documentation.  First line should end with a period.
+       Entire string should also end with a period, not a newline.  */
+    char *doc;
+
+    /* Auxiliary information.
+       It is up to the calling program to decide what this means.  */
+    char *aux;
+
+    /* Nonzero identifies a prefix command.  For them, the address
+       of the variable containing the list of subcommands.  */
+    struct cmd_list_element **prefixlist;
+
+    /* For prefix commands only:
+       String containing prefix commands to get here: this one
+       plus any others needed to get to it.  Should end in a space.
+       It is used before the word "command" in describing the
+       commands reached through this prefix.  */
+    char *prefixname;
+
+    /* For prefix commands only:
+       nonzero means do not get an error if subcommand is not
+       recognized; call the prefix's own function in that case.  */
+    char allow_unknown;
+
+    /* Nonzero says this is an abbreviation, and should not
+       be mentioned in lists of commands.
+       This allows "br<tab>" to complete to "break", which it
+       otherwise wouldn't.  */
+    char abbrev_flag;
+
+    /* Completion routine for this command.  */
+    char **(*completer)();
+
+    /* Type of "set" or "show" command (or SET_NOT_SET if not "set"
+       or "show").  */
+    cmd_types type;
+
+    /* Pointer to variable affected by "set" and "show".  Doesn't matter
+       if type is not_set.  */
+    char *var;
+
+    /* What kind of variable is *VAR?  */
+    var_types var_type;
+
+    /* Pointer to command strings of user-defined commands */
+    struct command_line *user_commands;
+  };
+
+/* Forward-declarations of the entry-points of command.c.  */
+
+extern struct cmd_list_element *add_cmd ();
+extern struct cmd_list_element *add_alias_cmd ();
+extern struct cmd_list_element *add_prefix_cmd ();
+extern struct cmd_list_element *add_abbrev_prefix_cmd ();
+extern struct cmd_list_element *lookup_cmd (), *lookup_cmd_1 ();
+extern void add_com ();
+extern void add_com_alias ();
+extern void add_info ();
+extern void add_info_alias ();
+extern char **complete_on_cmdlist ();
+extern void delete_cmd ();
+extern void help_cmd ();
+extern struct cmd_list_element *add_set_cmd ();
+extern struct cmd_list_element *add_show_from_set ();
+
+/* Do a "set" or "show" command.  ARG is NULL if no argument, or the text
+   of the argument, and FROM_TTY is nonzero if this command is being entered
+   directly by the user (i.e. these are just like any other
+   command).  C is the command list element for the command.  */
+extern void do_setshow_command ();
+
+/* Do a "show" command for each thing on a command list.  */
+extern void cmd_show_list ();
+
+extern void error_no_arg ();           /* Print error for missing argument */
+extern void dont_repeat ();            /* Avoid auto-repeat of command */
+
+#endif /* _COMMAND_H_INCLUDED */
diff --git a/gdb/copying.awk b/gdb/copying.awk
new file mode 100644 (file)
index 0000000..378d620
--- /dev/null
@@ -0,0 +1,55 @@
+BEGIN  {
+         FS="\"";
+         print "/* Do not modify this file; it is created automatically";
+         print "   by copying.awk.  */";
+         print "#include \"defs.h\""
+         print "#include \"command.h\""
+         print "extern int immediate_quit;";
+         print "static void";
+         print "copying_info ()";
+         print "{";
+         print "  immediate_quit++;";
+       }
+NR == 1,/^[    ]*NO WARRANTY[  ]*$/    {
+         if (! ($0 ~ /^[       ]*NO WARRANTY[  ]*$/)) 
+           {
+             printf "  printf_filtered (\"";
+             for (i = 1; i < NF; i++)
+               printf "%s\\\"", $i;
+             printf "%s\\n\");\n", $NF;
+           }
+       }
+/^[     ]*NO WARRANTY[         ]*$/    {
+         print "  immediate_quit--;";
+         print "}";
+         print "";
+         print "static void";
+         print "warranty_info ()";
+         print "{";
+         print "  immediate_quit++;";
+       }
+/^[    ]*NO WARRANTY[  ]*$/, /^[       ]*END OF TERMS AND CONDITIONS[  ]*$/{  
+         if (! ($0 ~ /^[       ]*END OF TERMS AND CONDITIONS[  ]*$/)) 
+           {
+             printf "  printf_filtered (\"";
+             for (i = 1; i < NF; i++)
+               printf "%s\\\"", $i;
+             printf "%s\\n\");\n", $NF;
+           }
+       }
+END    {
+         print "  immediate_quit--;";
+         print "}";
+         print "";
+         print "void"
+         print "_initialize_copying ()";
+         print "{";
+         print "  add_info (\"copying\", copying_info,";
+         print "           \"Conditions for redistributing copies of GDB.\");";
+         print "  add_info (\"warranty\", warranty_info,";
+         print "         \"Various kinds of warranty you do not have.\");";
+         print "}";
+       }
+
+
+           
diff --git a/gdb/copying.c b/gdb/copying.c
new file mode 100644 (file)
index 0000000..9164891
--- /dev/null
@@ -0,0 +1,217 @@
+/* Do not modify this file; it is created automatically
+   by copying.awk.  */
+#include "defs.h"
+#include "command.h"
+extern int immediate_quit;
+static void
+copying_info ()
+{
+  immediate_quit++;
+  printf_filtered ("\n");
+  printf_filtered ("               GNU GENERAL PUBLIC LICENSE\n");
+  printf_filtered ("                Version 1, February 1989\n");
+  printf_filtered ("\n");
+  printf_filtered (" Copyright (C) 1989 Free Software Foundation, Inc.\n");
+  printf_filtered ("                    675 Mass Ave, Cambridge, MA 02139, USA\n");
+  printf_filtered (" Everyone is permitted to copy and distribute verbatim copies\n");
+  printf_filtered (" of this license document, but changing it is not allowed.\n");
+  printf_filtered ("\n");
+  printf_filtered ("                       Preamble\n");
+  printf_filtered ("\n");
+  printf_filtered ("  The license agreements of most software companies try to keep users\n");
+  printf_filtered ("at the mercy of those companies.  By contrast, our General Public\n");
+  printf_filtered ("License is intended to guarantee your freedom to share and change free\n");
+  printf_filtered ("software--to make sure the software is free for all its users.  The\n");
+  printf_filtered ("General Public License applies to the Free Software Foundation's\n");
+  printf_filtered ("software and to any other program whose authors commit to using it.\n");
+  printf_filtered ("You can use it for your programs, too.\n");
+  printf_filtered ("\n");
+  printf_filtered ("  When we speak of free software, we are referring to freedom, not\n");
+  printf_filtered ("price.  Specifically, the General Public License is designed to make\n");
+  printf_filtered ("sure that you have the freedom to give away or sell copies of free\n");
+  printf_filtered ("software, that you receive source code or can get it if you want it,\n");
+  printf_filtered ("that you can change the software or use pieces of it in new free\n");
+  printf_filtered ("programs; and that you know you can do these things.\n");
+  printf_filtered ("\n");
+  printf_filtered ("  To protect your rights, we need to make restrictions that forbid\n");
+  printf_filtered ("anyone to deny you these rights or to ask you to surrender the rights.\n");
+  printf_filtered ("These restrictions translate to certain responsibilities for you if you\n");
+  printf_filtered ("distribute copies of the software, or if you modify it.\n");
+  printf_filtered ("\n");
+  printf_filtered ("  For example, if you distribute copies of a such a program, whether\n");
+  printf_filtered ("gratis or for a fee, you must give the recipients all the rights that\n");
+  printf_filtered ("you have.  You must make sure that they, too, receive or can get the\n");
+  printf_filtered ("source code.  And you must tell them their rights.\n");
+  printf_filtered ("\n");
+  printf_filtered ("  We protect your rights with two steps: (1) copyright the software, and\n");
+  printf_filtered ("(2) offer you this license which gives you legal permission to copy,\n");
+  printf_filtered ("distribute and/or modify the software.\n");
+  printf_filtered ("\n");
+  printf_filtered ("  Also, for each author's protection and ours, we want to make certain\n");
+  printf_filtered ("that everyone understands that there is no warranty for this free\n");
+  printf_filtered ("software.  If the software is modified by someone else and passed on, we\n");
+  printf_filtered ("want its recipients to know that what they have is not the original, so\n");
+  printf_filtered ("that any problems introduced by others will not reflect on the original\n");
+  printf_filtered ("authors' reputations.\n");
+  printf_filtered ("\n");
+  printf_filtered ("  The precise terms and conditions for copying, distribution and\n");
+  printf_filtered ("modification follow.\n");
+  printf_filtered ("\f\n");
+  printf_filtered ("               GNU GENERAL PUBLIC LICENSE\n");
+  printf_filtered ("   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n");
+  printf_filtered ("\n");
+  printf_filtered ("  0. This License Agreement applies to any program or other work which\n");
+  printf_filtered ("contains a notice placed by the copyright holder saying it may be\n");
+  printf_filtered ("distributed under the terms of this General Public License.  The\n");
+  printf_filtered ("\"Program\", below, refers to any such program or work, and a \"work based\n");
+  printf_filtered ("on the Program\" means either the Program or any work containing the\n");
+  printf_filtered ("Program or a portion of it, either verbatim or with modifications.  Each\n");
+  printf_filtered ("licensee is addressed as \"you\".\n");
+  printf_filtered ("\n");
+  printf_filtered ("  1. You may copy and distribute verbatim copies of the Program's source\n");
+  printf_filtered ("code as you receive it, in any medium, provided that you conspicuously and\n");
+  printf_filtered ("appropriately publish on each copy an appropriate copyright notice and\n");
+  printf_filtered ("disclaimer of warranty; keep intact all the notices that refer to this\n");
+  printf_filtered ("General Public License and to the absence of any warranty; and give any\n");
+  printf_filtered ("other recipients of the Program a copy of this General Public License\n");
+  printf_filtered ("along with the Program.  You may charge a fee for the physical act of\n");
+  printf_filtered ("transferring a copy.\n");
+  printf_filtered ("\n");
+  printf_filtered ("  2. You may modify your copy or copies of the Program or any portion of\n");
+  printf_filtered ("it, and copy and distribute such modifications under the terms of Paragraph\n");
+  printf_filtered ("1 above, provided that you also do the following:\n");
+  printf_filtered ("\n");
+  printf_filtered ("    a) cause the modified files to carry prominent notices stating that\n");
+  printf_filtered ("    you changed the files and the date of any change; and\n");
+  printf_filtered ("\n");
+  printf_filtered ("    b) cause the whole of any work that you distribute or publish, that\n");
+  printf_filtered ("    in whole or in part contains the Program or any part thereof, either\n");
+  printf_filtered ("    with or without modifications, to be licensed at no charge to all\n");
+  printf_filtered ("    third parties under the terms of this General Public License (except\n");
+  printf_filtered ("    that you may choose to grant warranty protection to some or all\n");
+  printf_filtered ("    third parties, at your option).\n");
+  printf_filtered ("\n");
+  printf_filtered ("    c) If the modified program normally reads commands interactively when\n");
+  printf_filtered ("    run, you must cause it, when started running for such interactive use\n");
+  printf_filtered ("    in the simplest and most usual way, to print or display an\n");
+  printf_filtered ("    announcement including an appropriate copyright notice and a notice\n");
+  printf_filtered ("    that there is no warranty (or else, saying that you provide a\n");
+  printf_filtered ("    warranty) and that users may redistribute the program under these\n");
+  printf_filtered ("    conditions, and telling the user how to view a copy of this General\n");
+  printf_filtered ("    Public License.\n");
+  printf_filtered ("\n");
+  printf_filtered ("    d) You may charge a fee for the physical act of transferring a\n");
+  printf_filtered ("    copy, and you may at your option offer warranty protection in\n");
+  printf_filtered ("    exchange for a fee.\n");
+  printf_filtered ("\n");
+  printf_filtered ("Mere aggregation of another independent work with the Program (or its\n");
+  printf_filtered ("derivative) on a volume of a storage or distribution medium does not bring\n");
+  printf_filtered ("the other work under the scope of these terms.\n");
+  printf_filtered ("\f\n");
+  printf_filtered ("  3. You may copy and distribute the Program (or a portion or derivative of\n");
+  printf_filtered ("it, under Paragraph 2) in object code or executable form under the terms of\n");
+  printf_filtered ("Paragraphs 1 and 2 above provided that you also do one of the following:\n");
+  printf_filtered ("\n");
+  printf_filtered ("    a) accompany it with the complete corresponding machine-readable\n");
+  printf_filtered ("    source code, which must be distributed under the terms of\n");
+  printf_filtered ("    Paragraphs 1 and 2 above; or,\n");
+  printf_filtered ("\n");
+  printf_filtered ("    b) accompany it with a written offer, valid for at least three\n");
+  printf_filtered ("    years, to give any third party free (except for a nominal charge\n");
+  printf_filtered ("    for the cost of distribution) a complete machine-readable copy of the\n");
+  printf_filtered ("    corresponding source code, to be distributed under the terms of\n");
+  printf_filtered ("    Paragraphs 1 and 2 above; or,\n");
+  printf_filtered ("\n");
+  printf_filtered ("    c) accompany it with the information you received as to where the\n");
+  printf_filtered ("    corresponding source code may be obtained.  (This alternative is\n");
+  printf_filtered ("    allowed only for noncommercial distribution and only if you\n");
+  printf_filtered ("    received the program in object code or executable form alone.)\n");
+  printf_filtered ("\n");
+  printf_filtered ("Source code for a work means the preferred form of the work for making\n");
+  printf_filtered ("modifications to it.  For an executable file, complete source code means\n");
+  printf_filtered ("all the source code for all modules it contains; but, as a special\n");
+  printf_filtered ("exception, it need not include source code for modules which are standard\n");
+  printf_filtered ("libraries that accompany the operating system on which the executable\n");
+  printf_filtered ("file runs, or for standard header files or definitions files that\n");
+  printf_filtered ("accompany that operating system.\n");
+  printf_filtered ("\n");
+  printf_filtered ("  4. You may not copy, modify, sublicense, distribute or transfer the\n");
+  printf_filtered ("Program except as expressly provided under this General Public License.\n");
+  printf_filtered ("Any attempt otherwise to copy, modify, sublicense, distribute or transfer\n");
+  printf_filtered ("the Program is void, and will automatically terminate your rights to use\n");
+  printf_filtered ("the Program under this License.  However, parties who have received\n");
+  printf_filtered ("copies, or rights to use copies, from you under this General Public\n");
+  printf_filtered ("License will not have their licenses terminated so long as such parties\n");
+  printf_filtered ("remain in full compliance.\n");
+  printf_filtered ("\n");
+  printf_filtered ("  5. By copying, distributing or modifying the Program (or any work based\n");
+  printf_filtered ("on the Program) you indicate your acceptance of this license to do so,\n");
+  printf_filtered ("and all its terms and conditions.\n");
+  printf_filtered ("\n");
+  printf_filtered ("  6. Each time you redistribute the Program (or any work based on the\n");
+  printf_filtered ("Program), the recipient automatically receives a license from the original\n");
+  printf_filtered ("licensor to copy, distribute or modify the Program subject to these\n");
+  printf_filtered ("terms and conditions.  You may not impose any further restrictions on the\n");
+  printf_filtered ("recipients' exercise of the rights granted herein.\n");
+  printf_filtered ("\f\n");
+  printf_filtered ("  7. The Free Software Foundation may publish revised and/or new versions\n");
+  printf_filtered ("of the General Public License from time to time.  Such new versions will\n");
+  printf_filtered ("be similar in spirit to the present version, but may differ in detail to\n");
+  printf_filtered ("address new problems or concerns.\n");
+  printf_filtered ("\n");
+  printf_filtered ("Each version is given a distinguishing version number.  If the Program\n");
+  printf_filtered ("specifies a version number of the license which applies to it and \"any\n");
+  printf_filtered ("later version\", you have the option of following the terms and conditions\n");
+  printf_filtered ("either of that version or of any later version published by the Free\n");
+  printf_filtered ("Software Foundation.  If the Program does not specify a version number of\n");
+  printf_filtered ("the license, you may choose any version ever published by the Free Software\n");
+  printf_filtered ("Foundation.\n");
+  printf_filtered ("\n");
+  printf_filtered ("  8. If you wish to incorporate parts of the Program into other free\n");
+  printf_filtered ("programs whose distribution conditions are different, write to the author\n");
+  printf_filtered ("to ask for permission.  For software which is copyrighted by the Free\n");
+  printf_filtered ("Software Foundation, write to the Free Software Foundation; we sometimes\n");
+  printf_filtered ("make exceptions for this.  Our decision will be guided by the two goals\n");
+  printf_filtered ("of preserving the free status of all derivatives of our free software and\n");
+  printf_filtered ("of promoting the sharing and reuse of software generally.\n");
+  printf_filtered ("\n");
+  immediate_quit--;
+}
+
+static void
+warranty_info ()
+{
+  immediate_quit++;
+  printf_filtered ("                       NO WARRANTY\n");
+  printf_filtered ("\n");
+  printf_filtered ("  9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n");
+  printf_filtered ("FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\n");
+  printf_filtered ("OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n");
+  printf_filtered ("PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n");
+  printf_filtered ("OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n");
+  printf_filtered ("MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\n");
+  printf_filtered ("TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\n");
+  printf_filtered ("PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n");
+  printf_filtered ("REPAIR OR CORRECTION.\n");
+  printf_filtered ("\n");
+  printf_filtered ("  10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n");
+  printf_filtered ("WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n");
+  printf_filtered ("REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n");
+  printf_filtered ("INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n");
+  printf_filtered ("OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n");
+  printf_filtered ("TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n");
+  printf_filtered ("YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n");
+  printf_filtered ("PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n");
+  printf_filtered ("POSSIBILITY OF SUCH DAMAGES.\n");
+  printf_filtered ("\n");
+  immediate_quit--;
+}
+
+void
+_initialize_copying ()
+{
+  add_info ("copying", copying_info,
+           "Conditions for redistributing copies of GDB.");
+  add_info ("warranty", warranty_info,
+         "Various kinds of warranty you do not have.");
+}
diff --git a/gdb/dbxread.c b/gdb/dbxread.c
new file mode 100644 (file)
index 0000000..37f456b
--- /dev/null
@@ -0,0 +1,5348 @@
+/* Read dbx symbol tables and convert to internal format, for GDB.
+   Copyright (C) 1986-1991 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.  */
+\f
+/* Symbol read-in occurs in two phases:
+   1.  A scan (read_dbx_symtab()) of the entire executable, whose sole
+       purpose is to make a list of symbols (partial symbol table)
+       which will cause symbols
+       to be read in if referenced.  This scan happens when the
+       "symbol-file" command is given (symbol_file_command()).
+   1a. The "add-file" command.  Similar to #1.
+   2.  Full read-in of symbols.  (dbx_psymtab_to_symtab()).  This happens
+       when a symbol in a file for which symbols have not yet been
+       read in is referenced.  */
+
+/* There used to be some PROFILE_TYPES code in this file which counted
+   the number of occurances of various symbols.  I'd suggest instead:
+     nm -ap foo | awk 'print $5' | sort | uniq -c
+   to print how many of each n_type, or something like
+     nm -ap foo | awk '$5 == "LSYM" {print $6 $7 $8 $9 $10 $11}' | \
+     awk 'BEGIN {FS=":"}
+     {print substr($2,1,1)}' | sort | uniq -c
+   to print the number of each kind of symbol descriptor (i.e. the letter
+   after ':').  */
+
+#include <stdio.h>
+#include <string.h>
+#include "defs.h"
+#include "param.h"
+
+#ifdef USG
+#include <sys/types.h>
+#include <fcntl.h>
+#define L_SET 0
+#define L_INCR 1
+#endif
+
+#include "a.out.gnu.h"         
+#include "stab.gnu.h"          /* We always use GNU stabs, not native, now */
+#include <ctype.h>
+
+#ifndef NO_GNU_STABS
+/*
+ * Define specifically gnu symbols here.
+ */
+
+/* The following type indicates the definition of a symbol as being
+   an indirect reference to another symbol.  The other symbol
+   appears as an undefined reference, immediately following this symbol.
+
+   Indirection is asymmetrical.  The other symbol's value will be used
+   to satisfy requests for the indirect symbol, but not vice versa.
+   If the other symbol does not have a definition, libraries will
+   be searched to find a definition.  */
+#ifndef N_INDR
+#define N_INDR 0xa
+#endif
+
+/* The following symbols refer to set elements.
+   All the N_SET[ATDB] symbols with the same name form one set.
+   Space is allocated for the set in the text section, and each set
+   element's value is stored into one word of the space.
+   The first word of the space is the length of the set (number of elements).
+
+   The address of the set is made into an N_SETV symbol
+   whose name is the same as the name of the set.
+   This symbol acts like a N_DATA global symbol
+   in that it can satisfy undefined external references.  */
+
+#ifndef N_SETA
+#define        N_SETA  0x14            /* Absolute set element symbol */
+#endif                         /* This is input to LD, in a .o file.  */
+
+#ifndef N_SETT
+#define        N_SETT  0x16            /* Text set element symbol */
+#endif                         /* This is input to LD, in a .o file.  */
+
+#ifndef N_SETD
+#define        N_SETD  0x18            /* Data set element symbol */
+#endif                         /* This is input to LD, in a .o file.  */
+
+#ifndef N_SETB
+#define        N_SETB  0x1A            /* Bss set element symbol */
+#endif                         /* This is input to LD, in a .o file.  */
+
+/* Macros dealing with the set element symbols defined in a.out.h */
+#define        SET_ELEMENT_P(x)        ((x)>=N_SETA&&(x)<=(N_SETB|N_EXT))
+#define TYPE_OF_SET_ELEMENT(x) ((x)-N_SETA+N_ABS)
+
+#ifndef N_SETV
+#define N_SETV 0x1C            /* Pointer to set vector in data area.  */
+#endif                         /* This is output from LD.  */
+
+#ifndef N_WARNING
+#define N_WARNING 0x1E         /* Warning message to print if file included */
+#endif                         /* This is input to ld */
+
+#endif /* NO_GNU_STABS */
+
+#include <obstack.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include "symtab.h"
+#include "breakpoint.h"
+#include "command.h"
+#include "target.h"
+#include "gdbcore.h"           /* for bfd stuff */
+#include "liba.out.h"          /* FIXME Secret internal BFD stuff for a.out */
+#include "symfile.h"
+
+struct dbx_symfile_info {
+  asection *text_sect;         /* Text section accessor */
+  int symcount;                        /* How many symbols are there in the file */
+  char *stringtab;             /* The actual string table */
+  int stringtab_size;          /* Its size */
+  off_t symtab_offset;         /* Offset in file to symbol table */
+  int desc;                    /* File descriptor of symbol file */
+};
+
+extern void qsort ();
+extern double atof ();
+extern struct cmd_list_element *cmdlist;
+
+extern void symbol_file_command ();
+
+/* Forward declarations */
+
+static void add_symbol_to_list ();
+static void read_dbx_symtab ();
+static void init_psymbol_list ();
+static void process_one_symbol ();
+static struct type *read_type ();
+static struct type *read_range_type ();
+static struct type *read_enum_type ();
+static struct type *read_struct_type ();
+static struct type *read_array_type ();
+static long read_number ();
+static void finish_block ();
+static struct blockvector *make_blockvector ();
+static struct symbol *define_symbol ();
+static void start_subfile ();
+static int hashname ();
+static struct pending *copy_pending ();
+static void fix_common_block ();
+static void add_undefined_type ();
+static void cleanup_undefined_types ();
+static void scan_file_globals ();
+static void read_ofile_symtab ();
+static void dbx_psymtab_to_symtab ();
+
+/* C++ */
+static struct type **read_args ();
+
+static const char vptr_name[] = { '_','v','p','t','r',CPLUS_MARKER };
+static const char vb_name[] =   { '_','v','b',CPLUS_MARKER };
+
+/* Macro to determine which symbols to ignore when reading the first symbol
+   of a file.  Some machines override this definition. */
+#ifndef IGNORE_SYMBOL
+/* This code is used on Ultrix systems.  Ignore it */
+#define IGNORE_SYMBOL(type)  (type == (int)N_NSYMS)
+#endif
+
+/* Macro for name of symbol to indicate a file compiled with gcc. */
+#ifndef GCC_COMPILED_FLAG_SYMBOL
+#define GCC_COMPILED_FLAG_SYMBOL "gcc_compiled."
+#endif
+
+/* Convert stab register number (from `r' declaration) to a gdb REGNUM.  */
+
+#ifndef STAB_REG_TO_REGNUM
+#define STAB_REG_TO_REGNUM(VALUE) (VALUE)
+#endif
+
+/* Define this as 1 if a pcc declaration of a char or short argument
+   gives the correct address.  Otherwise assume pcc gives the
+   address of the corresponding int, which is not the same on a
+   big-endian machine.  */
+
+#ifndef BELIEVE_PCC_PROMOTION
+#define BELIEVE_PCC_PROMOTION 0
+#endif
+\f
+/* Nonzero means give verbose info on gdb action.  From main.c.  */
+extern int info_verbose;
+
+/* Name of source file whose symbol data we are now processing.
+   This comes from a symbol of type N_SO.  */
+
+static char *last_source_file;
+
+/* Core address of start of text of current source file.
+   This too comes from the N_SO symbol.  */
+
+static CORE_ADDR last_source_start_addr;
+
+/* The entry point of a file we are reading.  */
+CORE_ADDR entry_point;
+
+/* The list of sub-source-files within the current individual compilation.
+   Each file gets its own symtab with its own linetable and associated info,
+   but they all share one blockvector.  */
+
+struct subfile
+{
+  struct subfile *next;
+  char *name;
+  char *dirname;
+  struct linetable *line_vector;
+  int line_vector_length;
+  int line_vector_index;
+  int prev_line_number;
+};
+
+static struct subfile *subfiles;
+
+static struct subfile *current_subfile;
+
+/* Count symbols as they are processed, for error messages.  */
+
+static unsigned int symnum;
+
+/* Vector of types defined so far, indexed by their dbx type numbers.
+   (In newer sun systems, dbx uses a pair of numbers in parens,
+    as in "(SUBFILENUM,NUMWITHINSUBFILE)".  Then these numbers must be
+    translated through the type_translations hash table to get
+    the index into the type vector.)  */
+
+static struct typevector *type_vector;
+
+/* Number of elements allocated for type_vector currently.  */
+
+static int type_vector_length;
+
+/* Vector of line number information.  */
+
+static struct linetable *line_vector;
+
+/* Index of next entry to go in line_vector_index.  */
+
+static int line_vector_index;
+
+/* Last line number recorded in the line vector.  */
+
+static int prev_line_number;
+
+/* Number of elements allocated for line_vector currently.  */
+
+static int line_vector_length;
+
+/* Hash table of global symbols whose values are not known yet.
+   They are chained thru the SYMBOL_VALUE_CHAIN, since we don't
+   have the correct data for that slot yet.  */
+/* The use of the LOC_BLOCK code in this chain is nonstandard--
+   it refers to a FORTRAN common block rather than the usual meaning.  */
+
+#define HASHSIZE 127
+static struct symbol *global_sym_chain[HASHSIZE];
+
+/* Record the symbols defined for each context in a list.
+   We don't create a struct block for the context until we
+   know how long to make it.  */
+
+#define PENDINGSIZE 100
+
+struct pending
+{
+  struct pending *next;
+  int nsyms;
+  struct symbol *symbol[PENDINGSIZE];
+};
+
+/* List of free `struct pending' structures for reuse.  */
+struct pending *free_pendings;
+
+/* Here are the three lists that symbols are put on.  */
+
+struct pending *file_symbols;  /* static at top level, and types */
+
+struct pending *global_symbols;        /* global functions and variables */
+
+struct pending *local_symbols; /* everything local to lexical context */
+
+/* List of symbols declared since the last BCOMM.  This list is a tail
+   of local_symbols.  When ECOMM is seen, the symbols on the list
+   are noted so their proper addresses can be filled in later,
+   using the common block base address gotten from the assembler
+   stabs.  */
+
+struct pending *common_block;
+int common_block_i;
+
+/* Stack representing unclosed lexical contexts
+   (that will become blocks, eventually).  */
+
+struct context_stack
+{
+  struct pending *locals;
+  struct pending_block *old_blocks;
+  struct symbol *name;
+  CORE_ADDR start_addr;
+  CORE_ADDR end_addr;          /* Temp slot for exception handling. */
+  int depth;
+};
+
+struct context_stack *context_stack;
+
+/* Index of first unused entry in context stack.  */
+int context_stack_depth;
+
+/* Currently allocated size of context stack.  */
+
+int context_stack_size;
+
+/* Nonzero if within a function (so symbols should be local,
+   if nothing says specifically).  */
+
+int within_function;
+
+/* List of blocks already made (lexical contexts already closed).
+   This is used at the end to make the blockvector.  */
+
+struct pending_block
+{
+  struct pending_block *next;
+  struct block *block;
+};
+
+struct pending_block *pending_blocks;
+
+extern CORE_ADDR startup_file_start;   /* From blockframe.c */
+extern CORE_ADDR startup_file_end;     /* From blockframe.c */
+
+/* Global variable which, when set, indicates that we are processing a
+   .o file compiled with gcc */
+
+static unsigned char processing_gcc_compilation;
+
+/* Make a list of forward references which haven't been defined.  */
+static struct type **undef_types;
+static int undef_types_allocated, undef_types_length;
+
+/* String table for the main symbol file.  It is kept in memory
+   permanently, to speed up symbol reading.  Other files' symbol tables
+   are read in on demand.  FIXME, this should be cleaner.  */
+
+static char *symfile_string_table;
+static int symfile_string_table_size;
+
+  /* Setup a define to deal cleanly with the underscore problem */
+
+#ifdef NAMES_HAVE_UNDERSCORE
+#define HASH_OFFSET 1
+#else
+#define HASH_OFFSET 0
+#endif
+
+/* Complaints about the symbols we have encountered.  */
+
+struct complaint innerblock_complaint =
+  {"inner block not inside outer block in %s", 0, 0};
+
+struct complaint blockvector_complaint = 
+  {"block at %x out of order", 0, 0};
+
+struct complaint lbrac_complaint = 
+  {"bad block start address patched", 0, 0};
+
+#if 0
+struct complaint dbx_class_complaint =
+  {"encountered DBX-style class variable debugging information.\n\
+You seem to have compiled your program with \
+\"g++ -g0\" instead of \"g++ -g\".\n\
+Therefore GDB will not know about your class variables", 0, 0};
+#endif
+
+struct complaint string_table_offset_complaint =
+  {"bad string table offset in symbol %d", 0, 0};
+
+struct complaint unknown_symtype_complaint =
+  {"unknown symbol type 0x%x", 0, 0};
+
+struct complaint lbrac_rbrac_complaint =
+  {"block start larger than block end", 0, 0};
+
+struct complaint const_vol_complaint =
+  {"const/volatile indicator missing, got '%c'", 0, 0};
+
+struct complaint error_type_complaint =
+  {"C++ type mismatch between compiler and debugger", 0, 0};
+
+struct complaint invalid_member_complaint =
+  {"invalid (minimal) member type data format at symtab pos %d.", 0, 0};
+\f
+/* Support for Sun changes to dbx symbol format */
+
+/* For each identified header file, we have a table of types defined
+   in that header file.
+
+   header_files maps header file names to their type tables.
+   It is a vector of n_header_files elements.
+   Each element describes one header file.
+   It contains a vector of types.
+
+   Sometimes it can happen that the same header file produces
+   different results when included in different places.
+   This can result from conditionals or from different
+   things done before including the file.
+   When this happens, there are multiple entries for the file in this table,
+   one entry for each distinct set of results.
+   The entries are distinguished by the INSTANCE field.
+   The INSTANCE field appears in the N_BINCL and N_EXCL symbol table and is
+   used to match header-file references to their corresponding data.  */
+
+struct header_file
+{
+  char *name;                  /* Name of header file */
+  int instance;                        /* Numeric code distinguishing instances
+                                  of one header file that produced
+                                  different results when included.
+                                  It comes from the N_BINCL or N_EXCL.  */
+  struct type **vector;                /* Pointer to vector of types */
+  int length;                  /* Allocated length (# elts) of that vector */
+};
+
+static struct header_file *header_files = 0;
+
+static int n_header_files;
+
+static int n_allocated_header_files;
+
+/* During initial symbol readin, we need to have a structure to keep
+   track of which psymtabs have which bincls in them.  This structure
+   is used during readin to setup the list of dependencies within each
+   partial symbol table. */
+
+struct header_file_location
+{
+  char *name;                  /* Name of header file */
+  int instance;                        /* See above */
+  struct partial_symtab *pst;  /* Partial symtab that has the
+                                  BINCL/EINCL defs for this file */
+};
+
+/* The actual list and controling variables */
+static struct header_file_location *bincl_list, *next_bincl;
+static int bincls_allocated;
+
+/* Within each object file, various header files are assigned numbers.
+   A type is defined or referred to with a pair of numbers
+   (FILENUM,TYPENUM) where FILENUM is the number of the header file
+   and TYPENUM is the number within that header file.
+   TYPENUM is the index within the vector of types for that header file.
+
+   FILENUM == 1 is special; it refers to the main source of the object file,
+   and not to any header file.  FILENUM != 1 is interpreted by looking it up
+   in the following table, which contains indices in header_files.  */
+
+static int *this_object_header_files = 0;
+
+static int n_this_object_header_files;
+
+static int n_allocated_this_object_header_files;
+
+/* When a header file is getting special overriding definitions
+   for one source file, record here the header_files index
+   of its normal definition vector.
+   At other times, this is -1.  */
+
+static int header_file_prev_index;
+
+/* Free up old header file tables, and allocate new ones.
+   We're reading a new symbol file now.  */
+
+void
+free_and_init_header_files ()
+{
+  register int i;
+  for (i = 0; i < n_header_files; i++)
+    free (header_files[i].name);
+  if (header_files)                    /* First time null */
+    free (header_files);
+  if (this_object_header_files)                /* First time null */
+    free (this_object_header_files);
+
+  n_allocated_header_files = 10;
+  header_files = (struct header_file *) xmalloc (10 * sizeof (struct header_file));
+  n_header_files = 0;
+
+  n_allocated_this_object_header_files = 10;
+  this_object_header_files = (int *) xmalloc (10 * sizeof (int));
+}
+
+/* Called at the start of each object file's symbols.
+   Clear out the mapping of header file numbers to header files.  */
+
+static void
+new_object_header_files ()
+{
+  /* Leave FILENUM of 0 free for builtin types and this file's types.  */
+  n_this_object_header_files = 1;
+  header_file_prev_index = -1;
+}
+
+/* Add header file number I for this object file
+   at the next successive FILENUM.  */
+
+static void
+add_this_object_header_file (i)
+     int i;
+{
+  if (n_this_object_header_files == n_allocated_this_object_header_files)
+    {
+      n_allocated_this_object_header_files *= 2;
+      this_object_header_files
+       = (int *) xrealloc (this_object_header_files,
+                           n_allocated_this_object_header_files * sizeof (int));
+    }
+
+  this_object_header_files[n_this_object_header_files++] = i;
+}
+
+/* Add to this file an "old" header file, one already seen in
+   a previous object file.  NAME is the header file's name.
+   INSTANCE is its instance code, to select among multiple
+   symbol tables for the same header file.  */
+
+static void
+add_old_header_file (name, instance)
+     char *name;
+     int instance;
+{
+  register struct header_file *p = header_files;
+  register int i;
+
+  for (i = 0; i < n_header_files; i++)
+    if (!strcmp (p[i].name, name) && instance == p[i].instance)
+      {
+       add_this_object_header_file (i);
+       return;
+      }
+  error ("Invalid symbol data: \"repeated\" header file that hasn't been seen before, at symtab pos %d.",
+        symnum);
+}
+
+/* Add to this file a "new" header file: definitions for its types follow.
+   NAME is the header file's name.
+   Most often this happens only once for each distinct header file,
+   but not necessarily.  If it happens more than once, INSTANCE has
+   a different value each time, and references to the header file
+   use INSTANCE values to select among them.
+
+   dbx output contains "begin" and "end" markers for each new header file,
+   but at this level we just need to know which files there have been;
+   so we record the file when its "begin" is seen and ignore the "end".  */
+
+static void
+add_new_header_file (name, instance)
+     char *name;
+     int instance;
+{
+  register int i;
+  header_file_prev_index = -1;
+
+  /* Make sure there is room for one more header file.  */
+
+  if (n_header_files == n_allocated_header_files)
+    {
+      n_allocated_header_files *= 2;
+      header_files = (struct header_file *)
+       xrealloc (header_files,
+                 (n_allocated_header_files
+                  * sizeof (struct header_file)));
+    }
+
+  /* Create an entry for this header file.  */
+
+  i = n_header_files++;
+  header_files[i].name = savestring (name, strlen(name));
+  header_files[i].instance = instance;
+  header_files[i].length = 10;
+  header_files[i].vector
+    = (struct type **) xmalloc (10 * sizeof (struct type *));
+  bzero (header_files[i].vector, 10 * sizeof (struct type *));
+
+  add_this_object_header_file (i);
+}
+
+/* Look up a dbx type-number pair.  Return the address of the slot
+   where the type for that number-pair is stored.
+   The number-pair is in TYPENUMS.
+
+   This can be used for finding the type associated with that pair
+   or for associating a new type with the pair.  */
+
+static struct type **
+dbx_lookup_type (typenums)
+     int typenums[2];
+{
+  register int filenum = typenums[0], index = typenums[1];
+
+  if (filenum < 0 || filenum >= n_this_object_header_files)
+    error ("Invalid symbol data: type number (%d,%d) out of range at symtab pos %d.",
+          filenum, index, symnum);
+
+  if (filenum == 0)
+    {
+      /* Type is defined outside of header files.
+        Find it in this object file's type vector.  */
+      if (index >= type_vector_length)
+       {
+         type_vector_length *= 2;
+         type_vector = (struct typevector *)
+           xrealloc (type_vector,
+                     (sizeof (struct typevector)
+                      + type_vector_length * sizeof (struct type *)));
+         bzero (&type_vector->type[type_vector_length / 2],
+                type_vector_length * sizeof (struct type *) / 2);
+       }
+      return &type_vector->type[index];
+    }
+  else
+    {
+      register int real_filenum = this_object_header_files[filenum];
+      register struct header_file *f;
+      int f_orig_length;
+
+      if (real_filenum >= n_header_files)
+       abort ();
+
+      f = &header_files[real_filenum];
+
+      f_orig_length = f->length;
+      if (index >= f_orig_length)
+       {
+         while (index >= f->length)
+           f->length *= 2;
+         f->vector = (struct type **)
+           xrealloc (f->vector, f->length * sizeof (struct type *));
+         bzero (&f->vector[f_orig_length],
+                (f->length - f_orig_length) * sizeof (struct type *));
+       }
+      return &f->vector[index];
+    }
+}
+
+/* Create a type object.  Occaisionally used when you need a type
+   which isn't going to be given a type number.  */
+
+static struct type *
+dbx_create_type ()
+{
+  register struct type *type =
+    (struct type *) obstack_alloc (symbol_obstack, sizeof (struct type));
+
+  bzero (type, sizeof (struct type));
+  TYPE_VPTR_FIELDNO (type) = -1;
+  return type;
+}
+
+/* Make sure there is a type allocated for type numbers TYPENUMS
+   and return the type object.
+   This can create an empty (zeroed) type object.
+   TYPENUMS may be (-1, -1) to return a new type object that is not
+   put into the type vector, and so may not be referred to by number. */
+
+static struct type *
+dbx_alloc_type (typenums)
+     int typenums[2];
+{
+  register struct type **type_addr;
+  register struct type *type;
+
+  if (typenums[1] != -1)
+    {
+      type_addr = dbx_lookup_type (typenums);
+      type = *type_addr;
+    }
+  else
+    {
+      type_addr = 0;
+      type = 0;
+    }
+
+  /* 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 = dbx_create_type ();
+      if (type_addr)
+       *type_addr = type;
+    }
+  
+  return type;
+}
+
+#if 0
+static struct type **
+explicit_lookup_type (real_filenum, index)
+     int real_filenum, index;
+{
+  register struct header_file *f = &header_files[real_filenum];
+
+  if (index >= f->length)
+    {
+      f->length *= 2;
+      f->vector = (struct type **)
+       xrealloc (f->vector, f->length * sizeof (struct type *));
+      bzero (&f->vector[f->length / 2],
+            f->length * sizeof (struct type *) / 2);
+    }
+  return &f->vector[index];
+}
+#endif
+\f
+/* maintain the lists of symbols and blocks */
+
+/* Add a symbol to one of the lists of symbols.  */
+static void
+add_symbol_to_list (symbol, listhead)
+     struct symbol *symbol;
+     struct pending **listhead;
+{
+  /* We keep PENDINGSIZE symbols in each link of the list.
+     If we don't have a link with room in it, add a new link.  */
+  if (*listhead == 0 || (*listhead)->nsyms == PENDINGSIZE)
+    {
+      register struct pending *link;
+      if (free_pendings)
+       {
+         link = free_pendings;
+         free_pendings = link->next;
+       }
+      else
+       link = (struct pending *) xmalloc (sizeof (struct pending));
+
+      link->next = *listhead;
+      *listhead = link;
+      link->nsyms = 0;
+    }
+
+  (*listhead)->symbol[(*listhead)->nsyms++] = symbol;
+}
+
+/* At end of reading syms, or in case of quit,
+   really free as many `struct pending's as we can easily find.  */
+
+/* ARGSUSED */
+static void
+really_free_pendings (foo)
+     int foo;
+{
+  struct pending *next, *next1;
+  struct pending_block *bnext, *bnext1;
+
+  for (next = free_pendings; next; next = next1)
+    {
+      next1 = next->next;
+      free (next);
+    }
+  free_pendings = 0;
+
+#if 0 /* Now we make the links in the symbol_obstack, so don't free them.  */
+  for (bnext = pending_blocks; bnext; bnext = bnext1)
+    {
+      bnext1 = bnext->next;
+      free (bnext);
+    }
+#endif
+  pending_blocks = 0;
+
+  for (next = file_symbols; next; next = next1)
+    {
+      next1 = next->next;
+      free (next);
+    }
+  for (next = global_symbols; next; next = next1)
+    {
+      next1 = next->next;
+      free (next);
+    }
+}
+
+/* Take one of the lists of symbols and make a block from it.
+   Keep the order the symbols have in the list (reversed from the input file).
+   Put the block on the list of pending blocks.  */
+
+static void
+finish_block (symbol, listhead, old_blocks, start, end)
+     struct symbol *symbol;
+     struct pending **listhead;
+     struct pending_block *old_blocks;
+     CORE_ADDR start, end;
+{
+  register struct pending *next, *next1;
+  register struct block *block;
+  register struct pending_block *pblock;
+  struct pending_block *opblock;
+  register int i;
+
+  /* Count the length of the list of symbols.  */
+
+  for (next = *listhead, i = 0; next; i += next->nsyms, next = next->next)
+    /*EMPTY*/;
+
+  block = (struct block *) obstack_alloc (symbol_obstack,
+                                         (sizeof (struct block)
+                                          + ((i - 1)
+                                             * sizeof (struct symbol *))));
+
+  /* Copy the symbols into the block.  */
+
+  BLOCK_NSYMS (block) = i;
+  for (next = *listhead; next; next = next->next)
+    {
+      register int j;
+      for (j = next->nsyms - 1; j >= 0; j--)
+       BLOCK_SYM (block, --i) = next->symbol[j];
+    }
+
+  BLOCK_START (block) = start;
+  BLOCK_END (block) = end;
+  BLOCK_SUPERBLOCK (block) = 0;        /* Filled in when containing block is made */
+  BLOCK_GCC_COMPILED (block) = processing_gcc_compilation;
+
+  /* Put the block in as the value of the symbol that names it.  */
+
+  if (symbol)
+    {
+      SYMBOL_BLOCK_VALUE (symbol) = block;
+      BLOCK_FUNCTION (block) = symbol;
+    }
+  else
+    BLOCK_FUNCTION (block) = 0;
+
+  /* Now "free" the links of the list, and empty the list.  */
+
+  for (next = *listhead; next; next = next1)
+    {
+      next1 = next->next;
+      next->next = free_pendings;
+      free_pendings = next;
+    }
+  *listhead = 0;
+
+  /* Install this block as the superblock
+     of all blocks made since the start of this scope
+     that don't have superblocks yet.  */
+
+  opblock = 0;
+  for (pblock = pending_blocks; pblock != old_blocks; pblock = pblock->next)
+    {
+      if (BLOCK_SUPERBLOCK (pblock->block) == 0) {
+#if 1
+       /* Check to be sure the blocks are nested as we receive them. 
+          If the compiler/assembler/linker work, this just burns a small
+          amount of time.  */
+       if (BLOCK_START (pblock->block) < BLOCK_START (block)
+        || BLOCK_END   (pblock->block) > BLOCK_END   (block)) {
+         complain(&innerblock_complaint, symbol? SYMBOL_NAME (symbol):
+                                                "(don't know)");
+         BLOCK_START (pblock->block) = BLOCK_START (block);
+         BLOCK_END   (pblock->block) = BLOCK_END   (block);
+       }
+#endif
+       BLOCK_SUPERBLOCK (pblock->block) = block;
+      }
+      opblock = pblock;
+    }
+
+  /* Record this block on the list of all blocks in the file.
+     Put it after opblock, or at the beginning if opblock is 0.
+     This puts the block in the list after all its subblocks.  */
+
+  /* Allocate in the symbol_obstack to save time.
+     It wastes a little space.  */
+  pblock = (struct pending_block *)
+    obstack_alloc (symbol_obstack,
+                  sizeof (struct pending_block));
+  pblock->block = block;
+  if (opblock)
+    {
+      pblock->next = opblock->next;
+      opblock->next = pblock;
+    }
+  else
+    {
+      pblock->next = pending_blocks;
+      pending_blocks = pblock;
+    }
+}
+
+static struct blockvector *
+make_blockvector ()
+{
+  register struct pending_block *next;
+  register struct blockvector *blockvector;
+  register int i;
+
+  /* Count the length of the list of blocks.  */
+
+  for (next = pending_blocks, i = 0; next; next = next->next, i++);
+
+  blockvector = (struct blockvector *)
+    obstack_alloc (symbol_obstack,
+                  (sizeof (struct blockvector)
+                   + (i - 1) * sizeof (struct block *)));
+
+  /* Copy the blocks into the blockvector.
+     This is done in reverse order, which happens to put
+     the blocks into the proper order (ascending starting address).
+     finish_block has hair to insert each block into the list
+     after its subblocks in order to make sure this is true.  */
+
+  BLOCKVECTOR_NBLOCKS (blockvector) = i;
+  for (next = pending_blocks; next; next = next->next) {
+    BLOCKVECTOR_BLOCK (blockvector, --i) = next->block;
+  }
+
+#if 0 /* Now we make the links in the obstack, so don't free them.  */
+  /* Now free the links of the list, and empty the list.  */
+
+  for (next = pending_blocks; next; next = next1)
+    {
+      next1 = next->next;
+      free (next);
+    }
+#endif
+  pending_blocks = 0;
+
+#if 1  /* FIXME, shut this off after a while to speed up symbol reading.  */
+  /* Some compilers output blocks in the wrong order, but we depend
+     on their being in the right order so we can binary search. 
+     Check the order and moan about it.  FIXME.  */
+  if (BLOCKVECTOR_NBLOCKS (blockvector) > 1)
+    for (i = 1; i < BLOCKVECTOR_NBLOCKS (blockvector); i++) {
+      if (BLOCK_START(BLOCKVECTOR_BLOCK (blockvector, i-1))
+         > BLOCK_START(BLOCKVECTOR_BLOCK (blockvector, i))) {
+       complain (&blockvector_complaint, 
+         BLOCK_START(BLOCKVECTOR_BLOCK (blockvector, i)));
+      }
+    }
+#endif
+
+  return blockvector;
+}
+\f
+/* Manage the vector of line numbers.  */
+
+static void
+record_line (line, pc)
+     int line;
+     CORE_ADDR pc;
+{
+  struct linetable_entry *e;
+  /* Ignore the dummy line number in libg.o */
+
+  if (line == 0xffff)
+    return;
+
+  /* Make sure line vector is big enough.  */
+
+  if (line_vector_index + 1 >= line_vector_length)
+    {
+      line_vector_length *= 2;
+      line_vector = (struct linetable *)
+       xrealloc (line_vector,
+                 (sizeof (struct linetable)
+                  + line_vector_length * sizeof (struct linetable_entry)));
+      current_subfile->line_vector = line_vector;
+    }
+
+  e = line_vector->item + line_vector_index++;
+  e->line = line; e->pc = pc;
+}
+\f
+/* Start a new symtab for a new source file.
+   This is called when a dbx symbol of type N_SO is seen;
+   it indicates the start of data for one original source file.  */
+
+static void
+start_symtab (name, dirname, start_addr)
+     char *name;
+     char *dirname;
+     CORE_ADDR start_addr;
+{
+
+  last_source_file = name;
+  last_source_start_addr = start_addr;
+  file_symbols = 0;
+  global_symbols = 0;
+  within_function = 0;
+
+  /* Context stack is initially empty, with room for 10 levels.  */
+  context_stack
+    = (struct context_stack *) xmalloc (10 * sizeof (struct context_stack));
+  context_stack_size = 10;
+  context_stack_depth = 0;
+
+  new_object_header_files ();
+
+  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 *));
+
+  /* Initialize the list of sub source files with one entry
+     for this file (the top-level source file).  */
+
+  subfiles = 0;
+  current_subfile = 0;
+  start_subfile (name, dirname);
+}
+
+/* Handle an N_SOL symbol, which indicates the start of
+   code that came from an included (or otherwise merged-in)
+   source file with a different name.  */
+
+static void
+start_subfile (name, dirname)
+     char *name;
+     char *dirname;
+{
+  register struct subfile *subfile;
+
+  /* Save the current subfile's line vector data.  */
+
+  if (current_subfile)
+    {
+      current_subfile->line_vector_index = line_vector_index;
+      current_subfile->line_vector_length = line_vector_length;
+      current_subfile->prev_line_number = prev_line_number;
+    }
+
+  /* See if this subfile is already known as a subfile of the
+     current main source file.  */
+
+  for (subfile = subfiles; subfile; subfile = subfile->next)
+    {
+      if (!strcmp (subfile->name, name))
+       {
+         line_vector = subfile->line_vector;
+         line_vector_index = subfile->line_vector_index;
+         line_vector_length = subfile->line_vector_length;
+         prev_line_number = subfile->prev_line_number;
+         current_subfile = subfile;
+         return;
+       }
+    }
+
+  /* This subfile is not known.  Add an entry for it.  */
+
+  line_vector_index = 0;
+  line_vector_length = 1000;
+  prev_line_number = -2;       /* Force first line number to be explicit */
+  line_vector = (struct linetable *)
+    xmalloc (sizeof (struct linetable)
+             + line_vector_length * sizeof (struct linetable_entry));
+
+  /* Make an entry for this subfile in the list of all subfiles
+     of the current main source file.  */
+
+  subfile = (struct subfile *) xmalloc (sizeof (struct subfile));
+  subfile->next = subfiles;
+  subfile->name = obsavestring (name, strlen (name));
+  if (dirname == NULL)
+    subfile->dirname = NULL;
+  else
+    subfile->dirname = obsavestring (dirname, strlen (dirname));
+  
+  subfile->line_vector = line_vector;
+  subfiles = subfile;
+  current_subfile = subfile;
+}
+
+/* Finish the symbol definitions for one main source file,
+   close off all the lexical contexts for that file
+   (creating struct block's for them), then make the struct symtab
+   for that file and put it in the list of all such.
+
+   END_ADDR is the address of the end of the file's text.  */
+
+static void
+end_symtab (end_addr)
+     CORE_ADDR end_addr;
+{
+  register struct symtab *symtab;
+  register struct blockvector *blockvector;
+  register struct subfile *subfile;
+  register struct linetable *lv;
+  struct subfile *nextsub;
+
+  /* Finish the lexical context of the last function in the file;
+     pop the context stack.  */
+
+  if (context_stack_depth > 0)
+    {
+      register struct context_stack *cstk;
+      context_stack_depth--;
+      cstk = &context_stack[context_stack_depth];
+      /* Make a block for the local symbols within.  */
+      finish_block (cstk->name, &local_symbols, cstk->old_blocks,
+                   cstk->start_addr, end_addr);
+    }
+
+  /* Cleanup any undefined types that have been left hanging around
+     (this needs to be done before the finish_blocks so that
+     file_symbols is still good).  */
+  cleanup_undefined_types ();
+
+  /* Finish defining all the blocks of this symtab.  */
+  finish_block (0, &file_symbols, 0, last_source_start_addr, end_addr);
+  finish_block (0, &global_symbols, 0, last_source_start_addr, end_addr);
+  blockvector = make_blockvector ();
+
+  current_subfile->line_vector_index = line_vector_index;
+
+  /* Now create the symtab objects proper, one for each subfile.  */
+  /* (The main file is one of them.)  */
+
+  for (subfile = subfiles; subfile; subfile = nextsub)
+    {
+      symtab = (struct symtab *) xmalloc (sizeof (struct symtab));
+
+      /* Fill in its components.  */
+      symtab->blockvector = blockvector;
+      lv = subfile->line_vector;
+      lv->nitems = subfile->line_vector_index;
+      symtab->linetable = (struct linetable *)
+       xrealloc (lv, (sizeof (struct linetable)
+                      + lv->nitems * sizeof (struct linetable_entry)));
+      type_vector->length = type_vector_length;
+      symtab->typevector = type_vector;
+
+      symtab->filename = subfile->name;
+      symtab->dirname = subfile->dirname;
+
+      symtab->free_code = free_linetable;
+      symtab->free_ptr = 0;
+      if (subfile->next == 0)
+       symtab->free_ptr = (char *) type_vector;
+
+      symtab->nlines = 0;
+      symtab->line_charpos = 0;
+
+      symtab->language = language_unknown;
+      symtab->fullname = NULL;
+
+      /* If there is already a symtab for a file of this name, remove it,
+        and clear out other dependent data structures such as
+        breakpoints.  This happens in VxWorks maybe?  -gnu@cygnus */
+      free_named_symtab (symtab->filename);
+
+      /* Link the new symtab into the list of such.  */
+      symtab->next = symtab_list;
+      symtab_list = symtab;
+
+      nextsub = subfile->next;
+      free (subfile);
+    }
+
+  type_vector = 0;
+  type_vector_length = -1;
+  line_vector = 0;
+  line_vector_length = -1;
+  last_source_file = 0;
+}
+\f
+/* Handle the N_BINCL and N_EINCL symbol types
+   that act like N_SOL for switching source files
+   (different subfiles, as we call them) within one object file,
+   but using a stack rather than in an arbitrary order.  */
+
+struct subfile_stack
+{
+  struct subfile_stack *next;
+  char *name;
+  int prev_index;
+};
+
+struct subfile_stack *subfile_stack;
+
+static void
+push_subfile ()
+{
+  register struct subfile_stack *tem
+    = (struct subfile_stack *) xmalloc (sizeof (struct subfile_stack));
+
+  tem->next = subfile_stack;
+  subfile_stack = tem;
+  if (current_subfile == 0 || current_subfile->name == 0)
+    abort ();
+  tem->name = current_subfile->name;
+  tem->prev_index = header_file_prev_index;
+}
+
+static char *
+pop_subfile ()
+{
+  register char *name;
+  register struct subfile_stack *link = subfile_stack;
+
+  if (link == 0)
+    abort ();
+
+  name = link->name;
+  subfile_stack = link->next;
+  header_file_prev_index = link->prev_index;
+  free (link);
+
+  return name;
+}
+\f
+void
+record_misc_function (name, address, type)
+     char *name;
+     CORE_ADDR address;
+     int type;
+{
+  enum misc_function_type misc_type =
+    (type == (N_TEXT | N_EXT) ? mf_text :
+     (type == (N_DATA | N_EXT)
+      || type == (N_DATA)
+      || type == (N_SETV | N_EXT)
+      ) ? mf_data :
+     type == (N_BSS | N_EXT) ? mf_bss :
+     type == (N_ABS | N_EXT) ? mf_abs : mf_unknown);
+
+  prim_record_misc_function (obsavestring (name, strlen (name)),
+                            address, misc_type);
+}
+\f
+/* Scan and build partial symbols for a symbol file.
+   We have been initialized by a call to dbx_symfile_init, which 
+   put all the relevant info into a "struct dbx_symfile_info"
+   hung off the struct sym_fns SF.
+
+   ADDR is the address relative to which the symbols in it are (e.g.
+   the base address of the text segment).
+   MAINLINE is true if we are reading the main symbol
+   table (as opposed to a shared lib or dynamically loaded file).  */
+
+void
+dbx_symfile_read (sf, addr, mainline)
+     struct sym_fns *sf;
+     CORE_ADDR addr;
+     int mainline;     /* FIXME comments above */
+{
+  struct dbx_symfile_info *info = (struct dbx_symfile_info *) (sf->sym_private);
+  bfd *sym_bfd = sf->sym_bfd;
+  int val;
+  char *filename = bfd_get_filename (sym_bfd);
+
+  val = lseek (info->desc, info->symtab_offset, L_SET);
+  if (val < 0)
+    perror_with_name (filename);
+
+  /* If mainline, set global string table pointers, and reinitialize global
+     partial symbol list.  */
+  if (mainline) {
+    symfile_string_table = info->stringtab;
+    symfile_string_table_size = info->stringtab_size;
+    init_psymbol_list (info->symcount);
+  }
+
+  symfile_bfd = sym_bfd;               /* Kludge for SWAP_SYMBOL */
+
+  pending_blocks = 0;
+  make_cleanup (really_free_pendings, 0);
+
+  init_misc_bunches ();
+  make_cleanup (discard_misc_bunches, 0);
+
+  /* Now that the symbol table data of the executable file are all in core,
+     process them and define symbols accordingly.  */
+
+  read_dbx_symtab (filename, 
+                  addr - bfd_section_vma (sym_bfd, info->text_sect), /*offset*/
+                  info->desc, info->stringtab, info->stringtab_size,
+                  info->symcount,
+                  bfd_section_vma  (sym_bfd, info->text_sect),
+                  bfd_section_size (sym_bfd, info->text_sect));
+
+  /* Go over the misc symbol bunches and install them in vector.  */
+
+  condense_misc_bunches (!mainline);
+
+  /* Free up any memory we allocated for ourselves.  */
+
+  if (!mainline) {
+    free (info->stringtab);    /* Stringtab is only saved for mainline */
+  }
+  free (info);
+  sf->sym_private = 0;         /* Zap pointer to our (now gone) info struct */
+
+  /* Call to select_source_symtab used to be here; it was using too
+     much time.  I'll make sure that list_sources can handle the lack
+     of current_source_symtab */
+
+  if (!partial_symtab_list)
+    printf_filtered ("\n(no debugging symbols found)...");
+}
+
+/* Discard any information we have cached during the reading of a
+   single symbol file.  This should not toss global information
+   from previous symbol files that have been read.  E.g. we might
+   be discarding info from reading a shared library, and should not
+   throw away the info from the main file.  */
+
+void
+dbx_symfile_discard ()
+{
+
+  /* Empty the hash table of global syms looking for values.  */
+  bzero (global_sym_chain, sizeof global_sym_chain);
+
+  free_pendings = 0;
+  file_symbols = 0;
+  global_symbols = 0;
+}
+
+/* Initialize anything that needs initializing when a completely new
+   symbol file is specified (not just adding some symbols from another
+   file, e.g. a shared library).  */
+
+void
+dbx_new_init ()
+{
+  dbx_symfile_discard ();
+  /* Don't put these on the cleanup chain; they need to stick around
+     until the next call to symbol_file_command.  *Then* we'll free
+     them. */
+  if (symfile_string_table)
+    {
+      free (symfile_string_table);
+      symfile_string_table = 0;
+      symfile_string_table_size = 0;
+    }
+  free_and_init_header_files ();
+}
+
+
+/* dbx_symfile_init ()
+   is the dbx-specific initialization routine for reading symbols.
+   It is passed a struct sym_fns which contains, among other things,
+   the BFD for the file whose symbols are being read, and a slot for a pointer
+   to "private data" which we fill with goodies.
+
+   We read the string table into malloc'd space and stash a pointer to it.
+
+   Since BFD doesn't know how to read debug symbols in a format-independent
+   way (and may never do so...), we have to do it ourselves.  We will never
+   be called unless this is an a.out (or very similar) file. 
+   FIXME, there should be a cleaner peephole into the BFD environment here.  */
+
+void
+dbx_symfile_init (sf)
+  struct sym_fns *sf;
+{
+  int val;
+  int desc;
+  struct stat statbuf;
+  bfd *sym_bfd = sf->sym_bfd;
+  char *name = bfd_get_filename (sym_bfd);
+  struct dbx_symfile_info *info;
+  unsigned char size_temp[4];
+
+  /* Allocate struct to keep track of the symfile */
+  sf->sym_private = xmalloc (sizeof (*info));   /* FIXME storage leak */
+  info = (struct dbx_symfile_info *)sf->sym_private;
+
+  /* FIXME POKING INSIDE BFD DATA STRUCTURES */
+  desc = fileno ((FILE *)(sym_bfd->iostream)); /* Raw file descriptor */
+#define        STRING_TABLE_OFFSET     (sym_bfd->origin + obj_str_filepos (sym_bfd))
+#define        SYMBOL_TABLE_OFFSET     (sym_bfd->origin + obj_sym_filepos (sym_bfd))
+  /* FIXME POKING INSIDE BFD DATA STRUCTURES */
+
+  info->desc = desc;
+  info->text_sect = bfd_get_section_by_name (sym_bfd, ".text");
+  if (!info->text_sect)
+    abort();
+  info->symcount = bfd_get_symcount_upper_bound(sym_bfd);   /* It's exact for a.out */
+
+  /* Read the string table size and check it for bogosity.  */
+  val = lseek (desc, STRING_TABLE_OFFSET, L_SET);
+  if (val < 0)
+      perror_with_name (name);
+  if (fstat (desc, &statbuf) == -1)
+      perror_with_name (name);
+
+  val = myread (desc, size_temp, sizeof (long));
+  if (val < 0)
+      perror_with_name (name);
+  info->stringtab_size = bfd_h_getlong (sym_bfd, size_temp);
+  
+  if (info->stringtab_size >= 0 && info->stringtab_size < statbuf.st_size)
+    {
+      info->stringtab = (char *) xmalloc (info->stringtab_size);
+      /* Caller is responsible for freeing the string table.  No cleanup. */
+    }
+  else
+    info->stringtab = NULL;
+  if (info->stringtab == NULL && info->stringtab_size != 0)
+    error ("ridiculous string table size: %d bytes", info->stringtab_size);
+
+  /* Now read in the string table in one big gulp.  */
+
+  val = lseek (desc, STRING_TABLE_OFFSET, L_SET);
+  if (val < 0)
+    perror_with_name (name);
+  val = myread (desc, info->stringtab, info->stringtab_size);
+  if (val < 0)
+    perror_with_name (name);
+
+  /* Record the position of the symbol table for later use.  */
+
+  info->symtab_offset = SYMBOL_TABLE_OFFSET;
+}
+\f
+/* Buffer for reading the symbol table entries.  */
+static struct nlist symbuf[4096];
+static int symbuf_idx;
+static int symbuf_end;
+
+/* I/O descriptor for reading the symbol table.  */
+static int symtab_input_desc;
+
+/* The address in memory of the string table of the object file we are
+   reading (which might not be the "main" object file, but might be a
+   shared library or some other dynamically loaded thing).  This is set
+   by read_dbx_symtab when building psymtabs, and by read_ofile_symtab 
+   when building symtabs, and is used only by next_symbol_text.  */
+static char *stringtab_global;
+
+/* Refill the symbol table input buffer
+   and set the variables that control fetching entries from it.
+   Reports an error if no data available.
+   This function can read past the end of the symbol table
+   (into the string table) but this does no harm.  */
+
+static int
+fill_symbuf ()
+{
+  int nbytes = myread (symtab_input_desc, symbuf, sizeof (symbuf));
+  if (nbytes < 0)
+    perror_with_name ("<symbol file>");
+  else if (nbytes == 0)
+    error ("Premature end of file reading symbol table");
+  symbuf_end = nbytes / sizeof (struct nlist);
+  symbuf_idx = 0;
+  return 1;
+}
+
+#define SWAP_SYMBOL(symp) \
+  { \
+    (symp)->n_un.n_strx = bfd_h_getlong(symfile_bfd,                   \
+                               (unsigned char *)&(symp)->n_un.n_strx); \
+    (symp)->n_desc = bfd_h_getshort (symfile_bfd,                      \
+                               (unsigned char *)&(symp)->n_desc);      \
+    (symp)->n_value = bfd_h_getlong (symfile_bfd,                      \
+                               (unsigned char *)&(symp)->n_value);     \
+  }
+
+/* Invariant: The symbol pointed to by symbuf_idx is the first one
+   that hasn't been swapped.  Swap the symbol at the same time
+   that symbuf_idx is incremented.  */
+
+/* dbx allows the text of a symbol name to be continued into the
+   next symbol name!  When such a continuation is encountered
+   (a \ at the end of the text of a name)
+   call this function to get the continuation.  */
+
+static char *
+next_symbol_text ()
+{
+  if (symbuf_idx == symbuf_end)
+    fill_symbuf ();
+  symnum++;
+  SWAP_SYMBOL(&symbuf[symbuf_idx]);
+  return symbuf[symbuf_idx++].n_un.n_strx + stringtab_global;
+}
+\f
+/* Initializes storage for all of the partial symbols that will be
+   created by read_dbx_symtab and subsidiaries.  */
+
+static void
+init_psymbol_list (total_symbols)
+     int total_symbols;
+{
+  /* Free any previously allocated psymbol lists.  */
+  if (global_psymbols.list)
+    free (global_psymbols.list);
+  if (static_psymbols.list)
+    free (static_psymbols.list);
+
+  /* Current best guess is that there are approximately a twentieth
+     of the total symbols (in a debugging file) are global or static
+     oriented symbols */
+  global_psymbols.size = total_symbols / 10;
+  static_psymbols.size = total_symbols / 10;
+  global_psymbols.next = global_psymbols.list = (struct partial_symbol *)
+    xmalloc (global_psymbols.size * sizeof (struct partial_symbol));
+  static_psymbols.next = static_psymbols.list = (struct partial_symbol *)
+    xmalloc (static_psymbols.size * sizeof (struct partial_symbol));
+}
+
+/* Initialize the list of bincls to contain none and have some
+   allocated.  */
+
+static void
+init_bincl_list (number)
+     int number;
+{
+  bincls_allocated = number;
+  next_bincl = bincl_list = (struct header_file_location *)
+      xmalloc (bincls_allocated * sizeof(struct header_file_location));
+}
+
+/* Add a bincl to the list.  */
+
+static void
+add_bincl_to_list (pst, name, instance)
+     struct partial_symtab *pst;
+     char *name;
+     int instance;
+{
+  if (next_bincl >= bincl_list + bincls_allocated)
+    {
+      int offset = next_bincl - bincl_list;
+      bincls_allocated *= 2;
+      bincl_list = (struct header_file_location *)
+       xrealloc ((char *)bincl_list,
+                 bincls_allocated * sizeof (struct header_file_location));
+      next_bincl = bincl_list + offset;
+    }
+  next_bincl->pst = pst;
+  next_bincl->instance = instance;
+  next_bincl++->name = name;
+}
+
+/* Given a name, value pair, find the corresponding
+   bincl in the list.  Return the partial symtab associated
+   with that header_file_location.  */
+
+struct partial_symtab *
+find_corresponding_bincl_psymtab (name, instance)
+     char *name;
+     int instance;
+{
+  struct header_file_location *bincl;
+
+  for (bincl = bincl_list; bincl < next_bincl; bincl++)
+    if (bincl->instance == instance
+       && !strcmp (name, bincl->name))
+      return bincl->pst;
+
+  return (struct partial_symtab *) 0;
+}
+
+/* Free the storage allocated for the bincl list.  */
+
+static void
+free_bincl_list ()
+{
+  free (bincl_list);
+  bincls_allocated = 0;
+}
+
+static struct partial_symtab *start_psymtab ();
+static void end_psymtab();
+
+#ifdef DEBUG
+/* This is normally a macro defined in read_dbx_symtab, but this
+   is a lot easier to debug.  */
+
+ADD_PSYMBOL_TO_PLIST(NAME, NAMELENGTH, NAMESPACE, CLASS, PLIST, VALUE)
+     char *NAME;
+     int NAMELENGTH;
+     enum namespace NAMESPACE;
+     enum address_class CLASS;
+     struct psymbol_allocation_list *PLIST;
+     unsigned long VALUE;
+{
+  register struct partial_symbol *psym;
+
+#define LIST *PLIST
+  do {                                                                 
+    if ((LIST).next >=                                 
+       (LIST).list + (LIST).size)                      
+      {                                                                        
+       (LIST).list = (struct partial_symbol *)                         
+         xrealloc ((LIST).list,                                        
+                   ((LIST).size * 2                                    
+                    * sizeof (struct partial_symbol)));                
+       /* Next assumes we only went one over.  Should be good if       
+          program works correctly */                                   
+       (LIST).next =                                                   
+         (LIST).list + (LIST).size;                            
+       (LIST).size *= 2;                               
+      }                                                                        
+    psym = (LIST).next++;                                              
+#undef LIST
+
+    SYMBOL_NAME (psym) = (char *) obstack_alloc (psymbol_obstack,      
+                                                (NAMELENGTH) + 1);     
+    strncpy (SYMBOL_NAME (psym), (NAME), (NAMELENGTH));                        
+    SYMBOL_NAME (psym)[(NAMELENGTH)] = '\0';                           
+    SYMBOL_NAMESPACE (psym) = (NAMESPACE);                             
+    SYMBOL_CLASS (psym) = (CLASS);                             
+    SYMBOL_VALUE (psym) = (VALUE);                                     
+  } while (0);
+}
+
+/* Since one arg is a struct, we have to pass in a ptr and deref it (sigh) */
+#define        ADD_PSYMBOL_TO_LIST(NAME, NAMELENGTH, NAMESPACE, CLASS,  LIST, VALUE) \
+       ADD_PSYMBOL_TO_PLIST(NAME, NAMELENGTH, NAMESPACE, CLASS, &LIST, VALUE)
+
+#endif /* DEBUG */
+
+/* Given pointers to an a.out symbol table in core containing dbx
+   style data, setup partial_symtab's describing each source file for
+   which debugging information is available.  NLISTLEN is the number
+   of symbols in the symbol table.  All symbol names are given as
+   offsets relative to STRINGTAB.  STRINGTAB_SIZE is the size of
+   STRINGTAB.  SYMFILE_NAME is the name of the file we are reading from
+   and ADDR is its relocated address (if incremental) or 0 (if not).  */
+
+static void
+read_dbx_symtab (symfile_name, addr,
+                desc, stringtab, stringtab_size, nlistlen,
+                text_addr, text_size)
+     char *symfile_name;
+     CORE_ADDR addr;
+     int desc;
+     register char *stringtab;
+     register long stringtab_size;
+     register int nlistlen;
+     CORE_ADDR text_addr;
+     int text_size;
+{
+  register struct nlist *bufp;
+  register char *namestring;
+  register struct partial_symbol *psym;
+  int nsl;
+  int past_first_source_file = 0;
+  CORE_ADDR last_o_file_start = 0;
+  struct cleanup *old_chain;
+  char *p;
+
+  /* End of the text segment of the executable file.  */
+  CORE_ADDR end_of_text_addr;
+
+  /* Current partial symtab */
+  struct partial_symtab *pst;
+
+  /* List of current psymtab's include files */
+  char **psymtab_include_list;
+  int includes_allocated;
+  int includes_used;
+
+  /* Index within current psymtab dependency list */
+  struct partial_symtab **dependency_list;
+  int dependencies_used, dependencies_allocated;
+
+  stringtab_global = stringtab;
+  
+  pst = (struct partial_symtab *) 0;
+
+  includes_allocated = 30;
+  includes_used = 0;
+  psymtab_include_list = (char **) alloca (includes_allocated *
+                                          sizeof (char *));
+
+  dependencies_allocated = 30;
+  dependencies_used = 0;
+  dependency_list =
+    (struct partial_symtab **) alloca (dependencies_allocated *
+                                      sizeof (struct partial_symtab *));
+
+  /* FIXME!!  If an error occurs, this blows away the whole symbol table! 
+     It should only blow away the psymtabs created herein.  We could
+     be reading a shared library or a dynloaded file!  */
+  old_chain = make_cleanup (free_all_psymtabs, 0);
+
+  /* Init bincl list */
+  init_bincl_list (20);
+  make_cleanup (free_bincl_list, 0);
+
+  last_source_file = 0;
+
+#ifdef END_OF_TEXT_DEFAULT
+  end_of_text_addr = END_OF_TEXT_DEFAULT;
+#else
+  end_of_text_addr = addr + text_size;
+#endif
+
+  symtab_input_desc = desc;    /* This is needed for fill_symbuf below */
+  symbuf_end = symbuf_idx = 0;
+
+  for (symnum = 0; symnum < nlistlen; symnum++)
+    {
+      /* Get the symbol for this run and pull out some info */
+      QUIT;    /* allow this to be interruptable */
+      if (symbuf_idx == symbuf_end)
+       fill_symbuf ();
+      bufp = &symbuf[symbuf_idx++];
+
+      /*
+       * Special case to speed up readin.
+       */
+      if (bufp->n_type == (unsigned char)N_SLINE) continue;
+
+      SWAP_SYMBOL (bufp);
+
+      /* Ok.  There is a lot of code duplicated in the rest of this
+         switch statement (for efficiency reasons).  Since I don't
+         like duplicating code, I will do my penance here, and
+         describe the code which is duplicated:
+
+        *) The assignment to namestring.
+        *) The call to strchr.
+        *) The addition of a partial symbol the the two partial
+           symbol lists.  This last is a large section of code, so
+           I've imbedded it in the following macro.
+        */
+      
+/* Set namestring based on bufp.  If the string table index is invalid, 
+   give a fake name, and print a single error message per symbol file read,
+   rather than abort the symbol reading or flood the user with messages.  */
+#define SET_NAMESTRING()\
+  if (bufp->n_un.n_strx < 0 || bufp->n_un.n_strx >= stringtab_size) {  \
+    complain (&string_table_offset_complaint, symnum);                 \
+    namestring = "foo";                                                        \
+  } else                                                               \
+    namestring = bufp->n_un.n_strx + stringtab
+
+/* Add a symbol with an integer value to a psymtab. */
+/* This is a macro unless we're debugging.  See above this function. */
+#ifndef DEBUG
+#  define ADD_PSYMBOL_TO_LIST(NAME, NAMELENGTH, NAMESPACE, CLASS, LIST, VALUE) \
+ ADD_PSYMBOL_VT_TO_LIST(NAME, NAMELENGTH, NAMESPACE, CLASS, LIST, VALUE, \
+                        SYMBOL_VALUE)
+#endif /* DEBUG */
+
+/* Add a symbol with a CORE_ADDR value to a psymtab. */
+#define        ADD_PSYMBOL_ADDR_TO_LIST(NAME, NAMELENGTH, NAMESPACE, CLASS, LIST, VALUE) \
+ ADD_PSYMBOL_VT_TO_LIST(NAME, NAMELENGTH, NAMESPACE, CLASS, LIST, VALUE, \
+                        SYMBOL_VALUE_ADDRESS)
+
+/* Add any kind of symbol to a psymtab. */
+#define        ADD_PSYMBOL_VT_TO_LIST(NAME, NAMELENGTH, NAMESPACE, CLASS, LIST, VALUE, VT)\
+  do {                                                                 \
+    if ((LIST).next >=                                                 \
+       (LIST).list + (LIST).size)                                      \
+      {                                                                        \
+       (LIST).list = (struct partial_symbol *)                         \
+         xrealloc ((LIST).list,                                        \
+                   ((LIST).size * 2                                    \
+                    * sizeof (struct partial_symbol)));                \
+       /* Next assumes we only went one over.  Should be good if       \
+          program works correctly */                                   \
+       (LIST).next =                                                   \
+         (LIST).list + (LIST).size;                                    \
+       (LIST).size *= 2;                                               \
+      }                                                                        \
+    psym = (LIST).next++;                                              \
+                                                                       \
+    SYMBOL_NAME (psym) = (char *) obstack_alloc (psymbol_obstack,      \
+                                                (NAMELENGTH) + 1);     \
+    strncpy (SYMBOL_NAME (psym), (NAME), (NAMELENGTH));                        \
+    SYMBOL_NAME (psym)[(NAMELENGTH)] = '\0';                           \
+    SYMBOL_NAMESPACE (psym) = (NAMESPACE);                             \
+    SYMBOL_CLASS (psym) = (CLASS);                                     \
+    VT (psym) = (VALUE);                                               \
+  } while (0);
+
+/* End of macro definitions, now let's handle them symbols!  */
+
+      switch (bufp->n_type)
+       {
+         /*
+          * Standard, external, non-debugger, symbols
+          */
+
+       case N_TEXT | N_EXT:
+       case N_NBTEXT | N_EXT:
+       case N_NBDATA | N_EXT:
+       case N_NBBSS | N_EXT:
+       case N_SETV | N_EXT:
+       case N_ABS | N_EXT:
+       case N_DATA | N_EXT:
+       case N_BSS | N_EXT:
+
+         bufp->n_value += addr;                /* Relocate */
+
+         SET_NAMESTRING();
+
+       bss_ext_symbol:
+         record_misc_function (namestring, bufp->n_value,
+                               bufp->n_type); /* Always */
+
+         continue;
+
+         /* Standard, local, non-debugger, symbols */
+
+       case N_NBTEXT:
+
+         /* We need to be able to deal with both N_FN or N_TEXT,
+            because we have no way of knowing whether the sys-supplied ld
+            or GNU ld was used to make the executable.  */
+#if ! (N_FN & N_EXT)
+       case N_FN:
+#endif
+       case N_FN | N_EXT:
+       case N_TEXT:
+         bufp->n_value += addr;                /* Relocate */
+         SET_NAMESTRING();
+         if ((namestring[0] == '-' && namestring[1] == 'l')
+             || (namestring [(nsl = strlen (namestring)) - 1] == 'o'
+                 && namestring [nsl - 2] == '.'))
+           {
+             if (entry_point < bufp->n_value
+                 && entry_point >= last_o_file_start
+                 && addr == 0)         /* FIXME nogood nomore */
+               {
+                 startup_file_start = last_o_file_start;
+                 startup_file_end = bufp->n_value;
+               }
+             if (past_first_source_file && pst
+                 /* The gould NP1 uses low values for .o and -l symbols
+                    which are not the address.  */
+                 && bufp->n_value > pst->textlow)
+               {
+                 end_psymtab (pst, psymtab_include_list, includes_used,
+                              symnum * sizeof (struct nlist), bufp->n_value,
+                              dependency_list, dependencies_used,
+                              global_psymbols.next, static_psymbols.next);
+                 pst = (struct partial_symtab *) 0;
+                 includes_used = 0;
+                 dependencies_used = 0;
+               }
+             else
+               past_first_source_file = 1;
+             last_o_file_start = bufp->n_value;
+           }
+         continue;
+
+       case N_DATA:
+         bufp->n_value += addr;                /* Relocate */
+         SET_NAMESTRING ();
+         /* Check for __DYNAMIC, which is used by Sun shared libraries. 
+            Record it even if it's local, not global, so we can find it.  */
+         if (namestring[8] == 'C' && (strcmp ("__DYNAMIC", namestring) == 0))
+           {
+             /* Not really a function here, but... */
+             record_misc_function (namestring, bufp->n_value,
+                                   bufp->n_type); /* Always */
+         }
+         continue;
+
+       case N_UNDF | N_EXT:
+         if (bufp->n_value != 0) {
+           /* This is a "Fortran COMMON" symbol.  See if the target
+              environment knows where it has been relocated to.  */
+
+           CORE_ADDR reladdr;
+
+           SET_NAMESTRING();
+           if (target_lookup_symbol (namestring, &reladdr)) {
+             continue;         /* Error in lookup; ignore symbol for now.  */
+           }
+           bufp->n_type ^= (N_BSS^N_UNDF);     /* Define it as a bss-symbol */
+           bufp->n_value = reladdr;
+           goto bss_ext_symbol;
+         }
+         continue;     /* Just undefined, not COMMON */
+
+           /* Lots of symbol types we can just ignore.  */
+
+       case N_UNDF:
+       case N_ABS:
+       case N_BSS:
+       case N_NBDATA:
+       case N_NBBSS:
+         continue;
+
+         /* Keep going . . .*/
+
+         /*
+          * Special symbol types for GNU
+          */
+       case N_INDR:
+       case N_INDR | N_EXT:
+       case N_SETA:
+       case N_SETA | N_EXT:
+       case N_SETT:
+       case N_SETT | N_EXT:
+       case N_SETD:
+       case N_SETD | N_EXT:
+       case N_SETB:
+       case N_SETB | N_EXT:
+       case N_SETV:
+         continue;
+
+         /*
+          * Debugger symbols
+          */
+
+       case N_SO: {
+         unsigned long valu = bufp->n_value;
+         /* Symbol number of the first symbol of this file (i.e. the N_SO
+            if there is just one, or the first if we have a pair).  */
+         int first_symnum = symnum;
+         
+         /* End the current partial symtab and start a new one */
+
+         SET_NAMESTRING();
+
+         /* Peek at the next symbol.  If it is also an N_SO, the
+            first one just indicates the directory.  */
+         if (symbuf_idx == symbuf_end)
+           fill_symbuf ();
+         bufp = &symbuf[symbuf_idx];
+         /* n_type is only a char, so swapping swapping is irrelevant.  */
+         if (bufp->n_type == (unsigned char)N_SO)
+           {
+             SWAP_SYMBOL (bufp);
+             SET_NAMESTRING ();
+             valu = bufp->n_value;
+             symbuf_idx++;
+             symnum++;
+           }
+         valu += addr;         /* Relocate */
+
+         if (pst && past_first_source_file)
+           {
+             end_psymtab (pst, psymtab_include_list, includes_used,
+                          first_symnum * sizeof (struct nlist), valu,
+                          dependency_list, dependencies_used,
+                          global_psymbols.next, static_psymbols.next);
+             pst = (struct partial_symtab *) 0;
+             includes_used = 0;
+             dependencies_used = 0;
+           }
+         else
+           past_first_source_file = 1;
+
+         pst = start_psymtab (symfile_name, addr,
+                              namestring, valu,
+                              first_symnum * sizeof (struct nlist),
+                              global_psymbols.next, static_psymbols.next);
+
+         continue;
+       }
+
+       case N_BINCL:
+         /* Add this bincl to the bincl_list for future EXCLs.  No
+            need to save the string; it'll be around until
+            read_dbx_symtab function returns */
+
+         SET_NAMESTRING();
+
+         add_bincl_to_list (pst, namestring, bufp->n_value);
+
+         /* Mark down an include file in the current psymtab */
+
+         psymtab_include_list[includes_used++] = namestring;
+         if (includes_used >= includes_allocated)
+           {
+             char **orig = psymtab_include_list;
+
+             psymtab_include_list = (char **)
+               alloca ((includes_allocated *= 2) *
+                       sizeof (char *));
+             bcopy (orig, psymtab_include_list,
+                    includes_used * sizeof (char *));
+           }
+
+         continue;
+
+       case N_SOL:
+         /* Mark down an include file in the current psymtab */
+
+         SET_NAMESTRING();
+
+         /* In C++, one may expect the same filename to come round many
+            times, when code is coming alternately from the main file
+            and from inline functions in other files. So I check to see
+            if this is a file we've seen before.
+
+            This seems to be a lot of time to be spending on N_SOL, but
+            things like "break expread.y:435" need to work (I
+            suppose the psymtab_include_list could be hashed or put
+            in a binary tree, if profiling shows this is a major hog).  */
+         {
+           register int i;
+           for (i = 0; i < includes_used; i++)
+             if (!strcmp (namestring, psymtab_include_list[i]))
+               {
+                 i = -1; 
+                 break;
+               }
+           if (i == -1)
+             continue;
+         }
+
+         psymtab_include_list[includes_used++] = namestring;
+         if (includes_used >= includes_allocated)
+           {
+             char **orig = psymtab_include_list;
+
+             psymtab_include_list = (char **)
+               alloca ((includes_allocated *= 2) *
+                       sizeof (char *));
+             bcopy (orig, psymtab_include_list,
+                    includes_used * sizeof (char *));
+           }
+         continue;
+
+       case N_LSYM:            /* Typedef or automatic variable. */
+         SET_NAMESTRING();
+
+         p = (char *) strchr (namestring, ':');
+
+         /* Skip if there is no :.  */
+         if (!p) continue;
+
+         switch (p[1])
+           {
+           case 'T':
+             ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+                                  STRUCT_NAMESPACE, LOC_TYPEDEF,
+                                  static_psymbols, bufp->n_value);
+             if (p[2] == 't')
+               {
+                 /* Also a typedef with the same name.  */
+                 ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+                                      VAR_NAMESPACE, LOC_TYPEDEF,
+                                      static_psymbols, bufp->n_value);
+                 p += 1;
+               }
+             goto check_enum;
+           case 't':
+             ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+                                  VAR_NAMESPACE, LOC_TYPEDEF,
+                                  static_psymbols, bufp->n_value);
+           check_enum:
+             /* If this is an enumerated type, we need to
+                add all the enum constants to the partial symbol
+                table.  This does not cover enums without names, e.g.
+                "enum {a, b} c;" in C, but fortunately those are
+                rare.  There is no way for GDB to find those from the
+                enum type without spending too much time on it.  Thus
+                to solve this problem, the compiler needs to put out separate
+                constant symbols ('c' N_LSYMS) for enum constants in
+                enums without names, or put out a dummy type.  */
+
+             /* We are looking for something of the form
+                <name> ":" ("t" | "T") [<number> "="] "e"
+                {<constant> ":" <value> ","} ";".  */
+
+             /* Skip over the colon and the 't' or 'T'.  */
+             p += 2;
+             /* This type may be given a number.  Skip over it.  */
+             while ((*p >= '0' && *p <= '9')
+                    || *p == '=')
+               p++;
+
+             if (*p++ == 'e')
+               {
+                 /* We have found an enumerated type.  */
+                 /* According to comments in read_enum_type
+                    a comma could end it instead of a semicolon.
+                    I don't know where that happens.
+                    Accept either.  */
+                 while (*p && *p != ';' && *p != ',')
+                   {
+                     char *q;
+
+                     /* Check for and handle cretinous dbx symbol name
+                        continuation!  */
+                     if (*p == '\\')
+                       p = next_symbol_text ();
+
+                     /* Point to the character after the name
+                        of the enum constant.  */
+                     for (q = p; *q && *q != ':'; q++)
+                       ;
+                     /* Note that the value doesn't matter for
+                        enum constants in psymtabs, just in symtabs.  */
+                     ADD_PSYMBOL_TO_LIST (p, q - p,
+                                          VAR_NAMESPACE, LOC_CONST,
+                                          static_psymbols, 0);
+                     /* Point past the name.  */
+                     p = q;
+                     /* Skip over the value.  */
+                     while (*p && *p != ',')
+                       p++;
+                     /* Advance past the comma.  */
+                     if (*p)
+                       p++;
+                   }
+               }
+
+             continue;
+           case 'c':
+             /* Constant, e.g. from "const" in Pascal.  */
+             ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+                                  VAR_NAMESPACE, LOC_CONST,
+                                  static_psymbols, bufp->n_value);
+             continue;
+           default:
+             /* Skip if the thing following the : is
+                not a letter (which indicates declaration of a local
+                variable, which we aren't interested in).  */
+             continue;
+           }
+
+       case N_FUN:
+       case N_GSYM:            /* Global (extern) variable; can be
+                                  data or bss (sigh).  */
+       case N_STSYM:           /* Data seg var -- static  */
+       case N_LCSYM:           /* BSS      "  */
+
+       case N_NBSTS:           /* Gould nobase.  */
+       case N_NBLCS:           /* symbols.  */
+
+       /* Following may probably be ignored; I'll leave them here
+          for now (until I do Pascal and Modula 2 extensions).  */
+
+       case N_PC:              /* I may or may not need this; I
+                                  suspect not.  */
+       case N_M2C:             /* I suspect that I can ignore this here. */
+       case N_SCOPE:           /* Same.   */
+
+         SET_NAMESTRING();
+
+         p = (char *) strchr (namestring, ':');
+         if (!p)
+           continue;           /* Not a debugging symbol.   */
+
+
+
+         /* Main processing section for debugging symbols which
+            the initial read through the symbol tables needs to worry
+            about.  If we reach this point, the symbol which we are
+            considering is definitely one we are interested in.
+            p must also contain the (valid) index into the namestring
+            which indicates the debugging type symbol.  */
+
+         switch (p[1])
+           {
+           case 'c':
+             ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+                                  VAR_NAMESPACE, LOC_CONST,
+                                  static_psymbols, bufp->n_value);
+             continue;
+           case 'S':
+             bufp->n_value += addr;            /* Relocate */
+             ADD_PSYMBOL_ADDR_TO_LIST (namestring, p - namestring,
+                                  VAR_NAMESPACE, LOC_STATIC,
+                                  static_psymbols, bufp->n_value);
+             continue;
+           case 'G':
+             bufp->n_value += addr;            /* Relocate */
+             ADD_PSYMBOL_ADDR_TO_LIST (namestring, p - namestring,
+                                  VAR_NAMESPACE, LOC_EXTERNAL,
+                                  global_psymbols, bufp->n_value);
+             continue;
+
+           case 't':
+             ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+                                  VAR_NAMESPACE, LOC_TYPEDEF,
+                                  global_psymbols, bufp->n_value);
+             continue;
+
+           case 'f':
+             ADD_PSYMBOL_TO_LIST (namestring, p - namestring,
+                                  VAR_NAMESPACE, LOC_BLOCK,
+                                  static_psymbols, bufp->n_value);
+             continue;
+
+             /* Two things show up here (hopefully); static symbols of
+                local scope (static used inside braces) or extensions
+                of structure symbols.  We can ignore both.  */
+           case 'V':
+           case '(':
+           case '0':
+           case '1':
+           case '2':
+           case '3':
+           case '4':
+           case '5':
+           case '6':
+           case '7':
+           case '8':
+           case '9':
+             /* Global functions are ignored here.  I'm not
+                sure what psymtab they go into (or just the misc
+                function vector).  */
+           case 'F':
+             continue;
+
+           default:
+             /* Unexpected symbol.  Ignore it; perhaps it is an extension
+                that we don't know about.
+
+                Someone says sun cc puts out symbols like
+                /foo/baz/maclib::/usr/local/bin/maclib,
+                which would get here with a symbol type of ':'.  */
+             continue;
+           }
+
+       case N_EXCL:
+
+         SET_NAMESTRING();
+
+         /* Find the corresponding bincl and mark that psymtab on the
+            psymtab dependency list */
+         {
+           struct partial_symtab *needed_pst =
+             find_corresponding_bincl_psymtab (namestring, bufp->n_value);
+
+           /* If this include file was defined earlier in this file,
+              leave it alone.  */
+           if (needed_pst == pst) continue;
+
+           if (needed_pst)
+             {
+               int i;
+               int found = 0;
+
+               for (i = 0; i < dependencies_used; i++)
+                 if (dependency_list[i] == needed_pst)
+                   {
+                     found = 1;
+                     break;
+                   }
+
+               /* If it's already in the list, skip the rest.  */
+               if (found) continue;
+
+               dependency_list[dependencies_used++] = needed_pst;
+               if (dependencies_used >= dependencies_allocated)
+                 {
+                   struct partial_symtab **orig = dependency_list;
+                   dependency_list =
+                     (struct partial_symtab **)
+                       alloca ((dependencies_allocated *= 2)
+                               * sizeof (struct partial_symtab *));
+                   bcopy (orig, dependency_list,
+                          (dependencies_used
+                           * sizeof (struct partial_symtab *)));
+#ifdef DEBUG_INFO
+                   fprintf (stderr, "Had to reallocate dependency list.\n");
+                   fprintf (stderr, "New dependencies allocated: %d\n",
+                            dependencies_allocated);
+#endif
+                 }
+             }
+           else
+             error ("Invalid symbol data: \"repeated\" header file not previously seen, at symtab pos %d.",
+                    symnum);
+         }
+         continue;
+
+       case N_EINCL:
+       case N_DSLINE:
+       case N_BSLINE:
+       case N_SSYM:            /* Claim: Structure or union element.
+                                  Hopefully, I can ignore this.  */
+       case N_ENTRY:           /* Alternate entry point; can ignore. */
+       case N_MAIN:            /* Can definitely ignore this.   */
+       case N_CATCH:           /* These are GNU C++ extensions */
+       case N_EHDECL:          /* that can safely be ignored here. */
+       case N_LENG:
+       case N_BCOMM:
+       case N_ECOMM:
+       case N_ECOML:
+       case N_FNAME:
+       case N_SLINE:
+       case N_RSYM:
+       case N_PSYM:
+       case N_LBRAC:
+       case N_RBRAC:
+       case N_NSYMS:           /* Ultrix 4.0: symbol count */
+         /* These symbols aren't interesting; don't worry about them */
+
+         continue;
+
+       default:
+         /* If we haven't found it yet, ignore it.  It's probably some
+            new type we don't know about yet.  */
+         complain (&unknown_symtype_complaint, bufp->n_type);
+         continue;
+       }
+    }
+
+  /* If there's stuff to be cleaned up, clean it up.  */
+  if (entry_point < bufp->n_value
+      && entry_point >= last_o_file_start)
+    {
+      startup_file_start = last_o_file_start;
+      startup_file_end = bufp->n_value;
+    }
+
+  if (pst)
+    {
+      end_psymtab (pst, psymtab_include_list, includes_used,
+                  symnum * sizeof (struct nlist), end_of_text_addr,
+                  dependency_list, dependencies_used,
+                  global_psymbols.next, static_psymbols.next);
+      includes_used = 0;
+      dependencies_used = 0;
+      pst = (struct partial_symtab *) 0;
+    }
+
+  free_bincl_list ();
+  discard_cleanups (old_chain);
+}
+
+/*
+ * Allocate and partially fill a partial symtab.  It will be
+ * completely filled at the end of the symbol list.
+
+ SYMFILE_NAME is the name of the symbol-file we are reading from, and ADDR
+ is the address relative to which its symbols are (incremental) or 0
+ (normal).  */
+static struct partial_symtab *
+start_psymtab (symfile_name, addr,
+              filename, textlow, ldsymoff, global_syms, static_syms)
+     char *symfile_name;
+     CORE_ADDR addr;
+     char *filename;
+     CORE_ADDR textlow;
+     int ldsymoff;
+     struct partial_symbol *global_syms;
+     struct partial_symbol *static_syms;
+{
+  struct partial_symtab *result =
+    (struct partial_symtab *) obstack_alloc (psymbol_obstack,
+                                            sizeof (struct partial_symtab));
+
+  result->addr = addr;
+
+  result->symfile_name =
+    (char *) obstack_alloc (psymbol_obstack,
+                           strlen (symfile_name) + 1);
+  strcpy (result->symfile_name, symfile_name);
+  
+  result->filename =
+    (char *) obstack_alloc (psymbol_obstack,
+                           strlen (filename) + 1);
+  strcpy (result->filename, filename);
+
+  result->textlow = textlow;
+  result->ldsymoff = ldsymoff;
+
+  result->readin = 0;
+  result->symtab = 0;
+  result->read_symtab = dbx_psymtab_to_symtab;
+
+  result->globals_offset = global_syms - global_psymbols.list;
+  result->statics_offset = static_syms - static_psymbols.list;
+
+  result->n_global_syms = 0;
+  result->n_static_syms = 0;
+
+
+  return result;
+}
+
+static int
+compare_psymbols (s1, s2)
+     register struct partial_symbol *s1, *s2;
+{
+  register char
+    *st1 = SYMBOL_NAME (s1),
+    *st2 = SYMBOL_NAME (s2);
+
+  return (st1[0] - st2[0] ? st1[0] - st2[0] :
+         strcmp (st1 + 1, st2 + 1));
+}
+
+
+/* Close off the current usage of a partial_symbol table entry.  This
+   involves setting the correct number of includes (with a realloc),
+   setting the high text mark, setting the symbol length in the
+   executable, and setting the length of the global and static lists
+   of psymbols.
+
+   The global symbols and static symbols are then seperately sorted.
+
+   Then the partial symtab is put on the global list.
+   *** List variables and peculiarities of same. ***
+   */
+static void
+end_psymtab (pst, include_list, num_includes, capping_symbol_offset,
+            capping_text, dependency_list, number_dependencies,
+            capping_global, capping_static)
+     struct partial_symtab *pst;
+     char **include_list;
+     int num_includes;
+     int capping_symbol_offset;
+     CORE_ADDR capping_text;
+     struct partial_symtab **dependency_list;
+     int number_dependencies;
+     struct partial_symbol *capping_global, *capping_static;
+{
+  int i;
+
+  pst->ldsymlen = capping_symbol_offset - pst->ldsymoff;
+  pst->texthigh = capping_text;
+
+  pst->n_global_syms =
+    capping_global - (global_psymbols.list + pst->globals_offset);
+  pst->n_static_syms =
+    capping_static - (static_psymbols.list + pst->statics_offset);
+
+  pst->number_of_dependencies = number_dependencies;
+  if (number_dependencies)
+    {
+      pst->dependencies = (struct partial_symtab **)
+       obstack_alloc (psymbol_obstack,
+                      number_dependencies * sizeof (struct partial_symtab *));
+      bcopy (dependency_list, pst->dependencies,
+            number_dependencies * sizeof (struct partial_symtab *));
+    }
+  else
+    pst->dependencies = 0;
+
+  for (i = 0; i < num_includes; i++)
+    {
+      /* Eventually, put this on obstack */
+      struct partial_symtab *subpst =
+       (struct partial_symtab *)
+         obstack_alloc (psymbol_obstack,
+                        sizeof (struct partial_symtab));
+
+      subpst->filename =
+       (char *) obstack_alloc (psymbol_obstack,
+                               strlen (include_list[i]) + 1);
+      strcpy (subpst->filename, include_list[i]);
+
+      subpst->symfile_name = pst->symfile_name;
+      subpst->addr = pst->addr;
+      subpst->ldsymoff =
+       subpst->ldsymlen =
+         subpst->textlow =
+           subpst->texthigh = 0;
+
+      subpst->dependencies = (struct partial_symtab **)
+       obstack_alloc (psymbol_obstack,
+                      sizeof (struct partial_symtab *));
+      subpst->dependencies[0] = pst;
+      subpst->number_of_dependencies = 1;
+
+      subpst->globals_offset =
+       subpst->n_global_syms =
+         subpst->statics_offset =
+           subpst->n_static_syms = 0;
+
+      subpst->readin = 0;
+      subpst->read_symtab = dbx_psymtab_to_symtab;
+
+      subpst->next = partial_symtab_list;
+      partial_symtab_list = subpst;
+    }
+
+  /* Sort the global list; don't sort the static list */
+  qsort (global_psymbols.list + pst->globals_offset, pst->n_global_syms,
+        sizeof (struct partial_symbol), compare_psymbols);
+
+  /* Put the psymtab on the psymtab list */
+  pst->next = partial_symtab_list;
+  partial_symtab_list = pst;
+}
+\f
+static void
+psymtab_to_symtab_1 (pst, desc, stringtab, stringtab_size, sym_offset)
+     struct partial_symtab *pst;
+     int desc;
+     char *stringtab;
+     int stringtab_size;
+     int sym_offset;
+{
+  struct cleanup *old_chain;
+  int i;
+  
+  if (!pst)
+    return;
+
+  if (pst->readin)
+    {
+      fprintf (stderr, "Psymtab for %s already read in.  Shouldn't happen.\n",
+              pst->filename);
+      return;
+    }
+
+  /* Read in all partial symbtabs on which this one is dependent */
+  for (i = 0; i < pst->number_of_dependencies; i++)
+    if (!pst->dependencies[i]->readin)
+      {
+       /* Inform about additional files that need to be read in.  */
+       if (info_verbose)
+         {
+           fputs_filtered (" ", stdout);
+           wrap_here ("");
+           fputs_filtered ("and ", stdout);
+           wrap_here ("");
+           printf_filtered ("%s...", pst->dependencies[i]->filename);
+           wrap_here ("");             /* Flush output */
+           fflush (stdout);
+         }
+       psymtab_to_symtab_1 (pst->dependencies[i], desc,
+                            stringtab, stringtab_size, sym_offset);
+      }
+
+  if (pst->ldsymlen)           /* Otherwise it's a dummy */
+    {
+      /* Init stuff necessary for reading in symbols */
+      free_pendings = 0;
+      pending_blocks = 0;
+      file_symbols = 0;
+      global_symbols = 0;
+      old_chain = make_cleanup (really_free_pendings, 0);
+
+      /* Read in this files symbols */
+      lseek (desc, sym_offset, L_SET);
+      read_ofile_symtab (desc, stringtab, stringtab_size,
+                        pst->ldsymoff,
+                        pst->ldsymlen, pst->textlow,
+                        pst->texthigh - pst->textlow, pst->addr);
+      sort_symtab_syms (symtab_list); /* At beginning since just added */
+
+      do_cleanups (old_chain);
+    }
+
+  pst->readin = 1;
+}
+
+/*
+ * Read in all of the symbols for a given psymtab for real.
+ * Be verbose about it if the user wants that.
+ */
+static void
+dbx_psymtab_to_symtab (pst)
+     struct partial_symtab *pst;
+{
+  int desc;
+  char *stringtab;
+  int stsize, val;
+  struct stat statbuf;
+  struct cleanup *old_chain;
+  bfd *sym_bfd;
+  long st_temp;
+
+  if (!pst)
+    return;
+
+  if (pst->readin)
+    {
+      fprintf (stderr, "Psymtab for %s already read in.  Shouldn't happen.\n",
+              pst->filename);
+      return;
+    }
+
+  if (pst->ldsymlen || pst->number_of_dependencies)
+    {
+      /* Print the message now, before reading the string table,
+        to avoid disconcerting pauses.  */
+      if (info_verbose)
+       {
+         printf_filtered ("Reading in symbols for %s...", pst->filename);
+         fflush (stdout);
+       }
+
+      /* Open symbol file and read in string table.  Symbol_file_command
+        guarantees that the symbol file name will be absolute, so there is
+        no need for openp.  */
+      desc = open(pst->symfile_name, O_RDONLY, 0);
+
+      if (desc < 0)
+       perror_with_name (pst->symfile_name);
+
+      sym_bfd = bfd_fdopenr (pst->symfile_name, NULL, desc);
+      if (!sym_bfd)
+       {
+         (void)close (desc);
+         error ("Could not open `%s' to read symbols: %s",
+                pst->symfile_name, bfd_errmsg (bfd_error));
+       }
+      old_chain = make_cleanup (bfd_close, sym_bfd);
+      if (!bfd_check_format (sym_bfd, bfd_object))
+         error ("\"%s\": can't read symbols: %s.",
+                pst->symfile_name, bfd_errmsg (bfd_error));
+
+      /* We keep the string table for symfile resident in memory, but
+        not the string table for any other symbol files.  */
+      if (0 != strcmp(pst->symfile_name, symfile))
+       {
+         /* Read in the string table */
+
+         /* FIXME, this uses internal BFD variables.  See above in
+            dbx_symbol_file_open where the macro is defined!  */
+         lseek (desc, STRING_TABLE_OFFSET, L_SET);
+
+         val = myread (desc, &st_temp, sizeof st_temp);
+         if (val < 0)
+             perror_with_name (pst->symfile_name);
+         stsize = bfd_h_getlong (sym_bfd, (unsigned char *)&st_temp);
+         if (fstat (desc, &statbuf) < 0)
+           perror_with_name (pst->symfile_name);
+         
+         if (stsize >= 0 && stsize < statbuf.st_size)
+           {
+#ifdef BROKEN_LARGE_ALLOCA
+             stringtab = (char *) xmalloc (stsize);
+             make_cleanup (free, stringtab);
+#else
+             stringtab = (char *) alloca (stsize);
+#endif
+           }
+         else
+           stringtab = NULL;
+         if (stringtab == NULL && stsize != 0)
+           error ("ridiculous string table size: %d bytes", stsize);
+
+         /* FIXME, this uses internal BFD variables.  See above in
+            dbx_symbol_file_open where the macro is defined!  */
+         val = lseek (desc, STRING_TABLE_OFFSET, L_SET);
+         if (val < 0)
+           perror_with_name (pst->symfile_name);
+         val = myread (desc, stringtab, stsize);
+         if (val < 0)
+           perror_with_name (pst->symfile_name);
+       }
+      else
+       {
+         stringtab = symfile_string_table;
+         stsize = symfile_string_table_size;
+       }
+
+      symfile_bfd = sym_bfd;           /* Kludge for SWAP_SYMBOL */
+
+      /* FIXME, this uses internal BFD variables.  See above in
+        dbx_symbol_file_open where the macro is defined!  */
+      psymtab_to_symtab_1 (pst, desc, stringtab, stsize,
+                          SYMBOL_TABLE_OFFSET);
+
+      /* Match with global symbols.  This only needs to be done once,
+         after all of the symtabs and dependencies have been read in.   */
+      scan_file_globals ();
+
+      do_cleanups (old_chain);
+
+      /* Finish up the debug error message.  */
+      if (info_verbose)
+       printf_filtered ("done.\n");
+    }
+}
+
+/*
+ * Scan through all of the global symbols defined in the object file,
+ * assigning values to the debugging symbols that need to be assigned
+ * to.  Get these symbols from the misc function list.
+ */
+static void
+scan_file_globals ()
+{
+  int hash;
+  int mf;
+
+  for (mf = 0; mf < misc_function_count; mf++)
+    {
+      char *namestring = misc_function_vector[mf].name;
+      struct symbol *sym, *prev;
+
+      QUIT;
+
+      prev = (struct symbol *) 0;
+
+      /* Get the hash index and check all the symbols
+        under that hash index. */
+
+      hash = hashname (namestring);
+
+      for (sym = global_sym_chain[hash]; sym;)
+       {
+         if (*namestring == SYMBOL_NAME (sym)[0]
+             && !strcmp(namestring + 1, SYMBOL_NAME (sym) + 1))
+           {
+             /* Splice this symbol out of the hash chain and
+                assign the value we have to it. */
+             if (prev)
+               SYMBOL_VALUE_CHAIN (prev) = SYMBOL_VALUE_CHAIN (sym);
+             else
+               global_sym_chain[hash] = SYMBOL_VALUE_CHAIN (sym);
+             
+             /* Check to see whether we need to fix up a common block.  */
+             /* Note: this code might be executed several times for
+                the same symbol if there are multiple references.  */
+             if (SYMBOL_CLASS (sym) == LOC_BLOCK)
+               fix_common_block (sym, misc_function_vector[mf].address);
+             else
+               SYMBOL_VALUE_ADDRESS (sym) = misc_function_vector[mf].address;
+             
+             if (prev)
+               sym = SYMBOL_VALUE_CHAIN (prev);
+             else
+               sym = global_sym_chain[hash];
+           }
+         else
+           {
+             prev = sym;
+             sym = SYMBOL_VALUE_CHAIN (sym);
+           }
+       }
+    }
+}
+
+/* Process a pair of symbols.  Currently they must both be N_SO's.  */
+static void
+process_symbol_pair (type1, desc1, value1, name1,
+                    type2, desc2, value2, name2)
+     int type1;
+     int desc1;
+     CORE_ADDR value1;
+     char *name1;
+     int type2;
+     int desc2;
+     CORE_ADDR value2;
+     char *name2;
+{
+  /* No need to check PCC_SOL_BROKEN, on the assumption that such
+     broken PCC's don't put out N_SO pairs.  */
+  if (last_source_file)
+    end_symtab (value2);
+  start_symtab (name2, name1, value2);
+}
+
+/*
+ * Read in a defined section of a specific object file's symbols.
+ *
+ * DESC is the file descriptor for the file, positioned at the
+ * beginning of the symtab
+ * STRINGTAB is a pointer to the files string
+ * table, already read in
+ * SYM_OFFSET is the offset within the file of
+ * the beginning of the symbols we want to read, NUM_SUMBOLS is the
+ * number of symbols to read
+ * TEXT_OFFSET is the beginning of the text segment we are reading symbols for
+ * TEXT_SIZE is the size of the text segment read in.
+ * OFFSET is a relocation offset which gets added to each symbol
+ */
+
+static void
+read_ofile_symtab (desc, stringtab, stringtab_size, sym_offset,
+                  sym_size, text_offset, text_size, offset)
+     int desc;
+     register char *stringtab;
+     unsigned int stringtab_size;
+     int sym_offset;
+     int sym_size;
+     CORE_ADDR text_offset;
+     int text_size;
+     int offset;
+{
+  register char *namestring;
+  struct nlist *bufp;
+  unsigned char type;
+  subfile_stack = 0;
+
+  stringtab_global = stringtab;
+  last_source_file = 0;
+
+  symtab_input_desc = desc;
+  symbuf_end = symbuf_idx = 0;
+
+  /* It is necessary to actually read one symbol *before* the start
+     of this symtab's symbols, because the GCC_COMPILED_FLAG_SYMBOL
+     occurs before the N_SO symbol.
+
+     Detecting this in read_dbx_symtab
+     would slow down initial readin, so we look for it here instead.  */
+  if (sym_offset >= (int)sizeof (struct nlist))
+    {
+      lseek (desc, sym_offset - sizeof (struct nlist), L_INCR);
+      fill_symbuf ();
+      bufp = &symbuf[symbuf_idx++];
+      SWAP_SYMBOL (bufp);
+
+      if (bufp->n_un.n_strx < 0 || bufp->n_un.n_strx >= stringtab_size)
+       error ("Invalid symbol data: bad string table offset: %d",
+              bufp->n_un.n_strx);
+      namestring = bufp->n_un.n_strx + stringtab;
+
+      processing_gcc_compilation =
+       (bufp->n_type == N_TEXT
+        && !strcmp (namestring, GCC_COMPILED_FLAG_SYMBOL));
+    }
+  else
+    {
+      /* The N_SO starting this symtab is the first symbol, so we
+        better not check the symbol before it.  I'm not this can
+        happen, but it doesn't hurt to check for it.  */
+      lseek(desc, sym_offset, L_INCR);
+      processing_gcc_compilation = 0;
+    }
+
+  if (symbuf_idx == symbuf_end)
+    fill_symbuf();
+  bufp = &symbuf[symbuf_idx];
+  if (bufp->n_type != (unsigned char)N_SO)
+    error("First symbol in segment of executable not a source symbol");
+
+  for (symnum = 0;
+       symnum < sym_size / sizeof(struct nlist);
+       symnum++)
+    {
+      QUIT;                    /* Allow this to be interruptable */
+      if (symbuf_idx == symbuf_end)
+       fill_symbuf();
+      bufp = &symbuf[symbuf_idx++];
+      SWAP_SYMBOL (bufp);
+
+      type = bufp->n_type & N_TYPE;
+      if (type == (unsigned char)N_CATCH)
+       {
+         /* N_CATCH is not fixed up by the linker, and unfortunately,
+            there's no other place to put it in the .stab map.  */
+         /* FIXME, do we also have to add OFFSET or something? -- gnu@cygnus */
+         bufp->n_value += text_offset;
+       }
+      else if (type == N_TEXT || type == N_DATA || type == N_BSS)
+       bufp->n_value += offset;
+
+      type = bufp->n_type;
+      if (bufp->n_un.n_strx < 0 || bufp->n_un.n_strx >= stringtab_size)
+       error ("Invalid symbol data: bad string table offset: %d",
+              bufp->n_un.n_strx);
+      namestring = bufp->n_un.n_strx + stringtab;
+
+      if (type & N_STAB)
+       {
+         short desc = bufp->n_desc;
+         unsigned long valu = bufp->n_value;
+
+         /* Check for a pair of N_SO symbols.  */
+         if (type == (unsigned char)N_SO)
+           {
+             if (symbuf_idx == symbuf_end)
+               fill_symbuf ();
+             bufp = &symbuf[symbuf_idx];
+             if (bufp->n_type == (unsigned char)N_SO)
+               {
+                 char *namestring2;
+
+                 SWAP_SYMBOL (bufp);
+                 bufp->n_value += offset;              /* Relocate */
+                 symbuf_idx++;
+                 symnum++;
+
+                 if (bufp->n_un.n_strx < 0
+                     || bufp->n_un.n_strx >= stringtab_size)
+                   error ("Invalid symbol data: bad string table offset: %d",
+                          bufp->n_un.n_strx);
+                 namestring2 = bufp->n_un.n_strx + stringtab;
+
+                 process_symbol_pair (N_SO, desc, valu, namestring,
+                                      N_SO, bufp->n_desc, bufp->n_value,
+                                      namestring2);
+               }
+             else
+               process_one_symbol(type, desc, valu, namestring);
+           }
+         else
+           process_one_symbol (type, desc, valu, namestring);
+       }
+      /* We skip checking for a new .o or -l file; that should never
+         happen in this routine. */
+      else if (type == N_TEXT
+              && !strcmp (namestring, GCC_COMPILED_FLAG_SYMBOL))
+       /* I don't think this code will ever be executed, because
+          the GCC_COMPILED_FLAG_SYMBOL usually is right before
+          the N_SO symbol which starts this source file.
+          However, there is no reason not to accept
+          the GCC_COMPILED_FLAG_SYMBOL anywhere.  */
+       processing_gcc_compilation = 1;
+      else if (type & N_EXT || type == (unsigned char)N_TEXT
+              || type == (unsigned char)N_NBTEXT
+              )
+         /* Global symbol: see if we came across a dbx defintion for
+            a corresponding symbol.  If so, store the value.  Remove
+            syms from the chain when their values are stored, but
+            search the whole chain, as there may be several syms from
+            different files with the same name. */
+         /* This is probably not true.  Since the files will be read
+            in one at a time, each reference to a global symbol will
+            be satisfied in each file as it appears. So we skip this
+            section. */
+         ;
+    }
+  end_symtab (text_offset + text_size);
+}
+\f
+static int
+hashname (name)
+     char *name;
+{
+  register char *p = name;
+  register int total = p[0];
+  register int c;
+
+  c = p[1];
+  total += c << 2;
+  if (c)
+    {
+      c = p[2];
+      total += c << 4;
+      if (c)
+       total += p[3] << 6;
+    }
+
+  /* Ensure result is positive.  */
+  if (total < 0) total += (1000 << 6);
+  return total % HASHSIZE;
+}
+
+\f
+static void
+process_one_symbol (type, desc, valu, name)
+     int type, desc;
+     CORE_ADDR valu;
+     char *name;
+{
+#ifndef SUN_FIXED_LBRAC_BUG
+  /* This records the last pc address we've seen.  We depend on their being
+     an SLINE or FUN or SO before the first LBRAC, since the variable does
+     not get reset in between reads of different symbol files.  */
+  static CORE_ADDR last_pc_address;
+#endif
+  register struct context_stack *new;
+  char *colon_pos;
+
+  /* Something is wrong if we see real data before
+     seeing a source file name.  */
+
+  if (last_source_file == 0 && type != (unsigned char)N_SO)
+    {
+      /* Currently this ignores N_ENTRY on Gould machines, N_NSYM on machines
+        where that code is defined.  */
+      if (IGNORE_SYMBOL (type))
+       return;
+
+      /* FIXME, this should not be an error, since it precludes extending
+         the symbol table information in this way...  */
+      error ("Invalid symbol data: does not start by identifying a source file.");
+    }
+
+  switch (type)
+    {
+    case N_FUN:
+    case N_FNAME:
+      /* Either of these types of symbols indicates the start of
+        a new function.  We must process its "name" normally for dbx,
+        but also record the start of a new lexical context, and possibly
+        also the end of the lexical context for the previous function.  */
+      /* This is not always true.  This type of symbol may indicate a
+         text segment variable.  */
+
+#ifndef SUN_FIXED_LBRAC_BUG
+      last_pc_address = valu;  /* Save for SunOS bug circumcision */
+#endif
+
+      colon_pos = strchr (name, ':');
+      if (!colon_pos++
+         || (*colon_pos != 'f' && *colon_pos != 'F'))
+       {
+         define_symbol (valu, name, desc, type);
+         break;
+       }
+
+      within_function = 1;
+      if (context_stack_depth > 0)
+       {
+         new = &context_stack[--context_stack_depth];
+         /* Make a block for the local symbols within.  */
+         finish_block (new->name, &local_symbols, new->old_blocks,
+                       new->start_addr, valu);
+       }
+      /* Stack must be empty now.  */
+      if (context_stack_depth != 0)
+       error ("Invalid symbol data: unmatched N_LBRAC before symtab pos %d.",
+              symnum);
+
+      new = &context_stack[context_stack_depth++];
+      new->old_blocks = pending_blocks;
+      new->start_addr = valu;
+      new->name = define_symbol (valu, name, desc, type);
+      local_symbols = 0;
+      break;
+
+    case N_CATCH:
+      /* Record the address at which this catch takes place.  */
+      define_symbol (valu, name, desc, type);
+      break;
+
+    case N_EHDECL:
+      /* Don't know what to do with these yet.  */
+      error ("action uncertain for eh extensions");
+      break;
+
+    case N_LBRAC:
+      /* This "symbol" just indicates the start of an inner lexical
+        context within a function.  */
+
+#if !defined (BLOCK_ADDRESS_ABSOLUTE)
+      /* On most machines, the block addresses are relative to the
+        N_SO, the linker did not relocate them (sigh).  */
+      valu += last_source_start_addr;
+#endif
+
+#ifndef SUN_FIXED_LBRAC_BUG
+      if (valu < last_pc_address) {
+       /* Patch current LBRAC pc value to match last handy pc value */
+       complain (&lbrac_complaint, 0);
+       valu = last_pc_address;
+      }
+#endif
+      if (context_stack_depth == context_stack_size)
+       {
+         context_stack_size *= 2;
+         context_stack = (struct context_stack *)
+           xrealloc (context_stack,
+                     (context_stack_size
+                      * sizeof (struct context_stack)));
+       }
+
+      new = &context_stack[context_stack_depth++];
+      new->depth = desc;
+      new->locals = local_symbols;
+      new->old_blocks = pending_blocks;
+      new->start_addr = valu;
+      new->name = 0;
+      local_symbols = 0;
+      break;
+
+    case N_RBRAC:
+      /* This "symbol" just indicates the end of an inner lexical
+        context that was started with N_LBRAC.  */
+
+#if !defined (BLOCK_ADDRESS_ABSOLUTE)
+      /* On most machines, the block addresses are relative to the
+        N_SO, the linker did not relocate them (sigh).  */
+      valu += last_source_start_addr;
+#endif
+
+      new = &context_stack[--context_stack_depth];
+      if (desc != new->depth)
+       error ("Invalid symbol data: N_LBRAC/N_RBRAC symbol mismatch, symtab pos %d.", symnum);
+
+      /* Some compilers put the variable decls inside of an
+         LBRAC/RBRAC block.  This macro should be nonzero if this
+        is true.  DESC is N_DESC from the N_RBRAC symbol.
+        GCC_P is true if we've detected the GCC_COMPILED_SYMBOL.  */
+#if !defined (VARIABLES_INSIDE_BLOCK)
+#define VARIABLES_INSIDE_BLOCK(desc, gcc_p) 0
+#endif
+
+      /* Can only use new->locals as local symbols here if we're in
+         gcc or on a machine that puts them before the lbrack.  */
+      if (!VARIABLES_INSIDE_BLOCK(desc, processing_gcc_compilation))
+       local_symbols = new->locals;
+
+      /* If this is not the outermost LBRAC...RBRAC pair in the
+        function, its local symbols preceded it, and are the ones
+        just recovered from the context stack.  Defined the block for them.
+
+        If this is the outermost LBRAC...RBRAC pair, there is no
+        need to do anything; leave the symbols that preceded it
+        to be attached to the function's own block.  However, if
+        it is so, we need to indicate that we just moved outside
+        of the function.  */
+      if (local_symbols
+         && (context_stack_depth
+             > !VARIABLES_INSIDE_BLOCK(desc, processing_gcc_compilation)))
+       {
+         /* FIXME Muzzle a compiler bug that makes end < start.  */
+         if (new->start_addr > valu)
+           {
+             complain(&lbrac_rbrac_complaint, 0);
+             new->start_addr = valu;
+           }
+         /* Make a block for the local symbols within.  */
+         finish_block (0, &local_symbols, new->old_blocks,
+                       new->start_addr, valu);
+       }
+      else
+       {
+         within_function = 0;
+       }
+      if (VARIABLES_INSIDE_BLOCK(desc, processing_gcc_compilation))
+       /* Now pop locals of block just finished.  */
+       local_symbols = new->locals;
+      break;
+
+    case N_FN | N_EXT:
+      /* This kind of symbol supposedly indicates the start
+        of an object file.  In fact this type does not appear.  */
+      break;
+
+    case N_SO:
+      /* This type of symbol indicates the start of data
+        for one source file.
+        Finish the symbol table of the previous source file
+        (if any) and start accumulating a new symbol table.  */
+#ifndef SUN_FIXED_LBRAC_BUG
+      last_pc_address = valu;  /* Save for SunOS bug circumcision */
+#endif
+  
+#ifdef PCC_SOL_BROKEN
+      /* pcc bug, occasionally puts out SO for SOL.  */
+      if (context_stack_depth > 0)
+       {
+         start_subfile (name, NULL);
+         break;
+       }
+#endif
+      if (last_source_file)
+       end_symtab (valu);
+      start_symtab (name, NULL, valu);
+      break;
+
+    case N_SOL:
+      /* This type of symbol indicates the start of data for
+        a sub-source-file, one whose contents were copied or
+        included in the compilation of the main source file
+        (whose name was given in the N_SO symbol.)  */
+      start_subfile (name, NULL);
+      break;
+
+    case N_BINCL:
+      push_subfile ();
+      add_new_header_file (name, valu);
+      start_subfile (name, NULL);
+      break;
+
+    case N_EINCL:
+      start_subfile (pop_subfile (), NULL);
+      break;
+
+    case N_EXCL:
+      add_old_header_file (name, valu);
+      break;
+
+    case N_SLINE:
+      /* This type of "symbol" really just records
+        one line-number -- core-address correspondence.
+        Enter it in the line list for this symbol table.  */
+#ifndef SUN_FIXED_LBRAC_BUG
+      last_pc_address = valu;  /* Save for SunOS bug circumcision */
+#endif
+      record_line (desc, valu);
+      break;
+
+    case N_BCOMM:
+      if (common_block)
+       error ("Invalid symbol data: common within common at symtab pos %d",
+              symnum);
+      common_block = local_symbols;
+      common_block_i = local_symbols ? local_symbols->nsyms : 0;
+      break;
+
+    case N_ECOMM:
+      /* Symbols declared since the BCOMM are to have the common block
+        start address added in when we know it.  common_block points to
+        the first symbol after the BCOMM in the local_symbols list;
+        copy the list and hang it off the symbol for the common block name
+        for later fixup.  */
+      {
+       int i;
+       struct symbol *sym =
+         (struct symbol *) xmalloc (sizeof (struct symbol));
+       bzero (sym, sizeof *sym);
+       SYMBOL_NAME (sym) = savestring (name, strlen (name));
+       SYMBOL_CLASS (sym) = LOC_BLOCK;
+       SYMBOL_NAMESPACE (sym) = (enum namespace)((long)
+         copy_pending (local_symbols, common_block_i, common_block));
+       i = hashname (SYMBOL_NAME (sym));
+       SYMBOL_VALUE_CHAIN (sym) = global_sym_chain[i];
+       global_sym_chain[i] = sym;
+       common_block = 0;
+       break;
+      }
+
+    case N_ECOML:
+    case N_LENG:
+      break;
+
+    default:
+      if (name)
+       define_symbol (valu, name, desc, type);
+    }
+}
+\f
+/* Read a number by which a type is referred to in dbx data,
+   or perhaps read a pair (FILENUM, TYPENUM) in parentheses.
+   Just a single number N is equivalent to (0,N).
+   Return the two numbers by storing them in the vector TYPENUMS.
+   TYPENUMS will then be used as an argument to dbx_lookup_type.  */
+
+static void
+read_type_number (pp, typenums)
+     register char **pp;
+     register int *typenums;
+{
+  if (**pp == '(')
+    {
+      (*pp)++;
+      typenums[0] = read_number (pp, ',');
+      typenums[1] = read_number (pp, ')');
+    }
+  else
+    {
+      typenums[0] = 0;
+      typenums[1] = read_number (pp, 0);
+    }
+}
+\f
+/* To handle GNU C++ typename abbreviation, we need to be able to
+   fill in a type's name as soon as space for that type is allocated.
+   `type_synonym_name' is the name of the type being allocated.
+   It is cleared as soon as it is used (lest all allocated types
+   get this name).  */
+static char *type_synonym_name;
+
+static struct symbol *
+define_symbol (valu, string, desc, type)
+     unsigned int valu;
+     char *string;
+     int desc;
+     int type;
+{
+  register struct symbol *sym;
+  char *p = (char *) strchr (string, ':');
+  int deftype;
+  int synonym = 0;
+  register int i;
+
+  /* Ignore syms with empty names.  */
+  if (string[0] == 0)
+    return 0;
+
+  /* Ignore old-style symbols from cc -go  */
+  if (p == 0)
+    return 0;
+
+  sym = (struct symbol *)obstack_alloc (symbol_obstack, sizeof (struct symbol));
+
+  if (processing_gcc_compilation) {
+    /* GCC 2.x puts the line number in desc.  SunOS apparently puts in the
+       number of bytes occupied by a type or object, which we ignore.  */
+    SYMBOL_LINE(sym) = desc;
+  } else {
+    SYMBOL_LINE(sym) = 0;                      /* unknown */
+  }
+  
+  if (string[0] == CPLUS_MARKER)
+    {
+      /* Special GNU C++ names.  */
+      switch (string[1])
+       {
+       case 't':
+         SYMBOL_NAME (sym) = "this";
+         break;
+       case 'v': /* $vtbl_ptr_type */
+         /* Was: SYMBOL_NAME (sym) = "vptr"; */
+         goto normal;
+       case 'e':
+         SYMBOL_NAME (sym) = "eh_throw";
+         break;
+
+       case '_':
+         /* This was an anonymous type that was never fixed up.  */
+         goto normal;
+
+       default:
+         abort ();
+       }
+    }
+  else
+    {
+    normal:
+      SYMBOL_NAME (sym)
+       = (char *) obstack_alloc (symbol_obstack, ((p - string) + 1));
+      /* Open-coded bcopy--saves function call time.  */
+      {
+       register char *p1 = string;
+       register char *p2 = SYMBOL_NAME (sym);
+       while (p1 != p)
+         *p2++ = *p1++;
+       *p2++ = '\0';
+      }
+    }
+  p++;
+  /* Determine the type of name being defined.  */
+  /* The Acorn RISC machine's compiler can put out locals that don't
+     start with "234=" or "(3,4)=", so assume anything other than the
+     deftypes we know how to handle is a local.  */
+  /* (Peter Watkins @ Computervision)
+     Handle Sun-style local fortran array types 'ar...' . 
+     (gnu@cygnus.com) -- this strchr() handles them properly?
+     (tiemann@cygnus.com) -- 'C' is for catch.  */
+  if (!strchr ("cfFGpPrStTvVXC", *p))
+    deftype = 'l';
+  else
+    deftype = *p++;
+
+  /* c is a special case, not followed by a type-number.
+     SYMBOL:c=iVALUE for an integer constant symbol.
+     SYMBOL:c=rVALUE for a floating constant symbol.
+     SYMBOL:c=eTYPE,INTVALUE for an enum constant symbol.
+        e.g. "b:c=e6,0" for "const b = blob1"
+       (where type 6 is defined by "blobs:t6=eblob1:0,blob2:1,;").  */
+  if (deftype == 'c')
+    {
+      if (*p++ != '=')
+       error ("Invalid symbol data at symtab pos %d.", symnum);
+      switch (*p++)
+       {
+       case 'r':
+         {
+           double d = atof (p);
+           char *valu;
+
+           SYMBOL_TYPE (sym) = builtin_type_double;
+           valu = (char *) obstack_alloc (symbol_obstack, sizeof (double));
+           bcopy (&d, valu, sizeof (double));
+           SWAP_TARGET_AND_HOST (valu, sizeof (double));
+           SYMBOL_VALUE_BYTES (sym) = valu;
+           SYMBOL_CLASS (sym) = LOC_CONST_BYTES;
+         }
+         break;
+       case 'i':
+         {
+           SYMBOL_TYPE (sym) = builtin_type_int;
+           SYMBOL_VALUE (sym) = atoi (p);
+           SYMBOL_CLASS (sym) = LOC_CONST;
+         }
+         break;
+       case 'e':
+         /* SYMBOL:c=eTYPE,INTVALUE for an enum constant symbol.
+            e.g. "b:c=e6,0" for "const b = blob1"
+            (where type 6 is defined by "blobs:t6=eblob1:0,blob2:1,;").  */
+         {
+           int typenums[2];
+           
+           read_type_number (&p, typenums);
+           if (*p++ != ',')
+             error ("Invalid symbol data: no comma in enum const symbol");
+           
+           SYMBOL_TYPE (sym) = *dbx_lookup_type (typenums);
+           SYMBOL_VALUE (sym) = atoi (p);
+           SYMBOL_CLASS (sym) = LOC_CONST;
+         }
+         break;
+       default:
+         error ("Invalid symbol data at symtab pos %d.", symnum);
+       }
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      add_symbol_to_list (sym, &file_symbols);
+      return sym;
+    }
+
+  /* Now usually comes a number that says which data type,
+     and possibly more stuff to define the type
+     (all of which is handled by read_type)  */
+
+  if (deftype == 'p' && *p == 'F')
+    /* pF is a two-letter code that means a function parameter in Fortran.
+       The type-number specifies the type of the return value.
+       Translate it into a pointer-to-function type.  */
+    {
+      p++;
+      SYMBOL_TYPE (sym)
+       = lookup_pointer_type (lookup_function_type (read_type (&p)));
+    }
+  else
+    {
+      struct type *type;
+      synonym = *p == 't';
+
+      if (synonym)
+       {
+         p += 1;
+         type_synonym_name = obsavestring (SYMBOL_NAME (sym),
+                                           strlen (SYMBOL_NAME (sym)));
+       }
+
+      type = read_type (&p);
+
+      if ((deftype == 'F' || deftype == 'f')
+         && TYPE_CODE (type) != TYPE_CODE_FUNC)
+       SYMBOL_TYPE (sym) = lookup_function_type (type);
+      else
+       SYMBOL_TYPE (sym) = type;
+    }
+
+  switch (deftype)
+    {
+    case 'C':
+      /* The name of a caught exception.  */
+      SYMBOL_CLASS (sym) = LOC_LABEL;
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      SYMBOL_VALUE_ADDRESS (sym) = valu;
+      add_symbol_to_list (sym, &local_symbols);
+      break;
+
+    case 'f':
+      SYMBOL_CLASS (sym) = LOC_BLOCK;
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      add_symbol_to_list (sym, &file_symbols);
+      break;
+
+    case 'F':
+      SYMBOL_CLASS (sym) = LOC_BLOCK;
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      add_symbol_to_list (sym, &global_symbols);
+      break;
+
+    case 'G':
+      /* For a class G (global) symbol, it appears that the
+        value is not correct.  It is necessary to search for the
+        corresponding linker definition to find the value.
+        These definitions appear at the end of the namelist.  */
+      i = hashname (SYMBOL_NAME (sym));
+      SYMBOL_VALUE_CHAIN (sym) = global_sym_chain[i];
+      global_sym_chain[i] = sym;
+      SYMBOL_CLASS (sym) = LOC_STATIC;
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      add_symbol_to_list (sym, &global_symbols);
+      break;
+
+      /* This case is faked by a conditional above,
+        when there is no code letter in the dbx data.
+        Dbx data never actually contains 'l'.  */
+    case 'l':
+      SYMBOL_CLASS (sym) = LOC_LOCAL;
+      SYMBOL_VALUE (sym) = valu;
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      add_symbol_to_list (sym, &local_symbols);
+      break;
+
+    case 'p':
+      /* Normally this is a parameter, a LOC_ARG.  On the i960, it
+        can also be a LOC_LOCAL_ARG depending on symbol type.  */
+#ifndef DBX_PARM_SYMBOL_CLASS
+#define        DBX_PARM_SYMBOL_CLASS(type)     LOC_ARG
+#endif
+      SYMBOL_CLASS (sym) = DBX_PARM_SYMBOL_CLASS (type);
+      SYMBOL_VALUE (sym) = valu;
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      add_symbol_to_list (sym, &local_symbols);
+
+      /* If it's gcc-compiled, if it says `short', believe it.  */
+      if (processing_gcc_compilation || BELIEVE_PCC_PROMOTION)
+       break;
+
+#if defined(BELIEVE_PCC_PROMOTION_TYPE)
+      /* This macro is defined on machines (e.g. sparc) where
+        we should believe the type of a PCC 'short' argument,
+        but shouldn't believe the address (the address is
+        the address of the corresponding int).  Note that
+        this is only different from the BELIEVE_PCC_PROMOTION
+        case on big-endian machines.
+
+        My guess is that this correction, as opposed to changing
+        the parameter to an 'int' (as done below, for PCC
+        on most machines), is the right thing to do
+        on all machines, but I don't want to risk breaking
+        something that already works.  On most PCC machines,
+        the sparc problem doesn't come up because the calling
+        function has to zero the top bytes (not knowing whether
+        the called function wants an int or a short), so there
+        is no practical difference between an int and a short
+        (except perhaps what happens when the GDB user types
+        "print short_arg = 0x10000;"). 
+
+        Hacked for SunOS 4.1 by gnu@cygnus.com.  In 4.1, the compiler
+        actually produces the correct address (we don't need to fix it
+        up).  I made this code adapt so that it will offset the symbol
+        if it was pointing at an int-aligned location and not
+        otherwise.  This way you can use the same gdb for 4.0.x and
+        4.1 systems.  */
+
+      if (0 == SYMBOL_VALUE (sym) % sizeof (int))
+       {
+         if (SYMBOL_TYPE (sym) == builtin_type_char
+             || SYMBOL_TYPE (sym) == builtin_type_unsigned_char)
+           SYMBOL_VALUE (sym) += 3;
+         else if (SYMBOL_TYPE (sym) == builtin_type_short
+             || SYMBOL_TYPE (sym) == builtin_type_unsigned_short)
+           SYMBOL_VALUE (sym) += 2;
+       }
+      break;
+
+#else /* no BELIEVE_PCC_PROMOTION_TYPE.  */
+
+      /* If PCC says a parameter is a short or a char,
+        it is really an int.  */
+      if (SYMBOL_TYPE (sym) == builtin_type_char
+         || SYMBOL_TYPE (sym) == builtin_type_short)
+       SYMBOL_TYPE (sym) = builtin_type_int;
+      else if (SYMBOL_TYPE (sym) == builtin_type_unsigned_char
+              || SYMBOL_TYPE (sym) == builtin_type_unsigned_short)
+       SYMBOL_TYPE (sym) = builtin_type_unsigned_int;
+      break;
+
+#endif /* no BELIEVE_PCC_PROMOTION_TYPE.  */
+
+    case 'P':
+      SYMBOL_CLASS (sym) = LOC_REGPARM;
+      SYMBOL_VALUE (sym) = STAB_REG_TO_REGNUM (valu);
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      add_symbol_to_list (sym, &local_symbols);
+      break;
+
+    case 'r':
+      SYMBOL_CLASS (sym) = LOC_REGISTER;
+      SYMBOL_VALUE (sym) = STAB_REG_TO_REGNUM (valu);
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      add_symbol_to_list (sym, &local_symbols);
+      break;
+
+    case 'S':
+      /* Static symbol at top level of file */
+      SYMBOL_CLASS (sym) = LOC_STATIC;
+      SYMBOL_VALUE_ADDRESS (sym) = valu;
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      add_symbol_to_list (sym, &file_symbols);
+      break;
+
+    case 't':
+      SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+      SYMBOL_VALUE (sym) = valu;
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      if (TYPE_NAME (SYMBOL_TYPE (sym)) == 0
+         && (TYPE_FLAGS (SYMBOL_TYPE (sym)) & TYPE_FLAG_PERM) == 0)
+       TYPE_NAME (SYMBOL_TYPE (sym)) =
+         obsavestring (SYMBOL_NAME (sym),
+                       strlen (SYMBOL_NAME (sym)));
+       /* C++ vagaries: we may have a type which is derived from
+        a base type which did not have its name defined when the
+        derived class was output.  We fill in the derived class's
+        base part member's name here in that case.  */
+       else if ((TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_STRUCT
+                || TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_UNION)
+               && TYPE_N_BASECLASSES (SYMBOL_TYPE (sym)))
+        {
+          int i;
+          for (i = TYPE_N_BASECLASSES (SYMBOL_TYPE (sym)) - 1; i >= 0; i--)
+            if (TYPE_BASECLASS_NAME (SYMBOL_TYPE (sym), i) == 0)
+              TYPE_BASECLASS_NAME (SYMBOL_TYPE (sym), i) =
+                type_name_no_tag (TYPE_BASECLASS (SYMBOL_TYPE (sym), i));
+        }
+
+      add_symbol_to_list (sym, &file_symbols);
+      break;
+
+    case 'T':
+      SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+      SYMBOL_VALUE (sym) = valu;
+      SYMBOL_NAMESPACE (sym) = STRUCT_NAMESPACE;
+      if (TYPE_NAME (SYMBOL_TYPE (sym)) == 0
+         && (TYPE_FLAGS (SYMBOL_TYPE (sym)) & TYPE_FLAG_PERM) == 0)
+       TYPE_NAME (SYMBOL_TYPE (sym))
+         = obconcat ("",
+                     (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_ENUM
+                      ? "enum "
+                      : (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_STRUCT
+                         ? "struct " : "union ")),
+                     SYMBOL_NAME (sym));
+      add_symbol_to_list (sym, &file_symbols);
+
+      if (synonym)
+       {
+         register struct symbol *typedef_sym
+           = (struct symbol *) obstack_alloc (symbol_obstack, sizeof (struct symbol));
+         SYMBOL_NAME (typedef_sym) = SYMBOL_NAME (sym);
+         SYMBOL_TYPE (typedef_sym) = SYMBOL_TYPE (sym);
+
+         SYMBOL_CLASS (typedef_sym) = LOC_TYPEDEF;
+         SYMBOL_VALUE (typedef_sym) = valu;
+         SYMBOL_NAMESPACE (typedef_sym) = VAR_NAMESPACE;
+         add_symbol_to_list (typedef_sym, &file_symbols);
+       }
+      break;
+
+    case 'V':
+      /* Static symbol of local scope */
+      SYMBOL_CLASS (sym) = LOC_STATIC;
+      SYMBOL_VALUE_ADDRESS (sym) = valu;
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      add_symbol_to_list (sym, &local_symbols);
+      break;
+
+    case 'v':
+      /* Reference parameter */
+      SYMBOL_CLASS (sym) = LOC_REF_ARG;
+      SYMBOL_VALUE (sym) = valu;
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      add_symbol_to_list (sym, &local_symbols);
+      break;
+
+    case 'X':
+      /* This is used by Sun FORTRAN for "function result value".
+        Sun claims ("dbx and dbxtool interfaces", 2nd ed)
+        that Pascal uses it too, but when I tried it Pascal used
+        "x:3" (local symbol) instead.  */
+      SYMBOL_CLASS (sym) = LOC_LOCAL;
+      SYMBOL_VALUE (sym) = valu;
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      add_symbol_to_list (sym, &local_symbols);
+      break;
+
+    default:
+      error ("Invalid symbol data: unknown symbol-type code `%c' at symtab pos %d.", deftype, symnum);
+    }
+  return sym;
+}
+\f
+/* What about types defined as forward references inside of a small lexical
+   scope?  */
+/* Add a type to the list of undefined types to be checked through
+   once this file has been read in.  */
+static void
+add_undefined_type (type)
+     struct type *type;
+{
+  if (undef_types_length == undef_types_allocated)
+    {
+      undef_types_allocated *= 2;
+      undef_types = (struct type **)
+       xrealloc (undef_types,
+                 undef_types_allocated * sizeof (struct type *));
+    }
+  undef_types[undef_types_length++] = type;
+}
+
+/* Add here something to go through each undefined type, see if it's
+   still undefined, and do a full lookup if so.  */
+static void
+cleanup_undefined_types ()
+{
+  struct type **type;
+
+  for (type = undef_types; type < undef_types + undef_types_length; type++)
+    {
+      /* Reasonable test to see if it's been defined since.  */
+      if (TYPE_NFIELDS (*type) == 0)
+       {
+         struct pending *ppt;
+         int i;
+         /* Name of the type, without "struct" or "union" */
+         char *typename = TYPE_NAME (*type);
+
+         if (!strncmp (typename, "struct ", 7))
+           typename += 7;
+         if (!strncmp (typename, "union ", 6))
+           typename += 6;
+
+         for (ppt = file_symbols; ppt; ppt = ppt->next)
+           for (i = 0; i < ppt->nsyms; i++)
+             {
+               struct symbol *sym = ppt->symbol[i];
+
+               if (SYMBOL_CLASS (sym) == LOC_TYPEDEF
+                   && SYMBOL_NAMESPACE (sym) == STRUCT_NAMESPACE
+                   && (TYPE_CODE (SYMBOL_TYPE (sym)) ==
+                       TYPE_CODE (*type))
+                   && !strcmp (SYMBOL_NAME (sym), typename))
+                 bcopy (SYMBOL_TYPE (sym), *type, sizeof (struct type));
+             }
+       }
+      else
+       /* It has been defined; don't mark it as a stub.  */
+       TYPE_FLAGS (*type) &= ~TYPE_FLAG_STUB;
+    }
+  undef_types_length = 0;
+}
+
+/* Skip rest of this symbol and return an error type.
+
+   General notes on error recovery:  error_type always skips to the
+   end of the symbol (modulo cretinous dbx symbol name continuation).
+   Thus code like this:
+
+   if (*(*pp)++ != ';')
+     return error_type (pp);
+
+   is wrong because if *pp starts out pointing at '\0' (typically as the
+   result of an earlier error), it will be incremented to point to the
+   start of the next symbol, which might produce strange results, at least
+   if you run off the end of the string table.  Instead use
+
+   if (**pp != ';')
+     return error_type (pp);
+   ++*pp;
+
+   or
+
+   if (**pp != ';')
+     foo = error_type (pp);
+   else
+     ++*pp;
+
+   And in case it isn't obvious, the point of all this hair is so the compiler
+   can define new types and new syntaxes, and old versions of the
+   debugger will be able to read the new symbol tables.  */
+
+static struct type *
+error_type (pp)
+     char **pp;
+{
+  complain (&error_type_complaint, 0);
+  while (1)
+    {
+      /* Skip to end of symbol.  */
+      while (**pp != '\0')
+       (*pp)++;
+
+      /* Check for and handle cretinous dbx symbol name continuation!  */
+      if ((*pp)[-1] == '\\')
+       *pp = next_symbol_text ();
+      else
+       break;
+    }
+  return builtin_type_error;
+}
+\f
+/* Read a dbx type reference or definition;
+   return the type that is meant.
+   This can be just a number, in which case it references
+   a type already defined and placed in type_vector.
+   Or the number can be followed by an =, in which case
+   it means to define a new type according to the text that
+   follows the =.  */
+
+static
+struct type *
+read_type (pp)
+     register char **pp;
+{
+  register struct type *type = 0;
+  struct type *type1;
+  int typenums[2];
+  int xtypenums[2];
+
+  /* Read type number if present.  The type number may be omitted.
+     for instance in a two-dimensional array declared with type
+     "ar1;1;10;ar1;1;10;4".  */
+  if ((**pp >= '0' && **pp <= '9')
+      || **pp == '(')
+    {
+      read_type_number (pp, typenums);
+      
+      /* Detect random reference to type not yet defined.
+        Allocate a type object but leave it zeroed.  */
+      if (**pp != '=')
+       return dbx_alloc_type (typenums);
+
+      *pp += 2;
+    }
+  else
+    {
+      /* 'typenums=' not present, type is anonymous.  Read and return
+        the definition, but don't put it in the type vector.  */
+      typenums[0] = typenums[1] = -1;
+      *pp += 1;
+    }
+      
+  switch ((*pp)[-1])
+    {
+    case 'x':
+      {
+       enum type_code code;
+
+       /* Used to index through file_symbols.  */
+       struct pending *ppt;
+       int i;
+       
+       /* Name including "struct", etc.  */
+       char *type_name;
+       
+       /* Name without "struct", etc.  */
+       char *type_name_only;
+
+       {
+         char *prefix;
+         char *from, *to;
+         
+         /* Set the type code according to the following letter.  */
+         switch ((*pp)[0])
+           {
+           case 's':
+             code = TYPE_CODE_STRUCT;
+             prefix = "struct ";
+             break;
+           case 'u':
+             code = TYPE_CODE_UNION;
+             prefix = "union ";
+             break;
+           case 'e':
+             code = TYPE_CODE_ENUM;
+             prefix = "enum ";
+             break;
+           default:
+             return error_type (pp);
+           }
+         
+         to = type_name = (char *)
+           obstack_alloc (symbol_obstack,
+                          (strlen (prefix) +
+                           ((char *) strchr (*pp, ':') - (*pp)) + 1));
+       
+         /* Copy the prefix.  */
+         from = prefix;
+         while (*to++ = *from++)
+           ;
+         to--; 
+       
+         type_name_only = to;
+
+         /* Copy the name.  */
+         from = *pp + 1;
+         while ((*to++ = *from++) != ':')
+           ;
+         *--to = '\0';
+         
+         /* Set the pointer ahead of the name which we just read.  */
+         *pp = from;
+       
+#if 0
+         /* The following hack is clearly wrong, because it doesn't
+            check whether we are in a baseclass.  I tried to reproduce
+            the case that it is trying to fix, but I couldn't get
+            g++ to put out a cross reference to a basetype.  Perhaps
+            it doesn't do it anymore.  */
+         /* Note: for C++, the cross reference may be to a base type which
+            has not yet been seen.  In this case, we skip to the comma,
+            which will mark the end of the base class name.  (The ':'
+            at the end of the base class name will be skipped as well.)
+            But sometimes (ie. when the cross ref is the last thing on
+            the line) there will be no ','.  */
+         from = (char *) strchr (*pp, ',');
+         if (from)
+           *pp = from;
+#endif /* 0 */
+       }
+
+       /* Now check to see whether the type has already been declared.  */
+       /* This is necessary at least in the case where the
+          program says something like
+            struct foo bar[5];
+          The compiler puts out a cross-reference; we better find
+          set the length of the structure correctly so we can
+          set the length of the array.  */
+       for (ppt = file_symbols; ppt; ppt = ppt->next)
+         for (i = 0; i < ppt->nsyms; i++)
+           {
+             struct symbol *sym = ppt->symbol[i];
+
+             if (SYMBOL_CLASS (sym) == LOC_TYPEDEF
+                 && SYMBOL_NAMESPACE (sym) == STRUCT_NAMESPACE
+                 && (TYPE_CODE (SYMBOL_TYPE (sym)) == code)
+                 && !strcmp (SYMBOL_NAME (sym), type_name_only))
+               {
+                 obstack_free (symbol_obstack, type_name);
+                 type = SYMBOL_TYPE (sym);
+                 return type;
+               }
+           }
+       
+       /* Didn't find the type to which this refers, so we must
+          be dealing with a forward reference.  Allocate a type
+          structure for it, and keep track of it so we can
+          fill in the rest of the fields when we get the full
+          type.  */
+       type = dbx_alloc_type (typenums);
+       TYPE_CODE (type) = code;
+       TYPE_NAME (type) = type_name;
+
+       TYPE_FLAGS (type) |= TYPE_FLAG_STUB;
+
+       add_undefined_type (type);
+       return type;
+      }
+
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+    case '6':
+    case '7':
+    case '8':
+    case '9':
+    case '(':
+      (*pp)--;
+      read_type_number (pp, xtypenums);
+      type = *dbx_lookup_type (xtypenums);
+      if (type == 0)
+       type = builtin_type_void;
+      if (typenums[0] != -1)
+       *dbx_lookup_type (typenums) = type;
+      break;
+
+    case '*':
+      type1 = read_type (pp);
+      type = lookup_pointer_type (type1);
+      if (typenums[0] != -1)
+       *dbx_lookup_type (typenums) = type;
+      break;
+
+    case '@':
+      {
+       struct type *domain = read_type (pp);
+       struct type *memtype;
+
+       if (**pp != ',')
+         /* Invalid member type data format.  */
+         return error_type (pp);
+       ++*pp;
+
+       memtype = read_type (pp);
+       type = dbx_alloc_type (typenums);
+       smash_to_member_type (type, domain, memtype);
+      }
+      break;
+
+    case '#':
+      if ((*pp)[0] == '#')
+       {
+         /* We'll get the parameter types from the name.  */
+         struct type *return_type;
+
+         *pp += 1;
+         return_type = read_type (pp);
+         if (*(*pp)++ != ';')
+           complain (&invalid_member_complaint, symnum);
+         type = lookup_function_type (return_type);
+         if (typenums[0] != -1)
+           *dbx_lookup_type (typenums) = type;
+         TYPE_CODE (type) = TYPE_CODE_METHOD;
+         TYPE_FLAGS (type) |= TYPE_FLAG_STUB;
+       }
+      else
+       {
+         struct type *domain = read_type (pp);
+         struct type *return_type;
+         struct type **args;
+
+         if (*(*pp)++ != ',')
+           error ("invalid member type data format, at symtab pos %d.",
+                  symnum);
+
+         return_type = read_type (pp);
+         args = read_args (pp, ';');
+         type = dbx_alloc_type (typenums);
+         smash_to_method_type (type, domain, return_type, args);
+       }
+      break;
+
+    case '&':
+      type1 = read_type (pp);
+      type = lookup_reference_type (type1);
+      if (typenums[0] != -1)
+       *dbx_lookup_type (typenums) = type;
+      break;
+
+    case 'f':
+      type1 = read_type (pp);
+      type = lookup_function_type (type1);
+      if (typenums[0] != -1)
+       *dbx_lookup_type (typenums) = type;
+      break;
+
+    case 'r':
+      type = read_range_type (pp, typenums);
+      if (typenums[0] != -1)
+       *dbx_lookup_type (typenums) = type;
+      break;
+
+    case 'e':
+      type = dbx_alloc_type (typenums);
+      type = read_enum_type (pp, type);
+      *dbx_lookup_type (typenums) = type;
+      break;
+
+    case 's':
+      type = dbx_alloc_type (typenums);
+      TYPE_NAME (type) = type_synonym_name;
+      type_synonym_name = 0;
+      type = read_struct_type (pp, type);
+      break;
+
+    case 'u':
+      type = dbx_alloc_type (typenums);
+      TYPE_NAME (type) = type_synonym_name;
+      type_synonym_name = 0;
+      type = read_struct_type (pp, type);
+      TYPE_CODE (type) = TYPE_CODE_UNION;
+      break;
+
+    case 'a':
+      if (**pp != 'r')
+       return error_type (pp);
+      ++*pp;
+      
+      type = dbx_alloc_type (typenums);
+      type = read_array_type (pp, type);
+      break;
+
+    default:
+      return error_type (pp);
+    }
+
+  if (type == 0)
+    abort ();
+
+#if 0
+  /* If this is an overriding temporary alteration for a header file's
+     contents, and this type number is unknown in the global definition,
+     put this type into the global definition at this type number.  */
+  if (header_file_prev_index >= 0)
+    {
+      register struct type **tp
+        = explicit_lookup_type (header_file_prev_index, typenums[1]);
+      if (*tp == 0)
+       *tp = type;
+    }
+#endif
+  return type;
+}
+\f
+#if 0
+/* This would be a good idea, but it doesn't really work.  The problem
+   is that in order to get the virtual context for a particular type,
+   you need to know the virtual info from all of its basetypes,
+   and you need to have processed its methods.  Since GDB reads
+   symbols on a file-by-file basis, this means processing the symbols
+   of all the files that are needed for each baseclass, which
+   means potentially reading in all the debugging info just to fill
+   in information we may never need.  */
+
+/* This page contains subroutines of read_type.  */
+
+/* FOR_TYPE is a struct type defining a virtual function NAME with type
+   FN_TYPE.  The `virtual context' for this virtual function is the
+   first base class of FOR_TYPE in which NAME is defined with signature
+   matching FN_TYPE.  OFFSET serves as a hash on matches here.
+
+   TYPE is the current type in which we are searching.  */
+
+static struct type *
+virtual_context (for_type, type, name, fn_type, offset)
+     struct type *for_type, *type;
+     char *name;
+     struct type *fn_type;
+     int offset;
+{
+  struct type *basetype = 0;
+  int i;
+
+  if (for_type != type)
+    {
+      /* Check the methods of TYPE.  */
+      /* Need to do a check_stub_type here, but that breaks
+        things because we can get infinite regress.  */
+      for (i = TYPE_NFN_FIELDS (type) - 1; i >= 0; --i)
+       if (!strcmp (TYPE_FN_FIELDLIST_NAME (type, i), name))
+         break;
+      if (i >= 0)
+       {
+         int j = TYPE_FN_FIELDLIST_LENGTH (type, i);
+         struct fn_field *f = TYPE_FN_FIELDLIST1 (type, i);
+
+         while (--j >= 0)
+           if (TYPE_FN_FIELD_VOFFSET (f, j) == offset-1)
+             return TYPE_FN_FIELD_FCONTEXT (f, j);
+       }
+    }
+  for (i = TYPE_N_BASECLASSES (type); i > 0; i--)
+    {
+      basetype = virtual_context (for_type, TYPE_BASECLASS (type, i), name,
+                                 fn_type, offset);
+      if (basetype != for_type)
+       return basetype;
+    }
+  return for_type;
+}
+#endif
+
+/* Read the description of a structure (or union type)
+   and return an object describing the type.  */
+
+static struct type *
+read_struct_type (pp, type)
+     char **pp;
+     register struct type *type;
+{
+  /* Total number of methods defined in this class.
+     If the class defines two `f' methods, and one `g' method,
+     then this will have the value 3.  */
+  int total_length = 0;
+
+  struct nextfield
+    {
+      struct nextfield *next;
+      int visibility;                  /* 0=public, 1=protected, 2=public */
+      struct field field;
+    };
+
+  struct next_fnfield
+    {
+      struct next_fnfield *next;
+      int visibility;                  /* 0=public, 1=protected, 2=public */
+      struct fn_field fn_field;
+    };
+
+  struct next_fnfieldlist
+    {
+      struct next_fnfieldlist *next;
+      struct fn_fieldlist fn_fieldlist;
+    };
+
+  register struct nextfield *list = 0;
+  struct nextfield *new;
+  register char *p;
+  int nfields = 0;
+  register int n;
+
+  register struct next_fnfieldlist *mainlist = 0;
+  int nfn_fields = 0;
+
+  if (TYPE_MAIN_VARIANT (type) == 0)
+    {
+      TYPE_MAIN_VARIANT (type) = type;
+    }
+
+  TYPE_CODE (type) = TYPE_CODE_STRUCT;
+
+  /* First comes the total size in bytes.  */
+
+  TYPE_LENGTH (type) = read_number (pp, 0);
+
+  /* C++: Now, if the class is a derived class, then the next character
+     will be a '!', followed by the number of base classes derived from.
+     Each element in the list contains visibility information,
+     the offset of this base class in the derived structure,
+     and then the base type. */
+  if (**pp == '!')
+    {
+      int i, n_baseclasses, offset;
+      struct type *baseclass;
+      int via_public;
+
+      /* Nonzero if it is a virtual baseclass, i.e.,
+
+        struct A{};
+        struct B{};
+        struct C : public B, public virtual A {};
+
+        B is a baseclass of C; A is a virtual baseclass for C.  This is a C++
+        2.0 language feature.  */
+      int via_virtual;
+
+      *pp += 1;
+
+      n_baseclasses = read_number (pp, ',');
+      TYPE_FIELD_VIRTUAL_BITS (type) =
+         (B_TYPE *) obstack_alloc (symbol_obstack, B_BYTES (n_baseclasses));
+      B_CLRALL (TYPE_FIELD_VIRTUAL_BITS (type), n_baseclasses);
+
+      for (i = 0; i < n_baseclasses; i++)
+       {
+         if (**pp == '\\')
+           *pp = next_symbol_text ();
+
+         switch (**pp)
+           {
+           case '0':
+             via_virtual = 0;
+             break;
+           case '1':
+             via_virtual = 1;
+             break;
+           default:
+             /* Bad visibility format.  */
+             return error_type (pp);
+           }
+         ++*pp;
+
+         switch (**pp)
+           {
+           case '0':
+             via_public = 0;
+             break;
+           case '2':
+             via_public = 2;
+             break;
+           default:
+             /* Bad visibility format.  */
+             return error_type (pp);
+           }
+         if (via_virtual) 
+           SET_TYPE_FIELD_VIRTUAL (type, i);
+         ++*pp;
+
+         /* Offset of the portion of the object corresponding to
+            this baseclass.  Always zero in the absence of
+            multiple inheritance.  */
+         offset = read_number (pp, ',');
+         baseclass = read_type (pp);
+         *pp += 1;             /* skip trailing ';' */
+
+#if 0
+/* One's understanding improves, grasshopper... */
+         if (offset != 0)
+           {
+             static int error_printed = 0;
+
+             if (!error_printed)
+               {
+                 fprintf (stderr, 
+"\nWarning:  GDB has limited understanding of multiple inheritance...");
+                 if (!info_verbose)
+                   fprintf(stderr, "\n");
+                 error_printed = 1;
+               }
+           }
+#endif
+
+         /* Make this baseclass visible for structure-printing purposes.  */
+         new = (struct nextfield *) alloca (sizeof (struct nextfield));
+         new->next = list;
+         list = new;
+         list->visibility = via_public;
+         list->field.type = baseclass;
+         list->field.name = type_name_no_tag (baseclass);
+         list->field.bitpos = offset;
+         list->field.bitsize = 0;      /* this should be an unpacked field! */
+         nfields++;
+       }
+      TYPE_N_BASECLASSES (type) = n_baseclasses;
+    }
+
+  /* Now come the fields, as NAME:?TYPENUM,BITPOS,BITSIZE; for each one.
+     At the end, we see a semicolon instead of a field.
+
+     In C++, this may wind up being NAME:?TYPENUM:PHYSNAME; for
+     a static field.
+
+     The `?' is a placeholder for one of '/2' (public visibility),
+     '/1' (protected visibility), '/0' (private visibility), or nothing
+     (C style symbol table, public visibility).  */
+
+  /* We better set p right now, in case there are no fields at all...    */
+  p = *pp;
+
+  while (**pp != ';')
+    {
+      /* Check for and handle cretinous dbx symbol name continuation!  */
+      if (**pp == '\\') *pp = next_symbol_text ();
+
+      /* Get space to record the next field's data.  */
+      new = (struct nextfield *) alloca (sizeof (struct nextfield));
+      new->next = list;
+      list = new;
+
+      /* Get the field name.  */
+      p = *pp;
+      if (*p == CPLUS_MARKER)
+       {
+         /* Special GNU C++ name.  */
+         if (*++p == 'v')
+           {
+             char *prefix, *name;      /* FIXME: NAME never set! */
+             struct type *context;
+
+             switch (*++p)
+               {
+               case 'f':
+                 prefix = vptr_name;
+                 break;
+               case 'b':
+                 prefix = vb_name;
+                 break;
+               default:
+                 error ("invalid abbreviation at symtab pos %d.", symnum);
+               }
+             *pp = p + 1;
+             context = read_type (pp);
+             if (type_name_no_tag (context) == 0)
+               {
+                 if (name == 0)
+                   error ("type name unknown at symtab pos %d.", symnum);
+                 TYPE_NAME (context) = obsavestring (name, p - name - 1);
+               }
+             list->field.name = obconcat (prefix, type_name_no_tag (context), "");
+             p = ++(*pp);
+             if (p[-1] != ':')
+               error ("invalid abbreviation at symtab pos %d.", symnum);
+             list->field.type = read_type (pp);
+             (*pp)++;                  /* Skip the comma.  */
+             list->field.bitpos = read_number (pp, ';');
+             /* This field is unpacked.  */
+             list->field.bitsize = 0;
+           }
+         else
+           error ("invalid abbreviation at symtab pos %d.", symnum);
+
+         nfields++;
+         continue;
+       }
+
+      while (*p != ':') p++;
+      list->field.name = obsavestring (*pp, p - *pp);
+
+      /* C++: Check to see if we have hit the methods yet.  */
+      if (p[1] == ':')
+       break;
+
+      *pp = p + 1;
+
+      /* This means we have a visibility for a field coming. */
+      if (**pp == '/')
+       {
+         switch (*++*pp)
+           {
+           case '0':
+             list->visibility = 0;     /* private */
+             *pp += 1;
+             break;
+
+           case '1':
+             list->visibility = 1;     /* protected */
+             *pp += 1;
+             break;
+
+           case '2':
+             list->visibility = 2;     /* public */
+             *pp += 1;
+             break;
+           }
+       }
+       else /* normal dbx-style format.  */
+       list->visibility = 2;           /* public */
+
+      list->field.type = read_type (pp);
+      if (**pp == ':')
+       {
+         /* Static class member.  */
+         list->field.bitpos = (long)-1;
+         p = ++(*pp);
+         while (*p != ';') p++;
+         list->field.bitsize = (long) savestring (*pp, p - *pp);
+         *pp = p + 1;
+         nfields++;
+         continue;
+       }
+       else if (**pp != ',')
+        /* Bad structure-type format.  */
+        return error_type (pp);
+
+      (*pp)++;                 /* Skip the comma.  */
+      list->field.bitpos = read_number (pp, ',');
+      list->field.bitsize = read_number (pp, ';');
+
+#if 0
+      /* FIXME tiemann: what is the story here?  What does the compiler
+       really do?  Also, patch gdb.texinfo for this case; I document
+       it as a possible problem there.  Search for "DBX-style".  */
+
+      /* This is wrong because this is identical to the symbols
+        produced for GCC 0-size arrays.  For example:
+         typedef union {
+          int num;
+          char str[0];
+        } foo;
+        The code which dumped core in such circumstances should be
+        fixed not to dump core.  */
+
+      /* g++ -g0 can put out bitpos & bitsize zero for a static
+        field.  This does not give us any way of getting its
+        class, so we can't know its name.  But we can just
+        ignore the field so we don't dump core and other nasty
+        stuff.  */
+      if (list->field.bitpos == 0
+         && list->field.bitsize == 0)
+       {
+         complain (&dbx_class_complaint, 0);
+         /* Ignore this field.  */
+         list = list->next;
+       }
+      else
+#endif /* 0 */
+       {
+         /* Detect an unpacked field and mark it as such.
+            dbx gives a bit size for all fields.
+            Note that forward refs cannot be packed,
+            and treat enums as if they had the width of ints.  */
+         if (TYPE_CODE (list->field.type) != TYPE_CODE_INT
+             && TYPE_CODE (list->field.type) != TYPE_CODE_ENUM)
+           list->field.bitsize = 0;
+         if ((list->field.bitsize == 8 * TYPE_LENGTH (list->field.type)
+              || (TYPE_CODE (list->field.type) == TYPE_CODE_ENUM
+                  && (list->field.bitsize
+                      == 8 * TYPE_LENGTH (builtin_type_int))
+                  )
+              )
+             &&
+             list->field.bitpos % 8 == 0)
+           list->field.bitsize = 0;
+         nfields++;
+       }
+    }
+
+  if (p[1] == ':')
+    /* chill the list of fields: the last entry (at the head)
+       is a partially constructed entry which we now scrub.  */
+    list = list->next;
+
+  /* Now create the vector of fields, and record how big it is.
+     We need this info to record proper virtual function table information
+     for this class's virtual functions.  */
+
+  TYPE_NFIELDS (type) = nfields;
+  TYPE_FIELDS (type) = (struct field *) obstack_alloc (symbol_obstack,
+                                              sizeof (struct field) * nfields);
+
+  TYPE_FIELD_PRIVATE_BITS (type) =
+    (B_TYPE *) obstack_alloc (symbol_obstack, B_BYTES (nfields));
+  B_CLRALL (TYPE_FIELD_PRIVATE_BITS (type), nfields);
+
+  TYPE_FIELD_PROTECTED_BITS (type) =
+    (B_TYPE *) obstack_alloc (symbol_obstack, B_BYTES (nfields));
+  B_CLRALL (TYPE_FIELD_PROTECTED_BITS (type), nfields);
+
+  /* Copy the saved-up fields into the field vector.  */
+
+  for (n = nfields; list; list = list->next)
+    {
+      n -= 1;
+      TYPE_FIELD (type, n) = list->field;
+      if (list->visibility == 0)
+       SET_TYPE_FIELD_PRIVATE (type, n);
+      else if (list->visibility == 1)
+       SET_TYPE_FIELD_PROTECTED (type, n);
+    }
+
+  /* Now come the method fields, as NAME::methods
+     where each method is of the form TYPENUM,ARGS,...:PHYSNAME;
+     At the end, we see a semicolon instead of a field.
+
+     For the case of overloaded operators, the format is
+     OPERATOR::*.methods, where OPERATOR is the string "operator",
+     `*' holds the place for an operator name (such as `+=')
+     and `.' marks the end of the operator name.  */
+  if (p[1] == ':')
+    {
+      /* Now, read in the methods.  To simplify matters, we
+        "unread" the name that has been read, so that we can
+        start from the top.  */
+
+      /* For each list of method lists... */
+      do
+       {
+         int i;
+         struct next_fnfield *sublist = 0;
+         int length = 0;
+         struct next_fnfieldlist *new_mainlist =
+           (struct next_fnfieldlist *)alloca (sizeof (struct next_fnfieldlist));
+         char *main_fn_name;
+
+         p = *pp;
+
+         /* read in the name.  */
+         while (*p != ':') p++;
+         if ((*pp)[0] == 'o' && (*pp)[1] == 'p' && (*pp)[2] == CPLUS_MARKER)
+           {
+             /* This lets the user type "break operator+".
+                We could just put in "+" as the name, but that wouldn't
+                work for "*".  */
+             static char opname[32] = "operator";
+             char *o = opname + 8;
+
+             /* Skip past '::'.  */
+             p += 2;
+             while (*p != '.')
+               *o++ = *p++;
+            main_fn_name = savestring (opname, o - opname);
+             /* Skip past '.'  */
+             *pp = p + 1;
+           }
+         else
+           {
+             i = 0;
+             main_fn_name = savestring (*pp, p - *pp);
+             /* Skip past '::'.  */
+             *pp = p + 2;
+           }
+         new_mainlist->fn_fieldlist.name = main_fn_name;
+
+         do
+           {
+             struct next_fnfield *new_sublist =
+               (struct next_fnfield *)alloca (sizeof (struct next_fnfield));
+
+             /* Check for and handle cretinous dbx symbol name continuation!  */
+             if (**pp == '\\') *pp = next_symbol_text ();
+
+             new_sublist->fn_field.type = read_type (pp);
+             if (**pp != ':')
+               /* Invalid symtab info for method.  */
+               return error_type (pp);
+
+             *pp += 1;
+             p = *pp;
+             while (*p != ';') p++;
+             /* If this is just a stub, then we don't have the
+                real name here.  */
+             new_sublist->fn_field.physname = savestring (*pp, p - *pp);
+             *pp = p + 1;
+             new_sublist->visibility = *(*pp)++ - '0';
+             if (**pp == '\\') *pp = next_symbol_text ();
+             /* FIXME: tiemann needs to add const/volatile info
+                to the methods.  For now, just skip the char.
+                In future, here's what we need to implement:
+
+                A for normal functions.
+                B for `const' member functions.
+                C for `volatile' member functions.
+                D for `const volatile' member functions.  */
+             if (**pp == 'A' || **pp == 'B' || **pp == 'C' || **pp == 'D')
+               (*pp)++;
+             else
+               complain(&const_vol_complaint, **pp);
+
+             switch (*(*pp)++)
+               {
+               case '*':
+                 /* virtual member function, followed by index.  */
+                 /* The sign bit is set to distinguish pointers-to-methods
+                    from virtual function indicies.  Since the array is
+                    in words, the quantity must be shifted left by 1
+                    on 16 bit machine, and by 2 on 32 bit machine, forcing
+                    the sign bit out, and usable as a valid index into
+                    the array.  Remove the sign bit here.  */
+                 new_sublist->fn_field.voffset =
+                     (0x7fffffff & read_number (pp, ';')) + 1;
+
+                 /* Figure out from whence this virtual function came.
+                    It may belong to virtual function table of
+                    one of its baseclasses.  */
+                 new_sublist->fn_field.fcontext = read_type (pp);
+                 if (**pp != ';')
+                   error_type (pp);
+                 else
+                   ++*pp;
+                 break;
+
+               case '?':
+                 /* static member function.  */
+                 new_sublist->fn_field.voffset = VOFFSET_STATIC;
+                 break;
+               default:
+                 /* **pp == '.'.  */
+                 /* normal member function.  */
+                 new_sublist->fn_field.voffset = 0;
+                 break;
+               }
+
+             new_sublist->next = sublist;
+             sublist = new_sublist;
+             length++;
+           }
+         while (**pp != ';' && *pp != '\0');
+
+         *pp += 1;
+
+         new_mainlist->fn_fieldlist.fn_fields =
+           (struct fn_field *) obstack_alloc (symbol_obstack,
+                                              sizeof (struct fn_field) * length);
+         TYPE_FN_PRIVATE_BITS (new_mainlist->fn_fieldlist) =
+           (B_TYPE *) obstack_alloc (symbol_obstack, B_BYTES (length));
+         B_CLRALL (TYPE_FN_PRIVATE_BITS (new_mainlist->fn_fieldlist), length);
+
+         TYPE_FN_PROTECTED_BITS (new_mainlist->fn_fieldlist) =
+           (B_TYPE *) obstack_alloc (symbol_obstack, B_BYTES (length));
+         B_CLRALL (TYPE_FN_PROTECTED_BITS (new_mainlist->fn_fieldlist), length);
+
+         for (i = length; (i--, sublist); sublist = sublist->next)
+           {
+             new_mainlist->fn_fieldlist.fn_fields[i] = sublist->fn_field;
+             if (sublist->visibility == 0)
+               B_SET (new_mainlist->fn_fieldlist.private_fn_field_bits, i);
+             else if (sublist->visibility == 1)
+               B_SET (new_mainlist->fn_fieldlist.protected_fn_field_bits, i);
+           }
+
+         new_mainlist->fn_fieldlist.length = length;
+         new_mainlist->next = mainlist;
+         mainlist = new_mainlist;
+         nfn_fields++;
+         total_length += length;
+       }
+      while (**pp != ';');
+    }
+
+  *pp += 1;
+
+  TYPE_FN_FIELDLISTS (type) =
+    (struct fn_fieldlist *) obstack_alloc (symbol_obstack,
+                                  sizeof (struct fn_fieldlist) * nfn_fields);
+
+  TYPE_NFN_FIELDS (type) = nfn_fields;
+  TYPE_NFN_FIELDS_TOTAL (type) = total_length;
+
+  {
+    int i;
+    for (i = 0; i < TYPE_N_BASECLASSES (type); ++i)
+      TYPE_NFN_FIELDS_TOTAL (type) +=
+       TYPE_NFN_FIELDS_TOTAL (TYPE_BASECLASS (type, i));
+  }
+
+  for (n = nfn_fields; mainlist; mainlist = mainlist->next)
+    TYPE_FN_FIELDLISTS (type)[--n] = mainlist->fn_fieldlist;
+
+  if (**pp == '~')
+    {
+      *pp += 1;
+
+      if (**pp == '=')
+       {
+         TYPE_FLAGS (type)
+           |= TYPE_FLAG_HAS_CONSTRUCTOR | TYPE_FLAG_HAS_DESTRUCTOR;
+         *pp += 1;
+       }
+      else if (**pp == '+')
+       {
+         TYPE_FLAGS (type) |= TYPE_FLAG_HAS_CONSTRUCTOR;
+         *pp += 1;
+       }
+      else if (**pp == '-')
+       {
+         TYPE_FLAGS (type) |= TYPE_FLAG_HAS_DESTRUCTOR;
+         *pp += 1;
+       }
+
+      /* Read either a '%' or the final ';'.  */
+      if (*(*pp)++ == '%')
+       {
+         /* Now we must record the virtual function table pointer's
+            field information.  */
+
+         struct type *t;
+         int i;
+
+         t = read_type (pp);
+         p = (*pp)++;
+         while (*p != '\0' && *p != ';')
+           p++;
+         if (*p == '\0')
+           /* Premature end of symbol.  */
+           return error_type (pp);
+         
+         TYPE_VPTR_BASETYPE (type) = t;
+         if (type == t)
+           {
+             if (TYPE_FIELD_NAME (t, TYPE_N_BASECLASSES (t)) == 0)
+               TYPE_VPTR_FIELDNO (type) = i = TYPE_N_BASECLASSES (t);
+             else for (i = TYPE_NFIELDS (t) - 1; i >= TYPE_N_BASECLASSES (t); --i)
+               if (! strncmp (TYPE_FIELD_NAME (t, i), vptr_name, 
+                       sizeof (vptr_name) -1))
+                 {
+                   TYPE_VPTR_FIELDNO (type) = i;
+                   break;
+                 }
+             if (i < 0)
+               /* Virtual function table field not found.  */
+               return error_type (pp);
+           }
+         else
+           TYPE_VPTR_FIELDNO (type) = TYPE_VPTR_FIELDNO (t);
+         *pp = p + 1;
+       }
+      else
+       {
+         TYPE_VPTR_BASETYPE (type) = 0;
+         TYPE_VPTR_FIELDNO (type) = -1;
+       }
+    }
+  else
+    {
+      TYPE_VPTR_BASETYPE (type) = 0;
+      TYPE_VPTR_FIELDNO (type) = -1;
+    }
+
+  return type;
+}
+
+/* Read a definition of an array type,
+   and create and return a suitable type object.
+   Also creates a range type which represents the bounds of that
+   array.  */
+static struct type *
+read_array_type (pp, type)
+     register char **pp;
+     register struct type *type;
+{
+  struct type *index_type, *element_type, *range_type;
+  int lower, upper;
+  int adjustable = 0;
+
+  /* Format of an array type:
+     "ar<index type>;lower;upper;<array_contents_type>".  Put code in
+     to handle this.
+
+     Fortran adjustable arrays use Adigits or Tdigits for lower or upper;
+     for these, produce a type like float[][].  */
+
+  index_type = read_type (pp);
+  if (**pp != ';')
+    /* Improper format of array type decl.  */
+    return error_type (pp);
+  ++*pp;
+
+  if (!(**pp >= '0' && **pp <= '9'))
+    {
+      *pp += 1;
+      adjustable = 1;
+    }
+  lower = read_number (pp, ';');
+
+  if (!(**pp >= '0' && **pp <= '9'))
+    {
+      *pp += 1;
+      adjustable = 1;
+    }
+  upper = read_number (pp, ';');
+  
+  element_type = read_type (pp);
+
+  if (adjustable)
+    {
+      lower = 0;
+      upper = -1;
+    }
+
+  {
+    /* Create range type.  */
+    range_type = (struct type *) obstack_alloc (symbol_obstack,
+                                               sizeof (struct type));
+    TYPE_CODE (range_type) = TYPE_CODE_RANGE;
+    TYPE_TARGET_TYPE (range_type) = index_type;
+
+    /* This should never be needed.  */
+    TYPE_LENGTH (range_type) = sizeof (int);
+
+    TYPE_NFIELDS (range_type) = 2;
+    TYPE_FIELDS (range_type) =
+      (struct field *) obstack_alloc (symbol_obstack,
+                                     2 * sizeof (struct field));
+    TYPE_FIELD_BITPOS (range_type, 0) = lower;
+    TYPE_FIELD_BITPOS (range_type, 1) = upper;
+  }
+
+  TYPE_CODE (type) = TYPE_CODE_ARRAY;
+  TYPE_TARGET_TYPE (type) = element_type;
+  TYPE_LENGTH (type) = (upper - lower + 1) * TYPE_LENGTH (element_type);
+  TYPE_NFIELDS (type) = 1;
+  TYPE_FIELDS (type) =
+    (struct field *) obstack_alloc (symbol_obstack,
+                                   sizeof (struct field));
+  TYPE_FIELD_TYPE (type, 0) = range_type;
+
+  return type;
+}
+
+
+/* Read a definition of an enumeration type,
+   and create and return a suitable type object.
+   Also defines the symbols that represent the values of the type.  */
+
+static struct type *
+read_enum_type (pp, type)
+     register char **pp;
+     register struct type *type;
+{
+  register char *p;
+  char *name;
+  register long n;
+  register struct symbol *sym;
+  int nsyms = 0;
+  struct pending **symlist;
+  struct pending *osyms, *syms;
+  int o_nsyms;
+
+  if (within_function)
+    symlist = &local_symbols;
+  else
+    symlist = &file_symbols;
+  osyms = *symlist;
+  o_nsyms = osyms ? osyms->nsyms : 0;
+
+  /* Read the value-names and their values.
+     The input syntax is NAME:VALUE,NAME:VALUE, and so on.
+     A semicolon or comman instead of a NAME means the end.  */
+  while (**pp && **pp != ';' && **pp != ',')
+    {
+      /* Check for and handle cretinous dbx symbol name continuation!  */
+      if (**pp == '\\')        *pp = next_symbol_text ();
+
+      p = *pp;
+      while (*p != ':') p++;
+      name = obsavestring (*pp, p - *pp);
+      *pp = p + 1;
+      n = read_number (pp, ',');
+
+      sym = (struct symbol *) obstack_alloc (symbol_obstack, sizeof (struct symbol));
+      bzero (sym, sizeof (struct symbol));
+      SYMBOL_NAME (sym) = name;
+      SYMBOL_CLASS (sym) = LOC_CONST;
+      SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+      SYMBOL_VALUE (sym) = n;
+      add_symbol_to_list (sym, symlist);
+      nsyms++;
+    }
+
+  if (**pp == ';')
+    (*pp)++;                   /* Skip the semicolon.  */
+
+  /* Now fill in the fields of the type-structure.  */
+
+  TYPE_LENGTH (type) = sizeof (int);
+  TYPE_CODE (type) = TYPE_CODE_ENUM;
+  TYPE_NFIELDS (type) = nsyms;
+  TYPE_FIELDS (type) = (struct field *) obstack_alloc (symbol_obstack, sizeof (struct field) * nsyms);
+
+  /* Find the symbols for the values and put them into the type.
+     The symbols can be found in the symlist that we put them on
+     to cause them to be defined.  osyms contains the old value
+     of that symlist; everything up to there was defined by us.  */
+  /* Note that we preserve the order of the enum constants, so
+     that in something like "enum {FOO, LAST_THING=FOO}" we print
+     FOO, not LAST_THING.  */
+
+  for (syms = *symlist, n = 0; syms; syms = syms->next)
+    {
+      int j = 0;
+      if (syms == osyms)
+       j = o_nsyms;
+      for (; j < syms->nsyms; j++,n++)
+       {
+         struct symbol *sym = syms->symbol[j];
+         SYMBOL_TYPE (sym) = type;
+         TYPE_FIELD_NAME (type, n) = SYMBOL_NAME (sym);
+         TYPE_FIELD_VALUE (type, n) = 0;
+         TYPE_FIELD_BITPOS (type, n) = SYMBOL_VALUE (sym);
+         TYPE_FIELD_BITSIZE (type, n) = 0;
+       }
+      if (syms == osyms)
+       break;
+    }
+
+  return type;
+}
+
+/* Read a number from the string pointed to by *PP.
+   The value of *PP is advanced over the number.
+   If END is nonzero, the character that ends the
+   number must match END, or an error happens;
+   and that character is skipped if it does match.
+   If END is zero, *PP is left pointing to that character.
+
+   If the number fits in a long, set *VALUE and set *BITS to 0.
+   If not, set *BITS to be the number of bits in the number.
+
+   If encounter garbage, set *BITS to -1.  */
+
+static void
+read_huge_number (pp, end, valu, bits)
+     char **pp;
+     int end;
+     long *valu;
+     int *bits;
+{
+  char *p = *pp;
+  int sign = 1;
+  long n = 0;
+  int radix = 10;
+  char overflow = 0;
+  int nbits = 0;
+  int c;
+  
+  if (*p == '-')
+    {
+      sign = -1;
+      p++;
+    }
+
+  /* Leading zero means octal.  GCC uses this to output values larger
+     than an int (because that would be hard in decimal).  */
+  if (*p == '0')
+    {
+      radix = 8;
+      p++;
+    }
+
+  while ((c = *p++) >= '0' && c <= ('0' + radix))
+    {
+      if (n <= LONG_MAX / radix)
+       {
+         n *= radix;
+         n += c - '0';         /* FIXME this overflows anyway */
+       }
+      else
+       overflow = 1;
+      
+      /* This depends on large values being output in octal, which is
+        what GCC does. */
+      if (radix == 8)
+       {
+         if (nbits == 0)
+           {
+             if (c == '0')
+               /* Ignore leading zeroes.  */
+               ;
+             else if (c == '1')
+               nbits = 1;
+             else if (c == '2' || c == '3')
+               nbits = 2;
+             else
+               nbits = 3;
+           }
+         else
+           nbits += 3;
+       }
+    }
+  if (end)
+    {
+      if (c && c != end)
+       {
+         if (bits != NULL)
+           *bits = -1;
+         return;
+       }
+    }
+  else
+    --p;
+
+  *pp = p;
+  if (overflow)
+    {
+      if (nbits == 0)
+       {
+         /* Large decimal constants are an error (because it is hard to
+            count how many bits are in them).  */
+         if (bits != NULL)
+           *bits = -1;
+         return;
+       }
+      
+      /* -0x7f is the same as 0x80.  So deal with it by adding one to
+        the number of bits.  */
+      if (sign == -1)
+       ++nbits;
+      if (bits)
+       *bits = nbits;
+    }
+  else
+    {
+      if (valu)
+       *valu = n * sign;
+      if (bits)
+       *bits = 0;
+    }
+}
+
+#define        MAX_OF_TYPE(t)  ((1 << (sizeof (t)*8 - 1)) - 1)
+#define MIN_OF_TYPE(t) (-(1 << (sizeof (t)*8 - 1)))
+
+static struct type *
+read_range_type (pp, typenums)
+     char **pp;
+     int typenums[2];
+{
+  int rangenums[2];
+  long n2, n3;
+  int n2bits, n3bits;
+  int self_subrange;
+  struct type *result_type;
+
+  /* First comes a type we are a subrange of.
+     In C it is usually 0, 1 or the type being defined.  */
+  read_type_number (pp, rangenums);
+  self_subrange = (rangenums[0] == typenums[0] &&
+                  rangenums[1] == typenums[1]);
+
+  /* A semicolon should now follow; skip it.  */
+  if (**pp == ';')
+    (*pp)++;
+
+  /* The remaining two operands are usually lower and upper bounds
+     of the range.  But in some special cases they mean something else.  */
+  read_huge_number (pp, ';', &n2, &n2bits);
+  read_huge_number (pp, ';', &n3, &n3bits);
+
+  if (n2bits == -1 || n3bits == -1)
+    return error_type (pp);
+  
+  /* If limits are huge, must be large integral type.  */
+  if (n2bits != 0 || n3bits != 0)
+    {
+      char got_signed = 0;
+      char got_unsigned = 0;
+      /* Number of bits in the type.  */
+      int nbits;
+
+      /* Range from 0 to <large number> is an unsigned large integral type.  */
+      if ((n2bits == 0 && n2 == 0) && n3bits != 0)
+       {
+         got_unsigned = 1;
+         nbits = n3bits;
+       }
+      /* Range from <large number> to <large number>-1 is a large signed
+        integral type.  */
+      else if (n2bits != 0 && n3bits != 0 && n2bits == n3bits + 1)
+       {
+         got_signed = 1;
+         nbits = n2bits;
+       }
+
+      if (got_signed || got_unsigned)
+       {
+         result_type = (struct type *) obstack_alloc (symbol_obstack,
+                                                      sizeof (struct type));
+         bzero (result_type, sizeof (struct type));
+         TYPE_LENGTH (result_type) = nbits / TARGET_CHAR_BIT;
+         TYPE_MAIN_VARIANT (result_type) = result_type;
+         TYPE_CODE (result_type) = TYPE_CODE_INT;
+         if (got_unsigned)
+           TYPE_FLAGS (result_type) |= TYPE_FLAG_UNSIGNED;
+         return result_type;
+       }
+      else
+       return error_type (pp);
+    }
+
+  /* A type defined as a subrange of itself, with bounds both 0, is void.  */
+  if (self_subrange && n2 == 0 && n3 == 0)
+    return builtin_type_void;
+
+  /* If n3 is zero and n2 is not, we want a floating type,
+     and n2 is the width in bytes.
+
+     Fortran programs appear to use this for complex types also,
+     and they give no way to distinguish between double and single-complex!
+     We don't have complex types, so we would lose on all fortran files!
+     So return type `double' for all of those.  It won't work right
+     for the complex values, but at least it makes the file loadable.  */
+
+  if (n3 == 0 && n2 > 0)
+    {
+      if (n2 == sizeof (float))
+       return builtin_type_float;
+      return builtin_type_double;
+    }
+
+  /* If the upper bound is -1, it must really be an unsigned int.  */
+
+  else if (n2 == 0 && n3 == -1)
+    {
+      if (sizeof (int) == sizeof (long))
+       return builtin_type_unsigned_int;
+      else
+       return builtin_type_unsigned_long;
+    }
+
+  /* Special case: char is defined (Who knows why) as a subrange of
+     itself with range 0-127.  */
+  else if (self_subrange && n2 == 0 && n3 == 127)
+    return builtin_type_char;
+
+  /* Assumptions made here: Subrange of self is equivalent to subrange
+     of int.  */
+  else if (n2 == 0
+          && (self_subrange ||
+              *dbx_lookup_type (rangenums) == builtin_type_int))
+    {
+      /* an unsigned type */
+#ifdef LONG_LONG
+      if (n3 == - sizeof (long long))
+       return builtin_type_unsigned_long_long;
+#endif
+      if (n3 == (unsigned int)~0L)
+       return builtin_type_unsigned_int;
+      if (n3 == (unsigned long)~0L)
+       return builtin_type_unsigned_long;
+      if (n3 == (unsigned short)~0L)
+       return builtin_type_unsigned_short;
+      if (n3 == (unsigned char)~0L)
+       return builtin_type_unsigned_char;
+    }
+#ifdef LONG_LONG
+  else if (n3 == 0 && n2 == -sizeof (long long))
+    return builtin_type_long_long;
+#endif  
+  else if (n2 == -n3 -1)
+    {
+      /* a signed type */
+      if (n3 == (1 << (8 * sizeof (int) - 1)) - 1)
+       return builtin_type_int;
+      if (n3 == (1 << (8 * sizeof (long) - 1)) - 1)
+        return builtin_type_long;
+      if (n3 == (1 << (8 * sizeof (short) - 1)) - 1)
+       return builtin_type_short;
+      if (n3 == (1 << (8 * sizeof (char) - 1)) - 1)
+       return builtin_type_char;
+    }
+
+  /* We have a real range type on our hands.  Allocate space and
+     return a real pointer.  */
+
+  /* At this point I don't have the faintest idea how to deal with
+     a self_subrange type; I'm going to assume that this is used
+     as an idiom, and that all of them are special cases.  So . . .  */
+  if (self_subrange)
+    return error_type (pp);
+
+  result_type = (struct type *) obstack_alloc (symbol_obstack,
+                                              sizeof (struct type));
+  bzero (result_type, sizeof (struct type));
+
+  TYPE_TARGET_TYPE (result_type) = (self_subrange ?
+                                   builtin_type_int :
+                                   *dbx_lookup_type(rangenums));
+
+  /* We have to figure out how many bytes it takes to hold this
+     range type.  I'm going to assume that anything that is pushing
+     the bounds of a long was taken care of above.  */
+  if (n2 >= MIN_OF_TYPE(char) && n3 <= MAX_OF_TYPE(char))
+    TYPE_LENGTH (result_type) = 1;
+  else if (n2 >= MIN_OF_TYPE(short) && n3 <= MAX_OF_TYPE(short))
+    TYPE_LENGTH (result_type) = sizeof (short);
+  else if (n2 >= MIN_OF_TYPE(int) && n3 <= MAX_OF_TYPE(int))
+    TYPE_LENGTH (result_type) = sizeof (int);
+  else if (n2 >= MIN_OF_TYPE(long) && n3 <= MAX_OF_TYPE(long))
+    TYPE_LENGTH (result_type) = sizeof (long);
+  else
+    /* Ranged type doesn't fit within known sizes.  */
+    return error_type (pp);
+
+  TYPE_LENGTH (result_type) = TYPE_LENGTH (TYPE_TARGET_TYPE (result_type));
+  TYPE_CODE (result_type) = TYPE_CODE_RANGE;
+  TYPE_NFIELDS (result_type) = 2;
+  TYPE_FIELDS (result_type) =
+    (struct field *) obstack_alloc (symbol_obstack,
+                                   2 * sizeof (struct field));
+  bzero (TYPE_FIELDS (result_type), 2 * sizeof (struct field));
+  TYPE_FIELD_BITPOS (result_type, 0) = n2;
+  TYPE_FIELD_BITPOS (result_type, 1) = n3;
+
+  return result_type;
+}
+
+/* Read a number from the string pointed to by *PP.
+   The value of *PP is advanced over the number.
+   If END is nonzero, the character that ends the
+   number must match END, or an error happens;
+   and that character is skipped if it does match.
+   If END is zero, *PP is left pointing to that character.  */
+
+static long
+read_number (pp, end)
+     char **pp;
+     int end;
+{
+  register char *p = *pp;
+  register long n = 0;
+  register int c;
+  int sign = 1;
+
+  /* Handle an optional leading minus sign.  */
+
+  if (*p == '-')
+    {
+      sign = -1;
+      p++;
+    }
+
+  /* Read the digits, as far as they go.  */
+
+  while ((c = *p++) >= '0' && c <= '9')
+    {
+      n *= 10;
+      n += c - '0';
+    }
+  if (end)
+    {
+      if (c && c != end)
+       error ("Invalid symbol data: invalid character \\%03o at symbol pos %d.", c, symnum);
+    }
+  else
+    --p;
+
+  *pp = p;
+  return n * sign;
+}
+
+/* Read in an argument list.  This is a list of types, separated by commas
+   and terminated with END.  Return the list of types read in, or (struct type
+   **)-1 if there is an error.  */
+static struct type **
+read_args (pp, end)
+     char **pp;
+     int end;
+{
+  struct type *types[1024], **rval; /* allow for fns of 1023 parameters */
+  int n = 0;
+
+  while (**pp != end)
+    {
+      if (**pp != ',')
+       /* Invalid argument list: no ','.  */
+       return (struct type **)-1;
+      *pp += 1;
+
+      /* Check for and handle cretinous dbx symbol name continuation! */
+      if (**pp == '\\')
+       *pp = next_symbol_text ();
+
+      types[n++] = read_type (pp);
+    }
+  *pp += 1;                    /* get past `end' (the ':' character) */
+
+  if (n == 1)
+    {
+      rval = (struct type **) xmalloc (2 * sizeof (struct type *));
+    }
+  else if (TYPE_CODE (types[n-1]) != TYPE_CODE_VOID)
+    {
+      rval = (struct type **) xmalloc ((n + 1) * sizeof (struct type *));
+      bzero (rval + n, sizeof (struct type *));
+    }
+  else
+    {
+      rval = (struct type **) xmalloc (n * sizeof (struct type *));
+    }
+  bcopy (types, rval, n * sizeof (struct type *));
+  return rval;
+}
+\f
+/* Copy a pending list, used to record the contents of a common
+   block for later fixup.  */
+static struct pending *
+copy_pending (beg, begi, end)
+    struct pending *beg, *end;
+    int begi;
+{
+  struct pending *new = 0;
+  struct pending *next;
+
+  for (next = beg; next != 0 && (next != end || begi < end->nsyms);
+       next = next->next, begi = 0)
+    {
+      register int j;
+      for (j = begi; j < next->nsyms; j++)
+       add_symbol_to_list (next->symbol[j], &new);
+    }
+  return new;
+}
+
+/* Add a common block's start address to the offset of each symbol
+   declared to be in it (by being between a BCOMM/ECOMM pair that uses
+   the common block name).  */
+
+static void
+fix_common_block (sym, valu)
+    struct symbol *sym;
+    int valu;
+{
+  struct pending *next = (struct pending *) SYMBOL_NAMESPACE (sym);
+  for ( ; next; next = next->next)
+    {
+      register int j;
+      for (j = next->nsyms - 1; j >= 0; j--)
+       SYMBOL_VALUE_ADDRESS (next->symbol[j]) += valu;
+    }
+}
+\f
+/* Register our willingness to decode symbols for SunOS and a.out and
+   b.out files handled by BFD... */
+static struct sym_fns sunos_sym_fns = {"sunOs", 6,
+              dbx_new_init, dbx_symfile_init,
+              dbx_symfile_read, dbx_symfile_discard};
+
+static struct sym_fns aout_sym_fns = {"a.out", 5,
+              dbx_new_init, dbx_symfile_init,
+              dbx_symfile_read, dbx_symfile_discard};
+
+static struct sym_fns bout_sym_fns = {"b.out", 5,
+              dbx_new_init, dbx_symfile_init,
+              dbx_symfile_read, dbx_symfile_discard};
+
+void
+_initialize_dbxread ()
+{
+  add_symtab_fns(&sunos_sym_fns);
+  add_symtab_fns(&aout_sym_fns);
+  add_symtab_fns(&bout_sym_fns);
+
+  undef_types_allocated = 20;
+  undef_types_length = 0;
+  undef_types = (struct type **) xmalloc (undef_types_allocated *
+                                         sizeof (struct type *));
+}
diff --git a/gdb/defs.h b/gdb/defs.h
new file mode 100644 (file)
index 0000000..51a46b4
--- /dev/null
@@ -0,0 +1,173 @@
+/* Basic definitions for GDB, the GNU debugger.
+   Copyright (C) 1986, 1989, 1991 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.  */
+
+/* An address in the program being debugged.  Host byte order.  */
+typedef unsigned int CORE_ADDR;
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#define max(a, b) ((a) > (b) ? (a) : (b))
+
+/* The character C++ uses to build identifiers that must be unique from
+   the program's identifiers (such as $this and $$vptr).  */
+#define CPLUS_MARKER '$'       /* May be overridden to '.' for SysV */
+
+/*
+ * Allow things in gdb to be declared "const".  If compiling ANSI, it
+ * just works.  If compiling with gcc but non-ansi, redefine to __const__.
+ * If non-ansi, non-gcc, then eliminate "const" entirely, making those
+ * objects be read-write rather than read-only.
+ */
+#ifndef __STDC__
+# ifdef __GNUC__
+#  define const __const__
+#  define volatile __volatile__
+# else
+#  define const /*nothing*/
+#  define volatile /*nothing*/
+# endif /* GNUC */
+#endif /* STDC */
+
+extern char *savestring ();
+extern char *strsave ();
+extern char *concat ();
+#ifdef __STDC__
+extern void *xmalloc (), *xrealloc ();
+#else
+extern char *xmalloc (), *xrealloc ();
+#endif
+extern void free ();
+extern int parse_escape ();
+extern char *reg_names[];
+/* Indicate that these routines do not return to the caller.  */
+extern volatile void error(), fatal();
+
+/* Various possibilities for alloca.  */
+#ifdef __GNUC__
+# define alloca __builtin_alloca
+#else
+# ifdef sparc
+#  include <alloca.h>
+# endif
+  extern char *alloca ();
+# endif
+
+extern int errno;                      /* System call error return status */
+
+extern int quit_flag;
+extern int immediate_quit;
+extern void quit ();
+
+#define QUIT { if (quit_flag) quit (); }
+
+/* Notes on classes: class_alias is for alias commands which are not
+   abbreviations of the original command.  */
+
+enum command_class
+{
+  /* Special args to help_list */
+  all_classes = -2, all_commands = -1,
+  /* Classes of commands */
+  no_class = -1, class_run = 0, class_vars, class_stack,
+  class_files, class_support, class_info, class_breakpoint,
+  class_alias, class_obscure, class_user
+};
+
+/* the cleanup list records things that have to be undone
+   if an error happens (descriptors to be closed, memory to be freed, etc.)
+   Each link in the chain records a function to call and an
+   argument to give it.
+
+   Use make_cleanup to add an element to the cleanup chain.
+   Use do_cleanups to do all cleanup actions back to a given
+   point in the chain.  Use discard_cleanups to remove cleanups
+   from the chain back to a given point, not doing them.  */
+
+struct cleanup
+{
+  struct cleanup *next;
+  void (*function) ();
+  int arg;
+};
+
+/* From utils.c.  */
+extern void do_cleanups ();
+extern void discard_cleanups ();
+extern struct cleanup *make_cleanup ();
+extern struct cleanup *save_cleanups ();
+extern void restore_cleanups ();
+extern void free_current_contents ();
+extern int myread ();
+extern int query ();
+extern int lines_to_list ();
+extern void reinitialize_more_filter ();
+extern void fputs_filtered ();
+extern void puts_filtered ();
+extern void fprintf_filtered ();
+extern void printf_filtered ();
+extern void print_spaces ();
+extern void print_spaces_filtered ();
+extern char *n_spaces ();
+extern void printchar ();
+extern void fprint_symbol ();
+extern void fputs_demangled ();
+extern void perror_with_name ();
+extern void print_sys_errmsg ();
+
+/* From printcmd.c */
+extern void print_address_symbolic ();
+extern void print_address ();
+
+/* From readline (but not in any readline .h files).  */
+extern char *tilde_expand ();
+
+/* Structure for saved commands lines
+   (for breakpoints, defined commands, etc).  */
+
+struct command_line
+{
+  struct command_line *next;
+  char *line;
+};
+
+extern struct command_line *read_command_lines ();
+extern void free_command_lines ();
+
+/* String containing the current directory (what getwd would return).  */
+
+char *current_directory;
+
+/* Default radixes for input and output.  Only some values supported.  */
+extern unsigned input_radix;
+extern unsigned output_radix;
+
+/* Baud rate specified for communication with serial target systems.  */
+char *baud_rate;
+
+#if !defined (UINT_MAX)
+#define UINT_MAX 0xffffffff
+#endif
+
+#if !defined (LONG_MAX)
+#define LONG_MAX 0x7fffffff
+#endif
+
+/* Just like CHAR_BIT in <limits.h> but describes the target machine.  */
+#if !defined (TARGET_CHAR_BIT)
+#define TARGET_CHAR_BIT 8
+#endif
diff --git a/gdb/environ.c b/gdb/environ.c
new file mode 100644 (file)
index 0000000..4109472
--- /dev/null
@@ -0,0 +1,187 @@
+/* environ.c -- library for manipulating environments for GNU.
+   Copyright (C) 1986, 1989 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 1, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#define max(a, b) ((a) > (b) ? (a) : (b))
+
+#include "environ.h"
+#include <string.h>
+
+extern char *xmalloc ();
+extern char *xrealloc ();
+extern void free ();
+\f
+/* Return a new environment object.  */
+
+struct environ *
+make_environ ()
+{
+  register struct environ *e;
+
+  e = (struct environ *) xmalloc (sizeof (struct environ));
+
+  e->allocated = 10;
+  e->vector = (char **) xmalloc ((e->allocated + 1) * sizeof (char *));
+  e->vector[0] = 0;
+  return e;
+}
+
+/* Free an environment and all the strings in it.  */
+
+void
+free_environ (e)
+     register struct environ *e;
+{
+  register char **vector = e->vector;
+
+  while (*vector)
+    free (*vector++);
+
+  free (e);
+}
+
+/* Copy the environment given to this process into E.
+   Also copies all the strings in it, so we can be sure
+   that all strings in these environments are safe to free.  */
+
+void
+init_environ (e)
+     register struct environ *e;
+{
+  extern char **environ;
+  register int i;
+
+  for (i = 0; environ[i]; i++) /*EMPTY*/;
+
+  if (e->allocated < i)
+    {
+      e->allocated = max (i, e->allocated + 10);
+      e->vector = (char **) xrealloc ((char *)e->vector,
+                                     (e->allocated + 1) * sizeof (char *));
+    }
+
+  bcopy (environ, e->vector, (i + 1) * sizeof (char *));
+
+  while (--i >= 0)
+    {
+      register int len = strlen (e->vector[i]);
+      register char *new = (char *) xmalloc (len + 1);
+      bcopy (e->vector[i], new, len + 1);
+      e->vector[i] = new;
+    }
+}
+
+/* Return the vector of environment E.
+   This is used to get something to pass to execve.  */
+
+char **
+environ_vector (e)
+     struct environ *e;
+{
+  return e->vector;
+}
+\f
+/* Return the value in environment E of variable VAR.  */
+
+char *
+get_in_environ (e, var)
+     struct environ *e;
+     char *var;
+{
+  register int len = strlen (var);
+  register char **vector = e->vector;
+  register char *s;
+
+  for (; s = *vector; vector++)
+    if (!strncmp (s, var, len)
+       && s[len] == '=')
+      return &s[len + 1];
+
+  return 0;
+}
+
+/* Store the value in E of VAR as VALUE.  */
+
+void
+set_in_environ (e, var, value)
+     struct environ *e;
+     char *var;
+     char *value;
+{
+  register int i;
+  register int len = strlen (var);
+  register char **vector = e->vector;
+  register char *s;
+
+  for (i = 0; s = vector[i]; i++)
+    if (!strncmp (s, var, len)
+       && s[len] == '=')
+      break;
+
+  if (s == 0)
+    {
+      if (i == e->allocated)
+       {
+         e->allocated += 10;
+         vector = (char **) xrealloc ((char *)vector,
+                                      (e->allocated + 1) * sizeof (char *));
+         e->vector = vector;
+       }
+      vector[i + 1] = 0;
+    }
+  else
+    free (s);
+
+  s = (char *) xmalloc (len + strlen (value) + 2);
+  strcpy (s, var);
+  strcat (s, "=");
+  strcat (s, value);
+  vector[i] = s;
+
+  /* Certain variables get exported back to the parent (e.g. our) 
+     environment, too.  */
+  if (!strcmp(var, "PATH")                     /* Object file location */
+   || !strcmp (var, "G960BASE")                /* Intel 960 downloads */
+   || !strcmp (var, "G960BIN")                         /* Intel 960 downloads */
+                               ) {
+    putenv (strsave (s));
+  }
+  return;
+}
+
+/* Remove the setting for variable VAR from environment E.  */
+
+void
+unset_in_environ (e, var)
+     struct environ *e;
+     char *var;
+{
+  register int len = strlen (var);
+  register char **vector = e->vector;
+  register char *s;
+
+  for (; s = *vector; vector++)
+    if (!strncmp (s, var, len)
+       && s[len] == '=')
+      {
+       free (s);
+       bcopy (vector + 1, vector,
+              (e->allocated - (vector - e->vector)) * sizeof (char *));
+       e->vector[e->allocated - 1] = 0;
+       return;
+      }
+}
diff --git a/gdb/environ.h b/gdb/environ.h
new file mode 100644 (file)
index 0000000..13f31f4
--- /dev/null
@@ -0,0 +1,39 @@
+/* Header for environment manipulation library.
+   Copyright (C) 1989, Free Software Foundation.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 1, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* We manipulate environments represented as these structures.  */
+
+struct environ
+{
+  /* Number of usable slots allocated in VECTOR.
+     VECTOR always has one slot not counted here,
+     to hold the terminating zero.  */
+  int allocated;
+  /* A vector of slots, ALLOCATED + 1 of them.
+     The first few slots contain strings "VAR=VALUE"
+     and the next one contains zero.
+     Then come some unused slots.  */
+  char **vector;
+};
+
+struct environ *make_environ ();
+void free_environ ();
+void init_environ ();
+char *get_in_environ ();
+void set_in_environ ();
+void unset_in_environ ();
+char **environ_vector ();
diff --git a/gdb/eval.c b/gdb/eval.c
new file mode 100644 (file)
index 0000000..0cf5cbf
--- /dev/null
@@ -0,0 +1,1042 @@
+/* Evaluate expressions for GDB.
+   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.  */
+
+#include "defs.h"
+#include "param.h"
+#include "symtab.h"
+#include "value.h"
+#include "expression.h"
+#include "target.h"
+
+#define        NULL_TYPE       ((struct type *)0)
+
+\f
+/* Parse the string EXP as a C expression, evaluate it,
+   and return the result as a number.  */
+
+CORE_ADDR
+parse_and_eval_address (exp)
+     char *exp;
+{
+  struct expression *expr = parse_c_expression (exp);
+  register CORE_ADDR addr;
+  register struct cleanup *old_chain
+    = make_cleanup (free_current_contents, &expr);
+
+  addr = (CORE_ADDR) value_as_long (evaluate_expression (expr));
+  do_cleanups (old_chain);
+  return addr;
+}
+
+/* Like parse_and_eval_address but takes a pointer to a char * variable
+   and advanced that variable across the characters parsed.  */
+
+CORE_ADDR
+parse_and_eval_address_1 (expptr)
+     char **expptr;
+{
+  struct expression *expr = parse_c_1 (expptr, 0, 0);
+  register CORE_ADDR addr;
+  register struct cleanup *old_chain
+    = make_cleanup (free_current_contents, &expr);
+
+  addr = (CORE_ADDR) value_as_long (evaluate_expression (expr));
+  do_cleanups (old_chain);
+  return addr;
+}
+
+value
+parse_and_eval (exp)
+     char *exp;
+{
+  struct expression *expr = parse_c_expression (exp);
+  register value val;
+  register struct cleanup *old_chain
+    = make_cleanup (free_current_contents, &expr);
+
+  val = evaluate_expression (expr);
+  do_cleanups (old_chain);
+  return val;
+}
+
+/* Parse up to a comma (or to a closeparen)
+   in the string EXPP as an expression, evaluate it, and return the value.
+   EXPP is advanced to point to the comma.  */
+
+value
+parse_to_comma_and_eval (expp)
+     char **expp;
+{
+  struct expression *expr = parse_c_1 (expp, 0, 1);
+  register value val;
+  register struct cleanup *old_chain
+    = make_cleanup (free_current_contents, &expr);
+
+  val = evaluate_expression (expr);
+  do_cleanups (old_chain);
+  return val;
+}
+\f
+/* Evaluate an expression in internal prefix form
+   such as is constructed by expread.y.
+
+   See expression.h for info on the format of an expression.  */
+
+static value evaluate_subexp ();
+static value evaluate_subexp_for_address ();
+static value evaluate_subexp_for_sizeof ();
+static value evaluate_subexp_with_coercion ();
+
+/* Values of NOSIDE argument to eval_subexp.  */
+enum noside
+{ EVAL_NORMAL,
+  EVAL_SKIP,                   /* Only effect is to increment pos.  */
+  EVAL_AVOID_SIDE_EFFECTS,     /* Don't modify any variables or
+                                  call any functions.  The value
+                                  returned will have the correct
+                                  type, and will have an
+                                  approximately correct lvalue
+                                  type (inaccuracy: anything that is
+                                  listed as being in a register in
+                                  the function in which it was
+                                  declared will be lval_register).  */
+};
+
+value
+evaluate_expression (exp)
+     struct expression *exp;
+{
+  int pc = 0;
+  return evaluate_subexp (NULL_TYPE, exp, &pc, EVAL_NORMAL);
+}
+
+/* Evaluate an expression, avoiding all memory references
+   and getting a value whose type alone is correct.  */
+
+value
+evaluate_type (exp)
+     struct expression *exp;
+{
+  int pc = 0;
+  return evaluate_subexp (NULL_TYPE, exp, &pc, EVAL_AVOID_SIDE_EFFECTS);
+}
+
+static value
+evaluate_subexp (expect_type, exp, pos, noside)
+     struct type *expect_type;
+     register struct expression *exp;
+     register int *pos;
+     enum noside noside;
+{
+  enum exp_opcode op;
+  int tem;
+  register int pc, pc2, oldpos;
+  register value arg1, arg2, arg3;
+  int nargs;
+  value *argvec;
+
+  pc = (*pos)++;
+  op = exp->elts[pc].opcode;
+
+  switch (op)
+    {
+    case OP_SCOPE:
+      tem = strlen (&exp->elts[pc + 2].string);
+      (*pos) += 3 + ((tem + sizeof (union exp_element))
+                    / sizeof (union exp_element));
+      return value_static_field (exp->elts[pc + 1].type,
+                                &exp->elts[pc + 2].string, -1);
+
+    case OP_LONG:
+      (*pos) += 3;
+      return value_from_long (exp->elts[pc + 1].type,
+                             exp->elts[pc + 2].longconst);
+
+    case OP_DOUBLE:
+      (*pos) += 3;
+      return value_from_double (exp->elts[pc + 1].type,
+                               exp->elts[pc + 2].doubleconst);
+
+    case OP_VAR_VALUE:
+      (*pos) += 2;
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      if (noside == EVAL_AVOID_SIDE_EFFECTS)
+       {
+         struct symbol * sym = exp->elts[pc + 1].symbol;
+         enum lval_type lv;
+
+         switch (SYMBOL_CLASS (sym))
+           {
+           case LOC_CONST:
+           case LOC_LABEL:
+           case LOC_CONST_BYTES:
+             lv = not_lval;
+             break;
+
+           case LOC_REGISTER:
+           case LOC_REGPARM:
+             lv = lval_register;
+             break;
+
+           default:
+             lv = lval_memory;
+             break;
+           }
+
+         return value_zero (SYMBOL_TYPE (sym), lv);
+       }
+      else
+       return value_of_variable (exp->elts[pc + 1].symbol);
+
+    case OP_LAST:
+      (*pos) += 2;
+      return access_value_history ((int) exp->elts[pc + 1].longconst);
+
+    case OP_REGISTER:
+      (*pos) += 2;
+      return value_of_register ((int) exp->elts[pc + 1].longconst);
+
+    case OP_INTERNALVAR:
+      (*pos) += 2;
+      return value_of_internalvar (exp->elts[pc + 1].internalvar);
+
+    case OP_STRING:
+      tem = strlen (&exp->elts[pc + 1].string);
+      (*pos) += 2 + ((tem + sizeof (union exp_element))
+                    / sizeof (union exp_element));
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      return value_string (&exp->elts[pc + 1].string, tem);
+
+    case TERNOP_COND:
+      /* Skip third and second args to evaluate the first one.  */
+      arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      if (value_zerop (arg1))
+       {
+         evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP);
+         return evaluate_subexp (NULL_TYPE, exp, pos, noside);
+       }
+      else
+       {
+         arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+         evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP);
+         return arg2;
+       }
+
+    case OP_FUNCALL:
+      (*pos) += 2;
+      op = exp->elts[*pos].opcode;
+      if (op == STRUCTOP_MEMBER || op == STRUCTOP_MPTR)
+       {
+         int fnptr;
+
+         nargs = (int) exp->elts[pc + 1].longconst + 1;
+         /* First, evaluate the structure into arg2 */
+         pc2 = (*pos)++;
+
+         if (noside == EVAL_SKIP)
+           goto nosideret;
+
+         if (op == STRUCTOP_MEMBER)
+           {
+             arg2 = evaluate_subexp_for_address (exp, pos, noside);
+           }
+         else
+           {
+             arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+           }
+
+         /* If the function is a virtual function, then the
+            aggregate value (providing the structure) plays
+            its part by providing the vtable.  Otherwise,
+            it is just along for the ride: call the function
+            directly.  */
+
+         arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+
+         fnptr = (int) value_as_long (arg1);
+         if (fnptr < 128)
+           {
+             struct type *basetype;
+             int i, j;
+             basetype = TYPE_TARGET_TYPE (VALUE_TYPE (arg2));
+             basetype = TYPE_VPTR_BASETYPE (basetype);
+             for (i = TYPE_NFN_FIELDS (basetype) - 1; i >= 0; i--)
+               {
+                 struct fn_field *f = TYPE_FN_FIELDLIST1 (basetype, i);
+                 /* If one is virtual, then all are virtual.  */
+                 if (TYPE_FN_FIELD_VIRTUAL_P (f, 0))
+                   for (j = TYPE_FN_FIELDLIST_LENGTH (basetype, i) - 1; j >= 0; --j)
+                     if (TYPE_FN_FIELD_VOFFSET (f, j) == fnptr)
+                       {
+                         value vtbl;
+                         value base = value_ind (arg2);
+                         struct type *fntype = lookup_pointer_type (TYPE_FN_FIELD_TYPE (f, j));
+
+                         if (TYPE_VPTR_FIELDNO (basetype) < 0)
+                           TYPE_VPTR_FIELDNO (basetype)
+                             = fill_in_vptr_fieldno (basetype);
+
+                         VALUE_TYPE (base) = basetype;
+                         vtbl = value_field (base, TYPE_VPTR_FIELDNO (basetype));
+                         VALUE_TYPE (vtbl) = lookup_pointer_type (fntype);
+                         VALUE_TYPE (arg1) = builtin_type_int;
+                         arg1 = value_subscript (vtbl, arg1);
+                         VALUE_TYPE (arg1) = fntype;
+                         goto got_it;
+                       }
+               }
+             if (i < 0)
+               error ("virtual function at index %d not found", fnptr);
+           }
+         else
+           {
+             VALUE_TYPE (arg1) = lookup_pointer_type (TYPE_TARGET_TYPE (VALUE_TYPE (arg1)));
+           }
+       got_it:
+
+         /* Now, say which argument to start evaluating from */
+         tem = 2;
+       }
+      else if (op == STRUCTOP_STRUCT || op == STRUCTOP_PTR)
+       {
+         /* Hair for method invocations */
+         int tem2;
+
+         nargs = (int) exp->elts[pc + 1].longconst + 1;
+         /* First, evaluate the structure into arg2 */
+         pc2 = (*pos)++;
+         tem2 = strlen (&exp->elts[pc2 + 1].string);
+         *pos += 2 + (tem2 + sizeof (union exp_element)) / sizeof (union exp_element);
+         if (noside == EVAL_SKIP)
+           goto nosideret;
+
+         if (op == STRUCTOP_STRUCT)
+           {
+             arg2 = evaluate_subexp_for_address (exp, pos, noside);
+           }
+         else
+           {
+             arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+           }
+         /* Now, say which argument to start evaluating from */
+         tem = 2;
+       }
+      else
+       {
+         nargs = (int) exp->elts[pc + 1].longconst;
+         tem = 0;
+       }
+      argvec = (value *) alloca (sizeof (value) * (nargs + 2));
+      for (; tem <= nargs; tem++)
+       /* Ensure that array expressions are coerced into pointer objects. */
+       argvec[tem] = evaluate_subexp_with_coercion (exp, pos, noside);
+
+      /* signal end of arglist */
+      argvec[tem] = 0;
+
+      if (op == STRUCTOP_STRUCT || op == STRUCTOP_PTR)
+       {
+         int static_memfuncp;
+         value temp = arg2;
+
+         argvec[1] = arg2;
+         argvec[0] =
+           value_struct_elt (&temp, argvec+1, &exp->elts[pc2 + 1].string,
+                             &static_memfuncp,
+                             op == STRUCTOP_STRUCT
+                             ? "structure" : "structure pointer");
+         if (VALUE_OFFSET (temp))
+           {
+             arg2 = value_from_long (builtin_type_long,
+                                     value_as_long (arg2)+VALUE_OFFSET (temp));
+             VALUE_TYPE (arg2) = lookup_pointer_type (VALUE_TYPE (temp));
+             argvec[1] = arg2;
+           }
+         if (static_memfuncp)
+           {
+             argvec[1] = argvec[0];
+             nargs--;
+             argvec++;
+           }
+       }
+      else if (op == STRUCTOP_MEMBER || op == STRUCTOP_MPTR)
+       {
+         argvec[1] = arg2;
+         argvec[0] = arg1;
+       }
+
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      if (noside == EVAL_AVOID_SIDE_EFFECTS)
+       {
+         /* If the return type doesn't look like a function type, call an
+            error.  This can happen if somebody tries to turn a variable into
+            a function call. This is here because people often want to
+            call, eg, strcmp, which gdb doesn't know is a function.  If
+            gdb isn't asked for it's opinion (ie. through "whatis"),
+            it won't offer it. */
+
+         struct type *ftype =
+           TYPE_TARGET_TYPE (VALUE_TYPE (argvec[0]));
+
+         if (ftype)
+           return allocate_value (TYPE_TARGET_TYPE (VALUE_TYPE (argvec[0])));
+         else
+           error ("Expression of type other than \"Function returning ...\" used as function");
+       }
+      return target_call_function (argvec[0], nargs, argvec + 1);
+
+    case STRUCTOP_STRUCT:
+      tem = strlen (&exp->elts[pc + 1].string);
+      (*pos) += 2 + ((tem + sizeof (union exp_element))
+                    / sizeof (union exp_element));
+      arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      if (noside == EVAL_AVOID_SIDE_EFFECTS)
+       return value_zero (lookup_struct_elt_type (VALUE_TYPE (arg1),
+                                                  &exp->elts[pc + 1].string),
+                          lval_memory);
+      else
+       {
+         value temp = arg1;
+         return value_struct_elt (&temp, (value *)0, &exp->elts[pc + 1].string,
+                                  (int *) 0, "structure");
+       }
+
+    case STRUCTOP_PTR:
+      tem = strlen (&exp->elts[pc + 1].string);
+      (*pos) += 2 + (tem + sizeof (union exp_element)) / sizeof (union exp_element);
+      arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      if (noside == EVAL_AVOID_SIDE_EFFECTS)
+       return value_zero (lookup_struct_elt_type (TYPE_TARGET_TYPE
+                                                  (VALUE_TYPE (arg1)),
+                                                  &exp->elts[pc + 1].string),
+                          lval_memory);
+      else
+       {
+         value temp = arg1;
+         return value_struct_elt (&temp, (value *)0, &exp->elts[pc + 1].string,
+                                  (int *) 0, "structure pointer");
+       }
+
+    case STRUCTOP_MEMBER:
+      arg1 = evaluate_subexp_for_address (exp, pos, noside);
+      arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      /* Now, convert these values to an address.  */
+      if (TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_PTR
+         || ((TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (arg2)))
+              != TYPE_CODE_MEMBER)
+             && (TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (arg2)))
+                 != TYPE_CODE_METHOD)))
+       error ("non-pointer-to-member value used in pointer-to-member construct");
+      arg3 = value_from_long (builtin_type_long,
+                             value_as_long (arg1) + value_as_long (arg2));
+      VALUE_TYPE (arg3) =
+       lookup_pointer_type (TYPE_TARGET_TYPE (TYPE_TARGET_TYPE (VALUE_TYPE (arg2))));
+      return value_ind (arg3);
+
+    case STRUCTOP_MPTR:
+      arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      /* Now, convert these values to an address.  */
+      if (TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_PTR
+         || (TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (arg2))) != TYPE_CODE_MEMBER
+             && TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (arg2))) != TYPE_CODE_METHOD))
+       error ("non-pointer-to-member value used in pointer-to-member construct");
+      arg3 = value_from_long (builtin_type_long,
+                             value_as_long (arg1) + value_as_long (arg2));
+      VALUE_TYPE (arg3) =
+       lookup_pointer_type (TYPE_TARGET_TYPE (TYPE_TARGET_TYPE (VALUE_TYPE (arg2))));
+      return value_ind (arg3);
+
+    case BINOP_ASSIGN:
+      arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside);
+      if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+       return arg1;
+      if (binop_user_defined_p (op, arg1, arg2))
+       return value_x_binop (arg1, arg2, op, 0);
+      else
+       return value_assign (arg1, arg2);
+
+    case BINOP_ASSIGN_MODIFY:
+      (*pos) += 2;
+      arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside);
+      if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+       return arg1;
+      op = exp->elts[pc + 1].opcode;
+      if (binop_user_defined_p (op, arg1, arg2))
+       return value_x_binop (arg1, arg2, BINOP_ASSIGN_MODIFY, op);
+      else if (op == BINOP_ADD)
+       arg2 = value_add (arg1, arg2);
+      else if (op == BINOP_SUB)
+       arg2 = value_sub (arg1, arg2);
+      else
+       arg2 = value_binop (arg1, arg2, op);
+      return value_assign (arg1, arg2);
+
+    case BINOP_ADD:
+      arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
+      arg2 = evaluate_subexp_with_coercion (exp, pos, noside);
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      if (binop_user_defined_p (op, arg1, arg2))
+       return value_x_binop (arg1, arg2, op, 0);
+      else
+       return value_add (arg1, arg2);
+
+    case BINOP_SUB:
+      arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
+      arg2 = evaluate_subexp_with_coercion (exp, pos, noside);
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      if (binop_user_defined_p (op, arg1, arg2))
+       return value_x_binop (arg1, arg2, op, 0);
+      else
+       return value_sub (arg1, arg2);
+
+    case BINOP_MUL:
+    case BINOP_DIV:
+    case BINOP_REM:
+    case BINOP_LSH:
+    case BINOP_RSH:
+    case BINOP_LOGAND:
+    case BINOP_LOGIOR:
+    case BINOP_LOGXOR:
+      arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      if (binop_user_defined_p (op, arg1, arg2))
+       return value_x_binop (arg1, arg2, op, 0);
+      else
+       if (noside == EVAL_AVOID_SIDE_EFFECTS
+           && op == BINOP_DIV)
+         return value_zero (VALUE_TYPE (arg1), not_lval);
+      else
+       return value_binop (arg1, arg2, op);
+
+    case BINOP_SUBSCRIPT:
+      arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
+      arg2 = evaluate_subexp_with_coercion (exp, pos, noside);
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      if (noside == EVAL_AVOID_SIDE_EFFECTS)
+       return value_zero (TYPE_TARGET_TYPE (VALUE_TYPE (arg1)),
+                          VALUE_LVAL (arg1));
+                          
+      if (binop_user_defined_p (op, arg1, arg2))
+       return value_x_binop (arg1, arg2, op, 0);
+      else
+       return value_subscript (arg1, arg2);
+      
+    case BINOP_AND:
+      arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      if (noside == EVAL_SKIP)
+       {
+         arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+         goto nosideret;
+       }
+      
+      oldpos = *pos;
+      arg2 = evaluate_subexp (NULL_TYPE, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
+      *pos = oldpos;
+      
+      if (binop_user_defined_p (op, arg1, arg2)) 
+       {
+         arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+         return value_x_binop (arg1, arg2, op, 0);
+       }
+      else
+       {
+         tem = value_zerop (arg1);
+         arg2 = evaluate_subexp (NULL_TYPE, exp, pos,
+                                 (tem ? EVAL_SKIP : noside));
+         return value_from_long (builtin_type_int,
+                                 (LONGEST) (!tem && !value_zerop (arg2)));
+       }
+
+    case BINOP_OR:
+      arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      if (noside == EVAL_SKIP)
+       {
+         arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+         goto nosideret;
+       }
+      
+      oldpos = *pos;
+      arg2 = evaluate_subexp (NULL_TYPE, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
+      *pos = oldpos;
+      
+      if (binop_user_defined_p (op, arg1, arg2)) 
+       {
+         arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+         return value_x_binop (arg1, arg2, op, 0);
+       }
+      else
+       {
+         tem = value_zerop (arg1);
+         arg2 = evaluate_subexp (NULL_TYPE, exp, pos,
+                                 (!tem ? EVAL_SKIP : noside));
+         return value_from_long (builtin_type_int,
+                                 (LONGEST) (!tem || !value_zerop (arg2)));
+       }
+
+    case BINOP_EQUAL:
+      arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside);
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      if (binop_user_defined_p (op, arg1, arg2))
+       {
+         return value_x_binop (arg1, arg2, op, 0);
+       }
+      else
+       {
+         tem = value_equal (arg1, arg2);
+         return value_from_long (builtin_type_int, (LONGEST) tem);
+       }
+
+    case BINOP_NOTEQUAL:
+      arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside);
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      if (binop_user_defined_p (op, arg1, arg2))
+       {
+         return value_x_binop (arg1, arg2, op, 0);
+       }
+      else
+       {
+         tem = value_equal (arg1, arg2);
+         return value_from_long (builtin_type_int, (LONGEST) ! tem);
+       }
+
+    case BINOP_LESS:
+      arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside);
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      if (binop_user_defined_p (op, arg1, arg2))
+       {
+         return value_x_binop (arg1, arg2, op, 0);
+       }
+      else
+       {
+         tem = value_less (arg1, arg2);
+         return value_from_long (builtin_type_int, (LONGEST) tem);
+       }
+
+    case BINOP_GTR:
+      arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside);
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      if (binop_user_defined_p (op, arg1, arg2))
+       {
+         return value_x_binop (arg1, arg2, op, 0);
+       }
+      else
+       {
+         tem = value_less (arg2, arg1);
+         return value_from_long (builtin_type_int, (LONGEST) tem);
+       }
+
+    case BINOP_GEQ:
+      arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside);
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      if (binop_user_defined_p (op, arg1, arg2))
+       {
+         return value_x_binop (arg1, arg2, op, 0);
+       }
+      else
+       {
+         tem = value_less (arg1, arg2);
+         return value_from_long (builtin_type_int, (LONGEST) ! tem);
+       }
+
+    case BINOP_LEQ:
+      arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside);
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      if (binop_user_defined_p (op, arg1, arg2))
+       {
+         return value_x_binop (arg1, arg2, op, 0);
+       }
+      else 
+       {
+         tem = value_less (arg2, arg1);
+         return value_from_long (builtin_type_int, (LONGEST) ! tem);
+       }
+
+    case BINOP_REPEAT:
+      arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      if (TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_INT)
+       error ("Non-integral right operand for \"@\" operator.");
+      if (noside == EVAL_AVOID_SIDE_EFFECTS)
+       return allocate_repeat_value (VALUE_TYPE (arg1),
+                                      (int) value_as_long (arg2));
+      else
+       return value_repeat (arg1, (int) value_as_long (arg2));
+
+    case BINOP_COMMA:
+      evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      return evaluate_subexp (NULL_TYPE, exp, pos, noside);
+
+    case UNOP_NEG:
+      arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      if (unop_user_defined_p (op, arg1))
+       return value_x_unop (arg1, op);
+      else
+       return value_neg (arg1);
+
+    case UNOP_LOGNOT:
+      arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      if (unop_user_defined_p (op, arg1))
+       return value_x_unop (arg1, op);
+      else
+       return value_lognot (arg1);
+
+    case UNOP_ZEROP:
+      arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      if (unop_user_defined_p (op, arg1))
+       return value_x_unop (arg1, op);
+      else
+       return value_from_long (builtin_type_int,
+                               (LONGEST) value_zerop (arg1));
+
+    case UNOP_IND:
+      if (expect_type && TYPE_CODE (expect_type) == TYPE_CODE_PTR)
+        expect_type = TYPE_TARGET_TYPE (expect_type);
+      arg1 = evaluate_subexp (expect_type, exp, pos, noside);
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      if (noside == EVAL_AVOID_SIDE_EFFECTS)
+       {
+         if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_PTR
+             || TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_REF
+             /* In C you can dereference an array to get the 1st elt.  */
+             || TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_ARRAY
+             )
+           return value_zero (TYPE_TARGET_TYPE (VALUE_TYPE (arg1)),
+                              lval_memory);
+         else if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_INT)
+           /* GDB allows dereferencing an int.  */
+           return value_zero (builtin_type_int, lval_memory);
+         else
+           error ("Attempt to take contents of a non-pointer value.");
+       }
+      return value_ind (arg1);
+
+    case UNOP_ADDR:
+      /* C++: check for and handle pointer to members.  */
+      
+      op = exp->elts[*pos].opcode;
+
+      if (noside == EVAL_SKIP)
+       {
+         if (op == OP_SCOPE)
+           {
+             char *name = &exp->elts[pc+3].string;
+             int temm = strlen (name);
+             (*pos) += 2 + (temm + sizeof (union exp_element)) / sizeof (union exp_element);
+           }
+         else
+           evaluate_subexp (expect_type, exp, pos, EVAL_SKIP);
+         goto nosideret;
+       }
+
+      if (op == OP_SCOPE)
+       {
+         char *name = &exp->elts[pc+3].string;
+         int temm = strlen (name);
+         struct type *domain = exp->elts[pc+2].type;
+         (*pos) += 2 + (temm + sizeof (union exp_element)) / sizeof (union exp_element);
+         arg1 = value_struct_elt_for_address (domain, expect_type, name);
+         if (arg1)
+           return arg1;
+         error ("no field `%s' in structure", name);
+       }
+      else
+       return evaluate_subexp_for_address (exp, pos, noside);
+
+    case UNOP_SIZEOF:
+      if (noside == EVAL_SKIP)
+       {
+         evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP);
+         goto nosideret;
+       }
+      return evaluate_subexp_for_sizeof (exp, pos);
+
+    case UNOP_CAST:
+      (*pos) += 2;
+      arg1 = evaluate_subexp (expect_type, exp, pos, noside);
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      return value_cast (exp->elts[pc + 1].type, arg1);
+
+    case UNOP_MEMVAL:
+      (*pos) += 2;
+      arg1 = evaluate_subexp (expect_type, exp, pos, noside);
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      if (noside == EVAL_AVOID_SIDE_EFFECTS)
+       return value_zero (exp->elts[pc + 1].type, lval_memory);
+      else
+       return value_at_lazy (exp->elts[pc + 1].type,
+                        (CORE_ADDR) value_as_long (arg1));
+
+    case UNOP_PREINCREMENT:
+      arg1 = evaluate_subexp (expect_type, exp, pos, noside);
+      if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+       return arg1;
+      else if (unop_user_defined_p (op, arg1))
+       {
+         return value_x_unop (arg1, op);
+       }
+      else
+       {
+         arg2 = value_add (arg1, value_from_long (builtin_type_char, 
+                                                  (LONGEST) 1));
+         return value_assign (arg1, arg2);
+       }
+
+    case UNOP_PREDECREMENT:
+      arg1 = evaluate_subexp (expect_type, exp, pos, noside);
+      if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+       return arg1;
+      else if (unop_user_defined_p (op, arg1))
+       {
+         return value_x_unop (arg1, op);
+       }
+      else
+       {
+         arg2 = value_sub (arg1, value_from_long (builtin_type_char, 
+                                                  (LONGEST) 1));
+         return value_assign (arg1, arg2);
+       }
+
+    case UNOP_POSTINCREMENT:
+      arg1 = evaluate_subexp (expect_type, exp, pos, noside);
+      if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+       return arg1;
+      else if (unop_user_defined_p (op, arg1))
+       {
+         return value_x_unop (arg1, op);
+       }
+      else
+       {
+         arg2 = value_add (arg1, value_from_long (builtin_type_char, 
+                                                  (LONGEST) 1));
+         value_assign (arg1, arg2);
+         return arg1;
+       }
+
+    case UNOP_POSTDECREMENT:
+      arg1 = evaluate_subexp (expect_type, exp, pos, noside);
+      if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+       return arg1;
+      else if (unop_user_defined_p (op, arg1))
+       {
+         return value_x_unop (arg1, op);
+       }
+      else
+       {
+         arg2 = value_sub (arg1, value_from_long (builtin_type_char, 
+                                                  (LONGEST) 1));
+         value_assign (arg1, arg2);
+         return arg1;
+       }
+       
+    case OP_THIS:
+      (*pos) += 1;
+      return value_of_this (1);
+
+    default:
+      error ("internal error: I do not know how to evaluate what you gave me");
+    }
+
+ nosideret:
+  return value_from_long (builtin_type_long, (LONGEST) 1);
+}
+\f
+/* Evaluate a subexpression of EXP, at index *POS,
+   and return the address of that subexpression.
+   Advance *POS over the subexpression.
+   If the subexpression isn't an lvalue, get an error.
+   NOSIDE may be EVAL_AVOID_SIDE_EFFECTS;
+   then only the type of the result need be correct.  */
+
+static value
+evaluate_subexp_for_address (exp, pos, noside)
+     register struct expression *exp;
+     register int *pos;
+     enum noside noside;
+{
+  enum exp_opcode op;
+  register int pc;
+
+  pc = (*pos);
+  op = exp->elts[pc].opcode;
+
+  switch (op)
+    {
+    case UNOP_IND:
+      (*pos)++;
+      return evaluate_subexp (NULL_TYPE, exp, pos, noside);
+
+    case UNOP_MEMVAL:
+      (*pos) += 3;
+      return value_cast (lookup_pointer_type (exp->elts[pc + 1].type),
+                        evaluate_subexp (NULL_TYPE, exp, pos, noside));
+
+    case OP_VAR_VALUE:
+      (*pos) += 3;
+      if (noside == EVAL_AVOID_SIDE_EFFECTS)
+       {
+         struct type *type =
+           lookup_pointer_type (SYMBOL_TYPE (exp->elts[pc + 1].symbol));
+         enum address_class sym_class =
+           SYMBOL_CLASS (exp->elts[pc + 1].symbol);
+
+         if (sym_class == LOC_CONST
+             || sym_class == LOC_CONST_BYTES
+             || sym_class == LOC_REGISTER
+             || sym_class == LOC_REGPARM)
+           error ("Attempt to take address of register or constant.");
+
+       return
+         value_zero (type, not_lval);
+       }
+      else
+       return locate_var_value (exp->elts[pc + 1].symbol, (CORE_ADDR) 0);
+
+    default:
+      if (noside == EVAL_AVOID_SIDE_EFFECTS)
+       {
+         value x = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+         if (VALUE_LVAL (x) == lval_memory)
+           return value_zero (TYPE_POINTER_TYPE (VALUE_TYPE (x)),
+                              not_lval);
+         else
+           error ("Attempt to take address of non-lval");
+       }
+      return value_addr (evaluate_subexp (NULL_TYPE, exp, pos, noside));
+    }
+}
+
+/* Evaluate like `evaluate_subexp' except coercing arrays to pointers.
+   When used in contexts where arrays will be coerced anyway,
+   this is equivalent to `evaluate_subexp'
+   but much faster because it avoids actually fetching array contents.  */
+
+static value
+evaluate_subexp_with_coercion (exp, pos, noside)
+     register struct expression *exp;
+     register int *pos;
+     enum noside noside;
+{
+  register enum exp_opcode op;
+  register int pc;
+  register value val;
+
+  pc = (*pos);
+  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);
+       }
+      default:
+       return evaluate_subexp (NULL_TYPE, exp, pos, noside);
+    }
+}
+
+/* Evaluate a subexpression of EXP, at index *POS,
+   and return a value for the size of that subexpression.
+   Advance *POS over the subexpression.  */
+
+static value
+evaluate_subexp_for_sizeof (exp, pos)
+     register struct expression *exp;
+     register int *pos;
+{
+  enum exp_opcode op;
+  register int pc;
+  value val;
+
+  pc = (*pos);
+  op = exp->elts[pc].opcode;
+
+  switch (op)
+    {
+      /* This case is handled specially
+        so that we avoid creating a value for the result type.
+        If the result type is very big, it's desirable not to
+        create a value unnecessarily.  */
+    case UNOP_IND:
+      (*pos)++;
+      val = evaluate_subexp (NULL_TYPE, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
+      return value_from_long (builtin_type_int, (LONGEST)
+                     TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (val))));
+
+    case UNOP_MEMVAL:
+      (*pos) += 3;
+      return value_from_long (builtin_type_int, 
+                             (LONGEST) TYPE_LENGTH (exp->elts[pc + 1].type));
+
+    case OP_VAR_VALUE:
+      (*pos) += 3;
+      return value_from_long (builtin_type_int,
+        (LONGEST) TYPE_LENGTH (SYMBOL_TYPE (exp->elts[pc + 1].symbol)));
+
+    default:
+      val = evaluate_subexp (NULL_TYPE, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
+      return value_from_long (builtin_type_int,
+                             (LONGEST) TYPE_LENGTH (VALUE_TYPE (val)));
+    }
+}
diff --git a/gdb/exec.c b/gdb/exec.c
new file mode 100644 (file)
index 0000000..eefe772
--- /dev/null
@@ -0,0 +1,350 @@
+/* Work with executable files, for GDB. 
+   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.  */
+
+#include <stdio.h>
+#include "defs.h"
+#include "param.h"
+#include "frame.h"
+#include "inferior.h"
+#include "target.h"
+
+#ifdef USG
+#include <sys/types.h>
+#endif
+
+#include <sys/param.h>
+#include <fcntl.h>
+
+#include "gdbcore.h"
+
+#ifdef STILL_NEEDED_FOR_DECSTATION
+#include <sys/dir.h>           /* For DECstations */
+#include <sys/user.h>          /* After a.out.h  */
+#include <sys/file.h>
+#endif
+
+#include <sys/stat.h>
+
+extern char *getenv();
+extern void child_create_inferior (), child_attach ();
+extern void symbol_file_command ();
+
+/* The Binary File Descriptor handle for the executable file.  */
+
+bfd *exec_bfd = NULL;
+
+/* The base and bounds of the table of the exec file's sections.  */
+
+struct section_table *exec_sections, *exec_sections_end;
+
+/* Forward decl */
+
+extern struct target_ops exec_ops;
+
+void
+exec_close (quitting)
+     int quitting;
+{
+  if (exec_bfd) {
+    bfd_close (exec_bfd);
+    exec_bfd = NULL;
+  }
+}
+
+void
+exec_file_command (filename, from_tty)
+     char *filename;
+     int from_tty;
+{
+
+  /* Remove any previous exec file.  */
+  unpush_target (&exec_ops);
+
+  /* Now open and digest the file the user requested, if any.  */
+
+  if (filename)
+    {
+      char *scratch_pathname;
+      int scratch_chan;
+      
+      filename = tilde_expand (filename);
+      make_cleanup (free, filename);
+      
+/* FIXME, if writeable is set, open for read/write. */
+      scratch_chan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0,
+                           &scratch_pathname);
+      if (scratch_chan < 0)
+       perror_with_name (filename);
+
+      exec_bfd = bfd_fdopenr (scratch_pathname, NULL, scratch_chan);
+      if (!exec_bfd)
+       error ("Could not open `%s' as an executable file: %s",
+              scratch_pathname, bfd_errmsg (bfd_error));
+      if (!bfd_check_format (exec_bfd, bfd_object))
+       error ("\"%s\": not in executable format: %s.",
+              scratch_pathname, bfd_errmsg (bfd_error));
+
+#if FIXME
+/* This code needs to be incorporated into BFD */
+#ifdef COFF_ENCAPSULATE
+       /* If we have a coff header, it can give us better values for
+          text_start and exec_data_start.  This is particularly useful
+          for remote debugging of embedded systems.  */
+       if (N_FLAGS(exec_aouthdr) & N_FLAGS_COFF_ENCAPSULATE)
+       {
+               struct coffheader ch;
+               int val;
+               val = lseek (execchan, -(sizeof (AOUTHDR) + sizeof (ch)), 1);
+               if (val == -1)
+                       perror_with_name (filename);
+               val = myread (execchan, &ch, sizeof (ch));
+               if (val < 0)
+                       perror_with_name (filename);
+               text_start = ch.text_start;
+               exec_data_start = ch.data_start;
+       } else
+#endif
+              {
+               text_start =
+                 IS_OBJECT_FILE (exec_aouthdr) ? 0 : N_TXTADDR (exec_aouthdr);
+               exec_data_start = IS_OBJECT_FILE (exec_aouthdr)
+                 ? exec_aouthdr.a_text : N_DATADDR (exec_aouthdr);
+       }
+#endif FIXME
+
+      if (build_section_table (exec_bfd, &exec_sections, &exec_sections_end))
+       error ("Can't find the file sections in `%s': %s", 
+               exec_bfd->filename, bfd_errmsg (bfd_error));
+
+      validate_files ();
+
+      push_target (&exec_ops);
+
+      /* Tell display code (if any) about the changed file name.  */
+      if (exec_file_display_hook)
+       (*exec_file_display_hook) (filename);
+    }
+  else if (from_tty)
+    printf ("No exec file now.\n");
+}
+
+/* Set both the exec file and the symbol file, in one command.  
+   What a novelty.  Why did GDB go through four major releases before this
+   command was added?  */
+
+void
+file_command (arg, from_tty)
+     char *arg;
+     int from_tty;
+{
+  /* FIXME, if we lose on reading the symbol file, we should revert
+     the exec file, but that's rough.  */
+  exec_file_command (arg, from_tty);
+  symbol_file_command (arg, from_tty);
+}
+
+\f
+/* Locate all mappable sections of a BFD file.  */
+
+void
+add_to_section_table (abfd, asect, table_pp)
+     bfd *abfd;
+     sec_ptr asect;
+     struct section_table **table_pp;
+{
+  flagword aflag;
+
+  aflag = bfd_get_section_flags (abfd, asect);
+  /* FIXME, we need to handle BSS segment here...it alloc's but doesn't load */
+  if (!(aflag & SEC_LOAD))
+    return;
+  (*table_pp)->sec_ptr = asect;
+  (*table_pp)->addr = bfd_section_vma (abfd, asect);
+  (*table_pp)->endaddr = (*table_pp)->addr + bfd_section_size (abfd, asect);
+  (*table_pp)++;
+}
+
+int
+build_section_table (some_bfd, start, end)
+     bfd *some_bfd;
+     struct section_table **start, **end;
+{
+  unsigned count;
+
+  count = bfd_count_sections (some_bfd);
+  if (count == 0)
+    abort();   /* return 1? */
+  *start = (struct section_table *) xmalloc (count * sizeof (**start));
+  *end = *start;
+  bfd_map_over_sections (some_bfd, add_to_section_table, end);
+  if (*end > *start + count)
+    abort();
+  /* We could realloc the table, but it probably loses for most files.  */
+  return 0;
+}
+\f
+/* Read or write the exec file.
+
+   Args are address within exec file, address within gdb address-space,
+   length, and a flag indicating whether to read or write.
+
+   Result is a length:
+
+       0:    We cannot handle this address and length.
+       > 0:  We have handled N bytes starting at this address.
+             (If N == length, we did it all.)  We might be able
+             to handle more bytes beyond this length, but no
+             promises.
+       < 0:  We cannot handle this address, but if somebody
+             else handles (-N) bytes, we can start from there.
+
+    The same routine is used to handle both core and exec files;
+    we just tail-call it with more arguments to select between them.  */
+
+int
+xfer_memory (memaddr, myaddr, len, write, abfd, sections, sections_end)
+     CORE_ADDR memaddr;
+     char *myaddr;
+     int len;
+     int write;
+     bfd *abfd;
+     struct section_table *sections, *sections_end;
+{
+  boolean res;
+  struct section_table *p;
+  CORE_ADDR nextsectaddr, memend;
+  boolean (*xfer_fn) ();
+
+  if (len <= 0)
+    abort();
+
+  memend = memaddr + len;
+  xfer_fn = write? bfd_set_section_contents: bfd_get_section_contents;
+  nextsectaddr = memend;
+
+  for (p = sections; p < sections_end; p++)
+    {
+      if (p->addr <= memaddr)
+       if (p->endaddr >= memend)
+         {
+           /* Entire transfer is within this section.  */
+           res = xfer_fn (abfd, p->sec_ptr, myaddr, memaddr - p->addr, len);
+           return (res != false)? len: 0;
+         }
+       else if (p->endaddr <= memaddr)
+         {
+           /* This section ends before the transfer starts.  */
+           continue;
+         }
+       else 
+         {
+           /* This section overlaps the transfer.  Just do half.  */
+           len = p->endaddr - memaddr;
+           res = xfer_fn (abfd, p->sec_ptr, myaddr, memaddr - p->addr, len);
+           return (res != false)? len: 0;
+         }
+      else if (p->addr < nextsectaddr)
+       nextsectaddr = p->addr;
+    }
+
+  if (nextsectaddr >= memend)
+    return 0;                          /* We can't help */
+  else
+    return - (nextsectaddr - memaddr); /* Next boundary where we can help */
+}
+
+/* The function called by target_xfer_memory via our target_ops */
+
+int
+exec_xfer_memory (memaddr, myaddr, len, write)
+     CORE_ADDR memaddr;
+     char *myaddr;
+     int len;
+     int write;
+{
+  return xfer_memory (memaddr, myaddr, len, write,
+                     exec_bfd, exec_sections, exec_sections_end);
+}
+
+
+#ifdef FIXME
+#ifdef REG_STACK_SEGMENT
+/* MOVE TO BFD... */
+    /* Pyramids and AM29000s have an extra segment in the virtual address space
+       for the (control) stack of register-window frames.  The AM29000 folk
+       call it the "register stack" rather than the "memory stack".  */
+    else if (memaddr >= reg_stack_start && memaddr < reg_stack_end)
+      {
+       i = min (len, reg_stack_end - memaddr);
+       fileptr = memaddr - reg_stack_start + reg_stack_offset;
+       wanna_xfer = coredata;
+      }
+#endif                         /* REG_STACK_SEGMENT */
+#endif FIXME
+\f
+static void
+exec_files_info ()
+{
+  struct section_table *p;
+
+  printf ("\tExecutable file `%s'.\n", bfd_get_filename(exec_bfd));
+
+  for (p = exec_sections; p < exec_sections_end; p++)
+    printf("\texecutable from 0x%08x to 0x%08x is %s\n",
+       p->addr, p->endaddr,
+       bfd_section_name (exec_bfd, p->sec_ptr));
+}
+
+struct target_ops exec_ops = {
+       "exec", "Local exec file",
+       exec_file_command, exec_close, /* open, close */
+       child_attach, 0, 0, 0, /* attach, detach, resume, wait, */
+       0, 0, /* fetch_registers, store_registers, */
+       0, 0, 0, /* prepare_to_store, conv_to, conv_from, */
+       exec_xfer_memory, exec_files_info,
+       0, 0, /* insert_breakpoint, remove_breakpoint, */
+       0, 0, 0, 0, 0, /* terminal stuff */
+       0, 0, 0, 0, 0, /* kill, load, add_syms, call fn, lookup sym */
+       child_create_inferior,
+       0, /* mourn_inferior */
+       file_stratum, 0, /* next */
+       0, 1, 0, 0, 0,  /* all mem, mem, stack, regs, exec */
+       OPS_MAGIC,              /* Always the last thing */
+};
+
+void
+_initialize_exec()
+{
+
+  add_com ("file", class_files, file_command,
+          "Use FILE as program to be debugged.\n\
+It is read for its symbols, for getting the contents of pure memory,\n\
+and it is the program executed when you use the `run' command.\n\
+If FILE cannot be found as specified, your execution directory path\n\
+($PATH) is searched for a command of that name.\n\
+No arg means to have no executable file and no symbols.");
+
+  add_com ("exec-file", class_files, exec_file_command,
+          "Use FILE as program for getting contents of pure memory.\n\
+If FILE cannot be found as specified, your execution directory path\n\
+is searched for a command of that name.\n\
+No arg means have no executable file.");
+
+  add_target (&exec_ops);
+}
diff --git a/gdb/expprint.c b/gdb/expprint.c
new file mode 100644 (file)
index 0000000..9e1e9d2
--- /dev/null
@@ -0,0 +1,324 @@
+/* Print in infix form a struct expression.
+   Copyright (C) 1986, 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 <stdio.h>
+#include "defs.h"
+#include "symtab.h"
+#include "param.h"
+#include "expression.h"
+#include "value.h"
+
+\f
+/* These codes indicate operator precedences, least tightly binding first.  */
+/* Adding 1 to a precedence value is done for binary operators,
+   on the operand which is more tightly bound, so that operators
+   of equal precedence within that operand will get parentheses.  */
+/* PREC_HYPER and PREC_ABOVE_COMMA are not the precedence of any operator;
+   they are used as the "surrounding precedence" to force
+   various kinds of things to be parenthesized.  */
+enum precedence
+{ PREC_NULL, PREC_COMMA, PREC_ABOVE_COMMA, PREC_ASSIGN, PREC_OR, PREC_AND,
+  PREC_LOGIOR, PREC_LOGAND, PREC_LOGXOR, PREC_EQUAL, PREC_ORDER,
+  PREC_SHIFT, PREC_ADD, PREC_MUL, PREC_REPEAT,
+  PREC_HYPER, PREC_PREFIX, PREC_SUFFIX };
+
+/* Table mapping opcodes into strings for printing operators
+   and precedences of the operators.  */
+
+struct op_print
+{
+  char *string;
+  enum exp_opcode opcode;
+  /* Precedence of operator.  These values are used only by comparisons.  */
+  enum precedence precedence;
+  int right_assoc;
+};
+
+static struct op_print op_print_tab[] =
+  {
+    {",", BINOP_COMMA, PREC_COMMA, 0},
+    {"=", BINOP_ASSIGN, PREC_ASSIGN, 1},
+    {"||", BINOP_OR, PREC_OR, 0},
+    {"&&", BINOP_AND, PREC_AND, 0},
+    {"|", BINOP_LOGIOR, PREC_LOGIOR, 0},
+    {"&", BINOP_LOGAND, PREC_LOGAND, 0},
+    {"^", BINOP_LOGXOR, PREC_LOGXOR, 0},
+    {"==", BINOP_EQUAL, PREC_EQUAL, 0},
+    {"!=", BINOP_NOTEQUAL, PREC_EQUAL, 0},
+    {"<=", BINOP_LEQ, PREC_ORDER, 0},
+    {">=", BINOP_GEQ, PREC_ORDER, 0},
+    {">", BINOP_GTR, PREC_ORDER, 0},
+    {"<", BINOP_LESS, PREC_ORDER, 0},
+    {">>", BINOP_RSH, PREC_SHIFT, 0},
+    {"<<", BINOP_LSH, PREC_SHIFT, 0},
+    {"+", BINOP_ADD, PREC_ADD, 0},
+    {"-", BINOP_SUB, PREC_ADD, 0},
+    {"*", BINOP_MUL, PREC_MUL, 0},
+    {"/", BINOP_DIV, PREC_MUL, 0},
+    {"%", BINOP_REM, PREC_MUL, 0},
+    {"@", BINOP_REPEAT, PREC_REPEAT, 0},
+    {"-", UNOP_NEG, PREC_PREFIX, 0},
+    {"!", UNOP_ZEROP, PREC_PREFIX, 0},
+    {"~", UNOP_LOGNOT, PREC_PREFIX, 0},
+    {"*", UNOP_IND, PREC_PREFIX, 0},
+    {"&", UNOP_ADDR, PREC_PREFIX, 0},
+    {"sizeof ", UNOP_SIZEOF, PREC_PREFIX, 0},
+    {"++", UNOP_PREINCREMENT, PREC_PREFIX, 0},
+    {"--", UNOP_PREDECREMENT, PREC_PREFIX, 0},
+    /* C++  */
+    {"::", BINOP_SCOPE, PREC_PREFIX, 0},
+  };
+\f
+static void print_subexp ();
+
+void
+print_expression (exp, stream)
+     struct expression *exp;
+     FILE *stream;
+{
+  int pc = 0;
+  print_subexp (exp, &pc, stream, PREC_NULL);
+}
+
+/* Print the subexpression of EXP that starts in position POS, on STREAM.
+   PREC is the precedence of the surrounding operator;
+   if the precedence of the main operator of this subexpression is less,
+   parentheses are needed here.  */
+
+static void
+print_subexp (exp, pos, stream, prec)
+     register struct expression *exp;
+     register int *pos;
+     FILE *stream;
+     enum precedence prec;
+{
+  register unsigned tem;
+  register int pc;
+  unsigned nargs;
+  register char *op_str;
+  int assign_modify = 0;
+  enum exp_opcode opcode;
+  enum precedence myprec;
+  /* Set to 1 for a right-associative operator.  */
+  int assoc;
+
+  pc = (*pos)++;
+  opcode = exp->elts[pc].opcode;
+  switch (opcode)
+    {
+    case OP_SCOPE:
+      myprec = PREC_PREFIX;
+      assoc = 0;
+      (*pos) += 2;
+      print_subexp (exp, pos, stream, (int) myprec + assoc);
+      fprintf (stream, " :: ");
+      nargs = strlen (&exp->elts[pc + 2].string);
+      (*pos) += 1 + (nargs + sizeof (union exp_element)) / sizeof (union exp_element);
+
+      fprintf (stream, &exp->elts[pc + 2].string);
+      return;
+
+    case OP_LONG:
+      (*pos) += 3;
+      value_print (value_from_long (exp->elts[pc + 1].type,
+                                   exp->elts[pc + 2].longconst),
+                  stream, 0, Val_no_prettyprint);
+      return;
+
+    case OP_DOUBLE:
+      (*pos) += 3;
+      value_print (value_from_double (exp->elts[pc + 1].type,
+                                     exp->elts[pc + 2].doubleconst),
+                  stream, 0, Val_no_prettyprint);
+      return;
+
+    case OP_VAR_VALUE:
+      (*pos) += 2;
+      fprintf (stream, "%s", SYMBOL_NAME (exp->elts[pc + 1].symbol));
+      return;
+
+    case OP_LAST:
+      (*pos) += 2;
+      fprintf (stream, "$%d", (int) exp->elts[pc + 1].longconst);
+      return;
+
+    case OP_REGISTER:
+      (*pos) += 2;
+      fprintf (stream, "$%s", reg_names[exp->elts[pc + 1].longconst]);
+      return;
+
+    case OP_INTERNALVAR:
+      (*pos) += 2;
+      fprintf (stream, "$%s",
+              internalvar_name (exp->elts[pc + 1].internalvar));
+      return;
+
+    case OP_FUNCALL:
+      (*pos) += 2;
+      nargs = exp->elts[pc + 1].longconst;
+      print_subexp (exp, pos, stream, PREC_SUFFIX);
+      fprintf (stream, " (");
+      for (tem = 0; tem < nargs; tem++)
+       {
+         if (tem != 0)
+           fprintf (stream, ", ");
+         print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
+       }
+      fprintf (stream, ")");
+      return;
+
+    case OP_STRING:
+      nargs = strlen (&exp->elts[pc + 1].string);
+      (*pos) += 2 + (nargs + sizeof (union exp_element)) / sizeof (union exp_element);
+      fprintf (stream, "\"");
+      for (tem = 0; tem < nargs; tem++)
+       printchar ((&exp->elts[pc + 1].string)[tem], stream, '"');
+      fprintf (stream, "\"");
+      return;
+
+    case TERNOP_COND:
+      if ((int) prec > (int) PREC_COMMA)
+       fprintf (stream, "(");
+      /* Print the subexpressions, forcing parentheses
+        around any binary operations within them.
+        This is more parentheses than are strictly necessary,
+        but it looks clearer.  */
+      print_subexp (exp, pos, stream, PREC_HYPER);
+      fprintf (stream, " ? ");
+      print_subexp (exp, pos, stream, PREC_HYPER);
+      fprintf (stream, " : ");
+      print_subexp (exp, pos, stream, PREC_HYPER);
+      if ((int) prec > (int) PREC_COMMA)
+       fprintf (stream, ")");
+      return;
+
+    case STRUCTOP_STRUCT:
+      tem = strlen (&exp->elts[pc + 1].string);
+      (*pos) += 2 + (tem + sizeof (union exp_element)) / sizeof (union exp_element);
+      print_subexp (exp, pos, stream, PREC_SUFFIX);
+      fprintf (stream, ".%s", &exp->elts[pc + 1].string);
+      return;
+
+    case STRUCTOP_PTR:
+      tem = strlen (&exp->elts[pc + 1].string);
+      (*pos) += 2 + (tem + sizeof (union exp_element)) / sizeof (union exp_element);
+      print_subexp (exp, pos, stream, PREC_SUFFIX);
+      fprintf (stream, "->%s", &exp->elts[pc + 1].string);
+      return;
+
+    case BINOP_SUBSCRIPT:
+      print_subexp (exp, pos, stream, PREC_SUFFIX);
+      fprintf (stream, "[");
+      print_subexp (exp, pos, stream, PREC_ABOVE_COMMA);
+      fprintf (stream, "]");
+      return;
+
+    case UNOP_POSTINCREMENT:
+      print_subexp (exp, pos, stream, PREC_SUFFIX);
+      fprintf (stream, "++");
+      return;
+
+    case UNOP_POSTDECREMENT:
+      print_subexp (exp, pos, stream, PREC_SUFFIX);
+      fprintf (stream, "--");
+      return;
+
+    case UNOP_CAST:
+      (*pos) += 2;
+      if ((int) prec > (int) PREC_PREFIX)
+       fprintf (stream, "(");
+      fprintf (stream, "(");
+      type_print (exp->elts[pc + 1].type, "", stream, 0);
+      fprintf (stream, ") ");
+      print_subexp (exp, pos, stream, PREC_PREFIX);
+      if ((int) prec > (int) PREC_PREFIX)
+       fprintf (stream, ")");
+      return;
+
+    case UNOP_MEMVAL:
+      (*pos) += 2;
+      if ((int) prec > (int) PREC_PREFIX)
+       fprintf (stream, "(");
+      fprintf (stream, "{");
+      type_print (exp->elts[pc + 1].type, "", stream, 0);
+      fprintf (stream, "} ");
+      print_subexp (exp, pos, stream, PREC_PREFIX);
+      if ((int) prec > (int) PREC_PREFIX)
+       fprintf (stream, ")");
+      return;
+
+    case BINOP_ASSIGN_MODIFY:
+      opcode = exp->elts[pc + 1].opcode;
+      (*pos) += 2;
+      myprec = PREC_ASSIGN;
+      assoc = 1;
+      assign_modify = 1;
+      for (tem = 0; tem < sizeof op_print_tab / sizeof op_print_tab[0]; tem++)
+       if (op_print_tab[tem].opcode == opcode)
+         {
+           op_str = op_print_tab[tem].string;
+           break;
+         }
+
+    case OP_THIS:
+      ++(*pos);
+      fprintf (stream, "this");
+      return;
+
+    default:
+      for (tem = 0; tem < sizeof op_print_tab / sizeof op_print_tab[0]; tem++)
+       if (op_print_tab[tem].opcode == opcode)
+         {
+           op_str = op_print_tab[tem].string;
+           myprec = op_print_tab[tem].precedence;
+           assoc = op_print_tab[tem].right_assoc;
+           break;
+         }
+    }
+
+  if ((int) myprec < (int) prec)
+    fprintf (stream, "(");
+  if ((int) opcode > (int) BINOP_END)
+    {
+      /* Unary prefix operator.  */
+      fprintf (stream, "%s", op_str);
+      print_subexp (exp, pos, stream, PREC_PREFIX);
+    }
+  else
+    {
+      /* Binary operator.  */
+      /* Print left operand.
+        If operator is right-associative,
+        increment precedence for this operand.  */
+      print_subexp (exp, pos, stream, (int) myprec + assoc);
+      /* Print the operator itself.  */
+      if (assign_modify)
+       fprintf (stream, " %s= ", op_str);
+      else if (op_str[0] == ',')
+       fprintf (stream, "%s ", op_str);
+      else
+       fprintf (stream, " %s ", op_str);
+      /* Print right operand.
+        If operator is left-associative,
+        increment precedence for this operand.  */
+      print_subexp (exp, pos, stream, (int) myprec + !assoc);
+    }
+  if ((int) myprec < (int) prec)
+    fprintf (stream, ")");
+}
diff --git a/gdb/expression.h b/gdb/expression.h
new file mode 100644 (file)
index 0000000..b7a6fff
--- /dev/null
@@ -0,0 +1,200 @@
+/* Definitions for expressions stored in reversed prefix form, for GDB.
+   Copyright (C) 1986, 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.  */
+
+/* Definitions for saved C expressions.  */
+
+/* An expression is represented as a vector of union exp_element's.
+   Each exp_element is an opcode, except that some opcodes cause
+   the following exp_element to be treated as a long or double constant
+   or as a variable.  The opcodes are obeyed, using a stack for temporaries.
+   The value is left on the temporary stack at the end.  */
+
+/* When it is necessary to include a string,
+   it can occupy as many exp_elements as it needs.
+   We find the length of the string using strlen,
+   divide to find out how many exp_elements are used up,
+   and skip that many.  Strings, like numbers, are indicated
+   by the preceding opcode.  */
+
+enum exp_opcode
+{
+/* BINOP_... operate on two values computed by following subexpressions,
+   replacing them by one result value.  They take no immediate arguments.  */
+  BINOP_ADD,           /* + */
+  BINOP_SUB,           /* - */
+  BINOP_MUL,           /* * */
+  BINOP_DIV,           /* / */
+  BINOP_REM,           /* % */
+  BINOP_LSH,           /* << */
+  BINOP_RSH,           /* >> */
+  BINOP_AND,           /* && */
+  BINOP_OR,            /* || */
+  BINOP_LOGAND,                /* & */
+  BINOP_LOGIOR,                /* | */
+  BINOP_LOGXOR,                /* ^ */
+  BINOP_EQUAL,         /* == */
+  BINOP_NOTEQUAL,      /* != */
+  BINOP_LESS,          /* < */
+  BINOP_GTR,           /* > */
+  BINOP_LEQ,           /* <= */
+  BINOP_GEQ,           /* >= */
+  BINOP_REPEAT,                /* @ */
+  BINOP_ASSIGN,                /* = */
+  BINOP_COMMA,         /* , */
+  BINOP_SUBSCRIPT,     /* x[y] */
+  BINOP_EXP,           /* Exponentiation */
+
+/* C++.  */
+  BINOP_MIN,           /* <? */
+  BINOP_MAX,           /* >? */
+  BINOP_SCOPE,         /* :: */
+
+  /* STRUCTOP_MEMBER is used for pointer-to-member constructs.
+     X . * Y translates into X STRUCTOP_MEMBER Y.  */
+  STRUCTOP_MEMBER,
+  /* STRUCTOP_MPTR is used for pointer-to-member constructs
+     when X is a pointer instead of an aggregate.  */
+  STRUCTOP_MPTR,
+/* end of C++.  */
+
+  BINOP_END,
+
+  BINOP_ASSIGN_MODIFY, /* +=, -=, *=, and so on.
+                          The following exp_element is another opcode,
+                          a BINOP_, saying how to modify.
+                          Then comes another BINOP_ASSIGN_MODIFY,
+                          making three exp_elements in total.  */
+
+/* Operates on three values computed by following subexpressions.  */
+  TERNOP_COND,         /* ?: */
+
+/* The OP_... series take immediate following arguments.
+   After the arguments come another OP_... (the same one)
+   so that the grouping can be recognized from the end.  */
+
+/* OP_LONG is followed by a type pointer in the next exp_element
+   and the long constant value in the following exp_element.
+   Then comes another OP_LONG.
+   Thus, the operation occupies four exp_elements.  */
+
+  OP_LONG,
+/* OP_DOUBLE is similar but takes a double constant instead of a long one.  */
+  OP_DOUBLE,
+/* OP_VAR_VALUE takes one struct symbol * in the following exp_element,
+   followed by another OP_VAR_VALUE, making three exp_elements.  */
+  OP_VAR_VALUE,
+/* OP_LAST is followed by an integer in the next exp_element.
+   The integer is zero for the last value printed,
+   or it is the absolute number of a history element.
+   With another OP_LAST at the end, this makes three exp_elements.  */
+  OP_LAST,
+/* OP_REGISTER is followed by an integer in the next exp_element.
+   This is the number of a register to fetch (as an int).
+   With another OP_REGISTER at the end, this makes three exp_elements.  */
+  OP_REGISTER,
+/* OP_INTERNALVAR is followed by an internalvar ptr in the next exp_element.
+   With another OP_INTERNALVAR at the end, this makes three exp_elements.  */
+  OP_INTERNALVAR,
+/* OP_FUNCALL is followed by an integer in the next exp_element.
+   The integer is the number of args to the function call.
+   That many plus one values from following subexpressions
+   are used, the first one being the function.
+   The integer is followed by a repeat of OP_FUNCALL,
+   making three exp_elements.  */
+  OP_FUNCALL,
+/* OP_STRING represents a string constant.
+   Its format is the same as that of a STRUCTOP, but the string
+   data is just made into a string constant when the operation
+   is executed.  */
+  OP_STRING,
+
+/* UNOP_CAST is followed by a type pointer in the next exp_element.
+   With another UNOP_CAST at the end, this makes three exp_elements.
+   It casts the value of the following subexpression.  */
+  UNOP_CAST,
+/* UNOP_MEMVAL is followed by a type pointer in the next exp_element
+   With another UNOP_MEMVAL at the end, this makes three exp_elements.
+   It casts the contents of the word addressed by the value of the
+   following subexpression.  */
+  UNOP_MEMVAL,
+/* UNOP_... operate on one value from a following subexpression
+   and replace it with a result.  They take no immediate arguments.  */
+  UNOP_NEG,            /* Unary - */
+  UNOP_ZEROP,          /* Unary ! */
+  UNOP_LOGNOT,         /* Unary ~ */
+  UNOP_IND,            /* Unary * */
+  UNOP_ADDR,           /* Unary & */
+  UNOP_PREINCREMENT,   /* ++ before an expression */
+  UNOP_POSTINCREMENT,  /* ++ after an expression */
+  UNOP_PREDECREMENT,   /* -- before an expression */
+  UNOP_POSTDECREMENT,  /* -- after an expression */
+  UNOP_SIZEOF,         /* Unary sizeof (followed by expression) */
+
+/* STRUCTOP_... operate on a value from a following subexpression
+   by extracting a structure component specified by a string
+   that appears in the following exp_elements (as many as needed).
+   STRUCTOP_STRUCT is used for "." and STRUCTOP_PTR for "->".
+   They differ only in the error message given in case the value is
+   not suitable or the structure component specified is not found.
+
+   The length of the string follows in the next exp_element,
+   (after the string), followed by another STRUCTOP_... code.  */
+  STRUCTOP_STRUCT,
+  STRUCTOP_PTR,
+
+/* C++ */
+  /* OP_THIS is just a placeholder for the class instance variable.
+     It just comes in a tight (OP_THIS, OP_THIS) pair.  */
+  OP_THIS,
+
+  /* OP_SCOPE surrounds a type name and a field name.  The type
+     name is encoded as one element, but the field name stays as
+     a string, which, of course, is variable length.  */
+  OP_SCOPE,
+
+};
+
+union exp_element
+{
+  enum exp_opcode opcode;
+  struct symbol *symbol;
+  LONGEST longconst;
+  double doubleconst;
+  char string;
+  struct type *type;
+  struct internalvar *internalvar;
+};
+
+struct expression
+{
+  int nelts;
+  union exp_element elts[1];
+};
+
+/* From expread.y.  */
+struct expression *parse_c_expression ();
+struct expression *parse_c_1 ();
+
+/* The innermost context required by the stack and register variables
+   we've encountered so far.  To use this, set it to NULL, then call
+   parse_c_<whatever>, then look at it.  */
+extern struct block *innermost_block;
+
+/* From expprint.c.  */
+void print_expression ();
diff --git a/gdb/findvar.c b/gdb/findvar.c
new file mode 100644 (file)
index 0000000..c674a54
--- /dev/null
@@ -0,0 +1,684 @@
+/* Find a variable's value in memory, for GDB, the GNU debugger.
+   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.  */
+
+#include <stdio.h>
+#include "defs.h"
+#include "param.h"
+#include "symtab.h"
+#include "frame.h"
+#include "value.h"
+#include "gdbcore.h"
+#include "inferior.h"
+#include "target.h"
+
+#if !defined (GET_SAVED_REGISTER)
+
+/* Return the address in which frame FRAME's value of register REGNUM
+   has been saved in memory.  Or return zero if it has not been saved.
+   If REGNUM specifies the SP, the value we return is actually
+   the SP value, not an address where it was saved.  */
+
+CORE_ADDR
+find_saved_register (frame, regnum)
+     FRAME frame;
+     int regnum;
+{
+  struct frame_info *fi;
+  struct frame_saved_regs saved_regs;
+
+  register FRAME frame1 = 0;
+  register CORE_ADDR addr = 0;
+
+  if (frame == 0)              /* No regs saved if want current frame */
+    return 0;
+
+#ifdef HAVE_REGISTER_WINDOWS
+  /* We assume that a register in a register window will only be saved
+     in one place (since the name changes and/or disappears as you go
+     towards inner frames), so we only call get_frame_saved_regs on
+     the current frame.  This is directly in contradiction to the
+     usage below, which assumes that registers used in a frame must be
+     saved in a lower (more interior) frame.  This change is a result
+     of working on a register window machine; get_frame_saved_regs
+     always returns the registers saved within a frame, within the
+     context (register namespace) of that frame. */
+
+  /* However, note that we don't want this to return anything if
+     nothing is saved (if there's a frame inside of this one).  Also,
+     callers to this routine asking for the stack pointer want the
+     stack pointer saved for *this* frame; this is returned from the
+     next frame.  */
+     
+
+  if (REGISTER_IN_WINDOW_P(regnum))
+    {
+      frame1 = get_next_frame (frame);
+      if (!frame1) return 0;   /* Registers of this frame are
+                                  active.  */
+      
+      /* Get the SP from the next frame in; it will be this
+        current frame.  */
+      if (regnum != SP_REGNUM)
+       frame1 = frame; 
+         
+      fi = get_frame_info (frame1);
+      get_frame_saved_regs (fi, &saved_regs);
+      return saved_regs.regs[regnum];  /* ... which might be zero */
+    }
+#endif /* HAVE_REGISTER_WINDOWS */
+
+  /* Note that this next routine assumes that registers used in
+     frame x will be saved only in the frame that x calls and
+     frames interior to it.  This is not true on the sparc, but the
+     above macro takes care of it, so we should be all right. */
+  while (1)
+    {
+      QUIT;
+      frame1 = get_prev_frame (frame1);
+      if (frame1 == 0 || frame1 == frame)
+       break;
+      fi = get_frame_info (frame1);
+      get_frame_saved_regs (fi, &saved_regs);
+      if (saved_regs.regs[regnum])
+       addr = saved_regs.regs[regnum];
+    }
+
+  return addr;
+}
+
+/* Find register number REGNUM relative to FRAME and put its
+   (raw) contents in *RAW_BUFFER.  Set *OPTIMIZED if the variable
+   was optimized out (and thus can't be fetched).  Set *LVAL to
+   lval_memory, lval_register, or not_lval, depending on whether the
+   value was fetched from memory, from a register, or in a strange
+   and non-modifiable way (e.g. a frame pointer which was calculated
+   rather than fetched).  Set *ADDRP to the address, either in memory
+   on as a REGISTER_BYTE offset into the registers array.
+
+   Note that this implementation never sets *LVAL to not_lval.  But
+   it can be replaced by defining GET_SAVED_REGISTER and supplying
+   your own.
+
+   The argument RAW_BUFFER must point to aligned memory.  */
+void
+get_saved_register (raw_buffer, optimized, addrp, frame, regnum, lval)
+     char *raw_buffer;
+     int *optimized;
+     CORE_ADDR *addrp;
+     FRAME frame;
+     int regnum;
+     enum lval_type *lval;
+{
+  CORE_ADDR addr;
+  /* Normal systems don't optimize out things with register numbers.  */
+  if (optimized != NULL)
+    *optimized = 0;
+  addr = find_saved_register (frame, regnum);
+  if (addr != NULL)
+    {
+      if (lval != NULL)
+       *lval = lval_memory;
+      if (regnum == SP_REGNUM)
+       {
+         if (raw_buffer != NULL)
+           *(CORE_ADDR *)raw_buffer = addr;
+         if (addrp != NULL)
+           *addrp = 0;
+         return;
+       }
+      if (raw_buffer != NULL)
+       read_memory (addr, raw_buffer, REGISTER_RAW_SIZE (regnum));
+    }
+  else
+    {
+      if (lval != NULL)
+       *lval = lval_register;
+      addr = REGISTER_BYTE (regnum);
+      if (raw_buffer != NULL)
+       read_register_gen (regnum, raw_buffer);
+    }
+  if (addrp != NULL)
+    *addrp = addr;
+}
+#endif /* GET_SAVED_REGISTER.  */
+
+/* Copy the bytes of register REGNUM, relative to the current stack frame,
+   into our memory at MYADDR, in target byte order.
+   The number of bytes copied is REGISTER_RAW_SIZE (REGNUM).
+
+   Returns 1 if could not be read, 0 if could.  */
+
+int
+read_relative_register_raw_bytes (regnum, myaddr)
+     int regnum;
+     char *myaddr;
+{
+  int optim;
+  if (regnum == FP_REGNUM && selected_frame)
+    {
+      bcopy (&FRAME_FP(selected_frame), myaddr, sizeof (CORE_ADDR));
+      SWAP_TARGET_AND_HOST (myaddr, sizeof (CORE_ADDR)); /* in target order */
+      return 0;
+    }
+
+  get_saved_register (myaddr, &optim, (CORE_ADDR) NULL, selected_frame,
+                      regnum, (enum lval_type *)NULL);
+  return optim;
+}
+
+/* Return a `value' with the contents of register REGNUM
+   in its virtual format, with the type specified by
+   REGISTER_VIRTUAL_TYPE.  */
+
+value
+value_of_register (regnum)
+     int regnum;
+{
+  CORE_ADDR addr;
+  int optim;
+  register value val;
+  char raw_buffer[MAX_REGISTER_RAW_SIZE];
+  char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE];
+  enum lval_type lval;
+
+  get_saved_register (raw_buffer, &optim, &addr,
+                     selected_frame, regnum, &lval);
+
+  target_convert_to_virtual (regnum, raw_buffer, virtual_buffer);
+  val = allocate_value (REGISTER_VIRTUAL_TYPE (regnum));
+  bcopy (virtual_buffer, VALUE_CONTENTS_RAW (val),
+        REGISTER_VIRTUAL_SIZE (regnum));
+  VALUE_LVAL (val) = lval;
+  VALUE_ADDRESS (val) = addr;
+  VALUE_REGNO (val) = regnum;
+  VALUE_OPTIMIZED_OUT (val) = optim;
+  return val;
+}
+\f
+/* Low level examining and depositing of registers.
+
+   The caller is responsible for making
+   sure that the inferior is stopped before calling the fetching routines,
+   or it will get garbage.  (a change from GDB version 3, in which
+   the caller got the value from the last stop).  */
+
+/* Contents of the registers in target byte order.
+   We allocate some extra slop since we do a lot of bcopy's around `registers',
+   and failing-soft is better than failing hard.  */
+char registers[REGISTER_BYTES + /* SLOP */ 256];
+
+/* Nonzero if that register has been fetched.  */
+char register_valid[NUM_REGS];
+
+/* Indicate that registers may have changed, so invalidate the cache.  */
+void
+registers_changed ()
+{
+  int i;
+  for (i = 0; i < NUM_REGS; i++)
+    register_valid[i] = 0;
+}
+
+/* Indicate that all registers have been fetched, so mark them all valid.  */
+void
+registers_fetched ()
+{
+  int i;
+  for (i = 0; i < NUM_REGS; i++)
+    register_valid[i] = 1;
+}
+
+/* Copy LEN bytes of consecutive data from registers
+   starting with the REGBYTE'th byte of register data
+   into memory at MYADDR.  */
+
+void
+read_register_bytes (regbyte, myaddr, len)
+     int regbyte;
+     char *myaddr;
+     int len;
+{
+  /* Fetch all registers.  */
+  int i;
+  for (i = 0; i < NUM_REGS; i++)
+    if (!register_valid[i])
+      {
+       target_fetch_registers (-1);
+       break;
+      }
+  if (myaddr != NULL)
+    bcopy (&registers[regbyte], myaddr, len);
+}
+
+/* Read register REGNO into memory at MYADDR, which must be large enough
+   for REGISTER_RAW_BYTES (REGNO).  If the register is known to be the
+   size of a CORE_ADDR or smaller, read_register can be used instead.  */
+void
+read_register_gen (regno, myaddr)
+     int regno;
+     char *myaddr;
+{
+  if (!register_valid[regno])
+    target_fetch_registers (regno);
+  bcopy (&registers[REGISTER_BYTE (regno)], myaddr, REGISTER_RAW_SIZE (regno));
+}
+
+/* Copy LEN bytes of consecutive data from memory at MYADDR
+   into registers starting with the REGBYTE'th byte of register data.  */
+
+void
+write_register_bytes (regbyte, myaddr, len)
+     int regbyte;
+     char *myaddr;
+     int len;
+{
+  /* Make sure the entire registers array is valid.  */
+  read_register_bytes (0, (char *)NULL, REGISTER_BYTES);
+  bcopy (myaddr, &registers[regbyte], len);
+  target_store_registers (-1);
+}
+
+/* Return the contents of register REGNO, regarding it as an integer.  */
+
+CORE_ADDR
+read_register (regno)
+     int regno;
+{
+  int reg;
+  if (!register_valid[regno])
+    target_fetch_registers (regno);
+  /* FIXME, this loses when REGISTER_RAW_SIZE (regno) != sizeof (int) */
+  reg = *(int *) &registers[REGISTER_BYTE (regno)];
+  SWAP_TARGET_AND_HOST (&reg, sizeof (int));
+  return reg;
+}
+
+/* Registers we shouldn't try to store.  */
+#if !defined (CANNOT_STORE_REGISTER)
+#define CANNOT_STORE_REGISTER(regno) 0
+#endif
+
+/* Store VALUE in the register number REGNO, regarded as an integer.  */
+
+void
+write_register (regno, val)
+     int regno, val;
+{
+  /* On the sparc, writing %g0 is a no-op, so we don't even want to change
+     the registers array if something writes to this register.  */
+  if (CANNOT_STORE_REGISTER (regno))
+    return;
+
+  SWAP_TARGET_AND_HOST (&val, sizeof (int));
+
+  target_prepare_to_store ();
+
+  register_valid [regno] = 1;
+  /* FIXME, this loses when REGISTER_RAW_SIZE (regno) != sizeof (int) */
+  /* FIXME, this depends on REGISTER_BYTE (regno) being aligned for host */
+  *(int *) &registers[REGISTER_BYTE (regno)] = val;
+
+  target_store_registers (regno);
+}
+
+/* Record that register REGNO contains VAL.
+   This is used when the value is obtained from the inferior or core dump,
+   so there is no need to store the value there.  */
+
+void
+supply_register (regno, val)
+     int regno;
+     char *val;
+{
+  register_valid[regno] = 1;
+  bcopy (val, &registers[REGISTER_BYTE (regno)], REGISTER_RAW_SIZE (regno));
+}
+\f
+/* Given a struct symbol for a variable,
+   and a stack frame id, read the value of the variable
+   and return a (pointer to a) struct value containing the value. 
+   If the variable cannot be found, return a zero pointer.  */
+
+value
+read_var_value (var, frame)
+     register struct symbol *var;
+     FRAME frame;
+{
+  register value v;
+  struct frame_info *fi;
+  struct type *type = SYMBOL_TYPE (var);
+  CORE_ADDR addr;
+  int val;
+  register int len;
+
+  v = allocate_value (type);
+  VALUE_LVAL (v) = lval_memory;        /* The most likely possibility.  */
+  len = TYPE_LENGTH (type);
+
+  if (frame == 0) frame = selected_frame;
+
+  switch (SYMBOL_CLASS (var))
+    {
+    case LOC_CONST:
+      val = SYMBOL_VALUE (var);
+      bcopy (&val, VALUE_CONTENTS_RAW (v), len);
+      SWAP_TARGET_AND_HOST (VALUE_CONTENTS_RAW (v), len);
+      VALUE_LVAL (v) = not_lval;
+      return v;
+
+    case LOC_LABEL:
+      addr = SYMBOL_VALUE_ADDRESS (var);
+      bcopy (&addr, VALUE_CONTENTS_RAW (v), len);
+      SWAP_TARGET_AND_HOST (VALUE_CONTENTS_RAW (v), len);
+      VALUE_LVAL (v) = not_lval;
+      return v;
+
+    case LOC_CONST_BYTES:
+      addr = SYMBOL_VALUE_ADDRESS (var);
+      bcopy (addr, VALUE_CONTENTS_RAW (v), len);
+      VALUE_LVAL (v) = not_lval;
+      return v;
+
+    case LOC_STATIC:
+    case LOC_EXTERNAL:
+      addr = SYMBOL_VALUE_ADDRESS (var);
+      break;
+
+/* Nonzero if a struct which is located in a register or a LOC_ARG
+   really contains
+   the address of the struct, not the struct itself.  GCC_P is nonzero
+   if the function was compiled with GCC.  */
+#if !defined (REG_STRUCT_HAS_ADDR)
+#define REG_STRUCT_HAS_ADDR(gcc_p) 0
+#endif
+
+    case LOC_ARG:
+      fi = get_frame_info (frame);
+      addr = FRAME_ARGS_ADDRESS (fi);
+      if (!addr) {
+       return 0;
+      }
+      addr += SYMBOL_VALUE (var);
+      break;
+      
+    case LOC_REF_ARG:
+      fi = get_frame_info (frame);
+      addr = FRAME_ARGS_ADDRESS (fi);
+      if (!addr) {
+       return 0;
+      }
+      addr += SYMBOL_VALUE (var);
+      addr = read_memory_integer (addr, sizeof (CORE_ADDR));
+      break;
+      
+    case LOC_LOCAL:
+    case LOC_LOCAL_ARG:
+      fi = get_frame_info (frame);
+      addr = SYMBOL_VALUE (var) + FRAME_LOCALS_ADDRESS (fi);
+      break;
+
+    case LOC_TYPEDEF:
+      error ("Cannot look up value of a typedef");
+      break;
+
+    case LOC_BLOCK:
+      VALUE_ADDRESS (v) = BLOCK_START (SYMBOL_BLOCK_VALUE (var));
+      return v;
+
+    case LOC_REGISTER:
+    case LOC_REGPARM:
+      {
+       struct block *b = get_frame_block (frame);
+
+       v = value_from_register (type, SYMBOL_VALUE (var), frame);
+
+       if (REG_STRUCT_HAS_ADDR(b->gcc_compile_flag)
+           && TYPE_CODE (type) == TYPE_CODE_STRUCT)
+         addr = *(CORE_ADDR *)VALUE_CONTENTS (v);
+       else
+         return v;
+      }
+      break;
+
+    default:
+      error ("Cannot look up value of a botched symbol.");
+      break;
+    }
+
+  VALUE_ADDRESS (v) = addr;
+  VALUE_LAZY (v) = 1;
+  return v;
+}
+
+/* Return a value of type TYPE, stored in register REGNUM, in frame
+   FRAME. */
+
+value
+value_from_register (type, regnum, frame)
+     struct type *type;
+     int regnum;
+     FRAME frame;
+{
+  char raw_buffer [MAX_REGISTER_RAW_SIZE];
+  char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE];
+  CORE_ADDR addr;
+  int optim;
+  value v = allocate_value (type);
+  int len = TYPE_LENGTH (type);
+  char *value_bytes = 0;
+  int value_bytes_copied = 0;
+  int num_storage_locs;
+  enum lval_type lval;
+
+  VALUE_REGNO (v) = regnum;
+
+  num_storage_locs = (len > REGISTER_VIRTUAL_SIZE (regnum) ?
+                     ((len - 1) / REGISTER_RAW_SIZE (regnum)) + 1 :
+                     1);
+
+  if (num_storage_locs > 1)
+    {
+      /* Value spread across multiple storage locations.  */
+      
+      int local_regnum;
+      int mem_stor = 0, reg_stor = 0;
+      int mem_tracking = 1;
+      CORE_ADDR last_addr = 0;
+      CORE_ADDR first_addr;
+
+      value_bytes = (char *) alloca (len + MAX_REGISTER_RAW_SIZE);
+
+      /* Copy all of the data out, whereever it may be.  */
+
+      for (local_regnum = regnum;
+          value_bytes_copied < len;
+          (value_bytes_copied += REGISTER_RAW_SIZE (local_regnum),
+           ++local_regnum))
+       {
+         get_saved_register (value_bytes + value_bytes_copied,
+                             &optim,
+                             &addr,
+                             frame,
+                             local_regnum,
+                             &lval);
+         if (lval == lval_register)
+           reg_stor++;
+         else
+           {
+             mem_stor++;
+
+             if (regnum == local_regnum)
+               first_addr = addr;
+             
+             mem_tracking =
+               (mem_tracking
+                && (regnum == local_regnum
+                    || addr == last_addr));
+           }
+         last_addr = addr;
+       }
+
+      if ((reg_stor && mem_stor)
+         || (mem_stor && !mem_tracking))
+       /* Mixed storage; all of the hassle we just went through was
+          for some good purpose.  */
+       {
+         VALUE_LVAL (v) = lval_reg_frame_relative;
+         VALUE_FRAME (v) = FRAME_FP (frame);
+         VALUE_FRAME_REGNUM (v) = regnum;
+       }
+      else if (mem_stor)
+       {
+         VALUE_LVAL (v) = lval_memory;
+         VALUE_ADDRESS (v) = first_addr;
+       }
+      else if (reg_stor)
+       {
+         VALUE_LVAL (v) = lval_register;
+         VALUE_ADDRESS (v) = first_addr;
+       }
+      else
+       fatal ("value_from_register: Value not stored anywhere!");
+
+      VALUE_OPTIMIZED_OUT (v) = optim;
+
+      /* Any structure stored in more than one register will always be
+        an integral number of registers.  Otherwise, you'd need to do
+        some fiddling with the last register copied here for little
+        endian machines.  */
+
+      /* Copy into the contents section of the value.  */
+      bcopy (value_bytes, VALUE_CONTENTS_RAW (v), len);
+
+      return v;
+    }
+
+  /* Data is completely contained within a single register.  Locate the
+     register's contents in a real register or in core;
+     read the data in raw format.  */
+
+  get_saved_register (raw_buffer, &optim, &addr, frame, regnum, &lval);
+  VALUE_OPTIMIZED_OUT (v) = optim;
+  VALUE_LVAL (v) = lval;
+  VALUE_ADDRESS (v) = addr;
+  
+  /* Convert the raw contents to virtual contents.
+     (Just copy them if the formats are the same.)  */
+  
+  target_convert_to_virtual (regnum, raw_buffer, virtual_buffer);
+  
+  if (REGISTER_CONVERTIBLE (regnum))
+    {
+      /* When the raw and virtual formats differ, the virtual format
+        corresponds to a specific data type.  If we want that type,
+        copy the data into the value.
+        Otherwise, do a type-conversion.  */
+      
+      if (type != REGISTER_VIRTUAL_TYPE (regnum))
+       {
+         /* eg a variable of type `float' in a 68881 register
+            with raw type `extended' and virtual type `double'.
+            Fetch it as a `double' and then convert to `float'.  */
+         v = allocate_value (REGISTER_VIRTUAL_TYPE (regnum));
+         bcopy (virtual_buffer, VALUE_CONTENTS_RAW (v), len);
+         v = value_cast (type, v);
+       }
+      else
+       bcopy (virtual_buffer, VALUE_CONTENTS_RAW (v), len);
+    }
+  else
+    {
+      /* Raw and virtual formats are the same for this register.  */
+
+#if TARGET_BYTE_ORDER == BIG_ENDIAN
+      if (len < REGISTER_RAW_SIZE (regnum))
+       {
+         /* Big-endian, and we want less than full size.  */
+         VALUE_OFFSET (v) = REGISTER_RAW_SIZE (regnum) - len;
+       }
+#endif
+
+      bcopy (virtual_buffer + VALUE_OFFSET (v),
+            VALUE_CONTENTS_RAW (v), len);
+    }
+  
+  return v;
+}
+\f
+/* Given a struct symbol for a variable,
+   and a stack frame id, 
+   return a (pointer to a) struct value containing the variable's address.  */
+
+value
+locate_var_value (var, frame)
+     register struct symbol *var;
+     FRAME frame;
+{
+  CORE_ADDR addr = 0;
+  struct type *type = SYMBOL_TYPE (var);
+  struct type *result_type;
+  value lazy_value;
+
+  /* Evaluate it first; if the result is a memory address, we're fine.
+     Lazy evaluation pays off here. */
+
+  lazy_value = read_var_value (var, frame);
+  if (lazy_value == 0)
+    error ("Address of \"%s\" is unknown.", SYMBOL_NAME (var));
+
+  if (VALUE_LAZY (lazy_value))
+    {
+      addr = VALUE_ADDRESS (lazy_value);
+
+      /* C++: The "address" of a reference should yield the address
+       * of the object pointed to. So force an extra de-reference. */
+
+      if (TYPE_CODE (type) == TYPE_CODE_REF)
+       {
+         char *buf = alloca (TYPE_LENGTH (type));
+         read_memory (addr, buf, TYPE_LENGTH (type));
+         addr = unpack_long (type, buf);
+         type = TYPE_TARGET_TYPE (type);
+       }
+
+      /* Address of an array is of the type of address of it's elements.  */
+      result_type =
+       lookup_pointer_type (TYPE_CODE (type) == TYPE_CODE_ARRAY ?
+                            TYPE_TARGET_TYPE (type) : type);
+
+      return value_cast (result_type,
+                        value_from_long (builtin_type_long, (LONGEST) addr));
+    }
+
+  /* Not a memory address; check what the problem was.  */
+  switch (VALUE_LVAL (lazy_value)) 
+    {
+    case lval_register:
+    case lval_reg_frame_relative:
+      error ("Address requested for identifier \"%s\" which is in a register.",
+            SYMBOL_NAME (var));
+      break;
+
+    default:
+      error ("Can't take address of \"%s\" which isn't an lvalue.",
+            SYMBOL_NAME (var));
+      break;
+    }
+  return 0;  /* For lint -- never reached */
+}
diff --git a/gdb/frame.h b/gdb/frame.h
new file mode 100644 (file)
index 0000000..5c98c9c
--- /dev/null
@@ -0,0 +1,128 @@
+/* Definitions for dealing with stack frames, for GDB, the GNU debugger.
+   Copyright (C) 1986, 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.  */
+
+#if !defined (FRAME_H)
+#define FRAME_H 1
+#include "param.h"
+
+/*
+ * FRAME is the type of the identifier of a specific stack frame.  It
+ * is a pointer to the frame cache item corresponding to this frame.
+ * Please note that frame id's are *not* constant over calls to the
+ * inferior.  Use frame addresses, which are.
+ *
+ * FRAME_ADDR is the type of the address of a specific frame.  I
+ * cannot imagine a case in which this would not be CORE_ADDR, so
+ * maybe it's silly to give it it's own type.  Life's rough.
+ *
+ * FRAME_FP is a macro which converts from a frame identifier into a
+ * frame_address.
+ *
+ * FRAME_INFO_ID is a macro which "converts" from a frame info pointer
+ * to a frame id.  This is here in case I or someone else decides to
+ * change the FRAME type again.
+ *
+ * This file and blockframe.c are the only places which are allowed to
+ * use the equivalence between FRAME and struct frame_info *.  EXCEPTION:
+ * value.h uses CORE_ADDR instead of FRAME_ADDR because the compiler
+ * will accept that in the absense of this file.
+ */
+typedef struct frame_info *FRAME;
+typedef CORE_ADDR      FRAME_ADDR;
+#define FRAME_FP(fr)   ((fr)->frame)
+#define FRAME_INFO_ID(f)       (f)
+
+/*
+ * Caching structure for stack frames.  This is also the structure
+ * used for extended info about stack frames.  May add more to this
+ * structure as it becomes necessary.
+ *
+ * Note that the first entry in the cache will always refer to the
+ * innermost executing frame.  This value should be set (is it?
+ * Check) in something like normal_stop.
+ */
+struct frame_info
+  {
+    /* Nominal address of the frame described.  */
+    FRAME_ADDR frame;
+    /* Address at which execution is occurring in this frame.
+       For the innermost frame, it's the current pc.
+       For other frames, it is a pc saved in the next frame.  */
+    CORE_ADDR pc;
+    /* The frame called by the frame we are describing, or 0.
+       This may be set even if there isn't a frame called by the one
+       we are describing (.->next == 0); in that case it is simply the
+       bottom of this frame */
+    FRAME_ADDR next_frame;
+    /* Anything extra for this structure that may have been defined
+       in the machine depedent files. */
+#ifdef EXTRA_FRAME_INFO
+    EXTRA_FRAME_INFO
+#endif
+    /* Pointers to the next and previous frame_info's in this stack.  */
+    FRAME next, prev;
+  };
+
+/* Describe the saved registers of a frame.  */
+
+struct frame_saved_regs
+  {
+    /* For each register, address of where it was saved on entry to the frame,
+       or zero if it was not saved on entry to this frame.  */
+    CORE_ADDR regs[NUM_REGS];
+  };
+
+/* The stack frame that the user has specified for commands to act on.
+   Note that one cannot assume this is the address of valid data.  */
+
+extern FRAME selected_frame;
+
+extern struct frame_info *get_frame_info ();
+extern struct frame_info *get_prev_frame_info ();
+
+extern FRAME create_new_frame ();
+extern void  flush_cached_frames ();
+
+extern void get_frame_saved_regs ();
+
+extern void  set_current_frame ();
+extern FRAME get_prev_frame ();
+extern FRAME get_current_frame ();
+extern FRAME get_next_frame ();
+
+extern struct block *get_frame_block ();
+extern struct block *get_current_block ();
+extern struct block *get_selected_block ();
+extern struct symbol *get_frame_function ();
+extern CORE_ADDR get_frame_pc ();
+extern CORE_ADDR get_pc_function_start ();
+struct block *block_for_pc ();
+
+int frameless_look_for_prologue ();
+
+void print_frame_args ();
+
+/* In stack.c */
+extern FRAME find_relative_frame ();
+extern void print_selected_frame ();
+extern void print_sel_frame ();
+extern void select_frame ();
+extern void record_selected_frame ();
+
+#endif /* frame.h not already included.  */
diff --git a/gdb/gdb-int.texinfo b/gdb/gdb-int.texinfo
new file mode 100755 (executable)
index 0000000..cc1b188
--- /dev/null
@@ -0,0 +1,242 @@
+\input texinfo
+@setfilename gdb-internals
+@ifinfo
+This file documents the internals of the GNU debugger GDB.
+
+Copyright (C) 1990, 1991 Free Software Foundation, Inc.
+Contributed by Cygnus Support.  Written by John Gilmore.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+@ignore
+Permission is granted to process this file through Tex and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@end ignore
+Permission is granted to copy or distribute modified versions of this
+manual under the terms of the GPL (for which purpose this text may be
+regarded as a program in the language TeX).
+@end ifinfo
+
+@setchapternewpage odd
+@settitle GDB Internals
+@titlepage
+@title{Working in GDB}
+@subtitle{A guide to the internals of the GNU debugger}
+@author John Gilmore
+@author Cygnus Support
+@page
+@tex
+\def\$#1${{#1}}  % Kluge: collect RCS revision info without $...$
+\xdef\manvers{\$Revision$}  % For use in headers, footers too
+{\parskip=0pt
+\hfill Cygnus Support\par
+\hfill \manvers\par
+\hfill \TeX{}info \texinfoversion\par
+}
+@end tex
+
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1990, 1991 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+@end titlepage
+
+@node Top, Cleanups, (dir), (dir)
+
+@menu
+* Cleanups::                   Cleanups
+* Wrapping::                   Wrapping output lines
+* Releases::                   Configuring GDB for release
+* README::                     The README file
+* New Architectures::          Defining a new host or target architecture
+* Host versus Targt::          What features are in which files
+
+@end menu
+
+@node Cleanups, Wrapping, Top, Top
+@chapter Cleanups
+
+Cleanups are a structured way to deal with things that need to be done
+later.  When your code does something (like malloc some memory, or open
+a file) that needs to be undone later (e.g. free the memory or close
+the file), it can make a cleanup.  The cleanup will be done at some
+future point:  when the command is finished, when an error occurs, or
+when your code decides it's time to do cleanups.
+
+You can also discard cleanups, that is, throw them away without doing
+what they say.  This is only done if you ask that it be done.
+
+Syntax:
+
+@table @code
+@item old_chain = make_cleanup (function, arg);
+This makes a cleanup which will cause FUNCTION to be called with ARG
+(a char *) later.  The result, OLD_CHAIN, is a handle that can be
+passed to do_cleanups or discard_cleanups later.  Unless you are
+going to call do_cleanups or discard_cleanups yourself,
+you can ignore the result from make_cleanup.
+
+
+@item do_cleanups (old_chain);
+Performs all cleanups done since make_cleanup returned OLD_CHAIN.
+E.g.:   make_cleanup (a, 0); old = make_cleanup (b, 0); do_cleanups (old);
+will call b() but will not call a().  The cleanup that calls a() will remain
+in the cleanup chain, and will be done later unless otherwise discarded.
+
+@item discard_cleanups (old_chain);
+Same as do_cleanups except that it just removes the cleanups from the
+chain and does not call the specified functions.
+
+@end table
+
+Some functions, e.g. @code{fputs_filtered()} or @code{error()}, specify that they
+``should not be called when cleanups are not in place''.  This means
+that any actions you need to reverse in the case of an error or
+interruption must be on the cleanup chain before you call these functions,
+since they might never return to your code (they @samp{longjmp} instead).
+
+
+@node Wrapping, Releases, Cleanups, Top
+@chapter Wrapping output lines
+
+Output that goes through printf_filtered or fputs_filtered or
+fputs_demangled needs only to have calls to wrap_here() added 
+in places that would be good breaking points.  The utility routines
+will take care of actually wrapping if the line width is exceeded.
+
+The argument to wrap_here() is an indentation string which is printed
+ONLY if the line breaks there.  This argument is saved away and used
+later.  It must remain valid until the next call to wrap_here() or
+until a newline has been printed through the *_filtered functions.
+Don't pass in a local variable and then return!
+
+It is usually best to call wrap_here() after printing a comma or space.
+If you call it before printing a space, make sure that your indentation
+properly accounts for the leading space that will print if the line wraps
+there.
+
+Any function or set of functions that produce filtered output must finish
+by printing a newline, to flush the wrap buffer, before switching to
+unfiltered ("printf") output.  Symbol reading routines that print
+warnings are a good example.
+
+
+@node Releases, README, Wrapping, Top
+@chapter Configuring GDB for release
+
+
+GDB should be released after doing @samp{config.gdb none} in the top level
+directory.  This will leave a makefile there, but no tm- or xm- files.
+The makefile is needed, for example, for @samp{make gdb.tar.Z}@dots{}  If you
+have tm- or xm-files in the main source directory, C's include rules
+cause them to be used in preference to tm- and xm-files in the 
+subdirectories where the user will actually configure and build the
+binaries.
+
+@samp{config.gdb none} is also a good way to rebuild the top level Makefile
+after changing Makefile.dist, alldeps.mak, etc.
+
+
+
+@node README, New Architectures, Releases, Top
+@chapter The README file
+
+
+Check the README file, it often has useful information that does not
+appear anywhere else in the directory.
+
+
+
+@node New Architectures, Host versus Target, README, Top
+@chapter Defining a new host or target architecture
+
+
+When building support for a new host and/or target, this will help you
+organize where to put the various parts.  @var{ARCH} stands for the
+architecture involved.
+
+Object files needed when the host system is an @var{ARCH} are listed in
+the file @file{xconfig/@var{ARCH}}, in the Makefile macro @samp{XDEPFILES
+= }@dots{}.  You can also define XXXXXX in there.
+
+There are some ``generic'' versions of routines that can be used by
+various host systems.  If these routines work for the @var{ARCH} host,
+you can just include the generic file's name (with .o, not .c) in
+@code{XDEPFILES}.  Otherwise, you will need to write routines that
+perform the same functions as the generic file, put them into
+@code{@var{ARCH}-xdep.c}, and put @code{@var{ARCH}-xdep.o} into
+@code{XDEPFILES}.  These generic host support files include:
+
+@example
+       coredep.c, coredep.o
+@end example
+
+@table @code
+@item fetch_core_registers()
+Support for reading registers out of a core file.  This routine calls
+@code{register_addr(}), see below.
+
+@item register_addr()
+If your @code{xm-@var{ARCH}.h} file defines the macro @code{REGISTER_U_ADDR(reg)} to be the
+offset within the @samp{user} struct of a register (represented as a GDB
+register number), @file{coredep.c} will define the @code{register_addr()} function
+and use the macro in it.  If you do not define @code{REGISTER_U_ADDR}, but
+you are using the standard @code{fetch_core_registers}, you
+will need to define your own version of @code{register_addr}, put it into
+your @code{@var{ARCH}-xdep.c} file, and be sure @code{@var{ARCH}-xdep.o} is in the @code{XDEPFILES} list.
+If you have your own @code{fetch_core_registers}, you only need to define
+@code{register_addr} if your @code{fetch_core_registers} calls it.  Many custom
+@code{fetch_core_registers} implementations simply locate the registers
+themselves.
+@end table
+
+Files needed when the target system is an @var{ARCH} are listed in the file
+@file{tconfig/@var{ARCH}}, in the @code{Makefile} macro @samp{TDEPFILES = }@dots{}.  You can also
+define XXXXXX in there.
+
+Similar generic support files for target systems are:
+
+@example
+       exec.c, exec.o:
+@end example
+
+This file defines functions for accessing files that are executable
+on the target system.  These functions open and examine an exec file,
+extract data from one, write data to one, print information about one,
+etc.  Now that executable files are handled with BFD, every architecture
+should be able to use the generic exec.c rather than its own custom code.
+
+@node Host versus Target, , README, Top
+@chapter What is considered ``host-dependent'' versus ``target-dependent''?
+
+The xconfig/*, xm-*.h and *-xdep.c files are for host support.  The
+question is, what features or aspects of a debugging or cross-debugging
+environment are considered to be ``host'' support.
+
+Defines and include files needed to build on the host are host support.
+Examples are tty support, system defined types, host byte order, host
+float format.
+
+Unix child process support is considered an aspect of the host.  Since
+when you fork on the host you are still on the host, the various macros
+needed for finding the registers in the upage, running ptrace, and such
+are all in the host-dependent files.
+
+This is still somewhat of a grey area; I (John Gilmore) didn't do the
+xm- and tm- split for gdb (it was done by Jim Kingdon) so I have had to
+figure out the grounds on which it was split, and make my own choices
+as I evolve it.  I have moved many things out of the xdep files
+actually, partly as a result of BFD and partly by removing duplicated
+code.
+
+@contents
+@bye
+
diff --git a/gdb/gdbcmd.h b/gdb/gdbcmd.h
new file mode 100644 (file)
index 0000000..39151f5
--- /dev/null
@@ -0,0 +1,63 @@
+/* Header file for GDB-specific command-line stuff.
+   Copyright (C) 1986, 1989, 1990 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 1, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include "command.h"
+
+/* Chain containing all defined commands.  */
+
+extern struct cmd_list_element *cmdlist;
+
+/* Chain containing all defined info subcommands.  */
+
+extern struct cmd_list_element *infolist;
+
+/* Chain containing all defined enable subcommands. */
+
+extern struct cmd_list_element *enablelist;
+
+/* Chain containing all defined disable subcommands. */
+
+extern struct cmd_list_element *disablelist;
+
+/* Chain containing all defined delete subcommands. */
+
+extern struct cmd_list_element *deletelist;
+
+/* Chain containing all defined "enable breakpoint" subcommands. */
+
+extern struct cmd_list_element *enablebreaklist;
+
+/* Chain containing all defined set subcommands */
+
+extern struct cmd_list_element *setlist;
+
+/* Chain containing all defined show subcommands.  */
+extern struct cmd_list_element *showlist;
+
+/* Chain containing all defined \"set history\".  */
+
+extern struct cmd_list_element *sethistlist;
+
+/* Chain containing all defined \"show history\".  */
+extern struct cmd_list_element *showhistlist;
+
+/* Chain containing all defined \"unset history\".  */
+
+extern struct cmd_list_element *unsethistlist;
+
+void execute_command ();
+char **noop_completer ();
diff --git a/gdb/gdbcore.h b/gdb/gdbcore.h
new file mode 100644 (file)
index 0000000..991ce64
--- /dev/null
@@ -0,0 +1,82 @@
+/* Machine independent variables that describe the core file under GDB.
+   Copyright (C) 1986, 1987, 1989, 1990  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.  */
+
+/* Interface routines for core, executable, etc.  */
+
+#include "bfd.h"               /* Binary File Description */
+
+/* Return the name of the executable file as a string.
+   ERR nonzero means get error if there is none specified;
+   otherwise return 0 in that case.  */
+char *get_exec_file ();
+
+/* Nonzero if there is a core file.  */
+int have_core_file_p ();
+
+/* Read "memory data" from whatever target or inferior we have. 
+   Returns zero if successful, errno value if not.  EIO is used
+   for address out of bounds.  If breakpoints are inserted, returns
+   shadow contents, not the breakpoints themselves.  From breakpoint.c.  */
+int read_memory_nobpt ();
+
+/* Report a memory error with error().  */
+
+void memory_error ();
+
+/* Like target_read_memory, but report an error if can't read.  */
+void read_memory ();
+
+/* Read an integer from debugged memory, given address and number of bytes.  */
+long read_memory_integer ();
+
+/* Hook for `exec_file_command' command to call.  */
+
+extern void (*exec_file_display_hook) ();
+   
+/* Binary File Diddlers for the exec and core files */
+extern bfd *core_bfd;
+extern bfd *exec_bfd;
+
+void core_file_command ();
+void exec_file_command ();
+void validate_files ();
+unsigned int register_addr ();
+int xfer_core_file ();
+void fetch_core_registers ();
+void registers_fetched ();
+
+#if !defined (KERNEL_U_ADDR)
+extern CORE_ADDR kernel_u_addr;
+#define KERNEL_U_ADDR kernel_u_addr
+#endif
+
+/* Struct section_table maps address ranges to file sections.  It is
+   mostly used with BFD files, but can be used without (e.g. for handling
+   raw disks, or files not in formats handled by BFD).  */
+
+struct section_table {
+  CORE_ADDR addr;              /* Lowest address in section */
+  CORE_ADDR endaddr;           /* 1+highest address in section */
+  sec_ptr   sec_ptr;           /* BFD section pointer */
+};
+
+/* Builds a section table, given args BFD, SECTABLE_PTR, SECEND_PTR.
+   Returns 0 if OK, 1 on error.  */
+
+int build_section_table ();    
diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
new file mode 100644 (file)
index 0000000..d621fa3
--- /dev/null
@@ -0,0 +1,494 @@
+/* Intel 386 stuff.
+   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.  */
+
+#include <stdio.h>
+#include "defs.h"
+#include "param.h"
+#include "frame.h"
+#include "inferior.h"
+#include "gdbcore.h"
+
+#ifdef USG
+#include <sys/types.h>
+#endif
+
+#include <sys/param.h>
+#include <sys/dir.h>
+#include <signal.h>
+#include <sys/user.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+#ifndef N_SET_MAGIC
+#ifdef COFF_FORMAT
+#define N_SET_MAGIC(exec, val) ((exec).magic = (val))
+#else
+#define N_SET_MAGIC(exec, val) ((exec).a_magic = (val))
+#endif
+#endif
+
+#include <sys/file.h>
+#include <sys/stat.h>
+
+/* I don't know whether this is right for cross-debugging even if you
+   do somehow manage to get the right include file.  */
+#if defined (USE_MACHINE_REG_H)
+#include <machine/reg.h>
+#else
+#include <sys/reg.h>
+#endif
+
+/* helper functions for m-i386.h */
+
+/* stdio style buffering to minimize calls to ptrace */
+static CORE_ADDR codestream_next_addr;
+static CORE_ADDR codestream_addr;
+static unsigned char codestream_buf[sizeof (int)];
+static int codestream_off;
+static int codestream_cnt;
+
+#define codestream_tell() (codestream_addr + codestream_off)
+#define codestream_peek() (codestream_cnt == 0 ? \
+                          codestream_fill(1): codestream_buf[codestream_off])
+#define codestream_get() (codestream_cnt-- == 0 ? \
+                        codestream_fill(0) : codestream_buf[codestream_off++])
+
+static unsigned char 
+codestream_fill (peek_flag)
+{
+  codestream_addr = codestream_next_addr;
+  codestream_next_addr += sizeof (int);
+  codestream_off = 0;
+  codestream_cnt = sizeof (int);
+  read_memory (codestream_addr,
+              (unsigned char *)codestream_buf,
+              sizeof (int));
+  
+  if (peek_flag)
+    return (codestream_peek());
+  else
+    return (codestream_get());
+}
+
+static void
+codestream_seek (place)
+{
+  codestream_next_addr = place & -sizeof (int);
+  codestream_cnt = 0;
+  codestream_fill (1);
+  while (codestream_tell() != place)
+    codestream_get ();
+}
+
+static void
+codestream_read (buf, count)
+     unsigned char *buf;
+{
+  unsigned char *p;
+  int i;
+  p = buf;
+  for (i = 0; i < count; i++)
+    *p++ = codestream_get ();
+}
+
+/* next instruction is a jump, move to target */
+static
+i386_follow_jump ()
+{
+  int long_delta;
+  short short_delta;
+  char byte_delta;
+  int data16;
+  int pos;
+  
+  pos = codestream_tell ();
+  
+  data16 = 0;
+  if (codestream_peek () == 0x66)
+    {
+      codestream_get ();
+      data16 = 1;
+    }
+  
+  switch (codestream_get ())
+    {
+    case 0xe9:
+      /* relative jump: if data16 == 0, disp32, else disp16 */
+      if (data16)
+       {
+         codestream_read ((unsigned char *)&short_delta, 2);
+         pos += short_delta + 3; /* include size of jmp inst */
+       }
+      else
+       {
+         codestream_read ((unsigned char *)&long_delta, 4);
+         pos += long_delta + 5;
+       }
+      break;
+    case 0xeb:
+      /* relative jump, disp8 (ignore data16) */
+      codestream_read ((unsigned char *)&byte_delta, 1);
+      pos += byte_delta + 2;
+      break;
+    }
+  codestream_seek (pos + data16);
+}
+
+/*
+ * find & return amound a local space allocated, and advance codestream to
+ * first register push (if any)
+ *
+ * if entry sequence doesn't make sense, return -1, and leave 
+ * codestream pointer random
+ */
+static long
+i386_get_frame_setup (pc)
+{
+  unsigned char op;
+  
+  codestream_seek (pc);
+  
+  i386_follow_jump ();
+  
+  op = codestream_get ();
+  
+  if (op == 0x58)              /* popl %eax */
+    {
+      /*
+       * this function must start with
+       * 
+       *    popl %eax            0x58
+       *    xchgl %eax, (%esp)  0x87 0x04 0x24
+       * or xchgl %eax, 0(%esp) 0x87 0x44 0x24 0x00
+       *
+       * (the system 5 compiler puts out the second xchg
+       * inst, and the assembler doesn't try to optimize it,
+       * so the 'sib' form gets generated)
+       * 
+       * this sequence is used to get the address of the return
+       * buffer for a function that returns a structure
+       */
+      int pos;
+      unsigned char buf[4];
+      static unsigned char proto1[3] = { 0x87,0x04,0x24 };
+      static unsigned char proto2[4] = { 0x87,0x44,0x24,0x00 };
+      pos = codestream_tell ();
+      codestream_read (buf, 4);
+      if (bcmp (buf, proto1, 3) == 0)
+       pos += 3;
+      else if (bcmp (buf, proto2, 4) == 0)
+       pos += 4;
+      
+      codestream_seek (pos);
+      op = codestream_get (); /* update next opcode */
+    }
+  
+  if (op == 0x55)              /* pushl %ebp */
+    {                  
+      /* check for movl %esp, %ebp - can be written two ways */
+      switch (codestream_get ())
+       {
+       case 0x8b:
+         if (codestream_get () != 0xec)
+           return (-1);
+         break;
+       case 0x89:
+         if (codestream_get () != 0xe5)
+           return (-1);
+         break;
+       default:
+         return (-1);
+       }
+      /* check for stack adjustment 
+       *
+       *  subl $XXX, %esp
+       *
+       * note: you can't subtract a 16 bit immediate
+       * from a 32 bit reg, so we don't have to worry
+       * about a data16 prefix 
+       */
+      op = codestream_peek ();
+      if (op == 0x83)
+       {
+         /* subl with 8 bit immed */
+         codestream_get ();
+         if (codestream_get () != 0xec)
+           /* Some instruction starting with 0x83 other than subl.  */
+           {
+             codestream_seek (codestream_tell () - 2);
+             return 0;
+           }
+         /* subl with signed byte immediate 
+          * (though it wouldn't make sense to be negative)
+          */
+         return (codestream_get());
+       }
+      else if (op == 0x81)
+       {
+         /* subl with 32 bit immed */
+         int locals;
+         codestream_get();
+         if (codestream_get () != 0xec)
+           /* Some instruction starting with 0x81 other than subl.  */
+           {
+             codestream_seek (codestream_tell () - 2);
+             return 0;
+           }
+         /* subl with 32 bit immediate */
+         codestream_read ((unsigned char *)&locals, 4);
+         return (locals);
+       }
+      else
+       {
+         return (0);
+       }
+    }
+  else if (op == 0xc8)
+    {
+      /* enter instruction: arg is 16 bit unsigned immed */
+      unsigned short slocals;
+      codestream_read ((unsigned char *)&slocals, 2);
+      codestream_get (); /* flush final byte of enter instruction */
+      return (slocals);
+    }
+  return (-1);
+}
+
+/* Return number of args passed to a frame.
+   Can return -1, meaning no way to tell.  */
+
+/* on the 386, the instruction following the call could be:
+ *  popl %ecx        -  one arg
+ *  addl $imm, %esp  -  imm/4 args; imm may be 8 or 32 bits
+ *  anything else    -  zero args
+ */
+
+int
+i386_frame_num_args (fi)
+     struct frame_info fi;
+{
+  int retpc;                                           
+  unsigned char op;                                    
+  struct frame_info *pfi;
+
+  int frameless;
+
+  FRAMELESS_FUNCTION_INVOCATION (fi, frameless);
+  if (frameless)
+    /* In the absence of a frame pointer, GDB doesn't get correct values
+       for nameless arguments.  Return -1, so it doesn't print any
+       nameless arguments.  */
+    return -1;
+
+  pfi = get_prev_frame_info ((fi));                    
+  if (pfi == 0)
+    {
+      /* Note:  this can happen if we are looking at the frame for
+        main, because FRAME_CHAIN_VALID won't let us go into
+        start.  If we have debugging symbols, that's not really
+        a big deal; it just means it will only show as many arguments
+        to main as are declared.  */
+      return -1;
+    }
+  else
+    {
+      retpc = pfi->pc;                                 
+      op = read_memory_integer (retpc, 1);                     
+      if (op == 0x59)                                  
+       /* pop %ecx */                         
+       return 1;                               
+      else if (op == 0x83)
+       {
+         op = read_memory_integer (retpc+1, 1);        
+         if (op == 0xc4)                               
+           /* addl $<signed imm 8 bits>, %esp */       
+           return (read_memory_integer (retpc+2,1)&0xff)/4;
+         else
+           return 0;
+       }
+      else if (op == 0x81)
+       { /* add with 32 bit immediate */
+         op = read_memory_integer (retpc+1, 1);        
+         if (op == 0xc4)                               
+           /* addl $<imm 32>, %esp */          
+           return read_memory_integer (retpc+2, 4) / 4;
+         else
+           return 0;
+       }
+      else
+       {
+         return 0;
+       }
+    }
+}
+
+/*
+ * parse the first few instructions of the function to see
+ * what registers were stored.
+ *
+ * We handle these cases:
+ *
+ * The startup sequence can be at the start of the function,
+ * or the function can start with a branch to startup code at the end.
+ *
+ * %ebp can be set up with either the 'enter' instruction, or 
+ * 'pushl %ebp, movl %esp, %ebp' (enter is too slow to be useful,
+ * but was once used in the sys5 compiler)
+ *
+ * Local space is allocated just below the saved %ebp by either the
+ * 'enter' instruction, or by 'subl $<size>, %esp'.  'enter' has
+ * a 16 bit unsigned argument for space to allocate, and the
+ * 'addl' instruction could have either a signed byte, or
+ * 32 bit immediate.
+ *
+ * Next, the registers used by this function are pushed.  In
+ * the sys5 compiler they will always be in the order: %edi, %esi, %ebx
+ * (and sometimes a harmless bug causes it to also save but not restore %eax);
+ * however, the code below is willing to see the pushes in any order,
+ * and will handle up to 8 of them.
+ *
+ * If the setup sequence is at the end of the function, then the
+ * next instruction will be a branch back to the start.
+ */
+
+i386_frame_find_saved_regs (fip, fsrp)
+     struct frame_info *fip;
+     struct frame_saved_regs *fsrp;
+{
+  long locals;
+  unsigned char *p;
+  unsigned char op;
+  CORE_ADDR dummy_bottom;
+  CORE_ADDR adr;
+  int i;
+  
+  bzero (fsrp, sizeof *fsrp);
+  
+  /* if frame is the end of a dummy, compute where the
+   * beginning would be
+   */
+  dummy_bottom = fip->frame - 4 - REGISTER_BYTES - CALL_DUMMY_LENGTH;
+  
+  /* check if the PC is in the stack, in a dummy frame */
+  if (dummy_bottom <= fip->pc && fip->pc <= fip->frame) 
+    {
+      /* all regs were saved by push_call_dummy () */
+      adr = fip->frame;
+      for (i = 0; i < NUM_REGS; i++) 
+       {
+         adr -= REGISTER_RAW_SIZE (i);
+         fsrp->regs[i] = adr;
+       }
+      return;
+    }
+  
+  locals = i386_get_frame_setup (get_pc_function_start (fip->pc));
+  
+  if (locals >= 0) 
+    {
+      adr = fip->frame - 4 - locals;
+      for (i = 0; i < 8; i++) 
+       {
+         op = codestream_get ();
+         if (op < 0x50 || op > 0x57)
+           break;
+         fsrp->regs[op - 0x50] = adr;
+         adr -= 4;
+       }
+    }
+  
+  fsrp->regs[PC_REGNUM] = fip->frame + 4;
+  fsrp->regs[FP_REGNUM] = fip->frame;
+}
+
+/* return pc of first real instruction */
+i386_skip_prologue (pc)
+{
+  unsigned char op;
+  int i;
+  
+  if (i386_get_frame_setup (pc) < 0)
+    return (pc);
+  
+  /* found valid frame setup - codestream now points to 
+   * start of push instructions for saving registers
+   */
+  
+  /* skip over register saves */
+  for (i = 0; i < 8; i++)
+    {
+      op = codestream_peek ();
+      /* break if not pushl inst */
+      if (op < 0x50 || op > 0x57) 
+       break;
+      codestream_get ();
+    }
+  
+  i386_follow_jump ();
+  
+  return (codestream_tell ());
+}
+
+i386_push_dummy_frame ()
+{
+  CORE_ADDR sp = read_register (SP_REGNUM);
+  int regnum;
+  char regbuf[MAX_REGISTER_RAW_SIZE];
+  
+  sp = push_word (sp, read_register (PC_REGNUM));
+  sp = push_word (sp, read_register (FP_REGNUM));
+  write_register (FP_REGNUM, sp);
+  for (regnum = 0; regnum < NUM_REGS; regnum++)
+    {
+      read_register_gen (regnum, regbuf);
+      sp = push_bytes (sp, regbuf, REGISTER_RAW_SIZE (regnum));
+    }
+  write_register (SP_REGNUM, sp);
+}
+
+i386_pop_frame ()
+{
+  FRAME frame = get_current_frame ();
+  CORE_ADDR fp;
+  int regnum;
+  struct frame_saved_regs fsr;
+  struct frame_info *fi;
+  char regbuf[MAX_REGISTER_RAW_SIZE];
+  
+  fi = get_frame_info (frame);
+  fp = fi->frame;
+  get_frame_saved_regs (fi, &fsr);
+  for (regnum = 0; regnum < NUM_REGS; regnum++) 
+    {
+      CORE_ADDR adr;
+      adr = fsr.regs[regnum];
+      if (adr)
+       {
+         read_memory (adr, regbuf, REGISTER_RAW_SIZE (regnum));
+         write_register_bytes (REGISTER_BYTE (regnum), regbuf,
+                               REGISTER_RAW_SIZE (regnum));
+       }
+    }
+  write_register (FP_REGNUM, read_memory_integer (fp, 4));
+  write_register (PC_REGNUM, read_memory_integer (fp + 4, 4));
+  write_register (SP_REGNUM, fp + 8);
+  flush_cached_frames ();
+  set_current_frame ( create_new_frame (read_register (FP_REGNUM),
+                                       read_pc ()));
+}
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
new file mode 100644 (file)
index 0000000..e3f86d4
--- /dev/null
@@ -0,0 +1,1088 @@
+/* Memory-access and commands for inferior process, for GDB.
+   Copyright (C) 1986, 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 <stdio.h>
+#include <signal.h>
+#include <sys/param.h>
+#include <string.h>
+#include "defs.h"
+#include "param.h"
+#include "symtab.h"
+#include "frame.h"
+#include "inferior.h"
+#include "environ.h"
+#include "value.h"
+#include "gdbcmd.h"
+#include "gdbcore.h"
+#include "target.h"
+
+extern char *sys_siglist[];
+
+extern void until_break_command ();    /* breakpoint.c */
+
+#define ERROR_NO_INFERIOR \
+   if (!target_has_execution) error ("The program is not being run.");
+
+/* String containing arguments to give to the program, separated by spaces.
+   Empty string (pointer to '\0') means no args.  */
+
+static char *inferior_args;
+
+/* File name for default use for standard in/out in the inferior.  */
+
+char *inferior_io_terminal;
+
+/* Pid of our debugged inferior, or 0 if no inferior now.
+   Since various parts of infrun.c test this to see whether there is a program
+   being debugged it should be nonzero (currently 3 is used) for remote
+   debugging.  */
+
+int inferior_pid;
+
+/* Last signal that the inferior received (why it stopped).  */
+
+int stop_signal;
+
+/* Address at which inferior stopped.  */
+
+CORE_ADDR stop_pc;
+
+/* Stack frame when program stopped.  */
+
+FRAME_ADDR stop_frame_address;
+
+/* Chain containing status of breakpoint(s) that we have stopped at.  */
+
+bpstat stop_bpstat;
+
+/* Flag indicating that a command has proceeded the inferior past the
+   current breakpoint.  */
+
+int breakpoint_proceeded;
+
+/* Nonzero if stopped due to a step command.  */
+
+int stop_step;
+
+/* Nonzero if stopped due to completion of a stack dummy routine.  */
+
+int stop_stack_dummy;
+
+/* Nonzero if stopped due to a random (unexpected) signal in inferior
+   process.  */
+
+int stopped_by_random_signal;
+
+/* Range to single step within.
+   If this is nonzero, respond to a single-step signal
+   by continuing to step if the pc is in this range.  */
+
+CORE_ADDR step_range_start; /* Inclusive */
+CORE_ADDR step_range_end; /* Exclusive */
+
+/* Stack frame address as of when stepping command was issued.
+   This is how we know when we step into a subroutine call,
+   and how to set the frame for the breakpoint used to step out.  */
+
+FRAME_ADDR step_frame_address;
+
+/* 1 means step over all subroutine calls.
+   -1 means step over calls to undebuggable functions.  */
+
+int step_over_calls;
+
+/* If stepping, nonzero means step count is > 1
+   so don't print frame next time inferior stops
+   if it stops due to stepping.  */
+
+int step_multi;
+
+/* Environment to use for running inferior,
+   in format described in environ.h.  */
+
+struct environ *inferior_environ;
+
+CORE_ADDR read_pc ();
+void breakpoint_clear_ignore_counts ();
+
+\f
+void
+tty_command (file, from_tty)
+     char *file;
+     int from_tty;
+{
+  if (file == 0)
+    error_no_arg ("terminal name for running target process");
+
+  inferior_io_terminal = savestring (file, strlen (file));
+}
+
+static void
+run_command (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  char *exec_file;
+
+  dont_repeat ();
+
+  if (inferior_pid)
+    {
+      if (
+         !query ("The program being debugged has been started already.\n\
+Start it from the beginning? "))
+       error ("Program not restarted.");
+      target_kill ((char *)0, 0);
+    }
+
+  exec_file = (char *) get_exec_file (0);
+
+  /* The exec file is re-read every time we do an inferior_died, so
+     we just have to worry about the symbol file.  */
+  reread_symbols ();
+
+  if (args)
+    {
+      char *cmd;
+      cmd = concat ("set args ", args, "");
+      make_cleanup (free, cmd);
+      execute_command (cmd, from_tty);
+    }
+
+  if (from_tty)
+    {
+      printf ("Starting program: %s %s\n",
+             exec_file? exec_file: "", inferior_args);
+      fflush (stdout);
+    }
+
+  target_create_inferior (exec_file, inferior_args,
+                         environ_vector (inferior_environ));
+}
+\f
+void
+continue_command (proc_count_exp, from_tty)
+     char *proc_count_exp;
+     int from_tty;
+{
+  ERROR_NO_INFERIOR;
+
+  /* If have argument, set proceed count of breakpoint we stopped at.  */
+
+  if (proc_count_exp != NULL)
+    {
+      bpstat bs = stop_bpstat;
+      int num = bpstat_num (&bs);
+      if (num == 0 && from_tty)
+       {
+         printf_filtered
+           ("Not stopped at any breakpoint; argument ignored.\n");
+       }
+      while (num != 0)
+       {
+         set_ignore_count (num,
+                           parse_and_eval_address (proc_count_exp) - 1,
+                           from_tty);
+         /* set_ignore_count prints a message ending with a period.
+            So print two spaces before "Continuing.".  */
+         if (from_tty)
+           printf ("  ");
+         num = bpstat_num (&bs);
+       }
+    }
+
+  if (from_tty)
+    printf ("Continuing.\n");
+
+  clear_proceed_status ();
+
+  proceed ((CORE_ADDR) -1, -1, 0);
+}
+\f
+/* Step until outside of current statement.  */
+static void step_1 ();
+
+static void
+step_command (count_string, from_tty)
+     char * count_string;
+     int from_tty;
+{
+  step_1 (0, 0, count_string);
+}
+
+/* Likewise, but skip over subroutine calls as if single instructions.  */
+
+static void
+next_command (count_string, from_tty)
+     char * count_string;
+     int from_tty;
+{
+  step_1 (1, 0, count_string);
+}
+
+/* Likewise, but step only one instruction.  */
+
+static void
+stepi_command (count_string, from_tty)
+     char * count_string;
+     int from_tty;
+{
+  step_1 (0, 1, count_string);
+}
+
+static void
+nexti_command (count_string, from_tty)
+     char * count_string;
+     int from_tty;
+{
+  step_1 (1, 1, count_string);
+}
+
+static void
+step_1 (skip_subroutines, single_inst, count_string)
+     int skip_subroutines;
+     int single_inst;
+     char *count_string;
+{
+  register int count = 1;
+  FRAME fr;
+
+  ERROR_NO_INFERIOR;
+  count = count_string ? parse_and_eval_address (count_string) : 1;
+
+  for (; count > 0; count--)
+    {
+      clear_proceed_status ();
+
+
+      fr = get_current_frame ();
+      if (!fr)                         /* Avoid coredump here.  Why tho? */
+       error ("No current frame");
+      step_frame_address = FRAME_FP (fr);
+
+      if (! single_inst)
+       {
+         find_pc_line_pc_range (stop_pc, &step_range_start, &step_range_end);
+         if (step_range_end == 0)
+           {
+             int misc;
+
+             misc = find_pc_misc_function (stop_pc);
+             target_terminal_ours ();
+             printf ("Current function has no line number information.\n");
+             fflush (stdout);
+
+             /* No info or after _etext ("Can't happen") */
+             if (misc == -1 || misc == misc_function_count - 1)
+               error ("No data available on pc function.");
+
+             printf ("Single stepping until function exit.\n");
+             fflush (stdout);
+
+             step_range_start = misc_function_vector[misc].address;
+             step_range_end = misc_function_vector[misc + 1].address;
+           }
+       }
+      else
+       {
+         /* Say we are stepping, but stop after one insn whatever it does.
+            Don't step through subroutine calls even to undebuggable
+            functions.  */
+         step_range_start = step_range_end = 1;
+         if (!skip_subroutines)
+           step_over_calls = 0;
+       }
+
+      if (skip_subroutines)
+       step_over_calls = 1;
+
+      step_multi = (count > 1);
+      proceed ((CORE_ADDR) -1, -1, 1);
+      if (! stop_step)
+       break;
+#if defined (SHIFT_INST_REGS)
+      write_register (NNPC_REGNUM, read_register (NPC_REGNUM));
+      write_register (NPC_REGNUM, read_register (PC_REGNUM));
+#endif
+    }
+}
+\f
+/* Continue program at specified address.  */
+
+static void
+jump_command (arg, from_tty)
+     char *arg;
+     int from_tty;
+{
+  register CORE_ADDR addr;
+  struct symtabs_and_lines sals;
+  struct symtab_and_line sal;
+
+  ERROR_NO_INFERIOR;
+
+  if (!arg)
+    error_no_arg ("starting address");
+
+  sals = decode_line_spec_1 (arg, 1);
+  if (sals.nelts != 1)
+    {
+      error ("Unreasonable jump request");
+    }
+
+  sal = sals.sals[0];
+  free (sals.sals);
+
+  if (sal.symtab == 0 && sal.pc == 0)
+    error ("No source file has been specified.");
+
+  if (sal.pc == 0)
+    sal.pc = find_line_pc (sal.symtab, sal.line);
+
+  {
+    struct symbol *fn = get_frame_function (get_current_frame ());
+    struct symbol *sfn = find_pc_function (sal.pc);
+    if (fn != 0 && sfn != fn
+       && ! query ("Line %d is not in `%s'.  Jump anyway? ",
+                   sal.line, SYMBOL_NAME (fn)))
+      error ("Not confirmed.");
+  }
+
+  if (sal.pc == 0)
+    error ("No line %d in file \"%s\".", sal.line, sal.symtab->filename);
+
+  addr = ADDR_BITS_SET (sal.pc);
+
+  if (from_tty)
+    printf ("Continuing at 0x%x.\n", addr);
+
+  clear_proceed_status ();
+  proceed (addr, 0, 0);
+}
+
+/* Continue program giving it specified signal.  */
+
+static void
+signal_command (signum_exp, from_tty)
+     char *signum_exp;
+     int from_tty;
+{
+  register int signum;
+
+  dont_repeat ();              /* Too dangerous.  */
+  ERROR_NO_INFERIOR;
+
+  if (!signum_exp)
+    error_no_arg ("signal number");
+
+  signum = parse_and_eval_address (signum_exp);
+
+  if (from_tty)
+    printf ("Continuing with signal %d.\n", signum);
+
+  clear_proceed_status ();
+  proceed (stop_pc, signum, 0);
+}
+
+/* Execute a "stack dummy", a piece of code stored in the stack
+   by the debugger to be executed in the inferior.
+
+   To call: first, do PUSH_DUMMY_FRAME.
+   Then push the contents of the dummy.  It should end with a breakpoint insn.
+   Then call here, passing address at which to start the dummy.
+
+   The contents of all registers are saved before the dummy frame is popped
+   and copied into the buffer BUFFER.
+
+   The dummy's frame is automatically popped whenever that break is hit.
+   If that is the first time the program stops, run_stack_dummy
+   returns to its caller with that frame already gone.
+   Otherwise, the caller never gets returned to.  */
+
+/* 4 => return instead of letting the stack dummy run.  */
+
+static int stack_dummy_testing = 0;
+
+void
+run_stack_dummy (addr, buffer)
+     CORE_ADDR addr;
+     char buffer[REGISTER_BYTES];
+{
+  /* Now proceed, having reached the desired place.  */
+  clear_proceed_status ();
+  if (stack_dummy_testing & 4)
+    {
+      POP_FRAME;
+      return;
+    }
+  proceed_to_finish = 1;       /* We want stop_registers, please... */
+  proceed (addr, 0, 0);
+
+  if (!stop_stack_dummy)
+    /* This used to say
+       "Cannot continue previously requested operation".  */
+    error ("\
+The program being debugged stopped while in a function called from GDB.\n\
+The expression which contained the function call has been discarded.");
+
+  /* On return, the stack dummy has been popped already.  */
+
+  bcopy (stop_registers, buffer, sizeof stop_registers);
+}
+\f
+/* Proceed until we reach a different source line with pc greater than
+   our current one or exit the function.  We skip calls in both cases.
+
+   Note that eventually this command should probably be changed so
+   that only source lines are printed out when we hit the breakpoint
+   we set.  I'm going to postpone this until after a hopeful rewrite
+   of wait_for_inferior and the proceed status code. -- randy */
+
+void
+until_next_command (from_tty)
+     int from_tty;
+{
+  FRAME frame;
+  CORE_ADDR pc;
+  struct symbol *func;
+  struct symtab_and_line sal;
+  clear_proceed_status ();
+
+  frame = get_current_frame ();
+
+  /* Step until either exited from this function or greater
+     than the current line (if in symbolic section) or pc (if
+     not). */
+
+  pc = read_pc ();
+  func = find_pc_function (pc);
+  
+  if (!func)
+    {
+      int misc_func = find_pc_misc_function (pc);
+      
+      if (misc_func != -1)
+       error ("Execution is not within a known function.");
+      
+      step_range_start = misc_function_vector[misc_func].address;
+      step_range_end = pc;
+    }
+  else
+    {
+      sal = find_pc_line (pc, 0);
+      
+      step_range_start = BLOCK_START (SYMBOL_BLOCK_VALUE (func));
+      step_range_end = sal.end;
+    }
+  
+  step_over_calls = 1;
+  step_frame_address = FRAME_FP (frame);
+  
+  step_multi = 0;              /* Only one call to proceed */
+  
+  proceed ((CORE_ADDR) -1, -1, 1);
+}
+
+void 
+until_command (arg, from_tty)
+     char *arg;
+     int from_tty;
+{
+  if (!target_has_execution)
+    error ("The program is not running.");
+  if (arg)
+    until_break_command (arg, from_tty);
+  else
+    until_next_command (from_tty);
+}
+\f
+/* "finish": Set a temporary breakpoint at the place
+   the selected frame will return to, then continue.  */
+
+static void
+finish_command (arg, from_tty)
+     char *arg;
+     int from_tty;
+{
+  struct symtab_and_line sal;
+  register FRAME frame;
+  struct frame_info *fi;
+  register struct symbol *function;
+
+  if (arg)
+    error ("The \"finish\" command does not take any arguments.");
+  if (!target_has_execution)
+    error ("The program is not running.");
+
+  frame = get_prev_frame (selected_frame);
+  if (frame == 0)
+    error ("\"finish\" not meaningful in the outermost frame.");
+
+  clear_proceed_status ();
+
+  fi = get_frame_info (frame);
+  sal = find_pc_line (fi->pc, 0);
+  sal.pc = fi->pc;
+  set_momentary_breakpoint (sal, frame);
+
+  /* Find the function we will return from.  */
+
+  fi = get_frame_info (selected_frame);
+  function = find_pc_function (fi->pc);
+
+  if (from_tty)
+    {
+      printf ("Run till exit from ");
+      print_selected_frame ();
+    }
+
+  proceed_to_finish = 1;               /* We want stop_registers, please... */
+  proceed ((CORE_ADDR) -1, -1, 0);
+
+  if (bpstat_momentary_breakpoint (stop_bpstat) && function != 0)
+    {
+      struct type *value_type;
+      register value val;
+      CORE_ADDR funcaddr;
+
+      value_type = TYPE_TARGET_TYPE (SYMBOL_TYPE (function));
+      if (!value_type)
+       fatal ("internal: finish_command: function has no target type");
+      
+      if (TYPE_CODE (value_type) == TYPE_CODE_VOID)
+       return;
+
+      funcaddr = BLOCK_START (SYMBOL_BLOCK_VALUE (function));
+
+      val = value_being_returned (value_type, stop_registers,
+             using_struct_return (value_of_variable (function),
+                                  funcaddr,
+                                  value_type,
+               BLOCK_GCC_COMPILED (SYMBOL_BLOCK_VALUE (function))));
+
+      printf ("Value returned is $%d = ", record_latest_value (val));
+      value_print (val, stdout, 0, Val_no_prettyprint);
+      putchar ('\n');
+    }
+}
+\f
+static void
+program_info (args, from_tty)
+    char *args;
+    int from_tty;
+{
+  bpstat bs = stop_bpstat;
+  int num = bpstat_num (&bs);
+  
+  if (!target_has_execution)
+    {
+      printf ("The program being debugged is not being run.\n");
+      return;
+    }
+
+  target_files_info ();
+  printf ("Program stopped at 0x%x.\n", stop_pc);
+  if (stop_step)
+    printf ("It stopped after being stepped.\n");
+  else if (num != 0)
+    {
+      /* There may be several breakpoints in the same place, so this
+        isn't as strange as it seems.  */
+      while (num != 0)
+       {
+         if (num < 0)
+           printf ("It stopped at a breakpoint that has since been deleted.\n");
+         else
+           printf ("It stopped at breakpoint %d.\n", num);
+         num = bpstat_num (&bs);
+       }
+    }
+  else if (stop_signal) {
+#ifdef PRINT_RANDOM_SIGNAL
+    PRINT_RANDOM_SIGNAL (stop_signal);
+#else
+    printf ("It stopped with signal %d (%s).\n",
+           stop_signal, 
+           (stop_signal > NSIG)? "unknown": sys_siglist[stop_signal]);
+#endif
+  }
+
+  if (!from_tty)
+    printf ("Type \"info stack\" or \"info registers\" for more information.\n");
+}
+\f
+static void
+environment_info (var)
+     char *var;
+{
+  if (var)
+    {
+      register char *val = get_in_environ (inferior_environ, var);
+      if (val)
+       printf ("%s = %s\n", var, val);
+      else
+       printf ("Environment variable \"%s\" not defined.\n", var);
+    }
+  else
+    {
+      register char **vector = environ_vector (inferior_environ);
+      while (*vector)
+       printf ("%s\n", *vector++);
+    }
+}
+
+static void
+set_environment_command (arg)
+     char *arg;
+{
+  register char *p, *val, *var;
+  int nullset = 0;
+
+  if (arg == 0)
+    error_no_arg ("environment variable and value");
+
+  /* Find seperation between variable name and value */
+  p = (char *) strchr (arg, '=');
+  val = (char *) strchr (arg, ' ');
+
+  if (p != 0 && val != 0)
+    {
+      /* We have both a space and an equals.  If the space is before the
+        equals and the only thing between the two is more space, use
+        the equals */
+      if (p > val)
+       while (*val == ' ')
+         val++;
+
+      /* Take the smaller of the two.  If there was space before the
+        "=", they will be the same right now. */
+      p = arg + min (p - arg, val - arg);
+    }
+  else if (val != 0 && p == 0)
+    p = val;
+
+  if (p == arg)
+    error_no_arg ("environment variable to set");
+
+  if (p == 0 || p[1] == 0)
+    {
+      nullset = 1;
+      if (p == 0)
+       p = arg + strlen (arg); /* So that savestring below will work */
+    }
+  else
+    {
+      /* Not setting variable value to null */
+      val = p + 1;
+      while (*val == ' ' || *val == '\t')
+       val++;
+    }
+
+  while (p != arg && (p[-1] == ' ' || p[-1] == '\t')) p--;
+
+  var = savestring (arg, p - arg);
+  if (nullset)
+    {
+      printf ("Setting environment variable \"%s\" to null value.\n", var);
+      set_in_environ (inferior_environ, var, "");
+    }
+  else
+    set_in_environ (inferior_environ, var, val);
+  free (var);
+}
+
+static void
+unset_environment_command (var, from_tty)
+     char *var;
+     int from_tty;
+{
+  if (var == 0)
+    {
+      /* If there is no argument, delete all environment variables.
+        Ask for confirmation if reading from the terminal.  */
+      if (!from_tty || query ("Delete all environment variables? "))
+       {
+         free_environ (inferior_environ);
+         inferior_environ = make_environ ();
+       }
+    }
+  else
+    unset_in_environ (inferior_environ, var);
+}
+
+/* Handle the execution path (PATH variable) */
+
+const static char path_var_name[] = "PATH";
+
+void
+path_info (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  printf ("Executable and object file path: %s\n", 
+      get_in_environ (inferior_environ, path_var_name));
+}
+
+/* Add zero or more directories to the front of the execution path.  */
+
+void
+path_command (dirname, from_tty)
+     char *dirname;
+     int from_tty;
+{
+  char *exec_path;
+
+  dont_repeat ();
+  exec_path = strsave (get_in_environ (inferior_environ, path_var_name));
+  mod_path (dirname, from_tty, &exec_path);
+  set_in_environ (inferior_environ, path_var_name, exec_path);
+  free (exec_path);
+  if (from_tty)
+    path_info ();
+}
+\f
+CORE_ADDR
+read_pc ()
+{
+  return ADDR_BITS_REMOVE ((CORE_ADDR) read_register (PC_REGNUM));
+}
+
+void
+write_pc (val)
+     CORE_ADDR val;
+{
+  write_register (PC_REGNUM, (long) val);
+#ifdef NPC_REGNUM
+  write_register (NPC_REGNUM, (long) val+4);
+#endif
+  pc_changed = 0;
+}
+
+char *reg_names[] = REGISTER_NAMES;
+
+/* Print out the machine register regnum. If regnum is -1,
+   print all registers.
+   For most machines, having all_registers_info() print the
+   register(s) one per line is good enough. If a different format
+   is required, (eg, for SPARC or Pyramid 90x, which both have
+   lots of regs), or there is an existing convention for showing
+   all the registers, define the macro DO_REGISTERS_INFO(regnum)
+   to provide that format.  */  
+#if !defined (DO_REGISTERS_INFO)
+#define DO_REGISTERS_INFO(regnum) do_registers_info(regnum)
+static void do_registers_info (regnum)
+     int regnum;
+{
+  register int i;
+
+  if (regnum == -1)
+    printf_filtered (
+      "Register       Contents (relative to selected stack frame)\n\n");
+
+  for (i = 0; i < NUM_REGS; i++)
+    {
+      char raw_buffer[MAX_REGISTER_RAW_SIZE];
+      char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE];
+
+      if (regnum != -1 && i != regnum)
+       continue;
+
+      fputs_filtered (reg_names[i], stdout);
+      print_spaces_filtered (15 - strlen (reg_names[i]), stdout);
+
+      /* Get the data in raw format, then convert also to virtual format.  */
+      if (read_relative_register_raw_bytes (i, raw_buffer))
+       {
+         printf_filtered ("Invalid register contents\n");
+         continue;
+       }
+      
+      target_convert_to_virtual (i, raw_buffer, virtual_buffer);
+
+      /* If virtual format is floating, print it that way, and in raw hex.  */
+      if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (i)) == TYPE_CODE_FLT
+         && ! INVALID_FLOAT (virtual_buffer, REGISTER_VIRTUAL_SIZE (i)))
+       {
+         register int j;
+
+         val_print (REGISTER_VIRTUAL_TYPE (i), virtual_buffer, 0,
+                    stdout, 0, 1, 0, Val_pretty_default);
+
+         printf_filtered ("\t(raw 0x");
+         for (j = 0; j < REGISTER_RAW_SIZE (i); j++)
+           printf_filtered ("%02x", (unsigned char)raw_buffer[j]);
+         printf_filtered (")");
+       }
+
+/* FIXME!  val_print probably can handle all of these cases now...  */
+
+      /* Else if virtual format is too long for printf,
+        print in hex a byte at a time.  */
+      else if (REGISTER_VIRTUAL_SIZE (i) > sizeof (long))
+       {
+         register int j;
+         printf_filtered ("0x");
+         for (j = 0; j < REGISTER_VIRTUAL_SIZE (i); j++)
+           printf_filtered ("%02x", (unsigned char)virtual_buffer[j]);
+       }
+      /* Else print as integer in hex and in decimal.  */
+      else
+       {
+         val_print (REGISTER_VIRTUAL_TYPE (i), raw_buffer, 0,
+                    stdout, 'x', 1, 0, Val_pretty_default);
+         printf_filtered ("\t");
+         val_print (REGISTER_VIRTUAL_TYPE (i), raw_buffer, 0,
+                    stdout,   0, 1, 0, Val_pretty_default);
+       }
+
+      /* The SPARC wants to print even-numbered float regs as doubles
+        in addition to printing them as floats.  */
+#ifdef PRINT_REGISTER_HOOK
+      PRINT_REGISTER_HOOK (i);
+#endif
+
+      printf_filtered ("\n");
+    }
+}
+#endif /* no DO_REGISTERS_INFO.  */
+
+static void
+registers_info (addr_exp)
+     char *addr_exp;
+{
+  int regnum;
+
+  if (!target_has_registers)
+    error ("The program has no registers now.");
+
+  if (addr_exp)
+    {
+      if (*addr_exp >= '0' && *addr_exp <= '9')
+       regnum = atoi (addr_exp);
+      else
+       {
+         register char *p = addr_exp;
+         if (p[0] == '$')
+           p++;
+         for (regnum = 0; regnum < NUM_REGS; regnum++)
+           if (!strcmp (p, reg_names[regnum]))
+             break;
+         if (regnum == NUM_REGS)
+           error ("%s: invalid register name.", addr_exp);
+       }
+    }
+  else
+    regnum = -1;
+
+  DO_REGISTERS_INFO(regnum);
+}
+\f
+/*
+ * TODO:
+ * Should save/restore the tty state since it might be that the
+ * program to be debugged was started on this tty and it wants
+ * the tty in some state other than what we want.  If it's running
+ * on another terminal or without a terminal, then saving and
+ * restoring the tty state is a harmless no-op.
+ * This only needs to be done if we are attaching to a process.
+ */
+
+/*
+ * attach_command --
+ * takes a program started up outside of gdb and ``attaches'' to it.
+ * This stops it cold in its tracks and allows us to start tracing it.
+ * For this to work, we must be able to send the process a
+ * signal and we must have the same effective uid as the program.
+ */
+void
+attach_command (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  target_attach (args, from_tty);
+}
+
+/*
+ * detach_command --
+ * takes a program previously attached to and detaches it.
+ * The program resumes execution and will no longer stop
+ * on signals, etc.  We better not have left any breakpoints
+ * in the program or it'll die when it hits one.  For this
+ * to work, it may be necessary for the process to have been
+ * previously attached.  It *might* work if the program was
+ * started via the normal ptrace (PTRACE_TRACEME).
+ */
+
+static void
+detach_command (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  target_detach (args, from_tty);
+}
+
+/* ARGSUSED */
+static void
+float_info (addr_exp)
+     char *addr_exp;
+{
+#ifdef FLOAT_INFO
+       FLOAT_INFO;
+#else
+       printf ("No floating point info available for this processor.\n");
+#endif
+}
+\f
+void
+_initialize_infcmd ()
+{
+  struct cmd_list_element *c;
+  
+  add_com ("tty", class_run, tty_command,
+          "Set terminal for future runs of program being debugged.");
+
+  add_show_from_set
+    (add_set_cmd ("args", class_run, var_string_noescape, (char *)&inferior_args,
+                 
+"Set arguments to give program being debugged when it is started.\n\
+Follow this command with any number of args, to be passed to the program.",
+                 &setlist),
+     &showlist);
+
+  c = add_cmd
+    ("environment", no_class, environment_info,
+     "The environment to give the program, or one variable's value.\n\
+With an argument VAR, prints the value of environment variable VAR to\n\
+give the program being debugged.  With no arguments, prints the entire\n\
+environment to be given to the program.", &showlist);
+  c->completer = noop_completer;
+
+  c = add_cmd ("environment", class_run, unset_environment_command,
+             "Cancel environment variable VAR for the program.\n\
+This does not affect the program until the next \"run\" command.",
+          &deletelist);
+  c->completer = noop_completer;
+
+  c = add_cmd ("environment", class_run, set_environment_command,
+              "Set environment variable value to give the program.\n\
+Arguments are VAR VALUE where VAR is variable name and VALUE is value.\n\
+VALUES of environment variables are uninterpreted strings.\n\
+This does not affect the program until the next \"run\" command.",
+          &setlist);
+  c->completer = noop_completer;
+  add_com ("path", class_files, path_command,
+       "Add directory DIR(s) to beginning of search path for object files.\n\
+$cwd in the path means the current working directory.\n\
+This path is equivalent to the $PATH shell variable.  It is a list of\n\
+directories, separated by colons.  These directories are searched to find\n\
+fully linked executable files and separately compiled object files as needed.");
+
+  add_info ("path", path_info,
+           "Current search path for finding object files.\n\
+$cwd in the path means the current working directory.\n\
+This path is equivalent to the $PATH shell variable.  It is a list of\n\
+directories, separated by colons.  These directories are searched to find\n\
+fully linked executable files and separately compiled object files as needed.");
+
+ add_com ("attach", class_run, attach_command,
+          "Attach to a process or file outside of GDB.\n\
+This command attaches to another target, of the same type as your last\n\
+`target' command (`info files' will show your target stack).\n\
+The command may take as argument a process id or a device file.\n\
+For a process id, you must have permission to send the process a signal,\n\
+and it must have the same effective uid as the debugger.\n\
+When using \"attach\", you should use the \"file\" command to specify\n\
+the program running in the process, and to load its symbol table.");
+
+  add_com ("detach", class_run, detach_command,
+          "Detach a process or file previously attached.\n\
+If a process, it is no longer traced, and it continues its execution.  If you\n\
+were debugging a file, the file is closed and gdb no longer accesses it.");
+
+  add_com ("signal", class_run, signal_command,
+          "Continue program giving it signal number SIGNUMBER.");
+
+  add_com ("stepi", class_run, stepi_command,
+          "Step one instruction exactly.\n\
+Argument N means do this N times (or till program stops for another reason).");
+  add_com_alias ("si", "stepi", class_alias, 0);
+
+  add_com ("nexti", class_run, nexti_command,
+          "Step one instruction, but proceed through subroutine calls.\n\
+Argument N means do this N times (or till program stops for another reason).");
+  add_com_alias ("ni", "nexti", class_alias, 0);
+
+  add_com ("finish", class_run, finish_command,
+          "Execute until selected stack frame returns.\n\
+Upon return, the value returned is printed and put in the value history.");
+
+  add_com ("next", class_run, next_command,
+          "Step program, proceeding through subroutine calls.\n\
+Like the \"step\" command as long as subroutine calls do not happen;\n\
+when they do, the call is treated as one instruction.\n\
+Argument N means do this N times (or till program stops for another reason).");
+  add_com_alias ("n", "next", class_run, 1);
+
+  add_com ("step", class_run, step_command,
+          "Step program until it reaches a different source line.\n\
+Argument N means do this N times (or till program stops for another reason).");
+  add_com_alias ("s", "step", class_run, 1);
+
+  add_com ("until", class_run, until_command,
+          "Execute until the program reaches a source line greater than the current\n\
+or a specified line or address or function (same args as break command).\n\
+Execution will also stop upon exit from the current stack frame.");
+  add_com_alias ("u", "until", class_run, 1);
+  
+  add_com ("jump", class_run, jump_command,
+          "Continue program being debugged at specified line or address.\n\
+Give as argument either LINENUM or *ADDR, where ADDR is an expression\n\
+for an address to start at.");
+
+  add_com ("continue", class_run, continue_command,
+          "Continue program being debugged, after signal or breakpoint.\n\
+If proceeding from breakpoint, a number N may be used as an argument:\n\
+then the same breakpoint won't break until the Nth time it is reached.");
+  add_com_alias ("c", "cont", class_run, 1);
+  add_com_alias ("fg", "cont", class_run, 1);
+
+  add_com ("run", class_run, run_command,
+          "Start debugged program.  You may specify arguments to give it.\n\
+Args may include \"*\", or \"[...]\"; they are expanded using \"sh\".\n\
+Input and output redirection with \">\", \"<\", or \">>\" are also allowed.\n\n\
+With no arguments, uses arguments last specified (with \"run\" or \"set args\".\n\
+To cancel previous arguments and run with no arguments,\n\
+use \"set args\" without arguments.");
+  add_com_alias ("r", "run", class_run, 1);
+
+  add_info ("registers", registers_info,
+           "List of registers and their contents, for selected stack frame.\n\
+Register name as argument means describe only that register.");
+
+  add_info ("program", program_info,
+           "Execution status of the program.");
+
+  add_info ("float", float_info,
+           "Print the status of the floating point unit\n");
+
+  inferior_args = savestring ("", 1);  /* Initially no args */
+  inferior_environ = make_environ ();
+  init_environ (inferior_environ);
+}
diff --git a/gdb/inferior.h b/gdb/inferior.h
new file mode 100644 (file)
index 0000000..d99c4a6
--- /dev/null
@@ -0,0 +1,201 @@
+/* Variables that describe the inferior process running under GDB:
+   Where it is, why it stopped, and how to step it.
+   Copyright (C) 1986, 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.  */
+
+/* For bpstat.  */
+#include "breakpoint.h"
+
+/* For FRAME_ADDR.  */
+#include "frame.h"
+
+/*
+ * Structure in which to save the status of the inferior.  Save
+ * through "save_inferior_status", restore through
+ * "restore_inferior_status".
+ * This pair of routines should be called around any transfer of
+ * control to the inferior which you don't want showing up in your
+ * control variables.
+ */
+struct inferior_status {
+  int pc_changed;
+  int stop_signal;
+  int stop_pc;
+  FRAME_ADDR stop_frame_address;
+  bpstat stop_bpstat;
+  int stop_step;
+  int stop_stack_dummy;
+  int stopped_by_random_signal;
+  int trap_expected;
+  CORE_ADDR step_range_start;
+  CORE_ADDR step_range_end;
+  FRAME_ADDR step_frame_address;
+  int step_over_calls;
+  CORE_ADDR step_resume_break_address;
+  int stop_after_trap;
+  int stop_soon_quietly;
+  FRAME_ADDR selected_frame_address;
+  int selected_level;
+  char stop_registers[REGISTER_BYTES];
+  int breakpoint_proceeded;
+  int restore_stack_info;
+  int proceed_to_finish;
+};
+
+void save_inferior_status (), restore_inferior_status ();
+
+/* File name for default use for standard in/out in the inferior.  */
+
+extern char *inferior_io_terminal;
+
+/* Pid of our debugged inferior, or 0 if no inferior now.  */
+
+extern int inferior_pid;
+
+/* Character array containing an image of the inferior programs' registers.  */
+
+extern char registers[];
+
+extern void clear_proceed_status ();
+extern void start_inferior ();
+extern void proceed ();
+extern void kill_inferior ();
+extern void kill_inferior_fast ();
+extern void generic_mourn_inferior ();
+extern void terminal_ours ();
+extern void detach ();
+extern void run_stack_dummy ();
+extern CORE_ADDR read_pc ();
+extern void write_pc ();
+extern void wait_for_inferior ();
+extern void init_wait_for_inferior ();
+extern void close_exec_file ();
+extern void reopen_exec_file ();
+
+/* Last signal that the inferior received (why it stopped).  */
+
+extern int stop_signal;
+
+/* Address at which inferior stopped.  */
+
+extern CORE_ADDR stop_pc;
+
+/* Stack frame when program stopped.  */
+
+extern FRAME_ADDR stop_frame_address;
+
+/* Chain containing status of breakpoint(s) that we have stopped at.  */
+
+extern bpstat stop_bpstat;
+
+/* Flag indicating that a command has proceeded the inferior past the
+   current breakpoint.  */
+
+extern int breakpoint_proceeded;
+
+/* Nonzero if stopped due to a step command.  */
+
+extern int stop_step;
+
+/* Nonzero if stopped due to completion of a stack dummy routine.  */
+
+extern int stop_stack_dummy;
+
+/* Nonzero if program stopped due to a random (unexpected) signal in
+   inferior process.  */
+
+extern int stopped_by_random_signal;
+
+/* Range to single step within.
+   If this is nonzero, respond to a single-step signal
+   by continuing to step if the pc is in this range.  */
+
+extern CORE_ADDR step_range_start; /* Inclusive */
+extern CORE_ADDR step_range_end; /* Exclusive */
+
+/* Stack frame address as of when stepping command was issued.
+   This is how we know when we step into a subroutine call,
+   and how to set the frame for the breakpoint used to step out.  */
+
+extern FRAME_ADDR step_frame_address;
+
+/* 1 means step over all subroutine calls.
+   -1 means step over calls to undebuggable functions.  */
+
+extern int step_over_calls;
+
+/* If stepping, nonzero means step count is > 1
+   so don't print frame next time inferior stops
+   if it stops due to stepping.  */
+
+extern int step_multi;
+
+/* Nonzero if proceed is being used for a "finish" command or a similar
+   situation when stop_registers should be saved.  */
+
+extern int proceed_to_finish;
+
+/* Save register contents here when about to pop a stack dummy frame,
+   if-and-only-if proceed_to_finish is set.
+   Thus this contains the return value from the called function (assuming
+   values are returned in a register).  */
+
+extern char stop_registers[REGISTER_BYTES];
+
+/* Nonzero if pc has been changed by the debugger
+   since the inferior stopped.  */
+
+extern int pc_changed;
+
+/* Nonzero if the child process in inferior_pid was attached rather
+   than forked.  */
+
+int attach_flag;
+\f
+/* Possible values for CALL_DUMMY_LOCATION.  */
+#define ON_STACK 1
+#define BEFORE_TEXT_END 2
+#define AFTER_TEXT_END 3
+
+#if !defined (CALL_DUMMY_LOCATION)
+#if defined (CANNOT_EXECUTE_STACK)
+#define CALL_DUMMY_LOCATION BEFORE_TEXT_END
+#else /* Can execute stack.  */
+#define CALL_DUMMY_LOCATION ON_STACK
+#endif /* Can execute stack.  */
+#endif /* No CALL_DUMMY_LOCATION.  */
+
+/* Are we in a call dummy?  The code below which allows DECR_PC_AFTER_BREAK
+   below is for infrun.c, which may give the macro a pc without that
+   subtracted out.  */
+#if !defined (PC_IN_CALL_DUMMY)
+#if CALL_DUMMY_LOCATION == BEFORE_TEXT_END
+#define PC_IN_CALL_DUMMY(pc, sp, frame_address) \
+  ((pc) >= text_end - CALL_DUMMY_LENGTH         \
+   && (pc) < text_end + DECR_PC_AFTER_BREAK)
+#else /* Not before text_end.  */
+#if CALL_DUMMY_LOCATION == AFTER_TEXT_END
+#define PC_IN_CALL_DUMMY(pc, sp, frame_address) \
+  ((pc) >= text_end   \
+   && (pc) < text_end + CALL_DUMMY_LENGTH + DECR_PC_AFTER_BREAK)
+#else /* On stack.  */
+#define PC_IN_CALL_DUMMY(pc, sp, frame_address) \
+  ((sp) INNER_THAN (pc) && (pc) INNER_THAN (frame_address))
+#endif /* On stack.  */
+#endif /* Not before text_end.  */
+#endif /* No PC_IN_CALL_DUMMY.  */
diff --git a/gdb/inflow.c b/gdb/inflow.c
new file mode 100644 (file)
index 0000000..6e6905f
--- /dev/null
@@ -0,0 +1,478 @@
+/* Low level interface to ptrace, for GDB when running under Unix.
+   Copyright (C) 1986, 1987, 1989, 1991 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 <stdio.h>
+#include "defs.h"
+#include "param.h"
+#include "frame.h"
+#include "inferior.h"
+#include "command.h"
+#include "signals.h"
+#include "terminal.h"
+#include "target.h"
+
+#ifdef USG
+#include <sys/types.h>
+#endif
+
+/* Some USG-esque systems (some of which are BSD-esque enough so that USG
+   is not defined) want this header, and it won't do any harm.  */
+#include <fcntl.h>
+
+#include <sys/param.h>
+#include <sys/dir.h>
+#include <signal.h>
+
+extern struct target_ops child_ops;
+
+/* Nonzero if we are debugging an attached outside process
+   rather than an inferior.  */
+
+int attach_flag;
+
+\f
+/* Record terminal status separately for debugger and inferior.  */
+
+static TERMINAL sg_inferior;
+static TERMINAL sg_ours;
+
+static int tflags_inferior;
+static int tflags_ours;
+
+#if defined(TIOCGETC) && !defined(TIOCGETC_BROKEN)
+static struct tchars tc_inferior;
+static struct tchars tc_ours;
+#endif
+
+#ifdef TIOCGLTC
+static struct ltchars ltc_inferior;
+static struct ltchars ltc_ours;
+#endif
+
+#ifdef TIOCLGET
+static int lmode_inferior;
+static int lmode_ours;
+#endif
+
+#ifdef TIOCGPGRP
+static int pgrp_inferior;
+static int pgrp_ours;
+#else
+static void (*sigint_ours) ();
+static void (*sigquit_ours) ();
+#endif /* TIOCGPGRP */
+
+/* Copy of inferior_io_terminal when inferior was last started.  */
+static char *inferior_thisrun_terminal;
+
+static void terminal_ours_1 ();
+
+/* Nonzero if our terminal settings are in effect.
+   Zero if the inferior's settings are in effect.  */
+static int terminal_is_ours;
+
+/* Initialize the terminal settings we record for the inferior,
+   before we actually run the inferior.  */
+
+void
+terminal_init_inferior ()
+{
+  sg_inferior = sg_ours;
+  tflags_inferior = tflags_ours;
+
+#if defined(TIOCGETC) && !defined(TIOCGETC_BROKEN)
+  tc_inferior = tc_ours;
+#endif
+
+#ifdef TIOCGLTC
+  ltc_inferior = ltc_ours;
+#endif
+
+#ifdef TIOCLGET
+  lmode_inferior = lmode_ours;
+#endif
+
+#ifdef TIOCGPGRP
+  pgrp_inferior = inferior_pid;
+#endif /* TIOCGPGRP */
+
+  terminal_is_ours = 1;
+}
+
+/* Put the inferior's terminal settings into effect.
+   This is preparation for starting or resuming the inferior.  */
+
+void
+terminal_inferior ()
+{
+  if (terminal_is_ours && inferior_thisrun_terminal == 0)
+    {
+      fcntl (0, F_SETFL, tflags_inferior);
+      fcntl (0, F_SETFL, tflags_inferior);
+      ioctl (0, TIOCSETN, &sg_inferior);
+
+#if defined(TIOCGETC) && !defined(TIOCGETC_BROKEN)
+      ioctl (0, TIOCSETC, &tc_inferior);
+#endif
+#ifdef TIOCGLTC
+      ioctl (0, TIOCSLTC, &ltc_inferior);
+#endif
+#ifdef TIOCLGET
+      ioctl (0, TIOCLSET, &lmode_inferior);
+#endif
+
+#ifdef TIOCGPGRP
+      ioctl (0, TIOCSPGRP, &pgrp_inferior);
+#else
+      sigint_ours = (void (*) ()) signal (SIGINT, SIG_IGN);
+      sigquit_ours = (void (*) ()) signal (SIGQUIT, SIG_IGN);
+#endif /* TIOCGPGRP */
+    }
+  terminal_is_ours = 0;
+}
+
+/* Put some of our terminal settings into effect,
+   enough to get proper results from our output,
+   but do not change into or out of RAW mode
+   so that no input is discarded.
+
+   After doing this, either terminal_ours or terminal_inferior
+   should be called to get back to a normal state of affairs.  */
+
+void
+terminal_ours_for_output ()
+{
+  terminal_ours_1 (1);
+}
+
+/* Put our terminal settings into effect.
+   First record the inferior's terminal settings
+   so they can be restored properly later.  */
+
+void
+terminal_ours ()
+{
+  terminal_ours_1 (0);
+}
+
+static void
+terminal_ours_1 (output_only)
+     int output_only;
+{
+#ifdef TIOCGPGRP
+  /* Ignore this signal since it will happen when we try to set the pgrp.  */
+  void (*osigttou) ();
+#endif /* TIOCGPGRP */
+
+  /* The check for inferior_thisrun_terminal had been commented out
+     when the call to ioctl (TIOCNOTTY) was commented out.
+     Checking inferior_thisrun_terminal is necessary so that
+     if GDB is running in the background, it won't block trying
+     to do the ioctl()'s below.  */
+  if (inferior_thisrun_terminal != 0)
+    return;
+
+  if (!terminal_is_ours)
+    {
+      terminal_is_ours = 1;
+
+#ifdef TIOCGPGRP
+      osigttou = (void (*) ()) signal (SIGTTOU, SIG_IGN);
+
+      ioctl (0, TIOCGPGRP, &pgrp_inferior);
+      ioctl (0, TIOCSPGRP, &pgrp_ours);
+
+      signal (SIGTTOU, osigttou);
+#else
+      signal (SIGINT, sigint_ours);
+      signal (SIGQUIT, sigquit_ours);
+#endif /* TIOCGPGRP */
+
+      tflags_inferior = fcntl (0, F_GETFL, 0);
+      ioctl (0, TIOCGETP, &sg_inferior);
+
+#if defined(TIOCGETC) && !defined(TIOCGETC_BROKEN)
+      ioctl (0, TIOCGETC, &tc_inferior);
+#endif
+#ifdef TIOCGLTC
+      ioctl (0, TIOCGLTC, &ltc_inferior);
+#endif
+#ifdef TIOCLGET
+      ioctl (0, TIOCLGET, &lmode_inferior);
+#endif
+    }
+
+#ifdef HAVE_TERMIO
+  sg_ours.c_lflag |= ICANON;
+  if (output_only && !(sg_inferior.c_lflag & ICANON))
+    sg_ours.c_lflag &= ~ICANON;
+#else /* not HAVE_TERMIO */
+  sg_ours.sg_flags &= ~RAW & ~CBREAK;
+  if (output_only)
+    sg_ours.sg_flags |= (RAW | CBREAK) & sg_inferior.sg_flags;
+#endif /* not HAVE_TERMIO */
+
+  fcntl (0, F_SETFL, tflags_ours);
+  fcntl (0, F_SETFL, tflags_ours);
+  ioctl (0, TIOCSETN, &sg_ours);
+
+#if defined(TIOCGETC) && !defined(TIOCGETC_BROKEN)
+  ioctl (0, TIOCSETC, &tc_ours);
+#endif
+#ifdef TIOCGLTC
+  ioctl (0, TIOCSLTC, &ltc_ours);
+#endif
+#ifdef TIOCLGET
+  ioctl (0, TIOCLSET, &lmode_ours);
+#endif
+
+#ifdef HAVE_TERMIO
+  sg_ours.c_lflag |= ICANON;
+#else /* not HAVE_TERMIO */
+  sg_ours.sg_flags &= ~RAW & ~CBREAK;
+#endif /* not HAVE_TERMIO */
+}
+
+/* ARGSUSED */
+void
+term_info (arg, from_tty)
+     char *arg;
+     int from_tty;
+{
+  target_terminal_info (arg, from_tty);
+}
+
+void
+child_terminal_info (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  register int i;
+
+  printf_filtered ("Inferior's terminal status (currently saved by GDB):\n");
+
+#ifdef HAVE_TERMIO
+
+  printf_filtered ("fcntl flags = 0x%x, c_iflag = 0x%x, c_oflag = 0x%x,\n",
+         tflags_inferior, sg_inferior.c_iflag, sg_inferior.c_oflag);
+  printf_filtered ("c_cflag = 0x%x, c_lflag = 0x%x, c_line = 0x%x.\n",
+         sg_inferior.c_cflag, sg_inferior.c_lflag, sg_inferior.c_line);
+  printf_filtered ("c_cc: ");
+  for (i = 0; (i < NCC); i += 1)
+    printf_filtered ("0x%x ", sg_inferior.c_cc[i]);
+  printf_filtered ("\n");
+
+#else /* not HAVE_TERMIO */
+
+  printf_filtered ("fcntl flags = 0x%x, sgttyb.sg_flags = 0x%x, owner pid = %d.\n",
+         tflags_inferior, sg_inferior.sg_flags, pgrp_inferior);
+
+#endif /* not HAVE_TERMIO */
+
+#if defined(TIOCGETC) && !defined(TIOCGETC_BROKEN)
+  printf_filtered ("tchars: ");
+  for (i = 0; i < (int)sizeof (struct tchars); i++)
+    printf_filtered ("0x%x ", ((char *)&tc_inferior)[i]);
+  printf_filtered ("\n");
+#endif
+
+#ifdef TIOCGLTC
+  printf_filtered ("ltchars: ");
+  for (i = 0; i < (int)sizeof (struct ltchars); i++)
+    printf_filtered ("0x%x ", ((char *)&ltc_inferior)[i]);
+  printf_filtered ("\n");
+#endif
+  
+#ifdef TIOCLGET
+  printf_filtered ("lmode:  0x%x\n", lmode_inferior);
+#endif
+}
+\f
+/* NEW_TTY is called in new child processes under Unix, which will
+   become debugger target processes.
+   If the TTYNAME argument is non-null, we switch to that tty for further
+   input and output.  In either case, we remember the setup.  */
+
+void
+new_tty (ttyname)
+     char *ttyname;
+{
+  register int tty;
+
+  /* Save the name for later, for determining whether we and the child
+     are sharing a tty.  */
+  inferior_thisrun_terminal = ttyname;
+  if (ttyname == 0)
+    return;
+
+#ifdef TIOCNOTTY
+  /* Disconnect the child process from our controlling terminal.  */
+  tty = open("/dev/tty", O_RDWR);
+  if (tty > 0)
+    {
+      ioctl(tty, TIOCNOTTY, 0);
+      close(tty);
+    }
+#endif
+
+  /* Now open the specified new terminal.  */
+
+  tty = open(ttyname, O_RDWR);
+  if (tty == -1)
+    {
+      print_sys_errmsg (ttyname, errno);
+      _exit(1);
+    }
+
+  /* Avoid use of dup2; doesn't exist on all systems.  */
+  if (tty != 0)
+    { close (0); dup (tty); }
+  if (tty != 1)
+    { close (1); dup (tty); }
+  if (tty != 2)
+    { close (2); dup (tty); }
+  if (tty > 2)
+    close(tty);
+}
+\f
+/* Kill the inferior process.  Make us have no inferior.  */
+
+/* ARGSUSED */
+static void
+kill_command (arg, from_tty)
+     char *arg;
+     int from_tty;
+{
+  if (inferior_pid == 0)
+    error ("The program is not being run.");
+  if (!query ("Kill the inferior process? "))
+    error ("Not confirmed.");
+  target_kill (arg, from_tty);
+}
+
+/* The inferior process has died.  Long live the inferior!  */
+
+void
+generic_mourn_inferior ()
+{
+  inferior_pid = 0;
+  attach_flag = 0;
+  mark_breakpoints_out ();
+  registers_changed ();
+
+#ifdef CLEAR_DEFERRED_STORES
+  /* Delete any pending stores to the inferior... */
+  CLEAR_DEFERRED_STORES;
+#endif
+
+  select_frame ((FRAME) 0, -1);
+  reopen_exec_file ();
+  if (target_has_stack)
+    set_current_frame ( create_new_frame (read_register (FP_REGNUM),
+                                         read_pc ()));
+  else
+    set_current_frame (0);
+  /* It is confusing to the user for ignore counts to stick around
+     from previous runs of the inferior.  So clear them.  */
+  breakpoint_clear_ignore_counts ();
+}
+
+void
+child_mourn_inferior ()
+{
+  unpush_target (&child_ops);
+  generic_mourn_inferior ();
+}
+\f
+#if 0 
+/* This function is just for testing, and on some systems (Sony NewsOS
+   3.2) <sys/user.h> also includes <sys/time.h> which leads to errors
+   (since on this system at least sys/time.h is not protected against
+   multiple inclusion).  */
+/* ARGSUSED */
+static void
+try_writing_regs_command (arg, from_tty)
+     char *arg;
+     int from_tty;
+{
+  register int i;
+  register int value;
+
+  if (inferior_pid == 0)
+    error ("There is no inferior process now.");
+
+  /* A Sun 3/50 or 3/60 (at least) running SunOS 4.0.3 will have a
+     kernel panic if we try to write past the end of the user area.
+     Presumably Sun will fix this bug (it has been reported), but it
+     is tacky to crash the system, so at least on SunOS4 we need to
+     stop writing when we hit the end of the user area.  */
+  for (i = 0; i < sizeof (struct user); i += 2)
+    {
+      QUIT;
+      errno = 0;
+      value = call_ptrace (3, inferior_pid, i, 0);
+      call_ptrace (6, inferior_pid, i, value);
+      if (errno == 0)
+       {
+         printf (" Succeeded with address 0x%x; value 0x%x (%d).\n",
+                 i, value, value);
+       }
+      else if ((i & 0377) == 0)
+       printf (" Failed at 0x%x.\n", i);
+    }
+}
+#endif
+\f
+void
+_initialize_inflow ()
+{
+  add_info ("terminal", term_info,
+          "Print inferior's saved terminal status.");
+
+#if 0
+  add_com ("try-writing-regs", class_obscure, try_writing_regs_command,
+          "Try writing all locations in inferior's system block.\n\
+Report which ones can be written.");
+#endif
+
+  add_com ("kill", class_run, kill_command,
+          "Kill execution of program being debugged.");
+
+  inferior_pid = 0;
+
+  ioctl (0, TIOCGETP, &sg_ours);
+  fcntl (0, F_GETFL, tflags_ours);
+
+#if defined(TIOCGETC) && !defined(TIOCGETC_BROKEN)
+  ioctl (0, TIOCGETC, &tc_ours);
+#endif
+#ifdef TIOCGLTC
+  ioctl (0, TIOCGLTC, &ltc_ours);
+#endif
+#ifdef TIOCLGET
+  ioctl (0, TIOCLGET, &lmode_ours);
+#endif
+
+#ifdef TIOCGPGRP
+  ioctl (0, TIOCGPGRP, &pgrp_ours);
+#endif /* TIOCGPGRP */
+
+  terminal_is_ours = 1;
+}
+
diff --git a/gdb/infptrace.c b/gdb/infptrace.c
new file mode 100644 (file)
index 0000000..03bb271
--- /dev/null
@@ -0,0 +1,397 @@
+/* Low level Unix child interface to ptrace, for GDB when running under Unix.
+   Copyright (C) 1988, 1989, 1990, 1991 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 <stdio.h>
+#include "defs.h"
+#include "param.h"
+#include "frame.h"
+#include "inferior.h"
+#include "target.h"
+
+#ifdef USG
+#include <sys/types.h>
+#endif
+
+#include <sys/param.h>
+#include <sys/dir.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <sys/ptrace.h>
+#if !defined (PT_KILL)
+#define PT_KILL 8
+#define PT_STEP 9
+#define PT_CONTINUE 7
+#define PT_READ_U 3
+#define PT_WRITE_U 6
+#define PT_READ_I 1
+#define PT_WRITE_I 4
+/* The Following Change is for a Sun */
+#define PT_WRITE_D 4
+#endif /* No PT_KILL.  */
+
+#ifndef PT_ATTACH
+#define PT_ATTACH PTRACE_ATTACH
+#endif
+#ifndef PT_DETACH
+#define PT_DETACH PTRACE_DETACH
+#endif
+
+#include "gdbcore.h"
+#include <sys/user.h>          /* After a.out.h  */
+#include <sys/file.h>
+#include <sys/stat.h>
+\f
+/* 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, addr, data)
+     int request, pid, *addr, data;
+{
+  return ptrace (request, pid, addr, data);
+}
+
+#ifdef DEBUG_PTRACE
+/* For the rest of the file, use an extra level of indirection */
+/* This lets us breakpoint usefully on call_ptrace. */
+#define ptrace call_ptrace
+#endif
+
+/* This is used when GDB is exiting.  It gives less chance of error.*/
+
+void
+kill_inferior_fast ()
+{
+  if (inferior_pid == 0)
+    return;
+  ptrace (PT_KILL, inferior_pid, 0, 0);
+  wait ((int *)0);
+}
+
+void
+kill_inferior (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  kill_inferior_fast ();
+  target_mourn_inferior ();
+}
+
+/* Resume execution of the inferior process.
+   If STEP is nonzero, single-step it.
+   If SIGNAL is nonzero, give it that signal.  */
+
+void
+child_resume (step, signal)
+     int step;
+     int signal;
+{
+  errno = 0;
+  /* An address of (int *)1 tells it to continue from where it was. 
+     (If GDB wanted it to start some other way, we have already written
+     a new PC value to the child.)  */
+  if (step)
+    {
+#if defined (NO_SINGLE_STEP)
+      single_step (signal);
+#else /* Have single step.  */
+      ptrace (PT_STEP, inferior_pid, (int *)1, signal);
+#endif /* Have single step.  */
+    }
+  else
+    ptrace (PT_CONTINUE, inferior_pid, (int *)1, signal);
+  if (errno)
+    perror_with_name ("ptrace");
+}
+\f
+#ifdef ATTACH_DETACH
+/* Nonzero if we are debugging an attached process rather than
+   an inferior.  */
+extern int attach_flag;
+
+/* Start debugging the process whose number is PID.  */
+int
+attach (pid)
+     int pid;
+{
+  errno = 0;
+  ptrace (PT_ATTACH, pid, 0, 0);
+  if (errno)
+    perror_with_name ("ptrace");
+  attach_flag = 1;
+  return pid;
+}
+
+/* Stop debugging the process whose number is PID
+   and continue it with signal number SIGNAL.
+   SIGNAL = 0 means just continue it.  */
+
+void
+detach (signal)
+     int signal;
+{
+  errno = 0;
+  ptrace (PT_DETACH, inferior_pid, 1, signal);
+  if (errno)
+    perror_with_name ("ptrace");
+  attach_flag = 0;
+}
+#endif /* ATTACH_DETACH */
+\f
+#if !defined (FETCH_INFERIOR_REGISTERS)
+
+/* KERNEL_U_ADDR is the amount to subtract from u.u_ar0
+   to get the offset in the core file of the register values.  */
+#if defined (KERNEL_U_ADDR_BSD)
+/* Get kernel_u_addr using BSD-style nlist().  */
+CORE_ADDR kernel_u_addr;
+
+void
+_initialize_kernel_u_addr ()
+{
+  struct nlist names[2];
+
+  names[0].n_un.n_name = "_u";
+  names[1].n_un.n_name = NULL;
+  if (nlist ("/vmunix", names) == 0)
+    kernel_u_addr = names[0].n_value;
+  else
+    fatal ("Unable to get kernel u area address.");
+}
+#endif /* KERNEL_U_ADDR_BSD.  */
+
+#if defined (KERNEL_U_ADDR_HPUX)
+/* Get kernel_u_addr using HPUX-style nlist().  */
+CORE_ADDR kernel_u_addr;
+
+struct hpnlist {      
+        char *          n_name;
+        long            n_value;  
+        unsigned char   n_type;   
+        unsigned char   n_length;  
+        short           n_almod;   
+        short           n_unused;
+};
+static struct hpnlist nl[] = {{ "_u", -1, }, { (char *) 0, }};
+
+/* read the value of the u area from the hp-ux kernel */
+void _initialize_kernel_u_addr ()
+{
+    struct user u;
+    nlist ("/hp-ux", &nl);
+    kernel_u_addr = nl[0].n_value;
+}
+#endif /* KERNEL_U_ADDR_HPUX.  */
+
+#if !defined (offsetof)
+#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
+#endif
+
+/* U_REGS_OFFSET is the offset of the registers within the u area.  */
+#if !defined (U_REGS_OFFSET)
+#define U_REGS_OFFSET \
+  ptrace (PT_READ_U, inferior_pid, \
+         (int *)(offsetof (struct user, u_ar0)), 0) - KERNEL_U_ADDR
+#endif
+
+/* Fetch one register.  */
+static void
+fetch_register (regno)
+     int regno;
+{
+  register unsigned int regaddr;
+  char buf[MAX_REGISTER_RAW_SIZE];
+  register int i;
+
+  /* Offset of registers within the u area.  */
+  unsigned int offset = U_REGS_OFFSET;
+
+  regaddr = register_addr (regno, offset);
+  for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int))
+    {
+      *(int *) &buf[i] = ptrace (PT_READ_U, inferior_pid, (int *)regaddr, 0);
+      regaddr += sizeof (int);
+    }
+  supply_register (regno, buf);
+}
+
+/* Fetch all registers, or just one, from the child process.
+   We should check for errors, but we don't.  FIXME.  */
+
+int
+fetch_inferior_registers (regno)
+     int regno;
+{
+  if (regno == -1)
+    for (regno = 0; regno < NUM_REGS; regno++)
+      fetch_register (regno);
+  else
+    fetch_register (regno);
+  return 0;
+}
+
+/* Registers we shouldn't try to store.  */
+#if !defined (CANNOT_STORE_REGISTER)
+#define CANNOT_STORE_REGISTER(regno) 0
+#endif
+
+/* 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).  */
+
+int
+store_inferior_registers (regno)
+     int regno;
+{
+  register unsigned int regaddr;
+  char buf[80];
+  extern char registers[];
+  register int i;
+  int result = 0;
+
+  unsigned int offset = U_REGS_OFFSET;
+
+  if (regno >= 0)
+    {
+      regaddr = register_addr (regno, offset);
+      for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(int))
+       {
+         errno = 0;
+         ptrace (PT_WRITE_U, inferior_pid, (int *)regaddr,
+                 *(int *) &registers[REGISTER_BYTE (regno) + i]);
+         if (errno != 0)
+           {
+             sprintf (buf, "writing register number %d(%d)", regno, i);
+             perror_with_name (buf);
+             result = -1;
+           }
+         regaddr += sizeof(int);
+       }
+    }
+  else
+    {
+      for (regno = 0; regno < NUM_REGS; regno++)
+       {
+         if (CANNOT_STORE_REGISTER (regno))
+           continue;
+         regaddr = register_addr (regno, offset);
+         for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(int))
+           {
+             errno = 0;
+             ptrace (PT_WRITE_U, inferior_pid, (int *)regaddr,
+                     *(int *) &registers[REGISTER_BYTE (regno) + i]);
+             if (errno != 0)
+               {
+                 sprintf (buf, "writing register number %d(%d)", regno, i);
+                 perror_with_name (buf);
+                 result = -1;
+               }
+             regaddr += sizeof(int);
+           }
+       }
+    }
+  return result;
+}
+#endif /* !defined (FETCH_INFERIOR_REGISTERS).  */
+\f
+/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory
+   in the NEW_SUN_PTRACE case.
+   It ought to be straightforward.  But it appears that writing did
+   not write the data that I specified.  I cannot understand where
+   it got the data that it actually did write.  */
+
+/* Copy LEN bytes to or from inferior's memory starting at MEMADDR
+   to debugger memory starting at MYADDR.   Copy to inferior if
+   WRITE is nonzero.
+  
+   Returns the length copied, which is either the LEN argument or zero.
+   This xfer function does not do partial moves, since child_ops
+   doesn't allow memory operations to cross below us in the target stack
+   anyway.  */
+
+int
+child_xfer_memory (memaddr, myaddr, len, write)
+     CORE_ADDR memaddr;
+     char *myaddr;
+     int len;
+     int write;
+{
+  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));
+
+  if (write)
+    {
+      /* Fill start and end extra bytes of buffer with existing memory data.  */
+
+      if (addr != memaddr || len < (int)sizeof (int)) {
+       /* Need part of initial word -- fetch it.  */
+        buffer[0] = ptrace (PT_READ_I, inferior_pid, (int *)addr, 0);
+      }
+
+      if (count > 1)           /* FIXME, avoid if even boundary */
+       {
+         buffer[count - 1]
+           = ptrace (PT_READ_I, inferior_pid,
+                     (int *)(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;
+         ptrace (PT_WRITE_D, inferior_pid, (int *)addr, buffer[i]);
+         if (errno)
+           {
+             /* Using the appropriate one (I or D) is necessary for
+                Gould NP1, at least.  */
+             errno = 0;
+             ptrace (PT_WRITE_I, inferior_pid, (int *)addr, buffer[i]);
+           }
+         if (errno)
+           return 0;
+       }
+    }
+  else
+    {
+      /* Read all the longwords */
+      for (i = 0; i < count; i++, addr += sizeof (int))
+       {
+         errno = 0;
+         buffer[i] = ptrace (PT_READ_I, inferior_pid, (int *)addr, 0);
+         if (errno)
+           return 0;
+         QUIT;
+       }
+
+      /* Copy appropriate bytes out of the buffer.  */
+      bcopy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len);
+    }
+  return len;
+}
diff --git a/gdb/infrun.c b/gdb/infrun.c
new file mode 100644 (file)
index 0000000..1cca592
--- /dev/null
@@ -0,0 +1,1690 @@
+/* Start (run) and stop the inferior process, for GDB.
+   Copyright (C) 1986, 1987, 1988, 1989, 1991 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.  */
+
+/* Notes on the algorithm used in wait_for_inferior to determine if we
+   just did a subroutine call when stepping.  We have the following
+   information at that point:
+
+                  Current and previous (just before this step) pc.
+                 Current and previous sp.
+                 Current and previous start of current function.
+
+   If the start's of the functions don't match, then
+
+       a) We did a subroutine call.
+
+   In this case, the pc will be at the beginning of a function.
+
+       b) We did a subroutine return.
+
+   Otherwise.
+
+       c) We did a longjmp.
+
+   If we did a longjump, we were doing "nexti", since a next would
+   have attempted to skip over the assembly language routine in which
+   the longjmp is coded and would have simply been the equivalent of a
+   continue.  I consider this ok behaivior.  We'd like one of two
+   things to happen if we are doing a nexti through the longjmp()
+   routine: 1) It behaves as a stepi, or 2) It acts like a continue as
+   above.  Given that this is a special case, and that anybody who
+   thinks that the concept of sub calls is meaningful in the context
+   of a longjmp, I'll take either one.  Let's see what happens.  
+
+   Acts like a subroutine return.  I can handle that with no problem
+   at all.
+
+   -->So: If the current and previous beginnings of the current
+   function don't match, *and* the pc is at the start of a function,
+   we've done a subroutine call.  If the pc is not at the start of a
+   function, we *didn't* do a subroutine call.  
+
+   -->If the beginnings of the current and previous function do match,
+   either: 
+
+       a) We just did a recursive call.
+
+          In this case, we would be at the very beginning of a
+          function and 1) it will have a prologue (don't jump to
+          before prologue, or 2) (we assume here that it doesn't have
+          a prologue) there will have been a change in the stack
+          pointer over the last instruction.  (Ie. it's got to put
+          the saved pc somewhere.  The stack is the usual place.  In
+          a recursive call a register is only an option if there's a
+          prologue to do something with it.  This is even true on
+          register window machines; the prologue sets up the new
+          window.  It might not be true on a register window machine
+          where the call instruction moved the register window
+          itself.  Hmmm.  One would hope that the stack pointer would
+          also change.  If it doesn't, somebody send me a note, and
+          I'll work out a more general theory.
+          bug-gdb@prep.ai.mit.edu).  This is true (albeit slipperly
+          so) on all machines I'm aware of:
+
+             m68k:     Call changes stack pointer.  Regular jumps don't.
+
+             sparc:    Recursive calls must have frames and therefor,
+                       prologues.
+
+             vax:      All calls have frames and hence change the
+                       stack pointer.
+
+       b) We did a return from a recursive call.  I don't see that we
+          have either the ability or the need to distinguish this
+          from an ordinary jump.  The stack frame will be printed
+          when and if the frame pointer changes; if we are in a
+          function without a frame pointer, it's the users own
+          lookout.
+
+       c) We did a jump within a function.  We assume that this is
+          true if we didn't do a recursive call.
+
+       d) We are in no-man's land ("I see no symbols here").  We
+          don't worry about this; it will make calls look like simple
+          jumps (and the stack frames will be printed when the frame
+          pointer moves), which is a reasonably non-violent response.
+
+#if 0
+    We skip this; it causes more problems than it's worth.
+#ifdef SUN4_COMPILER_FEATURE
+    We do a special ifdef for the sun 4, forcing it to single step
+  into calls which don't have prologues.  This means that we can't
+  nexti over leaf nodes, we can probably next over them (since they
+  won't have debugging symbols, usually), and we can next out of
+  functions returning structures (with a "call .stret4" at the end).
+#endif
+#endif
+*/
+   
+
+   
+   
+
+#include <stdio.h>
+#include <string.h>
+#include "defs.h"
+#include "param.h"
+#include "symtab.h"
+#include "frame.h"
+#include "inferior.h"
+#include "breakpoint.h"
+#include "wait.h"
+#include "gdbcore.h"
+#include "signame.h"
+#include "command.h"
+#include "terminal.h"          /* For #ifdef TIOCGPGRP and new_tty */
+#include "target.h"
+
+#include <signal.h>
+
+/* unistd.h is needed to #define X_OK */
+#ifdef USG
+#include <unistd.h>
+#else
+#include <sys/file.h>
+#endif
+
+#ifdef SET_STACK_LIMIT_HUGE
+extern int original_stack_limit;
+#endif /* SET_STACK_LIMIT_HUGE */
+
+/* Required by <sys/user.h>.  */
+#include <sys/types.h>
+/* Required by <sys/user.h>, at least on system V.  */
+#include <sys/dir.h>
+/* Needed by IN_SIGTRAMP on some machines (e.g. vax).  */
+#include <sys/param.h>
+/* Needed by IN_SIGTRAMP on some machines (e.g. vax).  */
+#include <sys/user.h>
+
+extern char *getenv ();
+
+extern struct target_ops child_ops;    /* In inftarg.c */
+
+/* Copy of inferior_io_terminal when inferior was last started.  */
+
+extern char *inferior_thisrun_terminal;
+
+
+/* Sigtramp is a routine that the kernel calls (which then calls the
+   signal handler).  On most machines it is a library routine that
+   is linked into the executable.
+
+   This macro, given a program counter value and the name of the
+   function in which that PC resides (which can be null if the
+   name is not known), returns nonzero if the PC and name show
+   that we are in sigtramp.
+
+   On most machines just see if the name is sigtramp (and if we have
+   no name, assume we are not in sigtramp).  */
+#if !defined (IN_SIGTRAMP)
+#define IN_SIGTRAMP(pc, name) \
+  name && !strcmp ("_sigtramp", name)
+#endif
+
+/* Tables of how to react to signals; the user sets them.  */
+
+static char signal_stop[NSIG];
+static char signal_print[NSIG];
+static char signal_program[NSIG];
+
+/* Nonzero if breakpoints are now inserted in the inferior.  */
+/* Nonstatic for initialization during xxx_create_inferior. FIXME. */
+
+/*static*/ int breakpoints_inserted;
+
+/* Function inferior was in as of last step command.  */
+
+static struct symbol *step_start_function;
+
+/* Nonzero => address for special breakpoint for resuming stepping.  */
+
+static CORE_ADDR step_resume_break_address;
+
+/* Pointer to orig contents of the byte where the special breakpoint is.  */
+
+static char step_resume_break_shadow[BREAKPOINT_MAX];
+
+/* Nonzero means the special breakpoint is a duplicate
+   so it has not itself been inserted.  */
+
+static int step_resume_break_duplicate;
+
+/* Nonzero if we are expecting a trace trap and should proceed from it.  */
+
+static int trap_expected;
+
+/* Nonzero if the next time we try to continue the inferior, it will
+   step one instruction and generate a spurious trace trap.
+   This is used to compensate for a bug in HP-UX.  */
+
+static int trap_expected_after_continue;
+
+/* Nonzero means expecting a trace trap
+   and should stop the inferior and return silently when it happens.  */
+
+int stop_after_trap;
+
+/* Nonzero means expecting a trap and caller will handle it themselves.
+   It is used after attach, due to attaching to a process;
+   when running in the shell before the child program has been exec'd;
+   and when running some kinds of remote stuff (FIXME?).  */
+
+int stop_soon_quietly;
+
+/* Nonzero if pc has been changed by the debugger
+   since the inferior stopped.  */
+
+int pc_changed;
+
+/* Nonzero if proceed is being used for a "finish" command or a similar
+   situation when stop_registers should be saved.  */
+
+int proceed_to_finish;
+
+/* Save register contents here when about to pop a stack dummy frame,
+   if-and-only-if proceed_to_finish is set.
+   Thus this contains the return value from the called function (assuming
+   values are returned in a register).  */
+
+char stop_registers[REGISTER_BYTES];
+
+/* Nonzero if program stopped due to error trying to insert breakpoints.  */
+
+static int breakpoints_failed;
+
+/* Nonzero after stop if current stack frame should be printed.  */
+
+static int stop_print_frame;
+
+#ifdef NO_SINGLE_STEP
+extern int one_stepped;                /* From machine dependent code */
+extern void single_step ();    /* Same. */
+#endif /* NO_SINGLE_STEP */
+
+static void insert_step_breakpoint ();
+static void remove_step_breakpoint ();
+/*static*/ void wait_for_inferior ();
+void init_wait_for_inferior ();
+void normal_stop ();
+
+\f
+/* Clear out all variables saying what to do when inferior is continued.
+   First do this, then set the ones you want, then call `proceed'.  */
+
+void
+clear_proceed_status ()
+{
+  trap_expected = 0;
+  step_range_start = 0;
+  step_range_end = 0;
+  step_frame_address = 0;
+  step_over_calls = -1;
+  step_resume_break_address = 0;
+  stop_after_trap = 0;
+  stop_soon_quietly = 0;
+  proceed_to_finish = 0;
+  breakpoint_proceeded = 1;    /* We're about to proceed... */
+
+  /* Discard any remaining commands or status from previous stop.  */
+  bpstat_clear (&stop_bpstat);
+}
+
+/* Basic routine for continuing the program in various fashions.
+
+   ADDR is the address to resume at, or -1 for resume where stopped.
+   SIGGNAL is the signal to give it, or 0 for none,
+     or -1 for act according to how it stopped.
+   STEP is nonzero if should trap after one instruction.
+     -1 means return after that and print nothing.
+     You should probably set various step_... variables
+     before calling here, if you are stepping.
+
+   You should call clear_proceed_status before calling proceed.  */
+
+void
+proceed (addr, siggnal, step)
+     CORE_ADDR addr;
+     int siggnal;
+     int step;
+{
+  int oneproc = 0;
+
+  if (step > 0)
+    step_start_function = find_pc_function (read_pc ());
+  if (step < 0)
+    stop_after_trap = 1;
+
+  if (addr == -1)
+    {
+      /* If there is a breakpoint at the address we will resume at,
+        step one instruction before inserting breakpoints
+        so that we do not stop right away.  */
+
+      if (!pc_changed && breakpoint_here_p (read_pc ()))
+       oneproc = 1;
+    }
+  else
+    {
+      write_register (PC_REGNUM, addr);
+#ifdef NPC_REGNUM
+      write_register (NPC_REGNUM, addr + 4);
+#ifdef NNPC_REGNUM
+      write_register (NNPC_REGNUM, addr + 8);
+#endif
+#endif
+    }
+
+  if (trap_expected_after_continue)
+    {
+      /* If (step == 0), a trap will be automatically generated after
+        the first instruction is executed.  Force step one
+        instruction to clear this condition.  This should not occur
+        if step is nonzero, but it is harmless in that case.  */
+      oneproc = 1;
+      trap_expected_after_continue = 0;
+    }
+
+  if (oneproc)
+    /* We will get a trace trap after one instruction.
+       Continue it automatically and insert breakpoints then.  */
+    trap_expected = 1;
+  else
+    {
+      int temp = insert_breakpoints ();
+      if (temp)
+       {
+         print_sys_errmsg ("ptrace", temp);
+         error ("Cannot insert breakpoints.\n\
+The same program may be running in another process.");
+       }
+      breakpoints_inserted = 1;
+    }
+
+  /* Install inferior's terminal modes.  */
+  target_terminal_inferior ();
+
+  if (siggnal >= 0)
+    stop_signal = siggnal;
+  /* If this signal should not be seen by program,
+     give it zero.  Used for debugging signals.  */
+  else if (stop_signal < NSIG && !signal_program[stop_signal])
+    stop_signal= 0;
+
+  /* Handle any optimized stores to the inferior NOW...  */
+#ifdef DO_DEFERRED_STORES
+  DO_DEFERRED_STORES;
+#endif
+
+  /* Resume inferior.  */
+  target_resume (oneproc || step || bpstat_should_step (), stop_signal);
+
+  /* Wait for it to stop (if not standalone)
+     and in any case decode why it stopped, and act accordingly.  */
+
+  wait_for_inferior ();
+  normal_stop ();
+}
+
+#if 0
+/* This might be useful (not sure), but isn't currently used.  See also
+   write_pc().  */
+/* Writing the inferior pc as a register calls this function
+   to inform infrun that the pc has been set in the debugger.  */
+
+void
+writing_pc (val)
+     CORE_ADDR val;
+{
+  stop_pc = val;
+  pc_changed = 1;
+}
+#endif
+
+/* Record the pc and sp of the program the last time it stopped.
+   These are just used internally by wait_for_inferior, but need
+   to be preserved over calls to it and cleared when the inferior
+   is started.  */
+static CORE_ADDR prev_pc;
+static CORE_ADDR prev_sp;
+static CORE_ADDR prev_func_start;
+static char *prev_func_name;
+
+/* Start an inferior Unix child process and sets inferior_pid to its pid.
+   EXEC_FILE is the file to run.
+   ALLARGS is a string containing the arguments to the program.
+   ENV is the environment vector to pass.  Errors reported with error().  */
+
+#ifndef SHELL_FILE
+#define SHELL_FILE "/bin/sh"
+#endif
+
+void
+child_create_inferior (exec_file, allargs, env)
+     char *exec_file;
+     char *allargs;
+     char **env;
+{
+  int pid;
+  char *shell_command;
+  extern int sys_nerr;
+  extern char *sys_errlist[];
+  char *shell_file;
+  static char default_shell_file[] = SHELL_FILE;
+  int len;
+  int pending_execs;
+  /* Set debug_fork then attach to the child while it sleeps, to debug. */
+  static int debug_fork = 0;
+  /* This is set to the result of setpgrp, which if vforked, will be visible
+     to you in the parent process.  It's only used by humans for debugging.  */
+  static int debug_setpgrp = 657473;
+
+  /* The user might want tilde-expansion, and in general probably wants
+     the program to behave the same way as if run from
+     his/her favorite shell.  So we let the shell run it for us.
+     FIXME, this should probably search the local environment (as
+     modified by the setenv command), not the env gdb inherited.  */
+  shell_file = getenv ("SHELL");
+  if (shell_file == NULL)
+    shell_file = default_shell_file;
+  
+  len = 5 + strlen (exec_file) + 1 + strlen (allargs) + 1 + /*slop*/ 10;
+  /* If desired, concat something onto the front of ALLARGS.
+     SHELL_COMMAND is the result.  */
+#ifdef SHELL_COMMAND_CONCAT
+  shell_command = (char *) alloca (strlen (SHELL_COMMAND_CONCAT) + len);
+  strcpy (shell_command, SHELL_COMMAND_CONCAT);
+#else
+  shell_command = (char *) alloca (len);
+  shell_command[0] = '\0';
+#endif
+  strcat (shell_command, "exec ");
+  strcat (shell_command, exec_file);
+  strcat (shell_command, " ");
+  strcat (shell_command, allargs);
+
+  /* exec is said to fail if the executable is open.  */
+  close_exec_file ();
+
+#if defined(USG) && !defined(HAVE_VFORK)
+  pid = fork ();
+#else
+  if (debug_fork)
+    pid = fork ();
+  else
+    pid = vfork ();
+#endif
+
+  if (pid < 0)
+    perror_with_name ("vfork");
+
+  if (pid == 0)
+    {
+      if (debug_fork) 
+       sleep (debug_fork);
+
+#ifdef TIOCGPGRP
+      /* Run inferior in a separate process group.  */
+      debug_setpgrp = setpgrp (getpid (), getpid ());
+      if (0 != debug_setpgrp)
+        perror("setpgrp failed in child");
+#endif /* TIOCGPGRP */
+
+#ifdef SET_STACK_LIMIT_HUGE
+      /* Reset the stack limit back to what it was.  */
+      {
+       struct rlimit rlim;
+
+       getrlimit (RLIMIT_STACK, &rlim);
+       rlim.rlim_cur = original_stack_limit;
+       setrlimit (RLIMIT_STACK, &rlim);
+      }
+#endif /* SET_STACK_LIMIT_HUGE */
+
+      /* Tell the terminal handling subsystem what tty we plan to run on;
+        it will now switch to that one if non-null.  */
+
+      new_tty (inferior_io_terminal);
+
+      /* Changing the signal handlers for the inferior after
+        a vfork can also change them for the superior, so we don't mess
+        with signals here.  See comments in
+        initialize_signals for how we get the right signal handlers
+        for the inferior.  */
+
+      call_ptrace (0, 0, 0, 0);                /* "Trace me, Dr. Memory!" */
+      execle (shell_file, shell_file, "-c", shell_command, (char *)0, env);
+
+      fprintf (stderr, "Cannot exec %s: %s.\n", shell_file,
+              errno < sys_nerr ? sys_errlist[errno] : "unknown error");
+      fflush (stderr);
+      _exit (0177);
+    }
+
+  /* Now that we have a child process, make it our target.  */
+  push_target (&child_ops);
+
+#ifdef CREATE_INFERIOR_HOOK
+  CREATE_INFERIOR_HOOK (pid);
+#endif  
+
+/* The process was started by the fork that created it,
+   but it will have stopped one instruction after execing the shell.
+   Here we must get it up to actual execution of the real program.  */
+
+  inferior_pid = pid;          /* Needed for wait_for_inferior stuff below */
+
+  clear_proceed_status ();
+
+#if defined (START_INFERIOR_HOOK)
+  START_INFERIOR_HOOK ();
+#endif
+
+  /* We will get a trace trap after one instruction.
+     Continue it automatically.  Eventually (after shell does an exec)
+     it will get another trace trap.  Then insert breakpoints and continue.  */
+
+#ifdef START_INFERIOR_TRAPS_EXPECTED
+  pending_execs = START_INFERIOR_TRAPS_EXPECTED;
+#else
+  pending_execs = 2;
+#endif
+
+  init_wait_for_inferior ();
+
+  /* Set up the "saved terminal modes" of the inferior
+     based on what modes we are starting it with.  */
+  target_terminal_init ();
+
+  /* Install inferior's terminal modes.  */
+  target_terminal_inferior ();
+
+  while (1)
+    {
+      stop_soon_quietly = 1;   /* Make wait_for_inferior be quiet */
+      wait_for_inferior ();
+      if (stop_signal != SIGTRAP)
+       {
+         /* Let shell child handle its own signals in its own way */
+         /* FIXME, what if child has exit()ed?  Must exit loop somehow */
+         target_resume (0, stop_signal);
+       }
+      else
+       {
+         /* We handle SIGTRAP, however; it means child did an exec.  */
+         if (0 == --pending_execs)
+           break;
+         target_resume (0, 0);         /* Just make it go on */
+       }
+    }
+  stop_soon_quietly = 0;
+
+  /* Should this perhaps just be a "proceed" call?  FIXME */
+  insert_step_breakpoint ();
+  breakpoints_failed = insert_breakpoints ();
+  if (!breakpoints_failed)
+    {
+      breakpoints_inserted = 1;
+      target_terminal_inferior();
+      /* Start the child program going on its first instruction, single-
+        stepping if we need to.  */
+      target_resume (bpstat_should_step (), 0);
+      wait_for_inferior ();
+      normal_stop ();
+    }
+}
+
+/* Start remote-debugging of a machine over a serial link.  */
+
+void
+start_remote ()
+{
+  init_wait_for_inferior ();
+  clear_proceed_status ();
+  stop_soon_quietly = 1;
+  trap_expected = 0;
+}
+
+/* Initialize static vars when a new inferior begins.  */
+
+void
+init_wait_for_inferior ()
+{
+  /* These are meaningless until the first time through wait_for_inferior.  */
+  prev_pc = 0;
+  prev_sp = 0;
+  prev_func_start = 0;
+  prev_func_name = NULL;
+
+  trap_expected_after_continue = 0;
+  breakpoints_inserted = 0;
+  mark_breakpoints_out ();
+  stop_signal = 0;             /* Don't confuse first call to proceed(). */
+}
+
+
+/* Attach to process PID, then initialize for debugging it
+   and wait for the trace-trap that results from attaching.  */
+
+void
+child_attach (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  char *exec_file;
+  int pid;
+
+  dont_repeat();
+
+  if (!args)
+    error_no_arg ("process-id to attach");
+
+#ifndef ATTACH_DETACH
+  error ("Can't attach to a process on this machine.");
+#else
+  pid = atoi (args);
+
+  if (target_has_execution)
+    {
+      if (query ("A program is being debugged already.  Kill it? "))
+       target_kill ((char *)0, from_tty);
+      else
+       error ("Inferior not killed.");
+    }
+
+  exec_file = (char *) get_exec_file (1);
+
+  if (from_tty)
+    {
+      printf ("Attaching program: %s pid %d\n",
+             exec_file, pid);
+      fflush (stdout);
+    }
+
+  attach (pid);
+  inferior_pid = pid;
+  push_target (&child_ops);
+
+  mark_breakpoints_out ();
+  target_terminal_init ();
+  clear_proceed_status ();
+  stop_soon_quietly = 1;
+  /*proceed (-1, 0, -2);*/
+  target_terminal_inferior ();
+  wait_for_inferior ();
+  normal_stop ();
+#endif  /* ATTACH_DETACH */
+}
+\f
+/* Wait for control to return from inferior to debugger.
+   If inferior gets a signal, we may decide to start it up again
+   instead of returning.  That is why there is a loop in this function.
+   When this function actually returns it means the inferior
+   should be left stopped and GDB should read more commands.  */
+
+void
+wait_for_inferior ()
+{
+  WAITTYPE w;
+  int another_trap;
+  int random_signal;
+  CORE_ADDR stop_sp;
+  CORE_ADDR stop_func_start;
+  char *stop_func_name;
+  CORE_ADDR prologue_pc;
+  int stop_step_resume_break;
+  struct symtab_and_line sal;
+  int remove_breakpoints_on_following_step = 0;
+
+#if 0
+  /* This no longer works now that read_register is lazy;
+     it might try to ptrace when the process is not stopped.  */
+  prev_pc = read_pc ();
+  (void) find_pc_partial_function (prev_pc, &prev_func_name,
+                                  &prev_func_start);
+  prev_func_start += FUNCTION_START_OFFSET;
+  prev_sp = read_register (SP_REGNUM);
+#endif /* 0 */
+
+  while (1)
+    {
+      /* Clean up saved state that will become invalid.  */
+      pc_changed = 0;
+      flush_cached_frames ();
+      registers_changed ();
+
+      target_wait (&w);
+
+      /* See if the process still exists; clean up if it doesn't.  */
+      if (WIFEXITED (w))
+       {
+         target_terminal_ours ();      /* Must do this before mourn anyway */
+         if (WEXITSTATUS (w))
+           printf ("\nProgram exited with code 0%o.\n", 
+                    (unsigned int)WEXITSTATUS (w));
+         else
+           if (!batch_mode())
+             printf ("\nProgram exited normally.\n");
+         fflush (stdout);
+         target_mourn_inferior ();
+#ifdef NO_SINGLE_STEP
+         one_stepped = 0;
+#endif
+         stop_print_frame = 0;
+         break;
+       }
+      else if (!WIFSTOPPED (w))
+       {
+         stop_print_frame = 0;
+         stop_signal = WTERMSIG (w);
+         target_terminal_ours ();      /* Must do this before mourn anyway */
+         target_kill ((char *)0, 0);   /* kill mourns as well */
+#ifdef PRINT_RANDOM_SIGNAL
+         printf ("\nProgram terminated: ");
+         PRINT_RANDOM_SIGNAL (stop_signal);
+#else
+         printf ("\nProgram terminated with signal %d, %s\n",
+                 stop_signal,
+                 stop_signal < NSIG
+                 ? sys_siglist[stop_signal]
+                 : "(undocumented)");
+#endif
+         printf ("The inferior process no longer exists.\n");
+         fflush (stdout);
+#ifdef NO_SINGLE_STEP
+         one_stepped = 0;
+#endif
+         break;
+       }
+      
+#ifdef NO_SINGLE_STEP
+      if (one_stepped)
+       single_step (0);        /* This actually cleans up the ss */
+#endif /* NO_SINGLE_STEP */
+      
+      stop_pc = read_pc ();
+      set_current_frame ( create_new_frame (read_register (FP_REGNUM),
+                                           read_pc ()));
+      
+      stop_frame_address = FRAME_FP (get_current_frame ());
+      stop_sp = read_register (SP_REGNUM);
+      stop_func_start = 0;
+      stop_func_name = 0;
+      /* Don't care about return value; stop_func_start and stop_func_name
+        will both be 0 if it doesn't work.  */
+      (void) find_pc_partial_function (stop_pc, &stop_func_name,
+                                      &stop_func_start);
+      stop_func_start += FUNCTION_START_OFFSET;
+      another_trap = 0;
+      bpstat_clear (&stop_bpstat);
+      stop_step = 0;
+      stop_stack_dummy = 0;
+      stop_print_frame = 1;
+      stop_step_resume_break = 0;
+      random_signal = 0;
+      stopped_by_random_signal = 0;
+      breakpoints_failed = 0;
+      
+      /* Look at the cause of the stop, and decide what to do.
+        The alternatives are:
+        1) break; to really stop and return to the debugger,
+        2) drop through to start up again
+        (set another_trap to 1 to single step once)
+        3) set random_signal to 1, and the decision between 1 and 2
+        will be made according to the signal handling tables.  */
+      
+      stop_signal = WSTOPSIG (w);
+      
+      /* First, distinguish signals caused by the debugger from signals
+        that have to do with the program's own actions.
+        Note that breakpoint insns may cause SIGTRAP or SIGILL
+        or SIGEMT, depending on the operating system version.
+        Here we detect when a SIGILL or SIGEMT is really a breakpoint
+        and change it to SIGTRAP.  */
+      
+      if (stop_signal == SIGTRAP
+         || (breakpoints_inserted &&
+             (stop_signal == SIGILL
+              || stop_signal == SIGEMT))
+         || stop_soon_quietly)
+       {
+         if (stop_signal == SIGTRAP && stop_after_trap)
+           {
+             stop_print_frame = 0;
+             break;
+           }
+         if (stop_soon_quietly)
+           break;
+
+         /* Don't even think about breakpoints
+            if just proceeded over a breakpoint.
+
+            However, if we are trying to proceed over a breakpoint
+            and end up in sigtramp, then step_resume_break_address
+            will be set and we should check whether we've hit the
+            step breakpoint.  */
+         if (stop_signal == SIGTRAP && trap_expected
+             && step_resume_break_address == NULL)
+           bpstat_clear (&stop_bpstat);
+         else
+           {
+             /* See if there is a breakpoint at the current PC.  */
+#if DECR_PC_AFTER_BREAK
+             /* Notice the case of stepping through a jump
+                that leads just after a breakpoint.
+                Don't confuse that with hitting the breakpoint.
+                What we check for is that 1) stepping is going on
+                and 2) the pc before the last insn does not match
+                the address of the breakpoint before the current pc.  */
+             if (!(prev_pc != stop_pc - DECR_PC_AFTER_BREAK
+                   && step_range_end && !step_resume_break_address))
+#endif /* DECR_PC_AFTER_BREAK not zero */
+               {
+                 /* See if we stopped at the special breakpoint for
+                    stepping over a subroutine call.  If both are zero,
+                    this wasn't the reason for the stop.  */
+                 if (stop_pc - DECR_PC_AFTER_BREAK
+                                 == step_resume_break_address
+                     && step_resume_break_address)
+                   {
+                     stop_step_resume_break = 1;
+                     if (DECR_PC_AFTER_BREAK)
+                       {
+                         stop_pc -= DECR_PC_AFTER_BREAK;
+                         write_register (PC_REGNUM, stop_pc);
+                         pc_changed = 0;
+                       }
+                   }
+                 else
+                   {
+                     stop_bpstat =
+                       bpstat_stop_status (&stop_pc, stop_frame_address);
+                     /* Following in case break condition called a
+                        function.  */
+                     stop_print_frame = 1;
+                   }
+               }
+           }
+         
+         if (stop_signal == SIGTRAP)
+           random_signal
+             = !(bpstat_explains_signal (stop_bpstat)
+                 || trap_expected
+                 || stop_step_resume_break
+                 || PC_IN_CALL_DUMMY (stop_pc, stop_sp, stop_frame_address)
+                 || (step_range_end && !step_resume_break_address));
+         else
+           {
+             random_signal
+               = !(bpstat_explains_signal (stop_bpstat)
+                   || stop_step_resume_break
+                   /* End of a stack dummy.  Some systems (e.g. Sony
+                      news) give another signal besides SIGTRAP,
+                      so check here as well as above.  */
+                   || (stop_sp INNER_THAN stop_pc
+                       && stop_pc INNER_THAN stop_frame_address)
+                   );
+             if (!random_signal)
+               stop_signal = SIGTRAP;
+           }
+       }
+      else
+       random_signal = 1;
+      
+      /* For the program's own signals, act according to
+        the signal handling tables.  */
+      
+      if (random_signal)
+       {
+         /* Signal not for debugging purposes.  */
+         int printed = 0;
+         
+         stopped_by_random_signal = 1;
+         
+         if (stop_signal >= NSIG
+             || signal_print[stop_signal])
+           {
+             printed = 1;
+             target_terminal_ours_for_output ();
+#ifdef PRINT_RANDOM_SIGNAL
+             PRINT_RANDOM_SIGNAL (stop_signal);
+#else
+             printf ("\nProgram received signal %d, %s\n",
+                     stop_signal,
+                     stop_signal < NSIG
+                     ? sys_siglist[stop_signal]
+                     : "(undocumented)");
+#endif /* PRINT_RANDOM_SIGNAL */
+             fflush (stdout);
+           }
+         if (stop_signal >= NSIG
+             || signal_stop[stop_signal])
+           break;
+         /* If not going to stop, give terminal back
+            if we took it away.  */
+         else if (printed)
+           target_terminal_inferior ();
+       }
+      
+      /* Handle cases caused by hitting a breakpoint.  */
+      
+      if (!random_signal
+         && (bpstat_explains_signal (stop_bpstat) || stop_step_resume_break))
+       {
+         /* Does a breakpoint want us to stop?  */
+         if (bpstat_stop (stop_bpstat))
+           {
+             stop_print_frame = bpstat_should_print (stop_bpstat);
+             break;
+           }
+         /* But if we have hit the step-resumption breakpoint,
+            remove it.  It has done its job getting us here.
+            The sp test is to make sure that we don't get hung
+            up in recursive calls in functions without frame
+            pointers.  If the stack pointer isn't outside of
+            where the breakpoint was set (within a routine to be
+            stepped over), we're in the middle of a recursive
+            call. Not true for reg window machines (sparc)
+            because the must change frames to call things and
+            the stack pointer doesn't have to change if it
+            the bp was set in a routine without a frame (pc can
+            be stored in some other window).
+            
+            The removal of the sp test is to allow calls to
+            alloca.  Nasty things were happening.  Oh, well,
+            gdb can only handle one level deep of lack of
+            frame pointer. */
+         if (stop_step_resume_break
+             && (step_frame_address == 0
+                 || (stop_frame_address == step_frame_address)))
+           {
+             remove_step_breakpoint ();
+             step_resume_break_address = 0;
+
+             /* If were waiting for a trap, hitting the step_resume_break
+                doesn't count as getting it.  */
+             if (trap_expected)
+               another_trap = 1;
+           }
+         /* Otherwise, must remove breakpoints and single-step
+            to get us past the one we hit.  */
+         else
+           {
+             remove_breakpoints ();
+             remove_step_breakpoint ();
+             breakpoints_inserted = 0;
+             another_trap = 1;
+           }
+         
+         /* We come here if we hit a breakpoint but should not
+            stop for it.  Possibly we also were stepping
+            and should stop for that.  So fall through and
+            test for stepping.  But, if not stepping,
+            do not stop.  */
+       }
+      
+      /* If this is the breakpoint at the end of a stack dummy,
+        just stop silently.  */
+      if (PC_IN_CALL_DUMMY (stop_pc, stop_sp, stop_frame_address))
+         {
+           stop_print_frame = 0;
+           stop_stack_dummy = 1;
+#ifdef HP_OS_BUG
+           trap_expected_after_continue = 1;
+#endif
+           break;
+         }
+      
+      if (step_resume_break_address)
+       /* Having a step-resume breakpoint overrides anything
+          else having to do with stepping commands until
+          that breakpoint is reached.  */
+       ;
+      /* If stepping through a line, keep going if still within it.  */
+      else if (!random_signal
+              && step_range_end
+              && stop_pc >= step_range_start
+              && stop_pc < step_range_end
+              /* The step range might include the start of the
+                 function, so if we are at the start of the
+                 step range and either the stack or frame pointers
+                 just changed, we've stepped outside */
+              && !(stop_pc == step_range_start
+                   && stop_frame_address
+                   && (stop_sp INNER_THAN prev_sp
+                       || stop_frame_address != step_frame_address)))
+       {
+#if 0
+         /* When "next"ing through a function,
+            This causes an extra stop at the end.
+            Is there any reason for this?
+            It's confusing to the user.  */
+         /* Don't step through the return from a function
+            unless that is the first instruction stepped through.  */
+         if (ABOUT_TO_RETURN (stop_pc))
+           {
+             stop_step = 1;
+             break;
+           }
+#endif
+       }
+      
+      /* We stepped out of the stepping range.  See if that was due
+        to a subroutine call that we should proceed to the end of.  */
+      else if (!random_signal && step_range_end)
+       {
+         if (stop_func_start)
+           {
+             prologue_pc = stop_func_start;
+             SKIP_PROLOGUE (prologue_pc);
+           }
+
+         /* Did we just take a signal?  */
+         if (IN_SIGTRAMP (stop_pc, stop_func_name)
+             && !IN_SIGTRAMP (prev_pc, prev_func_name))
+           {
+             /* This code is needed at least in the following case:
+                The user types "next" and then a signal arrives (before
+                the "next" is done).  */
+             /* We've just taken a signal; go until we are back to
+                the point where we took it and one more.  */
+             step_resume_break_address = prev_pc;
+             step_resume_break_duplicate =
+               breakpoint_here_p (step_resume_break_address);
+             if (breakpoints_inserted)
+               insert_step_breakpoint ();
+             /* Make sure that the stepping range gets us past
+                that instruction.  */
+             if (step_range_end == 1)
+               step_range_end = (step_range_start = prev_pc) + 1;
+             remove_breakpoints_on_following_step = 1;
+           }
+
+         /* ==> See comments at top of file on this algorithm.  <==*/
+         
+         else if (stop_pc == stop_func_start
+             && (stop_func_start != prev_func_start
+                 || prologue_pc != stop_func_start
+                 || stop_sp != prev_sp))
+           {
+             /* It's a subroutine call */
+             if (step_over_calls > 0 
+                 || (step_over_calls &&  find_pc_function (stop_pc) == 0))
+               {
+                 /* A subroutine call has happened.  */
+                 /* Set a special breakpoint after the return */
+                 step_resume_break_address =
+                   ADDR_BITS_REMOVE
+                     (SAVED_PC_AFTER_CALL (get_current_frame ()));
+                 step_resume_break_duplicate
+                   = breakpoint_here_p (step_resume_break_address);
+                 if (breakpoints_inserted)
+                   insert_step_breakpoint ();
+               }
+             /* Subroutine call with source code we should not step over.
+                Do step to the first line of code in it.  */
+             else if (step_over_calls)
+               {
+                 SKIP_PROLOGUE (stop_func_start);
+                 sal = find_pc_line (stop_func_start, 0);
+                 /* Use the step_resume_break to step until
+                    the end of the prologue, even if that involves jumps
+                    (as it seems to on the vax under 4.2).  */
+                 /* If the prologue ends in the middle of a source line,
+                    continue to the end of that source line.
+                    Otherwise, just go to end of prologue.  */
+#ifdef PROLOGUE_FIRSTLINE_OVERLAP
+                 /* no, don't either.  It skips any code that's
+                    legitimately on the first line.  */
+#else
+                 if (sal.end && sal.pc != stop_func_start)
+                   stop_func_start = sal.end;
+#endif
+                 
+                 if (stop_func_start == stop_pc)
+                   {
+                     /* We are already there: stop now.  */
+                     stop_step = 1;
+                     break;
+                   }
+                 else
+                   /* Put the step-breakpoint there and go until there. */
+                   {
+                     step_resume_break_address = stop_func_start;
+                     
+                     step_resume_break_duplicate
+                       = breakpoint_here_p (step_resume_break_address);
+                     if (breakpoints_inserted)
+                       insert_step_breakpoint ();
+                     /* Do not specify what the fp should be when we stop
+                        since on some machines the prologue
+                        is where the new fp value is established.  */
+                     step_frame_address = 0;
+                     /* And make sure stepping stops right away then.  */
+                     step_range_end = step_range_start;
+                   }
+               }
+             else
+               {
+                 /* We get here only if step_over_calls is 0 and we
+                    just stepped into a subroutine.  I presume
+                    that step_over_calls is only 0 when we're
+                    supposed to be stepping at the assembly
+                    language level.*/
+                 stop_step = 1;
+                 break;
+               }
+           }
+         /* No subroutince call; stop now.  */
+         else
+           {
+             stop_step = 1;
+             break;
+           }
+       }
+
+      else if (trap_expected
+              && IN_SIGTRAMP (stop_pc, stop_func_name)
+              && !IN_SIGTRAMP (prev_pc, prev_func_name))
+       {
+         /* What has happened here is that we have just stepped the inferior
+            with a signal (because it is a signal which shouldn't make
+            us stop), thus stepping into sigtramp.
+
+            So we need to set a step_resume_break_address breakpoint
+            and continue until we hit it, and then step.  */
+         step_resume_break_address = prev_pc;
+         /* Always 1, I think, but it's probably easier to have
+            the step_resume_break as usual rather than trying to
+            re-use the breakpoint which is already there.  */
+         step_resume_break_duplicate =
+           breakpoint_here_p (step_resume_break_address);
+         if (breakpoints_inserted)
+           insert_step_breakpoint ();
+         remove_breakpoints_on_following_step = 1;
+         another_trap = 1;
+       }
+
+      /* Save the pc before execution, to compare with pc after stop.  */
+      prev_pc = read_pc ();    /* Might have been DECR_AFTER_BREAK */
+      prev_func_start = stop_func_start; /* Ok, since if DECR_PC_AFTER
+                                         BREAK is defined, the
+                                         original pc would not have
+                                         been at the start of a
+                                         function. */
+      prev_func_name = stop_func_name;
+      prev_sp = stop_sp;
+
+      /* If we did not do break;, it means we should keep
+        running the inferior and not return to debugger.  */
+
+      if (trap_expected && stop_signal != SIGTRAP)
+       {
+         /* We took a signal (which we are supposed to pass through to
+            the inferior, else we'd have done a break above) and we
+            haven't yet gotten our trap.  Simply continue.  */
+         target_resume ((step_range_end && !step_resume_break_address)
+                 || (trap_expected && !step_resume_break_address)
+                 || bpstat_should_step (),
+                 stop_signal);
+       }
+      else
+       {
+         /* Either the trap was not expected, but we are continuing
+            anyway (the user asked that this signal be passed to the
+            child)
+              -- or --
+            The signal was SIGTRAP, e.g. it was our signal, but we
+            decided we should resume from it.
+
+            We're going to run this baby now!
+
+            Insert breakpoints now, unless we are trying
+            to one-proceed past a breakpoint.  */
+         /* If we've just finished a special step resume and we don't
+            want to hit a breakpoint, pull em out.  */
+         if (!step_resume_break_address &&
+             remove_breakpoints_on_following_step)
+           {
+             remove_breakpoints_on_following_step = 0;
+             remove_breakpoints ();
+             breakpoints_inserted = 0;
+           }
+         else if (!breakpoints_inserted &&
+                  (step_resume_break_address != NULL || !another_trap))
+           {
+             insert_step_breakpoint ();
+             breakpoints_failed = insert_breakpoints ();
+             if (breakpoints_failed)
+               break;
+             breakpoints_inserted = 1;
+           }
+
+         trap_expected = another_trap;
+
+         if (stop_signal == SIGTRAP)
+           stop_signal = 0;
+
+#ifdef SHIFT_INST_REGS
+         /* I'm not sure when this following segment applies.  I do know, now,
+            that we shouldn't rewrite the regs when we were stopped by a
+            random signal from the inferior process.  */
+
+          if (!stop_breakpoint && (stop_signal != SIGCLD) 
+              && !stopped_by_random_signal)
+            {
+            CORE_ADDR pc_contents = read_register (PC_REGNUM);
+            CORE_ADDR npc_contents = read_register (NPC_REGNUM);
+            if (pc_contents != npc_contents)
+              {
+              write_register (NNPC_REGNUM, npc_contents);
+              write_register (NPC_REGNUM, pc_contents);
+             }
+            }
+#endif /* SHIFT_INST_REGS */
+
+         target_resume ((step_range_end && !step_resume_break_address)
+                 || (trap_expected && !step_resume_break_address)
+                 || bpstat_should_step (),
+                 stop_signal);
+       }
+    }
+  if (target_has_execution)
+    {
+      /* Assuming the inferior still exists, set these up for next
+        time, just like we did above if we didn't break out of the
+        loop.  */
+      prev_pc = read_pc ();
+      prev_func_start = stop_func_start;
+      prev_func_name = stop_func_name;
+      prev_sp = stop_sp;
+    }
+}
+\f
+/* Here to return control to GDB when the inferior stops for real.
+   Print appropriate messages, remove breakpoints, give terminal our modes.
+
+   STOP_PRINT_FRAME nonzero means print the executing frame
+   (pc, function, args, file, line number and line text).
+   BREAKPOINTS_FAILED nonzero means stop was due to error
+   attempting to insert breakpoints.  */
+
+void
+normal_stop ()
+{
+  /* Make sure that the current_frame's pc is correct.  This
+     is a correction for setting up the frame info before doing
+     DECR_PC_AFTER_BREAK */
+  if (target_has_execution)
+    (get_current_frame ())->pc = read_pc ();
+  
+  if (breakpoints_failed)
+    {
+      target_terminal_ours_for_output ();
+      print_sys_errmsg ("ptrace", breakpoints_failed);
+      printf ("Stopped; cannot insert breakpoints.\n\
+The same program may be running in another process.\n");
+    }
+
+  if (target_has_execution)
+    remove_step_breakpoint ();
+
+  if (target_has_execution && breakpoints_inserted)
+    if (remove_breakpoints ())
+      {
+       target_terminal_ours_for_output ();
+       printf ("Cannot remove breakpoints because program is no longer writable.\n\
+It might be running in another process.\n\
+Further execution is probably impossible.\n");
+      }
+
+  breakpoints_inserted = 0;
+
+  /* Delete the breakpoint we stopped at, if it wants to be deleted.
+     Delete any breakpoint that is to be deleted at the next stop.  */
+
+  breakpoint_auto_delete (stop_bpstat);
+
+  /* If an auto-display called a function and that got a signal,
+     delete that auto-display to avoid an infinite recursion.  */
+
+  if (stopped_by_random_signal)
+    disable_current_display ();
+
+  if (step_multi && stop_step)
+    return;
+
+  target_terminal_ours ();
+
+  if (!target_has_stack)
+    return;
+
+  /* Select innermost stack frame except on return from a stack dummy routine,
+     or if the program has exited.  */
+  if (!stop_stack_dummy)
+    {
+      select_frame (get_current_frame (), 0);
+
+      if (stop_print_frame)
+       {
+         int source_only = bpstat_print (stop_bpstat);
+         print_sel_frame
+           (source_only
+            || (stop_step
+                && step_frame_address == stop_frame_address
+                && step_start_function == find_pc_function (stop_pc)));
+
+         /* Display the auto-display expressions.  */
+         do_displays ();
+       }
+    }
+
+  /* Save the function value return registers, if we care.
+     We might be about to restore their previous contents.  */
+  if (proceed_to_finish)
+    read_register_bytes (0, stop_registers, REGISTER_BYTES);
+
+  if (stop_stack_dummy)
+    {
+      /* Pop the empty frame that contains the stack dummy.
+         POP_FRAME ends with a setting of the current frame, so we
+        can use that next. */
+      POP_FRAME;
+      select_frame (get_current_frame (), 0);
+    }
+}
+\f
+static void
+insert_step_breakpoint ()
+{
+  if (step_resume_break_address && !step_resume_break_duplicate)
+    target_insert_breakpoint (step_resume_break_address,
+                             step_resume_break_shadow);
+}
+
+static void
+remove_step_breakpoint ()
+{
+  if (step_resume_break_address && !step_resume_break_duplicate)
+    target_remove_breakpoint (step_resume_break_address,
+                             step_resume_break_shadow);
+}
+\f
+static void
+sig_print_header ()
+{
+  printf_filtered ("Signal\t\tStop\tPrint\tPass to program\tDescription\n");
+}
+
+static void
+sig_print_info (number)
+     int number;
+{
+  char *abbrev = sig_abbrev(number);
+  if (abbrev == NULL)
+    printf_filtered ("%d\t\t", number);
+  else
+    printf_filtered ("SIG%s (%d)\t", abbrev, number);
+  printf_filtered ("%s\t", signal_stop[number] ? "Yes" : "No");
+  printf_filtered ("%s\t", signal_print[number] ? "Yes" : "No");
+  printf_filtered ("%s\t\t", signal_program[number] ? "Yes" : "No");
+  printf_filtered ("%s\n", sys_siglist[number]);
+}
+
+/* Specify how various signals in the inferior should be handled.  */
+
+static void
+handle_command (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  register char *p = args;
+  int signum = 0;
+  register int digits, wordlen;
+  char *nextarg;
+
+  if (!args)
+    error_no_arg ("signal to handle");
+
+  while (*p)
+    {
+      /* Find the end of the next word in the args.  */
+      for (wordlen = 0;
+          p[wordlen] && p[wordlen] != ' ' && p[wordlen] != '\t';
+          wordlen++);
+      /* Set nextarg to the start of the word after the one we just
+        found, and null-terminate this one.  */
+      if (p[wordlen] == '\0')
+       nextarg = p + wordlen;
+      else
+       {
+         p[wordlen] = '\0';
+         nextarg = p + wordlen + 1;
+       }
+      
+
+      for (digits = 0; p[digits] >= '0' && p[digits] <= '9'; digits++);
+
+      if (signum == 0)
+       {
+         /* It is the first argument--must be the signal to operate on.  */
+         if (digits == wordlen)
+           {
+             /* Numeric.  */
+             signum = atoi (p);
+             if (signum <= 0 || signum >= NSIG)
+               {
+                 p[wordlen] = '\0';
+                 error ("Invalid signal %s given as argument to \"handle\".", p);
+               }
+           }
+         else
+           {
+             /* Symbolic.  */
+             signum = sig_number (p);
+             if (signum == -1)
+               error ("No such signal \"%s\"", p);
+           }
+
+         if (signum == SIGTRAP || signum == SIGINT)
+           {
+             if (!query ("SIG%s is used by the debugger.\nAre you sure you want to change it? ", sig_abbrev (signum)))
+               error ("Not confirmed.");
+           }
+       }
+      /* Else, if already got a signal number, look for flag words
+        saying what to do for it.  */
+      else if (!strncmp (p, "stop", wordlen))
+       {
+         signal_stop[signum] = 1;
+         signal_print[signum] = 1;
+       }
+      else if (wordlen >= 2 && !strncmp (p, "print", wordlen))
+       signal_print[signum] = 1;
+      else if (wordlen >= 2 && !strncmp (p, "pass", wordlen))
+       signal_program[signum] = 1;
+      else if (!strncmp (p, "ignore", wordlen))
+       signal_program[signum] = 0;
+      else if (wordlen >= 3 && !strncmp (p, "nostop", wordlen))
+       signal_stop[signum] = 0;
+      else if (wordlen >= 4 && !strncmp (p, "noprint", wordlen))
+       {
+         signal_print[signum] = 0;
+         signal_stop[signum] = 0;
+       }
+      else if (wordlen >= 4 && !strncmp (p, "nopass", wordlen))
+       signal_program[signum] = 0;
+      else if (wordlen >= 3 && !strncmp (p, "noignore", wordlen))
+       signal_program[signum] = 1;
+      /* Not a number and not a recognized flag word => complain.  */
+      else
+       {
+         error ("Unrecognized flag word: \"%s\".", p);
+       }
+
+      /* Find start of next word.  */
+      p = nextarg;
+      while (*p == ' ' || *p == '\t') p++;
+    }
+
+  if (from_tty)
+    {
+      /* Show the results.  */
+      sig_print_header ();
+      sig_print_info (signum);
+    }
+}
+
+/* Print current contents of the tables set by the handle command.  */
+
+static void
+signals_info (signum_exp)
+     char *signum_exp;
+{
+  register int i;
+  sig_print_header ();
+
+  if (signum_exp)
+    {
+      /* First see if this is a symbol name.  */
+      i = sig_number (signum_exp);
+      if (i == -1)
+       {
+         /* Nope, maybe it's an address which evaluates to a signal
+            number.  */
+         i = parse_and_eval_address (signum_exp);
+         if (i >= NSIG || i < 0)
+           error ("Signal number out of bounds.");
+       }
+      sig_print_info (i);
+      return;
+    }
+
+  printf_filtered ("\n");
+  for (i = 0; i < NSIG; i++)
+    {
+      QUIT;
+
+      sig_print_info (i);
+    }
+
+  printf_filtered ("\nUse the \"handle\" command to change these tables.\n");
+}
+\f
+/* Save all of the information associated with the inferior<==>gdb
+   connection.  INF_STATUS is a pointer to a "struct inferior_status"
+   (defined in inferior.h).  */
+
+void
+save_inferior_status (inf_status, restore_stack_info)
+     struct inferior_status *inf_status;
+     int restore_stack_info;
+{
+  inf_status->pc_changed = pc_changed;
+  inf_status->stop_signal = stop_signal;
+  inf_status->stop_pc = stop_pc;
+  inf_status->stop_frame_address = stop_frame_address;
+  inf_status->stop_step = stop_step;
+  inf_status->stop_stack_dummy = stop_stack_dummy;
+  inf_status->stopped_by_random_signal = stopped_by_random_signal;
+  inf_status->trap_expected = trap_expected;
+  inf_status->step_range_start = step_range_start;
+  inf_status->step_range_end = step_range_end;
+  inf_status->step_frame_address = step_frame_address;
+  inf_status->step_over_calls = step_over_calls;
+  inf_status->step_resume_break_address = step_resume_break_address;
+  inf_status->stop_after_trap = stop_after_trap;
+  inf_status->stop_soon_quietly = stop_soon_quietly;
+  /* Save original bpstat chain here; replace it with copy of chain. 
+     If caller's caller is walking the chain, they'll be happier if we
+     hand them back the original chain when restore_i_s is called.  */
+  inf_status->stop_bpstat = stop_bpstat;
+  stop_bpstat = bpstat_copy (stop_bpstat);
+  inf_status->breakpoint_proceeded = breakpoint_proceeded;
+  inf_status->restore_stack_info = restore_stack_info;
+  inf_status->proceed_to_finish = proceed_to_finish;
+  
+  bcopy (stop_registers, inf_status->stop_registers, REGISTER_BYTES);
+  
+  record_selected_frame (&(inf_status->selected_frame_address),
+                        &(inf_status->selected_level));
+  return;
+}
+
+void
+restore_inferior_status (inf_status)
+     struct inferior_status *inf_status;
+{
+  FRAME fid;
+  int level = inf_status->selected_level;
+
+  pc_changed = inf_status->pc_changed;
+  stop_signal = inf_status->stop_signal;
+  stop_pc = inf_status->stop_pc;
+  stop_frame_address = inf_status->stop_frame_address;
+  stop_step = inf_status->stop_step;
+  stop_stack_dummy = inf_status->stop_stack_dummy;
+  stopped_by_random_signal = inf_status->stopped_by_random_signal;
+  trap_expected = inf_status->trap_expected;
+  step_range_start = inf_status->step_range_start;
+  step_range_end = inf_status->step_range_end;
+  step_frame_address = inf_status->step_frame_address;
+  step_over_calls = inf_status->step_over_calls;
+  step_resume_break_address = inf_status->step_resume_break_address;
+  stop_after_trap = inf_status->stop_after_trap;
+  stop_soon_quietly = inf_status->stop_soon_quietly;
+  bpstat_clear (&stop_bpstat);
+  stop_bpstat = inf_status->stop_bpstat;
+  breakpoint_proceeded = inf_status->breakpoint_proceeded;
+  proceed_to_finish = inf_status->proceed_to_finish;
+
+  bcopy (inf_status->stop_registers, stop_registers, REGISTER_BYTES);
+
+  /* The inferior can be gone if the user types "print exit(0)"
+     (and perhaps other times).  */
+  if (target_has_stack && inf_status->restore_stack_info)
+    {
+      fid = find_relative_frame (get_current_frame (),
+                                &level);
+
+      if (fid == 0 ||
+         FRAME_FP (fid) != inf_status->selected_frame_address ||
+         level != 0)
+       {
+#if 0
+         /* I'm not sure this error message is a good idea.  I have
+            only seen it occur after "Can't continue previously
+            requested operation" (we get called from do_cleanups), in
+            which case it just adds insult to injury (one confusing
+            error message after another.  Besides which, does the
+            user really care if we can't restore the previously
+            selected frame?  */
+         fprintf (stderr, "Unable to restore previously selected frame.\n");
+#endif
+         select_frame (get_current_frame (), 0);
+         return;
+       }
+      
+      select_frame (fid, inf_status->selected_level);
+    }
+}
+
+\f
+void
+_initialize_infrun ()
+{
+  register int i;
+
+  add_info ("signals", signals_info,
+           "What debugger does when program gets various signals.\n\
+Specify a signal number as argument to print info on that signal only.");
+
+  add_com ("handle", class_run, handle_command,
+          "Specify how to handle a signal.\n\
+Args are signal number followed by flags.\n\
+Flags allowed are \"stop\", \"print\", \"pass\",\n\
+ \"nostop\", \"noprint\" or \"nopass\".\n\
+Print means print a message if this signal happens.\n\
+Stop means reenter debugger if this signal happens (implies print).\n\
+Pass means let program see this signal; otherwise program doesn't know.\n\
+Pass and Stop may be combined.");
+
+  for (i = 0; i < NSIG; i++)
+    {
+      signal_stop[i] = 1;
+      signal_print[i] = 1;
+      signal_program[i] = 1;
+    }
+
+  /* Signals caused by debugger's own actions
+     should not be given to the program afterwards.  */
+  signal_program[SIGTRAP] = 0;
+  signal_program[SIGINT] = 0;
+
+  /* Signals that are not errors should not normally enter the debugger.  */
+#ifdef SIGALRM
+  signal_stop[SIGALRM] = 0;
+  signal_print[SIGALRM] = 0;
+#endif /* SIGALRM */
+#ifdef SIGVTALRM
+  signal_stop[SIGVTALRM] = 0;
+  signal_print[SIGVTALRM] = 0;
+#endif /* SIGVTALRM */
+#ifdef SIGPROF
+  signal_stop[SIGPROF] = 0;
+  signal_print[SIGPROF] = 0;
+#endif /* SIGPROF */
+#ifdef SIGCHLD
+  signal_stop[SIGCHLD] = 0;
+  signal_print[SIGCHLD] = 0;
+#endif /* SIGCHLD */
+#ifdef SIGCLD
+  signal_stop[SIGCLD] = 0;
+  signal_print[SIGCLD] = 0;
+#endif /* SIGCLD */
+#ifdef SIGIO
+  signal_stop[SIGIO] = 0;
+  signal_print[SIGIO] = 0;
+#endif /* SIGIO */
+#ifdef SIGURG
+  signal_stop[SIGURG] = 0;
+  signal_print[SIGURG] = 0;
+#endif /* SIGURG */
+}
+
diff --git a/gdb/inftarg.c b/gdb/inftarg.c
new file mode 100644 (file)
index 0000000..ce64437
--- /dev/null
@@ -0,0 +1,182 @@
+/* Subroutines for handling an "inferior" (child) process as a target
+   for debugging, in GDB.
+   Copyright 1990, 1991 Free Software Foundation, Inc.
+   Contributed by Cygnus Support.
+
+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 "frame.h"  /* required by inferior.h */
+#include "inferior.h"
+#include "target.h"
+#include "wait.h"
+#include "gdbcore.h"
+#include "ieee-float.h"                /* Required by REGISTER_CONVERT_TO_XXX */
+
+extern int fetch_inferior_registers();
+extern int store_inferior_registers();
+extern int child_xfer_memory();
+extern int memory_insert_breakpoint(), memory_remove_breakpoint();
+extern void terminal_init_inferior(), terminal_ours(), terminal_inferior();
+extern void terminal_ours_for_output(), child_terminal_info();
+extern void kill_inferior(), add_syms_addr_command();
+extern struct value *call_function_by_hand();
+extern void child_resume();
+extern void child_create_inferior();
+extern void child_mourn_inferior();
+extern void child_attach ();
+
+/* Forward declaration */
+extern struct target_ops child_ops;
+
+/* Wait for child to do something.  Return pid of child, or -1 in case
+   of error; store status through argument pointer STATUS.  */
+
+int
+child_wait (status)
+     int *status;
+{
+  int pid;
+
+  do {
+    pid = wait (status);
+    if (pid == -1)             /* No more children to wait for */
+      {
+       fprintf (stderr, "Child process unexpectedly missing.\n");
+       *status = 42;   /* Claim it exited with signal 42 */
+        return -1;
+      }
+  } while (pid != inferior_pid); /* Some other child died or stopped */
+  return pid;
+}
+
+
+/*
+ * child_detach()
+ * takes a program previously attached to and detaches it.
+ * The program resumes execution and will no longer stop
+ * on signals, etc.  We better not have left any breakpoints
+ * in the program or it'll die when it hits one.  For this
+ * to work, it may be necessary for the process to have been
+ * previously attached.  It *might* work if the program was
+ * started via the normal ptrace (PTRACE_TRACEME).
+ */
+
+static void
+child_detach (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  int siggnal = 0;
+
+#ifdef ATTACH_DETACH
+  if (from_tty)
+    {
+      char *exec_file = get_exec_file (0);
+      if (exec_file == 0)
+       exec_file = "";
+      printf ("Detaching program: %s pid %d\n",
+             exec_file, inferior_pid);
+      fflush (stdout);
+    }
+  if (args)
+    siggnal = atoi (args);
+  
+  detach (siggnal);
+  inferior_pid = 0;
+  unpush_target (&child_ops);          /* Pop out of handling an inferior */
+#else
+    error ("This version of Unix does not support detaching a process.");
+#endif
+}
+
+/* Get ready to modify the registers array.  On machines which store
+   individual registers, this doesn't need to do anything.  On machines
+   which store all the registers in one fell swoop, this makes sure
+   that registers contains all the registers from the program being
+   debugged.  */
+
+void
+child_prepare_to_store ()
+{
+#ifdef CHILD_PREPARE_TO_STORE
+  CHILD_PREPARE_TO_STORE ();
+#endif
+}
+
+/* Convert data from raw format for register REGNUM
+   to virtual format for register REGNUM.  */
+
+void
+host_convert_to_virtual (regnum, from, to)
+     int regnum;
+     char *from;
+     char *to;
+{
+  REGISTER_CONVERT_TO_VIRTUAL (regnum, from, to);
+}
+
+/* Convert data from virtual format for register REGNUM
+   to raw format for register REGNUM.  */
+
+void
+host_convert_from_virtual (regnum, from, to)
+     int regnum;
+     char *from;
+     char *to;
+{
+  REGISTER_CONVERT_TO_RAW (regnum, from, to);
+}
+
+/* Print status information about what we're accessing.  */
+
+static void
+child_files_info ()
+{
+  printf ("\tUsing the running image of %s process %d.\n",
+         attach_flag? "attached": "child", inferior_pid);
+}
+
+struct target_ops child_ops = {
+       "child", "Unix child process",
+       0, 0,  /* open, close */
+       child_attach, child_detach, 
+       child_resume,
+       child_wait,
+       fetch_inferior_registers, store_inferior_registers,
+       child_prepare_to_store,
+       host_convert_to_virtual, host_convert_from_virtual,
+       child_xfer_memory, child_files_info,
+       memory_insert_breakpoint, memory_remove_breakpoint,
+       terminal_init_inferior, terminal_inferior, 
+       terminal_ours_for_output, terminal_ours, child_terminal_info,
+       kill_inferior, 0, add_syms_addr_command,  /* load */
+       call_function_by_hand,
+       0, /* lookup_symbol */
+       child_create_inferior, child_mourn_inferior,
+       process_stratum, 0, /* next */
+       1, 1, 1, 1, 1,  /* all mem, mem, stack, regs, exec */
+       OPS_MAGIC,              /* Always the last thing */
+};
+
+void
+_initialize_inftarg ()
+{
+  add_target (&child_ops);
+}
diff --git a/gdb/m68k-tdep.c b/gdb/m68k-tdep.c
new file mode 100644 (file)
index 0000000..edb87db
--- /dev/null
@@ -0,0 +1,26 @@
+/* Target dependent code for the Motorola 68000 series.
+   Copyright (C) 1990 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 "defs.h"
+#include "ieee-float.h"
+
+const struct ext_format ext_format_68881 [] = {
+/* tot sbyte smask expbyte manbyte */
+ { 12, 0,    0x80, 0,1,           4,8  },              /* mc68881 */
+};
diff --git a/gdb/main.c b/gdb/main.c
new file mode 100644 (file)
index 0000000..5845079
--- /dev/null
@@ -0,0 +1,2127 @@
+/* Top level for GDB, the GNU debugger.
+   Copyright (C) 1986, 1987, 1988, 1989, 1990 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 <stdio.h>
+int fclose ();
+#include "defs.h"
+#include "gdbcmd.h"
+#include "param.h"
+#include "symtab.h"
+#include "inferior.h"
+#include "signals.h"
+#include "target.h"
+#include "breakpoint.h"
+
+#include <getopt.h>
+#include <readline/readline.h>
+#include <readline/history.h>
+
+/* readline defines this.  */
+#undef savestring
+
+#ifdef USG
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+#include <string.h>
+#include <sys/file.h>
+#include <setjmp.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#ifdef SET_STACK_LIMIT_HUGE
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <ctype.h>
+
+int original_stack_limit;
+#endif
+
+
+/* If this definition isn't overridden by the header files, assume
+   that isatty and fileno exist on this system.  */
+#ifndef ISATTY
+#define ISATTY(FP)     (isatty (fileno (FP)))
+#endif
+
+/* Initialization file name for gdb.  This is overridden in some configs.  */
+
+#ifndef        GDBINIT_FILENAME
+#define        GDBINIT_FILENAME        ".gdbinit"
+#endif
+char gdbinit[] = GDBINIT_FILENAME;
+
+/* Version number of GDB, as a string.  */
+
+extern char *version;
+
+/* Flag for whether we want all the "from_tty" gubbish printed.  */
+
+int caution = 1;                       /* Default is yes, sigh. */
+
+/*
+ * Define all cmd_list_element's
+ */
+
+/* Chain containing all defined commands.  */
+
+struct cmd_list_element *cmdlist;
+
+/* Chain containing all defined info subcommands.  */
+
+struct cmd_list_element *infolist;
+
+/* Chain containing all defined enable subcommands. */
+
+struct cmd_list_element *enablelist;
+
+/* Chain containing all defined disable subcommands. */
+
+struct cmd_list_element *disablelist;
+
+/* Chain containing all defined delete subcommands. */
+
+struct cmd_list_element *deletelist;
+
+/* Chain containing all defined "enable breakpoint" subcommands. */
+
+struct cmd_list_element *enablebreaklist;
+
+/* Chain containing all defined set subcommands */
+
+struct cmd_list_element *setlist;
+
+/* Chain containing all defined show subcommands.  */
+struct cmd_list_element *showlist;
+
+/* Chain containing all defined \"set history\".  */
+
+struct cmd_list_element *sethistlist;
+
+/* Chain containing all defined \"show history\".  */
+struct cmd_list_element *showhistlist;
+
+/* Chain containing all defined \"unset history\".  */
+
+struct cmd_list_element *unsethistlist;
+
+/* stdio stream that command input is being read from.  */
+
+FILE *instream;
+
+/* Current working directory.  */
+
+char *current_directory;
+
+/* The directory name is actually stored here (usually).  */
+static char dirbuf[MAXPATHLEN];
+
+/* Function to call before reading a command, if nonzero.
+   The function receives two args: an input stream,
+   and a prompt string.  */
+   
+void (*window_hook) ();
+
+extern int frame_file_full_name;
+int epoch_interface;
+int xgdb_verbose;
+
+/* The external commands we call... */
+extern void init_source_path ();
+extern void directory_command ();
+extern void exec_file_command ();
+extern void symbol_file_command ();
+extern void core_file_command ();
+extern void tty_command ();
+
+extern void help_list ();
+extern void initialize_all_files ();
+extern void init_malloc ();
+
+/* Forward declarations for this file */
+void free_command_lines ();
+char *gdb_readline ();
+char *command_line_input ();
+static void initialize_main ();
+static void initialize_cmd_lists ();
+static void init_signals ();
+static void quit_command ();
+void command_loop ();
+static void source_command ();
+static void print_gdb_version ();
+static void float_handler ();
+static void cd_command ();
+static void read_command_file ();
+
+char *getenv ();
+
+/* gdb prints this when reading a command interactively */
+static char *prompt;
+
+/* Buffer used for reading command lines, and the size
+   allocated for it so far.  */
+
+char *line;
+int linesize = 100;
+
+/* Baud rate specified for talking to serial target systems.  Default
+   is left as a zero pointer, so targets can choose their own defaults.  */
+
+char *baud_rate;
+
+/* Signal to catch ^Z typed while reading a command: SIGTSTP or SIGCONT.  */
+
+#ifndef STOP_SIGNAL
+#ifdef SIGTSTP
+#define STOP_SIGNAL SIGTSTP
+#endif
+#endif
+\f
+/* This is how `error' returns to command level.  */
+
+jmp_buf to_top_level;
+
+void
+return_to_top_level ()
+{
+  quit_flag = 0;
+  immediate_quit = 0;
+  bpstat_clear_actions(stop_bpstat);   /* Clear queued breakpoint commands */
+  clear_momentary_breakpoints ();
+  disable_current_display ();
+  do_cleanups (0);
+  longjmp (to_top_level, 1);
+}
+
+/* Call FUNC with arg ARGS, catching any errors.
+   If there is no error, return the value returned by FUNC.
+   If there is an error, return zero after printing ERRSTRING
+    (which is in addition to the specific error message already printed).  */
+
+int
+catch_errors (func, args, errstring)
+     int (*func) ();
+     int args;
+     char *errstring;
+{
+  jmp_buf saved;
+  int val;
+  struct cleanup *saved_cleanup_chain;
+
+  saved_cleanup_chain = save_cleanups ();
+
+  bcopy (to_top_level, saved, sizeof (jmp_buf));
+
+  if (setjmp (to_top_level) == 0)
+    val = (*func) (args);
+  else
+    {
+      if (errstring)
+       fprintf (stderr, "%s\n", errstring);
+      val = 0;
+    }
+
+  restore_cleanups (saved_cleanup_chain);
+
+  bcopy (saved, to_top_level, sizeof (jmp_buf));
+  return val;
+}
+
+/* Handler for SIGHUP.  */
+
+static void
+disconnect ()
+{
+  kill_inferior_fast ();
+  signal (SIGHUP, SIG_DFL);
+  kill (getpid (), SIGHUP);
+}
+\f
+/* Clean up on error during a "source" command (or execution of a
+   user-defined command).  */
+
+static void
+source_cleanup (stream)
+     FILE *stream;
+{
+  /* Restore the previous input stream.  */
+  instream = stream;
+}
+
+/* Read commands from STREAM.  */
+static void
+read_command_file (stream)
+     FILE *stream;
+{
+  struct cleanup *cleanups;
+
+  cleanups = make_cleanup (source_cleanup, instream);
+  instream = stream;
+  command_loop ();
+  do_cleanups (cleanups);
+}
+\f
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int count;
+  static int inhibit_gdbinit = 0;
+  static int quiet = 0;
+  static int batch = 0;
+
+  /* Pointers to various arguments from command line.  */
+  char *symarg = NULL;
+  char *execarg = NULL;
+  char *corearg = NULL;
+  char *cdarg = NULL;
+  char *ttyarg = NULL;
+
+  /* Pointers to all arguments of +command option.  */
+  char **cmdarg;
+  /* Allocated size of cmdarg.  */
+  int cmdsize;
+  /* Number of elements of cmdarg used.  */
+  int ncmd;
+
+  /* Indices of all arguments of +directory option.  */
+  char **dirarg;
+  /* Allocated size.  */
+  int dirsize;
+  /* Number of elements used.  */
+  int ndir;
+  
+  register int i;
+
+  /* This needs to happen before the first use of malloc.  */
+  init_malloc ();
+
+#if defined (ALIGN_STACK_ON_STARTUP)
+  i = (int) &count & 0x3;
+  if (i != 0)
+    alloca (4 - i);
+#endif
+
+  cmdsize = 1;
+  cmdarg = (char **) xmalloc (cmdsize * sizeof (*cmdarg));
+  ncmd = 0;
+  dirsize = 1;
+  dirarg = (char **) xmalloc (dirsize * sizeof (*dirarg));
+  ndir = 0;
+
+  quit_flag = 0;
+  line = (char *) xmalloc (linesize);
+  line[0] = '\0';              /* Terminate saved (now empty) cmd line */
+  instream = stdin;
+
+  getwd (dirbuf);
+  current_directory = dirbuf;
+
+#ifdef SET_STACK_LIMIT_HUGE
+  {
+    struct rlimit rlim;
+
+    /* Set the stack limit huge so that alloca (particularly stringtab
+     * in dbxread.c) does not fail. */
+    getrlimit (RLIMIT_STACK, &rlim);
+    original_stack_limit = rlim.rlim_cur;
+    rlim.rlim_cur = rlim.rlim_max;
+    setrlimit (RLIMIT_STACK, &rlim);
+  }
+#endif /* SET_STACK_LIMIT_HUGE */
+
+  /* Parse arguments and options.  */
+  {
+    int c;
+    static int print_help;
+    /* When var field is 0, use flag field to record the equivalent
+       short option (or arbitrary numbers starting at 10 for those
+       with no equivalent).  */
+    static struct option long_options[] =
+      {
+       {"quiet", 0, &quiet, 1},
+       {"nx", 0, &inhibit_gdbinit, 1},
+       {"batch", 0, &batch, 1},
+       {"epoch", 0, &epoch_interface, 1},
+       {"fullname", 0, &frame_file_full_name, 1},
+       {"help", 0, &print_help, 1},
+       {"se", 1, 0, 10},
+       {"symbols", 1, 0, 's'},
+       {"s", 1, 0, 's'},
+       {"exec", 1, 0, 'e'},
+       {"core", 1, 0, 'c'},
+       {"c", 1, 0, 'c'},
+       {"command", 1, 0, 'x'},
+       {"x", 1, 0, 'x'},
+       {"directory", 1, 0, 'd'},
+       {"cd", 1, 0, 11},
+       {"tty", 1, 0, 't'},
+       {"b", 1, 0, 'b'},
+/* Allow machine descriptions to add more options... */
+#ifdef ADDITIONAL_OPTIONS
+       ADDITIONAL_OPTIONS
+#endif
+      };
+
+    while (1)
+      {
+       c = getopt_long_only (argc, argv, "",
+                             long_options, &option_index);
+       if (c == EOF)
+         break;
+
+       /* Long option that takes an argument.  */
+       if (c == 0 && long_options[option_index].flag == 0)
+         c = long_options[option_index].val;
+
+       switch (c)
+         {
+         case 0:
+           /* Long option that just sets a flag.  */
+           break;
+         case 10:
+           symarg = optarg;
+           execarg = optarg;
+           break;
+         case 11:
+           cdarg = optarg;
+           break;
+         case 's':
+           symarg = optarg;
+           break;
+         case 'e':
+           execarg = optarg;
+           break;
+         case 'c':
+           corearg = optarg;
+           break;
+         case 'x':
+           cmdarg[ncmd++] = optarg;
+           if (ncmd >= cmdsize)
+             {
+               cmdsize *= 2;
+               cmdarg = (char **) xrealloc ((char *)cmdarg,
+                                            cmdsize * sizeof (*cmdarg));
+             }
+           break;
+         case 'd':
+           dirarg[ndir++] = optarg;
+           if (ndir >= dirsize)
+             {
+               dirsize *= 2;
+               dirarg = (char **) xrealloc ((char *)dirarg,
+                                            dirsize * sizeof (*dirarg));
+             }
+           break;
+         case 't':
+           ttyarg = optarg;
+           break;
+         case 'q':
+           quiet = 1;
+           break;
+         case 'b':
+           baud_rate = optarg;
+           break;
+#ifdef ADDITIONAL_OPTION_CASES
+         ADDITIONAL_OPTION_CASES
+#endif
+         case '?':
+           fprintf (stderr,
+                    "Use `%s +help' for a complete list of options.\n",
+                    argv[0]);
+           exit (1);
+         }
+
+      }
+    if (print_help)
+      {
+       fputs ("\
+This is GDB, the GNU debugger.  Use the command\n\
+    gdb [options] [executable [core-file]]\n\
+to enter the debugger.\n\
+\n\
+Options available are:\n\
+  -help             Print this message.\n\
+  -quiet            Do not print version number on startup.\n\
+  -fullname         Output information used by emacs-GDB interface.\n\
+  -epoch            Output information used by epoch emacs-GDB interface.\n\
+  -batch            Exit after processing options.\n\
+  -nx               Do not read .gdbinit file.\n\
+  -tty=TTY          Use TTY for input/output by the program being debugged.\n\
+  -cd=DIR           Change current directory to DIR.\n\
+  -directory=DIR    Search for source files in DIR.\n\
+  -command=FILE     Execute GDB commands from FILE.\n\
+  -symbols=SYMFILE  Read symbols from SYMFILE.\n\
+  -exec=EXECFILE    Use EXECFILE as the executable.\n\
+  -se=FILE          Use FILE as symbol file and executable file.\n\
+  -core=COREFILE    Analyze the core dump COREFILE.\n\
+  -b BAUDRATE       Set serial port baud rate used for remote debugging\n\
+", stderr);
+#ifdef ADDITIONAL_OPTION_HELP
+       fputs (ADDITIONAL_OPTION_HELP, stderr);
+#endif
+       fputs ("\n\
+For more information, type \"help\" from within GDB, or consult the\n\
+GDB manual (available as on-line info or a printed manual).\n", stderr);
+       /* Exiting after printing this message seems like
+          the most useful thing to do.  */
+       exit (0);
+      }
+    
+    /* OK, that's all the options.  The other arguments are filenames.  */
+    count = 0;
+    for (; optind < argc; optind++)
+      switch (++count)
+       {
+       case 1:
+         symarg = argv[optind];
+         execarg = argv[optind];
+         break;
+       case 2:
+         corearg = argv[optind];
+         break;
+       case 3:
+         fprintf (stderr,
+                  "Excess command line arguments ignored. (%s%s)\n",
+                  argv[optind], (optind == argc - 1) ? "" : " ...");
+         break;
+       }
+    if (batch)
+      quiet = 1;
+  }
+
+  /* Run the init function of each source file */
+
+  initialize_cmd_lists ();     /* This needs to be done first */
+  initialize_all_files ();
+  initialize_main ();          /* But that omits this file!  Do it now */
+  init_signals ();
+
+  if (!quiet)
+    {
+      /* Print all the junk in one place, with a blank line after it
+        to separate it from important stuff like "no such file".  
+        Also, we skip most of the noise, like Emacs, if started with
+        a file name rather than with no arguments.  */
+      if (execarg == 0) {
+       print_gdb_version (1);
+       printf ("Type \"help\" for a list of commands.\n\n");
+      }
+    }
+
+  /* Now perform all the actions indicated by the arguments.  */
+  if (cdarg != NULL)
+    {
+      if (!setjmp (to_top_level))
+       {
+         cd_command (cdarg, 0);
+         init_source_path ();
+       }
+    }
+  for (i = 0; i < ndir; i++)
+    if (!setjmp (to_top_level))
+      directory_command (dirarg[i], 0);
+  free (dirarg);
+  if (execarg != NULL
+      && symarg != NULL
+      && strcmp (execarg, symarg) == 0)
+    {
+      /* The exec file and the symbol-file are the same.  If we can't open
+        it, better only print one error message.  */
+      if (!setjmp (to_top_level))
+       {
+         exec_file_command (execarg, !batch);
+         symbol_file_command (symarg, !batch);
+       }
+    }
+  else
+    {
+      if (execarg != NULL)
+       if (!setjmp (to_top_level))
+         exec_file_command (execarg, !batch);
+      if (symarg != NULL)
+       if (!setjmp (to_top_level))
+         symbol_file_command (symarg, !batch);
+    }
+  if (corearg != NULL)
+    if (!setjmp (to_top_level))
+      core_file_command (corearg, !batch);
+    else if (!setjmp (to_top_level))
+      attach_command (corearg, !batch);
+
+  if (ttyarg != NULL)
+    if (!setjmp (to_top_level))
+      tty_command (ttyarg, !batch);
+
+#ifdef ADDITIONAL_OPTION_HANDLER
+  ADDITIONAL_OPTION_HANDLER;
+#endif
+
+  {
+    struct stat homebuf, cwdbuf;
+    char *homedir, *homeinit;
+
+    /* Read init file, if it exists in home directory  */
+    homedir = getenv ("HOME");
+    if (homedir)
+      {
+       homeinit = (char *) alloca (strlen (getenv ("HOME")) +
+                                   strlen (gdbinit) + 10);
+       strcpy (homeinit, getenv ("HOME"));
+       strcat (homeinit, "/");
+       strcat (homeinit, gdbinit);
+       if (!inhibit_gdbinit && access (homeinit, R_OK) == 0)
+         if (!setjmp (to_top_level))
+           source_command (homeinit, 0);
+
+       /* Do stats; no need to do them elsewhere since we'll only
+          need them if homedir is set.  Make sure that they are
+          zero in case one of them fails (this guarantees that they
+          won't match if either exists).  */
+       
+       bzero (&homebuf, sizeof (struct stat));
+       bzero (&cwdbuf, sizeof (struct stat));
+       
+       stat (homeinit, &homebuf);
+       stat (gdbinit, &cwdbuf); /* We'll only need this if
+                                        homedir was set.  */
+      }
+    
+    /* Read the input file in the current directory, *if* it isn't
+       the same file (it should exist, also).  */
+
+    if (!homedir
+       || bcmp ((char *) &homebuf,
+                (char *) &cwdbuf,
+                sizeof (struct stat)))
+      if (!inhibit_gdbinit && access (gdbinit, R_OK) == 0)
+       if (!setjmp (to_top_level))
+         source_command (gdbinit, 0);
+  }
+
+  for (i = 0; i < ncmd; i++)
+    if (!setjmp (to_top_level))
+      {
+       if (cmdarg[i][0] == '-' && cmdarg[i][1] == '\0')
+         read_command_file (stdin);
+       else
+         source_command (cmdarg[i], !batch);
+      }
+  free (cmdarg);
+
+  if (batch)
+    {
+      /* We have hit the end of the batch file.  */
+      exit (0);
+    }
+
+  /* Do any host- or target-specific hacks.  This is used for i960 targets
+     to force the user to set a nindy target and spec its parameters.  */
+
+#ifdef BEFORE_MAIN_LOOP_HOOK
+  BEFORE_MAIN_LOOP_HOOK;
+#endif
+
+  /* The command loop.  */
+
+  while (1)
+    {
+      if (!setjmp (to_top_level))
+       {
+         command_loop ();
+          quit_command ((char *)0, instream == stdin);
+       }
+    }
+  /* No exit -- exit is through quit_command.  */
+}
+
+/* Execute the line P as a command.
+   Pass FROM_TTY as second argument to the defining function.  */
+
+void
+execute_command (p, from_tty)
+     char *p;
+     int from_tty;
+{
+  register struct cmd_list_element *c;
+  register struct command_line *cmdlines;
+
+  free_all_values ();
+
+  /* This can happen when command_line_input hits end of file.  */
+  if (p == NULL)
+      return;
+  
+  while (*p == ' ' || *p == '\t') p++;
+  if (*p)
+    {
+      char *arg;
+      
+      c = lookup_cmd (&p, cmdlist, "", 0, 1);
+      /* Pass null arg rather than an empty one.  */
+      arg = *p ? p : 0;
+      if (c->class == class_user)
+       {
+         struct cleanup *old_chain;
+         
+         if (*p)
+           error ("User-defined commands cannot take arguments.");
+         cmdlines = c->user_commands;
+         if (cmdlines == 0)
+           /* Null command */
+           return;
+
+         /* Set the instream to 0, indicating execution of a
+            user-defined function.  */
+         old_chain =  make_cleanup (source_cleanup, instream);
+         instream = (FILE *) 0;
+         while (cmdlines)
+           {
+             execute_command (cmdlines->line, 0);
+             cmdlines = cmdlines->next;
+           }
+         do_cleanups (old_chain);
+       }
+      else if (c->type == set_cmd || c->type == show_cmd)
+       do_setshow_command (arg, from_tty & caution, c);
+      else if (c->function == NO_FUNCTION)
+       error ("That is not a command, just a help topic.");
+      else
+       (*c->function) (arg, from_tty & caution);
+    }
+}
+
+/* ARGSUSED */
+static void
+do_nothing (foo)
+     int foo;
+{
+}
+
+/* Read commands from `instream' and execute them
+   until end of file or error reading instream.  */
+void
+command_loop ()
+{
+  struct cleanup *old_chain;
+  char *command;
+  int stdin_is_tty = ISATTY (stdin);
+
+  while (!feof (instream))
+    {
+      if (window_hook && instream == stdin)
+       (*window_hook) (instream, prompt);
+
+      quit_flag = 0;
+      if (instream == stdin && stdin_is_tty)
+       reinitialize_more_filter ();
+      old_chain = make_cleanup (do_nothing, 0);
+      command = command_line_input (instream == stdin ? prompt : 0,
+                                     instream == stdin);
+      if (command == 0)
+       return;
+      execute_command (command, instream == stdin);
+      /* Do any commands attached to breakpoint we stopped at.  */
+      bpstat_do_actions (&stop_bpstat);
+      do_cleanups (old_chain);
+    }
+}
+\f
+/* Commands call this if they do not want to be repeated by null lines.  */
+
+void
+dont_repeat ()
+{
+  /* If we aren't reading from standard input, we are saving the last
+     thing read from stdin in line and don't want to delete it.  Null lines
+     won't repeat here in any case.  */
+  if (instream == stdin)
+    *line = 0;
+}
+\f
+/* Read a line from the stream "instream" without command line editing.
+
+   It prints PRROMPT once at the start.
+
+   If RETURN_RESULT is set it allocates
+   space for whatever the user types and returns the result.
+   If not, it just discards what the user types and returns a garbage
+   non-NULL value.
+
+   No matter what return_result is, a NULL return means end of file.  */
+char *
+gdb_readline (prrompt, return_result)
+     char *prrompt;
+     int return_result;
+{
+  int c;
+  char *result;
+  int input_index = 0;
+  int result_size = 80;
+
+  if (prrompt)
+    {
+      printf (prrompt);
+      fflush (stdout);
+    }
+  
+  if (return_result)
+    result = (char *) xmalloc (result_size);
+
+  while (1)
+    {
+      /* Read from stdin if we are executing a user defined command.
+        This is the right thing for prompt_for_continue, at least.  */
+      c = fgetc (instream ? instream : stdin);
+      if (c == EOF || c == '\n')
+       break;
+      if (return_result)
+       {
+         result[input_index++] = c;
+         while (input_index >= result_size)
+           {
+             result_size *= 2;
+             result = (char *) xrealloc (result, result_size);
+           }
+       }
+    }
+
+  if (c == EOF)
+    {
+      if (return_result)
+       free (result);
+      return NULL;
+    }
+
+  if (return_result)
+    {
+      result[input_index++] = '\0';
+      return result;
+    }
+  else
+    /* Return any old non-NULL pointer.  */
+    return (char *) "non-NULL";
+}
+
+/* Declaration for fancy readline with command line editing.  */
+char *readline ();
+
+/* Variables which control command line editing and history
+   substitution.  These variables are given default values at the end
+   of this file.  */
+static int command_editing_p;
+static int history_expansion_p;
+static int write_history_p;
+static int history_size;
+static char *history_filename;
+
+/* Variables which are necessary for fancy command line editing.  */
+char *gdb_completer_word_break_characters =
+  " \t\n!@#$%^&*()-+=|~`}{[]\"';:?/>.<,";
+
+/* Functions that are used as part of the fancy command line editing.  */
+
+/* This can be used for functions which don't want to complete on symbols
+   but don't want to complete on anything else either.  */
+/* ARGSUSED */
+char **
+noop_completer (text)
+     char *text;
+{
+  return NULL;
+}
+
+/* Generate symbol names one by one for the completer.  If STATE is
+   zero, then we need to initialize, otherwise the initialization has
+   already taken place.  TEXT is what we expect the symbol to start
+   with.  RL_LINE_BUFFER is available to be looked at; it contains the
+   entire text of the line.  RL_POINT is the offset in that line of
+   the cursor.  You should pretend that the line ends at RL_POINT.
+   The result is NULL if there are no more completions, else a char
+   string which is a possible completion.  */
+char *
+symbol_completion_function (text, state)
+     char *text;
+     int state;
+{
+  static char **list = (char **)NULL;
+  static int index;
+  char *output;
+  extern char *rl_line_buffer;
+  extern int rl_point;
+  char *tmp_command, *p;
+  struct cmd_list_element *c, *result_list;
+
+  if (!state)
+    {
+      /* Free the storage used by LIST, but not by the strings inside.  This is
+        because rl_complete_internal () frees the strings. */
+      if (list)
+       free (list);
+      list = 0;
+      index = 0;
+
+      /* Decide whether to complete on a list of gdb commands or on
+        symbols.  */
+      tmp_command = (char *) alloca (rl_point + 1);
+      p = tmp_command;
+      
+      strncpy (tmp_command, rl_line_buffer, rl_point);
+      tmp_command[rl_point] = '\0';
+
+      if (rl_point == 0)
+       {
+         /* An empty line we want to consider ambiguous; that is,
+            it could be any command.  */
+         c = (struct cmd_list_element *) -1;
+         result_list = 0;
+       }
+      else
+       c = lookup_cmd_1 (&p, cmdlist, &result_list, 1);
+
+      /* Move p up to the next interesting thing.  */
+      while (*p == ' ' || *p == '\t')
+       p++;
+
+      if (!c)
+       /* He's typed something unrecognizable.  Sigh.  */
+       list = (char **) 0;
+      else if (c == (struct cmd_list_element *) -1)
+       {
+         /* If we didn't recognize everything up to the thing that
+            needs completing, and we don't know what command it is
+            yet, we are in trouble.  Part of the trouble might be
+            that the list of delimiters used by readline includes
+            '-', which we use in commands.  Check for this.  */
+         if (p + strlen(text) != tmp_command + rl_point) {
+           if (tmp_command[rl_point - strlen(text) - 1] == '-')
+             text = p;
+           else {
+             /* This really should not produce an error.  Better would
+                be to pretend to hit RETURN here; this would produce a
+                response like "Ambiguous command: foo, foobar, etc",
+                and leave the line available for re-entry with ^P.  Instead,
+                this error blows away the user's typed input without
+                any way to get it back.  */
+             error ("  Unrecognized command.");
+           }
+         }
+         
+         /* He's typed something ambiguous.  This is easier.  */
+         if (result_list)
+           list = complete_on_cmdlist (*result_list->prefixlist, text);
+         else
+           list = complete_on_cmdlist (cmdlist, text);
+       }
+      else
+       {
+         /* If we've gotten this far, gdb has recognized a full
+            command.  There are several possibilities:
+
+            1) We need to complete on the command.
+            2) We need to complete on the possibilities coming after
+            the command.
+            2) We need to complete the text of what comes after the
+            command.   */
+
+         if (!*p && *text)
+           /* Always (might be longer versions of thie command).  */
+           list = complete_on_cmdlist (result_list, text);
+         else if (!*p && !*text)
+           {
+             if (c->prefixlist)
+               list = complete_on_cmdlist (*c->prefixlist, "");
+             else
+               list = (*c->completer) ("");
+           }
+         else
+           {
+             if (c->prefixlist && !c->allow_unknown)
+               {
+#if 0
+                 /* Something like "info adsfkdj".  But error() is not
+                    the proper response; just return no completions
+                    instead.  */
+                 *p = '\0';
+                 error ("\"%s\" command requires a subcommand.",
+                        tmp_command);
+#else
+                 list = NULL;
+#endif
+               }
+             else
+               list = (*c->completer) (text);
+           }
+       }
+    }
+
+  /* If the debugged program wasn't compiled with symbols, or if we're
+     clearly completing on a command and no command matches, return
+     NULL.  */
+  if (!list)
+    return ((char *)NULL);
+
+  output = list[index];
+  if (output)
+    index++;
+
+  return (output);
+}
+\f
+#ifdef STOP_SIGNAL
+static void
+stop_sig ()
+{
+#if STOP_SIGNAL == SIGTSTP
+  signal (SIGTSTP, SIG_DFL);
+  sigsetmask (0);
+  kill (getpid (), SIGTSTP);
+  signal (SIGTSTP, stop_sig);
+#else
+  signal (STOP_SIGNAL, stop_sig);
+#endif
+  printf ("%s", prompt);
+  fflush (stdout);
+
+  /* Forget about any previous command -- null line now will do nothing.  */
+  dont_repeat ();
+}
+#endif /* STOP_SIGNAL */
+
+#if 0
+Writing the history file upon a terminating signal is not useful,
+  because the info is rarely relevant and is in the core dump anyway.
+  It is an annoyance to have the file cluttering up the place.
+/* The list of signals that would terminate us if not caught.
+   We catch them, but just so that we can write the history file,
+   and so forth. */
+int terminating_signals[] = {
+  SIGHUP, SIGINT, SIGILL, SIGTRAP, SIGIOT,
+  SIGEMT, SIGFPE, SIGKILL, SIGBUS, SIGSEGV, SIGSYS,
+  SIGPIPE, SIGALRM, SIGTERM,
+#ifdef SIGXCPU
+  SIGXCPU,
+#endif
+#ifdef SIGXFSZ
+  SIGXFSZ,
+#endif
+#ifdef SIGVTALRM
+  SIGVTALRM,
+#endif
+#ifdef SIGPROF
+  SIGPROF,
+#endif
+#ifdef SIGLOST
+  SIGLOST,
+#endif
+#ifdef SIGUSR1
+  SIGUSR1, SIGUSR2
+#endif
+    };
+
+#define TERMSIGS_LENGTH (sizeof (terminating_signals) / sizeof (int))
+
+static void
+catch_termination (sig)
+     int sig;
+{
+  /* We are probably here because GDB has a bug.  Write out the history
+     so that we might have a better chance of reproducing it.  */
+  /* Tell the user what we are doing so he can delete the file if
+     it is unwanted.  */
+  write_history (history_filename);
+  printf ("\n%s written.\n", history_filename);
+  signal (sig, SIG_DFL);
+  kill (getpid (), sig);
+}
+#endif
+
+/* Initialize signal handlers. */
+static void
+init_signals ()
+{
+  extern void request_quit ();
+#if 0
+  register int i;
+
+  for (i = 0; i < TERMSIGS_LENGTH; i++)
+    signal (terminating_signals[i], catch_termination);
+#endif
+
+  signal (SIGINT, request_quit);
+
+  /* If we initialize SIGQUIT to SIG_IGN, then the SIG_IGN will get
+     passed to the inferior, which we don't want.  It would be
+     possible to do a "signal (SIGQUIT, SIG_DFL)" after we fork, but
+     on BSD4.3 systems using vfork, that will (apparently) affect the
+     GDB process as well as the inferior (the signal handling tables
+     being shared between the two, apparently).  Since we establish
+     a handler for SIGQUIT, when we call exec it will set the signal
+     to SIG_DFL for us.  */
+  signal (SIGQUIT, do_nothing);
+  if (signal (SIGHUP, do_nothing) != SIG_IGN)
+    signal (SIGHUP, disconnect);
+  signal (SIGFPE, float_handler);
+}
+\f
+/* Read one line from the command input stream `instream'
+   into the local static buffer `linebuffer' (whose current length
+   is `linelength').
+   The buffer is made bigger as necessary.
+   Returns the address of the start of the line.
+
+   NULL is returned for end of file.
+
+   *If* the instream == stdin & stdin is a terminal, the line read
+   is copied into the file line saver (global var char *line,
+   length linesize) so that it can be duplicated.
+
+   This routine either uses fancy command line editing or
+   simple input as the user has requested.  */
+
+char *
+command_line_input (prrompt, repeat)
+     char *prrompt;
+     int repeat;
+{
+  static char *linebuffer = 0;
+  static int linelength = 0;
+  register char *p;
+  char *p1;
+  char *rl;
+  char *local_prompt = prrompt;
+  register int c;
+  char *nline;
+  char got_eof = 0;
+
+  if (linebuffer == 0)
+    {
+      linelength = 80;
+      linebuffer = (char *) xmalloc (linelength);
+    }
+
+  p = linebuffer;
+
+  /* Control-C quits instantly if typed while in this loop
+     since it should not wait until the user types a newline.  */
+  immediate_quit++;
+#ifdef STOP_SIGNAL
+  signal (STOP_SIGNAL, stop_sig);
+#endif
+
+  while (1)
+    {
+      /* Don't use fancy stuff if not talking to stdin.  */
+      if (command_editing_p && instream == stdin
+         && ISATTY (instream))
+       rl = readline (local_prompt);
+      else
+       rl = gdb_readline (local_prompt, 1);
+
+      if (!rl || rl == (char *) EOF)
+       {
+         got_eof = 1;
+         break;
+       }
+      if (strlen(rl) + 1 + (p - linebuffer) > linelength)
+       {
+         linelength = strlen(rl) + 1 + (p - linebuffer);
+         nline = (char *) xrealloc (linebuffer, linelength);
+         p += nline - linebuffer;
+         linebuffer = nline;
+       }
+      p1 = rl;
+      /* Copy line.  Don't copy null at end.  (Leaves line alone
+         if this was just a newline)  */
+      while (*p1)
+       *p++ = *p1++;
+
+      free (rl);                       /* Allocated in readline.  */
+
+      if (p == linebuffer || *(p - 1) != '\\')
+       break;
+
+      p--;                     /* Put on top of '\'.  */
+      local_prompt = (char *) 0;
+  }
+
+#ifdef STOP_SIGNAL
+  signal (SIGTSTP, SIG_DFL);
+#endif
+  immediate_quit--;
+
+  if (got_eof)
+    return NULL;
+
+  /* Do history expansion if that is wished.  */
+  if (history_expansion_p && instream == stdin
+      && ISATTY (instream))
+    {
+      char *history_value;
+      int expanded;
+
+      *p = '\0';               /* Insert null now.  */
+      expanded = history_expand (linebuffer, &history_value);
+      if (expanded)
+       {
+         /* Print the changes.  */
+         printf ("%s\n", history_value);
+
+         /* If there was an error, call this function again.  */
+         if (expanded < 0)
+           {
+             free (history_value);
+             return command_line_input (prrompt, repeat);
+           }
+         if (strlen (history_value) > linelength)
+           {
+             linelength = strlen (history_value) + 1;
+             linebuffer = (char *) xrealloc (linebuffer, linelength);
+           }
+         strcpy (linebuffer, history_value);
+         p = linebuffer + strlen(linebuffer);
+         free (history_value);
+       }
+    }
+
+  /* If we just got an empty line, and that is supposed
+     to repeat the previous command, return the value in the
+     global buffer.  */
+  if (repeat)
+    {
+      if (p == linebuffer)
+       return line;
+      p1 = linebuffer;
+      while (*p1 == ' ' || *p1 == '\t')
+       p1++;
+      if (!*p1)
+       return line;
+    }
+
+  *p = 0;
+
+  /* Add line to history if appropriate.  */
+  if (instream == stdin
+      && ISATTY (stdin) && *linebuffer)
+    add_history (linebuffer);
+
+  /* Note: lines consisting soley of comments are added to the command
+     history.  This is useful when you type a command, and then
+     realize you don't want to execute it quite yet.  You can comment
+     out the command and then later fetch it from the value history
+     and remove the '#'.  The kill ring is probably better, but some
+     people are in the habit of commenting things out.  */
+  p1 = linebuffer;
+  while ((c = *p1++) != '\0')
+    {
+      if (c == '"')
+       while ((c = *p1++) != '"')
+         {
+           /* Make sure an escaped '"' doesn't make us think the string
+              is ended.  */
+           if (c == '\\')
+             parse_escape (&p1);
+           if (c == '\0')
+             break;
+         }
+      else if (c == '\'')
+       while ((c = *p1++) != '\'')
+         {
+           /* Make sure an escaped '\'' doesn't make us think the string
+              is ended.  */
+           if (c == '\\')
+             parse_escape (&p1);
+           if (c == '\0')
+             break;
+         }
+      else if (c == '#')
+       {
+         /* Found a comment.  */
+         p1[-1] = '\0';
+         break;
+       }
+    }
+
+  /* Save into global buffer if appropriate.  */
+  if (repeat)
+    {
+      if (linelength > linesize)
+       {
+         line = xrealloc (line, linelength);
+         linesize = linelength;
+       }
+      strcpy (line, linebuffer);
+      return line;
+    }
+
+  return linebuffer;
+}
+\f
+/* Read lines from the input stream
+   and accumulate them in a chain of struct command_line's
+   which is then returned.  */
+
+struct command_line *
+read_command_lines ()
+{
+  struct command_line *first = 0;
+  register struct command_line *next, *tail = 0;
+  register char *p, *p1;
+  struct cleanup *old_chain = 0;
+
+  while (1)
+    {
+      dont_repeat ();
+      p = command_line_input (0, instream == stdin);
+      if (p == NULL)
+       /* Treat end of file like "end".  */
+       break;
+      
+      /* Remove leading and trailing blanks.  */
+      while (*p == ' ' || *p == '\t') p++;
+      p1 = p + strlen (p);
+      while (p1 != p && (p1[-1] == ' ' || p1[-1] == '\t')) p1--;
+
+      /* Is this "end"?  */
+      if (p1 - p == 3 && !strncmp (p, "end", 3))
+       break;
+
+      /* No => add this line to the chain of command lines.  */
+      next = (struct command_line *) xmalloc (sizeof (struct command_line));
+      next->line = savestring (p, p1 - p);
+      next->next = 0;
+      if (tail)
+       {
+         tail->next = next;
+       }
+      else
+       {
+         /* We just read the first line.
+            From now on, arrange to throw away the lines we have
+            if we quit or get an error while inside this function.  */
+         first = next;
+         old_chain = make_cleanup (free_command_lines, &first);
+       }
+      tail = next;
+    }
+
+  dont_repeat ();
+
+  /* Now we are about to return the chain to our caller,
+     so freeing it becomes his responsibility.  */
+  if (first)
+    discard_cleanups (old_chain);
+  return first;
+}
+
+/* Free a chain of struct command_line's.  */
+
+void
+free_command_lines (lptr)
+      struct command_line **lptr;
+{
+  register struct command_line *l = *lptr;
+  register struct command_line *next;
+
+  while (l)
+    {
+      next = l->next;
+      free (l->line);
+      free (l);
+      l = next;
+    }
+}
+\f
+/* Add an element to the list of info subcommands.  */
+
+void
+add_info (name, fun, doc)
+     char *name;
+     void (*fun) ();
+     char *doc;
+{
+  add_cmd (name, no_class, fun, doc, &infolist);
+}
+
+/* Add an alias to the list of info subcommands.  */
+
+void
+add_info_alias (name, oldname, abbrev_flag)
+     char *name;
+     char *oldname;
+     int abbrev_flag;
+{
+  add_alias_cmd (name, oldname, 0, abbrev_flag, &infolist);
+}
+
+/* The "info" command is defined as a prefix, with allow_unknown = 0.
+   Therefore, its own definition is called only for "info" with no args.  */
+
+/* ARGSUSED */
+static void
+info_command (arg, from_tty)
+     char *arg;
+     int from_tty;
+{
+  printf ("\"info\" must be followed by the name of an info command.\n");
+  help_list (infolist, "info ", -1, stdout);
+}
+
+/* The "show" command with no arguments shows all the settings.  */
+
+/* ARGSUSED */
+static void
+show_command (arg, from_tty)
+     char *arg;
+     int from_tty;
+{
+  cmd_show_list (showlist, from_tty, "");
+}
+\f
+/* Add an element to the list of commands.  */
+
+void
+add_com (name, class, fun, doc)
+     char *name;
+     enum command_class class;
+     void (*fun) ();
+     char *doc;
+{
+  add_cmd (name, class, fun, doc, &cmdlist);
+}
+
+/* Add an alias or abbreviation command to the list of commands.  */
+
+void
+add_com_alias (name, oldname, class, abbrev_flag)
+     char *name;
+     char *oldname;
+     enum command_class class;
+     int abbrev_flag;
+{
+  add_alias_cmd (name, oldname, class, abbrev_flag, &cmdlist);
+}
+
+void
+error_no_arg (why)
+     char *why;
+{
+  error ("Argument required (%s).", why);
+}
+
+static void
+help_command (command, from_tty)
+     char *command;
+     int from_tty; /* Ignored */
+{
+  help_cmd (command, stdout);
+}
+\f
+static void
+validate_comname (comname)
+     char *comname;
+{
+  register char *p;
+
+  if (comname == 0)
+    error_no_arg ("name of command to define");
+
+  p = comname;
+  while (*p)
+    {
+      if (!(*p >= 'A' && *p <= 'Z')
+         && !(*p >= 'a' && *p <= 'z')
+         && !(*p >= '0' && *p <= '9')
+         && *p != '-')
+       error ("Junk in argument list: \"%s\"", p);
+      p++;
+    }
+}
+
+static void
+define_command (comname, from_tty)
+     char *comname;
+     int from_tty;
+{
+  register struct command_line *cmds;
+  register struct cmd_list_element *c, *newc;
+  char *tem = comname;
+  extern void not_just_help_class_command ();
+
+  validate_comname (comname);
+
+  c = lookup_cmd (&tem, cmdlist, "", -1, 1);
+  if (c)
+    {
+      if (c->class == class_user || c->class == class_alias)
+       tem = "Redefine command \"%s\"? ";
+      else
+       tem = "Really redefine built-in command \"%s\"? ";
+      if (!query (tem, comname))
+       error ("Command \"%s\" not redefined.", comname);
+    }
+
+  if (from_tty)
+    {
+      printf ("Type commands for definition of \"%s\".\n\
+End with a line saying just \"end\".\n", comname);
+      fflush (stdout);
+    }
+  comname = savestring (comname, strlen (comname));
+
+  cmds = read_command_lines ();
+
+  if (c && c->class == class_user)
+    free_command_lines (&c->user_commands);
+
+  newc = add_cmd (comname, class_user, not_just_help_class_command,
+          (c && c->class == class_user)
+          ? c->doc : savestring ("User-defined.", 13), &cmdlist);
+  newc->user_commands = cmds;
+}
+
+static void
+document_command (comname, from_tty)
+     char *comname;
+     int from_tty;
+{
+  struct command_line *doclines;
+  register struct cmd_list_element *c;
+  char *tem = comname;
+
+  validate_comname (comname);
+
+  c = lookup_cmd (&tem, cmdlist, "", 0, 1);
+
+  if (c->class != class_user)
+    error ("Command \"%s\" is built-in.", comname);
+
+  if (from_tty)
+    printf ("Type documentation for \"%s\".\n\
+End with a line saying just \"end\".\n", comname);
+
+  doclines = read_command_lines ();
+
+  if (c->doc) free (c->doc);
+
+  {
+    register struct command_line *cl1;
+    register int len = 0;
+
+    for (cl1 = doclines; cl1; cl1 = cl1->next)
+      len += strlen (cl1->line) + 1;
+
+    c->doc = (char *) xmalloc (len + 1);
+    *c->doc = 0;
+
+    for (cl1 = doclines; cl1; cl1 = cl1->next)
+      {
+       strcat (c->doc, cl1->line);
+       if (cl1->next)
+         strcat (c->doc, "\n");
+      }
+  }
+
+  free_command_lines (&doclines);
+}
+\f
+static void
+print_gdb_version (shout)
+     int shout;
+{
+  printf ("GDB %s, Copyright (C) 1991 Free Software Foundation, Inc.\n",
+         version);
+  if (shout)
+    printf ("\
+There is ABSOLUTELY NO WARRANTY for GDB; type \"info warranty\" for details.\n\
+GDB is free software and you are welcome to distribute copies of it\n\
+ under certain conditions; type \"info copying\" to see the conditions.\n");
+}
+
+static void
+version_info (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  immediate_quit++;
+  print_gdb_version (0);
+  immediate_quit--;
+}
+\f
+/* xgdb calls this to reprint the usual GDB prompt.  */
+
+void
+print_prompt ()
+{
+  printf ("%s", prompt);
+  fflush (stdout);
+}
+\f
+static void
+quit_command (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  if (inferior_pid != 0)
+    {
+      if (query ("The program is running.  Quit anyway? "))
+       {
+         target_kill (args, from_tty);
+       }
+      else
+       error ("Not confirmed.");
+    }
+  /* Save the history information if it is appropriate to do so.  */
+  if (write_history_p && history_filename)
+    write_history (history_filename);
+  exit (0);
+}
+
+int
+input_from_terminal_p ()
+{
+  return (instream == stdin) & caution;
+}
+\f
+static void
+pwd_command (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  if (args) error ("The \"pwd\" command does not take an argument: %s", args);
+  getwd (dirbuf);
+
+  if (strcmp (dirbuf, current_directory))
+    printf ("Working directory %s\n (canonically %s).\n",
+           current_directory, dirbuf);
+  else
+    printf ("Working directory %s.\n", current_directory);
+}
+
+static void
+cd_command (dir, from_tty)
+     char *dir;
+     int from_tty;
+{
+  int len;
+  int change;
+
+  if (dir == 0)
+    error_no_arg ("new working directory");
+
+  dir = tilde_expand (dir);
+  make_cleanup (free, dir);
+
+  len = strlen (dir);
+  dir = savestring (dir, len - (len > 1 && dir[len-1] == '/'));
+  if (dir[0] == '/')
+    current_directory = dir;
+  else
+    {
+      current_directory = concat (current_directory, "/", dir);
+      free (dir);
+    }
+
+  /* Now simplify any occurrences of `.' and `..' in the pathname.  */
+
+  change = 1;
+  while (change)
+    {
+      char *p;
+      change = 0;
+
+      for (p = current_directory; *p;)
+       {
+         if (!strncmp (p, "/./", 2)
+             && (p[2] == 0 || p[2] == '/'))
+           strcpy (p, p + 2);
+         else if (!strncmp (p, "/..", 3)
+                  && (p[3] == 0 || p[3] == '/')
+                  && p != current_directory)
+           {
+             char *q = p;
+             while (q != current_directory && q[-1] != '/') q--;
+             if (q != current_directory)
+               {
+                 strcpy (q-1, p+3);
+                 p = q-1;
+               }
+           }
+         else p++;
+       }
+    }
+
+  if (chdir (dir) < 0)
+    perror_with_name (dir);
+
+  forget_cached_source_info ();
+
+  if (from_tty)
+    pwd_command ((char *) 0, 1);
+}
+\f
+static void
+source_command (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  FILE *stream;
+  struct cleanup *cleanups;
+  char *file = args;
+
+  if (file == 0)
+    /* Let source without arguments read .gdbinit.  */
+    file = gdbinit;
+
+  file = tilde_expand (file);
+  make_cleanup (free, file);
+
+  stream = fopen (file, "r");
+  if (stream == 0)
+    perror_with_name (file);
+
+  cleanups = make_cleanup (fclose, stream);
+
+  read_command_file (stream);
+
+  do_cleanups (cleanups);
+}
+
+/* ARGSUSED */
+static void
+echo_command (text, from_tty)
+     char *text;
+     int from_tty;
+{
+  char *p = text;
+  register int c;
+
+  if (text)
+    while (c = *p++)
+      {
+       if (c == '\\')
+         {
+           /* \ at end of argument is used after spaces
+              so they won't be lost.  */
+           if (*p == 0)
+             return;
+
+           c = parse_escape (&p);
+           if (c >= 0)
+             fputc (c, stdout);
+         }
+       else
+         fputc (c, stdout);
+      }
+}
+
+/* ARGSUSED */
+static void
+dump_me_command (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  if (query ("Should GDB dump core? "))
+    {
+      signal (SIGQUIT, SIG_DFL);
+      kill (getpid (), SIGQUIT);
+    }
+}
+\f
+/* Functions to manipulate command line editing control variables.  */
+
+/* Number of commands to print in each call to editing_info.  */
+#define Hist_print 10
+static void
+editing_info (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  /* Index for history commands.  Relative to history_base.  */
+  int offset;
+
+  /* Number of the history entry which we are planning to display next.
+     Relative to history_base.  */
+  static int num = 0;
+
+  /* The first command in the history which doesn't exist (i.e. one more
+     than the number of the last command).  Relative to history_base.  */
+  int hist_len;
+
+  struct _hist_entry *history_get();
+  extern int history_base;
+
+#if 0
+  /* This is all reported by individual "show" commands.  */
+  printf_filtered ("Interactive command editing is %s.\n",
+         command_editing_p ? "on" : "off");
+
+  printf_filtered ("History expansion of command input is %s.\n",
+         history_expansion_p ? "on" : "off");
+  printf_filtered ("Writing of a history record upon exit is %s.\n",
+         write_history_p ? "enabled" : "disabled");
+  printf_filtered ("The size of the history list (number of stored commands) is %d.\n",
+         history_size);
+  printf_filtered ("The name of the history record is \"%s\".\n\n",
+         history_filename ? history_filename : "");
+#endif /* 0 */
+
+  /* Print out some of the commands from the command history.  */
+  /* First determine the length of the history list.  */
+  hist_len = history_size;
+  for (offset = 0; offset < history_size; offset++)
+    {
+      if (!history_get (history_base + offset))
+       {
+         hist_len = offset;
+         break;
+       }
+    }
+
+  if (args)
+    {
+      if (args[0] == '+' && args[1] == '\0')
+       /* "info editing +" should print from the stored position.  */
+       ;
+      else
+       /* "info editing <exp>" should print around command number <exp>.  */
+       num = (parse_and_eval_address (args) - history_base) - Hist_print / 2;
+    }
+  /* "info editing" means print the last Hist_print commands.  */
+  else
+    {
+      num = hist_len - Hist_print;
+    }
+
+  if (num < 0)
+    num = 0;
+
+  /* If there are at least Hist_print commands, we want to display the last
+     Hist_print rather than, say, the last 6.  */
+  if (hist_len - num < Hist_print)
+    {
+      num = hist_len - Hist_print;
+      if (num < 0)
+       num = 0;
+    }
+
+#if 0
+  /* No need for a header now that "info editing" only prints one thing.  */
+  if (num == hist_len - Hist_print)
+    printf_filtered ("The list of the last %d commands is:\n\n", Hist_print);
+  else
+    printf_filtered ("Some of the stored commands are:\n\n");
+#endif /* 0 */
+
+  for (offset = num; offset < num + Hist_print && offset < hist_len; offset++)
+    {
+      printf_filtered ("%5d  %s\n", history_base + offset,
+             (history_get (history_base + offset))->line);
+    }
+
+  /* The next command we want to display is the next one that we haven't
+     displayed yet.  */
+  num += Hist_print;
+  
+  /* If the user repeats this command with return, it should do what
+     "info editing +" does.  This is unnecessary if arg is null,
+     because "info editing +" is not useful after "info editing".  */
+  if (from_tty && args)
+    {
+      args[0] = '+';
+      args[1] = '\0';
+    }
+}
+
+/* Called by do_setshow_command.  */
+static void
+set_history_size_command (args, from_tty, c)
+     char *args;
+     int from_tty;
+     struct cmd_list_element *c;
+{
+  if (history_size == UINT_MAX)
+    unstifle_history ();
+  else
+    stifle_history (history_size);
+}
+
+static void
+set_history (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  printf ("\"set history\" must be followed by the name of a history subcommand.\n");
+  help_list (sethistlist, "set history ", -1, stdout);
+}
+
+static void
+show_history (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  cmd_show_list (showhistlist, from_tty);
+}
+
+int info_verbose = 0;          /* Default verbose msgs off */
+
+/* Called by do_setshow_command.  An elaborate joke.  */
+static void 
+set_verbose (args, from_tty, c)
+     char *args;
+     int from_tty;
+     struct cmd_list_element *c;
+{
+  char *cmdname = "verbose";
+  struct cmd_list_element *showcmd;
+  
+  showcmd = lookup_cmd_1 (&cmdname, showlist, NULL, 1);
+
+  if (info_verbose)
+    {
+      c->doc = "Set verbose printing of informational messages.";
+      showcmd->doc = "Show verbose printing of informational messages.";
+    }
+  else
+    {
+      c->doc = "Set verbosity.";
+      showcmd->doc = "Show verbosity.";
+    }
+}
+
+static void
+float_handler ()
+{
+  /* This message is based on ANSI C, section 4.7.  Note that integer
+     divide by zero causes this, so "float" is a misnomer.  */
+  error ("Erroneous arithmetic operation.");
+}
+
+/* Return whether we are running a batch file or from terminal.  */
+int
+batch_mode ()
+{
+  return !(instream == stdin && ISATTY (stdin));
+}
+
+\f
+static void
+initialize_cmd_lists ()
+{
+  cmdlist = (struct cmd_list_element *) 0;
+  infolist = (struct cmd_list_element *) 0;
+  enablelist = (struct cmd_list_element *) 0;
+  disablelist = (struct cmd_list_element *) 0;
+  deletelist = (struct cmd_list_element *) 0;
+  enablebreaklist = (struct cmd_list_element *) 0;
+  setlist = (struct cmd_list_element *) 0;
+  showlist = NULL;
+  sethistlist = (struct cmd_list_element *) 0;
+  showhistlist = NULL;
+  unsethistlist = (struct cmd_list_element *) 0;
+}
+
+static void
+initialize_main ()
+{
+  struct cmd_list_element *c;
+  
+  char *tmpenv;
+  
+#ifdef DEFAULT_PROMPT
+  prompt = savestring (DEFAULT_PROMPT, strlen(DEFAULT_PROMPT));
+#else
+  prompt = savestring ("(gdb) ", 6);
+#endif
+
+  /* Set the important stuff up for command editing.  */
+  command_editing_p = 1;
+  history_expansion_p = 0;
+  write_history_p = 0;
+  
+  if (tmpenv = getenv ("HISTSIZE"))
+    history_size = atoi (tmpenv);
+  else
+    history_size = 256;
+
+  stifle_history (history_size);
+
+  if (tmpenv = getenv ("GDBHISTFILE"))
+    history_filename = savestring (tmpenv, strlen(tmpenv));
+  else
+    /* We include the current directory so that if the user changes
+       directories the file written will be the same as the one
+       that was read.  */
+    history_filename = concat (current_directory, "/.gdb_history", "");
+
+  read_history (history_filename);
+
+  /* Setup important stuff for command line editing.  */
+  rl_completion_entry_function = (int (*)()) symbol_completion_function;
+  rl_completer_word_break_characters = gdb_completer_word_break_characters;
+  rl_readline_name = "gdb";
+
+  /* Define the classes of commands.
+     They will appear in the help list in the reverse of this order.  */
+
+  add_cmd ("obscure", class_obscure, NO_FUNCTION, "Obscure features.", &cmdlist);
+  add_cmd ("aliases", class_alias, NO_FUNCTION, "Aliases of other commands.", &cmdlist);
+  add_cmd ("user-defined", class_user, NO_FUNCTION, "User-defined commands.\n\
+The commands in this class are those defined by the user.\n\
+Use the \"define\" command to define a command.", &cmdlist);
+  add_cmd ("support", class_support, NO_FUNCTION, "Support facilities.", &cmdlist);
+  add_cmd ("status", class_info, NO_FUNCTION, "Status inquiries.", &cmdlist);
+  add_cmd ("files", class_files, NO_FUNCTION, "Specifying and examining files.", &cmdlist);
+  add_cmd ("breakpoints", class_breakpoint, NO_FUNCTION, "Making program stop at certain points.", &cmdlist);
+  add_cmd ("data", class_vars, NO_FUNCTION, "Examining data.", &cmdlist);
+  add_cmd ("stack", class_stack, NO_FUNCTION, "Examining the stack.\n\
+The stack is made up of stack frames.  Gdb assigns numbers to stack frames\n\
+counting from zero for the innermost (currently executing) frame.\n\n\
+At any time gdb identifies one frame as the \"selected\" frame.\n\
+Variable lookups are done with respect to the selected frame.\n\
+When the program being debugged stops, gdb selects the innermost frame.\n\
+The commands below can be used to select other frames by number or address.",
+          &cmdlist);
+  add_cmd ("running", class_run, NO_FUNCTION, "Running the program.", &cmdlist);
+
+  add_com ("pwd", class_files, pwd_command,
+          "Print working directory.  This is used for your program as well.");
+  add_com ("cd", class_files, cd_command,
+          "Set working directory to DIR for debugger and program being debugged.\n\
+The change does not take effect for the program being debugged\n\
+until the next time it is started.");
+
+  add_show_from_set
+    (add_set_cmd ("prompt", class_support, var_string, (char *)&prompt,
+          "Set gdb's prompt",
+          &setlist),
+     &showlist);
+  
+  add_com ("echo", class_support, echo_command,
+          "Print a constant string.  Give string as argument.\n\
+C escape sequences may be used in the argument.\n\
+No newline is added at the end of the argument;\n\
+use \"\\n\" if you want a newline to be printed.\n\
+Since leading and trailing whitespace are ignored in command arguments,\n\
+if you want to print some you must use \"\\\" before leading whitespace\n\
+to be printed or after trailing whitespace.");
+  add_com ("document", class_support, document_command,
+          "Document a user-defined command.\n\
+Give command name as argument.  Give documentation on following lines.\n\
+End with a line of just \"end\".");
+  add_com ("define", class_support, define_command,
+          "Define a new command name.  Command name is argument.\n\
+Definition appears on following lines, one command per line.\n\
+End with a line of just \"end\".\n\
+Use the \"document\" command to give documentation for the new command.\n\
+Commands defined in this way do not take arguments.");
+
+#ifdef __STDC__
+  add_com ("source", class_support, source_command,
+          "Read commands from a file named FILE.\n\
+Note that the file \"" GDBINIT_FILENAME "\" is read automatically in this way\n\
+when gdb is started.");
+#else
+  /* Punt file name, we can't help it easily.  */
+  add_com ("source", class_support, source_command,
+          "Read commands from a file named FILE.\n\
+Note that the file \".gdbinit\" is read automatically in this way\n\
+when gdb is started.");
+#endif
+
+  add_com ("quit", class_support, quit_command, "Exit gdb.");
+  add_com ("help", class_support, help_command, "Print list of commands.");
+  add_com_alias ("q", "quit", class_support, 1);
+  add_com_alias ("h", "help", class_support, 1);
+
+
+  c = add_set_cmd ("verbose", class_support, var_boolean, (char *)&info_verbose,
+                  "Set ",
+                  &setlist),
+  add_show_from_set (c, &showlist);
+  c->function = set_verbose;
+  set_verbose (NULL, 0, c);
+  
+  add_com ("dump-me", class_obscure, dump_me_command,
+          "Get fatal error; make debugger dump its core.");
+
+  add_show_from_set
+    (add_set_cmd ("editing", class_support, var_boolean, (char *)&command_editing_p,
+          "Set command line editing.\n\
+Use \"on\" to enable to enable the editing, and \"off\" to disable it.\n\
+Without an argument, command line editing is enabled.", &setlist),
+     &showlist);
+
+  add_prefix_cmd ("history", class_support, set_history,
+                 "Generic command for setting command history parameters.",
+                 &sethistlist, "set history ", 0, &setlist);
+  add_prefix_cmd ("history", class_support, show_history,
+                 "Generic command for showing command history parameters.",
+                 &showhistlist, "show history ", 0, &showlist);
+
+  add_show_from_set
+    (add_set_cmd ("expansion", no_class, var_boolean, (char *)&history_expansion_p,
+          "Set history expansion on command input.\n\
+Without an argument, history expansion is enabled.", &sethistlist),
+     &showhistlist);
+
+  add_show_from_set
+    (add_set_cmd ("write", no_class, var_boolean, (char *)&write_history_p,
+          "Set saving of the history record on exit.\n\
+Use \"on\" to enable to enable the saving, and \"off\" to disable it.\n\
+Without an argument, saving is enabled.", &sethistlist),
+     &showhistlist);
+
+  c = add_set_cmd ("size", no_class, var_uinteger, (char *)&history_size,
+                  "Set the size of the command history, \n\
+ie. the number of previous commands to keep a record of.", &sethistlist);
+  add_show_from_set (c, &showhistlist);
+  c->function = set_history_size_command;
+
+  add_show_from_set
+    (add_set_cmd ("filename", no_class, var_filename, (char *)&history_filename,
+          "Set the filename in which to record the command history\n\
+ (the list of previous commands of which a record is kept).", &sethistlist),
+     &showhistlist);
+
+  add_show_from_set
+    (add_set_cmd ("caution", class_support, var_boolean,
+                 (char *)&caution,
+          "Set expected caution of user.\n\
+If on (the default), more warnings are printed, and the user is asked whether\n\
+they really want to do various major commands.", &setlist),
+     &showlist);
+
+  add_prefix_cmd ("info", class_info, info_command,
+                 "Generic command for printing status.",
+                 &infolist, "info ", 0, &cmdlist);
+  add_com_alias ("i", "info", class_info, 1);
+
+  add_prefix_cmd ("show", class_info, show_command,
+                 "Generic command for showing things set with \"set\".",
+                 &showlist, "show ", 0, &cmdlist);
+  /* Another way to get at the same thing.  */
+  add_info ("set", show_command, "Show all GDB settings.");
+
+  add_info ("editing", editing_info, "Status of command editor.");
+
+  add_info ("version", version_info, "Report what version of GDB this is.");
+}
diff --git a/gdb/mem-break.c b/gdb/mem-break.c
new file mode 100644 (file)
index 0000000..eebe7e2
--- /dev/null
@@ -0,0 +1,178 @@
+/* Simulate breakpoints by patching locations in the target system.
+   Copyright (C) 1990 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 "defs.h"
+#include "param.h"
+
+#ifdef BREAKPOINT
+/* This file is only useful if BREAKPOINT is set.  If not, we punt.  */
+
+#include <stdio.h>
+#include "breakpoint.h"
+#include "inferior.h"
+#include "target.h"
+
+/* This is the sequence of bytes we insert for a breakpoint.  On some
+   machines, breakpoints are handled by the target environment and we
+   don't have to worry about them here.  */
+
+static char break_insn[] = BREAKPOINT;
+
+/* This is only to check that BREAKPOINT fits in BREAKPOINT_MAX bytes.  */
+
+static char check_break_insn_size[BREAKPOINT_MAX] = BREAKPOINT;
+
+/* Insert a breakpoint on machines that don't have any better breakpoint
+   support.  We read the contents of the target location and stash it,
+   then overwrite it with a breakpoint instruction.  ADDR is the target
+   location in the target machine.  CONTENTS_CACHE is a pointer to 
+   memory allocated for saving the target contents.  It is guaranteed
+   by the caller to be long enough to save sizeof BREAKPOINT bytes.
+   FIXME: This size is target_arch dependent and should be available in
+   the target_arch transfer vector, if we ever have one...  */
+
+int
+memory_insert_breakpoint (addr, contents_cache)
+     CORE_ADDR addr;
+     char *contents_cache;
+{
+  int val;
+
+  val = target_read_memory (addr, contents_cache, sizeof break_insn);
+
+  if (val == 0)
+    val = target_write_memory (addr, break_insn, sizeof break_insn);
+
+  return val;
+}
+
+
+int
+memory_remove_breakpoint (addr, contents_cache)
+     CORE_ADDR addr;
+     char *contents_cache;
+{
+  return target_write_memory (addr, contents_cache, sizeof break_insn);
+}
+
+
+#if 0
+/* This should move back into breakpoint.c, sad to say.   Encapsulate
+    sizeof (BREAKPOINT) by export it as an int from mem-break.c.  */
+
+/* Like target_read_memory() but if breakpoints are inserted, return
+   the shadow contents instead of the breakpoints themselves.  */
+int
+read_memory_nobpt (memaddr, myaddr, len)
+     CORE_ADDR memaddr;
+     char *myaddr;
+     unsigned len;
+{
+  int status;
+  struct breakpoint *b;
+  ALL_BREAKPOINTS (b)
+    {
+      if (b->address == NULL || !b->inserted)
+       continue;
+      else if (b->address + sizeof (break_insn) <= memaddr)
+       /* The breakpoint is entirely before the chunk of memory
+          we are reading.  */
+       continue;
+      else if (b->address >= memaddr + len)
+       /* The breakpoint is entirely after the chunk of memory we
+          are reading.  */
+       continue;
+      else
+       {
+         /* Copy the breakpoint from the shadow contents, and recurse
+            for the things before and after.  */
+         
+         /* Addresses and length of the part of the breakpoint that
+            we need to copy.  */
+         CORE_ADDR membpt = b->address;
+         unsigned int bptlen = sizeof (break_insn);
+         /* Offset within shadow_contents.  */
+         int bptoffset = 0;
+         
+         if (membpt < memaddr)
+           {
+             /* Only copy the second part of the breakpoint.  */
+             bptlen -= memaddr - membpt;
+             bptoffset = memaddr - membpt;
+             membpt = memaddr;
+           }
+
+         if (membpt + bptlen > memaddr + len)
+           {
+             /* Only copy the first part of the breakpoint.  */
+             bptlen -= (membpt + bptlen) - (memaddr + len);
+           }
+
+         bcopy (b->shadow_contents + bptoffset,
+                myaddr + membpt - memaddr, bptlen);
+
+         if (membpt > memaddr)
+           {
+             /* Copy the section of memory before the breakpoint.  */
+             status = read_memory_nobpt (memaddr, myaddr, membpt - memaddr);
+             if (status != 0)
+               return status;
+           }
+
+         if (membpt + bptlen < memaddr + len)
+           {
+             /* Copy the section of memory after the breakpoint.  */
+             status = read_memory_nobpt
+               (membpt + bptlen,
+                myaddr + membpt + bptlen - memaddr,
+                memaddr + len - (membpt + bptlen));
+             if (status != 0)
+               return status;
+           }
+         return 0;
+       }
+    }
+  /* Nothing overlaps.  Just call read_memory_noerr.  */
+  return target_read_memory (memaddr, myaddr, len);
+}
+#endif /* 0 */
+
+#else  /* BREAKPOINT */
+
+char nogo[] = "Breakpoints not implemented for this target.";
+
+int
+memory_insert_breakpoint (addr, contents_cache)
+     CORE_ADDR addr;
+     char *contents_cache;
+{
+  error (nogo);
+  return 0;    /* lint */
+}
+
+int
+memory_remove_breakpoint (addr, contents_cache)
+     CORE_ADDR addr;
+     char *contents_cache;
+{
+  error (nogo);
+  return 0;    /* lint */
+}
+
+#endif /* BREAKPOINT */
diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c
new file mode 100644 (file)
index 0000000..abdd206
--- /dev/null
@@ -0,0 +1,679 @@
+/* Work with core dump and executable files, for GDB on MIPS. 
+   This code would be in core.c if it weren't machine-dependent. */
+
+/* Low level interface to ptrace, for GDB when running under Unix.
+   Copyright (C) 1988, 1989, 1990  Free Software Foundation, Inc.
+   Contributed by Alessandro Forin(af@cs.cmu.edu) at CMU
+   and by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin.
+
+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.  */
+
+/* FIXME: Can a MIPS porter/tester determine which of these include
+   files we still need?   -- gnu@cygnus.com */
+#include <stdio.h>
+#include <mips/inst.h>
+#include "defs.h"
+#include "param.h"
+#include "frame.h"
+#include "inferior.h"
+#include "symtab.h"
+#include "value.h"
+#include "gdbcmd.h"
+
+#ifdef USG
+#include <sys/types.h>
+#endif
+
+#include <sys/param.h>
+#include <sys/dir.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+
+#include "gdbcore.h"
+
+#ifndef        MIPSMAGIC
+#ifdef MIPSEL
+#define MIPSMAGIC      MIPSELMAGIC
+#else
+#define MIPSMAGIC      MIPSEBMAGIC
+#endif
+#endif
+
+#define VM_MIN_ADDRESS (unsigned)0x400000
+
+#include <sys/user.h>          /* After a.out.h  */
+#include <sys/file.h>
+#include <sys/stat.h>
+
+\f
+#define PROC_LOW_ADDR(proc) ((proc)->adr) /* least address */
+#define PROC_HIGH_ADDR(proc) ((proc)->pad2) /* upper address bound */
+#define PROC_FRAME_OFFSET(proc) ((proc)->framesize)
+#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_)
+
+struct linked_proc_info
+{
+  struct mips_extra_func_info info;
+  struct linked_proc_info *next;
+} * linked_proc_desc_table = NULL;
+
+\f
+#define READ_FRAME_REG(fi, regno) read_next_frame_reg((fi)->next, regno)
+
+int
+read_next_frame_reg(fi, regno)
+     FRAME fi;
+     int regno;
+{
+#define SIGFRAME_BASE   sizeof(struct sigcontext)
+#define SIGFRAME_PC_OFF (-SIGFRAME_BASE+ 2*sizeof(int))
+#define SIGFRAME_SP_OFF (-SIGFRAME_BASE+32*sizeof(int))
+#define SIGFRAME_RA_OFF (-SIGFRAME_BASE+34*sizeof(int))
+  for (; fi; fi = fi->next)
+      if (in_sigtramp(fi->pc, 0)) {
+         /* No idea if this code works. --PB. */
+         int offset;
+         if (regno == PC_REGNUM) offset = SIGFRAME_PC_OFF;
+         else if (regno == RA_REGNUM) offset = SIGFRAME_RA_OFF;
+         else if (regno == SP_REGNUM) offset = SIGFRAME_SP_OFF;
+         else return 0;
+         return read_memory_integer(fi->frame + offset, 4);
+      }
+      else 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
+mips_frame_saved_pc(frame)
+     FRAME frame;
+{
+  mips_extra_func_info_t proc_desc = (mips_extra_func_info_t)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 struct mips_extra_func_info 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 its 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;
+}
+
+mips_extra_func_info_t
+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;
+    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(temp_proc_desc));
+    bzero(&temp_saved_regs, sizeof(struct frame_saved_regs));
+    if (start_pc + 200 < limit_pc) limit_pc = start_pc + 200;
+  restart:
+    frame_size = 0;
+    for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += 4) {
+       unsigned long word;
+       int status;
+
+       status = read_memory_nobpt (cur_pc, &word, 4); 
+       if (status) memory_error (status, cur_pc); 
+       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_extra_func_info_t
+find_proc_desc(pc, next_frame)
+    CORE_ADDR pc;
+    FRAME next_frame;
+{
+  mips_extra_func_info_t proc_desc;
+  extern struct block *block_for_pc();
+  struct block   *b = block_for_pc(pc);
+
+  struct symbol *sym =
+      b ? lookup_symbol(".gdbinfo.", b, LABEL_NAMESPACE, 0, NULL) : NULL;
+  if (sym != NULL)
+    {
+       /* 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.
+        */
+       proc_desc = (struct mips_extra_func_info *)sym->value.value;
+       if (next_frame == NULL) {
+           struct symtab_and_line val;
+           struct symbol *proc_symbol =
+               PROC_DESC_IS_DUMMY(proc_desc) ? 0 : 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_extra_func_info_t found_heuristic =
+                   heuristic_proc_desc(PROC_LOW_ADDR(proc_desc),
+                                       pc, next_frame);
+               if (found_heuristic) proc_desc = found_heuristic;
+           }
+       }
+    }
+  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;
+}
+
+mips_extra_func_info_t cached_proc_desc;
+
+FRAME_ADDR mips_frame_chain(frame)
+    FRAME frame;
+{
+    extern CORE_ADDR startup_file_start;       /* From blockframe.c */
+    mips_extra_func_info_t 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) & 0xFC00003F == 0xD)
+           return 0;  /* break */
+      }
+    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 */
+  mips_extra_func_info_t 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
+mips_push_dummy_frame()
+{
+  int ireg;
+  struct linked_proc_info *link = (struct linked_proc_info*)
+      xmalloc(sizeof(struct linked_proc_info));
+  mips_extra_func_info_t 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 tm-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_LOW_ADDR(proc_desc) = sp - CALL_DUMMY_SIZE + CALL_DUMMY_START_OFFSET;
+  PROC_HIGH_ADDR(proc_desc) = sp;
+  SET_PROC_DESC_IS_DUMMY(proc_desc);
+  PROC_PC_REG(proc_desc) = RA_REGNUM;
+}
+
+void
+mips_pop_frame()
+{ register int regnum;
+  FRAME frame = get_current_frame ();
+  CORE_ADDR new_sp = frame->frame;
+  mips_extra_func_info_t proc_desc = (mips_extra_func_info_t)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 ("; ");
+      }
+  }
+}
+/* Return number of args passed to a frame. described by FIP.
+   Can return -1, meaning no way to tell.  */
+
+mips_frame_num_args(fip)
+       FRAME fip;
+{
+#if 0
+       struct chain_info_t *p;
+
+       p = mips_find_cached_frame(FRAME_FP(fip));
+       if (p->valid)
+               return p->the_info.numargs;
+#endif
+       return -1;
+}
+
+\f
+/* Bad floats: Returns 0 if P points to a valid IEEE floating point number,
+   1 if P points to a denormalized number or a NaN. LEN says whether this is
+   a single-precision or double-precision float */
+#define SINGLE_EXP_BITS  8
+#define DOUBLE_EXP_BITS 11
+int
+isa_NAN(p, len)
+     int *p, len;
+{
+  int exponent;
+  if (len == 4)
+    {
+      exponent = *p;
+      exponent = exponent << 1 >> (32 - SINGLE_EXP_BITS - 1);
+      return ((exponent == -1) || (! exponent && *p));
+    }
+  else if (len == 8)
+    {
+      exponent = *(p+1);
+      exponent = exponent << 1 >> (32 - DOUBLE_EXP_BITS - 1);
+      return ((exponent == -1) || (! exponent && *p * *(p+1)));
+    }
+  else return 1;
+}
+
+/* To skip prologues, I use this predicate. Returns either PC
+   itself if the code at PC does not look like a function prologue,
+   PC+4 if it does (our caller does not need anything more fancy). */
+
+CORE_ADDR mips_skip_prologue(pc)
+     CORE_ADDR pc;
+{
+    struct symbol *f;
+    struct block *b;
+    unsigned long inst;
+
+    /* For -g modules and most functions anyways the
+       first instruction adjusts the stack. */
+    inst = read_memory_integer(pc, 4);
+    if ((inst & 0xffff0000) == 0x27bd0000)
+       return pc + 4;
+
+    /* Well, it looks like a frameless. Let's make sure.
+       Note that we are not called on the current PC,
+       but on the function`s start PC, and I have definitely
+       seen optimized code that adjusts the SP quite later */
+    b = block_for_pc(pc);
+    if (!b) return pc;
+
+    f = lookup_symbol(".gdbinfo.", b, LABEL_NAMESPACE, 0, NULL);
+    if (!f) return pc;
+    /* Ideally, I would like to use the adjusted info
+       from mips_frame_info(), but for all practical
+       purposes it will not matter (and it would require
+       a different definition of SKIP_PROLOGUE())
+
+       Actually, it would not hurt to skip the storing
+       of arguments on the stack as well. */
+    if (((struct mips_extra_func_info *)f->value.value)->framesize)
+       return pc + 4;
+
+    return pc;
+}
diff --git a/gdb/mipsread.c b/gdb/mipsread.c
new file mode 100644 (file)
index 0000000..2c7112f
--- /dev/null
@@ -0,0 +1,2879 @@
+/* Read a symbol table in MIPS' format (Third-Eye).
+   Copyright (C) 1986, 1987, 1989-1991 Free Software Foundation, Inc.
+   Contributed by Alessandro Forin (af@cs.cmu.edu) at CMU
+
+This file is part of GDB.
+
+GDB is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GDB is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GDB; see the file COPYING.  If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <stdio.h>
+#include "param.h"
+#include "obstack.h"
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include "defs.h"
+#include "symtab.h"
+#include "gdbcore.h"
+#include "symfile.h"
+#ifdef CMUCS
+#include <mips/syms.h>
+#endif CMUCS
+
+/* Since these things are defined differently on various systems I'll
+   (re)define here what I really need in this module.  I only assume the
+   three standard COFF structure definitions: filehdr, aouthdr, scnhdr */
+#define MIPS           /* Kludge to get MIPS version of coff */
+#include "intel-coff.h"
+
+struct coff_exec {
+       struct filehdr f;
+       struct aouthdr a;
+};
+#undef a_magic
+#undef a_text
+#undef a_data
+#undef a_bss
+#undef a_syms
+#undef a_entry
+#define a_magic        a.magic         /* magic number */
+#define a_text a.tsize         /* size of text segment */
+#define a_data a.dsize         /* size of initialized data */
+#define a_bss  a.bsize         /* size of uninitialized data */
+#define a_syms f.f_nsyms       /* size of symbol table */
+#define a_entry        a.entry         /* entry point */
+
+#undef N_BADMAG
+#define        N_BADMAG(x) \
+    (((x).a_magic)!=OMAGIC && ((x).a_magic)!=NMAGIC && ((x).a_magic)!=ZMAGIC)
+
+/* Things we import explicitly from other modules */
+
+extern int          info_verbose;
+extern struct block *block_for_pc();
+extern void         sort_symtab_syms();
+
+/* Forward declarations */
+
+static void psymtab_to_symtab_1();
+
+/* Macros and extra defs */
+
+struct complaint unknown_ext_complaint = 
+       {"unknown external symbol %s", 0, 0};
+
+/* Already parsed symbols are marked specially */
+
+#define stParsed stType
+
+/* Puns: hard to find whether -g was used and how */
+
+#define MIN_GLEVEL GLEVEL_0
+#define compare_glevel(a,b)                                    \
+       (((a) == GLEVEL_3) ? ((b) < GLEVEL_3) :                 \
+        ((b) == GLEVEL_3) ? -1 : (int)((b) - (a)))
+
+/* When looking at .o files avoid tripping over bad addresses */
+
+#define SAFE_TEXT_ADDR 0x400000
+#define SAFE_DATA_ADDR 0x10000000
+
+#define UNSAFE_DATA_ADDR(p)    ((unsigned)p < SAFE_DATA_ADDR || (unsigned)p > 2*SAFE_DATA_ADDR)
+
+\f
+/* Things we export to other modules */
+
+
+/* Lists of partial symbols */
+
+struct psymbol_allocation_list global_psymbols, static_psymbols;
+
+/* Address bounds for the signal trampoline in inferior, if any */
+
+CORE_ADDR sigtramp_address, sigtramp_end;
+
+
+/* Functions that we really export */
+
+/* THIS DESCRIPTION IS OBSOLETE POST-BFD; FIXME! */
+/* Basically, this module must provide two functions: symbol_file_command()
+   which loads the symbol table from a file, and add_file_command() which
+   adds more symbols to the symbol table (incrementally).
+
+   These two functions only do the minimum work necessary for letting the
+   user "name" things symbolically, they do not read the entire symtab.
+   Instead, they read in the external symbols and put them in partial
+   symbol tables.  When more extensive information is requested of a
+   file the corresponding partial symbol table is mutated into a full
+   fledged symbol table by going back and reading the relative symbols
+   for real.  mipscoff_psymtab_to_symtab() is the function that does this */
+
+/* The entry point (starting address) of the file, if it is an executable.  */
+
+static CORE_ADDR entry_point;
+
+extern CORE_ADDR startup_file_start;   /* From blockframe.c */
+extern CORE_ADDR startup_file_end;     /* From blockframe.c */
+
+void
+mipscoff_new_init()
+{
+}
+
+void
+mipscoff_symfile_init (sf)
+     struct sym_fns *sf;
+{
+  bfd *abfd = sf->sym_bfd;
+  sf->sym_private = NULL;
+  /* Save startup file's range of PC addresses to help blockframe.c
+     decide where the bottom of the stack is.  */
+  if (bfd_get_file_flags (abfd) & EXEC_P)
+    {
+      /* Executable file -- record its entry point so we'll recognize
+        the startup file because it contains the entry point.  */
+      entry_point = bfd_get_start_address (abfd);
+    }
+  else
+    {
+      /* Examination of non-executable.o files.  Short-circuit this stuff.  */
+      /* ~0 will not be in any file, we hope.  */
+      entry_point = ~0;
+      /* set the startup file to be an empty range.  */
+      startup_file_start = 0;
+      startup_file_end = 0;
+    }
+}
+
+void
+mipscoff_symfile_read(sf, addr, mainline)
+     struct sym_fns *sf;
+     CORE_ADDR addr;
+     int mainline;
+{
+  struct coff_symfile_info *info = (struct coff_symfile_info *)sf->sym_private;
+  bfd *abfd = sf->sym_bfd;
+  char *name = bfd_get_filename (abfd);
+  int desc;
+  register int val;
+  int num_symbols;
+  int symtab_offset;
+  int stringtab_offset;
+
+/* WARNING WILL ROBINSON!  ACCESSING BFD-PRIVATE DATA HERE!  FIXME!  */
+   desc = fileno ((FILE *)(abfd->iostream));   /* Raw file descriptor */
+   num_symbols = bfd_get_symcount (abfd);      /* How many syms */
+/*   symtab_offset = obj_sym_filepos (abfd);   * Symbol table file offset */
+/*   stringtab_offset = symtab_offset + num_symbols * SYMESZ;  * String tab */
+/* End of warning */
+
+#ifdef TDESC
+  debug_info = text_hdr.s_relptr;
+  if (tdesc_handle)
+    {
+       dc_terminate (tdesc_handle);
+       tdesc_handle = 0;
+    }
+#endif
+
+#if 0
+  /* Read the line number table, all at once.  */
+  info->min_lineno_offset = 0;
+  info->max_lineno_offset = 0;
+  bfd_map_over_sections (abfd, find_linenos, info);
+
+  val = init_lineno (desc, info->min_lineno_offset, 
+                    info->max_lineno_offset - info->min_lineno_offset);
+  if (val < 0)
+    error ("\"%s\": error reading line numbers\n", name);
+
+  /* Now read the string table, all at once.  */
+
+  val = init_stringtab (desc, stringtab_offset);
+  if (val < 0)
+    {
+      free_all_symtabs ();             /* FIXME blows whole symtab */
+      printf ("\"%s\": can't get string table", name);
+      fflush (stdout);
+      return;
+    }
+  make_cleanup (free_stringtab, 0);
+#endif
+  /* Position to read the symbol table.  Do not read it all at once. */
+  val = lseek (desc, (long)symtab_offset, 0);
+  if (val < 0)
+    perror_with_name (name);
+
+  init_misc_bunches ();
+  make_cleanup (discard_misc_bunches, 0);
+
+  /* Now that the executable file is positioned at symbol table,
+     process it and define symbols accordingly.  */
+
+  printf("Reading symbol data from %s...", name);
+  fflush(stdout);
+  read_mips_symtab(desc, 0);
+
+/*  patch_opaque_types ();*/
+
+  /* Sort symbols alphabetically within each block.  */
+
+  sort_all_symtab_syms ();
+
+  /* Go over the misc symbol bunches and install them in vector.  */
+
+  condense_misc_bunches (0);
+
+  /* Make a default for file to list.  */
+
+  select_source_symtab (0);    /* FIXME, this might be too slow, see dbxread */
+}  
+  
+void
+mipscoff_symfile_discard()
+{
+}
+  
+  
+#if 0
+/* Exported procedure: Reads symbols from file NAME.
+   Invoked at startup time if executable was given.
+   When invoked cleans up the world */
+
+void
+symbol_file_command(name, from_tty)
+     char *name;
+     int from_tty;
+{
+  int                  desc;
+  struct coff_exec     hdr;
+  register int         val;
+  extern void          close();
+  struct cleanup *old_chain;
+
+  dont_repeat();
+
+  /*
+   * Make sure s/he means it 
+   */
+  if (name == 0) {
+    if ((symtab_list || partial_symtab_list)
+       && from_tty
+       && !query("Discard symbol table? ", 0))
+       error("Not confirmed.");
+    destroy_all_symtabs();
+    return;
+  }
+
+  name = tilde_expand(name);
+  make_cleanup(free, name);
+
+  if (symtab_list &&
+      !query("Load new symbol table from \"%s\"? ", name))
+      error("Not confirmed.");
+
+  /* Open the file */
+  {
+    char *absolute_name;
+    desc = openp (getenv ("PATH"), 1, name, O_RDONLY, 0, &absolute_name);
+    if (desc < 0)
+      perror_with_name (name);
+    else
+      name = absolute_name;
+  }
+
+  old_chain = make_cleanup (close, desc);
+  make_cleanup (free_current_contents, &name);
+
+  /*
+   * Check file is indeed executable 
+   */
+  val = myread(desc, &hdr, sizeof hdr);
+  if (val < 0)
+     perror_with_name(name);
+
+  if (N_BADMAG(hdr))
+    error("File \"%s\" not in executable format.", name);
+
+  if (hdr.a.entry < SAFE_TEXT_ADDR && access(name, 1))
+      printf_filtered("Warning: %s is not executable!\n", name);
+
+  if (hdr.a_syms == 0) {
+    printf_filtered("%s does not have a symbol-table.\n", name);
+    fflush(stdout);
+    return;
+  }
+
+  /* Get the modification time.  */
+  {
+    struct stat symstat;
+
+    if (fstat (desc, &symstat) < 0)
+      perror_with_name (name);
+
+    symfile_mtime = symstat.st_mtime;
+  }
+
+  /*
+   * Throw away the old symbol table.  
+   */
+
+  destroy_all_symtabs();
+
+  /* Make a default for file to list.  */
+
+  symfile = savestring (name, strlen (name));
+
+  /* Prepare to remember misc symbol values */
+
+  init_misc_bunches ();
+  make_cleanup (discard_misc_bunches, 0);
+
+  /*
+   * Now read the new symbol table 
+   */
+
+  read_mips_symtab(desc, 0);
+
+  /* Go over the misc symbol bunches and install them in vector.  */
+
+  condense_misc_bunches (0);
+
+  /* Don't allow char * to have a typename (else would get caddr_t.)  */
+
+  TYPE_NAME (lookup_pointer_type (builtin_type_char)) = 0;
+
+  /* Force reinit of the sigtramp info */
+  sigtramp_address = 0;
+
+  do_cleanups (old_chain);     /* Descriptor closed here */
+
+  if (!partial_symtab_list)
+    printf ("\n(no debugging symbols found)...");
+
+  printf ("done.\n");
+  fflush(stdout);
+}
+#endif
+
+/* C++:
+   This function allows the addition of incrementally linked object files.
+   Since this has a fair amount of code in common with symbol_file_command,
+   it might be worthwhile to consolidate things, as was done with
+   read_dbx_symtab and condense_misc_bunches. */
+
+/* Exported procedure: add more symbols from file NAME. */
+
+void
+add_file_command(arg_string)
+     char* arg_string;
+{
+  int                  desc;
+  struct coff_exec     hdr;
+  register int         val;
+  extern void          close();
+  struct cleanup *old_chain;
+  char *name;
+  unsigned text_addr;
+
+  if (arg_string == 0)
+    error ("add-file takes a file name and an address");
+
+  if (arg_string == 0)
+    error ("add-file takes a file name and an address");
+
+  arg_string = tilde_expand (arg_string);
+  make_cleanup (free, arg_string);
+
+  for( ; *arg_string == ' '; arg_string++ );
+  name = arg_string;
+  for( ; *arg_string && *arg_string != ' ' ; arg_string++ );
+  *arg_string++ = (char) 0;
+
+  if (name[0] == 0)
+    error ("add-file takes a file name and an address");
+
+  text_addr = parse_and_eval_address (arg_string);
+
+  dont_repeat();
+
+  if (!query ("add symbol table from filename \"%s\" at text_addr = 0x%x\n",
+             name, text_addr))
+    error ("Not confirmed.");
+
+  /*
+   * Open the file 
+   */
+  {
+    char           *absolute_name;
+
+    desc = openp(getenv("PATH"), 1, name, O_RDONLY, 0, &absolute_name);
+    if (desc < 0)
+      perror_with_name(name);
+    else
+      name = absolute_name;
+  }
+  old_chain = make_cleanup (close, desc);
+
+
+  /*
+   * Check file is indeed executable 
+   */
+  val = myread(desc, &hdr, sizeof hdr);
+  if (val < 0)
+      perror_with_name(name);
+
+  if (N_BADMAG(hdr))
+      error("File \"%s\" not in executable format.", name);
+
+  if (hdr.a.entry < SAFE_TEXT_ADDR && access(name, 1))
+      printf_filtered("Warning: %s is not executable!\n", name);
+
+  if (hdr.a_syms == 0) {
+      printf_filtered("%s does not have a symbol-table.\n", name);
+      fflush(stdout);
+      return;
+  }
+
+  if (symfile)
+      free(symfile);
+  symfile = 0;
+
+  /*
+   * Now read the new symbol table 
+   */
+
+  symfile = savestring(name, strlen(name));
+
+  init_misc_bunches ();
+  make_cleanup (discard_misc_bunches, 0);
+  read_mips_symtab(desc, 1);
+
+  /* Go over the misc symbol bunches and install them in vector.  */
+
+  condense_misc_bunches (1);
+
+  /* Don't allow char * to have a typename (else would get caddr_t.)  */
+
+  TYPE_NAME (lookup_pointer_type (builtin_type_char)) = 0;
+
+  do_cleanups (old_chain);
+
+  printf_filtered("done.\n");
+  fflush(stdout);
+}
+
+/* Exported procedure: Allocate zeroed memory */
+
+char *xzalloc(size)
+{
+       char           *p = xmalloc(size);
+
+       bzero(p, size);
+       return p;
+}
+
+/* Exported procedure: Builds a symtab from the PST partial one.
+   Restores the environment in effect when PST was created, delegates
+   most of the work to an ancillary procedure, and sorts
+   and reorders the symtab list at the end */
+
+/* Forward decls */
+static HDRR    *cur_hdr;       /* MIPS symtab header for the current file */
+
+void
+mipscoff_psymtab_to_symtab(pst)
+       struct partial_symtab *pst;
+{
+       struct symtab  *ret;
+       int             i;
+
+       if (!pst)
+               return;
+
+       if (info_verbose) {
+               printf_filtered("Reading in symbols for %s...", pst->filename);
+               fflush(stdout);
+       }
+       /* Restore the header and list of pending typedefs */
+       cur_hdr = (HDRR *) pst->ldsymlen;
+
+       psymtab_to_symtab_1(pst);
+
+       reorder_symtabs();
+
+       /* Finish up the debug error message.  */
+       if (info_verbose)
+               printf_filtered("done.\n");
+}
+
+/* Exported procedure: Is PC in the signal trampoline code */
+
+int in_sigtramp(pc,name)
+       CORE_ADDR pc;
+{
+       if (sigtramp_address == 0)
+               fixup_sigtramp();
+       return (pc >= sigtramp_address && pc < sigtramp_end);
+}
+
+\f
+/* Things that really are local to this module */
+
+/* All allocated symtabs and psymtabs */
+
+static int all_symtabs_count;
+static int all_psymtabs_count;
+
+/* GDB symtable for the current compilation unit */
+
+static struct symtab *cur_stab;
+
+/* Header for executable/object file we read symbols from */
+
+static struct coff_exec filhdr;
+#define END_OF_TEXT_SEGMENT(f) ((f).a.text_start + (f).a.tsize)
+
+/* Pointer to current file decriptor record, and its index */
+
+static FDR     *cur_fdr;
+static int      cur_fd;
+
+/* Index of current symbol */
+
+static int      cur_sdx;
+
+/* Note how much "debuggable" this image is.  We would like
+   to see at least one FDR with full symbols */
+
+static max_gdbinfo;
+static max_glevel;
+
+/* When examining .o files, report on undefined symbols */
+
+static int n_undef_symbols, n_undef_labels, n_undef_vars, n_undef_procs;
+
+/* Extra builtin types */
+
+struct type *builtin_type_complex;
+struct type *builtin_type_double_complex;
+struct type *builtin_type_fixed_dec;
+struct type *builtin_type_float_dec;
+struct type *builtin_type_string;
+
+/* Template types */
+
+static struct type *builtin_type_ptr;
+static struct type *builtin_type_struct;
+static struct type *builtin_type_union;
+static struct type *builtin_type_enum;
+static struct type *builtin_type_range;
+static struct type *builtin_type_set;
+
+
+/* Forward decls */
+
+static struct symbol   *new_symbol();
+static struct type     *new_type();
+static struct field    *new_field();
+static struct block    *new_block();
+static struct symtab   *new_symtab();
+static struct linetable        *new_linetable();
+static struct blockvector *new_bvect();
+
+static struct type     *parse_type();
+static struct type     *make_type();
+static struct symbol   *mylookup_symbol();
+static struct block    *shrink_block();
+
+static int compare_symtabs();
+static int compare_psymtabs();
+static int compare_blocks();
+
+static struct partial_symtab *new_psymtab();
+static struct partial_symbol *new_psymbol();
+static struct partial_symtab *parse_fdr();
+static int compare_psymbols();
+\f
+/* File-level interface functions */
+
+/* Read the symtab information from file FSYM into memory */
+
+static
+read_the_mips_symtab(fsym)
+{
+       int             stsize, st_hdrsize;
+       unsigned        st_filptr;
+       HDRR            st_hdr;
+
+       /* Find and read the symbol table header */
+       st_hdrsize = filhdr.f.f_nsyms;
+       st_filptr = filhdr.f.f_symptr;
+       if (st_filptr == 0)
+               return 0;
+
+       lseek(fsym, st_filptr, L_SET);
+       if (read(fsym, &st_hdr, st_hdrsize) != st_hdrsize)
+               goto readerr;
+
+       /* Find out how large the symbol table is */
+       stsize = (st_hdr.cbExtOffset - (st_filptr + st_hdrsize))
+               + st_hdr.iextMax * cbEXTR;
+
+       /* Allocate space for the symbol table.  Read it in.  */
+       cur_hdr = (HDRR *) xmalloc(stsize + st_hdrsize);
+
+       bcopy(&st_hdr, cur_hdr, st_hdrsize);
+       if (read(fsym, (char *) cur_hdr + st_hdrsize, stsize) != stsize)
+               goto readerr;
+
+       /* Fixup file_pointers in it */
+       fixup_symtab(cur_hdr, (char *) cur_hdr + st_hdrsize,
+                    st_filptr + st_hdrsize);
+
+       return;
+readerr:
+       error("Short read on %s", symfile);
+}
+
+
+/* Turn all file-relative pointers in the symtab described by HDR
+   into memory pointers, given that the symtab itself is located
+   at DATA in memory and F_PTR in the file. */
+
+static
+fixup_symtab( hdr, data, f_ptr)
+       HDRR *hdr;
+       char *data;
+{
+       int             f_idx, s_idx;
+       FDR            *fh;
+       SYMR           *sh;
+       OPTR           *op;
+       PDR            *pr;
+       EXTR           *esh;
+
+       /*
+        * These fields are useless (and empty) by now:
+        *      hdr->cbDnOffset, hdr->cbOptOffset
+        * We use them for other internal purposes.
+        */
+       hdr->cbDnOffset = 0;
+       hdr->cbOptOffset = 0;
+
+#define FIX(off) \
+        if (hdr->off) hdr->off = (unsigned int)data + (hdr->off - f_ptr);
+
+        FIX(cbLineOffset);
+        FIX(cbPdOffset);
+        FIX(cbSymOffset);
+        FIX(cbOptOffset);
+        FIX(cbAuxOffset);
+        FIX(cbSsOffset);
+        FIX(cbSsExtOffset);
+        FIX(cbFdOffset);
+        FIX(cbRfdOffset);
+        FIX(cbExtOffset);
+#undef FIX
+
+
+       /*
+        * Fix all string pointers inside the symtab, and
+        * the FDR records.  Also fix other miscellany.
+        */
+       for (f_idx = 0; f_idx < hdr->ifdMax; f_idx++) {
+               register unsigned code_offset;
+
+               /* Header itself, and strings */
+               fh = (FDR *) (hdr->cbFdOffset) + f_idx;
+               fh->issBase += hdr->cbSsOffset;
+               if (fh->rss != -1)
+                       fh->rss = (long)fh->rss + fh->issBase;
+               for (s_idx = 0; s_idx < fh->csym; s_idx++) {
+                       sh = (SYMR*)(hdr->cbSymOffset) + fh->isymBase + s_idx;
+                       sh->iss = (long) sh->iss + fh->issBase;
+                       sh->reserved = 0;
+               }
+
+               cur_fd = f_idx;
+
+               /* Local symbols */
+               fh->isymBase = (int)((SYMR*)(hdr->cbSymOffset)+fh->isymBase);
+
+               /* cannot fix fh->ipdFirst because it is a short */
+#define IPDFIRST(h,fh) \
+               ((long)h->cbPdOffset + fh->ipdFirst * sizeof(PDR))
+
+               /* Optional symbols (actually used for partial_symtabs) */
+               fh->ioptBase = 0;
+               fh->copt = 0;
+
+               /* Aux symbols */
+               if (fh->caux)
+                       fh->iauxBase = hdr->cbAuxOffset + fh->iauxBase * sizeof(AUXU);
+               /* Relative file descriptor table */
+               fh->rfdBase = hdr->cbRfdOffset + fh->rfdBase * sizeof(RFDT);
+
+               /* Line numbers */
+               if (fh->cbLine)
+                       fh->cbLineOffset += hdr->cbLineOffset;
+
+               /* Procedure symbols.  (XXX This should be done later) */
+               code_offset = fh->adr;
+               for (s_idx = 0; s_idx < fh->cpd; s_idx++) {
+                       unsigned name, only_ext;
+
+                       pr = (PDR*)(IPDFIRST(hdr,fh)) + s_idx;
+
+                       /* Simple rule to find files linked "-x" */
+                       only_ext = fh->rss == -1;
+                       if (only_ext) {
+                               if (pr->isym == -1) {
+                                       /* static function */
+                                       sh = (SYMR*)-1;
+                               } else {
+                                       /* external */
+                                       name = hdr->cbExtOffset + pr->isym * sizeof(EXTR);
+                                       sh = &((EXTR*)name)->asym;
+                               }
+                       } else {
+                               /* Full symbols */
+                               sh = (SYMR*)fh->isymBase + pr->isym;
+                               /* Included code ? */
+                               if (s_idx == 0 && pr->adr != 0)
+                                       code_offset -= pr->adr;
+                       }
+
+                       /* Turn index into a pointer */
+                       pr->isym = (long)sh;
+
+                       /* Fix line numbers */
+                       pr->cbLineOffset += fh->cbLineOffset;
+
+                       /* Relocate address */
+                       if (!only_ext)
+                               pr->adr += code_offset;
+               }               
+       }
+
+       /* External symbols: fix string */
+       for (s_idx = 0; s_idx < hdr->iextMax; s_idx++) {
+               esh = (EXTR*)(hdr->cbExtOffset) + s_idx;
+               esh->asym.iss = esh->asym.iss + hdr->cbSsExtOffset;
+       }
+}
+
+
+/* Find a file descriptor given its index RF relative to a file CF */
+
+static
+FDR *get_rfd( cf, rf)
+{
+       register FDR   *f;
+
+       f = (FDR *) (cur_hdr->cbFdOffset) + cf;
+       /* Object files do not have the RFD table, all refs are absolute */
+       if (f->rfdBase == 0)
+               return (FDR *) (cur_hdr->cbFdOffset) + rf;
+       cf = *((pRFDT) f->rfdBase + rf);
+       return (FDR *) (cur_hdr->cbFdOffset) + cf;
+}
+
+/* Return a safer print NAME for a file descriptor */
+
+static
+char *fdr_name(name)
+       char *name;
+{
+       if (name == (char *) -1)
+               return "<stripped file>";
+       if (UNSAFE_DATA_ADDR(name))
+               return "<NFY>";
+       return name;
+}
+
+
+/* Read in and parse the symtab of the file DESC. INCREMENTAL says
+   whether we are adding to the general symtab or not */
+
+static
+read_mips_symtab( desc, incremental)
+{
+       /*
+        * We get here with DESC pointing to the symtab header. But we need
+        * other info from the initial headers 
+        */
+       lseek(desc, 0L, 0);
+       myread(desc, &filhdr, sizeof filhdr);
+
+       read_the_mips_symtab(desc);
+
+       parse_partial_symbols(cur_hdr, incremental);
+       cur_hdr = 0;
+
+       /*
+        * Check to make sure file was compiled with -g.
+        * If not, warn the user of this limitation.
+        */
+       if (compare_glevel(max_glevel, GLEVEL_2) < 0) {
+               if (max_gdbinfo == 0)
+                       printf("\n%s not compiled with -g, debugging support is limited.", symfile);
+               printf("\nYou should compile with -g2 or -g3 for best debugging support.\n");
+               fflush(stdout);
+       }
+
+       /*
+        * Dont allow char * to have a typename (else would get
+        * caddr_t.)  
+        */
+       TYPE_NAME(lookup_pointer_type(builtin_type_char)) = 0;
+}
+
+\f
+/* Local utilities */
+
+
+/* Map of FDR indexes to partial symtabs */
+
+static struct pst_map {
+       struct partial_symtab *pst;     /* the psymtab proper */
+       int n_globals;                  /* globals it exports */
+} * fdr_to_pst;
+
+
+/* Utility stack, used to nest procedures and blocks properly.
+   It is a doubly linked list, to avoid too many alloc/free.
+   Since we might need it quite a few times it is NOT deallocated
+   after use. */
+
+static struct parse_stack {
+       struct parse_stack      *next, *prev;
+       struct symtab           *cur_st;        /* Current symtab */
+       struct block            *cur_block;     /* Block in it */
+       int                      blocktype;     /* What are we parsing */
+       int                      maxsyms;       /* Max symbols in this block */
+       struct type             *cur_type;      /* Type we parse fields for */
+       int                      procadr;       /* Start addres of this procedure */
+       int                      numargs;       /* Its argument count */
+} *top_stack;  /* Top stack ptr */
+
+
+/* Enter a new lexical context */
+
+static push_parse_stack()
+{
+       struct parse_stack *new;
+
+       /* Reuse frames if possible */
+       if (top_stack && top_stack->prev)
+               new = top_stack->prev;
+       else
+               new = (struct parse_stack *) xzalloc(sizeof(struct parse_stack));
+       /* Initialize new frame with previous content */
+       if (top_stack) {
+               register struct parse_stack *prev = new->prev;
+
+               *new = *top_stack;
+               top_stack->prev = new;
+               new->prev = prev;
+               new->next = top_stack;
+       }
+       top_stack = new;
+}
+
+/* Exit a lexical context */
+
+static pop_parse_stack()
+{
+       if (!top_stack)
+               return;
+       if (top_stack->next)
+               top_stack = top_stack->next;
+}
+
+
+/* Cross-references might be to things we haven't looked at
+   yet, e.g. type references.  To avoid too many type
+   duplications we keep a quick fixup table, an array
+   of lists of references indexed by file descriptor */
+
+static struct pending {
+       struct pending  *next;          /* link */
+       SYMR            *s;             /* the symbol */
+       struct type     *t;             /* its partial type descriptor */
+} **pending_list;
+
+
+/* Check whether we already saw symbol SH in file FH as undefined */
+
+static
+struct pending *is_pending_symbol(fh, sh)
+       FDR *fh;
+       SYMR *sh;
+{
+       int             f_idx = fh - (FDR *) cur_hdr->cbFdOffset;
+       register struct pending *p;
+
+       /* Linear search is ok, list is typically no more than 10 deep */
+       for (p = pending_list[f_idx]; p; p = p->next)
+               if (p->s == sh)
+                       break;
+       return p;
+}
+
+/* Check whether we already saw type T in file FH as undefined */
+
+static
+struct pending *is_pending_type(fh, t)
+       FDR *fh;
+       struct type *t;
+{
+       int             f_idx = fh - (FDR *) cur_hdr->cbFdOffset;
+       register struct pending *p;
+
+       for (p = pending_list[f_idx]; p; p = p->next)
+               if (p->t == t)
+                       break;
+       return p;
+}
+
+/* Add a new undef symbol SH of type T */
+
+static
+add_pending(fh, sh, t)
+       FDR *fh;
+       SYMR *sh;
+       struct type *t;
+{
+       int             f_idx = fh - (FDR *) cur_hdr->cbFdOffset;
+       struct pending *p = is_pending_symbol(fh, sh);
+
+       /* Make sure we do not make duplicates */
+       if (!p) {
+               p = (struct pending *) xmalloc(sizeof(*p));
+               p->s = sh;
+               p->t = t;
+               p->next = pending_list[f_idx];
+               pending_list[f_idx] = p;
+       }
+       sh->reserved = 1;       /* for quick check */
+}
+
+/* Throw away undef entries when done with file index F_IDX */
+
+static
+free_pending(f_idx)
+{
+       register struct pending *p, *q;
+
+       for (p = pending_list[f_idx]; p; p = q) {
+               q = p->next;
+               free(p);
+       }
+       pending_list[f_idx] = 0;
+}
+
+/* The number of args to a procedure is not explicit in the symtab,
+   this is the list of all those we know of.
+   This makes parsing more reasonable and avoids extra passes */
+
+static struct numarg {
+       struct numarg   *next;          /* link */
+       unsigned         adr;           /* procedure's start address */
+       unsigned         num;           /* arg count */
+} *numargs_list;
+
+/* Record that the procedure at ADR takes NUM arguments. */
+
+static
+got_numargs(adr,num)
+{
+       struct numarg  *n = (struct numarg *) xmalloc(sizeof(struct numarg));
+
+       n->adr = adr;
+       n->num = num;
+       n->next = numargs_list;
+       numargs_list = n;
+}
+
+/* See if we know how many arguments the procedure at ADR takes */
+
+static
+lookup_numargs(adr)
+{
+       struct numarg  *n = numargs_list;
+
+       while (n && n->adr != adr)
+               n = n->next;
+       return (n) ? n->num : -1;
+}
+
+/* Release storage when done with this file */
+
+static
+free_numargs()
+{
+       struct numarg  *n = numargs_list, *m;
+
+       while (n) {
+               m = n->next;
+               free(n);
+               n = m;
+       }
+       numargs_list = 0;
+}
+
+\f
+/* Parsing Routines proper. */
+
+/* Parse a single symbol. Mostly just make up a GDB symbol for it.
+   For blocks, procedures and types we open a new lexical context.
+   This is basically just a big switch on the symbol's type */
+
+static
+parse_symbol(sh, ax)
+       SYMR *sh;
+       AUXU *ax;
+{
+       struct symbol  *s;
+       struct block   *b;
+       struct type    *t;
+       struct field   *f;
+       /* When a symbol is cross-referenced from other files/symbols
+          we mark it explicitly */
+       int             pend = (sh->reserved == 1);
+       enum address_class class;
+
+       switch (sh->st) {
+
+           case stNil:
+               break;
+
+           case stGlobal:      /* external symbol, goes into the primary block */
+               class = LOC_STATIC;
+               b = BLOCKVECTOR_BLOCK(BLOCKVECTOR(top_stack->cur_st), 0);
+               goto data;
+
+           case stStatic:      /* static data, goes into the current block. */
+               class = LOC_STATIC;
+               b = top_stack->cur_block;
+               goto data;
+
+           case stLocal:       /* local variable, goes into the current block */
+               if (sh->sc == scRegister) {
+                       class = LOC_REGISTER;
+                       if (sh->value > 31)
+                               sh->value += 6;
+               } else
+                       class = LOC_LOCAL;
+               b = top_stack->cur_block;
+
+data:          /* Common code for symbols describing data */
+               s = new_symbol(sh->iss);
+               SYMBOL_NAMESPACE(s) = VAR_NAMESPACE;
+               SYMBOL_CLASS(s) = class;
+               add_symbol(s, b);
+
+               /* Type could be missing in a number of cases */
+               if (sh->sc == scUndefined || sh->sc == scNil ||
+                   sh->index == 0xfffff)
+                       SYMBOL_TYPE(s) = builtin_type_int;      /* undefined? */
+               else
+                       SYMBOL_TYPE(s) = parse_type(ax + sh->index, sh, 0);
+               /* Value of a data symbol is its memory address */
+               SYMBOL_VALUE(s) = sh->value;
+               break;
+
+           case stParam:       /* argument to procedure, goes into current block */
+               max_gdbinfo++;
+               top_stack->numargs++;
+               s = new_symbol(sh->iss);
+               SYMBOL_NAMESPACE(s) = VAR_NAMESPACE;
+               if (sh->sc == scRegister) {
+                       SYMBOL_CLASS(s) = LOC_REGPARM;
+                       if (sh->value > 31)
+                               sh->value += 6;
+               } else
+                       SYMBOL_CLASS(s) = LOC_ARG;
+               SYMBOL_VALUE(s) = sh->value;
+               SYMBOL_TYPE(s) = parse_type(ax + sh->index, sh, 0);
+               add_symbol(s, top_stack->cur_block);
+               break;
+
+           case stLabel:       /* label, we do make a symbol for it */
+               s = new_symbol(sh->iss);
+               SYMBOL_NAMESPACE(s) = VAR_NAMESPACE;    /* so that it can be used */
+               SYMBOL_CLASS(s) = LOC_LABEL;            /* but not misused */
+               SYMBOL_VALUE(s) = sh->value;
+               SYMBOL_TYPE(s) = builtin_type_int;
+               add_symbol(s, top_stack->cur_block);
+               break;
+
+           case stProc:        /* Procedure */
+           case stStaticProc:  /* Static procedure */
+               s = new_symbol(sh->iss);
+               SYMBOL_NAMESPACE(s) = VAR_NAMESPACE;
+               SYMBOL_CLASS(s) = LOC_BLOCK;
+               /* Type of the return value */
+               if (sh->sc == scUndefined || sh->sc == scNil)
+                       t = builtin_type_int;
+               else
+                       t = parse_type(ax + sh->index, sh, 0);
+               add_symbol(s, top_stack->cur_block);
+
+               /* Make a type for the procedure itself */
+               SYMBOL_TYPE(s) = lookup_function_type (t);
+
+               /* Create and enter a new lexical context */
+               b = new_block(top_stack->maxsyms);
+               SYMBOL_BLOCK_VALUE(s) = b;
+               BLOCK_FUNCTION(b) = s;
+               BLOCK_START(b) = BLOCK_END(b) = sh->value;
+               BLOCK_SUPERBLOCK(b) = top_stack->cur_block;
+               add_block(b, top_stack->cur_st);
+
+               /* Not if we only have partial info */
+               if (sh->sc == scUndefined || sh->sc == scNil)
+                       break;
+
+               push_parse_stack();
+               top_stack->cur_block = b;
+               top_stack->blocktype = sh->st;
+               top_stack->cur_type = SYMBOL_TYPE(s);
+               top_stack->procadr = sh->value;
+               top_stack->numargs = 0;
+
+               sh->value = (long) SYMBOL_TYPE(s);
+               break;
+
+           case stBlock:       /* Either a lexical block, or some type */
+               push_parse_stack();
+               top_stack->blocktype = stBlock;
+               if (sh->sc == scInfo) { /* structure/union/enum def */
+                       s = new_symbol(sh->iss);
+                       SYMBOL_NAMESPACE(s) = STRUCT_NAMESPACE;
+                       SYMBOL_CLASS(s) = LOC_TYPEDEF;
+                       SYMBOL_VALUE(s) = 0;
+                       add_symbol(s, top_stack->cur_block);
+                       /* If this type was expected, use its partial definition */
+                       if (pend) {
+                               t = is_pending_symbol(cur_fdr, sh)->t;
+                       } else {
+                               /* Uhmm, can`t decide yet. Smash later */
+                               t = new_type(sh->iss);
+                               TYPE_CODE(t) = TYPE_CODE_UNDEF;
+                               add_pending(cur_fdr, sh, t);
+                       }
+                       SYMBOL_TYPE(s) = t;
+                       /* make this the current type */
+                       top_stack->cur_type = t;
+                       TYPE_LENGTH(t) = sh->value;
+                       /* Mark that symbol has a type, and say which one */
+                       sh->value = (long) t;
+               } else {
+                       /* beginnning of (code) block. Value of symbol
+                          is the displacement from procedure start */
+                       b = new_block(top_stack->maxsyms);
+                       BLOCK_START(b) = sh->value + top_stack->procadr;
+                       BLOCK_SUPERBLOCK(b) = top_stack->cur_block;
+                       top_stack->cur_block = b;
+                       add_block(b, top_stack->cur_st);
+               }
+               break;
+
+           case stEnd:         /* end (of anything) */
+               if (sh->sc == scInfo) {
+                       /* Finished with type */
+                       top_stack->cur_type = 0;
+               } else if (sh->sc == scText &&
+                          (top_stack->blocktype == stProc ||
+                           top_stack->blocktype == stStaticProc)) {
+                   /* Finished with procedure */
+                   struct blockvector *bv = BLOCKVECTOR(top_stack->cur_st);
+                   struct block *b;
+                   int i;
+
+                   BLOCK_END(top_stack->cur_block) += sh->value; /* size */
+                   got_numargs(top_stack->procadr, top_stack->numargs);
+                   /* Reallocate symbols, saving memory */
+                   b = shrink_block(top_stack->cur_block, top_stack->cur_st);
+
+                   /* f77 emits proc-level with address bounds==[0,0],
+                      So look for such child blocks, and patch them.  */
+                   for (i = 0; i < BLOCKVECTOR_NBLOCKS(bv); i++) {
+                       struct block *b_bad = BLOCKVECTOR_BLOCK(bv,i);
+                       if (BLOCK_SUPERBLOCK(b_bad) == b
+                        && BLOCK_START(b_bad) == top_stack->procadr
+                        && BLOCK_END(b_bad) == top_stack->procadr) {
+                           BLOCK_START(b_bad) = BLOCK_START(b);
+                           BLOCK_END(b_bad) = BLOCK_END(b);
+                       }
+                   }
+               } else if (sh->sc == scText && top_stack->blocktype == stBlock) {
+                       /* End of (code) block. The value of the symbol
+                          is the displacement from the procedure`s start
+                          address of the end of this block. */
+                       BLOCK_END(top_stack->cur_block) = sh->value + top_stack->procadr;
+                       (void) shrink_block(top_stack->cur_block, top_stack->cur_st);
+               }
+               pop_parse_stack();      /* restore previous lexical context */
+               break;
+
+           case stMember:      /* member of struct/union/enum.. */
+               f = new_field(top_stack->cur_type, sh->iss);
+               f->bitpos = sh->value;
+               f->type = parse_type(ax + sh->index, sh, &f->bitsize);
+               break;
+
+           case stTypedef:     /* type definition */
+               s = new_symbol(sh->iss);
+               SYMBOL_NAMESPACE(s) = VAR_NAMESPACE;
+               SYMBOL_CLASS(s) = LOC_TYPEDEF;
+               SYMBOL_BLOCK_VALUE(s) = top_stack->cur_block;
+               add_symbol(s, top_stack->cur_block);                    
+               SYMBOL_TYPE(s) = parse_type(ax + sh->index, sh, 0);
+               sh->value = (long) SYMBOL_TYPE(s);
+               break;
+
+           case stFile:        /* file name */
+               push_parse_stack();
+               top_stack->blocktype = sh->st;
+               break;
+
+               /* I`ve never seen these for C */
+           case stRegReloc:
+               break;          /* register relocation */
+           case stForward:
+               break;          /* forwarding address */
+           case stConstant:
+               break;          /* constant */
+           default:
+               error("Unknown symbol type %x.", sh->st);
+       }
+       sh->st = stParsed;
+}
+
+/* Parse the type information provided in the AX entries for
+   the symbol SH. Return the bitfield size in BS, in case. */
+
+static struct type *parse_type(ax, sh, bs)
+       AUXU    *ax;
+       SYMR    *sh;
+       int     *bs;
+{
+       /* Null entries in this map are treated specially */
+       static struct type **map_bt[] =
+       {
+                &builtin_type_void,            /* btNil */
+                0,                             /* btAdr */
+                &builtin_type_char,            /* btChar */
+                &builtin_type_unsigned_char,   /* btUChar */
+                &builtin_type_short,           /* btShort */
+                &builtin_type_unsigned_short,  /* btUShort */
+                &builtin_type_int,             /* btInt */
+                &builtin_type_unsigned_int,    /* btUInt */
+                &builtin_type_long,            /* btLong */
+                &builtin_type_unsigned_long,   /* btULong */
+                &builtin_type_float,           /* btFloat */
+                &builtin_type_double,          /* btDouble */
+                0,                             /* btStruct */
+                0,                             /* btUnion */
+                0,                             /* btEnum */
+                0,                             /* btTypedef */
+                0,                             /* btRange */
+                0,                             /* btSet */
+                &builtin_type_complex,         /* btComplex */
+                &builtin_type_double_complex,  /* btDComplex */
+                0,                             /* btIndirect */
+                &builtin_type_fixed_dec,       /* btFixedDec */
+                &builtin_type_float_dec,       /* btFloatDec */
+                &builtin_type_string,          /* btString */
+                0,                             /* btBit */
+                0,                             /* btPicture */
+                &builtin_type_void,            /* btVoid */
+       };
+
+       TIR            *t;
+       struct type    *tp = 0, *tp1;
+       char           *fmt = "%s";
+
+       /* Procedures start off by one */
+       if (sh->st == stProc || sh->st == stStaticProc)
+               ax++;
+
+       /* Undefined ? Should not happen */
+       if (ax->rndx.rfd == 0xfff) {
+               return builtin_type_void;
+       }
+
+       /* Use aux as a type information record, map its basic type */
+       t = &ax->ti;
+       if (t->bt > 26 || t->bt == btPicture) {
+               printf_filtered("Internal: cannot map MIPS basic type x%x\n", t->bt);
+               return builtin_type_int;
+       }
+       if (map_bt[t->bt])
+               tp = *map_bt[t->bt];
+       else {
+               /* Cannot use builtin types, use templates */
+               tp = make_type(TYPE_CODE_VOID, 0, 0, 0);
+               switch (t->bt) {
+                   case btAdr:
+                       *tp = *builtin_type_ptr;
+                       break;
+                   case btStruct:
+                       *tp = *builtin_type_struct;
+                       fmt = "struct %s";
+                       break;
+                   case btUnion:
+                       *tp = *builtin_type_union;
+                       fmt = "union %s";
+                       break;
+                   case btEnum:
+                       *tp = *builtin_type_enum;
+                       fmt = "enum %s";
+                       break;
+                   case btRange:
+                       *tp = *builtin_type_range;
+                       break;
+                   case btSet:
+                       *tp = *builtin_type_set;
+                       fmt = "set %s";
+                       break;
+               }
+       }
+
+       /* Move on to next aux */
+       ax++;
+       if (t->continued) {
+               /* This is the way it would work if the compiler worked */
+               register TIR *t1 = t;
+               while (t1->continued)
+                       ax++;
+       }
+
+       /* For bitfields all we need is the width */
+       if (t->fBitfield) {
+               *bs = ax->width;
+               return tp;
+       }
+
+       /* All these types really point to some (common) MIPS type
+          definition, and only the type-qualifiers fully identify
+          them.  We`ll make the same effort at sharing */
+       if (t->bt == btIndirect ||
+           t->bt == btStruct ||
+           t->bt == btUnion ||
+           t->bt == btEnum ||
+           t->bt == btTypedef ||
+           t->bt == btRange ||
+           t->bt == btSet) {
+               char            name[256], *pn;
+
+               /* Try to cross reference this type */
+               tp1 = tp;
+               ax += cross_ref(ax, &tp1, &pn);
+               /* SOMEONE OUGHT TO FIX DBXREAD TO DROP "STRUCT" */
+               sprintf(name, fmt, pn);
+
+               /* reading .o file ? */
+               if (UNSAFE_DATA_ADDR(tp1))
+                       tp1 = tp;
+               if (TYPE_CODE(tp1) == TYPE_CODE_UNDEF) {
+                       /*
+                        * Type was incompletely defined, now we know.
+                        */
+                       TYPE_CODE(tp1) = TYPE_CODE(tp);
+                       TYPE_NAME(tp1) = obsavestring(name, strlen(name));
+                       if (TYPE_CODE(tp1) == TYPE_CODE_ENUM) {
+                               int             i;
+
+                               for (i = 0; i < TYPE_NFIELDS(tp1); i++)
+                                       make_enum_constant(&TYPE_FIELD(tp1,i), tp1);
+                       }
+               }
+               if (tp1 != tp) {
+                       /* found as cross ref, rid of our template */
+                       if ((TYPE_FLAGS(tp) & TYPE_FLAG_PERM) == 0)
+                               free(tp);
+                       tp = tp1;
+                       /* stupid idea of prepending "struct" to type names */
+                       if (t->bt == btStruct && !index(TYPE_NAME(tp), ' ')) {
+                               sprintf(name, fmt, TYPE_NAME(tp));
+                               TYPE_NAME(tp) = obsavestring(name, strlen(name));
+                       }
+               } else
+                       TYPE_NAME(tp) = savestring(name, strlen(name));
+       }
+
+       /* Deal with range types */
+       if (t->bt == btRange) {
+               struct field   *f;
+
+               f = new_field(tp, "Low");
+               f->bitpos = ax->dnLow;
+               ax++;
+               f = new_field(tp, "High");
+               f->bitpos = ax->dnHigh;
+               ax++;
+       }
+
+       /* Parse all the type qualifiers now. If there are more
+          than 6 the game will continue in the next aux */
+
+#define PARSE_TQ(tq) \
+       if (t->tq != tqNil) ax += upgrade_type(&tp, t->tq, ax, sh);
+
+again: PARSE_TQ(tq0);
+       PARSE_TQ(tq1);
+       PARSE_TQ(tq2);
+       PARSE_TQ(tq3);
+       PARSE_TQ(tq4);
+       PARSE_TQ(tq5);
+#undef PARSE_TQ
+
+       if (t->continued) {
+               t++;
+               goto again;
+       }
+       return tp;
+}
+
+/* Make up a complex type from a basic one.  Type is passed by
+   reference in TPP and side-effected as necessary. The type
+   qualifier TQ says how to handle the aux symbols at AX for
+   the symbol SX we are currently analyzing.
+   Returns the number of aux symbols we parsed. */
+
+static
+upgrade_type(tpp, tq, ax, sh)
+       struct type   **tpp;
+       AUXU           *ax;
+       SYMR           *sh;
+{
+       int             off = 0;
+       int             ret = 0;
+       struct type    *t;
+
+       if (tq == tqPtr) {
+               t = lookup_pointer_type (*tpp);
+       } else if (tq == tqProc) {
+               t = lookup_function_type (*tpp);
+       } else if (tq == tqArray) {
+               int             rf, id;
+               FDR            *fh;
+               struct field   *f;
+               SYMR            ss;
+
+               t = make_type(TYPE_CODE_ARRAY, 0, 0, 0);
+               TYPE_TARGET_TYPE(t) = *tpp;
+
+               /* Pointer to domain type (type of index) */
+               id = ax->rndx.index;
+               if ((rf = ax->rndx.rfd) == 0xfff)
+                       rf = (++ax)->isym, off++;
+
+               fh = get_rfd(cur_fd, rf);
+               f = new_field(t, 0);
+               bzero(&ss, sizeof ss);
+/* XXX */      f->type = parse_type(fh->iauxBase + id * sizeof(AUXU),
+                                    &ss, &f->bitsize);
+
+               /*
+                * This seems to be a pointer to the end of the Block defining
+                * the type.  Why it is here is magic for me, and I have no
+                * good use for it anyways.
+                */
+               if (off == 0) {
+                       off++;
+                       id = (++ax)->rndx.index;
+                       if ((rf = ax->rndx.rfd) == 0xfff)
+                               rf = (++ax)->isym, off++;
+               }
+               f->bitpos = (++ax)->dnLow;      /* ?? */
+               f->bitsize = (++ax)->dnHigh;    /* ?? */
+               rf = (++ax)->width - 1; /* bit alignment */
+               id = TYPE_LENGTH(TYPE_TARGET_TYPE(t)) << 3; /* bitsize */
+
+               if (id == 0) {
+                       /* Most likely an undefined type */
+                       id = rf + 1;
+                       TYPE_LENGTH(TYPE_TARGET_TYPE(t)) = id >> 3;
+               }
+               TYPE_LENGTH(t) = (f->bitsize < 0) ? 0 :
+                       (f->bitsize - f->bitpos + 1) * (id >> 3);
+               ret = 4 + off;
+       } else {
+               if (tq != tqVol)
+                       printf_filtered("Internal: unknown type qualifier %x\n", tq);
+               return ret;
+       }
+
+       *tpp = t;
+       return ret;
+}
+
+
+/* Parse a procedure descriptor record PR.  Note that the procedure
+   is parsed _after_ the local symbols, now we just make up the
+   extra information we need into a special symbol that we insert
+   in the procedure's main block.  Note also that images that
+   have been partially stripped (ld -x) have been deprived
+   of local symbols, and we have to cope with them here.
+   The procedure's code ends at BOUND */
+
+static
+parse_procedure(pr, bound)
+       PDR *pr;
+{
+       struct symbol *s, *i;
+       SYMR *sh = (SYMR*)pr->isym;
+       struct block *b;
+       struct mips_extra_func_info *e;
+       char name[100];
+       char *sh_name;
+
+       /* Reuse the MIPS record */
+       e = (struct mips_extra_func_info *) pr;
+       e->numargs = lookup_numargs(pr->adr);
+
+       /* Make up our special symbol */
+       i = new_symbol(".gdbinfo.");
+       SYMBOL_VALUE(i) = (int)e;
+       SYMBOL_NAMESPACE(i) = LABEL_NAMESPACE;
+       SYMBOL_CLASS(i) = LOC_CONST;
+       SYMBOL_TYPE(i) = builtin_type_void;
+
+       /* Make up a name for static procedures. Sigh. */
+       if (sh == (SYMR*)-1) {
+           sprintf(name,".static_procedure@%x",pr->adr);
+           sh_name = savestring(name, strlen(name));
+           s = NULL;
+       }
+       else {
+           sh_name = (char*)sh->iss;
+           s = mylookup_symbol(sh_name, top_stack->cur_block,
+                               VAR_NAMESPACE, LOC_BLOCK);
+       }
+       if (s != 0) {
+               b = SYMBOL_BLOCK_VALUE(s);
+       } else {
+               s = new_symbol(sh_name);
+               SYMBOL_NAMESPACE(s) = VAR_NAMESPACE;
+               SYMBOL_CLASS(s) = LOC_BLOCK;
+               /* Donno its type, hope int is ok */
+               SYMBOL_TYPE(s) = lookup_function_type (builtin_type_int);
+               add_symbol(s, top_stack->cur_block);
+               /* Wont have symbols for this one */
+               b = new_block(2);
+               SYMBOL_BLOCK_VALUE(s) = b;
+               BLOCK_FUNCTION(b) = s;
+               BLOCK_START(b) = pr->adr;
+               BLOCK_END(b) = bound;
+               BLOCK_SUPERBLOCK(b) = top_stack->cur_block;
+               add_block(b, top_stack->cur_st);
+       }
+       e->isym = (long)s;
+       add_symbol(i,b);
+}
+
+/* Parse the external symbol ES. Just call parse_symbol() after
+   making sure we know where the aux are for it. For procedures,
+   parsing of the PDRs has already provided all the needed
+   information, we only parse them if SKIP_PROCEDURES is false,
+   and only if this causes no symbol duplication */
+
+static
+parse_external(es, skip_procedures)
+       EXTR *es;
+{
+       AUXU *ax;
+
+       if (es->ifd != ifdNil) {
+               cur_fd = es->ifd;
+               cur_fdr = (FDR*)(cur_hdr->cbFdOffset) + cur_fd;
+               ax = (AUXU*)cur_fdr->iauxBase;
+       } else {
+               cur_fdr = (FDR*)(cur_hdr->cbFdOffset);
+               ax = 0;
+       }
+       top_stack->cur_st = cur_stab;
+       top_stack->cur_block = BLOCKVECTOR_BLOCK(BLOCKVECTOR(top_stack->cur_st),0);
+
+       /* Reading .o files */
+       if (es->asym.sc == scUndefined || es->asym.sc == scNil) {
+               char *what;
+               switch (es->asym.st) {
+               case stStaticProc:
+               case stProc:    what = "Procedure"; n_undef_procs++;  break;
+               case stGlobal:  what = "Variable";  n_undef_vars++;   break;
+               case stLabel:   what = "Label";     n_undef_labels++; break;
+               default :       what = "Symbol";                      break;
+               }
+               n_undef_symbols++;
+               if (info_verbose)
+                       printf_filtered("Warning: %s %s is undefined (in %s)\n", what,
+                               es->asym.iss, fdr_name(cur_fdr->rss));
+               return;
+       }
+
+       switch (es->asym.st) {
+       case stProc:
+               /* If we have full symbols we do not need more */
+               if (skip_procedures)
+                       return;
+               if (mylookup_symbol (es->asym.iss, top_stack->cur_block,
+                                       VAR_NAMESPACE, LOC_BLOCK))
+                       break;
+               /* fall through */
+       case stGlobal:
+       case stLabel:
+               /*
+                * Note that the case of a symbol with indexNil
+                * must be handled anyways by parse_symbol().
+                */
+               parse_symbol(&es->asym, ax);
+               break;
+       default:
+               break;
+       }
+}
+
+/* Parse the line number info for file descriptor FH into
+   GDB's linetable LT.  MIPS' encoding requires a little bit
+   of magic to get things out.  Note also that MIPS' line
+   numbers can go back and forth, apparently we can live
+   with that and do not need to reorder our linetables */
+
+static
+parse_lines(fh, lt)
+       FDR *fh;
+       struct linetable *lt;
+{
+       char *base = (char*)fh->cbLineOffset;
+       int i, j, k;
+       int delta, count, lineno = 0;
+       PDR *pr;
+
+       if (base == 0)
+               return;
+
+       /* Scan by procedure descriptors */
+       i = 0; j = 0, k = 0;
+       for (pr = (PDR*)IPDFIRST(cur_hdr,fh); j < fh->cpd; j++, pr++) {
+               int l, halt;
+
+               /* No code for this one */
+               if (pr->iline == ilineNil ||
+                   pr->lnLow == -1 || pr->lnHigh == -1)
+                       continue;
+               /*
+                *      Aurgh! To know where to stop expanding we
+                *      must look-ahead.
+                */
+               for (l = 1; l < (fh->cpd - j); l++)
+                       if (pr[l].iline != -1)
+                               break;
+               if (l == (fh->cpd - j))
+                       halt = fh->cline;
+               else
+                       halt = pr[l].iline;
+               /*
+                * When procedures are moved around the linenumbers
+                * are attributed to the next procedure up
+                */
+               if (pr->iline >= halt) continue;
+
+               base = (char*)pr->cbLineOffset;
+               l = pr->adr >> 2;       /* in words */
+               halt += (pr->adr >> 2) - pr->iline;
+               for (lineno = pr->lnLow; l < halt;) {
+                       count = *base & 0x0f;
+                       delta = *base++ >> 4;
+                       if (delta == -8) {
+                               delta = (base[0] << 8) | (base[1] & 0xff);
+                               base += 2;
+                       }
+                       lineno += delta;/* first delta is 0 */
+                       k = add_line(lt, lineno, l, k);
+                       l += count + 1;
+               }
+       }
+}
+
+
+/* Parse the symbols of the file described by FH, whose index is F_IDX.
+   BOUND is the highest core address of this file's procedures */
+
+static
+parse_one_file(fh, f_idx, bound)
+       FDR *fh;
+{
+       register int s_idx;
+       SYMR *sh;
+       PDR *pr;
+
+       /* Parse local symbols first */
+
+       for (s_idx = 0; s_idx < fh->csym; s_idx++) {
+               sh = (SYMR *) (fh->isymBase) + s_idx;
+               cur_sdx = s_idx;
+               parse_symbol(sh, fh->iauxBase);
+       }
+
+       /* Procedures next, note we need to look-ahead to
+          find out where the procedure's code ends */
+
+       for (s_idx = 0; s_idx < fh->cpd-1; s_idx++) {
+               pr = (PDR *) (IPDFIRST(cur_hdr, fh)) + s_idx;
+               parse_procedure(pr, pr[1].adr); /* next proc up */
+       }
+       if (fh->cpd) {
+               pr = (PDR *) (IPDFIRST(cur_hdr, fh)) + s_idx;
+               parse_procedure(pr, bound);     /* next file up */
+       }
+
+       /* Linenumbers. At the end, check if we can save memory */
+       parse_lines(fh, LINETABLE(cur_stab));
+       if (LINETABLE(cur_stab)->nitems < fh->cline)
+               shrink_linetable(cur_stab);
+}
+
+
+/* Master parsing procedure. Parses the symtab described by the
+   symbolic header HDR.  If INCREMENTAL is true we are called
+   by add-file and must preserve the old symtabs */
+static
+parse_partial_symbols(hdr, incremental)
+       HDRR *hdr;
+{
+       int             f_idx, s_idx, h_max;
+       CORE_ADDR       dummy, *prevhigh;
+       /* Running pointers */
+       FDR            *fh;
+       RFDT           *rh;
+       register EXTR           *esh;
+
+       /*
+        * Big plan: 
+        *
+        * Only parse the External symbols, and the Relative FDR.
+        * Fixup enough of the loader symtab to be able to use it.
+        * Allocate space only for the file`s portions we need to
+        * look at. (XXX)
+        */
+
+       cur_hdr = hdr;
+       max_gdbinfo = 0;
+       max_glevel = MIN_GLEVEL;
+
+       /* Allocate the map FDR -> PST.
+          Minor hack: -O3 images might claim some global data belongs
+          to FDR -1. We`ll go along with that */
+       fdr_to_pst = (struct pst_map *)xzalloc((hdr->ifdMax+1) * sizeof *fdr_to_pst);
+       fdr_to_pst++;
+       {
+               struct partial_symtab * pst = new_psymtab("");
+               fdr_to_pst[-1].pst = pst;
+               pst->ldsymoff = -1;
+       }
+
+       /* Now scan the FDRs, mostly for dependencies */
+       for (f_idx = 0; f_idx < hdr->ifdMax; f_idx++)
+               (void) parse_fdr(f_idx, 1);
+
+       /* Take a good guess at how many symbols we might ever need */
+       h_max = hdr->iextMax;
+
+       /* Parse externals: two passes because they can be ordered
+          in any way */
+
+       /* Pass 1: Presize and partition the list */
+       for (s_idx = 0; s_idx < hdr->iextMax; s_idx++) {
+               esh = (EXTR *) (hdr->cbExtOffset) + s_idx;
+               fdr_to_pst[esh->ifd].n_globals++;
+       }
+
+       if (global_psymbols.list) {
+               global_psymbols.list = (struct partial_symbol *)
+                       xrealloc( global_psymbols.list, (h_max +
+                               global_psymbols.size) * sizeof(struct partial_symbol));
+               global_psymbols.next = global_psymbols.list + global_psymbols.size;
+               global_psymbols.size += h_max;
+       } else {
+               global_psymbols.list = (struct partial_symbol *)
+                               xmalloc( h_max * sizeof(struct partial_symbol));
+               global_psymbols.size = h_max;
+               global_psymbols.next = global_psymbols.list;
+       }
+
+       s_idx = global_psymbols.next - global_psymbols.list;
+       for (f_idx = -1; f_idx < hdr->ifdMax; f_idx++) {
+               fdr_to_pst[f_idx].pst->globals_offset = s_idx;
+               s_idx += fdr_to_pst[f_idx].n_globals;
+       }
+
+       /* Pass 2: fill in symbols */
+       for (s_idx = 0; s_idx < hdr->iextMax; s_idx++) {
+               register struct partial_symbol *p;
+               enum misc_function_type misc_type = mf_text;
+               esh = (EXTR *) (hdr->cbExtOffset) + s_idx;
+
+               if (esh->asym.sc == scUndefined || esh->asym.sc == scNil)
+                       continue;
+               p = new_psymbol(&global_psymbols, esh->asym.iss, esh->ifd);
+               SYMBOL_VALUE(p) = esh->asym.value;
+               SYMBOL_NAMESPACE(p) = VAR_NAMESPACE;
+
+               switch (esh->asym.st) {
+               case stProc:
+                       SYMBOL_CLASS(p) = LOC_BLOCK;
+                       break;
+               case stGlobal:
+                       SYMBOL_CLASS(p) = LOC_STATIC;
+                       misc_type = mf_data;
+                       break;
+               case stLabel:
+                       SYMBOL_CLASS(p) = LOC_LABEL;
+                       break;
+               default:
+                       misc_type = mf_unknown;
+                       complain (&unknown_ext_complaint, SYMBOL_NAME(p));
+               }
+               prim_record_misc_function (SYMBOL_NAME(p),
+                                          SYMBOL_VALUE(p),
+                                          misc_type);
+       }
+
+
+       /* The array (of lists) of globals must be sorted.
+          Take care, since we are at it, of pst->texthigh.
+
+          NOTE: The way we handle textlow/high is incorrect, but good
+          enough for a first approximation. The case we fail is on a
+          file "foo.c" that looks like
+               proc1() {...}
+               #include "bar.c"        -- this contains proc2()
+               proc3() {...}
+          where proc3() is attributed to bar.c.  But since this is a
+          dependent file it will cause loading of foo.c as well, so
+          everything will be fine at the end.  */
+
+       prevhigh = &dummy;
+       for (f_idx = 0; f_idx < hdr->ifdMax; f_idx++) {
+               struct partial_symtab *pst = fdr_to_pst[f_idx].pst;
+               if (pst->n_global_syms > 1)
+                       qsort (global_psymbols.list + pst->globals_offset,
+                               pst->n_global_syms, sizeof (struct partial_symbol),
+                               compare_psymbols);
+               if (pst->textlow) {
+                       *prevhigh = pst->textlow;
+                       prevhigh = &pst->texthigh;
+               }
+       }
+
+       /* Mark the last code address, and remember it for later */
+       *prevhigh = END_OF_TEXT_SEGMENT(filhdr);
+       hdr->cbDnOffset = END_OF_TEXT_SEGMENT(filhdr);
+
+       reorder_psymtabs();
+       free(&fdr_to_pst[-1]);
+       fdr_to_pst = 0;
+}
+
+
+/* Do the initial analisys of the F_IDX-th file descriptor.
+   Allocates a partial symtab for it, and builds the list
+   of dependent files by recursion. LEV says at which level
+   of recursion we are called (to pretty up debug traces) */
+
+static struct partial_symtab *
+parse_fdr(f_idx, lev)
+       int f_idx;
+{
+       register FDR *fh;
+       register struct partial_symtab *pst;
+       int s_idx, s_id0;
+
+       fh = (FDR *) (cur_hdr->cbFdOffset) + f_idx;
+
+       /* Use this to indicate into which symtab this file was parsed */
+       if (fh->ioptBase)
+               return (struct partial_symtab *) fh->ioptBase;
+
+       /* Debuggability level */
+       if (compare_glevel(max_glevel, fh->glevel) < 0)
+               max_glevel = fh->glevel;
+
+       /* Make a new partial_symtab */
+       pst = new_psymtab(fh->rss);
+       if (fh->cpd == 0){
+               pst->textlow = 0;
+               pst->texthigh = 0;
+       } else {
+               pst->textlow = fh->adr;
+               pst->texthigh = fh->cpd;        /* To be fixed later */
+       }
+       /* Reverse mapping PST -> FDR */
+       pst->ldsymoff = f_idx;
+
+       fdr_to_pst[f_idx].pst = pst;
+       fh->ioptBase = (int)pst;
+
+       /* Analyze its dependencies */
+       if (fh->crfd <= 1)
+               return pst;
+
+       s_id0 = 0;
+       if (fh->cpd == 0) {  /* If there are no functions defined here ... */
+               /* ...then presumably a .h file: drop reverse depends .h->.c */
+               for (; s_id0 < fh->crfd; s_id0++) {
+                       RFDT *rh = (RFDT *) (fh->rfdBase) + s_id0;
+                       if (*rh == f_idx) {
+                               s_id0++;        /* Skip self-dependency */
+                               break;
+                       }
+               }
+       }
+       pst->number_of_dependencies = fh->crfd - s_id0;
+       pst->dependencies = (struct partial_symtab **)
+               obstack_alloc (psymbol_obstack,
+                              pst->number_of_dependencies * sizeof(char*));
+       for (s_idx = s_id0; s_idx < fh->crfd; s_idx++) {
+               RFDT *rh = (RFDT *) (fh->rfdBase) + s_idx;
+
+               pst->dependencies[s_idx-s_id0] = parse_fdr(*rh, lev+1);
+
+       }
+
+       return pst;
+}
+
+
+/* Ancillary function to psymtab_to_symtab().  Does all the work
+   for turning the partial symtab PST into a symtab, recurring
+   first on all dependent psymtabs */
+
+static void psymtab_to_symtab_1(pst)
+       struct partial_symtab *pst;
+{
+       int             i, f_max;
+       struct symtab  *st;
+       FDR *fh;
+
+       if (pst->readin)
+               return;
+       pst->readin = 1;
+
+       pending_list = (struct pending **) cur_hdr->cbOptOffset;
+       if (pending_list == 0) {
+               pending_list = (struct pending **)
+                       xzalloc(cur_hdr->ifdMax * sizeof(struct pending *));
+               cur_hdr->cbOptOffset = (int)pending_list;
+       }
+
+       /* How many symbols will we need */
+       f_max = pst->n_global_syms + pst->n_static_syms;
+       if (pst->ldsymoff == -1) {
+               fh = 0;
+               st = new_symtab( "unknown", f_max, 0);
+       } else {
+               fh = (FDR *) (cur_hdr->cbFdOffset) + pst->ldsymoff;
+               f_max += fh->csym + fh->cpd;
+               st = new_symtab(pst->filename, 2 * f_max, 2 * fh->cline);
+       }
+
+       /*
+        * Read in all partial symbtabs on which this one is dependent.
+        * NOTE that we do have circular dependencies, sigh. 
+        */
+       for (i = 0; i < pst->number_of_dependencies; i++)
+               if (!pst->dependencies[i]->readin) {
+                       /*
+                        * DO NOT inform about additional files that need to
+                        * be read in, it would only annoy the user.
+                        */
+                       psymtab_to_symtab_1(pst->dependencies[i]);
+               }
+
+       /* Now read the symbols for this symtab */
+
+       cur_fd = pst->ldsymoff;
+       cur_fdr = fh;
+       cur_stab = st;
+
+       /* Get a new lexical context */
+
+       push_parse_stack();
+       top_stack->cur_st = cur_stab;
+       top_stack->cur_block = BLOCKVECTOR_BLOCK(BLOCKVECTOR(cur_stab), 0);
+       BLOCK_START(top_stack->cur_block) = fh ? fh->adr : 0;
+       BLOCK_END(top_stack->cur_block) = 0;
+       top_stack->blocktype = stFile;
+       top_stack->maxsyms = f_max;
+       top_stack->cur_type = 0;
+       top_stack->procadr = 0;
+       top_stack->numargs = 0;
+
+       /* Parse locals and procedures */
+       if (fh)
+               parse_one_file(fh, cur_fd, (cur_fd == (cur_hdr->ifdMax - 1)) ?
+                               cur_hdr->cbDnOffset : fh[1].adr);
+
+       /* .. and our share of externals.
+          XXX use the global list to speed up things here. how ? */
+       top_stack->blocktype = stFile;
+       top_stack->maxsyms = cur_hdr->isymMax + cur_hdr->ipdMax + cur_hdr->iextMax;
+       for (i = 0; i < cur_hdr->iextMax; i++) {
+               register EXTR *esh = (EXTR *) (cur_hdr->cbExtOffset) + i;
+               if (esh->ifd == cur_fd)
+                       parse_external(esh, 1);
+       }
+
+       /* If there are undefined, tell the user */
+       if (n_undef_symbols) {
+               printf_filtered("File %s contains %d unresolved references:",
+                               st->filename, n_undef_symbols);
+               printf_filtered("\n\t%4d variables\n\t%4d procedures\n\t%4d labels\n",
+                               n_undef_vars, n_undef_procs, n_undef_labels);
+               n_undef_symbols = n_undef_labels = n_undef_vars = n_undef_procs = 0;
+       }
+
+       pop_parse_stack();
+
+       /*
+        * Sort the symbol table now, we are done adding symbols to it.
+        */
+       sort_symtab_syms(st);
+}
+
+
+
+\f
+/* Ancillary parsing procedures. */
+
+/* Lookup the type at relative index RN.  Return it in TPP
+   if found and in any event come up with its name PNAME.
+   Return value says how many aux symbols we ate */
+
+static
+cross_ref(rn, tpp, pname)
+       RNDXR *rn;
+       struct type **tpp;
+       char **pname;
+{
+       unsigned        rf;
+
+       /* Escape index means 'the next one' */
+       if (rn->rfd == 0xfff)
+               rf = *(unsigned *) (rn + 1);
+       else
+               rf = rn->rfd;
+
+       if (rf == -1) {
+               /* Ooops */
+               *pname = "<undefined>";
+       } else {
+               /*
+                * Find the relative file descriptor and the symbol in it 
+                */
+               FDR            *fh = get_rfd(cur_fd, rf);
+               SYMR           *sh;
+               struct type    *t;
+
+               /*
+                * If we have processed this symbol then we left a forwarding
+                * pointer to the corresponding GDB symbol.  If not, we`ll put
+                * it in a list of pending symbols, to be processed later when
+                * the file f will be.  In any event, we collect the name for
+                * the type here. Which is why we made a first pass at
+                * strings. 
+                */
+               sh = (SYMR *) (fh->isymBase) + rn->index;
+
+               /* Careful, we might be looking at .o files */
+               *pname = (UNSAFE_DATA_ADDR(sh->iss)) ? "<undefined>" :
+                       (char *) sh->iss;
+
+               /* Have we parsed it ? */
+               if ((!UNSAFE_DATA_ADDR(sh->value)) && (sh->st == stParsed)) {
+                       t = (struct type *) sh->value;
+                       *tpp = t;
+               } else {
+                       struct pending *p;
+
+                       /* Avoid duplicates */
+                       p = is_pending_symbol(fh, sh);
+
+                       if (p)
+                               *tpp = p->t;
+                       else
+                               add_pending(fh, sh, *tpp);
+               }
+       }
+       return (rn->rfd == 0xfff);
+}
+
+
+/* Quick&dirty lookup procedure, to avoid the MI ones that require
+   keeping the symtab sorted */
+
+static struct symbol *
+mylookup_symbol (name, block, namespace, class)
+     char *name;
+     register struct block *block;
+     enum namespace namespace;
+     enum address_class class;
+{
+       register int    bot, top, inc;
+       register struct symbol *sym;
+
+       bot = 0;
+       top = BLOCK_NSYMS(block);
+       inc = name[0];
+       while (bot < top) {
+               sym = BLOCK_SYM(block, bot);
+               if (SYMBOL_NAME(sym)[0] == inc
+                   && SYMBOL_NAMESPACE(sym) == namespace
+                   && SYMBOL_CLASS(sym) == class
+                   && !strcmp(SYMBOL_NAME(sym), name))
+                       return sym;
+               bot++;
+       }
+       if (block = BLOCK_SUPERBLOCK (block))
+               return mylookup_symbol (name, block, namespace, class);
+       return 0;
+}
+
+
+/* Add a new symbol S to a block B */
+
+static
+add_symbol(s,b)
+       struct symbol *s;
+       struct block *b;
+{
+       BLOCK_SYM(b,BLOCK_NSYMS(b)++) = s;
+       if (b == top_stack->cur_block &&
+           BLOCK_NSYMS(b) > top_stack->maxsyms)
+               printf_filtered("Internal: block at @%x overfilled (by %d)\n",
+                       b, BLOCK_NSYMS(b) - top_stack->maxsyms);
+}
+
+/* Add a new block B to a symtab S */
+
+static
+add_block(b,s)
+       struct block *b;
+       struct symtab *s;
+{
+       struct blockvector *bv = BLOCKVECTOR(s);
+
+       bv = (struct blockvector *)xrealloc(bv, sizeof(struct blockvector) +
+                                           BLOCKVECTOR_NBLOCKS(bv) * sizeof(bv->block));
+       if (bv != BLOCKVECTOR(s))
+               BLOCKVECTOR(s) = bv;
+
+       BLOCKVECTOR_BLOCK(bv, BLOCKVECTOR_NBLOCKS(bv)++) = b;
+}
+
+/* Add a new linenumber entry (LINENO,ADR) to a linevector LT.
+   MIPS' linenumber encoding might need more than one byte
+   to describe it, LAST is used to detect these continuation lines */
+
+static 
+add_line(lt, lineno, adr, last)
+       struct linetable *lt;
+       CORE_ADDR adr;
+{
+       if (last == 0)
+               last = -2;      /* make sure we record first line */
+
+       if (last == lineno)     /* skip continuation lines */
+               return lineno;
+
+       lt->item[lt->nitems].line = lineno;
+       lt->item[lt->nitems++].pc = adr << 2;
+       return lineno;
+}
+
+
+\f
+/* Comparison functions, used when sorting things */
+
+/*  Symtabs must be ordered viz the code segments they cover */
+
+static int
+compare_symtabs( s1, s2)
+       struct symtab **s1, **s2;
+{
+       /* "most specific" first */
+
+       register struct block *b1, *b2;
+       b1 = BLOCKVECTOR_BLOCK(BLOCKVECTOR(*s1),0);
+       b2 = BLOCKVECTOR_BLOCK(BLOCKVECTOR(*s2),0);
+       if (BLOCK_END(b1) == BLOCK_END(b2))
+               return BLOCK_START(b1) - BLOCK_START(b2);
+       return BLOCK_END(b1) - BLOCK_END(b2);
+}
+
+
+/*  Partial Symtabs, same */
+
+static int
+compare_psymtabs( s1, s2)
+       struct partial_symtab **s1, **s2;
+{
+       /* Perf twist: put the ones with no code at the end */
+
+       register int a = (*s1)->textlow;
+       register int b = (*s2)->textlow;
+       if (a == 0)
+               return b;
+       if (b == 0)
+               return -a;
+       return a - b;
+}
+
+
+/* Partial symbols are compared lexicog by their print names */
+
+static int
+compare_psymbols (s1, s2)
+       register struct partial_symbol *s1, *s2;
+{
+       register char
+                      *st1 = SYMBOL_NAME(s1),
+                      *st2 = SYMBOL_NAME(s2);
+
+       return (st1[0] - st2[0] ? st1[0] - st2[0] :
+               strcmp(st1 + 1, st2 + 1));
+}
+
+/* Blocks with a smaller low bound should come first */
+
+static int compare_blocks(b1,b2)
+       struct block **b1, **b2;
+{
+       register int addr_diff;
+
+       addr_diff = (BLOCK_START((*b1))) - (BLOCK_START((*b2)));
+       if (addr_diff == 0)
+               return (BLOCK_END((*b1))) - (BLOCK_END((*b2)));
+       return addr_diff;
+}
+
+\f
+/* Sorting and reordering procedures */
+
+/* Sort the blocks of a symtab S.
+   Reorder the blocks in the blockvector by code-address,
+   as required by some MI search routines */
+
+static
+sort_blocks(s)
+       struct symtab *s;
+{
+       struct blockvector *bv = BLOCKVECTOR(s);
+
+       if (BLOCKVECTOR_NBLOCKS(bv) <= 2) {
+               /* Cosmetic */
+               if (BLOCK_END(BLOCKVECTOR_BLOCK(bv,0)) == 0)
+                       BLOCK_START(BLOCKVECTOR_BLOCK(bv,0)) = 0;
+               return;
+       }
+       /*
+        * This is very unfortunate: normally all functions are compiled in
+        * the order they are found, but if the file is compiled -O3 things
+        * are very different.  It would be nice to find a reliable test
+        * to detect -O3 images in advance.
+        */
+       if (BLOCKVECTOR_NBLOCKS(bv) > 3)
+               qsort(&BLOCKVECTOR_BLOCK(bv,2),
+                     BLOCKVECTOR_NBLOCKS(bv) - 2,
+                     sizeof(struct block *),
+                     compare_blocks);
+
+       {
+               register CORE_ADDR high = 0;
+               register int    i, j = BLOCKVECTOR_NBLOCKS(bv);
+
+               for (i = 2; i < j; i++)
+                       if (high < BLOCK_END(BLOCKVECTOR_BLOCK(bv,i)))
+                               high = BLOCK_END(BLOCKVECTOR_BLOCK(bv,i));
+               BLOCK_END(BLOCKVECTOR_BLOCK(bv,0)) = high;
+       }
+
+       BLOCK_START(BLOCKVECTOR_BLOCK(bv,0)) = BLOCK_START(BLOCKVECTOR_BLOCK(bv,2));
+
+       BLOCK_START(BLOCKVECTOR_BLOCK(bv,1)) = BLOCK_START(BLOCKVECTOR_BLOCK(bv,0));
+       BLOCK_END  (BLOCKVECTOR_BLOCK(bv,1)) = BLOCK_END  (BLOCKVECTOR_BLOCK(bv,0));
+}
+
+/* Sort the symtab list, as required by some search procedures.
+   We want files ordered to make them look right to users, and for
+   searching (see block_for_pc).  */
+
+static
+reorder_symtabs()
+{
+       register int i;
+       struct symtab *stab;
+       struct symtab **all_symtabs = (struct symtab **)
+               obstack_alloc (psymbol_obstack,
+                               all_symtabs_count * sizeof (struct symtab *));
+
+       /* Create an array of pointers to all the symtabs.  */
+       for (i = 0, stab = symtab_list;
+            i < all_symtabs_count;
+            i++, stab = stab->next) {
+               all_symtabs[i] = stab;
+               /* FIXME: Only do this for new symtabs ??? */
+               sort_blocks(all_symtabs[i]);
+       }
+
+       qsort(all_symtabs, all_symtabs_count,
+               sizeof(struct symtab *), compare_symtabs);
+
+       /* Re-construct the symtab list, but now it is sorted.  */
+       for (i = 0; i < all_symtabs_count-1; i++)
+               all_symtabs[i]->next = all_symtabs[i+1];
+       all_symtabs[i]->next = 0;
+       symtab_list = all_symtabs[0];
+       obstack_free (psymbol_obstack, all_symtabs);
+}
+
+/* Sort the partial symtab list, as required by some search procedures */
+
+static reorder_psymtabs()
+{
+       register int i;
+       struct partial_symtab *pstab;
+
+       /*
+        * PC lookups stop at the first psymtab such that
+        *      textlow <= PC < texthigh 
+        */
+       /* Create an array of pointers to all the partial_symtabs.  */
+       struct partial_symtab **all_psymtabs = (struct partial_symtab **)
+         obstack_alloc (psymbol_obstack,
+                        all_psymtabs_count*sizeof(struct partial_symtab*));
+       for (i = 0, pstab = partial_symtab_list;
+            i < all_psymtabs_count;
+            i++, pstab = pstab->next)
+         all_psymtabs[i] = pstab;
+
+       qsort(all_psymtabs, all_psymtabs_count,
+               sizeof(struct partial_symtab *), compare_psymtabs);
+
+       /* Re-construct the partial_symtab_list, but now it is sorted.  */
+
+       for (i = 0; i < all_psymtabs_count-1; i++)
+               all_psymtabs[i]->next = all_psymtabs[i+1];
+       all_psymtabs[i]->next = 0;
+       partial_symtab_list = all_psymtabs[0];
+
+       obstack_free (psymbol_obstack, all_psymtabs);
+}
+
+
+\f
+/* Constructor/restructor/destructor procedures */
+
+/* Allocate a new symtab for NAME.  Needs an estimate of how many symbols
+   MAXSYMS and linenumbers MAXLINES we'll put in it */
+
+static
+struct symtab *
+new_symtab(name, maxsyms, maxlines)
+       char *name;
+{
+       struct symtab *s = (struct symtab *) xzalloc(sizeof(struct symtab));
+       int i;
+
+       LINETABLE(s) = new_linetable(maxlines);
+
+       s->filename = name;
+
+       /* All symtabs must have at least two blocks */
+       BLOCKVECTOR(s) = new_bvect(2);
+       BLOCKVECTOR_BLOCK(BLOCKVECTOR(s), 0) = new_block(maxsyms);
+       BLOCKVECTOR_BLOCK(BLOCKVECTOR(s), 1) = new_block(maxsyms);
+       BLOCK_SUPERBLOCK( BLOCKVECTOR_BLOCK(BLOCKVECTOR(s),1)) =
+               BLOCKVECTOR_BLOCK(BLOCKVECTOR(s), 0);
+
+       s->free_code = free_linetable;
+
+       /* Link the new symtab into the list of such.  */
+       s->next = symtab_list;
+       symtab_list = s;
+
+       all_symtabs_count++;
+
+       return s;
+}
+
+/* Cleanup before loading a fresh image */
+
+static destroy_all_symtabs()
+{
+  if (symfile)
+    free(symfile);
+  symfile = 0;
+
+  free_all_symtabs();
+  all_symtabs_count = 0;
+  current_source_symtab = 0;
+  /* psymtabs! */
+}
+
+/* Allocate a new partial_symtab NAME */
+
+static struct partial_symtab *
+new_psymtab(name)
+       char *name;
+{
+       struct partial_symtab *pst;
+
+       pst = (struct partial_symtab *)
+             obstack_alloc (psymbol_obstack, sizeof (*pst));
+       bzero (pst, sizeof (*pst));
+
+       if (name == (char*)-1)          /* FIXME -- why not null here? */
+               pst->filename = "<no name>";
+       else
+               pst->filename = name;
+
+       pst->next = partial_symtab_list;
+       partial_symtab_list = pst;
+       all_psymtabs_count++;
+
+       /* Keep a backpointer to the file`s symbols */
+       pst->ldsymlen = (int)cur_hdr;
+
+       /* The way to turn this into a symtab is to call... */
+       pst->read_symtab = mipscoff_psymtab_to_symtab;
+
+       return pst;
+}
+
+
+/* Allocate a new NAME psymbol from LIST, extending it if necessary.
+   The psymbol belongs to the psymtab at index PST_IDX */
+
+static struct partial_symbol *
+new_psymbol(list, name, pst_idx)
+       struct psymbol_allocation_list *list;
+       char *name;
+{
+       struct partial_symbol *p;
+       struct partial_symtab *pst = fdr_to_pst[pst_idx].pst;
+
+       /* Lists are pre-sized, we won`t overflow */
+
+       p = list->list + pst->globals_offset + pst->n_global_syms++;
+       SYMBOL_NAME(p) = name;
+       return p;
+}
+
+
+/* Allocate a linetable array of the given SIZE */
+
+static
+struct linetable *new_linetable(size)
+{
+       struct linetable *l;
+
+       size = size * sizeof(l->item) + sizeof(struct linetable);
+       l = (struct linetable *)xmalloc(size);
+       l->nitems = 0;
+       return l;
+}
+
+/* Oops, too big. Shrink it.  This was important with the 2.4 linetables,
+   I am not so sure about the 3.4 ones */
+
+static shrink_linetable(s)
+       struct symtab *s;
+{
+       struct linetable *l = new_linetable(LINETABLE(s)->nitems);
+
+       bcopy(LINETABLE(s), l,
+             LINETABLE(s)->nitems * sizeof(l->item) + sizeof(struct linetable));
+       free (LINETABLE(s));
+       LINETABLE(s) = l;
+}
+
+/* Allocate and zero a new blockvector of NBLOCKS blocks. */
+
+static
+struct blockvector *new_bvect(nblocks)
+{
+       struct blockvector *bv;
+       int size;
+
+       size = sizeof(struct blockvector) + nblocks * sizeof(struct block*);
+       bv = (struct blockvector *) xzalloc(size);
+
+       BLOCKVECTOR_NBLOCKS(bv) = nblocks;
+
+       return bv;
+}
+
+/* Allocate and zero a new block of MAXSYMS symbols */
+
+static
+struct block *new_block(maxsyms)
+{
+       int size = sizeof(struct block) + (maxsyms-1) * sizeof(struct symbol *);
+       struct block *b = (struct block *)xzalloc(size);
+
+       return b;
+}
+
+/* Ooops, too big. Shrink block B in symtab S to its minimal size */
+
+static struct block *
+shrink_block(b, s)
+       struct block *b;
+       struct symtab *s;
+{
+       struct block *new;
+       struct blockvector *bv = BLOCKVECTOR(s);
+       int i;
+
+       /* Just get a new one, copy, and fix references to the old one */
+
+       new = (struct block *)xmalloc(sizeof(struct block) +
+               (BLOCK_NSYMS(b)-1) * sizeof(struct symbol *));
+
+       bcopy(b, new, sizeof(*new) + (BLOCK_NSYMS(b) - 1) * sizeof(struct symbol*));
+
+       /* Should chase pointers to old one.  Fortunately, that`s just
+          the block`s function and inferior blocks */
+       if (BLOCK_FUNCTION(b) && SYMBOL_BLOCK_VALUE(BLOCK_FUNCTION(b)) == b)
+               SYMBOL_BLOCK_VALUE(BLOCK_FUNCTION(b)) = new;
+       for (i = 0; i < BLOCKVECTOR_NBLOCKS(bv); i++)
+               if (BLOCKVECTOR_BLOCK(bv,i) == b)
+                       BLOCKVECTOR_BLOCK(bv,i) = new;
+               else if (BLOCK_SUPERBLOCK(BLOCKVECTOR_BLOCK(bv,i)) == b)
+                       BLOCK_SUPERBLOCK(BLOCKVECTOR_BLOCK(bv,i)) = new;
+       free(b);
+       return new;
+}
+
+/* Create a new symbol with printname NAME */
+
+static
+struct symbol *
+new_symbol(name)
+       char *name;
+{
+       struct symbol *s = (struct symbol *) 
+               obstack_alloc (symbol_obstack, sizeof (struct symbol));
+
+       bzero (s, sizeof (*s));
+       SYMBOL_NAME(s) = name;
+       return s;
+}
+
+/* Create a new type with printname NAME */
+
+static
+struct type *
+new_type(name)
+       char *name;
+{
+       struct type *t = (struct type *)
+               obstack_alloc (symbol_obstack, sizeof (struct type));
+
+       bzero (t, sizeof (*t));
+       TYPE_NAME(t) = name;
+       return t;
+}
+
+/* Create and initialize a new type with printname NAME.
+   CODE and LENGTH are the initial info we put in,
+   UNS says whether the type is unsigned or not.  */
+
+static
+struct type *
+make_type(code, length, uns, name)
+     enum type_code code;
+     int length, uns;
+     char *name;
+{
+       register struct type *type;
+
+       type = (struct type *) xzalloc(sizeof(struct type));
+       TYPE_CODE(type) = code;
+       TYPE_LENGTH(type) = length;
+       TYPE_FLAGS(type) = uns ? TYPE_FLAG_UNSIGNED : 0;
+       TYPE_NAME(type) = name;
+
+       return type;
+}
+
+/* Allocate a new field named NAME to the type TYPE */
+
+static
+struct field *new_field(type,name)
+       struct type *type;
+       char *name;
+{
+       struct field *f;
+
+       /* Fields are kept in an array */
+       if (TYPE_NFIELDS(type))
+               TYPE_FIELDS(type) = (struct field*)xrealloc(TYPE_FIELDS(type),
+                       (TYPE_NFIELDS(type)+1) * sizeof(struct field));
+       else
+               TYPE_FIELDS(type) = (struct field*)xzalloc(2*sizeof(struct field));
+       f = &(TYPE_FIELD(type,TYPE_NFIELDS(type)++));
+       bzero(f, sizeof(struct field));
+       if (name)
+               f->name = name;
+       return f;
+}
+
+/* Make an enum constant for a member F of an enumerated type T */
+
+static
+make_enum_constant(f,t)
+       struct field *f;
+       struct type *t;
+{
+       struct symbol *s;
+       /*
+        * This is awful, but that`s the way it is supposed to be
+        * (BTW, no need to free the real 'type', it's a builtin)
+        */
+       f->type = (struct type *) f->bitpos;
+
+       s = new_symbol(f->name);
+       SYMBOL_NAMESPACE(s) = VAR_NAMESPACE;
+       SYMBOL_CLASS(s) = LOC_CONST;
+       SYMBOL_TYPE(s) = t;
+       SYMBOL_VALUE(s) = f->bitpos;
+       add_symbol(s, top_stack->cur_block);
+}
+
+
+\f
+/* Things used for calling functions in the inferior.
+   These functions are exported to our companion
+   mips-dep.c file and are here because they play
+   with the symbol-table explicitly. */
+
+#if 0
+/* Need to make a new symbol on the fly for the dummy
+   frame we put on the stack.  Which goes in the.. */
+
+static struct symtab *dummy_symtab;
+
+/* Make up a dummy symbol for the code we put at END_PC,
+   of size SIZE, invoking a function with NARGS arguments
+   and using a frame of FRAMESIZE bytes */
+
+mips_create_dummy_symbol(end_pc, size, nargs, framesize)
+{
+       struct block   *bl;
+       struct symbol  *g;
+       struct mips_extra_func_info *gdbinfo;
+
+       /* Allocate symtab if not done already */
+       if (dummy_symtab == 0)
+               dummy_symtab = new_symtab(".dummy_symtab.", 100, 0);
+
+       /* Make a new block. Only needs one symbol */
+       bl = new_block(1);
+       BLOCK_START(bl) = end_pc - size;
+       BLOCK_END(bl) = end_pc;
+
+       BLOCK_SUPERBLOCK(bl) = BLOCKVECTOR_BLOCK(BLOCKVECTOR(dummy_symtab),0);
+       add_block(bl, dummy_symtab);
+       sort_blocks(dummy_symtab);
+
+       BLOCK_FUNCTION(bl) = new_symbol("??");
+       SYMBOL_BLOCK_VALUE(BLOCK_FUNCTION(bl)) = bl;
+       g = new_symbol(".gdbinfo.");
+       BLOCK_SYM(bl,BLOCK_NSYMS(bl)++) = g;
+
+       SYMBOL_NAMESPACE(g) = LABEL_NAMESPACE;
+       SYMBOL_CLASS(g) = LOC_CONST;
+       SYMBOL_TYPE(g) = builtin_type_void;
+       gdbinfo = (struct mips_extra_func_info *)
+               xzalloc(sizeof(struct mips_extra_func_info));
+
+       SYMBOL_VALUE(g) = (long) gdbinfo;
+
+       gdbinfo->numargs = nargs;
+       gdbinfo->framesize = framesize;
+       gdbinfo->framereg = 29;
+       gdbinfo->pcreg = 31;
+       gdbinfo->regmask = -2;
+       gdbinfo->regoffset = -4;
+       gdbinfo->fregmask = 0;  /* XXX */
+       gdbinfo->fregoffset = 0;        /* XXX */
+}
+
+/* We just returned from the dummy code at END_PC, drop its symbol */
+
+mips_destroy_dummy_symbol(end_pc)
+{
+       struct block *bl;
+       struct blockvector *bv = BLOCKVECTOR(dummy_symtab);
+       int i;
+
+       bl = block_for_pc(end_pc);
+       free(BLOCK_FUNCTION(bl));
+       free(SYMBOL_VALUE(BLOCK_SYM(bl,0)));
+       free(BLOCK_SYM(bl,0));
+
+       for (i = 2; i < BLOCKVECTOR_NBLOCKS(bv); i++)
+               if (BLOCKVECTOR_BLOCK(bv,i) == bl)
+                       break;
+       for (; i < BLOCKVECTOR_NBLOCKS(bv) - 1; i++)
+               BLOCKVECTOR_BLOCK(bv,i) = BLOCKVECTOR_BLOCK(bv,i+1);
+       BLOCKVECTOR_NBLOCKS(bv)--;
+       sort_blocks(dummy_symtab);
+       free(bl);
+}
+#endif
+
+/* Sigtramp: make sure we have all the necessary information
+   about the signal trampoline code. Since the official code
+   from MIPS does not do so, we make up that information ourselves.
+   If they fix the library (unlikely) this code will neutralize itself. */
+
+static
+fixup_sigtramp()
+{
+       struct symbol  *s;
+       struct symtab  *st;
+       struct block   *b, *b0;
+
+       sigtramp_address = -1;
+
+       /* We know it is sold as sigvec */
+       s = lookup_symbol("sigvec", 0, VAR_NAMESPACE, 0, NULL);
+
+       /* Most programs do not play with signals */
+       if (s == 0)
+               return;
+
+       b0 = SYMBOL_BLOCK_VALUE(s);
+
+       /* A label of sigvec, to be more precise */
+       s = lookup_symbol("sigtramp", b0, VAR_NAMESPACE, 0, NULL);
+
+       /* But maybe this program uses its own version of sigvec */
+       if (s == 0)
+               return;
+
+       sigtramp_address = SYMBOL_VALUE(s);
+       sigtramp_end = sigtramp_address + 0x88; /* black magic */
+
+       /* Did we or MIPSco fix the library ? */
+       if (SYMBOL_CLASS(s) == LOC_BLOCK)
+               return;
+
+       /* But what symtab does it live in ? */
+       st = find_pc_symtab(SYMBOL_VALUE(s));
+
+       /*
+        * Ok, there goes the fix: turn it into a procedure, with all the
+        * needed info.  Note we make it a nested procedure of sigvec,
+        * which is the way the (assembly) code is actually written.
+        */
+       SYMBOL_NAMESPACE(s) = VAR_NAMESPACE;
+       SYMBOL_CLASS(s) = LOC_BLOCK;
+       SYMBOL_TYPE(s) = make_type(TYPE_CODE_FUNC, 4, 0, 0);
+       TYPE_TARGET_TYPE(SYMBOL_TYPE(s)) = builtin_type_void;
+
+       /* Need a block to allocate .gdbinfo. in */
+       b = new_block(1);
+       SYMBOL_BLOCK_VALUE(s) = b;
+       BLOCK_START(b) = sigtramp_address;
+       BLOCK_END(b) = sigtramp_end;
+       BLOCK_FUNCTION(b) = s;
+       BLOCK_SUPERBLOCK(b) = BLOCK_SUPERBLOCK(b0);
+       add_block(b, st);
+       sort_blocks(st);
+
+       /* Make a .gdbinfo. for it */
+       {
+               struct mips_extra_func_info *e =
+                       (struct mips_extra_func_info *)
+                       xzalloc(sizeof(struct mips_extra_func_info));
+
+               e->numargs = 0; /* the kernel thinks otherwise */
+               /* align_longword(sigcontext + SIGFRAME) */
+               e->framesize = 0x150;
+               e->framereg = SP_REGNUM;
+               e->pcreg = 31;
+               e->regmask = -2;
+               e->regoffset = -(41 * sizeof(int));
+               e->fregmask = -1;
+               e->fregoffset = -(37 * sizeof(int));
+               e->isym = (long)s;
+
+               s = new_symbol(".gdbinfo.");
+               SYMBOL_VALUE(s) = (int) e;
+               SYMBOL_NAMESPACE(s) = LABEL_NAMESPACE;
+               SYMBOL_CLASS(s) = LOC_CONST;
+               SYMBOL_TYPE(s) = builtin_type_void;
+       }
+
+       BLOCK_SYM(b,BLOCK_NSYMS(b)++) = s;
+}
+
+\f
+/* Initialization */
+
+static struct sym_fns ecoff_sym_fns = {"ecoff", 5,
+               mipscoff_new_init, mipscoff_symfile_init,
+               mipscoff_symfile_read, mipscoff_symfile_discard};
+
+_initialize_mipsread ()
+{
+       add_symtab_fns (&ecoff_sym_fns);
+
+       bzero (&global_psymbols, sizeof (global_psymbols));
+       bzero (&static_psymbols, sizeof (static_psymbols));
+
+       add_com("add-file", class_files, add_file_command,
+               "Add a new symbol table (in mips format) from file FILE.");
+
+       /* Missing basic types */
+       builtin_type_string = make_type(TYPE_CODE_PASCAL_ARRAY,
+                                       1, 0, "string");
+       builtin_type_complex = make_type(TYPE_CODE_FLT,
+                                        2 * sizeof(float), 0, "complex");
+       builtin_type_double_complex = make_type(TYPE_CODE_FLT,
+                                   2 * sizeof(double), 0, "double_complex");
+       builtin_type_fixed_dec = make_type(TYPE_CODE_INT, sizeof(int),
+                                          0, "fixed_decimal");
+       builtin_type_float_dec = make_type(TYPE_CODE_FLT, sizeof(double),
+                                          0, "floating_decimal");
+
+       /* Templates types */
+       builtin_type_ptr = lookup_pointer_type (builtin_type_void);
+       builtin_type_struct = make_type(TYPE_CODE_STRUCT, 0, 0, 0);
+       builtin_type_union = make_type(TYPE_CODE_UNION, 0, 0, 0);
+       builtin_type_enum = make_type(TYPE_CODE_ENUM, 0, 0, 0);
+       builtin_type_range = make_type(TYPE_CODE_RANGE, 0, 0, 0);
+       builtin_type_set = make_type(TYPE_CODE_SET, 0, 0, 0);
+}
diff --git a/gdb/printcmd.c b/gdb/printcmd.c
new file mode 100644 (file)
index 0000000..b8bc298
--- /dev/null
@@ -0,0 +1,1960 @@
+/* Print values for GNU debugger GDB.
+   Copyright (C) 1986-1991 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 <stdio.h>
+#include <string.h>
+#include "defs.h"
+#include "param.h"
+#include "frame.h"
+#include "symtab.h"
+#include "value.h"
+#include "expression.h"
+#include "gdbcore.h"
+#include "gdbcmd.h"
+#include "target.h"
+
+extern int asm_demangle;       /* Whether to demangle syms in asm printouts */
+
+extern struct block *get_current_block ();
+
+static void print_frame_nameless_args ();
+
+struct format_data
+{
+  int count;
+  char format;
+  char size;
+};
+
+/* Last specified output format.  */
+
+static char last_format = 'x';
+
+/* Last specified examination size.  'b', 'h', 'w' or `q'.  */
+
+static char last_size = 'w';
+
+/* Default address to examine next.  */
+
+static CORE_ADDR next_address;
+
+/* Last address examined.  */
+
+static CORE_ADDR last_examine_address;
+
+/* Contents of last address examined.
+   This is not valid past the end of the `x' command!  */
+
+static value last_examine_value;
+
+/* Number of auto-display expression currently being displayed.
+   So that we can deleted it if we get an error or a signal within it.
+   -1 when not doing one.  */
+
+int current_display_number;
+
+/* Flag to low-level print routines that this value is being printed
+   in an epoch window.  We'd like to pass this as a parameter, but
+   every routine would need to take it.  Perhaps we can encapsulate
+   this in the I/O stream once we have GNU stdio. */
+
+int inspect_it = 0;
+
+static void do_one_display ();
+
+void do_displays ();
+void print_scalar_formatted ();
+
+\f
+/* Decode a format specification.  *STRING_PTR should point to it.
+   OFORMAT and OSIZE are used as defaults for the format and size
+   if none are given in the format specification.
+   If OSIZE is zero, then the size field of the returned value
+   should be set only if a size is explicitly specified by the
+   user.
+   The structure returned describes all the data
+   found in the specification.  In addition, *STRING_PTR is advanced
+   past the specification and past all whitespace following it.  */
+
+struct format_data
+decode_format (string_ptr, oformat, osize)
+     char **string_ptr;
+     char oformat;
+     char osize;
+{
+  struct format_data val;
+  register char *p = *string_ptr;
+
+  val.format = '?';
+  val.size = '?';
+  val.count = 1;
+
+  if (*p >= '0' && *p <= '9')
+    val.count = atoi (p);
+  while (*p >= '0' && *p <= '9') p++;
+
+  /* Now process size or format letters that follow.  */
+
+  while (1)
+    {
+      if (*p == 'b' || *p == 'h' || *p == 'w' || *p == 'g')
+       val.size = *p++;
+#ifdef LONG_LONG
+      else if (*p == 'l')
+       {
+         val.size = 'g';
+         p++;
+       }
+#endif
+      else if (*p >= 'a' && *p <= 'z')
+       val.format = *p++;
+      else
+       break;
+    }
+
+#ifndef LONG_LONG
+  /* Make sure 'g' size is not used on integer types.
+     Well, actually, we can handle hex.  */
+  if (val.size == 'g' && val.format != 'f' && val.format != 'x')
+    val.size = 'w';
+#endif
+
+  while (*p == ' ' || *p == '\t') p++;
+  *string_ptr = p;
+
+  /* Set defaults for format and size if not specified.  */
+  if (val.format == '?')
+    {
+      if (val.size == '?')
+       {
+         /* Neither has been specified.  */
+         val.format = oformat;
+         val.size = osize;
+       }
+      else
+       /* If a size is specified, any format makes a reasonable
+          default except 'i'.  */
+       val.format = oformat == 'i' ? 'x' : oformat;
+    }
+  else if (val.size == '?')
+    switch (val.format)
+      {
+      case 'a':
+      case 's':
+       /* Addresses must be words.  */
+       val.size = osize ? 'w' : osize;
+       break;
+      case 'f':
+       /* Floating point has to be word or giantword.  */
+       if (osize == 'w' || osize == 'g')
+         val.size = osize;
+       else
+         /* Default it to giantword if the last used size is not
+            appropriate.  */
+         val.size = osize ? 'g' : osize;
+       break;
+      case 'c':
+       /* Characters default to one byte.  */
+       val.size = osize ? 'b' : osize;
+       break;
+      default:
+       /* The default is the size most recently specified.  */
+       val.size = osize;
+      }
+
+  return val;
+}
+\f
+/* Print value VAL on stdout according to FORMAT, a letter or 0.
+   Do not end with a newline.
+   0 means print VAL according to its own type.
+   SIZE is the letter for the size of datum being printed.
+   This is used to pad hex numbers so they line up.  */
+
+static void
+print_formatted (val, format, size)
+     register value val;
+     register char format;
+     char size;
+{
+  int len = TYPE_LENGTH (VALUE_TYPE (val));
+
+  if (VALUE_LVAL (val) == lval_memory)
+    next_address = VALUE_ADDRESS (val) + len;
+
+  switch (format)
+    {
+    case 's':
+      next_address = VALUE_ADDRESS (val)
+       + value_print (value_addr (val), stdout, format, Val_pretty_default);
+      break;
+
+    case 'i':
+      next_address = VALUE_ADDRESS (val)
+       + print_insn (VALUE_ADDRESS (val), stdout);
+      break;
+
+    default:
+      if (format == 0
+         || TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_ARRAY
+         || TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_STRUCT
+         || TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_UNION
+         || VALUE_REPEATED (val))
+       value_print (val, stdout, format, Val_pretty_default);
+      else
+       print_scalar_formatted (VALUE_CONTENTS (val), VALUE_TYPE (val),
+                               format, size, stdout);
+    }
+}
+
+/* Print a scalar of data of type TYPE, pointed to in GDB by VALADDR,
+   according to letters FORMAT and SIZE on STREAM.
+   FORMAT may not be zero.  Formats s and i are not supported at this level.
+
+   This is how the elements of an array or structure are printed
+   with a format.  */
+
+void
+print_scalar_formatted (valaddr, type, format, size, stream)
+     char *valaddr;
+     struct type *type;
+     char format;
+     int size;
+     FILE *stream;
+{
+  LONGEST val_long;
+  int len = TYPE_LENGTH (type);
+
+  if (size == 'g' && sizeof (LONGEST) < 8
+      && format == 'x')
+    {
+      /* ok, we're going to have to get fancy here.  Assumption: a
+         long is four bytes.  FIXME.  */
+      unsigned long v1, v2, tmp;
+
+      v1 = unpack_long (builtin_type_long, valaddr);
+      v2 = unpack_long (builtin_type_long, valaddr + 4);
+
+#if TARGET_BYTE_ORDER == LITTLE_ENDIAN
+      /* Swap the two for printing */
+      tmp = v1;
+      v1 = v2;
+      v2 = tmp;
+#endif
+  
+      switch (format)
+       {
+       case 'x':
+         fprintf_filtered (stream, "0x%08x%08x", v1, v2);
+         break;
+       default:
+         error ("Output size \"g\" unimplemented for format \"%c\".",
+                format);
+       }
+      return;
+    }
+      
+  val_long = unpack_long (type, valaddr);
+
+  /* If value is unsigned, truncate it in case negative.  */
+  if (format != 'd')
+    {
+      if (len == sizeof (char))
+       val_long &= (1 << 8 * sizeof(char)) - 1;
+      else if (len == sizeof (short))
+       val_long &= (1 << 8 * sizeof(short)) - 1;
+      else if (len == sizeof (long))
+       val_long &= (unsigned long) - 1;
+    }
+
+  switch (format)
+    {
+    case 'x':
+      if (!size)
+       {
+         /* no size specified, like in print.  Print varying # of digits. */
+#if defined (LONG_LONG)
+         fprintf_filtered (stream, "0x%llx", val_long);
+#else /* not LONG_LONG.  */
+         fprintf_filtered (stream, "0x%lx", val_long);
+#endif /* not LONG_LONG.  */
+       }
+      else
+#if defined (LONG_LONG)
+      switch (size)
+       {
+       case 'b':
+         fprintf_filtered (stream, "0x%02llx", val_long);
+         break;
+       case 'h':
+         fprintf_filtered (stream, "0x%04llx", val_long);
+         break;
+       case 'w':
+         fprintf_filtered (stream, "0x%08llx", val_long);
+         break;
+       case 'g':
+         fprintf_filtered (stream, "0x%016llx", val_long);
+         break;
+       default:
+         error ("Undefined output size \"%c\".", size);
+       }
+#else /* not LONG_LONG.  */
+      switch (size)
+       {
+       case 'b':
+         fprintf_filtered (stream, "0x%02x", val_long);
+         break;
+       case 'h':
+         fprintf_filtered (stream, "0x%04x", val_long);
+         break;
+       case 'w':
+         fprintf_filtered (stream, "0x%08x", val_long);
+         break;
+       case 'g':
+         fprintf_filtered (stream, "0x%016x", val_long);
+         break;
+       default:
+         error ("Undefined output size \"%c\".", size);
+       }
+#endif /* not LONG_LONG */
+      break;
+
+    case 'd':
+#ifdef LONG_LONG
+      fprintf_filtered (stream, "%lld", val_long);
+#else
+      fprintf_filtered (stream, "%d", val_long);
+#endif
+      break;
+
+    case 'u':
+#ifdef LONG_LONG
+      fprintf_filtered (stream, "%llu", val_long);
+#else
+      fprintf_filtered (stream, "%u", val_long);
+#endif
+      break;
+
+    case 'o':
+      if (val_long)
+#ifdef LONG_LONG
+       fprintf_filtered (stream, "0%llo", val_long);
+#else
+       fprintf_filtered (stream, "0%o", val_long);
+#endif
+      else
+       fprintf_filtered (stream, "0");
+      break;
+
+    case 'a':
+      print_address ((CORE_ADDR) val_long, stream);
+      break;
+
+    case 'c':
+      value_print (value_from_long (builtin_type_char, val_long), stream, 0,
+                  Val_pretty_default);
+      break;
+
+    case 'f':
+      if (len == sizeof (float))
+       type = builtin_type_float;
+      else if (len == sizeof (double))
+       type = builtin_type_double;
+      print_floating (valaddr, type, stream);
+      break;
+
+    case 0:
+      abort ();
+
+    default:
+      error ("Undefined output format \"%c\".", format);
+    }
+}
+
+/* Specify default address for `x' command.
+   `info lines' uses this.  */
+
+void
+set_next_address (addr)
+     CORE_ADDR addr;
+{
+  next_address = addr;
+
+  /* Make address available to the user as $_.  */
+  set_internalvar (lookup_internalvar ("_"),
+                  value_from_long (builtin_type_int, (LONGEST) addr));
+}
+
+/* Optionally print address ADDR symbolically as <SYMBOL+OFFSET> on STREAM.
+   DO_DEMANGLE controls whether to print a symbol in its native "raw" form,
+   or to interpret it as a possible C++ name and convert it back to source
+   form. */
+
+void
+print_address_symbolic (addr, stream, do_demangle)
+     CORE_ADDR addr;
+     FILE *stream;
+     int do_demangle;
+{
+  int name_location;
+  register int i = find_pc_misc_function (addr);
+
+  /* If nothing comes out, don't print anything symbolic.  */
+  
+  if (i < 0)
+    return;
+
+  fputs_filtered (" <", stream);
+  if (do_demangle)
+    fputs_demangled (misc_function_vector[i].name, stream, 1);
+  else
+    fputs_filtered (misc_function_vector[i].name, stream);
+  name_location = misc_function_vector[i].address;
+  if (addr - name_location)
+    fprintf_filtered (stream, "+%d>", addr - name_location);
+  else
+    fputs_filtered (">", stream);
+}
+
+/* Print address ADDR symbolically on STREAM.
+   First print it as a number.  Then perhaps print
+   <SYMBOL + OFFSET> after the number.  */
+
+void
+print_address (addr, stream)
+     CORE_ADDR addr;
+     FILE *stream;
+{
+  fprintf_filtered (stream, "0x%x", addr);
+  print_address_symbolic (addr, stream, asm_demangle);
+}
+
+/* Print address ADDR symbolically on STREAM.  Parameter DEMANGLE
+   controls whether to print the symbolic name "raw" or demangled.  */
+
+void
+print_address_demangle (addr, stream, do_demangle)
+     CORE_ADDR addr;
+     FILE *stream;
+     int do_demangle;
+{
+  fprintf_filtered (stream, "0x%x", addr);
+  print_address_symbolic (addr, stream, do_demangle);
+}
+
+\f
+
+/* Examine data at address ADDR in format FMT.
+   Fetch it from memory and print on stdout.  */
+
+static void
+do_examine (fmt, addr)
+     struct format_data fmt;
+     CORE_ADDR addr;
+{
+  register char format = 0;
+  register char size;
+  register int count = 1;
+  struct type *val_type;
+  register int i;
+  register int maxelts;
+
+  format = fmt.format;
+  size = fmt.size;
+  count = fmt.count;
+  next_address = addr;
+
+  /* String or instruction format implies fetch single bytes
+     regardless of the specified size.  */
+  if (format == 's' || format == 'i')
+    size = 'b';
+
+  if (size == 'b')
+    val_type = builtin_type_char;
+  else if (size == 'h')
+    val_type = builtin_type_short;
+  else if (size == 'w')
+    val_type = builtin_type_long;
+  else if (size == 'g')
+#ifndef LONG_LONG
+    val_type = builtin_type_double;
+#else
+    val_type = builtin_type_long_long;
+#endif
+
+  maxelts = 8;
+  if (size == 'w')
+    maxelts = 4;
+  if (size == 'g')
+    maxelts = 2;
+  if (format == 's' || format == 'i')
+    maxelts = 1;
+
+  /* Print as many objects as specified in COUNT, at most maxelts per line,
+     with the address of the next one at the start of each line.  */
+
+  while (count > 0)
+    {
+      print_address (next_address, stdout);
+      printf_filtered (":");
+      for (i = maxelts;
+          i > 0 && count > 0;
+          i--, count--)
+       {
+         printf_filtered ("\t");
+         /* Note that print_formatted sets next_address for the next
+            object.  */
+         last_examine_address = next_address;
+         last_examine_value = value_at (val_type, next_address);
+         print_formatted (last_examine_value, format, size);
+       }
+      printf_filtered ("\n");
+      fflush (stdout);
+    }
+}
+\f
+static void
+validate_format (fmt, cmdname)
+     struct format_data fmt;
+     char *cmdname;
+{
+  if (fmt.size != 0)
+    error ("Size letters are meaningless in \"%s\" command.", cmdname);
+  if (fmt.count != 1)
+    error ("Item count other than 1 is meaningless in \"%s\" command.",
+          cmdname);
+  if (fmt.format == 'i' || fmt.format == 's')
+    error ("Format letter \"%c\" is meaningless in \"%s\" command.",
+          fmt.format, cmdname);
+}
+
+static void
+print_command_1 (exp, inspect, voidprint)
+     char *exp;
+     int inspect;
+     int voidprint;
+{
+  struct expression *expr;
+  register struct cleanup *old_chain = 0;
+  register char format = 0;
+  register value val;
+  struct format_data fmt;
+  int cleanup = 0;
+
+  /* Pass inspect flag to the rest of the print routines in a global (sigh). */
+  inspect_it = inspect;
+
+  if (exp && *exp == '/')
+    {
+      exp++;
+      fmt = decode_format (&exp, last_format, 0);
+      validate_format (fmt, "print");
+      last_format = format = fmt.format;
+    }
+  else
+    {
+      fmt.count = 1;
+      fmt.format = 0;
+      fmt.size = 0;
+    }
+
+  if (exp && *exp)
+    {
+      expr = parse_c_expression (exp);
+      old_chain = make_cleanup (free_current_contents, &expr);
+      cleanup = 1;
+      val = evaluate_expression (expr);
+    }
+  else
+    val = access_value_history (0);
+
+  if (voidprint || (val && VALUE_TYPE (val) &&
+                    TYPE_CODE (VALUE_TYPE (val)) != TYPE_CODE_VOID))
+    {
+      int histindex = record_latest_value (val);
+
+      if (inspect)
+       printf ("\031(gdb-makebuffer \"%s\"  %d '(\"", exp, histindex);
+      else
+       if (histindex >= 0) printf_filtered ("$%d = ", histindex);
+
+      print_formatted (val, format, fmt.size);
+      printf_filtered ("\n");
+      if (inspect)
+       printf("\") )\030");
+    }
+
+  if (cleanup)
+    do_cleanups (old_chain);
+  inspect_it = 0;      /* Reset print routines to normal */
+}
+
+static void
+print_command (exp, from_tty)
+     char *exp;
+     int from_tty;
+{
+  print_command_1 (exp, 0, 1);
+}
+
+/* Same as print, except in epoch, it gets its own window */
+static void
+inspect_command (exp, from_tty)
+     char *exp;
+     int from_tty;
+{
+  extern int epoch_interface;
+
+  print_command_1 (exp, epoch_interface, 1);
+}
+
+/* Same as print, except it doesn't print void results. */
+static void
+call_command (exp, from_tty)
+     char *exp;
+     int from_tty;
+{
+  print_command_1 (exp, 0, 0);
+}
+
+static void
+output_command (exp, from_tty)
+     char *exp;
+     int from_tty;
+{
+  struct expression *expr;
+  register struct cleanup *old_chain;
+  register char format = 0;
+  register value val;
+  struct format_data fmt;
+
+  if (exp && *exp == '/')
+    {
+      exp++;
+      fmt = decode_format (&exp, 0, 0);
+      validate_format (fmt, "print");
+      format = fmt.format;
+    }
+
+  expr = parse_c_expression (exp);
+  old_chain = make_cleanup (free_current_contents, &expr);
+
+  val = evaluate_expression (expr);
+
+  print_formatted (val, format, fmt.size);
+
+  do_cleanups (old_chain);
+}
+
+static void
+set_command (exp, from_tty)
+     char *exp;
+     int from_tty;
+{
+  struct expression *expr = parse_c_expression (exp);
+  register struct cleanup *old_chain
+    = make_cleanup (free_current_contents, &expr);
+  evaluate_expression (expr);
+  do_cleanups (old_chain);
+}
+
+static void
+address_info (exp, from_tty)
+     char *exp;
+     int from_tty;
+{
+  register struct symbol *sym;
+  register CORE_ADDR val;
+  int is_a_field_of_this;      /* C++: lookup_symbol sets this to nonzero
+                                  if exp is a field of `this'. */
+
+  if (exp == 0)
+    error ("Argument required.");
+
+  sym = lookup_symbol (exp, get_selected_block (), VAR_NAMESPACE, 
+                      &is_a_field_of_this, (struct symtab **)NULL);
+  if (sym == 0)
+    {
+      register int i;
+
+      if (is_a_field_of_this)
+       {
+         printf ("Symbol \"%s\" is a field of the local class variable `this'\n", exp);
+         return;
+       }
+
+      for (i = 0; i < misc_function_count; i++)
+       if (!strcmp (misc_function_vector[i].name, exp))
+         break;
+
+      if (i < misc_function_count)
+       printf ("Symbol \"%s\" is at 0x%x in a file compiled without -g.\n",
+               exp, misc_function_vector[i].address);
+      else
+       error ("No symbol \"%s\" in current context.", exp);
+      return;
+    }
+
+  printf ("Symbol \"%s\" is ", SYMBOL_NAME (sym));
+  val = SYMBOL_VALUE (sym);
+
+  switch (SYMBOL_CLASS (sym))
+    {
+    case LOC_CONST:
+    case LOC_CONST_BYTES:
+      printf ("constant");
+      break;
+
+    case LOC_LABEL:
+      printf ("a label at address 0x%x", SYMBOL_VALUE_ADDRESS (sym));
+      break;
+
+    case LOC_REGISTER:
+      printf ("a variable in register %s", reg_names[val]);
+      break;
+
+    case LOC_STATIC:
+      printf ("static at address 0x%x", SYMBOL_VALUE_ADDRESS (sym));
+      break;
+
+    case LOC_REGPARM:
+      printf ("an argument in register %s", reg_names[val]);
+      break;
+      
+    case LOC_ARG:
+      printf ("an argument at offset %d", (int)val);
+      break;
+
+    case LOC_LOCAL_ARG:
+      printf ("an argument at frame offset %d", (int)val);
+      break;
+
+    case LOC_LOCAL:
+      printf ("a local variable at frame offset %d", (int)val);
+      break;
+
+    case LOC_REF_ARG:
+      printf ("a reference argument at offset %d", (int)val);
+      break;
+
+    case LOC_TYPEDEF:
+      printf ("a typedef");
+      break;
+
+    case LOC_BLOCK:
+      printf ("a function at address 0x%x",
+             BLOCK_START (SYMBOL_BLOCK_VALUE (sym)));
+      break;
+
+    case LOC_EXTERNAL:
+      printf ("an external symbol at address 0x%x",
+             SYMBOL_VALUE_ADDRESS (sym));
+      break;
+
+    default:
+      printf ("of unknown (botched) type");
+      break;
+    }
+  printf (".\n");
+}
+\f
+static void
+x_command (exp, from_tty)
+     char *exp;
+     int from_tty;
+{
+  struct expression *expr;
+  struct format_data fmt;
+  struct cleanup *old_chain;
+  struct value *val;
+
+  fmt.format = last_format;
+  fmt.size = last_size;
+  fmt.count = 1;
+
+  if (exp && *exp == '/')
+    {
+      exp++;
+      fmt = decode_format (&exp, last_format, last_size);
+      last_size = fmt.size;
+      last_format = fmt.format;
+    }
+
+  /* If we have an expression, evaluate it and use it as the address.  */
+
+  if (exp != 0 && *exp != 0)
+    {
+      expr = parse_c_expression (exp);
+      /* Cause expression not to be there any more
+        if this command is repeated with Newline.
+        But don't clobber a user-defined command's definition.  */
+      if (from_tty)
+       *exp = 0;
+      old_chain = make_cleanup (free_current_contents, &expr);
+      val = evaluate_expression (expr);
+      /* In rvalue contexts, such as this, functions are coerced into
+        pointers to functions.  This makes "x/i main" work.  */
+      if (/* last_format == 'i'
+         && */ TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_FUNC
+         && VALUE_LVAL (val) == lval_memory)
+       next_address = VALUE_ADDRESS (val);
+      else
+       next_address = (CORE_ADDR) value_as_long (val);
+      do_cleanups (old_chain);
+    }
+
+  do_examine (fmt, next_address);
+
+  /* Set a couple of internal variables if appropriate. */
+  if (last_examine_value)
+    {
+      /* Make last address examined available to the user as $_.  */
+      set_internalvar (lookup_internalvar ("_"),
+                      value_from_long (builtin_type_int, 
+                                       (LONGEST) last_examine_address));
+      
+      /* Make contents of last address examined available to the user as $__.*/
+      set_internalvar (lookup_internalvar ("__"), last_examine_value);
+    }
+}
+\f
+/* Commands for printing types of things.  */
+
+/* Print type of EXP, or last thing in value history if EXP == NULL.
+   show is passed to type_print.  */
+static void
+whatis_exp (exp, show)
+     char *exp;
+     int show;
+{
+  struct expression *expr;
+  register value val;
+  register struct cleanup *old_chain;
+
+  if (exp)
+    {
+      expr = parse_c_expression (exp);
+      old_chain = make_cleanup (free_current_contents, &expr);
+      val = evaluate_type (expr);
+    }
+  else
+    val = access_value_history (0);
+
+  printf_filtered ("type = ");
+  type_print (VALUE_TYPE (val), "", stdout, show);
+  printf_filtered ("\n");
+
+  if (exp)
+    do_cleanups (old_chain);
+}
+
+static void
+whatis_command (exp, from_tty)
+     char *exp;
+     int from_tty;
+{
+  /* Most of the time users do not want to see all the fields
+     in a structure.  If they do they can use the "ptype" command.
+     Hence the "-1" below.  */
+  whatis_exp (exp, -1);
+}
+
+/* TYPENAME is either the name of a type, or an expression.  */
+static void
+ptype_command (typename, from_tty)
+     char *typename;
+     int from_tty;
+{
+  register char *p = typename;
+  register int len;
+  register struct block *b
+    = target_has_stack ? get_current_block () : 0;
+  register struct type *type;
+
+  if (typename == 0)
+    {
+      whatis_exp (typename, 1);
+      return;
+    }
+
+  while (*p && *p != ' ' && *p != '\t') p++;
+  len = p - typename;
+  while (*p == ' ' || *p == '\t') p++;
+
+  if (len == 6 && !strncmp (typename, "struct", 6))
+    type = lookup_struct (p, b);
+  else if (len == 5 && !strncmp (typename, "union", 5))
+    type = lookup_union (p, b);
+  else if (len == 4 && !strncmp (typename, "enum", 4))
+    type = lookup_enum (p, b);
+  else
+    {
+      type = lookup_typename (typename, b, 1);
+      if (type == 0)
+       {
+         register struct symbol *sym
+           = lookup_symbol (typename, b, STRUCT_NAMESPACE, 0,
+                            (struct symtab **)NULL);
+         if (sym == 0)
+           {
+             whatis_exp (typename, 1 /* FIXME: right? */);
+             return;
+           }
+         printf_filtered ("No type named %s, but there is a ",
+                 typename);
+         switch (TYPE_CODE (SYMBOL_TYPE (sym)))
+           {
+           case TYPE_CODE_STRUCT:
+             printf_filtered ("struct");
+             break;
+
+           case TYPE_CODE_UNION:
+             printf_filtered ("union");
+             break;
+
+           case TYPE_CODE_ENUM:
+             printf_filtered ("enum");
+             break;
+
+           default:
+             printf_filtered ("(Internal error in gdb)");
+             break;
+           }
+         printf_filtered (" %s.  Type \"help ptype\".\n", typename);
+         type = SYMBOL_TYPE (sym);
+       }
+    }
+
+  type_print (type, "", stdout, 1);
+  printf_filtered ("\n");
+}
+\f
+#if 0
+/* This is not necessary.  Instead, decode_line_1 takes any variable,
+   so "info line foo" is a close equivalent to "whereis foo".  */
+static void
+whereis_command (var, from_tty)
+     char *var;
+     int from_tty;
+{
+  struct symtab *s;
+  struct symbol *sym;
+  
+  if (var == NULL)
+    error_no_arg ("Variable name.");
+
+  sym = lookup_symbol (var, get_selected_block (), VAR_NAMESPACE,
+                      NULL, &s);
+  
+  if (sym != NULL && s != NULL)
+    printf_filtered ("Symbol \"%s\" is at line %d of file %s\n",
+                    var, sym->line, s->filename);
+  else
+    {
+      if (lookup_misc_func (var) >= 0)
+       printf_filtered ("Symbol \"%s\" is in a file compiled without -g.",
+                        var);
+      else
+       error ("No symbol \"%s\" in current context.", var);
+    }
+}
+#endif /* 0 */
+\f
+enum display_status {disabled, enabled};
+
+struct display
+{
+  /* Chain link to next auto-display item.  */
+  struct display *next;
+  /* Expression to be evaluated and displayed.  */
+  struct expression *exp;
+  /* Item number of this auto-display item.  */
+  int number;
+  /* Display format specified.  */
+  struct format_data format;
+  /* Innermost block required by this expression when evaluated */
+  struct block *block;
+  /* Status of this display (enabled or disabled) */
+  enum display_status status;
+};
+
+/* Chain of expressions whose values should be displayed
+   automatically each time the program stops.  */
+
+static struct display *display_chain;
+
+static int display_number;
+
+/* Add an expression to the auto-display chain.
+   Specify the expression.  */
+
+static void
+display_command (exp, from_tty)
+     char *exp;
+     int from_tty;
+{
+  struct format_data fmt;
+  register struct expression *expr;
+  register struct display *new;
+
+  if (exp == 0)
+    {
+      do_displays ();
+      return;
+    }
+
+  if (*exp == '/')
+    {
+      exp++;
+      fmt = decode_format (&exp, 0, 0);
+      if (fmt.size && fmt.format == 0)
+       fmt.format = 'x';
+      if (fmt.format == 'i' || fmt.format == 's')
+       fmt.size = 'b';
+    }
+  else
+    {
+      fmt.format = 0;
+      fmt.size = 0;
+      fmt.count = 0;
+    }
+
+  innermost_block = 0;
+  expr = parse_c_expression (exp);
+
+  new = (struct display *) xmalloc (sizeof (struct display));
+
+  new->exp = expr;
+  new->block = innermost_block;
+  new->next = display_chain;
+  new->number = ++display_number;
+  new->format = fmt;
+  new->status = enabled;
+  display_chain = new;
+
+  if (from_tty && target_has_execution)
+    do_one_display (new);
+
+  dont_repeat ();
+}
+
+static void
+free_display (d)
+     struct display *d;
+{
+  free (d->exp);
+  free (d);
+}
+
+/* Clear out the display_chain.
+   Done when new symtabs are loaded, since this invalidates
+   the types stored in many expressions.  */
+
+void
+clear_displays ()
+{
+  register struct display *d;
+
+  while (d = display_chain)
+    {
+      free (d->exp);
+      display_chain = d->next;
+      free (d);
+    }
+}
+
+/* Delete the auto-display number NUM.  */
+
+void
+delete_display (num)
+     int num;
+{
+  register struct display *d1, *d;
+
+  if (!display_chain)
+    error ("No display number %d.", num);
+
+  if (display_chain->number == num)
+    {
+      d1 = display_chain;
+      display_chain = d1->next;
+      free_display (d1);
+    }
+  else
+    for (d = display_chain; ; d = d->next)
+      {
+       if (d->next == 0)
+         error ("No display number %d.", num);
+       if (d->next->number == num)
+         {
+           d1 = d->next;
+           d->next = d1->next;
+           free_display (d1);
+           break;
+         }
+      }
+}
+
+/* Delete some values from the auto-display chain.
+   Specify the element numbers.  */
+
+static void
+undisplay_command (args)
+     char *args;
+{
+  register char *p = args;
+  register char *p1;
+  register int num;
+
+  if (args == 0)
+    {
+      if (query ("Delete all auto-display expressions? "))
+       clear_displays ();
+      dont_repeat ();
+      return;
+    }
+
+  while (*p)
+    {
+      p1 = p;
+      while (*p1 >= '0' && *p1 <= '9') p1++;
+      if (*p1 && *p1 != ' ' && *p1 != '\t')
+       error ("Arguments must be display numbers.");
+
+      num = atoi (p);
+
+      delete_display (num);
+
+      p = p1;
+      while (*p == ' ' || *p == '\t') p++;
+    }
+  dont_repeat ();
+}
+
+/* Display a single auto-display.  
+   Do nothing if the display cannot be printed in the current context,
+   or if the display is disabled. */
+
+static void
+do_one_display (d)
+     struct display *d;
+{
+  int within_current_scope;
+
+  if (d->status == disabled)
+    return;
+
+  if (d->block)
+    within_current_scope = contained_in (get_selected_block (), d->block);
+  else
+    within_current_scope = 1;
+  if (!within_current_scope)
+    return;
+
+  current_display_number = d->number;
+
+  printf_filtered ("%d: ", d->number);
+  if (d->format.size)
+    {
+      CORE_ADDR addr;
+      
+      printf_filtered ("x/");
+      if (d->format.count != 1)
+       printf_filtered ("%d", d->format.count);
+      printf_filtered ("%c", d->format.format);
+      if (d->format.format != 'i' && d->format.format != 's')
+       printf_filtered ("%c", d->format.size);
+      printf_filtered (" ");
+      print_expression (d->exp, stdout);
+      if (d->format.count != 1)
+       printf_filtered ("\n");
+      else
+       printf_filtered ("  ");
+      
+      addr = (CORE_ADDR) value_as_long (evaluate_expression (d->exp));
+      if (d->format.format == 'i')
+       addr = ADDR_BITS_REMOVE (addr);
+      
+      do_examine (d->format, addr);
+    }
+  else
+    {
+      if (d->format.format)
+       printf_filtered ("/%c ", d->format.format);
+      print_expression (d->exp, stdout);
+      printf_filtered (" = ");
+      print_formatted (evaluate_expression (d->exp),
+                      d->format.format, d->format.size);
+      printf_filtered ("\n");
+    }
+
+  fflush (stdout);
+  current_display_number = -1;
+}
+
+/* Display all of the values on the auto-display chain which can be
+   evaluated in the current scope.  */
+
+void
+do_displays ()
+{
+  register struct display *d;
+
+  for (d = display_chain; d; d = d->next)
+    do_one_display (d);
+}
+
+/* Delete the auto-display which we were in the process of displaying.
+   This is done when there is an error or a signal.  */
+
+void
+disable_display (num)
+     int num;
+{
+  register struct display *d;
+
+  for (d = display_chain; d; d = d->next)
+    if (d->number == num)
+      {
+       d->status = disabled;
+       return;
+      }
+  printf ("No display number %d.\n", num);
+}
+  
+void
+disable_current_display ()
+{
+  if (current_display_number >= 0)
+    {
+      disable_display (current_display_number);
+      fprintf (stderr, "Disabling display %d to avoid infinite recursion.\n",
+              current_display_number);
+    }
+  current_display_number = -1;
+}
+
+static void
+display_info ()
+{
+  register struct display *d;
+
+  if (!display_chain)
+    printf ("There are no auto-display expressions now.\n");
+  else
+      printf_filtered ("Auto-display expressions now in effect:\n\
+Num Enb Expression\n");
+
+  for (d = display_chain; d; d = d->next)
+    {
+      printf_filtered ("%d:   %c  ", d->number, "ny"[(int)d->status]);
+      if (d->format.size)
+       printf_filtered ("/%d%c%c ", d->format.count, d->format.size,
+               d->format.format);
+      else if (d->format.format)
+       printf_filtered ("/%c ", d->format.format);
+      print_expression (d->exp, stdout);
+      if (d->block && !contained_in (get_selected_block (), d->block))
+       printf_filtered (" (cannot be evaluated in the current context)");
+      printf_filtered ("\n");
+      fflush (stdout);
+    }
+}
+
+void
+enable_display (args)
+     char *args;
+{
+  register char *p = args;
+  register char *p1;
+  register int num;
+  register struct display *d;
+
+  if (p == 0)
+    {
+      for (d = display_chain; d; d = d->next)
+       d->status = enabled;
+    }
+  else
+    while (*p)
+      {
+       p1 = p;
+       while (*p1 >= '0' && *p1 <= '9')
+         p1++;
+       if (*p1 && *p1 != ' ' && *p1 != '\t')
+         error ("Arguments must be display numbers.");
+       
+       num = atoi (p);
+       
+       for (d = display_chain; d; d = d->next)
+         if (d->number == num)
+           {
+             d->status = enabled;
+             goto win;
+           }
+       printf ("No display number %d.\n", num);
+      win:
+       p = p1;
+       while (*p == ' ' || *p == '\t')
+         p++;
+      }
+}
+
+void
+disable_display_command (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  register char *p = args;
+  register char *p1;
+  register struct display *d;
+
+  if (p == 0)
+    {
+      for (d = display_chain; d; d = d->next)
+       d->status = disabled;
+    }
+  else
+    while (*p)
+      {
+       p1 = p;
+       while (*p1 >= '0' && *p1 <= '9')
+         p1++;
+       if (*p1 && *p1 != ' ' && *p1 != '\t')
+         error ("Arguments must be display numbers.");
+       
+       disable_display (atoi (p));
+
+       p = p1;
+       while (*p == ' ' || *p == '\t')
+         p++;
+      }
+}
+
+\f
+/* Print the value in stack frame FRAME of a variable
+   specified by a struct symbol.  */
+
+void
+print_variable_value (var, frame, stream)
+     struct symbol *var;
+     FRAME frame;
+     FILE *stream;
+{
+  value val = read_var_value (var, frame);
+  value_print (val, stream, 0, Val_pretty_default);
+}
+
+/* Print the arguments of a stack frame, given the function FUNC
+   running in that frame (as a symbol), the info on the frame,
+   and the number of args according to the stack frame (or -1 if unknown).  */
+
+/* References here and elsewhere to "number of args according to the
+   stack frame" appear in all cases to refer to "number of ints of args
+   according to the stack frame".  At least for VAX, i386, isi.  */
+
+void
+print_frame_args (func, fi, num, stream)
+     struct symbol *func;
+     struct frame_info *fi;
+     int num;
+     FILE *stream;
+{
+  struct block *b;
+  int nsyms = 0;
+  int first = 1;
+  register int i;
+  register struct symbol *sym;
+  register value val;
+  /* Offset of next stack argument beyond the one we have seen that is
+     at the highest offset.
+     -1 if we haven't come to a stack argument yet.  */
+  int highest_offset = -1;
+  int arg_size;
+  /* Number of ints of arguments that we have printed so far.  */
+  int args_printed = 0;
+
+  if (func)
+    {
+      b = SYMBOL_BLOCK_VALUE (func);
+      nsyms = BLOCK_NSYMS (b);
+    }
+
+  for (i = 0; i < nsyms; i++)
+    {
+      QUIT;
+      sym = BLOCK_SYM (b, i);
+
+      if (SYMBOL_CLASS (sym) != LOC_REGPARM
+         && SYMBOL_CLASS (sym) != LOC_ARG
+         && SYMBOL_CLASS (sym) != LOC_LOCAL_ARG
+         && SYMBOL_CLASS (sym) != LOC_REF_ARG)
+       continue;
+
+      /* We have to re-look-up the symbol because arguments often have
+        two entries (one a parameter, one a register or local), and the one
+        we want is the non-parm, which lookup_symbol will find for
+        us.  After this, sym could be any SYMBOL_CLASS...  */
+      sym = lookup_symbol (SYMBOL_NAME (sym),
+                   b, VAR_NAMESPACE, (int *)NULL, (struct symtab **)NULL);
+
+      switch (SYMBOL_CLASS (sym)) {
+
+      /* Keep track of the highest stack argument offset seen */
+      case LOC_ARG:
+      case LOC_REF_ARG:
+       {
+         int current_offset = SYMBOL_VALUE (sym);
+
+         arg_size = TYPE_LENGTH (SYMBOL_TYPE (sym));
+         
+         /* Compute address of next argument by adding the size of
+            this argument and rounding to an int boundary.  */
+         current_offset
+           = ((current_offset + arg_size + sizeof (int) - 1)
+              & ~(sizeof (int) - 1));
+
+         /* If this is the highest offset seen yet, set highest_offset.  */
+         if (highest_offset == -1
+             || (current_offset > highest_offset))
+           highest_offset = current_offset;
+
+         /* Add the number of ints we're about to print to args_printed.  */
+         args_printed += (arg_size + sizeof (int) - 1) / sizeof (int);
+       }
+
+      /* Other types of symbols don't need to be kept track of.  */
+      default:
+       break;
+      }
+
+      /* Print the current arg.  */
+      if (! first)
+       fprintf_filtered (stream, ", ");
+      wrap_here ("    ");
+      fprint_symbol (stream, SYMBOL_NAME (sym));
+      fputs_filtered ("=", stream);
+
+      /* Avoid value_print because it will deref ref parameters.  We just
+        want to print their addresses.  Print ??? for args whose address
+        we do not know.  */
+      val = read_var_value (sym, FRAME_INFO_ID (fi));
+      if (val)
+        val_print (VALUE_TYPE (val), VALUE_CONTENTS (val), VALUE_ADDRESS (val),
+                  stream, 0, 0, 0, Val_no_prettyprint);
+      else
+       fputs_filtered ("???", stream);
+      first = 0;
+    }
+
+  /* Don't print nameless args in situations where we don't know
+     enough about the stack to find them.  */
+  if (num != -1)
+    {
+      int start;
+      CORE_ADDR addr;
+
+      if (highest_offset == -1)
+       start = FRAME_ARGS_SKIP;
+      else
+       start = highest_offset;
+
+      addr = FRAME_ARGS_ADDRESS (fi);
+      if (addr)
+        print_frame_nameless_args (addr, start, num - args_printed,
+                                  first, stream);
+    }
+}
+
+/* Print nameless args on STREAM.
+   ARGSADDR is the address of the arglist, START is the offset
+   of the first nameless arg, and NUM is the number of nameless args to
+   print.  FIRST is nonzero if this is the first argument (not just
+   the first nameless arg).  */
+static void
+print_frame_nameless_args (argsaddr, start, num, first, stream)
+     CORE_ADDR argsaddr;
+     int start;
+     int num;
+     int first;
+     FILE *stream;
+{
+  int i;
+  for (i = 0; i < num; i++)
+    {
+      QUIT;
+      if (!first)
+       fprintf_filtered (stream, ", ");
+#ifndef PRINT_TYPELESS_INTEGER
+      fprintf_filtered (stream, "%d",
+              read_memory_integer (argsaddr + start, sizeof (int)));
+#else
+      PRINT_TYPELESS_INTEGER (stream, builtin_type_int,
+                             (LONGEST)
+                             read_memory_integer (argsaddr + start,
+                                                  sizeof (int)));
+#endif
+      first = 0;
+      start += sizeof (int);
+    }
+}
+\f
+static void
+printf_command (arg, from_tty)
+     char *arg;
+     int from_tty;
+{
+  register char *f;
+  register char *s = arg;
+  char *string;
+  value *val_args;
+  int nargs = 0;
+  int allocated_args = 20;
+  char *arg_bytes;
+
+  val_args = (value *) xmalloc (allocated_args * sizeof (value));
+
+  if (s == 0)
+    error_no_arg ("format-control string and values to print");
+
+  /* Skip white space before format string */
+  while (*s == ' ' || *s == '\t') s++;
+
+  /* A format string should follow, enveloped in double quotes */
+  if (*s++ != '"')
+    error ("Bad format string, missing '\"'.");
+
+  /* Parse the format-control string and copy it into the string STRING,
+     processing some kinds of escape sequence.  */
+
+  f = string = (char *) alloca (strlen (s) + 1);
+  while (*s != '"')
+    {
+      int c = *s++;
+      switch (c)
+       {
+       case '\0':
+         error ("Bad format string, non-terminated '\"'.");
+         /* doesn't return */
+
+       case '\\':
+         switch (c = *s++)
+           {
+           case '\\':
+             *f++ = '\\';
+             break;
+           case 'n':
+             *f++ = '\n';
+             break;
+           case 't':
+             *f++ = '\t';
+             break;
+           case 'r':
+             *f++ = '\r';
+             break;
+           case '"':
+             *f++ = '"';
+             break;
+           default:
+             /* ??? TODO: handle other escape sequences */
+             error ("Unrecognized \\ escape character in format string.");
+           }
+         break;
+
+       default:
+         *f++ = c;
+       }
+    }
+
+  /* Skip over " and following space and comma.  */
+  s++;
+  *f++ = '\0';
+  while (*s == ' ' || *s == '\t') s++;
+
+  if (*s != ',' && *s != 0)
+    error ("Invalid argument syntax");
+
+  if (*s == ',') s++;
+  while (*s == ' ' || *s == '\t') s++;
+
+  {
+    /* Now scan the string for %-specs and see what kinds of args they want.
+       argclass[I] classifies the %-specs so we can give vprintf something
+       of the right size.  */
+    enum argclass {int_arg, string_arg, double_arg, long_long_arg};
+    enum argclass *argclass;
+    int nargs_wanted;
+    int argindex;
+    int lcount;
+    int i;
+    argclass = (enum argclass *) alloca (strlen (s) * sizeof *argclass);
+    nargs_wanted = 0;
+    f = string;
+    while (*f)
+      if (*f++ == '%')
+       {
+         lcount = 0;
+         while (strchr ("0123456789.hlL-+ #", *f)) 
+           {
+             if (*f == 'l' || *f == 'L')
+               lcount++;
+             f++;
+           }
+         if (*f == 's')
+           argclass[nargs_wanted++] = string_arg;
+         else if (*f == 'e' || *f == 'f' || *f == 'g')
+           argclass[nargs_wanted++] = double_arg;
+         else if (lcount > 1)
+           argclass[nargs_wanted++] = long_long_arg;
+         else if (*f != '%')
+           argclass[nargs_wanted++] = int_arg;
+         f++;
+       }
+    /* Now, parse all arguments and evaluate them.
+       Store the VALUEs in VAL_ARGS.  */
+    while (*s != '\0')
+      {
+       char *s1;
+       if (nargs == allocated_args)
+         val_args = (value *) xrealloc (val_args,
+                                        (allocated_args *= 2)
+                                        * sizeof (value));
+       s1 = s;
+       val_args[nargs] = parse_to_comma_and_eval (&s1);
+       /* If format string wants a float, unchecked-convert the value to
+          floating point of the same size */
+       if (argclass[nargs] == double_arg)
+         {
+           if (TYPE_LENGTH (VALUE_TYPE (val_args[nargs])) == sizeof (float))
+             VALUE_TYPE (val_args[nargs]) = builtin_type_float;
+           if (TYPE_LENGTH (VALUE_TYPE (val_args[nargs])) == sizeof (double))
+             VALUE_TYPE (val_args[nargs]) = builtin_type_double;
+         }
+       nargs++;
+       s = s1;
+       if (*s == ',')
+         s++;
+      }
+    if (nargs != nargs_wanted)
+      error ("Wrong number of arguments for specified format-string");
+    /* Now lay out an argument-list containing the arguments
+       as doubles, integers and C pointers.  */
+    arg_bytes = (char *) alloca (sizeof (double) * nargs);
+    argindex = 0;
+    for (i = 0; i < nargs; i++)
+      {
+       if (argclass[i] == string_arg)
+         {
+           char *str;
+           int tem, j;
+           tem = value_as_long (val_args[i]);
+           /* This is a %s argument.  Find the length of the string.  */
+           for (j = 0; ; j++)
+             {
+               char c;
+               QUIT;
+               read_memory (tem + j, &c, 1);
+               if (c == 0)
+                 break;
+             }
+           /* Copy the string contents into a string inside GDB.  */
+           str = (char *) alloca (j + 1);
+           read_memory (tem, str, j);
+           str[j] = 0;
+           /* Pass address of internal copy as the arg to vprintf.  */
+           *((int *) &arg_bytes[argindex]) = (int) str;
+           argindex += sizeof (int);
+         }
+       else if (VALUE_TYPE (val_args[i])->code == TYPE_CODE_FLT)
+         {
+           *((double *) &arg_bytes[argindex]) = value_as_double (val_args[i]);
+           argindex += sizeof (double);
+         }
+       else
+#ifdef LONG_LONG
+         if (argclass[i] == long_long_arg)
+           {
+             *(long long *) &arg_bytes[argindex] = value_as_long (val_args[i]);
+             argindex += sizeof (long long);
+           }
+         else
+#endif
+           {
+             *((int *) &arg_bytes[argindex]) = value_as_long (val_args[i]);
+             argindex += sizeof (int);
+           }
+      }
+  }
+
+  /* There is not a standard way to make a va_list, so we need
+     to do various things for different systems.  */
+#if defined (__INT_VARARGS_H)
+  {
+    va_list list;
+
+    list.__va_arg = 0;
+    list.__va_stk = (int *) arg_bytes;
+    list.__va_reg = (int *) arg_bytes;
+    vprintf (string, list);
+  }
+#else /* No __INT_VARARGS_H.  */
+  vprintf (string, arg_bytes);
+#endif /* No __INT_VARARGS_H.  */
+}
+\f
+/* Helper function for asdump_command.  Finds the bounds of a function
+   for a specified section of text.  PC is an address within the
+   function which you want bounds for; *LOW and *HIGH are set to the
+   beginning (inclusive) and end (exclusive) of the function.  This
+   function returns 1 on success and 0 on failure.  */
+
+static int
+containing_function_bounds (pc, low, high)
+     CORE_ADDR pc, *low, *high;
+{
+  int scan;
+
+  if (!find_pc_partial_function (pc, 0, low))
+    return 0;
+
+  scan = *low;
+  do {
+    scan++;
+    if (!find_pc_partial_function (scan, 0, high))
+      return 0;
+  } while (*low == *high);
+
+  return 1;
+}
+
+/* Dump a specified section of assembly code.  With no command line
+   arguments, this command will dump the assembly code for the
+   function surrounding the pc value in the selected frame.  With one
+   argument, it will dump the assembly code surrounding that pc value.
+   Two arguments are interpeted as bounds within which to dump
+   assembly.  */
+
+static void
+disassemble_command (arg, from_tty)
+     char *arg;
+     int from_tty;
+{
+  CORE_ADDR low, high;
+  CORE_ADDR pc;
+  char *space_index;
+
+  if (!arg)
+    {
+      if (!selected_frame)
+       error ("No frame selected.\n");
+
+      pc = get_frame_pc (selected_frame);
+      if (!containing_function_bounds (pc, &low, &high))
+       error ("No function contains pc specified by selected frame.\n");
+    }
+  else if (!(space_index = (char *) strchr (arg, ' ')))
+    {
+      /* One argument.  */
+      pc = parse_and_eval_address (arg);
+      if (!containing_function_bounds (pc, &low, &high))
+       error ("No function contains specified pc.\n");
+    }
+  else
+    {
+      /* Two arguments.  */
+      *space_index = '\0';
+      low = parse_and_eval_address (arg);
+      high = parse_and_eval_address (space_index + 1);
+    }
+
+  printf_filtered ("Dump of assembler code ");
+  if (!space_index)
+    {
+      char *name;
+      find_pc_partial_function (pc, &name, 0);
+      printf_filtered ("for function %s:\n", name);
+    }
+  else
+    printf_filtered ("from 0x%x to 0x%x:\n", low, high);
+
+  /* Dump the specified range.  */
+  for (pc = low; pc < high; )
+    {
+      QUIT;
+      print_address (pc, stdout);
+      printf_filtered (":\t");
+      pc += print_insn (pc, stdout);
+      printf_filtered ("\n");
+    }
+  printf_filtered ("End of assembler dump.\n");
+  fflush (stdout);
+}
+
+\f
+void
+_initialize_printcmd ()
+{
+  current_display_number = -1;
+
+  add_info ("address", address_info,
+          "Describe where variable VAR is stored.");
+
+  add_com ("x", class_vars, x_command,
+          "Examine memory: x/FMT ADDRESS.\n\
+ADDRESS is an expression for the memory address to examine.\n\
+FMT is a repeat count followed by a format letter and a size letter.\n\
+Format letters are o(octal), x(hex), d(decimal), u(unsigned decimal),\n\
+ f(float), a(address), i(instruction), c(char) and s(string).\n\
+Size letters are b(byte), h(halfword), w(word), g(giant, 8 bytes).\n\
+  g is meaningful only with f, for type double.\n\
+The specified number of objects of the specified size are printed\n\
+according to the format.\n\n\
+Defaults for format and size letters are those previously used.\n\
+Default count is 1.  Default address is following last thing printed\n\
+with this command or \"print\".");
+
+  add_com ("disassemble", class_vars, disassemble_command,
+          "Disassemble a specified section of memory.\n\
+Default is the function surrounding the pc of the selected frame.\n\
+With a single argument, the function surrounding that address is dumped.\n\
+Two arguments are taken as a range of memory to dump.");
+
+  add_com ("ptype", class_vars, ptype_command,
+          "Print definition of type TYPE.\n\
+Argument may be a type name defined by typedef, or \"struct STRUCTNAME\"\n\
+or \"union UNIONNAME\" or \"enum ENUMNAME\".\n\
+The selected stack frame's lexical context is used to look up the name.");
+
+  add_com ("whatis", class_vars, whatis_command,
+          "Print data type of expression EXP.");
+
+#if 0
+  add_com ("whereis", class_vars, whereis_command,
+          "Print line number and file of definition of variable.");
+#endif
+  
+  add_info ("display", display_info,
+           "Expressions to display when program stops, with code numbers.");
+
+  add_cmd ("undisplay", class_vars, undisplay_command,
+          "Cancel some expressions to be displayed when program stops.\n\
+Arguments are the code numbers of the expressions to stop displaying.\n\
+No argument means cancel all automatic-display expressions.\n\
+\"delete display\" has the same effect as this command.\n\
+Do \"info display\" to see current list of code numbers.",
+                 &cmdlist);
+
+  add_com ("display", class_vars, display_command,
+          "Print value of expression EXP each time the program stops.\n\
+/FMT may be used before EXP as in the \"print\" command.\n\
+/FMT \"i\" or \"s\" or including a size-letter is allowed,\n\
+as in the \"x\" command, and then EXP is used to get the address to examine\n\
+and examining is done as in the \"x\" command.\n\n\
+With no argument, display all currently requested auto-display expressions.\n\
+Use \"undisplay\" to cancel display requests previously made.");
+
+  add_cmd ("display", class_vars, enable_display, 
+          "Enable some expressions to be displayed when program stops.\n\
+Arguments are the code numbers of the expressions to resume displaying.\n\
+No argument means enable all automatic-display expressions.\n\
+Do \"info display\" to see current list of code numbers.", &enablelist);
+
+  add_cmd ("display", class_vars, disable_display_command, 
+          "Disable some expressions to be displayed when program stops.\n\
+Arguments are the code numbers of the expressions to stop displaying.\n\
+No argument means disable all automatic-display expressions.\n\
+Do \"info display\" to see current list of code numbers.", &disablelist);
+
+  add_cmd ("display", class_vars, undisplay_command, 
+          "Cancel some expressions to be displayed when program stops.\n\
+Arguments are the code numbers of the expressions to stop displaying.\n\
+No argument means cancel all automatic-display expressions.\n\
+Do \"info display\" to see current list of code numbers.", &deletelist);
+
+  add_com ("printf", class_vars, printf_command,
+       "printf \"printf format string\", arg1, arg2, arg3, ..., argn\n\
+This is useful for formatted output in user-defined commands.");
+  add_com ("output", class_vars, output_command,
+          "Like \"print\" but don't put in value history and don't print newline.\n\
+This is useful in user-defined commands.");
+
+  add_prefix_cmd ("set", class_vars, set_command,
+"Perform an assignment VAR = EXP.\n\
+You must type the \"=\".  VAR may be a debugger \"convenience\" variable\n\
+(names starting with $), a register (a few standard names starting with $),\n\
+or an actual variable in the program being debugged.  EXP is any expression.\n\
+Use \"set variable\" for variables with names identical to set subcommands.\n\
+\nWith a subcommand, this command modifies parts of the gdb environment.\n\
+You can see these environment settings with the \"show\" command.",
+                  &setlist, "set ", 1, &cmdlist);
+
+  /* "call" is the same as "set", but handy for dbx users to call fns. */
+  add_com ("call", class_vars, call_command,
+          "Call a function in the inferior process.\n\
+The argument is the function name and arguments, in standard C notation.\n\
+The result is printed and saved in the value history, if it is not void.");
+
+  add_cmd ("variable", class_vars, set_command,
+           "Perform an assignment VAR = EXP.\n\
+You must type the \"=\".  VAR may be a debugger \"convenience\" variable\n\
+(names starting with $), a register (a few standard names starting with $),\n\
+or an actual variable in the program being debugged.  EXP is any expression.\n\
+This may usually be abbreviated to simply \"set\".",
+           &setlist);
+
+  add_com ("print", class_vars, print_command,
+          concat ("Print value of expression EXP.\n\
+Variables accessible are those of the lexical environment of the selected\n\
+stack frame, plus all those whose scope is global or an entire file.\n\
+\n\
+$NUM gets previous value number NUM.  $ and $$ are the last two values.\n\
+$$NUM refers to NUM'th value back from the last one.\n\
+Names starting with $ refer to registers (with the values they would have\n\
+if the program were to return to the stack frame now selected, restoring\n\
+all registers saved by frames farther in) or else to debugger\n\
+\"convenience\" variables (any such name not a known register).\n\
+Use assignment expressions to give values to convenience variables.\n",
+                  "\n\
+{TYPE}ADREXP refers to a datum of data type TYPE, located at address ADREXP.\n\
+@ is a binary operator for treating consecutive data objects\n\
+anywhere in memory as an array.  FOO@NUM gives an array whose first\n\
+element is FOO, whose second element is stored in the space following\n\
+where FOO is stored, etc.  FOO must be an expression whose value\n\
+resides in memory.\n",
+                  "\n\
+EXP may be preceded with /FMT, where FMT is a format letter\n\
+but no count or size letter (see \"x\" command)."));
+  add_com_alias ("p", "print", class_vars, 1);
+
+  add_com ("inspect", class_vars, inspect_command,
+"Same as \"print\" command, except that if you are running in the epoch\n\
+environment, the value is printed in its own window.");
+}
diff --git a/gdb/remote-sa.m68k.shar b/gdb/remote-sa.m68k.shar
new file mode 100755 (executable)
index 0000000..aeb76e5
--- /dev/null
@@ -0,0 +1,893 @@
+# This is a shell archive.  Remove anything before this line,
+# then unpack it by saving it in a file and typing "sh file".
+#
+# Wrapped by Glenn Engel <glenne@labgre> on Mon Jun 12 15:19:20 1989
+#
+# This archive contains:
+#      remcom.c        
+#
+
+LANG=""; export LANG
+PATH=/bin:/usr/bin:$PATH; export PATH
+
+echo x - remcom.c
+cat >remcom.c <<'@EOF'
+
+/****************************************************************************
+
+               THIS SOFTWARE IS NOT COPYRIGHTED  
+   
+   HP offers the following for use in the public domain.  HP makes no
+   warranty with regard to the software or it's performance and the 
+   user accepts the software "AS IS" with all faults.
+
+   HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
+   TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+****************************************************************************/
+
+/****************************************************************************
+ *  $Header$                   
+ *
+ *  $Module name: remcom.c $  
+ *  $Revision$
+ *  $Date$
+ *  $Contributor:     Lake Stevens Instrument Division$
+ *  
+ *  $Description:     low level support for gdb debugger. $
+ *
+ *  $Considerations:  only works on target hardware $
+ *
+ *  $Written by:      Glenn Engel $
+ *  $ModuleState:     Experimental $ 
+ *
+ *  $NOTES:           See Below $
+ * 
+ *  To enable debugger support, two things need to happen.  One, a
+ *  call to set_debug_traps() is necessary in order to allow any breakpoints
+ *  or error conditions to be properly intercepted and reported to gdb.
+ *  Two, a breakpoint needs to be generated to begin communication.  This
+ *  is most easily accomplished by a call to breakpoint().  Breakpoint()
+ *  simulates a breakpoint by executing a trap #1.
+ *  
+ *  Some explanation is probably necessary to explain how exceptions are
+ *  handled.  When an exception is encountered the 68000 pushes the current
+ *  program counter and status register onto the supervisor stack and then
+ *  transfers execution to a location specified in it's vector table.
+ *  The handlers for the exception vectors are hardwired to jmp to an address
+ *  given by the relation:  (exception - 256) * 6.  These are decending 
+ *  addresses starting from -6, -12, -18, ...  By allowing 6 bytes for
+ *  each entry, a jsr, jmp, bsr, ... can be used to enter the exception 
+ *  handler.  Using a jsr to handle an exception has an added benefit of
+ *  allowing a single handler to service several exceptions and use the
+ *  return address as the key differentiation.  The vector number can be
+ *  computed from the return address by [ exception = (addr + 1530) / 6 ].
+ *  The sole purpose of the routine _catchException is to compute the
+ *  exception number and push it on the stack in place of the return address.
+ *  The external function exceptionHandler() is
+ *  used to attach a specific handler to a specific 68k exception.
+ *  For 68020 machines, the ability to have a return address around just
+ *  so the vector can be determined is not necessary because the '020 pushes an
+ *  extra word onto the stack containing the vector offset
+ * 
+ *  Because gdb will sometimes write to the stack area to execute function
+ *  calls, this program cannot rely on using the supervisor stack so it
+ *  uses it's own stack area reserved in the int array remcomStack.  
+ * 
+ *************
+ *
+ *    The following gdb commands are supported:
+ * 
+ * command          function                               Return value
+ * 
+ *    g             return the value of the CPU registers  hex data or ENN
+ *    G             set the value of the CPU registers     OK or ENN
+ * 
+ *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
+ *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
+ * 
+ *    c             Resume at current address              SNN   ( signal NN)
+ *    cAA..AA       Continue at address AA..AA             SNN
+ * 
+ *    s             Step one instruction                   SNN
+ *    sAA..AA       Step one instruction from AA..AA       SNN
+ * 
+ *    k             kill
+ *
+ *    ?             What was the last sigval ?             SNN   (signal NN)
+ * 
+ * All commands and responses are sent with a packet which includes a 
+ * checksum.  A packet consists of 
+ * 
+ * $<packet info>#<checksum>.
+ * 
+ * where
+ * <packet info> :: <characters representing the command or response>
+ * <checksum>    :: < two hex digits computed as modulo 256 sum of <packetinfo>>
+ * 
+ * When a packet is received, it is first acknowledged with either '+' or '-'.
+ * '+' indicates a successful transfer.  '-' indicates a failed transfer.
+ * 
+ * Example:
+ * 
+ * Host:                  Reply:
+ * $m0,10#2a               +$00010203040506070809101112131415#42
+ * 
+ ****************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <setjmp.h>
+
+/************************************************************************
+ *
+ * external low-level support routines 
+ */
+typedef void (*ExceptionHook)(int);   /* pointer to function with int parm */
+typedef void (*Function)();           /* pointer to a function */
+
+extern putDebugChar();   /* write a single character      */
+extern getDebugChar();   /* read and return a single char */
+
+extern Function exceptionHandler();  /* assign an exception handler */
+extern ExceptionHook exceptionHook;  /* hook variable for errors/exceptions */
+
+
+/************************************************************************/
+/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
+/* at least NUMREGBYTES*2 are needed for register packets */
+#define BUFMAX 400
+
+static char initialized;  /* boolean flag. != 0 means we've been initialized */
+
+int     remote_debug = 0;
+/*  debug >  0 prints ill-formed commands in valid packets & checksum errors */ 
+
+char hexchars[]="0123456789abcdef";
+
+/* there are 180 bytes of registers on a 68020 w/68881      */
+/* many of the fpa registers are 12 byte (96 bit) registers */
+#define NUMREGBYTES 180
+enum regnames {D0,D1,D2,D3,D4,D5,D6,D7, 
+               A0,A1,A2,A3,A4,A5,A6,A7, 
+               PS,PC,
+               FP0,FP1,FP2,FP3,FP4,FP5,FP6,FP7,
+               FPCONTROL,FPSTATUS,FPIADDR
+              };
+
+typedef struct FrameStruct
+{
+    struct FrameStruct  *previous;
+    int       exceptionPC;      /* pc value when this frame created */
+    int       exceptionVector;  /* cpu vector causing exception     */
+    short     frameSize;        /* size of cpu frame in words       */
+    short     sr;               /* for 68000, this not always sr    */
+    int       pc;
+    short     format;
+    int       fsaveHeader;
+    int       morejunk[0];        /* exception frame, fp save... */
+} Frame;
+
+#define FRAMESIZE 500
+static Frame *lastFrame;
+static int   frameStack[FRAMESIZE];
+
+/*
+ * these should not be static cuz they can be used outside this module
+ */
+int registers[NUMREGBYTES/4];
+int superStack;
+
+static int remcomStack[400];
+static int* stackPtr = &remcomStack[399];
+
+/*
+ * In many cases, the system will want to continue exception processing
+ * when a continue command is given.  
+ * oldExceptionHook is a function to invoke in this case.
+ */
+
+static ExceptionHook oldExceptionHook;
+
+/* the size of the exception stack on the 68020 varies with the type of
+ * exception.  The following table is the number of WORDS used
+ * for each exception format.
+ */
+static short exceptionSize[] = { 4,4,6,4,4,4,4,4,29,10,16,46,4,4,4,4 };
+
+/************* jump buffer used for setjmp/longjmp **************************/
+jmp_buf env;
+
+/***************************  ASSEMBLY CODE MACROS *************************/
+/*                                                                        */
+
+#ifdef __HAVE_68881__
+/* do an fsave, then remember the address to begin a restore from */
+#define SAVE_FP_REGS()    asm(" fsave   a0@-");                \
+                         asm(" fmovemx fp0-fp7,_registers+72");        \
+                         asm(" fmoveml fpcr/fpsr/fpi,_registers+168"); 
+#define RESTORE_FP_REGS() asm(" fmoveml _registers+168,fpcr/fpsr/fpi"); \
+                         asm(" fmovemx _registers+72,fp0-fp7");        \
+                         asm(" frestore a0@+");
+#else
+#define SAVE_FP_REGS()
+#define RESTORE_FP_REGS()
+#endif /* __HAVE_68881__ */
+
+asm("
+.text
+.globl _return_to_super
+_return_to_super:
+        movel   _registers+60,sp /* get new stack pointer */        
+        movel   _lastFrame,a0   /* get last frame info  */              
+        bra     return_to_any
+
+.globl _return_to_user
+_return_to_user:
+        movel   _registers+60,a0 /* get usp */                          
+        movel   a0,usp           /* set usp */                         
+        movel   _superStack,sp  /* get original stack pointer */        
+
+return_to_any:
+        movel   _lastFrame,a0   /* get last frame info  */              
+        movel   a0@+,_lastFrame /* link in previous frame     */        
+        addql   #8,a0           /* skip over pc, vector#*/              
+        movew   a0@+,d0         /* get # of words in cpu frame */       
+        addw    d0,a0           /* point to end of data        */       
+        addw    d0,a0           /* point to end of data        */       
+        movel   a0,a1                                                   
+#                                                                       
+# copy the stack frame                                                  
+        subql   #1,d0                                                   
+copyUserLoop:                                                               
+        movew   a1@-,sp@-                                               
+        dbf     d0,copyUserLoop                                             
+");                                                                     
+        RESTORE_FP_REGS()                                              
+   asm("   moveml  _registers,d0-d7/a0-a6");                           
+   asm("   rte");  /* pop and go! */                                    
+
+#define DISABLE_INTERRUPTS()   asm("         oriw   #0x0700,sr");
+#define BREAKPOINT() asm("   trap #1");
+
+/* this function is called immediately when a level 7 interrupt occurs */
+/* if the previous interrupt level was 7 then we're already servicing  */
+/* this interrupt and an rte is in order to return to the debugger.    */
+/* For the 68000, the offset for sr is 6 due to the jsr return address */
+asm("
+.text
+.globl __debug_level7
+__debug_level7:
+       movew   d0,sp@-");
+#ifdef mc68020
+asm("  movew   sp@(2),d0");
+#else
+asm("  movew   sp@(6),d0");
+#endif
+asm("  andiw   #0x700,d0
+       cmpiw   #0x700,d0
+       beq     _already7
+        movew   sp@+,d0        
+        bra     __catchException
+_already7:
+       movew   sp@+,d0");
+#ifndef mc68020
+asm("  lea     sp@(4),sp");     /* pull off 68000 return address */
+#endif
+asm("  rte");
+
+extern void _catchException();
+
+#ifdef mc68020
+/* This function is called when a 68020 exception occurs.  It saves
+ * all the cpu and fpcp regs in the _registers array, creates a frame on a
+ * linked list of frames which has the cpu and fpcp stack frames needed
+ * to properly restore the context of these processors, and invokes
+ * an exception handler (remcom_handler).
+ *
+ * stack on entry:                       stack on exit:
+ *   N bytes of junk                     exception # MSWord
+ *   Exception Format Word               exception # MSWord
+ *   Program counter LSWord              
+ *   Program counter MSWord             
+ *   Status Register                    
+ *                                       
+ *                                       
+ */
+asm(" 
+.text
+.globl __catchException
+__catchException:");
+DISABLE_INTERRUPTS();
+asm("
+        moveml  d0-d7/a0-a6,_registers /* save registers        */
+       movel   _lastFrame,a0   /* last frame pointer */
+");
+SAVE_FP_REGS();        
+asm("
+       lea     _registers,a5   /* get address of registers     */
+        movew   sp@,d1          /* get status register          */
+        movew   d1,a5@(66)      /* save sr                     */      
+       movel   sp@(2),a4       /* save pc in a4 for later use  */
+        movel   a4,a5@(68)      /* save pc in _regisers[]              */
+
+#
+# figure out how many bytes in the stack frame
+       movew   sp@(6),d0       /* get '020 exception format    */
+        movew   d0,d2           /* make a copy of format word   */
+        andiw   #0xf000,d0      /* mask off format type         */
+        rolw    #5,d0           /* rotate into the low byte *2  */
+        lea     _exceptionSize,a1   
+        addw    d0,a1           /* index into the table         */
+       movew   a1@,d0          /* get number of words in frame */
+        movew   d0,d3           /* save it                      */
+        subw    d0,a0          /* adjust save pointer          */
+        subw    d0,a0          /* adjust save pointer(bytes)   */
+       movel   a0,a1           /* copy save pointer            */
+       subql   #1,d0           /* predecrement loop counter    */
+#
+# copy the frame
+saveFrameLoop:
+       movew   sp@+,a1@+
+       dbf     d0,saveFrameLoop
+#
+# now that the stack has been clenaed,
+# save the a7 in use at time of exception
+        movel   sp,_superStack  /* save supervisor sp           */
+        andiw   #0x2000,d1      /* were we in supervisor mode ? */
+        beq     userMode       
+        movel   a7,a5@(60)      /* save a7                  */
+        bra     a7saveDone
+userMode:  
+       movel   usp,a1          
+        movel   a1,a5@(60)      /* save user stack pointer     */
+a7saveDone:
+
+#
+# save size of frame
+        movew   d3,a0@-
+
+#
+# compute exception number
+       andl    #0xfff,d2       /* mask off vector offset       */
+       lsrw    #2,d2           /* divide by 4 to get vect num  */
+        movel   d2,a0@-         /* save it                      */
+#
+# save pc causing exception
+        movel   a4,a0@-
+#
+# save old frame link and set the new value
+       movel   _lastFrame,a1   /* last frame pointer */
+       movel   a1,a0@-         /* save pointer to prev frame   */
+        movel   a0,_lastFrame
+
+        movel   d2,sp@-                /* push exception num           */
+       movel   _exceptionHook,a0  /* get address of handler */
+        jbsr    a0@             /* and call it */
+        jmp     __returnFromException     /* now, return        */
+");
+#else /* mc68000 */
+/* This function is called when an exception occurs.  It translates the
+ * return address found on the stack into an exception vector # which
+ * is then handled by either handle_exception or a system handler.
+ * _catchException provides a front end for both.  
+ *
+ * stack on entry:                       stack on exit:
+ *   Program counter MSWord              exception # MSWord 
+ *   Program counter LSWord              exception # MSWord
+ *   Status Register                     
+ *   Return Address  MSWord              
+ *   Return Address  LSWord             
+ */
+asm("
+.text
+.globl __catchException
+__catchException:");
+DISABLE_INTERRUPTS();
+asm("
+        moveml d0-d7/a0-a6,_registers  /* save registers               */
+       movel   _lastFrame,a0   /* last frame pointer */
+");
+SAVE_FP_REGS();        
+asm("
+        lea     _registers,a5   /* get address of registers     */
+        movel   sp@+,d2         /* pop return address           */
+       addl    #1530,d2        /* convert return addr to       */
+       divs    #6,d2           /*  exception number            */
+       extl    d2   
+
+        moveql  #3,d3           /* assume a three word frame     */
+
+        cmpiw   #3,d2           /* bus error or address error ? */
+        bgt     normal          /* if >3 then normal error      */
+        movel   sp@+,a0@-       /* copy error info to frame buff*/
+        movel   sp@+,a0@-       /* these are never used         */
+        moveql  #7,d3           /* this is a 7 word frame       */
+     
+normal:   
+       movew   sp@+,d1         /* pop status register          */
+        movel   sp@+,a4         /* pop program counter          */
+        movew   d1,a5@(66)      /* save sr                     */      
+        movel   a4,a5@(68)      /* save pc in _regisers[]              */
+        movel   a4,a0@-         /* copy pc to frame buffer      */
+       movew   d1,a0@-         /* copy sr to frame buffer      */
+
+        movel   sp,_superStack  /* save supervisor sp          */
+
+        andiw   #0x2000,d1      /* were we in supervisor mode ? */
+        beq     userMode       
+        movel   a7,a5@(60)      /* save a7                  */
+        bra     saveDone             
+userMode:
+        movel   usp,a1         /* save user stack pointer      */
+        movel   a1,a5@(60)      /* save user stack pointer     */
+saveDone:
+
+        movew   d3,a0@-         /* push frame size in words     */
+        movel   d2,a0@-         /* push vector number           */
+        movel   a4,a0@-         /* push exception pc            */
+
+#
+# save old frame link and set the new value
+       movel   _lastFrame,a1   /* last frame pointer */
+       movel   a1,a0@-         /* save pointer to prev frame   */
+        movel   a0,_lastFrame
+
+        movel   d2,sp@-                /* push exception num           */
+       movel   _exceptionHook,a0  /* get address of handler */
+        jbsr    a0@             /* and call it */
+        jmp     __returnFromException     /* now, return        */
+");
+#endif
+
+
+/*
+ * remcomHandler is a front end for handle_exception.  It moves the
+ * stack pointer into an area reserved for debugger use in case the
+ * breakpoint happened in supervisor mode.
+ */
+asm("_remcomHandler:");
+asm("           addl    #4,sp");        /* pop off return address     */
+asm("           movel   sp@+,d0");      /* get the exception number   */
+asm("          movel   _stackPtr,sp"); /* move to remcom stack area  */
+asm("          movel   d0,sp@-");      /* push exception onto stack  */
+asm("          jbsr    _handle_exception");    /* this never returns */
+asm("           rts");                  /* return */
+
+void _returnFromException( Frame *frame )
+{
+    /* if no existing frame, dummy one up */
+    if (! frame)
+    {
+        frame = lastFrame -1;
+        frame->frameSize = 4;
+        frame->format = 0;
+        frame->fsaveHeader = 0;
+        frame->previous = lastFrame;
+    }
+
+#ifndef mc68020
+    /* a 68000 cannot use the internal info pushed onto a bus error
+     * or address error frame when doing an RTE so don't put this info
+     * onto the stack or the stack will creep every time this happens.
+     */
+    frame->frameSize=3;
+#endif
+
+    /* throw away any frames in the list after this frame */
+    lastFrame = frame;
+
+    frame->sr = registers[(int) PS];
+    frame->pc = registers[(int) PC];
+
+    if (registers[(int) PS] & 0x2000)
+    { 
+        /* return to supervisor mode... */
+        return_to_super();
+    }
+    else
+    { /* return to user mode */
+        return_to_user();
+    }
+}
+
+int hex(ch)
+char ch;
+{
+  if ((ch >= 'a') && (ch <= 'f')) return (ch-'a'+10);
+  if ((ch >= '0') && (ch <= '9')) return (ch-'0');
+  return (0);
+}
+
+
+/* scan for the sequence $<data>#<checksum>     */
+void getpacket(buffer)
+char * buffer;
+{
+  unsigned char checksum;
+  unsigned char xmitcsum;
+  int  i;
+  int  count;
+  char ch;
+  
+  do {
+    /* wait around for the start character, ignore all other characters */
+    while ((ch = getDebugChar()) != '$'); 
+    checksum = 0;
+    count = 0;
+    
+    /* now, read until a # or end of buffer is found */
+    while (count < BUFMAX) {
+      ch = getDebugChar();
+      if (ch == '#') break;
+      checksum = checksum + ch;
+      buffer[count] = ch;
+      count = count + 1;
+      }
+    buffer[count] = 0;
+
+    if (ch == '#') {
+      xmitcsum = hex(getDebugChar()) << 4;
+      xmitcsum += hex(getDebugChar());
+      if ((remote_debug ) && (checksum != xmitcsum)) {
+        fprintf(stderr,"bad checksum.  My count = 0x%x, sent=0x%x. buf=%s\n",
+                                                    checksum,xmitcsum,buffer);
+      }
+      
+      if (checksum != xmitcsum) putDebugChar('-');  /* failed checksum */ 
+      else {
+        putDebugChar('+');  /* successful transfer */
+        /* if a sequence char is present, reply the sequence ID */
+        if (buffer[2] == ':') {
+           putDebugChar( buffer[0] );
+           putDebugChar( buffer[1] );
+           /* remove sequence chars from buffer */
+           count = strlen(buffer);
+           for (i=3; i <= count; i++) buffer[i-3] = buffer[i];
+        } 
+      } 
+    } 
+  } while (checksum != xmitcsum);
+  
+}
+
+/* send the packet in buffer.  The host get's one chance to read it.  
+   This routine does not wait for a positive acknowledge.  */
+
+
+void putpacket(buffer)
+char * buffer;
+{
+  unsigned char checksum;
+  int  count;
+  char ch;
+  
+  /*  $<packet info>#<checksum>. */
+  do {
+  putDebugChar('$');
+  checksum = 0;
+  count    = 0;
+  
+  while (ch=buffer[count]) {
+    if (! putDebugChar(ch)) return;
+    checksum += ch;
+    count += 1;
+  }
+  
+  putDebugChar('#');
+  putDebugChar(hexchars[checksum >> 4]);
+  putDebugChar(hexchars[checksum % 16]);
+
+  } while (1 == 0);  /* (getDebugChar() != '+'); */
+  
+}
+
+static char  inbuffer[BUFMAX];
+static char  outbuffer[BUFMAX];
+static short error;
+
+
+void debug_error(format, parm)
+char * format;
+char * parm;
+{
+  if (remote_debug) fprintf(stderr,format,parm);
+}
+
+/* convert the memory pointed to by mem into hex, placing result in buf */
+/* return a pointer to the last char put in buf (null) */
+char* mem2hex(mem, buf, count)
+char* mem;
+char* buf;
+int   count;
+{
+      int i;
+      unsigned char ch;
+      for (i=0;i<count;i++) {
+          ch = *mem++;
+          *buf++ = hexchars[ch >> 4];
+          *buf++ = hexchars[ch % 16];
+      }
+      *buf = 0; 
+      return(buf);
+}
+
+/* convert the hex array pointed to by buf into binary to be placed in mem */
+/* return a pointer to the character AFTER the last byte written */
+char* hex2mem(buf, mem, count)
+char* buf;
+char* mem;
+int   count;
+{
+      int i;
+      unsigned char ch;
+      for (i=0;i<count;i++) {
+          ch = hex(*buf++) << 4;
+          ch = ch + hex(*buf++);
+          *mem++ = ch;
+      }
+      return(mem);
+}
+
+/* a bus error has occurred, perform a longjmp
+   to return execution and allow handling of the error */
+
+void handle_buserror()
+{
+  longjmp(env,1);
+}
+
+/* this function takes the 68000 exception number and attempts to 
+   translate this number into a unix compatible signal value */
+int computeSignal( exceptionVector )
+int exceptionVector;
+{
+  int sigval;
+  switch (exceptionVector) {
+    case 2 : sigval = 10; break; /* bus error           */
+    case 3 : sigval = 10; break; /* address error       */
+    case 4 : sigval = 4;  break; /* illegal instruction */
+    case 5 : sigval = 8;  break; /* zero divide         */
+    case 6 : sigval = 16; break; /* chk instruction     */
+    case 7 : sigval = 16; break; /* trapv instruction   */
+    case 8 : sigval = 11; break; /* privilege violation */
+    case 9 : sigval = 5;  break; /* trace trap          */
+    case 10: sigval = 4;  break; /* line 1010 emulator  */
+    case 11: sigval = 4;  break; /* line 1111 emulator  */
+    case 31: sigval = 2;  break; /* interrupt           */
+    case 33: sigval = 5;  break; /* breakpoint          */
+    case 40: sigval = 8;  break; /* floating point err  */
+    case 48: sigval = 8;  break; /* floating point err  */
+    case 49: sigval = 8;  break; /* floating point err  */
+    case 50: sigval = 8;  break; /* zero divide         */
+    case 51: sigval = 8;  break; /* underflow           */
+    case 52: sigval = 8;  break; /* operand error       */
+    case 53: sigval = 8;  break; /* overflow            */
+    case 54: sigval = 8;  break; /* NAN                 */
+    default: 
+      sigval = 7;         /* "software generated"*/
+  }
+  return (sigval);
+}
+
+/*
+ * This function does all command procesing for interfacing to gdb.
+ */
+void handle_exception(int exceptionVector)
+{
+  int    sigval;
+  int    addr, length;
+  char * ptr;
+  int    newPC;
+  Frame  *frame;
+  
+  if (remote_debug) printf("vector=%d, sr=0x%x, pc=0x%x\n", 
+                           exceptionVector,
+                           registers[ PS ], 
+                           registers[ PC ]);
+
+  /* reply to host that an exception has occurred */
+  sigval = computeSignal( exceptionVector );
+  sprintf(outbuffer,"S%02x",sigval);
+  putpacket(outbuffer); 
+
+  while (1==1) { 
+    error = 0;
+    outbuffer[0] = 0;
+    getpacket(inbuffer);
+    switch (inbuffer[0]) {
+      case '?' : sprintf(outbuffer,"S%02x",sigval);
+                 break; 
+      case 'd' : remote_debug = !(remote_debug);  /* toggle debug flag */
+                 break; 
+      case 'g' : /* return the value of the CPU registers */
+                mem2hex((char*) registers, outbuffer, NUMREGBYTES);
+                break;
+      case 'G' : /* set the value of the CPU registers - return OK */
+                hex2mem(&inbuffer[1], (char*) registers, NUMREGBYTES);
+                strcpy(outbuffer,"OK");
+                break;
+      
+      /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
+      case 'm' : 
+               if (setjmp(env) == 0) {
+                   exceptionHandler(2,handle_buserror); 
+
+                   if (2 == sscanf(&inbuffer[1],"%x,%x",&addr,&length)) {
+                     mem2hex((char*) addr, outbuffer, length);
+                   }
+                   else {
+                     strcpy(outbuffer,"E01");
+                     debug_error("malformed read memory command: %s",inbuffer);
+                     }     
+                } 
+               else {
+                 exceptionHandler(2,_catchException);   
+                 strcpy(outbuffer,"E03");
+                 debug_error("bus error");
+                 }     
+                
+               /* restore handler for bus error */
+               exceptionHandler(2,_catchException);   
+               break;
+      
+      /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
+      case 'M' : 
+               if (setjmp(env) == 0) {
+                   exceptionHandler(2,handle_buserror); 
+
+                   if (2 == sscanf(&inbuffer[1],"%x,%x:",&addr,&length)) {
+                     ptr = strchr(inbuffer,':');
+                     ptr += 1; /* point 1 past the colon */
+                     hex2mem(ptr, (char*) addr, length);
+                     strcpy(outbuffer,"OK");
+                   }
+                   else {
+                     strcpy(outbuffer,"E02");
+                     debug_error("malformed write memory command: %s",inbuffer);
+                     }     
+                } 
+               else {
+                 exceptionHandler(2,_catchException);   
+                 strcpy(outbuffer,"E03");
+                 debug_error("bus error");
+                 }     
+                break;
+     
+     /* cAA..AA    Continue at address AA..AA(optional) */
+     /* sAA..AA   Step one instruction from AA..AA(optional) */
+     case 'c' : 
+     case 's' : 
+          /* try to read optional parameter, addr unchanged if no parm */
+          if (1 == sscanf(&inbuffer[1],"%x",&registers[ PC ])); 
+          newPC = registers[ PC];
+          
+          /* clear the trace bit */
+          registers[ PS ] &= 0x7fff;
+          
+          /* set the trace bit if we're stepping */
+          if (inbuffer[0] == 's') registers[ PS ] |= 0x8000;
+          
+          /*
+           * look for newPC in the linked list of exception frames.
+           * if it is found, use the old frame it.  otherwise,
+           * fake up a dummy frame in returnFromException().
+           */
+          if (remote_debug) printf("new pc = 0x%x\n",newPC);
+          frame = lastFrame;
+          while (frame)
+          {
+              if (remote_debug)
+                  printf("frame at 0x%x has pc=0x%x, except#=%d\n",
+                         frame,frame->exceptionPC,
+                         frame->exceptionVector);
+              if (frame->exceptionPC == newPC) break;  /* bingo! a match */
+              /*
+               * for a breakpoint instruction, the saved pc may
+               * be off by two due to re-executing the instruction
+               * replaced by the trap instruction.  Check for this.
+               */
+              if ((frame->exceptionVector == 33) &&
+                  (frame->exceptionPC == (newPC+2))) break;
+              frame = frame->previous;
+          }
+          
+          /*
+           * If we found a match for the PC AND we are not returning
+           * as a result of a breakpoint (33),
+           * trace exception (9), nmi (31), jmp to
+           * the old exception handler as if this code never ran.
+           */
+          if (frame) 
+          {
+              if ((frame->exceptionVector != 9)  && 
+                  (frame->exceptionVector != 31) && 
+                  (frame->exceptionVector != 33))
+              { 
+                  /*
+                   * invoke the previous handler.
+                   */
+                  if (oldExceptionHook)
+                      (*oldExceptionHook) (frame->exceptionVector);
+                  newPC = registers[ PC ];    /* pc may have changed  */
+                  if (newPC != frame->exceptionPC)
+                  {
+                      if (remote_debug)
+                          printf("frame at 0x%x has pc=0x%x, except#=%d\n",
+                                 frame,frame->exceptionPC,
+                                 frame->exceptionVector);
+                      /* dispose of this frame, we're skipping it (longjump?)*/
+                      lastFrame = frame->previous;
+                      frame = (Frame *) 0;
+                  }
+              }
+          }         
+
+          _returnFromException( frame );
+
+          break;
+          
+      /* kill the program */
+      case 'k' :  /* do nothing */
+                break;
+      } /* switch */ 
+    
+    /* reply to the request */
+    putpacket(outbuffer); 
+    }
+}
+
+
+/* this function is used to set up exception handlers for tracing and 
+   breakpoints */
+void set_debug_traps()
+{
+extern void _debug_level7();
+extern void remcomHandler();
+int exception;
+
+  for (exception = 2; exception <= 23; exception++)
+      exceptionHandler(exception,_catchException);   
+
+  /* level 7 interrupt              */
+  exceptionHandler(31,_debug_level7);    
+  
+  /* breakpoint exception (trap #1) */
+  exceptionHandler(33,_catchException);
+  
+  /* floating point error (trap #8) */
+  exceptionHandler(40,_catchException);
+  
+  /* 48 to 54 are floating point coprocessor errors */
+  for (exception = 48; exception <= 54; exception++)
+      exceptionHandler(exception,_catchException);   
+
+  if (oldExceptionHook != remcomHandler)
+  {
+      oldExceptionHook = exceptionHook;
+      exceptionHook    = remcomHandler;
+  }
+  
+  initialized = 1;
+
+  lastFrame = (Frame *) &frameStack[FRAMESIZE-1];
+  lastFrame->previous = (Frame *) 0;
+}
+
+/* This function will generate a breakpoint exception.  It is used at the
+   beginning of a program to sync up with a debugger and can be used
+   otherwise as a quick means to stop program execution and "break" into
+   the debugger. */
+   
+void breakpoint()
+{
+  if (initialized) BREAKPOINT();
+}
+
+@EOF
+
+chmod 444 remcom.c
+
+exit 0
+
diff --git a/gdb/remote.c b/gdb/remote.c
new file mode 100644 (file)
index 0000000..9ff5650
--- /dev/null
@@ -0,0 +1,829 @@
+/* Memory-access and commands for inferior process, for GDB.
+   Copyright (C) 1988-1991 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.  */
+
+/* Remote communication protocol.
+   All values are encoded in ascii hex digits.
+
+       Request         Packet
+
+       read registers  g
+       reply           XX....X         Each byte of register data
+                                       is described by two hex digits.
+                                       Registers are in the internal order
+                                       for GDB, and the bytes in a register
+                                       are in the same order the machine uses.
+                       or ENN          for an error.
+
+       write regs      GXX..XX         Each byte of register data
+                                       is described by two hex digits.
+       reply           OK              for success
+                       ENN             for an error
+
+       read mem        mAA..AA,LLLL    AA..AA is address, LLLL is length.
+       reply           XX..XX          XX..XX is mem contents
+                       or ENN          NN is errno
+
+       write mem       MAA..AA,LLLL:XX..XX
+                                       AA..AA is address,
+                                       LLLL is number of bytes,
+                                       XX..XX is data
+       reply           OK              for success
+                       ENN             for an error
+
+       cont            cAA..AA         AA..AA is address to resume
+                                       If AA..AA is omitted,
+                                       resume at same address.
+
+       step            sAA..AA         AA..AA is address to resume
+                                       If AA..AA is omitted,
+                                       resume at same address.
+
+       last signal     ?               Reply the current reason for stopping.
+                                        This is the same reply as is generated
+                                       for step or cont : SAA where AA is the
+                                       signal number.
+
+       There is no immediate reply to step or cont.
+       The reply comes when the machine stops.
+       It is           SAA             AA is the "signal number"
+
+       kill req        k
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include "defs.h"
+#include "param.h"
+#include "frame.h"
+#include "inferior.h"
+#include "target.h"
+#include "wait.h"
+#include "terminal.h"
+
+#ifdef USG
+#include <sys/types.h>
+#endif
+
+#include <signal.h>
+
+extern int memory_insert_breakpoint ();
+extern int memory_remove_breakpoint ();
+extern void add_syms_addr_command ();
+extern struct value *call_function_by_hand();
+extern void start_remote ();
+
+extern struct target_ops remote_ops;   /* Forward decl */
+
+static int kiodebug;
+static int timeout = 5;
+
+#if 0
+int icache;
+#endif
+
+/* Descriptor for I/O to remote machine.  Initialize it to -1 so that
+   remote_open knows that we don't have a file open when the program
+   starts.  */
+int remote_desc = -1;
+
+#define        PBUFSIZ 400
+
+/* Maximum number of bytes to read/write at once.  The value here
+   is chosen to fill up a packet (the headers account for the 32).  */
+#define MAXBUFBYTES ((PBUFSIZ-32)/2)
+
+static void remote_send ();
+static void putpkt ();
+static void getpkt ();
+#if 0
+static void dcache_flush ();
+#endif
+
+\f
+/* Called when SIGALRM signal sent due to alarm() timeout.  */
+#ifndef HAVE_TERMIO
+void
+remote_timer ()
+{
+  if (kiodebug)
+    printf ("remote_timer called\n");
+
+  alarm (timeout);
+}
+#endif
+
+/* Initialize remote connection */
+
+void
+remote_start()
+{
+}
+
+/* Clean up connection to a remote debugger.  */
+
+void
+remote_close (quitting)
+     int quitting;
+{
+  if (remote_desc >= 0)
+    close (remote_desc);
+  remote_desc = -1;
+}
+
+/* Open a connection to a remote debugger.
+   NAME is the filename used for communication.  */
+
+void
+remote_open (name, from_tty)
+     char *name;
+     int from_tty;
+{
+  TERMINAL sg;
+
+  if (name == 0)
+    error (
+"To open a remote debug connection, you need to specify what serial\n\
+device is attached to the remote system (e.g. /dev/ttya).");
+
+  remote_close (0);
+
+#if 0
+  dcache_init ();
+#endif
+
+  remote_desc = open (name, O_RDWR);
+  if (remote_desc < 0)
+    perror_with_name (name);
+
+  ioctl (remote_desc, TIOCGETP, &sg);
+#ifdef HAVE_TERMIO
+  sg.c_cc[VMIN] = 0;           /* read with timeout.  */
+  sg.c_cc[VTIME] = timeout * 10;
+  sg.c_lflag &= ~(ICANON | ECHO);
+#else
+  sg.sg_flags = RAW;
+#endif
+  ioctl (remote_desc, TIOCSETP, &sg);
+
+  if (from_tty)
+    printf ("Remote debugging using %s\n", name);
+  push_target (&remote_ops);   /* Switch to using remote target now */
+  start_remote ();             /* Initialize gdb process mechanisms */
+
+#ifndef HAVE_TERMIO
+#ifndef NO_SIGINTERRUPT
+  /* Cause SIGALRM's to make reads fail.  */
+  if (siginterrupt (SIGALRM, 1) != 0)
+    perror ("remote_open: error in siginterrupt");
+#endif
+
+  /* Set up read timeout timer.  */
+  if ((void (*)) signal (SIGALRM, remote_timer) == (void (*)) -1)
+    perror ("remote_open: error in signal");
+#endif
+
+  putpkt ("?");                        /* initiate a query from remote machine */
+}
+
+/* remote_detach()
+   takes a program previously attached to and detaches it.
+   We better not have left any breakpoints
+   in the program or it'll die when it hits one.
+   Close the open connection to the remote debugger.
+   Use this when you want to detach and do something else
+   with your gdb.  */
+
+static void
+remote_detach (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  if (args)
+    error ("Argument given to \"detach\" when remotely debugging.");
+  
+  pop_target ();
+  if (from_tty)
+    printf ("Ending remote debugging.\n");
+}
+
+/* Convert hex digit A to a number.  */
+
+static int
+fromhex (a)
+     int a;
+{
+  if (a >= '0' && a <= '9')
+    return a - '0';
+  else if (a >= 'a' && a <= 'f')
+    return a - 'a' + 10;
+  else
+    error ("Reply contains invalid hex digit");
+  return -1;
+}
+
+/* Convert number NIB to a hex digit.  */
+
+static int
+tohex (nib)
+     int nib;
+{
+  if (nib < 10)
+    return '0'+nib;
+  else
+    return 'a'+nib-10;
+}
+\f
+/* Tell the remote machine to resume.  */
+
+void
+remote_resume (step, siggnal)
+     int step, siggnal;
+{
+  char buf[PBUFSIZ];
+
+  if (siggnal)
+    error ("Can't send signals to a remote system.");
+
+#if 0
+  dcache_flush ();
+#endif
+
+  strcpy (buf, step ? "s": "c");
+
+  putpkt (buf);
+}
+
+/* Wait until the remote machine stops, then return,
+   storing status in STATUS just as `wait' would.  */
+
+int
+remote_wait (status)
+     WAITTYPE *status;
+{
+  unsigned char buf[PBUFSIZ];
+
+  WSETEXIT ((*status), 0);
+  getpkt (buf);
+  if (buf[0] == 'E')
+    error ("Remote failure reply: %s", buf);
+  if (buf[0] != 'S')
+    error ("Invalid remote reply: %s", buf);
+  WSETSTOP ((*status), (((fromhex (buf[1])) << 4) + (fromhex (buf[2]))));
+}
+
+/* Read the remote registers into the block REGS.  */
+
+int
+remote_fetch_registers (regno)
+     int regno;
+{
+  char buf[PBUFSIZ];
+  int i;
+  char *p;
+  char regs[REGISTER_BYTES];
+
+  sprintf (buf, "g");
+  remote_send (buf);
+
+  /* Reply describes registers byte by byte, each byte encoded as two
+     hex characters.  Suck them all up, then supply them to the
+     register cacheing/storage mechanism.  */
+
+  p = buf;
+  for (i = 0; i < REGISTER_BYTES; i++)
+    {
+      if (p[0] == 0 || p[1] == 0)
+       error ("Remote reply is too short: %s", buf);
+      regs[i] = fromhex (p[0]) * 16 + fromhex (p[1]);
+      p += 2;
+    }
+  for (i = 0; i < NUM_REGS; i++)
+    supply_register (i, &regs[REGISTER_BYTE(i)]);
+  return 0;
+}
+
+/* Prepare to store registers.  Since we send them all, we have to
+   read out the ones we don't want to change first.  */
+
+void 
+remote_prepare_to_store ()
+{
+  remote_fetch_registers (-1);
+}
+
+/* Store the remote registers from the contents of the block REGISTERS. 
+   FIXME, eventually just store one register if that's all that is needed.  */
+
+int
+remote_store_registers (regno)
+     int regno;
+{
+  char buf[PBUFSIZ];
+  int i;
+  char *p;
+
+  buf[0] = 'G';
+  
+  /* Command describes registers byte by byte,
+     each byte encoded as two hex characters.  */
+
+  p = buf + 1;
+  for (i = 0; i < REGISTER_BYTES; i++)
+    {
+      *p++ = tohex ((registers[i] >> 4) & 0xf);
+      *p++ = tohex (registers[i] & 0xf);
+    }
+  *p = '\0';
+
+  remote_send (buf);
+  return 0;
+}
+
+#if 0
+/* Read a word from remote address ADDR and return it.
+   This goes through the data cache.  */
+
+int
+remote_fetch_word (addr)
+     CORE_ADDR addr;
+{
+  if (icache)
+    {
+      extern CORE_ADDR text_start, text_end;
+
+      if (addr >= text_start && addr < text_end)
+       {
+         int buffer;
+         xfer_core_file (addr, &buffer, sizeof (int));
+         return buffer;
+       }
+    }
+  return dcache_fetch (addr);
+}
+
+/* Write a word WORD into remote address ADDR.
+   This goes through the data cache.  */
+
+void
+remote_store_word (addr, word)
+     CORE_ADDR addr;
+     int word;
+{
+  dcache_poke (addr, word);
+}
+#endif /* 0 */
+\f
+/* Write memory data directly to the remote machine.
+   This does not inform the data cache; the data cache uses this.
+   MEMADDR is the address in the remote memory space.
+   MYADDR is the address of the buffer in our space.
+   LEN is the number of bytes.  */
+
+void
+remote_write_bytes (memaddr, myaddr, len)
+     CORE_ADDR memaddr;
+     char *myaddr;
+     int len;
+{
+  char buf[PBUFSIZ];
+  int i;
+  char *p;
+
+  if (len > PBUFSIZ / 2 - 20)
+    abort ();
+
+  sprintf (buf, "M%x,%x:", memaddr, len);
+
+  /* Command describes registers byte by byte,
+     each byte encoded as two hex characters.  */
+
+  p = buf + strlen (buf);
+  for (i = 0; i < len; i++)
+    {
+      *p++ = tohex ((myaddr[i] >> 4) & 0xf);
+      *p++ = tohex (myaddr[i] & 0xf);
+    }
+  *p = '\0';
+
+  remote_send (buf);
+}
+
+/* Read memory data directly from the remote machine.
+   This does not use the data cache; the data cache uses this.
+   MEMADDR is the address in the remote memory space.
+   MYADDR is the address of the buffer in our space.
+   LEN is the number of bytes.  */
+
+void
+remote_read_bytes (memaddr, myaddr, len)
+     CORE_ADDR memaddr;
+     char *myaddr;
+     int len;
+{
+  char buf[PBUFSIZ];
+  int i;
+  char *p;
+
+  if (len > PBUFSIZ / 2 - 1)
+    abort ();
+
+  sprintf (buf, "m%x,%x", memaddr, len);
+  remote_send (buf);
+
+  /* Reply describes registers byte by byte,
+     each byte encoded as two hex characters.  */
+
+  p = buf;
+  for (i = 0; i < len; i++)
+    {
+      if (p[0] == 0 || p[1] == 0)
+       error ("Remote reply is too short: %s", buf);
+      myaddr[i] = fromhex (p[0]) * 16 + fromhex (p[1]);
+      p += 2;
+    }
+}
+\f
+/* Read or write LEN bytes from inferior memory at MEMADDR, transferring
+   to or from debugger address MYADDR.  Write to inferior if WRITE is
+   nonzero.  Returns length of data written or read; 0 for error.  */
+
+int
+remote_xfer_inferior_memory(memaddr, myaddr, len, write)
+     CORE_ADDR memaddr;
+     char *myaddr;
+     int len;
+     int write;
+{
+  int origlen = len;
+  int xfersize;
+  while (len > 0)
+    {
+      if (len > MAXBUFBYTES)
+       xfersize = MAXBUFBYTES;
+      else
+       xfersize = len;
+
+      if (write)
+        remote_write_bytes(memaddr, myaddr, xfersize);
+      else
+       remote_read_bytes (memaddr, myaddr, xfersize);
+      memaddr += xfersize;
+      myaddr  += xfersize;
+      len     -= xfersize;
+    }
+  return origlen; /* no error possible */
+}
+
+void
+remote_files_info ()
+{
+  printf ("remote files info missing here.  FIXME.\n");
+}
+\f
+/*
+
+A debug packet whose contents are <data>
+is encapsulated for transmission in the form:
+
+       $ <data> # CSUM1 CSUM2
+
+       <data> must be ASCII alphanumeric and cannot include characters
+       '$' or '#'
+
+       CSUM1 and CSUM2 are ascii hex representation of an 8-bit 
+       checksum of <data>, the most significant nibble is sent first.
+       the hex digits 0-9,a-f are used.
+
+Receiver responds with:
+
+       +       - if CSUM is correct and ready for next packet
+       -       - if CSUM is incorrect
+
+*/
+
+static int
+readchar ()
+{
+  char buf;
+
+  buf = '\0';
+#ifdef HAVE_TERMIO
+  /* termio does the timeout for us.  */
+  read (remote_desc, &buf, 1);
+#else
+  alarm (timeout);
+  read (remote_desc, &buf, 1);
+  alarm (0);
+#endif
+
+  return buf & 0x7f;
+}
+
+/* Send the command in BUF to the remote machine,
+   and read the reply into BUF.
+   Report an error if we get an error reply.  */
+
+static void
+remote_send (buf)
+     char *buf;
+{
+
+  putpkt (buf);
+  getpkt (buf);
+
+  if (buf[0] == 'E')
+    error ("Remote failure reply: %s", buf);
+}
+
+/* Send a packet to the remote machine, with error checking.
+   The data of the packet is in BUF.  */
+
+static void
+putpkt (buf)
+     char *buf;
+{
+  int i;
+  unsigned char csum = 0;
+  char buf2[500];
+  int cnt = strlen (buf);
+  char ch;
+  char *p;
+
+  /* Copy the packet into buffer BUF2, encapsulating it
+     and giving it a checksum.  */
+
+  p = buf2;
+  *p++ = '$';
+
+  for (i = 0; i < cnt; i++)
+    {
+      csum += buf[i];
+      *p++ = buf[i];
+    }
+  *p++ = '#';
+  *p++ = tohex ((csum >> 4) & 0xf);
+  *p++ = tohex (csum & 0xf);
+
+  /* Send it over and over until we get a positive ack.  */
+
+  do {
+    if (kiodebug)
+      {
+       *p = '\0';
+       printf ("Sending packet: %s (%s)\n", buf2, buf);
+      }
+    write (remote_desc, buf2, p - buf2);
+
+    /* read until either a timeout occurs (\0) or '+' is read */
+    do {
+      ch = readchar ();
+    } while ((ch != '+') && (ch != '\0'));
+  } while (ch != '+');
+}
+
+/* Read a packet from the remote machine, with error checking,
+   and store it in BUF.  */
+
+static void
+getpkt (buf)
+     char *buf;
+{
+  char *bp;
+  unsigned char csum;
+  int c;
+  unsigned char c1, c2;
+
+  /* allow immediate quit while reading from device, it could be hung */
+  immediate_quit++;
+
+  while (1)
+    {
+      /* Force csum to be zero here because of possible error retry.  */
+      csum = 0;
+      
+      while ((c = readchar()) != '$');
+
+      bp = buf;
+      while (1)
+       {
+         c = readchar ();
+         if (c == '#')
+           break;
+         *bp++ = c;
+         csum += c;
+       }
+      *bp = 0;
+
+      c1 = fromhex (readchar ());
+      c2 = fromhex (readchar ());
+      if ((csum & 0xff) == (c1 << 4) + c2)
+       break;
+      printf ("Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s\n",
+             (c1 << 4) + c2, csum & 0xff, buf);
+      write (remote_desc, "-", 1);
+    }
+
+  immediate_quit--;
+
+  write (remote_desc, "+", 1);
+
+  if (kiodebug)
+    fprintf (stderr,"Packet received :%s\n", buf);
+}
+\f
+/* The data cache leads to incorrect results because it doesn't know about
+   volatile variables, thus making it impossible to debug functions which
+   use hardware registers.  Therefore it is #if 0'd out.  Effect on
+   performance is some, for backtraces of functions with a few
+   arguments each.  For functions with many arguments, the stack
+   frames don't fit in the cache blocks, which makes the cache less
+   helpful.  Disabling the cache is a big performance win for fetching
+   large structures, because the cache code fetched data in 16-byte
+   chunks.  */
+#if 0
+/* The data cache records all the data read from the remote machine
+   since the last time it stopped.
+
+   Each cache block holds 16 bytes of data
+   starting at a multiple-of-16 address.  */
+
+#define DCACHE_SIZE 64         /* Number of cache blocks */
+
+struct dcache_block {
+       struct dcache_block *next, *last;
+       unsigned int addr;      /* Address for which data is recorded.  */
+       int data[4];
+};
+
+struct dcache_block dcache_free, dcache_valid;
+
+/* Free all the data cache blocks, thus discarding all cached data.  */ 
+
+static void
+dcache_flush ()
+{
+  register struct dcache_block *db;
+
+  while ((db = dcache_valid.next) != &dcache_valid)
+    {
+      remque (db);
+      insque (db, &dcache_free);
+    }
+}
+
+/*
+ * If addr is present in the dcache, return the address of the block 
+ * containing it.
+ */
+
+struct dcache_block *
+dcache_hit (addr)
+{
+  register struct dcache_block *db;
+
+  if (addr & 3)
+    abort ();
+
+  /* Search all cache blocks for one that is at this address.  */
+  db = dcache_valid.next;
+  while (db != &dcache_valid)
+    {
+      if ((addr & 0xfffffff0) == db->addr)
+       return db;
+      db = db->next;
+    }
+  return NULL;
+}
+
+/*  Return the int data at address ADDR in dcache block DC.  */
+
+int
+dcache_value (db, addr)
+     struct dcache_block *db;
+     unsigned int addr;
+{
+  if (addr & 3)
+    abort ();
+  return (db->data[(addr>>2)&3]);
+}
+
+/* Get a free cache block, put it on the valid list,
+   and return its address.  The caller should store into the block
+   the address and data that it describes.  */
+
+struct dcache_block *
+dcache_alloc ()
+{
+  register struct dcache_block *db;
+
+  if ((db = dcache_free.next) == &dcache_free)
+    /* If we can't get one from the free list, take last valid */
+    db = dcache_valid.last;
+
+  remque (db);
+  insque (db, &dcache_valid);
+  return (db);
+}
+
+/* Return the contents of the word at address ADDR in the remote machine,
+   using the data cache.  */
+
+int
+dcache_fetch (addr)
+     CORE_ADDR addr;
+{
+  register struct dcache_block *db;
+
+  db = dcache_hit (addr);
+  if (db == 0)
+    {
+      db = dcache_alloc ();
+      remote_read_bytes (addr & ~0xf, db->data, 16);
+      db->addr = addr & ~0xf;
+    }
+  return (dcache_value (db, addr));
+}
+
+/* Write the word at ADDR both in the data cache and in the remote machine.  */
+
+dcache_poke (addr, data)
+     CORE_ADDR addr;
+     int data;
+{
+  register struct dcache_block *db;
+
+  /* First make sure the word is IN the cache.  DB is its cache block.  */
+  db = dcache_hit (addr);
+  if (db == 0)
+    {
+      db = dcache_alloc ();
+      remote_read_bytes (addr & ~0xf, db->data, 16);
+      db->addr = addr & ~0xf;
+    }
+
+  /* Modify the word in the cache.  */
+  db->data[(addr>>2)&3] = data;
+
+  /* Send the changed word.  */
+  remote_write_bytes (addr, &data, 4);
+}
+
+/* Initialize the data cache.  */
+
+dcache_init ()
+{
+  register i;
+  register struct dcache_block *db;
+
+  db = (struct dcache_block *) xmalloc (sizeof (struct dcache_block) * 
+                                       DCACHE_SIZE);
+  dcache_free.next = dcache_free.last = &dcache_free;
+  dcache_valid.next = dcache_valid.last = &dcache_valid;
+  for (i=0;i<DCACHE_SIZE;i++,db++)
+    insque (db, &dcache_free);
+}
+#endif /* 0 */
+
+/* Define the target subroutine names */
+
+struct target_ops remote_ops = {
+       "remote", "Remote serial target in gdb-specific protocol",
+       remote_open, remote_close,
+       0, remote_detach, remote_resume, remote_wait,  /* attach */
+       remote_fetch_registers, remote_store_registers,
+       remote_prepare_to_store, 0, 0, /* conv_from, conv_to */
+       remote_xfer_inferior_memory, remote_files_info,
+       0, 0, /* insert_breakpoint, remove_breakpoint, */
+       0, 0, 0, 0, 0,  /* Terminal crud */
+       0, /* kill */
+       0, add_syms_addr_command,  /* load */
+       call_function_by_hand,
+       0, /* lookup_symbol */
+       0, 0, /* create_inferior FIXME, mourn_inferior FIXME */
+       process_stratum, 0, /* next */
+       1, 1, 1, 1, 1,  /* all mem, mem, stack, regs, exec */
+       OPS_MAGIC,              /* Always the last thing */
+};
+
+void
+_initialize_remote ()
+{
+  add_target (&remote_ops);
+}
diff --git a/gdb/solib.c b/gdb/solib.c
new file mode 100644 (file)
index 0000000..ab9336f
--- /dev/null
@@ -0,0 +1,245 @@
+/* Copyright (C) 1990 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.  */
+
+/*
+**     symbol definitions
+*/
+#include <sys/types.h>
+#include <string.h>
+#include <link.h>
+#include "defs.h"
+#include "param.h"
+#include "symtab.h"
+#include "gdbcore.h"
+#include "command.h"
+
+/*
+**     local data declarations
+*/
+#define MAX_PATH_SIZE 256
+struct so_list {
+    struct link_map inferior_lm;               /* inferior link map */
+    struct link_map *inferior_lm_add;
+    long   ld_text;
+    char inferior_so_name[MAX_PATH_SIZE];      /* Shared Object Library Name */
+    struct so_list *next;                      /* Next Structure */
+    int        symbols_loaded;
+};
+
+static struct so_list *so_list_head = 0;
+
+/*=======================================================================*/
+
+/*     find_solib
+**
+**Description:
+**
+**     This module contains the routine which finds the names of any loaded
+**     "images" in the current process. The argument in must be NULL on the
+**     first call, and then the returned value must be passed in on
+**     subsequent calls. This provides the capability to "step" down the
+**     list of loaded objects. On the last object, a NULL value is returned.
+**     The arg and return value are "struct link_map" pointers, as defined
+**     in <link.h>.
+**
+**     NOTE: This only works under SunOS4.0.
+*/
+
+struct so_list *find_solib(so_list_ptr)
+struct so_list *so_list_ptr;                   /* so_list_head position ptr */
+{
+struct so_list *so_list_next = 0;
+CORE_ADDR inferior_dynamic_ptr = 0;
+struct link_map *inferior_lm = 0;
+struct link_dynamic inferior_dynamic_cpy;
+struct link_dynamic_2 inferior_ld_2_cpy;
+struct so_list *new;
+int i;
+
+     if (!so_list_ptr) {
+        if (!(so_list_next = so_list_head)) {
+            for (i = 0; i < misc_function_count; i++) {
+                if (!strcmp (misc_function_vector[i].name, "_DYNAMIC")) {
+                    inferior_dynamic_ptr = misc_function_vector[i].address;
+                    break;
+                }      
+            }          
+            if (inferior_dynamic_ptr) {
+                read_memory(inferior_dynamic_ptr, &inferior_dynamic_cpy, sizeof(struct link_dynamic));
+                if (inferior_dynamic_cpy.ld_version == 3) {
+                    read_memory((CORE_ADDR)inferior_dynamic_cpy.ld_un.ld_2,
+                                &inferior_ld_2_cpy,
+                                sizeof(struct link_dynamic_2));
+                    inferior_lm = inferior_ld_2_cpy.ld_loaded;
+                }
+            }
+        }
+     } else {
+        /*
+        ** Advance to next local abbreviated load_map structure
+        */
+        if (!(inferior_lm = so_list_ptr->inferior_lm.lm_next)) {
+            /* 
+            ** See if any were added
+            */
+            read_memory((CORE_ADDR)so_list_ptr->inferior_lm_add,
+                        &so_list_ptr->inferior_lm,
+                        sizeof(struct link_map));
+            inferior_lm = so_list_ptr->inferior_lm.lm_next;
+        }
+        so_list_next = so_list_ptr->next;
+     }
+     if ((!so_list_next) && inferior_lm) {
+        /* 
+        ** Get Next LM Structure from inferior image and build
+        ** an local abbreviated load_map structure
+        */
+        new = (struct so_list *) xmalloc(sizeof(struct so_list));
+         new->inferior_lm_add = inferior_lm;
+        read_memory((CORE_ADDR)inferior_lm,
+                    &new->inferior_lm,
+                    sizeof(struct link_map));
+
+        read_memory((CORE_ADDR)new->inferior_lm.lm_name,
+                    new->inferior_so_name,
+                    MAX_PATH_SIZE - 1);
+        new->inferior_so_name[MAX_PATH_SIZE - 1] = 0;
+        /* Zero everything after the first terminating null */
+        strncpy(new->inferior_so_name, new->inferior_so_name, MAX_PATH_SIZE);
+
+        read_memory((CORE_ADDR)new->inferior_lm.lm_ld,
+                    &inferior_dynamic_cpy,
+                    sizeof(struct link_dynamic));
+        read_memory((CORE_ADDR)inferior_dynamic_cpy.ld_un.ld_2,
+                    &inferior_ld_2_cpy,
+                    sizeof(struct link_dynamic_2));
+        new->ld_text = inferior_ld_2_cpy.ld_text;
+    
+        new->next = 0;
+        new->symbols_loaded = 0;
+        if (so_list_ptr)
+            so_list_ptr->next = new;
+        else
+            so_list_head = new;
+        so_list_next = new;
+     }
+     return(so_list_next);
+}
+/*=======================================================================*/
+
+static void solib_add(arg_string, from_tty)
+char *arg_string;
+int from_tty;
+{      
+    register struct so_list *so = 0;           /* link map state variable */
+    char *val;
+    int sz;
+
+    if (arg_string == 0)
+       re_comp (".");
+    else if (val = (char *) re_comp (arg_string)) {
+       error ("Invalid regexp: %s", val);
+    }
+    printf_filtered ("All shared libraries");
+    if (arg_string)
+      printf_filtered (" matching regular expresion \"%s\"", arg_string);
+    printf_filtered (":\n");
+    
+    dont_repeat();
+
+    while (so = find_solib(so)) {
+       if (re_exec(so->inferior_so_name)) {
+           if (so->symbols_loaded) {
+               printf("Symbols already loaded for %s\n", so->inferior_so_name);
+           } else {
+               /* File Name String Freed by processing */
+               sz = strlen(so->inferior_so_name) + 1;
+               val = (char *) xmalloc(sz);
+               bcopy(so->inferior_so_name, val, sz);
+               symbol_file_add (val, from_tty,
+                                (unsigned int)so->inferior_lm.lm_addr, 0);
+               so->symbols_loaded = 1;
+           }
+       }
+    }
+}
+/*=======================================================================*/
+
+static void solib_info()
+{
+register struct so_list *so = 0;       /* link map state variable */
+
+    while (so = find_solib(so)) {
+       if (so == so_list_head) {
+           printf("      Address Range      Symbols     Shared Object Library\n");
+       }
+       printf(" 0x%08x - 0x%08x   %s   %s\n", 
+           so->inferior_lm.lm_addr, 
+           so->inferior_lm.lm_addr + so->ld_text - 1,
+           (so->symbols_loaded ? "Yes" : "No "),
+           so->inferior_so_name);
+    }
+    if (!so_list_head) {
+       printf("No shared libraries loaded at this time.\n");   
+    }
+}
+
+/*
+** Called by Insert Breakpoint to see if Address is Shared Library Address 
+*/
+int
+solib_address(address)
+     CORE_ADDR address;
+{
+register struct so_list *so = 0;       /* link map state variable */
+
+    while (so = find_solib(so)) {
+       if ((address >= (CORE_ADDR) so->inferior_lm.lm_addr) &&
+           (address < (CORE_ADDR) so->inferior_lm.lm_addr + so->ld_text))
+         return 1;
+    }
+    return 0;
+}
+
+/*
+** Called by free_all_symtabs
+*/
+void 
+clear_solib()
+{
+struct so_list *next;
+
+  while (so_list_head) {
+    next = so_list_head->next;
+    free(so_list_head);
+    so_list_head = next;
+  }
+    
+}
+
+void
+_initialize_solib()
+{
+
+  add_com("sharedlibrary", class_files, solib_add,
+          "Load shared object library symbols for files matching REGEXP.");
+  add_info("sharedlibrary", solib_info, 
+          "Status of loaded shared object libraries");
+
+}
diff --git a/gdb/source.c b/gdb/source.c
new file mode 100644 (file)
index 0000000..ebc7041
--- /dev/null
@@ -0,0 +1,1186 @@
+/* List lines of source files for GDB, the GNU debugger.
+   Copyright (C) 1986, 1987, 1988, 1989, 1991 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 <stdio.h>
+#include "defs.h"
+#include "symtab.h"
+#include "param.h"
+#include "command.h"
+#include "frame.h"
+
+#ifdef USG
+#include <sys/types.h>
+#endif
+
+#include <string.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "gdbcore.h"
+
+extern char *strstr();
+
+extern void set_next_address ();
+
+void mod_path ();
+
+/* Path of directories to search for source files.
+   Same format as the PATH environment variable's value.  */
+
+char *source_path;
+
+/* Symtab of default file for listing lines of.  */
+
+struct symtab *current_source_symtab;
+
+/* Default next line to list.  */
+
+int current_source_line;
+
+/* Line number of last line printed.  Default for various commands.
+   current_source_line is usually, but not always, the same as this.  */
+
+static int last_line_listed;
+
+/* First line number listed by last listing command.  */
+
+static int first_line_listed;
+
+\f
+/* Set the source file default for the "list" command, specifying a
+   symtab.  Sigh.  Behavior specification: If it is called with a
+   non-zero argument, that is the symtab to select.  If it is not,
+   first lookup "main"; if it exists, use the symtab and line it
+   defines.  If not, take the last symtab in the symtab_list (if it
+   exists) or the last symtab in the psymtab_list (if *it* exists).  If
+   none of this works, report an error.   */
+
+void
+select_source_symtab (s)
+     register struct symtab *s;
+{
+  struct symtabs_and_lines sals;
+  struct symtab_and_line sal;
+  struct partial_symtab *ps;
+  struct partial_symtab *cs_pst = 0;
+  
+  if (s)
+    {
+      current_source_symtab = s;
+      current_source_line = 1;
+      return;
+    }
+
+  /* Make the default place to list be the function `main'
+     if one exists.  */
+  if (lookup_symbol ("main", 0, VAR_NAMESPACE, 0, NULL))
+    {
+      sals = decode_line_spec ("main", 1);
+      sal = sals.sals[0];
+      free (sals.sals);
+      current_source_symtab = sal.symtab;
+      current_source_line = max (sal.line - (lines_to_list () - 1), 1);
+      return;
+    }
+  
+  /* All right; find the last file in the symtab list (ignoring .h's).  */
+
+  if (s = symtab_list)
+    {
+      do
+       {
+         char *name = s->filename;
+         int len = strlen (name);
+         if (! (len > 2 && !strcmp (&name[len - 2], ".h")))
+           current_source_symtab = s;
+         s = s->next;
+       }
+      while (s);
+      current_source_line = 1;
+    }
+  else if (partial_symtab_list)
+    {
+      ps = partial_symtab_list;
+      while (ps)
+       {
+         char *name = ps->filename;
+         int len = strlen (name);
+         if (! (len > 2 && !strcmp (&name[len - 2], ".h")))
+           cs_pst = ps;
+         ps = ps->next;
+       }
+      if (cs_pst)
+       if (cs_pst->readin)
+         fatal ("Internal: select_source_symtab: readin pst found and no symtabs.");
+       else
+         current_source_symtab = PSYMTAB_TO_SYMTAB (cs_pst);
+      else
+       current_source_symtab = 0;
+      current_source_line = 1;
+    }
+}
+\f
+static void
+directories_info ()
+{
+  printf ("Source directories searched: %s\n", source_path);
+}
+
+/* Forget what we learned about line positions in source files,
+   and which directories contain them;
+   must check again now since files may be found in
+   a different directory now.  */
+
+void
+forget_cached_source_info ()
+{
+  register struct symtab *s;
+
+  for (s = symtab_list; s; s = s->next)
+    {
+      if (s->line_charpos != 0)
+       {
+         free (s->line_charpos);
+         s->line_charpos = 0;
+       }
+      if (s->fullname != 0)
+       {
+         free (s->fullname);
+         s->fullname = 0;
+       }
+    }
+}
+
+void
+init_source_path ()
+{
+  source_path = savestring ("$cdir:$cwd", /* strlen of it */ 10);
+  forget_cached_source_info ();
+}
+
+/* Add zero or more directories to the front of the source path.  */
+void
+directory_command (dirname, from_tty)
+     char *dirname;
+     int from_tty;
+{
+  dont_repeat ();
+  /* FIXME, this goes to "delete dir"... */
+  if (dirname == 0)
+    {
+      if (query ("Reinitialize source path to empty? ", ""))
+       {
+         free (source_path);
+         init_source_path ();
+       }
+    }
+  else
+    mod_path (dirname, from_tty, &source_path);
+  if (from_tty)
+    directories_info ();
+  forget_cached_source_info ();
+}
+
+/* Add zero or more directories to the front of an arbitrary path.  */
+
+void
+mod_path (dirname, from_tty, which_path)
+     char *dirname;
+     int from_tty;
+     char **which_path;
+{
+  char *old = *which_path;
+  int prefix = 0;
+
+  if (dirname == 0)
+    return;
+
+  dirname = strsave (dirname);
+  make_cleanup (free, dirname);
+
+  do
+    {
+      extern char *index ();
+      char *name = dirname;
+      register char *p;
+      struct stat st;
+
+      {
+       char *colon = index (name, ':');
+       char *space = index (name, ' ');
+       char *tab = index (name, '\t');
+       if (colon == 0 && space == 0 && tab ==  0)
+         p = dirname = name + strlen (name);
+       else
+         {
+           p = 0;
+           if (colon != 0 && (p == 0 || colon < p))
+             p = colon;
+           if (space != 0 && (p == 0 || space < p))
+             p = space;
+           if (tab != 0 && (p == 0 || tab < p))
+             p = tab;
+           dirname = p + 1;
+           while (*dirname == ':' || *dirname == ' ' || *dirname == '\t')
+             ++dirname;
+         }
+      }
+
+      if (p[-1] == '/')
+       /* Sigh. "foo/" => "foo" */
+       --p;
+      *p = '\0';
+
+      while (p[-1] == '.')
+       {
+         if (p - name == 1)
+           {
+             /* "." => getwd ().  */
+             name = current_directory;
+             goto append;
+           }
+         else if (p[-2] == '/')
+           {
+             if (p - name == 2)
+               {
+                 /* "/." => "/".  */
+                 *--p = '\0';
+                 goto append;
+               }
+             else
+               {
+                 /* "...foo/." => "...foo".  */
+                 p -= 2;
+                 *p = '\0';
+                 continue;
+               }
+           }
+         else
+           break;
+       }
+
+      if (name[0] == '~')
+       name = tilde_expand (name);
+      else if (name[0] != '/' && name[0] != '$')
+       name = concat (current_directory, "/", name);
+      else
+       name = savestring (name, p - name);
+      make_cleanup (free, name);
+
+      /* Unless it's a variable, check existence.  */
+      if (name[0] != '$') {
+       if (stat (name, &st) < 0)
+         perror_with_name (name);
+       if ((st.st_mode & S_IFMT) != S_IFDIR)
+         error ("%s is not a directory.", name);
+      }
+
+    append:
+      {
+       register unsigned int len = strlen (name);
+
+       p = *which_path;
+       while (1)
+         {
+           if (!strncmp (p, name, len)
+               && (p[len] == '\0' || p[len] == ':'))
+             {
+               /* Found it in the search path, remove old copy */
+               if (p > *which_path)
+                 p--;                  /* Back over leading colon */
+               if (prefix > p - *which_path)
+                 goto skip_dup;        /* Same dir twice in one cmd */
+               strcpy (p, &p[len+1]);  /* Copy from next \0 or  : */
+             }
+           p = index (p, ':');
+           if (p != 0)
+             ++p;
+           else
+             break;
+         }
+       if (p == 0)
+         {
+           /* If we have already tacked on a name(s) in this command,                     be sure they stay on the front as we tack on some more.  */
+           if (prefix)
+             {
+               char *temp, c;
+
+               c = old[prefix];
+               old[prefix] = '\0';
+               temp = concat (old, ":", name);
+               old[prefix] = c;
+               *which_path = concat (temp, "", &old[prefix]);
+               prefix = strlen (temp);
+               free (temp);
+             }
+           else
+             {
+               *which_path = concat (name, (old[0]? ":" : old), old);
+               prefix = strlen (name);
+             }
+           free (old);
+           old = *which_path;
+         }
+      }
+  skip_dup: ;
+    } while (*dirname != '\0');
+}
+
+
+static void
+source_info ()
+{
+  register struct symtab *s = current_source_symtab;
+
+  if (!s)
+    {
+      printf("No current source file.\n");
+      return;
+    }
+  printf ("Current source file is %s\n", s->filename);
+  if (s->dirname)
+    printf ("Compilation directory is %s\n", s->dirname);
+  if (s->fullname)
+    printf ("Located in %s\n", s->fullname);
+  if (s->nlines)
+    printf ("Contains %d lines\n", s->nlines);
+
+  switch (s->language) {
+  case language_c:
+    printf("Written in the C language.\n");
+  /* Add more cases here when -Wswitch complains... */
+  case language_unknown:
+    break;
+  }
+}
+
+
+\f
+/* Open a file named STRING, searching path PATH (dir names sep by colons)
+   using mode MODE and protection bits PROT in the calls to open.
+   If TRY_CWD_FIRST, try to open ./STRING before searching PATH.
+   (ie pretend the first element of PATH is ".")
+   If FILENAMED_OPENED is non-null, set it to a newly allocated string naming
+   the actual file opened (this string will always start with a "/".  We
+   have to take special pains to avoid doubling the "/" between the directory
+   and the file, sigh!  Emacs gets confuzzed by this when we print the
+   source file name!!! 
+
+   If a file is found, return the descriptor.
+   Otherwise, return -1, with errno set for the last name we tried to open.  */
+
+/*  >>>> This should only allow files of certain types,
+    >>>>  eg executable, non-directory */
+int
+openp (path, try_cwd_first, string, mode, prot, filename_opened)
+     char *path;
+     int try_cwd_first;
+     char *string;
+     int mode;
+     int prot;
+     char **filename_opened;
+{
+  register int fd;
+  register char *filename;
+  register char *p, *p1;
+  register int len;
+  int alloclen;
+
+  if (!path)
+    path = ".";
+
+  /* ./foo => foo */
+  while (string[0] == '.' && string[1] == '/')
+    string += 2;
+
+  if (try_cwd_first || string[0] == '/')
+    {
+      filename = string;
+      fd = open (filename, mode, prot);
+      if (fd >= 0 || string[0] == '/')
+       goto done;
+    }
+
+  alloclen = strlen (path) + strlen (string) + 2;
+  filename = (char *) alloca (alloclen);
+  fd = -1;
+  for (p = path; p; p = p1 ? p1 + 1 : 0)
+    {
+      p1 = (char *) index (p, ':');
+      if (p1)
+       len = p1 - p;
+      else
+       len = strlen (p);
+
+      if (len == 4 && p[0] == '$' && p[1] == 'c'
+                  && p[2] == 'w' && p[3] == 'd') {
+       /* Name is $cwd -- insert current directory name instead.  */
+       int newlen;
+
+       /* First, realloc the filename buffer if too short. */
+       len = strlen (current_directory);
+       newlen = len + strlen (string) + 2;
+       if (newlen > alloclen) {
+         alloclen = newlen;
+         filename = (char *) alloca (alloclen);
+       }
+       strcpy (filename, current_directory);
+      } else {
+       /* Normal file name in path -- just use it.  */
+       strncpy (filename, p, len);
+       filename[len] = 0;
+      }
+
+      /* Beware the // my son, the Emacs barfs, the botch that catch... */
+      while (len > 1 && filename[len-1] == '/')
+       filename[--len] = 0;
+      strcat (filename+len, "/");
+      strcat (filename, string);
+
+      fd = open (filename, mode, prot);
+      if (fd >= 0) break;
+    }
+
+ done:
+  if (filename_opened)
+    if (fd < 0)
+      *filename_opened = (char *) 0;
+    else if (filename[0] == '/')
+      *filename_opened = savestring (filename, strlen (filename));
+    else
+      {
+       /* Beware the // my son, the Emacs barfs, the botch that catch... */
+          
+       *filename_opened = concat (current_directory, 
+          '/' == current_directory[strlen(current_directory)-1]? "": "/",
+                                  filename);
+      }
+
+  return fd;
+}
+
+/* Open a source file given a symtab S.  Returns a file descriptor
+   or negative number for error.  */
+int
+open_source_file (s)
+     struct symtab *s;
+{
+  char *path = source_path;
+  char *p;
+  int result;
+
+  /* Quick way out if we already know its full name */
+  if (s->fullname) 
+    {
+      result = open (s->fullname, O_RDONLY);
+      if (result >= 0)
+        return result;
+      /* Didn't work -- free old one, try again. */
+      free (s->fullname);
+      s->fullname = NULL;
+    }
+
+  if (s->dirname != NULL)
+    {
+      /* Replace a path entry of  $cdir  with the compilation directory name */
+#define        cdir_len        5
+      p = strstr (source_path, "$cdir");
+      if (p && (p == path || p[-1] == ':')
+           && (p[cdir_len] == ':' || p[cdir_len] == '\0')) {
+       int len;
+
+       path = (char *)
+              alloca (strlen (source_path) + 1 + strlen (s->dirname) + 1);
+       len = p - source_path;
+       strncpy (path, source_path, len);               /* Before $cdir */
+       strcpy (path + len, s->dirname);                /* new stuff */
+       strcat (path + len, source_path + len + cdir_len); /* After $cdir */
+      }
+    }
+
+  return openp (path, 0, s->filename, O_RDONLY, 0, &s->fullname);
+}
+
+\f
+/* Create and initialize the table S->line_charpos that records
+   the positions of the lines in the source file, which is assumed
+   to be open on descriptor DESC.
+   All set S->nlines to the number of such lines.  */
+
+static void
+find_source_lines (s, desc)
+     struct symtab *s;
+     int desc;
+{
+  struct stat st;
+  register char *data, *p, *end;
+  int nlines = 0;
+  int lines_allocated = 1000;
+  int *line_charpos = (int *) xmalloc (lines_allocated * sizeof (int));
+
+  if (fstat (desc, &st) < 0)
+    perror_with_name (s->filename);
+  if (exec_bfd && bfd_get_mtime(exec_bfd) < st.st_mtime)
+    printf ("Source file is more recent than executable.\n");
+
+#if defined (BROKEN_LARGE_ALLOCA)
+  data = (char *) xmalloc (st.st_size);
+  make_cleanup (free, data);
+#else
+  data = (char *) alloca (st.st_size);
+#endif
+  if (myread (desc, data, st.st_size) < 0)
+    perror_with_name (s->filename);
+  end = data + st.st_size;
+  p = data;
+  line_charpos[0] = 0;
+  nlines = 1;
+  while (p != end)
+    {
+      if (*p++ == '\n'
+         /* A newline at the end does not start a new line.  */
+         && p != end)
+       {
+         if (nlines == lines_allocated)
+           {
+             lines_allocated *= 2;
+             line_charpos = (int *) xrealloc (line_charpos,
+                                              sizeof (int) * lines_allocated);
+           }
+         line_charpos[nlines++] = p - data;
+       }
+    }
+  s->nlines = nlines;
+  s->line_charpos = (int *) xrealloc (line_charpos, nlines * sizeof (int));
+}
+
+/* Return the character position of a line LINE in symtab S.
+   Return 0 if anything is invalid.  */
+
+int
+source_line_charpos (s, line)
+     struct symtab *s;
+     int line;
+{
+  if (!s) return 0;
+  if (!s->line_charpos || line <= 0) return 0;
+  if (line > s->nlines)
+    line = s->nlines;
+  return s->line_charpos[line - 1];
+}
+
+/* Return the line number of character position POS in symtab S.  */
+
+int
+source_charpos_line (s, chr)
+    register struct symtab *s;
+    register int chr;
+{
+  register int line = 0;
+  register int *lnp;
+    
+  if (s == 0 || s->line_charpos == 0) return 0;
+  lnp = s->line_charpos;
+  /* Files are usually short, so sequential search is Ok */
+  while (line < s->nlines  && *lnp <= chr)
+    {
+      line++;
+      lnp++;
+    }
+  if (line >= s->nlines)
+    line = s->nlines;
+  return line;
+}
+\f
+/* Get full pathname and line number positions for a symtab.
+   Return nonzero if line numbers may have changed.
+   Set *FULLNAME to actual name of the file as found by `openp',
+   or to 0 if the file is not found.  */
+
+int
+get_filename_and_charpos (s, fullname)
+     struct symtab *s;
+     char **fullname;
+{
+  register int desc, linenums_changed = 0;
+  
+  desc = open_source_file (s);
+  if (desc < 0)
+    {
+      if (fullname)
+       *fullname = NULL;
+      return 0;
+    }  
+  if (fullname)
+    *fullname = s->fullname;
+  if (s->line_charpos == 0) linenums_changed = 1;
+  if (linenums_changed) find_source_lines (s, desc);
+  close (desc);
+  return linenums_changed;
+}
+
+/* Print text describing the full name of the source file S
+   and the line number LINE and its corresponding character position.
+   The text starts with two Ctrl-z so that the Emacs-GDB interface
+   can easily find it.
+
+   MID_STATEMENT is nonzero if the PC is not at the beginning of that line.
+
+   Return 1 if successful, 0 if could not find the file.  */
+
+int
+identify_source_line (s, line, mid_statement)
+     struct symtab *s;
+     int line;
+     int mid_statement;
+{
+  if (s->line_charpos == 0)
+    get_filename_and_charpos (s, (char **)NULL);
+  if (s->fullname == 0)
+    return 0;
+  printf ("\032\032%s:%d:%d:%s:0x%x\n", s->fullname,
+         line, s->line_charpos[line - 1],
+         mid_statement ? "middle" : "beg",
+         get_frame_pc (get_current_frame()));
+  current_source_line = line;
+  first_line_listed = line;
+  last_line_listed = line;
+  current_source_symtab = s;
+  return 1;
+}
+\f
+/* Print source lines from the file of symtab S,
+   starting with line number LINE and stopping before line number STOPLINE.  */
+
+void
+print_source_lines (s, line, stopline, noerror)
+     struct symtab *s;
+     int line, stopline;
+     int noerror;
+{
+  register int c;
+  register int desc;
+  register FILE *stream;
+  int nlines = stopline - line;
+
+  /* Regardless of whether we can open the file, set current_source_symtab. */
+  current_source_symtab = s;
+  current_source_line = line;
+  first_line_listed = line;
+
+  desc = open_source_file (s);
+  if (desc < 0)
+    {
+      if (! noerror) {
+       char *name = alloca (strlen (s->filename) + 100);
+       sprintf (name, "%s:%d", s->filename, line);
+        print_sys_errmsg (name, errno);
+      }
+      return;
+    }
+
+  if (s->line_charpos == 0)
+    find_source_lines (s, desc);
+
+  if (line < 1 || line > s->nlines)
+    {
+      close (desc);
+      error ("Line number %d out of range; %s has %d lines.",
+            line, s->filename, s->nlines);
+    }
+
+  if (lseek (desc, s->line_charpos[line - 1], 0) < 0)
+    {
+      close (desc);
+      perror_with_name (s->filename);
+    }
+
+  stream = fdopen (desc, "r");
+  clearerr (stream);
+
+  while (nlines-- > 0)
+    {
+      c = fgetc (stream);
+      if (c == EOF) break;
+      last_line_listed = current_source_line;
+      printf_filtered ("%d\t", current_source_line++);
+      do
+       {
+         if (c < 040 && c != '\t' && c != '\n')
+             printf_filtered ("^%c", c + 0100);
+         else if (c == 0177)
+           printf_filtered ("^?");
+         else
+           printf_filtered ("%c", c);
+       } while (c != '\n' && (c = fgetc (stream)) >= 0);
+    }
+
+  fclose (stream);
+}
+\f
+
+
+/* 
+  C++
+  Print a list of files and line numbers which a user may choose from
+  in order to list a function which was specified ambiguously
+  (as with `list classname::overloadedfuncname', for example).
+  The vector in SALS provides the filenames and line numbers.
+  */
+static void
+ambiguous_line_spec (sals)
+     struct symtabs_and_lines *sals;
+{
+  int i;
+
+  for (i = 0; i < sals->nelts; ++i)
+    printf("file: \"%s\", line number: %d\n",
+          sals->sals[i].symtab->filename, sals->sals[i].line);
+}
+
+
+static void
+list_command (arg, from_tty)
+     char *arg;
+     int from_tty;
+{
+  struct symtabs_and_lines sals, sals_end;
+  struct symtab_and_line sal, sal_end;
+  struct symbol *sym;
+  char *arg1;
+  int no_end = 1;
+  int dummy_end = 0;
+  int dummy_beg = 0;
+  int linenum_beg = 0;
+  char *p;
+
+  if (symtab_list == 0 && partial_symtab_list == 0)
+    error ("No symbol table is loaded.  Use the \"symbol-file\" command.");
+
+  /* Pull in a current source symtab if necessary */
+  if (current_source_symtab == 0 &&
+      (arg == 0 || arg[0] == '+' || arg[0] == '-'))
+    select_source_symtab (0);
+
+  /* "l" or "l +" lists next ten lines.  */
+
+  if (arg == 0 || !strcmp (arg, "+"))
+    {
+      if (current_source_symtab == 0)
+       error ("No default source file yet.  Do \"help list\".");
+      print_source_lines (current_source_symtab, current_source_line,
+                         current_source_line + lines_to_list (), 0);
+      return;
+    }
+
+  /* "l -" lists previous ten lines, the ones before the ten just listed.  */
+  if (!strcmp (arg, "-"))
+    {
+      if (current_source_symtab == 0)
+       error ("No default source file yet.  Do \"help list\".");
+      print_source_lines (current_source_symtab,
+                         max (first_line_listed - lines_to_list (), 1),
+                         first_line_listed, 0);
+      return;
+    }
+
+  /* Now if there is only one argument, decode it in SAL
+     and set NO_END.
+     If there are two arguments, decode them in SAL and SAL_END
+     and clear NO_END; however, if one of the arguments is blank,
+     set DUMMY_BEG or DUMMY_END to record that fact.  */
+
+  arg1 = arg;
+  if (*arg1 == ',')
+    dummy_beg = 1;
+  else
+    {
+      sals = decode_line_1 (&arg1, 0, 0, 0);
+
+      if (! sals.nelts) return;  /*  C++  */
+      if (sals.nelts > 1)
+       {
+         ambiguous_line_spec (&sals);
+         free (sals.sals);
+         return;
+       }
+
+      sal = sals.sals[0];
+      free (sals.sals);
+    }
+
+  /* Record whether the BEG arg is all digits.  */
+
+  for (p = arg; p != arg1 && *p >= '0' && *p <= '9'; p++);
+  linenum_beg = (p == arg1);
+
+  while (*arg1 == ' ' || *arg1 == '\t')
+    arg1++;
+  if (*arg1 == ',')
+    {
+      no_end = 0;
+      arg1++;
+      while (*arg1 == ' ' || *arg1 == '\t')
+       arg1++;
+      if (*arg1 == 0)
+       dummy_end = 1;
+      else
+       {
+         if (dummy_beg)
+           sals_end = decode_line_1 (&arg1, 0, 0, 0);
+         else
+           sals_end = decode_line_1 (&arg1, 0, sal.symtab, sal.line);
+         if (sals_end.nelts == 0) 
+           return;
+         if (sals_end.nelts > 1)
+           {
+             ambiguous_line_spec (&sals_end);
+             free (sals_end.sals);
+             return;
+           }
+         sal_end = sals_end.sals[0];
+         free (sals_end.sals);
+       }
+    }
+
+  if (*arg1)
+    error ("Junk at end of line specification.");
+
+  if (!no_end && !dummy_beg && !dummy_end
+      && sal.symtab != sal_end.symtab)
+    error ("Specified start and end are in different files.");
+  if (dummy_beg && dummy_end)
+    error ("Two empty args do not say what lines to list.");
+  /* if line was specified by address,
+     first print exactly which line, and which file.
+     In this case, sal.symtab == 0 means address is outside
+     of all known source files, not that user failed to give a filename.  */
+  if (*arg == '*')
+    {
+      if (sal.symtab == 0)
+       error ("No source file for address 0x%x.", sal.pc);
+      sym = find_pc_function (sal.pc);
+      if (sym)
+       printf ("0x%x is in %s (%s, line %d).\n",
+               sal.pc, SYMBOL_NAME (sym), sal.symtab->filename, sal.line);
+      else
+       printf ("0x%x is in %s, line %d.\n",
+               sal.pc, sal.symtab->filename, sal.line);
+    }
+
+  /* If line was not specified by just a line number,
+     and it does not imply a symtab, it must be an undebuggable symbol
+     which means no source code.  */
+
+  if (! linenum_beg && sal.symtab == 0)
+    error ("No line number known for %s.", arg);
+
+  /* If this command is repeated with RET,
+     turn it into the no-arg variant.  */
+
+  if (from_tty)
+    *arg = 0;
+
+  if (dummy_beg && sal_end.symtab == 0)
+    error ("No default source file yet.  Do \"help list\".");
+  if (dummy_beg)
+    print_source_lines (sal_end.symtab,
+                       max (sal_end.line - (lines_to_list () - 1), 1),
+                       sal_end.line + 1, 0);
+  else if (sal.symtab == 0)
+    error ("No default source file yet.  Do \"help list\".");
+  else if (no_end)
+    print_source_lines (sal.symtab,
+                       max (sal.line - (lines_to_list () / 2), 1),
+                       sal.line + 5, 0);
+  else
+    print_source_lines (sal.symtab, sal.line,
+                       (dummy_end
+                        ? sal.line + lines_to_list ()
+                        : sal_end.line + 1),
+                       0);
+}
+\f
+/* Print info on range of pc's in a specified line.  */
+
+static void
+line_info (arg, from_tty)
+     char *arg;
+     int from_tty;
+{
+  struct symtabs_and_lines sals;
+  struct symtab_and_line sal;
+  CORE_ADDR start_pc, end_pc;
+  int i;
+
+  if (arg == 0)
+    {
+      sal.symtab = current_source_symtab;
+      sal.line = last_line_listed;
+      sals.nelts = 1;
+      sals.sals = (struct symtab_and_line *)
+       xmalloc (sizeof (struct symtab_and_line));
+      sals.sals[0] = sal;
+    }
+  else
+    {
+      sals = decode_line_spec_1 (arg, 0);
+      
+      /* If this command is repeated with RET,
+        turn it into the no-arg variant.  */
+      if (from_tty)
+       *arg = 0;
+    }
+
+  /* C++  More than one line may have been specified, as when the user
+     specifies an overloaded function name. Print info on them all. */
+  for (i = 0; i < sals.nelts; i++)
+    {
+      sal = sals.sals[i];
+      
+      if (sal.symtab == 0)
+       error ("No source file specified.");
+
+      if (sal.line > 0
+         && find_line_pc_range (sal.symtab, sal.line, &start_pc, &end_pc))
+       {
+         if (start_pc == end_pc)
+           printf ("Line %d of \"%s\" is at pc 0x%x but contains no code.\n",
+                   sal.line, sal.symtab->filename, start_pc);
+         else
+           printf ("Line %d of \"%s\" starts at pc 0x%x and ends at 0x%x.\n",
+                   sal.line, sal.symtab->filename, start_pc, end_pc);
+         /* x/i should display this line's code.  */
+         set_next_address (start_pc);
+         /* Repeating "info line" should do the following line.  */
+         last_line_listed = sal.line + 1;
+       }
+      else
+       printf ("Line number %d is out of range for \"%s\".\n",
+               sal.line, sal.symtab->filename);
+    }
+}
+\f
+/* Commands to search the source file for a regexp.  */
+
+static void
+forward_search_command (regex, from_tty)
+     char *regex;
+     int from_tty;
+{
+  register int c;
+  register int desc;
+  register FILE *stream;
+  int line = last_line_listed + 1;
+  char *msg;
+
+  msg = (char *) re_comp (regex);
+  if (msg)
+    error (msg);
+
+  if (current_source_symtab == 0)
+    select_source_symtab (0);
+
+  /* Search from last_line_listed+1 in current_source_symtab */
+
+  desc = open_source_file (current_source_symtab);
+  if (desc < 0)
+    perror_with_name (current_source_symtab->filename);
+
+  if (current_source_symtab->line_charpos == 0)
+    find_source_lines (current_source_symtab, desc);
+
+  if (line < 1 || line > current_source_symtab->nlines)
+    {
+      close (desc);
+      error ("Expression not found");
+    }
+
+  if (lseek (desc, current_source_symtab->line_charpos[line - 1], 0) < 0)
+    {
+      close (desc);
+      perror_with_name (current_source_symtab->filename);
+    }
+
+  stream = fdopen (desc, "r");
+  clearerr (stream);
+  while (1) {
+    char buf[4096];            /* Should be reasonable??? */
+    register char *p = buf;
+
+    c = fgetc (stream);
+    if (c == EOF)
+      break;
+    do {
+      *p++ = c;
+    } while (c != '\n' && (c = fgetc (stream)) >= 0);
+
+    /* we now have a source line in buf, null terminate and match */
+    *p = 0;
+    if (re_exec (buf) > 0)
+      {
+       /* Match! */
+       fclose (stream);
+       print_source_lines (current_source_symtab,
+                          line, line+1, 0);
+       current_source_line = max (line - lines_to_list () / 2, 1);
+       return;
+      }
+    line++;
+  }
+
+  printf ("Expression not found\n");
+  fclose (stream);
+}
+
+static void
+reverse_search_command (regex, from_tty)
+     char *regex;
+     int from_tty;
+{
+  register int c;
+  register int desc;
+  register FILE *stream;
+  int line = last_line_listed - 1;
+  char *msg;
+
+  msg = (char *) re_comp (regex);
+  if (msg)
+    error (msg);
+
+  if (current_source_symtab == 0)
+    select_source_symtab (0);
+
+  /* Search from last_line_listed-1 in current_source_symtab */
+
+  desc = open_source_file (current_source_symtab);
+  if (desc < 0)
+    perror_with_name (current_source_symtab->filename);
+
+  if (current_source_symtab->line_charpos == 0)
+    find_source_lines (current_source_symtab, desc);
+
+  if (line < 1 || line > current_source_symtab->nlines)
+    {
+      close (desc);
+      error ("Expression not found");
+    }
+
+  if (lseek (desc, current_source_symtab->line_charpos[line - 1], 0) < 0)
+    {
+      close (desc);
+      perror_with_name (current_source_symtab->filename);
+    }
+
+  stream = fdopen (desc, "r");
+  clearerr (stream);
+  while (line > 1)
+    {
+      char buf[4096];          /* Should be reasonable??? */
+      register char *p = buf;
+
+      c = fgetc (stream);
+      if (c == EOF)
+       break;
+      do {
+       *p++ = c;
+      } while (c != '\n' && (c = fgetc (stream)) >= 0);
+
+      /* We now have a source line in buf; null terminate and match.  */
+      *p = 0;
+      if (re_exec (buf) > 0)
+       {
+         /* Match! */
+         fclose (stream);
+         print_source_lines (current_source_symtab,
+                             line, line+1, 0);
+         current_source_line = max (line - lines_to_list () / 2, 1);
+         return;
+       }
+      line--;
+      if (fseek (stream, current_source_symtab->line_charpos[line - 1], 0) < 0)
+       {
+         fclose (stream);
+         perror_with_name (current_source_symtab->filename);
+       }
+    }
+
+  printf ("Expression not found\n");
+  fclose (stream);
+  return;
+}
+\f
+void
+_initialize_source ()
+{
+  current_source_symtab = 0;
+  init_source_path ();
+
+  add_com ("directory", class_files, directory_command,
+          "Add directory DIR to beginning of search path for source files.\n\
+Forget cached info on source file locations and line positions.\n\
+DIR can also be $cwd for the current working directory, or $cdir for the\n\
+directory in which the source file was compiled into object code.\n\
+With no argument, reset the search path to $cdir:$cwd, the default.");
+
+  add_info ("directories", directories_info,
+           "Current search path for finding source files.\n\
+$cwd in the path means the current working directory.\n\
+$cdir in the path means the compilation directory of the source file.");
+
+  add_info ("source", source_info,
+           "Information about the current source file.");
+
+  add_info ("line", line_info,
+           "Core addresses of the code for a source line.\n\
+Line can be specified as\n\
+  LINENUM, to list around that line in current file,\n\
+  FILE:LINENUM, to list around that line in that file,\n\
+  FUNCTION, to list around beginning of that function,\n\
+  FILE:FUNCTION, to distinguish among like-named static functions.\n\
+Default is to describe the last source line that was listed.\n\n\
+This sets the default address for \"x\" to the line's first instruction\n\
+so that \"x/i\" suffices to start examining the machine code.\n\
+The address is also stored as the value of \"$_\".");
+
+  add_com ("forward-search", class_files, forward_search_command,
+          "Search for regular expression (see regex(3)) from last line listed.");
+  add_com_alias ("search", "forward-search", class_files, 0);
+
+  add_com ("reverse-search", class_files, reverse_search_command,
+          "Search backward for regular expression (see regex(3)) from last line listed.");
+
+  add_com ("list", class_files, list_command,
+          "List specified function or line.\n\
+With no argument, lists ten more lines after or around previous listing.\n\
+\"list -\" lists the ten lines before a previous ten-line listing.\n\
+One argument specifies a line, and ten lines are listed around that line.\n\
+Two arguments with comma between specify starting and ending lines to list.\n\
+Lines can be specified in these ways:\n\
+  LINENUM, to list around that line in current file,\n\
+  FILE:LINENUM, to list around that line in that file,\n\
+  FUNCTION, to list around beginning of that function,\n\
+  FILE:FUNCTION, to distinguish among like-named static functions.\n\
+  *ADDRESS, to list around the line containing that address.\n\
+With two args if one is empty it stands for ten lines away from the other arg.");
+  add_com_alias ("l", "list", class_files, 0);
+}
+
diff --git a/gdb/sparc-tdep.c b/gdb/sparc-tdep.c
new file mode 100644 (file)
index 0000000..e0fb8ba
--- /dev/null
@@ -0,0 +1,586 @@
+/* Machine-dependent code which would otherwise be in inflow.c and core.c,
+   for GDB, the GNU debugger.
+   Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc.
+   This code is for the sparc cpu.
+
+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 "frame.h"
+#include "inferior.h"
+#include "obstack.h"
+#include "signame.h"
+#include "target.h"
+#include "ieee-float.h"
+
+#include <sys/param.h>
+#include <sys/dir.h>
+#include <sys/user.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+#include <sys/ptrace.h>
+#include <machine/reg.h>
+
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/core.h>
+
+#include "gdbcore.h"
+
+/* From infrun.c */
+extern int stop_after_trap;
+
+typedef enum
+{
+  Error, not_branch, bicc, bicca, ba, baa, ticc, ta,
+} branch_type;
+
+/* Simulate single-step ptrace call for sun4.  Code written by Gary
+   Beihl (beihl@mcc.com).  */
+
+/* npc4 and next_pc describe the situation at the time that the
+   step-breakpoint was set, not necessary the current value of NPC_REGNUM.  */
+static CORE_ADDR next_pc, npc4, target;
+static int brknpc4, brktrg;
+typedef char binsn_quantum[BREAKPOINT_MAX];
+static binsn_quantum break_mem[3];
+
+/* Non-zero if we just simulated a single-step ptrace call.  This is
+   needed because we cannot remove the breakpoints in the inferior
+   process until after the `wait' in `wait_for_inferior'.  Used for
+   sun4. */
+
+int one_stepped;
+
+void
+single_step (signal)
+     int signal;
+{
+  branch_type br, isannulled();
+  CORE_ADDR pc;
+  long pc_instruction;
+
+  if (!one_stepped)
+    {
+      /* Always set breakpoint for NPC.  */
+      next_pc = read_register (NPC_REGNUM);
+      npc4 = next_pc + 4; /* branch not taken */
+
+      target_insert_breakpoint (next_pc, break_mem[0]);
+      /* printf ("set break at %x\n",next_pc); */
+
+      pc = read_register (PC_REGNUM);
+      pc_instruction = read_memory_integer (pc, sizeof(pc_instruction));
+      br = isannulled (pc_instruction, pc, &target);
+      brknpc4 = brktrg = 0;
+
+      if (br == bicca)
+       {
+         /* Conditional annulled branch will either end up at
+            npc (if taken) or at npc+4 (if not taken).
+            Trap npc+4.  */
+         brknpc4 = 1;
+         target_insert_breakpoint (npc4, break_mem[1]);
+       }
+      else if (br == baa && target != next_pc)
+       {
+         /* Unconditional annulled branch will always end up at
+            the target.  */
+         brktrg = 1;
+         target_insert_breakpoint (target, break_mem[2]);
+       }
+
+      /* Let it go */
+      ptrace (7, inferior_pid, 1, signal);
+      one_stepped = 1;
+      return;
+    }
+  else
+    {
+      /* Remove breakpoints */
+      target_remove_breakpoint (next_pc, break_mem[0]);
+
+      if (brknpc4)
+       target_remove_breakpoint (npc4, break_mem[1]);
+
+      if (brktrg)
+       target_remove_breakpoint (target, break_mem[2]);
+
+      one_stepped = 0;
+    }
+}
+\f
+/*
+ * Find the pc saved in frame FRAME.  
+ */
+CORE_ADDR
+frame_saved_pc (frame)
+     FRAME frame;
+{
+  CORE_ADDR prev_pc;
+
+  /* If it's at the bottom, the return value's stored in i7/rp */
+  if (get_current_frame () == frame)
+    prev_pc = GET_RWINDOW_REG (read_register (SP_REGNUM), rw_in[7]);
+  else
+    /* Wouldn't this always work?  This would allow this routine to
+       be completely a macro.  */
+    prev_pc = GET_RWINDOW_REG (frame->bottom, rw_in[7]);
+  
+  return PC_ADJUST (prev_pc);
+}
+
+/*
+ * Since an individual frame in the frame cache is defined by two
+ * arguments (a frame pointer and a stack pointer), we need two
+ * arguments to get info for an arbitrary stack frame.  This routine
+ * takes two arguments and makes the cached frames look as if these
+ * two arguments defined a frame on the cache.  This allows the rest
+ * of info frame to extract the important arguments without
+ * difficulty. 
+ */
+FRAME
+setup_arbitrary_frame (frame, stack)
+     FRAME_ADDR frame, stack;
+{
+  FRAME fid = create_new_frame (frame, 0);
+
+  if (!fid)
+    fatal ("internal: create_new_frame returned invalid frame id");
+  
+  fid->bottom = stack;
+
+  return fid;
+}
+
+/* This code was written by Gary Beihl (beihl@mcc.com).
+   It was modified by Michael Tiemann (tiemann@corto.inria.fr).  */
+
+/*
+ * This routine appears to be passed a size by which to increase the
+ * stack.  It then executes a save instruction in the inferior to
+ * increase the stack by this amount.  Only the register window system
+ * should be affected by this; the program counter & etc. will not be.
+ *
+ * This instructions used for this purpose are:
+ *
+ *     sethi %hi(0x0),g1                    *
+ *     add g1,0x1ee0,g1                     *
+ *     save sp,g1,sp                        
+ *     sethi %hi(0x0),g1                    *
+ *     add g1,0x1ee0,g1                     *
+ *     t g0,0x1,o0
+ *     sethi %hi(0x0),g0                    (nop)
+ *
+ *  I presume that these set g1 to be the negative of the size, do a
+ * save (putting the stack pointer at sp - size) and restore the
+ * original contents of g1.  A * indicates that the actual value of
+ * the instruction is modified below.
+ */
+static int save_insn_opcodes[] = {
+  0x03000000, 0x82007ee0, 0x9de38001, 0x03000000,
+  0x82007ee0, 0x91d02001, 0x01000000 };
+
+/* Neither do_save_insn or do_restore_insn save stack configuration
+   (current_frame, etc),
+   since the stack is in an indeterminate state through the call to
+   each of them.  That responsibility of the routine which calls them.  */
+
+static void
+do_save_insn (size)
+     int size;
+{
+  int g1 = read_register (G1_REGNUM);
+  CORE_ADDR sp = read_register (SP_REGNUM);
+  CORE_ADDR pc = read_register (PC_REGNUM);
+  CORE_ADDR npc = read_register (NPC_REGNUM);
+  CORE_ADDR fake_pc = sp - sizeof (save_insn_opcodes);
+  struct inferior_status inf_status;
+
+  save_inferior_status (&inf_status, 0); /* Don't restore stack info */
+  /*
+   * See above.
+   */
+  save_insn_opcodes[0] = 0x03000000 | ((-size >> 10) & 0x3fffff);
+  save_insn_opcodes[1] = 0x82006000 | (-size & 0x3ff);
+  save_insn_opcodes[3] = 0x03000000 | ((g1 >> 10) & 0x3fffff);
+  save_insn_opcodes[4] = 0x82006000 | (g1 & 0x3ff);
+  write_memory (fake_pc, (char *)save_insn_opcodes, sizeof (save_insn_opcodes));
+
+  clear_proceed_status ();
+  stop_after_trap = 1;
+  proceed (fake_pc, 0, 0);
+
+  write_register (PC_REGNUM, pc);
+  write_register (NPC_REGNUM, npc);
+  restore_inferior_status (&inf_status);
+}
+
+/*
+ * This routine takes a program counter value.  It restores the
+ * register window system to the frame above the current one.
+ * THIS ROUTINE CLOBBERS PC AND NPC IN THE TARGET!
+ */
+
+/*    The following insns translate to:
+       restore %g0,%g0,%g0
+       t %g0,1
+       sethi %hi(0),%g0        */
+
+static int restore_insn_opcodes[] = { 0x81e80000, 0x91d02001, 0x01000000 };
+
+static void
+do_restore_insn ()
+{
+  CORE_ADDR sp = read_register (SP_REGNUM);
+  CORE_ADDR fake_pc = sp - sizeof (restore_insn_opcodes);
+  struct inferior_status inf_status;
+
+  save_inferior_status (&inf_status, 0); /* Don't restore stack info */
+
+  write_memory (fake_pc, (char *)restore_insn_opcodes,
+               sizeof (restore_insn_opcodes));
+
+  clear_proceed_status ();
+  stop_after_trap = 1;
+  proceed (fake_pc, 0, 0);
+
+  restore_inferior_status (&inf_status);
+}
+
+/* This routine should be more specific in it's actions; making sure
+   that it uses the same register in the initial prologue section.
+   Also, FIXME-SOON, it should recognize leaf functions as ones without
+   a SAVE in the prologue, and pass that info back to the caller so the
+   PC and arguments can be properly located.  */
+CORE_ADDR 
+skip_prologue (pc)
+     CORE_ADDR pc;
+{
+  union
+    {
+      unsigned long int code;
+      struct
+       {
+         unsigned int op:2;
+         unsigned int rd:5;
+         unsigned int op2:3;
+         unsigned int imm22:22;
+       } sethi;
+      struct
+       {
+         unsigned int op:2;
+         unsigned int rd:5;
+         unsigned int op3:6;
+         unsigned int rs1:5;
+         unsigned int i:1;
+         unsigned int simm13:13;
+       } add;
+      int i;
+    } x;
+  int dest = -1;
+
+  x.i = read_memory_integer (pc, 4);
+
+  /* Recognize the `sethi' insn and record its destination.  */
+  if (x.sethi.op == 0 && x.sethi.op2 == 4)
+    {
+      dest = x.sethi.rd;
+      pc += 4;
+      x.i = read_memory_integer (pc, 4);
+    }
+
+  /* Recognize an add immediate value to register to either %g1 or
+     the destination register recorded above.  Actually, this might
+     well recognize several different arithmetic operations.  */
+  if (x.add.op == 2 && x.add.i && (x.add.rd == 1 || x.add.rd == dest))
+    {
+      pc += 4;
+      x.i = read_memory_integer (pc, 4);
+    }
+
+  /* This recognizes any SAVE insn.  But why do the XOR and then
+     the compare?  That's identical to comparing against 60 (as long
+     as there isn't any sign extension).  */
+  if (x.add.op == 2 && (x.add.op3 ^ 32) == 28)
+    {
+      pc += 4;
+      x.i = read_memory_integer (pc, 4);
+    }
+
+  /* Now we need to recognize stores into the frame from the input
+     registers.  This recognizes all non alternate stores of input
+     register, into a location offset from the frame pointer.  */
+  while (x.add.op == 3
+        && (x.add.op3 & 0x3c) == 4 /* Store, non-alternate.  */
+        && (x.add.rd & 0x18) == 0x18 /* Input register.  */
+        && x.add.i             /* Immediate mode.  */
+        && x.add.rs1 == 30     /* Off of frame pointer.  */
+        /* Into reserved stack space.  */
+        && x.add.simm13 >= 0x44
+        && x.add.simm13 < 0x5b)
+    {
+      pc += 4;
+      x.i = read_memory_integer (pc, 4);
+    }
+  return pc;
+}
+
+/* Check instruction at ADDR to see if it is an annulled branch.
+   All other instructions will go to NPC or will trap.
+   Set *TARGET if we find a canidate branch; set to zero if not. */
+   
+branch_type
+isannulled (instruction, addr, target)
+     long instruction;
+     CORE_ADDR addr, *target;
+{
+  branch_type val = not_branch;
+  long int offset;             /* Must be signed for sign-extend.  */
+  union
+    {
+      unsigned long int code;
+      struct
+       {
+         unsigned int op:2;
+         unsigned int a:1;
+         unsigned int cond:4;
+         unsigned int op2:3;
+         unsigned int disp22:22;
+       } b;
+    } insn;
+
+  *target = 0;
+  insn.code = instruction;
+
+  if (insn.b.op == 0
+      && (insn.b.op2 == 2 || insn.b.op2 == 6 || insn.b.op2 == 7))
+    {
+      if (insn.b.cond == 8)
+       val = insn.b.a ? baa : ba;
+      else
+       val = insn.b.a ? bicca : bicc;
+      offset = 4 * ((int) (insn.b.disp22 << 10) >> 10);
+      *target = addr + offset;
+    }
+
+  return val;
+}
+
+/* sparc_frame_find_saved_regs ()
+
+   Stores, 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.
+
+   Note that on register window machines, we are currently making the
+   assumption that window registers are being saved somewhere in the
+   frame in which they are being used.  If they are stored in an
+   inferior frame, find_saved_register will break.
+
+   On the Sun 4, the only time all registers are saved is when
+   a dummy frame is involved.  Otherwise, the only saved registers
+   are the LOCAL and IN registers which are saved as a result
+   of the "save/restore" opcodes.  This condition is determined
+   by address rather than by value.
+
+   The "pc" is not stored in a frame on the SPARC.  (What is stored
+   is a return address minus 8.)  sparc_pop_frame knows how to
+   deal with that.  Other routines might or might not.
+
+   See tm-sparc.h (PUSH_FRAME and friends) for CRITICAL information
+   about how this works.  */
+
+void
+sparc_frame_find_saved_regs (fi, saved_regs_addr)
+     struct frame_info *fi;
+     struct frame_saved_regs *saved_regs_addr;
+{
+  register int regnum;
+  FRAME_ADDR frame = read_register (FP_REGNUM);
+  FRAME fid = FRAME_INFO_ID (fi);
+
+  if (!fid)
+    fatal ("Bad frame info struct in FRAME_FIND_SAVED_REGS");
+
+  bzero (saved_regs_addr, sizeof (*saved_regs_addr));
+
+  /* Old test.
+  if (fi->pc >= frame - CALL_DUMMY_LENGTH - 0x140
+      && fi->pc <= frame) */
+
+  if (fi->pc >= (fi->bottom ? fi->bottom :
+                  read_register (SP_REGNUM))
+      && fi->pc <= FRAME_FP(fi))
+    {
+      /* Dummy frame.  All but the window regs are in there somewhere. */
+      for (regnum = G1_REGNUM; regnum < G1_REGNUM+7; regnum++)
+       saved_regs_addr->regs[regnum] =
+         frame + (regnum - G0_REGNUM) * 4 - 0xa0;
+      for (regnum = I0_REGNUM; regnum < I0_REGNUM+8; regnum++)
+       saved_regs_addr->regs[regnum] =
+         frame + (regnum - I0_REGNUM) * 4 - 0xc0;
+      for (regnum = FP0_REGNUM; regnum < FP0_REGNUM + 32; regnum++)
+       saved_regs_addr->regs[regnum] =
+         frame + (regnum - FP0_REGNUM) * 4 - 0x80;
+      for (regnum = Y_REGNUM; regnum < NUM_REGS; regnum++)
+       saved_regs_addr->regs[regnum] =
+         frame + (regnum - Y_REGNUM) * 4 - 0xe0;
+      frame = fi->bottom ?
+       fi->bottom : read_register (SP_REGNUM);
+    }
+  else
+    {
+      /* Normal frame.  Just Local and In registers */
+      frame = fi->bottom ?
+       fi->bottom : read_register (SP_REGNUM);
+      for (regnum = L0_REGNUM; regnum < L0_REGNUM+16; regnum++)
+       saved_regs_addr->regs[regnum] = frame + (regnum-L0_REGNUM) * 4;
+    }
+  if (fi->next)
+    {
+      /* Pull off either the next frame pointer or the stack pointer */
+      FRAME_ADDR next_next_frame =
+       (fi->next->bottom ?
+        fi->next->bottom :
+        read_register (SP_REGNUM));
+      for (regnum = O0_REGNUM; regnum < O0_REGNUM+8; regnum++)
+       saved_regs_addr->regs[regnum] = next_next_frame + regnum * 4;
+    }
+  /* Otherwise, whatever we would get from ptrace(GETREGS) is accurate */
+  saved_regs_addr->regs[SP_REGNUM] = FRAME_FP (fi);
+}
+
+/* Push an empty stack frame, and record in it the current PC, regs, etc.
+
+   Note that the write's are of registers in the context of the newly
+   pushed frame.  Thus the the fp*'s, the g*'s, the i*'s, and
+   the randoms, of the new frame, are being saved.  The locals and outs
+   are new; they don't need to be saved. The i's and l's of
+   the last frame were saved by the do_save_insn in the register
+   file (now on the stack, since a context switch happended imm after).
+
+   The return pointer register %i7 does not have
+   the pc saved into it (return from this frame will be accomplished
+   by a POP_FRAME).  In fact, we must leave it unclobbered, since we
+   must preserve it in the calling routine except across call instructions.  */
+
+/* Definitely see tm-sparc.h for more doc of the frame format here.  */
+
+void
+sparc_push_dummy_frame ()
+{
+  CORE_ADDR fp;
+  char register_temp[REGISTER_BYTES];
+
+  do_save_insn (0x140); /* FIXME where does this value come from? */
+  fp = read_register (FP_REGNUM);
+
+  read_register_bytes (REGISTER_BYTE (FP0_REGNUM), register_temp, 32 * 4);
+  write_memory (fp - 0x80, register_temp, 32 * 4);
+
+  read_register_bytes (REGISTER_BYTE (G0_REGNUM), register_temp, 8 * 4);
+  write_memory (fp - 0xa0, register_temp, 8 * 4);
+
+  read_register_bytes (REGISTER_BYTE (I0_REGNUM), register_temp, 8 * 4);
+  write_memory (fp - 0xc0, register_temp, 8 * 4);
+
+  /* Y, PS, WIM, TBR, PC, NPC, FPS, CPS regs */
+  read_register_bytes (REGISTER_BYTE (Y_REGNUM), register_temp, 8 * 4);
+  write_memory (fp - 0xe0, register_temp, 8 * 4);
+}
+
+/* Discard from the stack the innermost frame, restoring all saved registers.
+
+   Note that the values stored in fsr by get_frame_saved_regs are *in
+   the context of the called frame*.  What this means is that the i
+   regs of fsr must be restored into the o regs of the (calling) frame that
+   we pop into.  We don't care about the output regs of the calling frame,
+   since unless it's a dummy frame, it won't have any output regs in it.
+
+   We never have to bother with %l (local) regs, since the called routine's
+   locals get tossed, and the calling routine's locals are already saved
+   on its stack.  */
+
+/* Definitely see tm-sparc.h for more doc of the frame format here.  */
+
+void
+sparc_pop_frame ()
+{
+  register FRAME frame = get_current_frame ();
+  register CORE_ADDR pc;
+  struct frame_saved_regs fsr;
+  struct frame_info *fi;
+  char raw_buffer[REGISTER_BYTES];
+
+  fi = get_frame_info (frame);
+  get_frame_saved_regs (fi, &fsr);
+  do_restore_insn ();
+  if (fsr.regs[FP0_REGNUM])
+    {
+      read_memory (fsr.regs[FP0_REGNUM], raw_buffer, 32 * 4);
+      write_register_bytes (REGISTER_BYTE (FP0_REGNUM), raw_buffer, 32 * 4);
+    }
+  if (fsr.regs[G1_REGNUM])
+    {
+      read_memory (fsr.regs[G1_REGNUM], raw_buffer, 7 * 4);
+      write_register_bytes (REGISTER_BYTE (G1_REGNUM), raw_buffer, 7 * 4);
+    }
+  if (fsr.regs[I0_REGNUM])
+    {
+      read_memory (fsr.regs[I0_REGNUM], raw_buffer, 8 * 4);
+      write_register_bytes (REGISTER_BYTE (O0_REGNUM), raw_buffer, 8 * 4);
+    }
+  if (fsr.regs[PS_REGNUM])
+    write_register (PS_REGNUM, read_memory_integer (fsr.regs[PS_REGNUM], 4));
+  if (fsr.regs[Y_REGNUM])
+    write_register (Y_REGNUM, read_memory_integer (fsr.regs[Y_REGNUM], 4));
+  if (fsr.regs[PC_REGNUM])
+    {
+      /* Explicitly specified PC (and maybe NPC) -- just restore them. */
+      write_register (PC_REGNUM, read_memory_integer (fsr.regs[PC_REGNUM], 4));
+      if (fsr.regs[NPC_REGNUM])
+       write_register (NPC_REGNUM,
+                       read_memory_integer (fsr.regs[NPC_REGNUM], 4));
+    }
+  else if (fsr.regs[I7_REGNUM])
+    {
+      /* Return address in %i7 -- adjust it, then restore PC and NPC from it */
+      pc = PC_ADJUST (read_memory_integer (fsr.regs[I7_REGNUM], 4));
+      write_register (PC_REGNUM,  pc);
+      write_register (NPC_REGNUM, pc + 4);
+    }
+  flush_cached_frames ();
+  set_current_frame ( create_new_frame (read_register (FP_REGNUM),
+                                       read_pc ()));
+}
+
+/* Structure of SPARC extended floating point numbers.
+   This information is not currently used by GDB, since no current SPARC
+   implementations support extended float.  */
+
+const struct ext_format ext_format_sparc[] = {
+/* tot sbyte smask expbyte manbyte */
+ { 16, 0,    0x80, 0,1,           4,8  },              /* sparc */
+};
diff --git a/gdb/stack.c b/gdb/stack.c
new file mode 100644 (file)
index 0000000..0992013
--- /dev/null
@@ -0,0 +1,1139 @@
+/* Print and select stack frames for GDB, the GNU debugger.
+   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.  */
+
+#include <stdio.h>
+
+#include "defs.h"
+#include "param.h"
+#include "symtab.h"
+#include "frame.h"
+#include "gdbcmd.h"
+#include "value.h"
+#include "gdbcore.h"
+#include "target.h"
+#include "breakpoint.h"
+
+extern int addressprint;       /* Print addresses, or stay symbolic only? */
+extern int info_verbose;       /* Verbosity of symbol reading msgs */
+extern char *reg_names[];      /* Names of registers */
+
+/* Thie "selected" stack frame is used by default for local and arg access.
+   May be zero, for no selected frame.  */
+
+FRAME selected_frame;
+
+/* Level of the selected frame:
+   0 for innermost, 1 for its caller, ...
+   or -1 for frame specified by address with no defined level.  */
+
+int selected_frame_level;
+
+/* Nonzero means print the full filename and linenumber
+   when a frame is printed, and do so in a format programs can parse.  */
+
+int frame_file_full_name = 0;
+
+void print_frame_info ();
+\f
+/* Print a stack frame briefly.  FRAME should be the frame id
+   and LEVEL should be its level in the stack (or -1 for level not defined).
+   This prints the level, the function executing, the arguments,
+   and the file name and line number.
+   If the pc is not at the beginning of the source line,
+   the actual pc is printed at the beginning.
+
+   If SOURCE is 1, print the source line as well.
+   If SOURCE is -1, print ONLY the source line.  */
+
+static void
+print_stack_frame (frame, level, source)
+     FRAME frame;
+     int level;
+     int source;
+{
+  struct frame_info *fi;
+
+  fi = get_frame_info (frame);
+
+  print_frame_info (fi, level, source, 1);
+}
+
+void
+print_frame_info (fi, level, source, args)
+     struct frame_info *fi;
+     register int level;
+     int source;
+     int args;
+{
+  struct symtab_and_line sal;
+  struct symbol *func;
+  register char *funname = 0;
+  int numargs;
+
+#if 0  /* Symbol reading is fast enough now */
+  struct partial_symtab *pst;
+
+  /* Don't give very much information if we haven't readin the
+     symbol table yet.  */
+  pst = find_pc_psymtab (fi->pc);
+  if (pst && !pst->readin)
+    {
+      /* Abbreviated information.  */
+      char *fname;
+
+      if (!find_pc_partial_function (fi->pc, &fname, 0))
+       fname = "??";
+       
+      printf_filtered ("#%-2d ", level);
+      if (addressprint)
+        printf_filtered ("0x%x in ", fi->pc);
+
+      fputs_demangled (fname, stdout, -1);
+      fputs_filtered (" (...)\n", stdout);
+      
+      return;
+    }
+#endif
+
+  sal = find_pc_line (fi->pc, fi->next_frame);
+  func = find_pc_function (fi->pc);
+  if (func)
+    {
+      /* In certain pathological cases, the symtabs give the wrong
+        function (when we are in the first function in a file which
+        is compiled without debugging symbols, the previous function
+        is compiled with debugging symbols, and the "foo.o" symbol
+        that is supposed to tell us where the file with debugging symbols
+        ends has been truncated by ar because it is longer than 15
+        characters).
+
+        So look in the misc_function_vector as well, and if it comes
+        up with a larger address for the function use that instead.
+        I don't think this can ever cause any problems;
+        there shouldn't be any
+        misc_function_vector symbols in the middle of a function.  */
+      int misc_index = find_pc_misc_function (fi->pc);
+      if (misc_index >= 0
+         && (misc_function_vector[misc_index].address
+             > BLOCK_START (SYMBOL_BLOCK_VALUE (func))))
+       {
+         /* In this case we have no way of knowing the source file
+            and line number, so don't print them.  */
+         sal.symtab = 0;
+         /* We also don't know anything about the function besides
+            its address and name.  */
+         func = 0;
+         funname = misc_function_vector[misc_index].name;
+       }
+      else
+       funname = SYMBOL_NAME (func);
+    }
+  else
+    {
+      register int misc_index = find_pc_misc_function (fi->pc);
+      if (misc_index >= 0)
+       funname = misc_function_vector[misc_index].name;
+    }
+
+  if (source >= 0 || !sal.symtab)
+    {
+      if (level >= 0)
+       printf_filtered ("#%-2d ", level);
+      if (addressprint)
+       if (fi->pc != sal.pc || !sal.symtab)
+         printf_filtered ("0x%x in ", fi->pc);
+      fputs_demangled (funname ? funname : "??", stdout, -1);
+      wrap_here ("   ");
+      fputs_filtered (" (", stdout);
+      if (args)
+       {
+         FRAME_NUM_ARGS (numargs, fi);
+         print_frame_args (func, fi, numargs, stdout);
+       }
+      printf_filtered (")");
+      if (sal.symtab && sal.symtab->filename)
+       {
+          wrap_here ("   ");
+         printf_filtered (" at %s:%d", sal.symtab->filename, sal.line);
+       }
+      printf_filtered ("\n");
+    }
+
+  if ((source != 0) && sal.symtab)
+    {
+      int done = 0;
+      int mid_statement = source < 0 && fi->pc != sal.pc;
+      if (frame_file_full_name)
+       done = identify_source_line (sal.symtab, sal.line, mid_statement);
+      if (!done)
+       {
+         if (addressprint && mid_statement)
+           printf_filtered ("0x%x\t", fi->pc);
+         print_source_lines (sal.symtab, sal.line, sal.line + 1, 0);
+       }
+      current_source_line = max (sal.line - lines_to_list () / 2, 1);
+    }
+  if (source != 0)
+    set_default_breakpoint (1, fi->pc, sal.symtab, sal.line);
+
+  fflush (stdout);
+}
+
+/* Call here to print info on selected frame, after a trap.  */
+
+void
+print_sel_frame (just_source)
+     int just_source;
+{
+  print_stack_frame (selected_frame, -1, just_source ? -1 : 1);
+}
+
+/* Print info on the selected frame, including level number
+   but not source.  */
+
+void
+print_selected_frame ()
+{
+  print_stack_frame (selected_frame, selected_frame_level, 0);
+}
+
+void flush_cached_frames ();
+
+#ifdef FRAME_SPECIFICATION_DYADIC
+extern FRAME setup_arbitrary_frame ();
+#endif
+
+/*
+ * Read a frame specification in whatever the appropriate format is.
+ */
+static FRAME
+parse_frame_specification (frame_exp)
+     char *frame_exp;
+{
+  int numargs = 0;
+  int arg1, arg2;
+  
+  if (frame_exp)
+    {
+      char *addr_string, *p;
+      struct cleanup *tmp_cleanup;
+
+      while (*frame_exp == ' ') frame_exp++;
+      for (p = frame_exp; *p && *p != ' '; p++)
+       ;
+
+      if (*frame_exp)
+       {
+         numargs = 1;
+         addr_string = savestring(frame_exp, p - frame_exp);
+
+         {
+           tmp_cleanup = make_cleanup (free, addr_string);
+           arg1 = parse_and_eval_address (addr_string);
+           do_cleanups (tmp_cleanup);
+         }
+
+         while (*p == ' ') p++;
+         
+         if (*p)
+           {
+             numargs = 2;
+             arg2 = parse_and_eval_address (p);
+           }
+       }
+    }
+
+  switch (numargs)
+    {
+    case 0:
+      return selected_frame;
+      /* NOTREACHED */
+    case 1:
+      {
+       int level = arg1;
+       FRAME fid = find_relative_frame (get_current_frame (), &level);
+       FRAME tfid;
+
+       if (level == 0)
+         /* find_relative_frame was successful */
+         return fid;
+
+       /* If (s)he specifies the frame with an address, he deserves what
+          (s)he gets.  Still, give the highest one that matches.  */
+
+       for (fid = get_current_frame ();
+            fid && FRAME_FP (fid) != arg1;
+            fid = get_prev_frame (fid))
+         ;
+
+       if (fid)
+         while ((tfid = get_prev_frame (fid)) &&
+                (FRAME_FP (tfid) == arg1))
+           fid = tfid;
+         
+#ifdef FRAME_SPECIFICATION_DYADIC
+       if (!fid)
+         error ("Incorrect number of args in frame specification");
+
+       return fid;
+#else
+       return create_new_frame (arg1, 0);
+#endif
+      }
+      /* NOTREACHED */
+    case 2:
+      /* Must be addresses */
+#ifndef FRAME_SPECIFICATION_DYADIC
+      error ("Incorrect number of args in frame specification");
+#else
+      return setup_arbitrary_frame (arg1, arg2);
+#endif
+      /* NOTREACHED */
+    }
+  fatal ("Internal: Error in parsing in parse_frame_specification");
+  /* NOTREACHED */
+}
+
+/* FRAME_ARGS_ADDRESS_CORRECT is just like FRAME_ARGS_ADDRESS except
+   that if it is unsure about the answer, it returns 0
+   instead of guessing (this happens on the VAX and i960, for example).
+
+   On most machines, we never have to guess about the args address,
+   so FRAME_ARGS_ADDRESS{,_CORRECT} are the same.  */
+#if !defined (FRAME_ARGS_ADDRESS_CORRECT)
+#define FRAME_ARGS_ADDRESS_CORRECT FRAME_ARGS_ADDRESS
+#endif
+
+/* Print verbosely the selected frame or the frame at address ADDR.
+   This means absolutely all information in the frame is printed.  */
+
+static void
+frame_info (addr_exp)
+     char *addr_exp;
+{
+  FRAME frame;
+  struct frame_info *fi;
+  struct frame_saved_regs fsr;
+  struct symtab_and_line sal;
+  struct symbol *func;
+  FRAME calling_frame;
+  int i, count;
+  char *funname = 0;
+
+  if (!target_has_stack)
+    error ("No inferior or core file.");
+
+  frame = parse_frame_specification (addr_exp);
+  if (!frame)
+    error ("Invalid frame specified.");
+
+  fi = get_frame_info (frame);
+  sal = find_pc_line (fi->pc, fi->next_frame);
+  func = get_frame_function (frame);
+  if (func)
+    funname = SYMBOL_NAME (func);
+  else
+    {
+      register int misc_index = find_pc_misc_function (fi->pc);
+      if (misc_index >= 0)
+       funname = misc_function_vector[misc_index].name;
+    }
+  calling_frame = get_prev_frame (frame);
+
+  if (!addr_exp && selected_frame_level >= 0)
+    printf_filtered ("Stack level %d, frame at 0x%x:\n %s = 0x%x",
+           selected_frame_level, FRAME_FP(frame),
+           reg_names[PC_REGNUM], fi->pc);
+  else
+    printf_filtered ("Stack frame at 0x%x:\n %s = 0x%x",
+           FRAME_FP(frame), reg_names[PC_REGNUM], fi->pc);
+
+  wrap_here ("   ");
+  if (funname)
+    printf_filtered (" in %s", funname);
+  wrap_here ("   ");
+  if (sal.symtab)
+    printf_filtered (" (%s:%d)", sal.symtab->filename, sal.line);
+  puts_filtered ("; ");
+  wrap_here ("    ");
+  printf_filtered ("saved %s 0x%x\n", reg_names[PC_REGNUM],
+                                     FRAME_SAVED_PC (frame));
+  if (calling_frame)
+    printf_filtered (" called by frame at 0x%x", FRAME_FP (calling_frame));
+  if (fi->next_frame && calling_frame)
+    puts_filtered (",");
+  wrap_here ("   ");
+  if (fi->next_frame)
+    printf_filtered (" caller of frame at 0x%x", fi->next_frame);
+  if (fi->next_frame || calling_frame)
+    puts_filtered ("\n");
+
+  {
+    /* Address of the argument list for this frame, or 0.  */
+    CORE_ADDR arg_list = FRAME_ARGS_ADDRESS_CORRECT (fi);
+    /* Number of args for this frame, or -1 if unknown.  */
+    int numargs;
+
+    if (arg_list == 0)
+       printf_filtered (" Arglist at unknown address.\n");
+    else
+      {
+       printf_filtered (" Arglist at 0x%x,", arg_list);
+
+       FRAME_NUM_ARGS (numargs, fi);
+       if (numargs < 0)
+         puts_filtered (" args: ");
+       else if (numargs == 0)
+         puts_filtered (" no args.");
+       else if (numargs == 1)
+         puts_filtered (" 1 arg: ");
+       else
+         printf_filtered (" %d args: ", numargs);
+       print_frame_args (func, fi, numargs, stdout);
+       puts_filtered ("\n");
+      }
+  }
+
+#if defined (FRAME_FIND_SAVED_REGS)  
+  get_frame_saved_regs (fi, &fsr);
+  /* The sp is special; what's returned isn't the save address, but
+     actually the value of the previous frame's sp.  */
+  printf_filtered (" Previous frame's sp is 0x%x\n", fsr.regs[SP_REGNUM]);
+  count = 0;
+  for (i = 0; i < NUM_REGS; i++)
+    if (fsr.regs[i] && i != SP_REGNUM)
+      {
+       if (count == 0)
+         puts_filtered (" Saved registers:\n ");
+       else
+         puts_filtered (",");
+       wrap_here (" ");
+       printf_filtered (" %s at 0x%x", reg_names[i], fsr.regs[i]);
+       count++;
+      }
+  if (count)
+    puts_filtered ("\n");
+#endif /* Have FRAME_FIND_SAVED_REGS.  */
+}
+
+#if 0
+/* Set a limit on the number of frames printed by default in a
+   backtrace.  */
+
+static int backtrace_limit;
+
+static void
+set_backtrace_limit_command (count_exp, from_tty)
+     char *count_exp;
+     int from_tty;
+{
+  int count = parse_and_eval_address (count_exp);
+
+  if (count < 0)
+    error ("Negative argument not meaningful as backtrace limit.");
+
+  backtrace_limit = count;
+}
+
+static void
+backtrace_limit_info (arg, from_tty)
+     char *arg;
+     int from_tty;
+{
+  if (arg)
+    error ("\"Info backtrace-limit\" takes no arguments.");
+
+  printf ("Backtrace limit: %d.\n", backtrace_limit);
+}
+#endif
+
+/* Print briefly all stack frames or just the innermost COUNT frames.  */
+
+static void
+backtrace_command (count_exp, from_tty)
+     char *count_exp;
+     int from_tty;
+{
+  struct frame_info *fi;
+  register int count;
+  register FRAME frame;
+  register int i;
+  register FRAME trailing;
+  register int trailing_level;
+
+  /* The following code must do two things.  First, it must
+     set the variable TRAILING to the frame from which we should start
+     printing.  Second, it must set the variable count to the number
+     of frames which we should print, or -1 if all of them.  */
+  trailing = get_current_frame ();
+  trailing_level = 0;
+  if (count_exp)
+    {
+      count = parse_and_eval_address (count_exp);
+      if (count < 0)
+       {
+         FRAME current;
+
+         count = -count;
+
+         current = trailing;
+         while (current && count--)
+           {
+             QUIT;
+             current = get_prev_frame (current);
+           }
+         
+         /* Will stop when CURRENT reaches the top of the stack.  TRAILING
+            will be COUNT below it.  */
+         while (current)
+           {
+             QUIT;
+             trailing = get_prev_frame (trailing);
+             current = get_prev_frame (current);
+             trailing_level++;
+           }
+         
+         count = -1;
+       }
+    }
+  else
+    count = -1;
+
+  if (info_verbose)
+    {
+      struct partial_symtab *ps;
+      
+      /* Read in symbols for all of the frames.  Need to do this in
+        a separate pass so that "Reading in symbols for xxx" messages
+        don't screw up the appearance of the backtrace.  Also
+        if people have strong opinions against reading symbols for
+        backtrace this may have to be an option.  */
+      i = count;
+      for (frame = trailing;
+          frame != NULL && i--;
+          frame = get_prev_frame (frame))
+       {
+         QUIT;
+         fi = get_frame_info (frame);
+         ps = find_pc_psymtab (fi->pc);
+         if (ps)
+           (void) PSYMTAB_TO_SYMTAB (ps);      /* Force syms to come in */
+       }
+    }
+
+  for (i = 0, frame = trailing;
+       frame && count--;
+       i++, frame = get_prev_frame (frame))
+    {
+      QUIT;
+      fi = get_frame_info (frame);
+      print_frame_info (fi, trailing_level + i, 0, 1);
+    }
+
+  /* If we've stopped before the end, mention that.  */
+  if (frame && from_tty)
+    printf_filtered ("(More stack frames follow...)\n");
+}
+\f
+/* Print the local variables of a block B active in FRAME.
+   Return 1 if any variables were printed; 0 otherwise.  */
+
+static int
+print_block_frame_locals (b, frame, stream)
+     struct block *b;
+     register FRAME frame;
+     register FILE *stream;
+{
+  int nsyms;
+  register int i;
+  register struct symbol *sym;
+  register int values_printed = 0;
+
+  nsyms = BLOCK_NSYMS (b);
+
+  for (i = 0; i < nsyms; i++)
+    {
+      sym = BLOCK_SYM (b, i);
+      if (SYMBOL_CLASS (sym) == LOC_LOCAL
+         || SYMBOL_CLASS (sym) == LOC_REGISTER
+         || SYMBOL_CLASS (sym) == LOC_STATIC)
+       {
+         values_printed = 1;
+         fprint_symbol (stream, SYMBOL_NAME (sym));
+         fputs_filtered (" = ", stream);
+         print_variable_value (sym, frame, stream);
+         fprintf_filtered (stream, "\n");
+         fflush (stream);
+       }
+    }
+  return values_printed;
+}
+
+/* Same, but print labels.
+   FIXME, this does not even reference FRAME... --gnu  */
+
+static int
+print_block_frame_labels (b, frame, have_default, stream)
+     struct block *b;
+     register FRAME frame;
+     int *have_default;
+     register FILE *stream;
+{
+  int nsyms;
+  register int i;
+  register struct symbol *sym;
+  register int values_printed = 0;
+
+  nsyms = BLOCK_NSYMS (b);
+
+  for (i = 0; i < nsyms; i++)
+    {
+      sym = BLOCK_SYM (b, i);
+      if (! strcmp (SYMBOL_NAME (sym), "default"))
+       {
+         if (*have_default)
+           continue;
+         *have_default = 1;
+       }
+      if (SYMBOL_CLASS (sym) == LOC_LABEL)
+       {
+         struct symtab_and_line sal;
+         sal = find_pc_line (SYMBOL_VALUE_ADDRESS (sym), 0);
+         values_printed = 1;
+         fputs_demangled (SYMBOL_NAME (sym), stream, 1);
+         if (addressprint)
+           fprintf_filtered (stream, " 0x%x", SYMBOL_VALUE_ADDRESS (sym));
+         fprintf_filtered (stream, " in file %s, line %d\n",
+                           sal.symtab->filename, sal.line);
+         fflush (stream);
+       }
+    }
+  return values_printed;
+}
+
+/* Print on STREAM all the local variables in frame FRAME,
+   including all the blocks active in that frame
+   at its current pc.
+
+   Returns 1 if the job was done,
+   or 0 if nothing was printed because we have no info
+   on the function running in FRAME.  */
+
+static int
+print_frame_local_vars (frame, stream)
+     register FRAME frame;
+     register FILE *stream;
+{
+  register struct block *block = get_frame_block (frame);
+  register int values_printed = 0;
+
+  if (block == 0)
+    {
+      fprintf_filtered (stream, "No symbol table info available.\n");
+      fflush (stream);
+      return 0;
+    }
+  
+  while (block != 0)
+    {
+      if (print_block_frame_locals (block, frame, stream))
+       values_printed = 1;
+      /* After handling the function's top-level block, stop.
+        Don't continue to its superblock, the block of
+        per-file symbols.  */
+      if (BLOCK_FUNCTION (block))
+       break;
+      block = BLOCK_SUPERBLOCK (block);
+    }
+
+  if (!values_printed)
+    {
+      fprintf_filtered (stream, "No locals.\n");
+      fflush (stream);
+    }
+  
+  return 1;
+}
+
+/* Same, but print labels.  */
+
+static int
+print_frame_label_vars (frame, this_level_only, stream)
+     register FRAME frame;
+     int this_level_only;
+     register FILE *stream;
+{
+  extern struct blockvector *blockvector_for_pc ();
+  register struct blockvector *bl;
+  register struct block *block = get_frame_block (frame);
+  register int values_printed = 0;
+  int index, have_default = 0;
+  char *blocks_printed;
+  struct frame_info *fi = get_frame_info (frame);
+  CORE_ADDR pc = fi->pc;
+
+  if (block == 0)
+    {
+      fprintf_filtered (stream, "No symbol table info available.\n");
+      fflush (stream);
+      return 0;
+    }
+
+  bl = blockvector_for_pc (BLOCK_END (block) - 4, &index);
+  blocks_printed = (char *) alloca (BLOCKVECTOR_NBLOCKS (bl) * sizeof (char));
+  bzero (blocks_printed, BLOCKVECTOR_NBLOCKS (bl) * sizeof (char));
+
+  while (block != 0)
+    {
+      CORE_ADDR end = BLOCK_END (block) - 4;
+      int last_index;
+
+      if (bl != blockvector_for_pc (end, &index))
+       error ("blockvector blotch");
+      if (BLOCKVECTOR_BLOCK (bl, index) != block)
+       error ("blockvector botch");
+      last_index = BLOCKVECTOR_NBLOCKS (bl);
+      index += 1;
+
+      /* Don't print out blocks that have gone by.  */
+      while (index < last_index
+            && BLOCK_END (BLOCKVECTOR_BLOCK (bl, index)) < pc)
+       index++;
+
+      while (index < last_index
+            && BLOCK_END (BLOCKVECTOR_BLOCK (bl, index)) < end)
+       {
+         if (blocks_printed[index] == 0)
+           {
+             if (print_block_frame_labels (BLOCKVECTOR_BLOCK (bl, index), frame, &have_default, stream))
+               values_printed = 1;
+             blocks_printed[index] = 1;
+           }
+         index++;
+       }
+      if (have_default)
+       return 1;
+      if (values_printed && this_level_only)
+       return 1;
+
+      /* After handling the function's top-level block, stop.
+        Don't continue to its superblock, the block of
+        per-file symbols.  */
+      if (BLOCK_FUNCTION (block))
+       break;
+      block = BLOCK_SUPERBLOCK (block);
+    }
+
+  if (!values_printed && !this_level_only)
+    {
+      fprintf_filtered (stream, "No catches.\n");
+      fflush (stream);
+    }
+  
+  return values_printed;
+}
+
+static void
+locals_info (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  if (!target_has_stack)
+    error ("No stack.");
+
+  print_frame_local_vars (selected_frame, stdout);
+}
+
+static void
+catch_info ()
+{
+  if (!target_has_stack)
+    error ("No stack.");
+
+  print_frame_label_vars (selected_frame, 0, stdout);
+}
+
+static int
+print_frame_arg_vars (frame, stream)
+     register FRAME frame;
+     register FILE *stream;
+{
+  struct symbol *func = get_frame_function (frame);
+  register struct block *b;
+  int nsyms;
+  register int i;
+  register struct symbol *sym, *sym2;
+  register int values_printed = 0;
+
+  if (func == 0)
+    {
+      fprintf_filtered (stream, "No symbol table info available.\n");
+      fflush (stream);
+      return 0;
+    }
+
+  b = SYMBOL_BLOCK_VALUE (func);
+  nsyms = BLOCK_NSYMS (b);
+
+  for (i = 0; i < nsyms; i++)
+    {
+      sym = BLOCK_SYM (b, i);
+      if (SYMBOL_CLASS (sym) == LOC_ARG
+         || SYMBOL_CLASS (sym) == LOC_LOCAL_ARG
+         || SYMBOL_CLASS (sym) == LOC_REF_ARG
+         || SYMBOL_CLASS (sym) == LOC_REGPARM)
+       {
+         values_printed = 1;
+         fprint_symbol (stream, SYMBOL_NAME (sym));
+         fputs_filtered (" = ", stream);
+         /* We have to look up the symbol because arguments often have
+            two entries (one a parameter, one a register) and the one
+            we want is the register, which lookup_symbol will find for
+            us.  */
+         sym2 = lookup_symbol (SYMBOL_NAME (sym),
+                       b, VAR_NAMESPACE, (int *)NULL, (struct symtab **)NULL);
+         print_variable_value (sym2, frame, stream);
+         fprintf_filtered (stream, "\n");
+         fflush (stream);
+       }
+    }
+
+  if (!values_printed)
+    {
+      fprintf_filtered (stream, "No arguments.\n");
+      fflush (stream);
+    }
+
+  return 1;
+}
+
+static void
+args_info ()
+{
+  if (!target_has_stack)
+    error ("No stack.");
+  print_frame_arg_vars (selected_frame, stdout);
+}
+\f
+/* Select frame FRAME, and note that its stack level is LEVEL.
+   LEVEL may be -1 if an actual level number is not known.  */
+
+void
+select_frame (frame, level)
+     FRAME frame;
+     int level;
+{
+  selected_frame = frame;
+  selected_frame_level = level;
+  /* Ensure that symbols for this frame are readin.  */
+  if (frame)
+    find_pc_symtab (get_frame_info (frame)->pc);
+}
+
+/* Store the selected frame and its level into *FRAMEP and *LEVELP.  */
+
+void
+record_selected_frame (frameaddrp, levelp)
+     FRAME_ADDR *frameaddrp;
+     int *levelp;
+{
+  *frameaddrp = FRAME_FP (selected_frame);
+  *levelp = selected_frame_level;
+}
+
+/* Return the symbol-block in which the selected frame is executing.
+   Can return zero under various legitimate circumstances.  */
+
+struct block *
+get_selected_block ()
+{
+  if (!target_has_stack)
+    return 0;
+
+  if (!selected_frame)
+    return get_current_block ();
+  return get_frame_block (selected_frame);
+}
+
+/* Find a frame a certain number of levels away from FRAME.
+   LEVEL_OFFSET_PTR points to an int containing the number of levels.
+   Positive means go to earlier frames (up); negative, the reverse.
+   The int that contains the number of levels is counted toward
+   zero as the frames for those levels are found.
+   If the top or bottom frame is reached, that frame is returned,
+   but the final value of *LEVEL_OFFSET_PTR is nonzero and indicates
+   how much farther the original request asked to go.  */
+
+FRAME
+find_relative_frame (frame, level_offset_ptr)
+     register FRAME frame;
+     register int* level_offset_ptr;
+{
+  register FRAME prev;
+  register FRAME frame1, frame2;
+
+  /* Going up is simple: just do get_prev_frame enough times
+     or until initial frame is reached.  */
+  while (*level_offset_ptr > 0)
+    {
+      prev = get_prev_frame (frame);
+      if (prev == 0)
+       break;
+      (*level_offset_ptr)--;
+      frame = prev;
+    }
+  /* Going down could be done by iterating get_frame_info to
+     find the next frame, but that would be quadratic
+     since get_frame_info must scan all the way from the current frame.
+     The following algorithm is linear.  */
+  if (*level_offset_ptr < 0)
+    {
+      /* First put frame1 at innermost frame
+        and frame2 N levels up from there.  */
+      frame1 = get_current_frame ();
+      frame2 = frame1;
+      while (*level_offset_ptr < 0 && frame2 != frame)
+       {
+         frame2 = get_prev_frame (frame2);
+         (*level_offset_ptr) ++;
+       }
+      /* Then slide frame1 and frame2 up in synchrony
+        and when frame2 reaches our starting point
+        frame1 must be N levels down from there.  */
+      while (frame2 != frame)
+       {
+         frame1 = get_prev_frame (frame1);
+         frame2 = get_prev_frame (frame2);
+       }
+      return frame1;
+    }
+  return frame;
+}
+
+/* The "frame" command.  With no arg, print selected frame briefly.
+   With arg LEVEL_EXP, select the frame at level LEVEL if it is a
+   valid level.  Otherwise, treat level_exp as an address expression
+   and print it.  See parse_frame_specification for more info on proper
+   frame expressions. */
+
+static void
+frame_command (level_exp, from_tty)
+     char *level_exp;
+     int from_tty;
+{
+  register FRAME frame, frame1;
+  unsigned int level = 0;
+
+  if (!target_has_stack)
+    error ("No stack.");
+
+  frame = parse_frame_specification (level_exp);
+
+  for (frame1 = get_prev_frame (0);
+       frame1 && frame1 != frame;
+       frame1 = get_prev_frame (frame1))
+    level++;
+
+  if (!frame1)
+    level = 0;
+
+  select_frame (frame, level);
+
+  if (!from_tty)
+    return;
+
+  print_stack_frame (selected_frame, selected_frame_level, 1);
+}
+
+/* Select the frame up one or COUNT stack levels
+   from the previously selected frame, and print it briefly.  */
+
+static void
+up_silently_command (count_exp, from_tty)
+     char *count_exp;
+     int from_tty;
+{
+  register FRAME frame;
+  int count = 1, count1;
+  if (count_exp)
+    count = parse_and_eval_address (count_exp);
+  count1 = count;
+  
+  if (!target_has_stack)
+    error ("No stack.");
+
+  frame = find_relative_frame (selected_frame, &count1);
+  if (count1 != 0 && count_exp == 0)
+    error ("Initial frame selected; you cannot go up.");
+  select_frame (frame, selected_frame_level + count - count1);
+}
+
+static void
+up_command (count_exp, from_tty)
+     char *count_exp;
+     int from_tty;
+{
+  up_silently_command (count_exp, from_tty);
+  print_stack_frame (selected_frame, selected_frame_level, 1);
+}
+
+/* Select the frame down one or COUNT stack levels
+   from the previously selected frame, and print it briefly.  */
+
+static void
+down_silently_command (count_exp, from_tty)
+     char *count_exp;
+     int from_tty;
+{
+  register FRAME frame;
+  int count = -1, count1;
+  if (count_exp)
+    count = - parse_and_eval_address (count_exp);
+  count1 = count;
+  
+  frame = find_relative_frame (selected_frame, &count1);
+  if (count1 != 0 && count_exp == 0)
+    error ("Bottom (i.e., innermost) frame selected; you cannot go down.");
+  select_frame (frame, selected_frame_level + count - count1);
+}
+
+
+static void
+down_command (count_exp, from_tty)
+     char *count_exp;
+     int from_tty;
+{
+  down_silently_command (count_exp, from_tty);
+  print_stack_frame (selected_frame, selected_frame_level, 1);
+}
+\f
+static void
+return_command (retval_exp, from_tty)
+     char *retval_exp;
+     int from_tty;
+{
+  struct symbol *thisfun = get_frame_function (selected_frame);
+  FRAME_ADDR selected_frame_addr = FRAME_FP (selected_frame);
+  CORE_ADDR selected_frame_pc = (get_frame_info (selected_frame))->pc;
+  FRAME frame;
+
+  /* If interactive, require confirmation.  */
+
+  if (from_tty)
+    {
+      if (thisfun != 0)
+       {
+         if (!query ("Make %s return now? ", SYMBOL_NAME (thisfun)))
+           error ("Not confirmed.");
+       }
+      else
+       if (!query ("Make selected stack frame return now? "))
+         error ("Not confirmed.");
+    }
+
+  /* Do the real work.  Pop until the specified frame is current.  We
+     use this method because the selected_frame is not valid after
+     a POP_FRAME.  The pc comparison makes this work even if the
+     selected frame shares its fp with another frame.  */
+
+  while ( selected_frame_addr != FRAME_FP (frame = get_current_frame())
+       || selected_frame_pc   != (get_frame_info (frame))->pc  )
+    POP_FRAME;
+
+  /* Then pop that frame.  */
+
+  POP_FRAME;
+
+  /* Compute the return value (if any) and store in the place
+     for return values.  */
+
+  if (retval_exp)
+    set_return_value (parse_and_eval (retval_exp));
+
+  /* If interactive, print the frame that is now current.  */
+
+  if (from_tty)
+    frame_command ("0", 1);
+}
+\f
+void
+_initialize_stack ()
+{
+#if 0  
+  backtrace_limit = 30;
+#endif
+
+  add_com ("return", class_stack, return_command,
+          "Make selected stack frame return to its caller.\n\
+Control remains in the debugger, but when you continue\n\
+execution will resume in the frame above the one now selected.\n\
+If an argument is given, it is an expression for the value to return.");
+
+  add_com ("up", class_stack, up_command,
+          "Select and print stack frame that called this one.\n\
+An argument says how many frames up to go.");
+  add_com ("up-silently", class_support, up_silently_command,
+          "Same as the `up' command, but does not print anything.\n\
+This is useful in command scripts.");
+
+  add_com ("down", class_stack, down_command,
+          "Select and print stack frame called by this one.\n\
+An argument says how many frames down to go.");
+  add_com_alias ("do", "down", class_stack, 1);
+  add_com ("down-silently", class_support, down_silently_command,
+          "Same as the `down' command, but does not print anything.\n\
+This is useful in command scripts.");
+
+  add_com ("frame", class_stack, frame_command,
+          "Select and print a stack frame.\n\
+With no argument, print the selected stack frame.  (See also \"info frame\").\n\
+An argument specifies the frame to select.\n\
+It can be a stack frame number or the address of the frame.\n\
+With argument, nothing is printed if input is coming from\n\
+a command file or a user-defined command.");
+
+  add_com_alias ("f", "frame", class_stack, 1);
+
+  add_com ("backtrace", class_stack, backtrace_command,
+          "Print backtrace of all stack frames, or innermost COUNT frames.\n\
+With a negative argument, print outermost -COUNT frames.");
+  add_com_alias ("bt", "backtrace", class_stack, 0);
+  add_com_alias ("where", "backtrace", class_alias, 0);
+  add_info ("stack", backtrace_command,
+           "Backtrace of the stack, or innermost COUNT frames.");
+  add_info_alias ("s", "stack", 1);
+  add_info ("frame", frame_info,
+           "All about selected stack frame, or frame at ADDR.");
+  add_info_alias ("f", "frame", 1);
+  add_info ("locals", locals_info,
+           "Local variables of current stack frame.");
+  add_info ("args", args_info,
+           "Argument variables of current stack frame.");
+  add_info ("catch", catch_info,
+           "Exceptions that can be caught in the current stack frame.");
+
+#if 0
+  add_cmd ("backtrace-limit", class_stack, set_backtrace_limit_command, 
+          "Specify maximum number of frames for \"backtrace\" to print by default.",
+          &setlist);
+  add_info ("backtrace-limit", backtrace_limit_info,
+           "The maximum number of frames for \"backtrace\" to print by default.");
+#endif
+}
+
diff --git a/gdb/symfile.c b/gdb/symfile.c
new file mode 100644 (file)
index 0000000..31aa1e2
--- /dev/null
@@ -0,0 +1,746 @@
+/* Generic symbol file reading for the GNU debugger, GDB.
+   Copyright 1990, 1991 Free Software Foundation, Inc.
+   Contributed by Cygnus Support, using pieces from other GDB modules.
+
+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 "symtab.h"
+#include "param.h"
+#include "gdbcore.h"
+#include "frame.h"
+#include "target.h"
+#include "value.h"
+#include "symfile.h"
+#include "gdbcmd.h"
+#include "breakpoint.h"
+
+#include <obstack.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/stat.h>
+
+extern int info_verbose;
+
+extern int close ();
+extern void qsort ();
+extern char *getenv ();
+
+/* Functions this file defines */
+static bfd *symfile_open();
+static struct sym_fns *symfile_init();
+
+/* List of all available sym_fns.  */
+
+struct sym_fns *symtab_fns = NULL;
+
+/* Saves the sym_fns of the current symbol table, so we can call
+   the right sym_discard function when we free it.  */
+
+static struct sym_fns *symfile_fns;
+
+/* Allocate an obstack to hold objects that should be freed
+   when we load a new symbol table.
+   This includes the symbols made by dbxread
+   and the types that are not permanent.  */
+
+struct obstack obstack1;
+
+struct obstack *symbol_obstack = &obstack1;
+
+/* This obstack will be used for partial_symbol objects.  It can
+   probably actually be the same as the symbol_obstack above, but I'd
+   like to keep them seperate for now.  If I want to later, I'll
+   replace one with the other.  */
+
+struct obstack obstack2;
+
+struct obstack *psymbol_obstack = &obstack2;
+
+/* File name symbols were loaded from.  */
+
+char *symfile = 0;
+
+/* The modification date of the file when they were loaded.  */
+
+int symfile_mtime = 0;
+
+/* Structures with which to manage partial symbol allocation.  */
+
+struct psymbol_allocation_list global_psymbols = {0}, static_psymbols = {0};
+
+/* Structure to manage complaints about symbol file contents.  */
+
+struct complaint complaint_root[1] = {
+  {(char *)0, 0, complaint_root},
+};
+
+\f
+/* In the following sort, we always make sure that
+   register debug symbol declarations always come before regular
+   debug symbol declarations (as might happen when parameters are
+   then put into registers by the compiler).  */
+
+static int
+compare_symbols (s1, s2)
+     struct symbol **s1, **s2;
+{
+  register int namediff;
+
+  /* Compare the initial characters.  */
+  namediff = SYMBOL_NAME (*s1)[0] - SYMBOL_NAME (*s2)[0];
+  if (namediff != 0) return namediff;
+
+  /* If they match, compare the rest of the names.  */
+  namediff = strcmp (SYMBOL_NAME (*s1), SYMBOL_NAME (*s2));
+  if (namediff != 0) return namediff;
+
+  /* For symbols of the same name, registers should come first.  */
+  return ((SYMBOL_CLASS (*s2) == LOC_REGISTER)
+         - (SYMBOL_CLASS (*s1) == LOC_REGISTER));
+}
+
+/* Call sort_block_syms to sort alphabetically the symbols of one block.  */
+
+void
+sort_block_syms (b)
+     register struct block *b;
+{
+  qsort (&BLOCK_SYM (b, 0), BLOCK_NSYMS (b),
+        sizeof (struct symbol *), compare_symbols);
+}
+
+/* Call sort_symtab_syms to sort alphabetically
+   the symbols of each block of one symtab.  */
+
+void
+sort_symtab_syms (s)
+     register struct symtab *s;
+{
+  register struct blockvector *bv = BLOCKVECTOR (s);
+  int nbl = BLOCKVECTOR_NBLOCKS (bv);
+  int i;
+  register struct block *b;
+
+  for (i = 0; i < nbl; i++)
+    {
+      b = BLOCKVECTOR_BLOCK (bv, i);
+      if (BLOCK_SHOULD_SORT (b))
+       sort_block_syms (b);
+    }
+}
+
+void
+sort_all_symtab_syms ()
+{
+  register struct symtab *s;
+
+  for (s = symtab_list; s; s = s->next)
+    {
+      sort_symtab_syms (s);
+    }
+}
+
+/* Make a copy of the string at PTR with SIZE characters in the symbol obstack
+   (and add a null character at the end in the copy).
+   Returns the address of the copy.  */
+
+char *
+obsavestring (ptr, size)
+     char *ptr;
+     int size;
+{
+  register char *p = (char *) obstack_alloc (symbol_obstack, size + 1);
+  /* Open-coded bcopy--saves function call time.
+     These strings are usually short.  */
+  {
+    register char *p1 = ptr;
+    register char *p2 = p;
+    char *end = ptr + size;
+    while (p1 != end)
+      *p2++ = *p1++;
+  }
+  p[size] = 0;
+  return p;
+}
+
+/* Concatenate strings S1, S2 and S3; return the new string.
+   Space is found in the symbol_obstack.  */
+
+char *
+obconcat (s1, s2, s3)
+     char *s1, *s2, *s3;
+{
+  register int len = strlen (s1) + strlen (s2) + strlen (s3) + 1;
+  register char *val = (char *) obstack_alloc (symbol_obstack, len);
+  strcpy (val, s1);
+  strcat (val, s2);
+  strcat (val, s3);
+  return val;
+}
+\f
+/* 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;
+
+void
+init_misc_bunches ()
+{
+  misc_count = 0;
+  misc_bunch = 0;
+  misc_bunch_index = MISC_BUNCH_SIZE;
+}
+
+void
+prim_record_misc_function (name, address, misc_type)
+     char *name;
+     CORE_ADDR address;
+     enum misc_function_type misc_type;
+{
+  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 = name;
+  misc_bunch->contents[misc_bunch_index].address = address;
+  misc_bunch->contents[misc_bunch_index].type = misc_type;
+  misc_bunch->contents[misc_bunch_index].misc_info = 0;
+  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;
+}
+
+/* ARGSUSED */
+void
+discard_misc_bunches (foo)
+     int foo;
+{
+  register struct misc_bunch *next;
+
+  while (misc_bunch)
+    {
+      next = misc_bunch->next;
+      free (misc_bunch);
+      misc_bunch = next;
+    }
+}
+
+/* INCLINK nonzero means bunches are from an incrementally-linked file.
+   Add them to the existing bunches.
+   Otherwise INCLINK is zero, and we start from scratch. */
+void
+condense_misc_bunches (inclink)
+     int inclink;
+{
+  register int i, j;
+  register struct misc_bunch *bunch;
+
+  if (inclink)
+    {
+      misc_function_vector
+       = (struct misc_function *)
+         xrealloc (misc_function_vector, (misc_count + misc_function_count)
+                   * sizeof (struct misc_function));
+      j = misc_function_count;
+    }
+  else
+    {
+      misc_function_vector
+       = (struct misc_function *)
+         xmalloc (misc_count * sizeof (struct misc_function));
+      j = 0;
+    }
+
+  bunch = misc_bunch;
+  while (bunch)
+    {
+      for (i = 0; i < misc_bunch_index; i++, j++)
+        {
+         misc_function_vector[j] = bunch->contents[i];
+#ifdef NAMES_HAVE_UNDERSCORE
+         if (misc_function_vector[j].name[0] == '_')
+             misc_function_vector[j].name++;
+#endif
+       }
+      bunch = bunch->next;
+      misc_bunch_index = MISC_BUNCH_SIZE;
+    }
+
+  if (misc_function_count + misc_count != j)           /* DEBUG */
+    printf_filtered ("Function counts are off!  %d + %d != %d\n",
+      misc_function_count, misc_count, j);
+
+  misc_function_count = j;
+
+  /* Sort the misc functions by address.  */
+
+  qsort (misc_function_vector, misc_function_count,
+        sizeof (struct misc_function),
+        compare_misc_functions);
+}
+
+
+/* Get the symbol table that corresponds to a partial_symtab.
+   This is fast after the first time you do it.  In fact, there
+   is an even faster macro PSYMTAB_TO_SYMTAB that does the fast
+   case inline.  */
+
+struct symtab *
+psymtab_to_symtab (pst)
+     register struct partial_symtab *pst;
+{
+  register struct symtab *result;
+
+  /* If it's been looked up before, return it. */
+  if (pst->symtab)
+    return pst->symtab;
+
+  /* If it has not yet been read in, read it.  */
+  if (!pst->readin)
+    { 
+      (*pst->read_symtab) (pst);
+    }
+
+  /* Search through list for correct name. */
+  for (result = symtab_list; result; result = result->next)
+    if (!strcmp (result->filename, pst->filename))
+      {
+       pst->symtab = result;           /* Remember where it was.  */
+       return result;
+      }
+
+  return 0;
+}
+
+/* Process a symbol file, as either the main file or as a dynamically
+   loaded file.
+
+   NAME is the file name (which will be tilde-expanded and made absolute
+   herein).  FROM_TTY says how verbose to be.  MAINLINE specifies whether
+   this is the main symbol file, or whether it's an extra symbol file
+   such as dynamically loaded code.  If !mainline, ADDR is the address
+   where the text segment was loaded.  */
+
+void
+symbol_file_add (name, from_tty, addr, mainline)
+     char *name;
+     int from_tty;
+     CORE_ADDR addr;
+     int mainline;
+{
+  bfd *sym_bfd;
+  asection *text_sect;
+  struct sym_fns *sf;
+  char *realname;
+
+  sym_bfd = symfile_open (name);
+
+  entry_point = bfd_get_start_address (sym_bfd);
+
+  if (mainline)
+    symfile_mtime = bfd_get_mtime (sym_bfd);
+
+  /* There is a distinction between having no symbol table
+     (we refuse to read the file, leaving the old set of symbols around)
+     and having no debugging symbols in your symbol table (we read
+     the file and end up with a mostly empty symbol table).  */
+
+  if (!(bfd_get_file_flags (sym_bfd) & HAS_SYMS))
+    {
+      error ("%s has no symbol-table", name);
+    }
+
+  if ((symtab_list || partial_symtab_list)
+      && mainline
+      && from_tty
+      && !query ("Load new symbol table from \"%s\"? ", name))
+    error ("Not confirmed.");
+
+  if (from_tty)
+    {
+      printf ("Reading symbol data from %s...", name);
+      fflush (stdout);
+    }
+
+  sf = symfile_init (sym_bfd);
+  realname = bfd_get_filename (sym_bfd);
+  realname = savestring (realname, strlen (realname));
+  /* FIXME, this probably creates a storage leak... */
+
+  if (mainline) 
+    {
+      /* Since no error yet, throw away the old symbol table.  */
+
+      if (symfile)
+       free (symfile);
+      symfile = 0;
+      free_all_symtabs ();
+      free_all_psymtabs ();
+
+      (*sf->sym_new_init) ();
+
+      /* For mainline, caller didn't know the specified address of the
+         text section.  We fix that here.  */
+      text_sect = bfd_get_section_by_name (sym_bfd, ".text");
+      addr = bfd_section_vma (sym_bfd, text_sect);
+    }
+
+  clear_complaints();  /* Allow complaints to appear for this new file. */
+
+  (*sf->sym_read) (sf, addr, mainline);
+
+  /* Don't allow char * to have a typename (else would get caddr_t.)  */
+  /* Ditto void *.  FIXME should do this for all the builtin types.  */
+
+  TYPE_NAME (lookup_pointer_type (builtin_type_char)) = 0;
+  TYPE_NAME (lookup_pointer_type (builtin_type_void)) = 0;
+
+  if (mainline)
+    {
+      /* OK, make it the "real" symbol file.  */
+      symfile = realname;
+      symfile_fns = sf;
+    }
+
+  if (from_tty)
+    {
+      printf ("done.\n");
+      fflush (stdout);
+    }
+}
+
+/* This is the symbol-file command.  Read the file, analyze its symbols,
+   and add a struct symtab to symtab_list.  */
+
+void
+symbol_file_command (name, from_tty)
+     char *name;
+     int from_tty;
+{
+
+  dont_repeat ();
+
+  if (name == 0)
+    {
+      if ((symtab_list || partial_symtab_list)
+         && from_tty
+         && !query ("Discard symbol table from `%s'? ", symfile))
+       error ("Not confirmed.");
+      if (symfile)
+       free (symfile);
+      symfile = 0;
+      free_all_symtabs ();
+      free_all_psymtabs ();
+      /* FIXME, this does not account for the main file and subsequent
+         files (shared libs, dynloads, etc) having different formats. 
+         It only calls the cleanup routine for the main file's format.  */
+      (*symfile_fns->sym_new_init) ();
+      free (symfile_fns);
+      symfile_fns = 0;
+      return;
+    }
+
+  symbol_file_add (name, from_tty, (CORE_ADDR)0, 1);
+}
+
+/* Open NAME and hand it off to BFD for preliminary analysis.  Result
+   is a BFD *, which includes a new copy of NAME dynamically allocated
+   (which will be freed by the cleanup chain).  In case of trouble,
+   error() is called.  */
+
+static bfd *
+symfile_open (name)
+     char *name;
+{
+  bfd *sym_bfd;
+  int desc;
+  char *absolute_name;
+
+  name = tilde_expand (name);
+  make_cleanup (free, name);
+
+  desc = openp (getenv ("PATH"), 1, name, O_RDONLY, 0, &absolute_name);
+  if (desc < 0)
+    perror_with_name (name);
+  else
+    {
+      make_cleanup (free, absolute_name);
+      name = absolute_name;
+    }
+
+  sym_bfd = bfd_fdopenr (name, NULL, desc);
+  if (!sym_bfd)
+    {
+      close (desc);
+      error ("Could not open `%s' to read symbols: %s",
+            name, bfd_errmsg (bfd_error));
+    }
+  make_cleanup (bfd_close, sym_bfd);
+
+  if (!bfd_check_format (sym_bfd, bfd_object))
+    error ("\"%s\": can't read symbols: %s.",
+          name, bfd_errmsg (bfd_error));
+
+  return sym_bfd;
+}
+
+/* Link a new symtab_fns into the global symtab_fns list.
+   Called by various _initialize routines.  */
+
+void
+add_symtab_fns (sf)
+     struct sym_fns *sf;
+{
+  sf->next = symtab_fns;
+  symtab_fns = sf;
+}
+
+
+/* Initialize to read symbols from the symbol file sym_bfd.  It either
+   returns or calls error().  The result is a malloc'd struct sym_fns
+   that contains cached information about the symbol file.  */
+
+static struct sym_fns *
+symfile_init (sym_bfd)
+     bfd *sym_bfd;
+{
+  struct sym_fns *sf, *sf2;
+
+  for (sf = symtab_fns; sf != NULL; sf = sf->next)
+    {
+      if (!strncmp (bfd_get_target (sym_bfd), sf->sym_name, sf->sym_namelen))
+       {
+         sf2 = (struct sym_fns *)xmalloc (sizeof (*sf2));      
+         /* FIXME, who frees this? */
+         *sf2 = *sf;
+         sf2->sym_bfd = sym_bfd;
+         sf2->sym_private = 0;                 /* Not alloc'd yet */
+         (*sf2->sym_init) (sf2);
+         return sf2;
+       }
+    }
+  error ("I'm sorry, Dave, I can't do that.  Symbol format unknown.");
+}
+\f
+/* This function runs the load command of our current target.  */
+
+void
+load_command (arg, from_tty)
+     char *arg;
+     int from_tty;
+{
+  target_load (arg, from_tty);
+}
+
+/* This function runs the add_syms command of our current target.  */
+
+void
+add_syms_command (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  target_add_syms (args, from_tty);
+}
+
+/* This function allows the addition of incrementally linked object files.  */
+
+void
+add_syms_addr_command (arg_string, from_tty)
+     char* arg_string;
+     int from_tty;
+{
+  char *name;
+  CORE_ADDR text_addr;
+  
+  if (arg_string == 0)
+    error ("add-syms takes a file name and an address");
+
+  arg_string = tilde_expand (arg_string);
+  make_cleanup (free, arg_string);
+
+  for( ; *arg_string == ' '; arg_string++ );
+  name = arg_string;
+  for( ; *arg_string && *arg_string != ' ' ; arg_string++ );
+  *arg_string++ = (char) 0;
+
+  if (name[0] == 0)
+    error ("add-syms takes a file name and an address");
+
+  text_addr = parse_and_eval_address (arg_string);
+
+  dont_repeat ();
+
+  if (!query ("add symbol table from file \"%s\" at text_addr = 0x%x\n",
+             name, text_addr))
+    error ("Not confirmed.");
+
+  symbol_file_add (name, 0, text_addr, 0);
+}
+\f
+/* Re-read symbols if the symbol-file has changed.  */
+void
+reread_symbols ()
+{
+  struct stat symstat;
+
+  /* With the addition of shared libraries, this should be modified,
+     the load time should be saved in the partial symbol tables, since
+     different tables may come from different source files.  FIXME.
+     This routine should then walk down each partial symbol table
+     and see if the symbol table that it originates from has been changed
+  */
+
+  if (stat (symfile, &symstat) < 0)
+    /* Can't read symbol-file.  Assume it is up to date.  */
+    return;
+
+  if (symstat.st_mtime > symfile_mtime)
+    {
+      printf_filtered ("Symbol file has changed; re-reading symbols.\n");
+      symbol_file_command (symfile, 0);
+      breakpoint_re_set ();
+    }
+}
+
+
+/* This function is really horrible, but to avoid it, there would need
+   to be more filling in of forward references.  */
+int
+fill_in_vptr_fieldno (type)
+     struct type *type;
+{
+  check_stub_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);
+}
+\f
+/* Functions to handle complaints during symbol reading.  */
+
+/* How many complaints about a particular thing should be printed before
+   we stop whining about it?  */
+
+static unsigned stop_whining = 1;
+
+/* Print a complaint about the input symbols, and link the complaint block
+   into a chain for later handling.  Result is 1 if the complaint was
+   printed, 0 if it was suppressed.  */
+
+int
+complain (complaint, val)
+     struct complaint *complaint;
+     char *val;
+{
+  complaint->counter++;
+  if (complaint->next == 0) {
+    complaint->next = complaint_root->next;
+    complaint_root->next = complaint;
+  }
+  if (complaint->counter > stop_whining)
+    return 0;
+  wrap_here ("");
+  if (!info_verbose) {
+    puts_filtered ("During symbol reading...");
+  }
+  printf_filtered (complaint->message, val);
+  puts_filtered ("...");
+  wrap_here("");
+  if (!info_verbose)
+    puts_filtered ("\n");
+  return 1;
+}
+
+/* Clear out all complaint counters that have ever been incremented.  */
+
+void
+clear_complaints ()
+{
+  struct complaint *p;
+
+  for (p = complaint_root->next; p != complaint_root; p = p->next)
+    p->counter = 0;
+}
+\f
+void
+_initialize_symfile ()
+{
+
+  add_com ("symbol-file", class_files, symbol_file_command,
+          "Load symbol table from executable file FILE.\n\
+The `file' command can also load symbol tables, as well as setting the file\n\
+to execute.");
+
+  add_com ("add-syms", class_files, add_syms_command,
+   "Load the symbols from FILE, assuming FILE has been dynamically loaded.\n\
+The second argument provides the starting address of the file's text.");
+
+  add_com ("load", class_files, load_command,
+   "Dynamically load FILE into the running program, and record its symbols\n\
+for access from GDB.");
+
+  add_show_from_set
+    (add_set_cmd ("complaints", class_support, var_uinteger,
+                 (char *)&stop_whining,
+         "Set max number of complaints about incorrect symbols.",
+                 &setlist),
+     &showlist);
+
+  obstack_init (symbol_obstack);
+  obstack_init (psymbol_obstack);
+}
diff --git a/gdb/symfile.h b/gdb/symfile.h
new file mode 100644 (file)
index 0000000..6785117
--- /dev/null
@@ -0,0 +1,170 @@
+/* Definitions for reading symbol files into GDB.
+   Copyright (C) 1990  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.  */
+
+/* This file requires that you first include "bfd.h".  */
+
+/* Data structures and function definitions for dealing with
+   symbol table reading from files.  */
+
+/* Structure to keep track of symbol reading functions for various
+   object file types.  */
+
+struct sym_fns {
+
+  /* sym_name
+     is the name, or name prefix, of the BFD "target type" that this
+     set of functions handles.  E.g. "a.out" or "sunOs" or "coff".  */
+
+  char *sym_name;
+
+  /* sym_namelen
+     counts how many bytes of sym_name should be checked against the
+     BFD target type of the file being read.  If an exact match is
+     desired, specify the number of characters in sym_name plus 1 for the
+     NUL.  If a prefix match is desired, specify the number of characters in
+     sym_name.  */
+
+  int sym_namelen;
+
+  /* sym_new_init
+     initializes anything that is global to the entire
+     symbol table.  It is called e.g. during symbol_file_command, when
+     we begin debugging an entirely new program.  */
+
+  void (*sym_new_init) ();
+
+  /* sym_init (sf)
+     reads any initial information from a symbol file, and
+     initializes the struct sym_fns SF in preparation for sym_read().
+     It is called every time we read a symbol file for any reason.  */
+
+  void (*sym_init) ();
+
+  /* sym_read (sf, addr, mainline)
+     reads a symbol file into a psymtab (or possibly a symtab).
+     SF is the struct sym_fns that sym_init initialized.  ADDR
+     is the offset between the file's specified start address and
+     its true address in memory.  MAINLINE is 1 if this is the
+     main symbol table being read, and 0 if a secondary
+     symbol file (e.g. shared library or dynamically loaded file)
+     is being read.  */
+
+  void (*sym_read) ();
+
+  /* sym_discard (sf)
+     discards any cached information from SF or elsewhere, that
+     was saved as part of reading a single symbol file.  */
+
+  void (*sym_discard) ();
+
+  /* sym_bfd
+     is the accessor for the symbol file being read.  */
+
+  bfd  *sym_bfd;
+
+  /* sym_private
+     is where information can be shared among sym_init, sym_read and
+     sym_discard.  It is typically a pointer to malloc'd memory.  */
+
+  char *sym_private;                   /* Should be void * */
+
+  /* next
+     finds the next struct sym_fns.  They are allocated and initialized
+     in whatever module implements the functions pointed to; an 
+     initializer calls add_symtab_fns to add them to the global chain.  */
+  struct sym_fns *next;
+};
+
+                       /*   Functions   */
+
+extern void free_named_symtab ();
+extern int  fill_in_vptr_fieldno ();
+extern void add_symtab_fns ();
+
+/* Functions for dealing with the misc "function" vector, really a misc
+   address<->symbol mapping vector for things we don't have debug symbols
+   for.  */
+
+extern void init_misc_bunches ();
+extern void prim_record_misc_function ();
+extern void discard_misc_bunches ();
+extern void condense_misc_bunches ();
+
+/* Sorting your symbols for fast lookup or alphabetical printing.  */
+
+extern void sort_block_syms ();
+extern void sort_symtab_syms ();
+extern void sort_all_symtab_syms ();
+extern void sort_block_syms ();
+
+/* Make a copy of the string at PTR with SIZE characters in the symbol obstack
+   (and add a null character at the end in the copy).
+   Returns the address of the copy.  */
+
+extern char *obsavestring ();
+
+/* Concatenate strings S1, S2 and S3; return the new string.
+   Space is found in the symbol_obstack.  */
+
+extern char *obconcat ();
+
+                       /*   Variables   */
+
+/* File name symbols were loaded from.  */
+
+extern char *symfile;
+
+/* The modification date of the file when they were loaded.  */
+
+extern int symfile_mtime;
+
+/* The BFD for this file -- only good while we're actively reading
+   symbols into a psymtab or a symtab.  */
+
+static bfd *symfile_bfd;
+
+/* Vectors of all partial symbols read in from file.  */
+
+extern struct psymbol_allocation_list {
+  struct partial_symbol *list, *next;
+  int size;
+} global_psymbols, static_psymbols;
+
+/* Support for complaining about things in the symbol file that aren't
+   catastrophic.
+
+   Each such thing gets a counter.  The first time we have the problem,
+   during a symbol read, we report it.  At the end of symbol reading,
+   if verbose, we report how many of each problem we had.  */
+
+struct complaint {
+  char *message;
+  unsigned counter;
+  struct complaint *next;
+};
+
+/* Root of the chain of complaints that have at some point been issued. 
+   This is used to reset the counters, and/or report the total counts.  */
+
+extern struct complaint complaint_root[1];
+
+/* Functions that handle complaints.  (in symfile.c)  */
+
+int complain();
+void clear_complaints();
diff --git a/gdb/symmisc.c b/gdb/symmisc.c
new file mode 100644 (file)
index 0000000..2aead6e
--- /dev/null
@@ -0,0 +1,442 @@
+/* Do various things to symbol tables (other than lookup)), for GDB.
+   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.  */
+
+
+#include "defs.h"
+#include "param.h"
+#include "symtab.h"
+#include "breakpoint.h"
+#include "command.h"
+
+#include <stdio.h>
+#include <obstack.h>
+
+static void free_symtab ();
+
+\f
+/* Free all the symtabs that are currently installed,
+   and all storage associated with them.
+   Leaves us in a consistent state with no symtabs installed.  */
+
+void
+free_all_symtabs ()
+{
+  register struct symtab *s, *snext;
+
+  /* All values will be invalid because their types will be!  */
+
+  clear_value_history ();
+  clear_displays ();
+  clear_internalvars ();
+#if defined (CLEAR_SOLIB)
+  CLEAR_SOLIB ();
+#endif
+  set_default_breakpoint (0, 0, 0, 0);
+
+  current_source_symtab = 0;
+
+  for (s = symtab_list; s; s = snext)
+    {
+      snext = s->next;
+      free_symtab (s);
+    }
+  symtab_list = 0;
+  obstack_free (symbol_obstack, 0);
+  obstack_init (symbol_obstack);
+
+  if (misc_function_vector)
+    free (misc_function_vector);
+  misc_function_count = 0;
+  misc_function_vector = 0;
+  clear_pc_function_cache();
+}
+
+/* Free a struct block <- B and all the symbols defined in that block.  */
+
+static void
+free_symtab_block (b)
+     struct block *b;
+{
+  register int i, n;
+  n = BLOCK_NSYMS (b);
+  for (i = 0; i < n; i++)
+    {
+      free (SYMBOL_NAME (BLOCK_SYM (b, i)));
+      free (BLOCK_SYM (b, i));
+    }
+  free (b);
+}
+
+/* Free all the storage associated with the struct symtab <- S.
+   Note that some symtabs have contents malloc'ed structure by structure,
+   while some have contents that all live inside one big block of memory,
+   and some share the contents of another symbol table and so you should
+   not free the contents on their behalf (except sometimes the linetable,
+   which maybe per symtab even when the rest is not).
+   It is s->free_code that says which alternative to use.  */
+
+static void
+free_symtab (s)
+     register struct symtab *s;
+{
+  register int i, n;
+  register struct blockvector *bv;
+  register struct typevector *tv;
+
+  switch (s->free_code)
+    {
+    case free_nothing:
+      /* All the contents are part of a big block of memory
+        and some other symtab is in charge of freeing that block.
+        Therefore, do nothing.  */
+      break;
+
+    case free_contents:
+      /* Here all the contents were malloc'ed structure by structure
+        and must be freed that way.  */
+      /* First free the blocks (and their symbols.  */
+      bv = BLOCKVECTOR (s);
+      n = BLOCKVECTOR_NBLOCKS (bv);
+      for (i = 0; i < n; i++)
+       free_symtab_block (BLOCKVECTOR_BLOCK (bv, i));
+      /* Free the blockvector itself.  */
+      free (bv);
+      /* Free the type vector.  */
+      tv = TYPEVECTOR (s);
+      free (tv);
+      /* Also free the linetable.  */
+      
+    case free_linetable:
+      /* Everything will be freed either by our `free_ptr'
+        or by some other symbatb, except for our linetable.
+        Free that now.  */
+      free (LINETABLE (s));
+      break;
+    }
+
+  /* If there is a single block of memory to free, free it.  */
+  if (s->free_ptr)
+    free (s->free_ptr);
+
+  /* Free source-related stuff */
+  if (s->line_charpos)
+    free (s->line_charpos);
+  if (s->fullname)
+    free (s->fullname);
+  free (s);
+}
+
+/* If a symtab for filename NAME is found, free it along
+   with any dependent breakpoints, displays, etc.
+   Used when loading new versions of object modules with the "add-file"
+   command.
+   
+   FIXME.  I think this is not the right way to do this.  It needs further
+   investigation, though.  -- gnu@cygnus  */
+
+void
+free_named_symtab (name)
+     char *name;
+{
+  register struct symtab *s;
+  register struct symtab *prev;
+  struct blockvector *bv;
+
+#if 0  /* FIXME */
+  /* Look for a symtab with the specified name.
+     We can't use lookup_symtab () for this, since it 
+     might generate a recursive call to psymtab_to_symtab ().  */
+
+  for (s = symtab_list; s; s = s->next)
+    {
+      if (!strcmp (name, s->filename))
+       break;
+      prev = s;
+    }
+
+  if (s)
+    {
+      if (s == symtab_list)
+       symtab_list = s->next;
+      else
+       prev->next = s->next;
+
+      /* For now, delete all breakpoints, displays, etc., whether or
+        not they depend on the symtab being freed.  This should be
+        changed so that only those data structures affected are deleted.  */
+
+      /* But don't delete anything if the symtab is empty.
+        This test is necessary due to a bug in "dbxread.c" that
+        causes empty symtabs to be created for N_SO symbols that
+        contain the pathname of the object file.  (This problem
+        has been fixed in GDB 3.9x).  */
+
+      bv = BLOCKLIST (s);
+      if (BLOCKLIST_NBLOCKS (bv) > 2
+         || BLOCK_NSYMS (BLOCKVECTOR_BLOCK (bv, 0))
+         || BLOCK_NSYMS (BLOCKVECTOR_BLOCK (bv, 1)))
+       {
+         /* Took the following line out because GDB ends up printing it
+            many times when a given module is loaded, because each module
+            contains many symtabs.  */
+         /*
+         printf ("Clearing breakpoints and resetting debugger state.\n");
+         */
+
+         clear_value_history ();
+         clear_displays ();
+         clear_internalvars ();
+         clear_breakpoints ();
+         set_default_breakpoint (0, 0, 0, 0);
+         current_source_symtab = 0;
+       }
+
+      free_symtab (s);
+    }
+  else
+    /* It is still possible that some breakpoints will be affected
+       even though no symtab was found, since the file might have
+       been compiled without debugging, and hence not be associated
+       with a symtab.  In order to handle this correctly, we would need
+       to keep a list of text address ranges for undebuggable files.
+       For now, we do nothing, since this is a fairly obscure case.  */
+    ;
+#endif  /* FIXME */
+}
+
+\f
+static int block_depth ();
+static void print_symbol ();
+
+void
+print_symtabs (filename)
+     char *filename;
+{
+  FILE *outfile;
+  register struct symtab *s;
+  register int i, j;
+  int len, blen;
+  register struct linetable *l;
+  struct blockvector *bv;
+  register struct block *b;
+  int depth;
+  struct cleanup *cleanups;
+  extern int fclose();
+
+  if (filename == 0)
+    error_no_arg ("file to write symbol data in");
+
+  filename = tilde_expand (filename);
+  make_cleanup (free, filename);
+  
+  outfile = fopen (filename, "w");
+  if (outfile == 0)
+    perror_with_name (filename);
+
+  cleanups = make_cleanup (fclose, outfile);
+  immediate_quit++;
+
+  for (s = symtab_list; s; s = s->next)
+    {
+      /* First print the line table.  */
+      fprintf (outfile, "Symtab for file %s\n\n", s->filename);
+      fprintf (outfile, "Line table:\n\n");
+      l = LINETABLE (s);
+      len = l->nitems;
+      for (i = 0; i < len; i++)
+       fprintf (outfile, " line %d at %x\n", l->item[i].line,
+                l->item[i].pc);
+      /* Now print the block info.  */
+      fprintf (outfile, "\nBlockvector:\n\n");
+      bv = BLOCKVECTOR (s);
+      len = BLOCKVECTOR_NBLOCKS (bv);
+      for (i = 0; i < len; i++)
+       {
+         b = BLOCKVECTOR_BLOCK (bv, i);
+         depth = block_depth (b) * 2;
+         print_spaces (depth, outfile);
+         fprintf (outfile, "block #%03d (object 0x%x) ", i, b);
+         fprintf (outfile, "[0x%x..0x%x]", BLOCK_START (b), BLOCK_END (b));
+         if (BLOCK_SUPERBLOCK (b))
+           fprintf (outfile, " (under 0x%x)", BLOCK_SUPERBLOCK (b));
+         if (BLOCK_FUNCTION (b))
+           fprintf (outfile, " %s", SYMBOL_NAME (BLOCK_FUNCTION (b)));
+         fputc ('\n', outfile);
+         blen = BLOCK_NSYMS (b);
+         for (j = 0; j < blen; j++)
+           {
+             print_symbol (BLOCK_SYM (b, j), depth + 1, outfile);
+           }
+       }
+
+      fprintf (outfile, "\n\n");
+    }
+
+  immediate_quit--;
+  do_cleanups (cleanups);
+}
+
+static void
+print_symbol (symbol, depth, outfile)
+     struct symbol *symbol;
+     int depth;
+     FILE *outfile;
+{
+  print_spaces (depth, outfile);
+  if (SYMBOL_NAMESPACE (symbol) == LABEL_NAMESPACE)
+    {
+      fprintf (outfile, "label %s at 0x%x\n", SYMBOL_NAME (symbol),
+              SYMBOL_VALUE_ADDRESS (symbol));
+      return;
+    }
+  if (SYMBOL_NAMESPACE (symbol) == STRUCT_NAMESPACE)
+    {
+      if (TYPE_NAME (SYMBOL_TYPE (symbol)))
+       {
+         type_print_1 (SYMBOL_TYPE (symbol), "", outfile, 1, depth);
+       }
+      else
+       {
+         fprintf (outfile, "%s %s = ",
+              (TYPE_CODE (SYMBOL_TYPE (symbol)) == TYPE_CODE_ENUM
+               ? "enum"
+               : (TYPE_CODE (SYMBOL_TYPE (symbol)) == TYPE_CODE_STRUCT
+                  ? "struct" : "union")),
+              SYMBOL_NAME (symbol));
+         type_print_1 (SYMBOL_TYPE (symbol), "", outfile, 1, depth);
+       }
+      fprintf (outfile, ";\n");
+    }
+  else
+    {
+      if (SYMBOL_CLASS (symbol) == LOC_TYPEDEF)
+       fprintf (outfile, "typedef ");
+      if (SYMBOL_TYPE (symbol))
+       {
+         type_print_1 (SYMBOL_TYPE (symbol), SYMBOL_NAME (symbol),
+                       outfile, 1, depth);
+         fprintf (outfile, "; ");
+       }
+      else
+       fprintf (outfile, "%s ", SYMBOL_NAME (symbol));
+
+      switch (SYMBOL_CLASS (symbol))
+       {
+       case LOC_CONST:
+         fprintf (outfile, "const %ld (0x%lx),",
+                  SYMBOL_VALUE (symbol), SYMBOL_VALUE (symbol));
+         break;
+
+       case LOC_CONST_BYTES:
+         fprintf (outfile, "const %u hex bytes:",
+                  TYPE_LENGTH (SYMBOL_TYPE (symbol)));
+         {
+           unsigned i;
+           for (i = 0; i < TYPE_LENGTH (SYMBOL_TYPE (symbol)); i++)
+             fprintf (outfile, " %2x",
+                        (unsigned)SYMBOL_VALUE_BYTES (symbol) [i]);
+           fprintf (outfile, ",");
+         }
+         break;
+
+       case LOC_STATIC:
+         fprintf (outfile, "static at 0x%x,", SYMBOL_VALUE_ADDRESS (symbol));
+         break;
+
+       case LOC_REGISTER:
+         fprintf (outfile, "register %ld,", SYMBOL_VALUE (symbol));
+         break;
+
+       case LOC_ARG:
+         fprintf (outfile, "arg at 0x%lx,", SYMBOL_VALUE (symbol));
+         break;
+
+       case LOC_LOCAL_ARG:
+         fprintf (outfile, "arg at offset 0x%x from fp,",
+                  SYMBOL_VALUE (symbol));
+
+       case LOC_REF_ARG:
+         fprintf (outfile, "reference arg at 0x%lx,", SYMBOL_VALUE (symbol));
+         break;
+
+       case LOC_REGPARM:
+         fprintf (outfile, "parameter register %ld,", SYMBOL_VALUE (symbol));
+         break;
+
+       case LOC_LOCAL:
+         fprintf (outfile, "local at 0x%lx,", SYMBOL_VALUE (symbol));
+         break;
+
+       case LOC_TYPEDEF:
+         break;
+
+       case LOC_LABEL:
+         fprintf (outfile, "label at 0x%lx", SYMBOL_VALUE_ADDRESS (symbol));
+         break;
+
+       case LOC_BLOCK:
+         fprintf (outfile, "block (object 0x%x) starting at 0x%x,",
+                  SYMBOL_BLOCK_VALUE (symbol),
+                  BLOCK_START (SYMBOL_BLOCK_VALUE (symbol)));
+         break;
+
+       case LOC_EXTERNAL:
+         fprintf (outfile, "external at 0x%x", SYMBOL_VALUE_ADDRESS (symbol));
+         break;
+
+        default:
+         fprintf (outfile, "botched symbol class %x", SYMBOL_CLASS (symbol));
+         break;
+       }
+    }
+  fprintf (outfile, "\n");
+}
+
+/* Return the nexting depth of a block within other blocks in its symtab.  */
+
+static int
+block_depth (block)
+     struct block *block;
+{
+  register int i = 0;
+  while (block = BLOCK_SUPERBLOCK (block)) i++;
+  return i;
+}
+\f
+/*
+ * Free all partial_symtab storage.
+ */
+void
+free_all_psymtabs()
+{
+  obstack_free (psymbol_obstack, 0);
+  obstack_init (psymbol_obstack);
+  partial_symtab_list = (struct partial_symtab *) 0;
+}
+\f
+void
+_initialize_symmisc ()
+{
+  symtab_list = (struct symtab *) 0;
+  partial_symtab_list = (struct partial_symtab *) 0;
+  
+  add_com ("printsyms", class_obscure, print_symtabs,
+          "Print dump of current symbol definitions to file OUTFILE.");
+}
+
diff --git a/gdb/symtab.c b/gdb/symtab.c
new file mode 100644 (file)
index 0000000..09f3282
--- /dev/null
@@ -0,0 +1,2622 @@
+/* Symbol table lookup for the GNU debugger, GDB.
+   Copyright (C) 1986, 1987, 1988, 1989, 1990 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 <stdio.h>
+#include "defs.h"
+#include "symtab.h"
+#include "param.h"
+#include "gdbcore.h"
+#include "frame.h"
+#include "target.h"
+#include "value.h"
+#include "symfile.h"
+#include "gdbcmd.h"
+
+#include <obstack.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/stat.h>
+
+extern int close ();
+extern void qsort ();
+extern char *getenv ();
+
+extern char *cplus_demangle ();
+extern struct value *value_of_this ();
+extern void break_command ();
+extern void select_source_symtab ();
+
+/* Functions this file defines */
+static int find_line_common ();
+struct partial_symtab *lookup_partial_symtab ();
+static struct partial_symbol *lookup_partial_symbol ();
+
+/* These variables point to the objects
+   representing the predefined C data types.  */
+
+struct type *builtin_type_void;
+struct type *builtin_type_char;
+struct type *builtin_type_short;
+struct type *builtin_type_int;
+struct type *builtin_type_long;
+#ifdef LONG_LONG
+struct type *builtin_type_long_long;
+#endif
+struct type *builtin_type_unsigned_char;
+struct type *builtin_type_unsigned_short;
+struct type *builtin_type_unsigned_int;
+struct type *builtin_type_unsigned_long;
+#ifdef LONG_LONG
+struct type *builtin_type_unsigned_long_long;
+#endif
+struct type *builtin_type_float;
+struct type *builtin_type_double;
+struct type *builtin_type_error;
+
+/* Block in which the most recently searched-for symbol was found.
+   Might be better to make this a parameter to lookup_symbol and 
+   value_of_this. */
+struct block *block_found;
+
+char no_symtab_msg[] = "No symbol table is loaded.  Use the \"file\" command.";
+
+/* Check for a symtab of a specific name; first in symtabs, then in
+   psymtabs.  *If* there is no '/' in the name, a match after a '/'
+   in the symtab filename will also work.  */
+
+static struct symtab *
+lookup_symtab_1 (name)
+     char *name;
+{
+  register struct symtab *s;
+  register struct partial_symtab *ps;
+  register char *slash = strchr (name, '/');
+  register int len = strlen (name);
+
+  for (s = symtab_list; s; s = s->next)
+    if (!strcmp (name, s->filename))
+      return s;
+
+  for (ps = partial_symtab_list; ps; ps = ps->next)
+    if (!strcmp (name, ps->filename))
+      {
+       if (ps->readin)
+         fatal ("Internal: readin pst found when no symtab found.");
+       return PSYMTAB_TO_SYMTAB (ps);
+      }
+
+  if (!slash)
+    {
+      for (s = symtab_list; s; s = s->next)
+       {
+         int l = strlen (s->filename);
+
+         if (s->filename[l - len -1] == '/'
+             && !strcmp (s->filename + l - len, name))
+           return s;
+       }
+
+      for (ps = partial_symtab_list; ps; ps = ps->next)
+       {
+         int l = strlen (ps->filename);
+
+         if (ps->filename[l - len - 1] == '/'
+             && !strcmp (ps->filename + l - len, name))
+           {
+             if (ps->readin)
+               fatal ("Internal: readin pst found when no symtab found.");
+             return PSYMTAB_TO_SYMTAB (ps);
+           }
+       }
+    }
+  return 0;
+}
+
+/* Lookup the symbol table of a source file named NAME.  Try a couple
+   of variations if the first lookup doesn't work.  */
+
+struct symtab *
+lookup_symtab (name)
+     char *name;
+{
+  register struct symtab *s;
+  register char *copy;
+
+  s = lookup_symtab_1 (name);
+  if (s) return s;
+
+  /* If name not found as specified, see if adding ".c" helps.  */
+
+  copy = (char *) alloca (strlen (name) + 3);
+  strcpy (copy, name);
+  strcat (copy, ".c");
+  s = lookup_symtab_1 (copy);
+  if (s) return s;
+
+  /* We didn't find anything; die.  */
+  return 0;
+}
+
+/* Lookup the partial symbol table of a source file named NAME.  This
+   only returns true on an exact match (ie. this semantics are
+   different from lookup_symtab.  */
+
+struct partial_symtab *
+lookup_partial_symtab (name)
+char *name;
+{
+  register struct partial_symtab *s;
+  
+  for (s = partial_symtab_list; s; s = s->next)
+    if (!strcmp (name, s->filename))
+      return s;
+  
+  return 0;
+}
+\f
+/* Return a typename for a struct/union/enum type
+   without the tag qualifier.  If the type has a NULL name,
+   NULL is returned.  */
+char *
+type_name_no_tag (type)
+     register struct type *type;
+{
+  register char *name = TYPE_NAME (type);
+  char *strchr ();
+  if (name == 0)
+    return 0;
+
+#if 0
+  switch (TYPE_CODE (type))
+    {
+    case TYPE_CODE_STRUCT:
+      return name + 7;
+    case TYPE_CODE_UNION:
+      return name + 6;
+    case TYPE_CODE_ENUM:
+      return name + 5;
+    }
+#endif
+
+  name = strchr (name, ' ');
+  if (name)
+    return name + 1;
+
+  return TYPE_NAME (type);
+}
+
+/* Added by Bryan Boreham, Kewill, Sun Sep 17 18:07:17 1989.
+
+   If this is a stubbed struct (i.e. declared as struct foo *), see if
+   we can find a full definition in some other file. If so, copy this
+   definition, so we can use it in future.  If not, set a flag so we 
+   don't waste too much time in future.
+
+   This used to be coded as a macro, but I don't think it is called 
+   often enough to merit such treatment.
+*/
+
+struct complaint stub_noname_complaint =
+  {"stub type has NULL name", 0, 0};
+
+void 
+check_stub_type(type)
+     struct type *type;
+{
+  if (TYPE_FLAGS(type) & TYPE_FLAG_STUB)
+    {
+      char* name= type_name_no_tag (type);
+      struct symbol *sym;
+      if (name == 0)
+       {
+         complain (&stub_noname_complaint, 0, 0);
+         return;
+       }
+      if (sym = lookup_symbol (name, 0, STRUCT_NAMESPACE, 0, 
+                              (struct symtab **)NULL) )
+       bcopy (SYMBOL_TYPE(sym), type, sizeof (struct type));
+    }
+}
+
+/* Demangle a GDB method stub type.  */
+char *
+gdb_mangle_typename (type)
+     struct type *type;
+{
+  static struct type *last_type;
+  static char *mangled_typename;
+
+  if (type != last_type)
+    {
+      /* Need a new type prefix.  */
+      char *strchr ();
+      char *newname = type_name_no_tag (type);
+      char buf[20];
+      int len;
+
+      if (mangled_typename)
+       free (mangled_typename);
+
+      len = strlen (newname);
+      sprintf (buf, "__%d", len);
+      mangled_typename = (char *)xmalloc (strlen (buf) + len + 1);
+      strcpy (mangled_typename, buf);
+      strcat (mangled_typename, newname);
+      /* Now we have built "__#newname".  */
+    }
+  return mangled_typename;
+}
+
+/* Lookup a primitive type named NAME. 
+   Return zero if NAME is not a primitive type.*/
+
+struct type *
+lookup_primitive_typename (name)
+     char *name;
+{
+  if (!strcmp (name, "int"))
+    return builtin_type_int;
+  if (!strcmp (name, "long"))
+    return builtin_type_long;
+  if (!strcmp (name, "short"))
+    return builtin_type_short;
+  if (!strcmp (name, "char"))
+    return builtin_type_char;
+  if (!strcmp (name, "float"))
+    return builtin_type_float;
+  if (!strcmp (name, "double"))
+    return builtin_type_double;
+  if (!strcmp (name, "void"))
+    return builtin_type_void;
+  return 0;
+}
+
+/* Lookup a typedef or primitive type named NAME,
+   visible in lexical block BLOCK.
+   If NOERR is nonzero, return zero if NAME is not suitably defined.  */
+
+struct type *
+lookup_typename (name, block, noerr)
+     char *name;
+     struct block *block;
+     int noerr;
+{
+  register struct symbol *sym =
+    lookup_symbol (name, block, VAR_NAMESPACE, 0, (struct symtab **)NULL);
+  if (sym == 0 || SYMBOL_CLASS (sym) != LOC_TYPEDEF)
+    {
+      struct type *tmp;
+      tmp = lookup_primitive_typename (name);
+      if (!tmp && noerr)
+       return 0;
+      error ("No type named %s.", name);
+    }
+  return SYMBOL_TYPE (sym);
+}
+
+struct type *
+lookup_unsigned_typename (name)
+     char *name;
+{
+  if (!strcmp (name, "int"))
+    return builtin_type_unsigned_int;
+  if (!strcmp (name, "long"))
+    return builtin_type_unsigned_long;
+  if (!strcmp (name, "short"))
+    return builtin_type_unsigned_short;
+  if (!strcmp (name, "char"))
+    return builtin_type_unsigned_char;
+  error ("No type named unsigned %s.", name);
+  return (struct type *)-1;  /* for lint */
+}
+
+/* Lookup a structure type named "struct NAME",
+   visible in lexical block BLOCK.  */
+
+struct type *
+lookup_struct (name, block)
+     char *name;
+     struct block *block;
+{
+  register struct symbol *sym 
+    = lookup_symbol (name, block, STRUCT_NAMESPACE, 0, (struct symtab **)NULL);
+
+  if (sym == 0)
+    error ("No struct type named %s.", name);
+  if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_STRUCT)
+    error ("This context has class, union or enum %s, not a struct.", name);
+  return SYMBOL_TYPE (sym);
+}
+
+/* Lookup a union type named "union NAME",
+   visible in lexical block BLOCK.  */
+
+struct type *
+lookup_union (name, block)
+     char *name;
+     struct block *block;
+{
+  register struct symbol *sym 
+    = lookup_symbol (name, block, STRUCT_NAMESPACE, 0, (struct symtab **)NULL);
+
+  if (sym == 0)
+    error ("No union type named %s.", name);
+  if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_UNION)
+    error ("This context has class, struct or enum %s, not a union.", name);
+  return SYMBOL_TYPE (sym);
+}
+
+/* Lookup an enum type named "enum NAME",
+   visible in lexical block BLOCK.  */
+
+struct type *
+lookup_enum (name, block)
+     char *name;
+     struct block *block;
+{
+  register struct symbol *sym 
+    = lookup_symbol (name, block, STRUCT_NAMESPACE, 0, (struct symtab **)NULL);
+  if (sym == 0)
+    error ("No enum type named %s.", name);
+  if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_ENUM)
+    error ("This context has class, struct or union %s, not an enum.", name);
+  return SYMBOL_TYPE (sym);
+}
+
+/* Given a type TYPE, lookup the type of the component of type named
+   NAME.  */
+
+struct type *
+lookup_struct_elt_type (type, name)
+     struct type *type;
+     char *name;
+{
+  int i;
+
+  if (TYPE_CODE (type) != TYPE_CODE_STRUCT
+      && TYPE_CODE (type) != TYPE_CODE_UNION)
+    {
+      target_terminal_ours ();
+      fflush (stdout);
+      fprintf (stderr, "Type ");
+      type_print (type, "", stderr, -1);
+      error (" is not a structure or union type.");
+    }
+
+  for (i = TYPE_NFIELDS (type) - 1; i >= TYPE_N_BASECLASSES (type); i--)
+    if (!strcmp (TYPE_FIELD_NAME (type, i), name))
+      return TYPE_FIELD_TYPE (type, i);
+
+  target_terminal_ours ();
+  fflush (stdout);
+  fprintf (stderr, "Type ");
+  type_print (type, "", stderr, -1);
+  fprintf (stderr, " has no component named ");
+  fputs_filtered (name, stderr);
+  error (".");
+  return (struct type *)-1;    /* For lint */
+}
+
+/* Given a type TYPE, return a type of pointers to that type.
+   May need to construct such a type if this is the first use.
+
+   C++: use TYPE_MAIN_VARIANT and TYPE_CHAIN to keep pointer
+   to member types under control.  */
+
+struct type *
+lookup_pointer_type (type)
+     struct type *type;
+{
+  register struct type *ptype = TYPE_POINTER_TYPE (type);
+  if (ptype) return TYPE_MAIN_VARIANT (ptype);
+
+  /* This is the first time anyone wanted a pointer to a TYPE.  */
+  if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+    ptype  = (struct type *) xmalloc (sizeof (struct type));
+  else
+    ptype  = (struct type *) obstack_alloc (symbol_obstack,
+                                           sizeof (struct type));
+
+  bzero (ptype, sizeof (struct type));
+  TYPE_MAIN_VARIANT (ptype) = ptype;
+  TYPE_TARGET_TYPE (ptype) = type;
+  TYPE_POINTER_TYPE (type) = ptype;
+  /* New type is permanent if type pointed to is permanent.  */
+  if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+    TYPE_FLAGS (ptype) |= TYPE_FLAG_PERM;
+  /* We assume the machine has only one representation for pointers!  */
+  TYPE_LENGTH (ptype) = sizeof (char *);
+  TYPE_CODE (ptype) = TYPE_CODE_PTR;
+  return ptype;
+}
+
+struct type *
+lookup_reference_type (type)
+     struct type *type;
+{
+  register struct type *rtype = TYPE_REFERENCE_TYPE (type);
+  if (rtype) return TYPE_MAIN_VARIANT (rtype);
+
+  /* This is the first time anyone wanted a pointer to a TYPE.  */
+  if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+    rtype  = (struct type *) xmalloc (sizeof (struct type));
+  else
+    rtype  = (struct type *) obstack_alloc (symbol_obstack,
+                                           sizeof (struct type));
+
+  bzero (rtype, sizeof (struct type));
+  TYPE_MAIN_VARIANT (rtype) = rtype;
+  TYPE_TARGET_TYPE (rtype) = type;
+  TYPE_REFERENCE_TYPE (type) = rtype;
+  /* New type is permanent if type pointed to is permanent.  */
+  if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+    TYPE_FLAGS (rtype) |= TYPE_FLAG_PERM;
+  /* We assume the machine has only one representation for pointers!  */
+  TYPE_LENGTH (rtype) = sizeof (char *);
+  TYPE_CODE (rtype) = TYPE_CODE_REF;
+  return rtype;
+}
+
+
+/* Implement direct support for MEMBER_TYPE in GNU C++.
+   May need to construct such a type if this is the first use.
+   The TYPE is the type of the member.  The DOMAIN is the type
+   of the aggregate that the member belongs to.  */
+
+struct type *
+lookup_member_type (type, domain)
+     struct type *type, *domain;
+{
+  register struct type *mtype = TYPE_MAIN_VARIANT (type);
+  struct type *main_type;
+
+  main_type = mtype;
+  while (mtype)
+    {
+      if (TYPE_DOMAIN_TYPE (mtype) == domain)
+       return mtype;
+      mtype = TYPE_NEXT_VARIANT (mtype);
+    }
+
+  /* This is the first time anyone wanted this member type.  */
+  if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+    mtype  = (struct type *) xmalloc (sizeof (struct type));
+  else
+    mtype  = (struct type *) obstack_alloc (symbol_obstack,
+                                           sizeof (struct type));
+
+  bzero (mtype, sizeof (struct type));
+  if (main_type == 0)
+    main_type = mtype;
+  else
+    {
+      TYPE_NEXT_VARIANT (mtype) = TYPE_NEXT_VARIANT (main_type);
+      TYPE_NEXT_VARIANT (main_type) = mtype;
+    }
+  TYPE_MAIN_VARIANT (mtype) = main_type;
+  TYPE_TARGET_TYPE (mtype) = type;
+  TYPE_DOMAIN_TYPE (mtype) = domain;
+  /* New type is permanent if type pointed to is permanent.  */
+  if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+    TYPE_FLAGS (mtype) |= TYPE_FLAG_PERM;
+
+  /* In practice, this is never used.  */
+  TYPE_LENGTH (mtype) = 1;
+  TYPE_CODE (mtype) = TYPE_CODE_MEMBER;
+
+#if 0
+  /* Now splice in the new member pointer type.  */
+  if (main_type)
+    {
+      /* This type was not "smashed".  */
+      TYPE_CHAIN (mtype) = TYPE_CHAIN (main_type);
+      TYPE_CHAIN (main_type) = mtype;
+    }
+#endif
+
+  return mtype;
+}
+
+struct type *
+lookup_method_type (type, domain, args)
+     struct type *type, *domain, **args;
+{
+  register struct type *mtype = TYPE_MAIN_VARIANT (type);
+  struct type *main_type;
+
+  main_type = mtype;
+  while (mtype)
+    {
+      if (TYPE_DOMAIN_TYPE (mtype) == domain)
+       {
+         struct type **t1 = args;
+         struct type **t2 = TYPE_ARG_TYPES (mtype);
+         if (t2)
+           {
+             int i;
+             for (i = 0; t1[i] != 0 && t1[i]->code != TYPE_CODE_VOID; i++)
+               if (t1[i] != t2[i])
+                 break;
+             if (t1[i] == t2[i])
+               return mtype;
+           }
+       }
+      mtype = TYPE_NEXT_VARIANT (mtype);
+    }
+
+  /* This is the first time anyone wanted this member type.  */
+  if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+    mtype  = (struct type *) xmalloc (sizeof (struct type));
+  else
+    mtype  = (struct type *) obstack_alloc (symbol_obstack,
+                                           sizeof (struct type));
+
+  bzero (mtype, sizeof (struct type));
+  if (main_type == 0)
+    main_type = mtype;
+  else
+    {
+      TYPE_NEXT_VARIANT (mtype) = TYPE_NEXT_VARIANT (main_type);
+      TYPE_NEXT_VARIANT (main_type) = mtype;
+    }
+  TYPE_MAIN_VARIANT (mtype) = main_type;
+  TYPE_TARGET_TYPE (mtype) = type;
+  TYPE_DOMAIN_TYPE (mtype) = domain;
+  TYPE_ARG_TYPES (mtype) = args;
+  /* New type is permanent if type pointed to is permanent.  */
+  if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+    TYPE_FLAGS (mtype) |= TYPE_FLAG_PERM;
+
+  /* In practice, this is never used.  */
+  TYPE_LENGTH (mtype) = 1;
+  TYPE_CODE (mtype) = TYPE_CODE_METHOD;
+
+#if 0
+  /* Now splice in the new member pointer type.  */
+  if (main_type)
+    {
+      /* This type was not "smashed".  */
+      TYPE_CHAIN (mtype) = TYPE_CHAIN (main_type);
+      TYPE_CHAIN (main_type) = mtype;
+    }
+#endif
+
+  return mtype;
+}
+
+#if 0
+/* Given a type TYPE, return a type which has offset OFFSET,
+   via_virtual VIA_VIRTUAL, and via_public VIA_PUBLIC.
+   May need to construct such a type if none exists.  */
+struct type *
+lookup_basetype_type (type, offset, via_virtual, via_public)
+     struct type *type;
+     int offset;
+     int via_virtual, via_public;
+{
+  register struct type *btype = TYPE_MAIN_VARIANT (type);
+  struct type *main_type;
+
+  if (offset != 0)
+    {
+      printf ("Internal error: type offset non-zero in lookup_basetype_type");
+      offset = 0;
+    }
+
+  main_type = btype;
+  while (btype)
+    {
+      if (/* TYPE_OFFSET (btype) == offset
+         && */ TYPE_VIA_PUBLIC (btype) == via_public
+         && TYPE_VIA_VIRTUAL (btype) == via_virtual)
+       return btype;
+      btype = TYPE_NEXT_VARIANT (btype);
+    }
+
+  /* This is the first time anyone wanted this member type.  */
+  if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+    btype  = (struct type *) xmalloc (sizeof (struct type));
+  else
+    btype  = (struct type *) obstack_alloc (symbol_obstack,
+                                           sizeof (struct type));
+
+  if (main_type == 0)
+    {
+      main_type = btype;
+      bzero (btype, sizeof (struct type));
+      TYPE_MAIN_VARIANT (btype) = main_type;
+    }
+  else
+    {
+      bcopy (main_type, btype, sizeof (struct type));
+      TYPE_NEXT_VARIANT (main_type) = btype;
+    }
+/* TYPE_OFFSET (btype) = offset; */
+  if (via_public)
+    TYPE_FLAGS (btype) |= TYPE_FLAG_VIA_PUBLIC;
+  if (via_virtual)
+    TYPE_FLAGS (btype) |= TYPE_FLAG_VIA_VIRTUAL;
+  /* New type is permanent if type pointed to is permanent.  */
+  if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+    TYPE_FLAGS (btype) |= TYPE_FLAG_PERM;
+
+  /* In practice, this is never used.  */
+  TYPE_LENGTH (btype) = 1;
+  TYPE_CODE (btype) = TYPE_CODE_STRUCT;
+
+  return btype;
+}
+#endif
+
+/* Given a type TYPE, return a type of functions that return that type.
+   May need to construct such a type if this is the first use.  */
+
+struct type *
+lookup_function_type (type)
+     struct type *type;
+{
+  register struct type *ptype = TYPE_FUNCTION_TYPE (type);
+  if (ptype) return ptype;
+
+  /* This is the first time anyone wanted a function returning a TYPE.  */
+  if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+    ptype  = (struct type *) xmalloc (sizeof (struct type));
+  else
+    ptype  = (struct type *) obstack_alloc (symbol_obstack,
+                                           sizeof (struct type));
+
+  bzero (ptype, sizeof (struct type));
+  TYPE_TARGET_TYPE (ptype) = type;
+  TYPE_FUNCTION_TYPE (type) = ptype;
+  /* New type is permanent if type returned is permanent.  */
+  if (TYPE_FLAGS (type) & TYPE_FLAG_PERM)
+    TYPE_FLAGS (ptype) |= TYPE_FLAG_PERM;
+  TYPE_LENGTH (ptype) = 1;
+  TYPE_CODE (ptype) = TYPE_CODE_FUNC;
+  TYPE_NFIELDS (ptype) = 0;
+  return ptype;
+}
+\f
+/* Create an array type.  Elements will be of type TYPE, and there will
+   be NUM of them.
+
+   Eventually this should be extended to take two more arguments which
+   specify the bounds of the array and the type of the index.
+   It should also be changed to be a "lookup" function, with the
+   appropriate data structures added to the type field.
+   Then read array type should call here.  */
+
+struct type *
+create_array_type (element_type, number)
+     struct type *element_type;
+     int number;
+{
+  struct type *result_type = (struct type *)
+    obstack_alloc (symbol_obstack, sizeof (struct type));
+
+  bzero (result_type, sizeof (struct type));
+
+  TYPE_CODE (result_type) = TYPE_CODE_ARRAY;
+  TYPE_TARGET_TYPE (result_type) = element_type;
+  TYPE_LENGTH (result_type) = number * TYPE_LENGTH (element_type);
+  TYPE_NFIELDS (result_type) = 1;
+  TYPE_FIELDS (result_type) =
+    (struct field *) obstack_alloc (symbol_obstack, sizeof (struct field));
+  TYPE_FIELD_TYPE (result_type, 0) = builtin_type_int;
+  TYPE_VPTR_FIELDNO (result_type) = -1;
+
+  return result_type;
+}
+
+\f
+/* Smash TYPE to be a type of members of DOMAIN with type TO_TYPE.  */
+
+void
+smash_to_member_type (type, domain, to_type)
+     struct type *type, *domain, *to_type;
+{
+  bzero (type, sizeof (struct type));
+  TYPE_TARGET_TYPE (type) = to_type;
+  TYPE_DOMAIN_TYPE (type) = domain;
+
+  /* In practice, this is never needed.  */
+  TYPE_LENGTH (type) = 1;
+  TYPE_CODE (type) = TYPE_CODE_MEMBER;
+
+  TYPE_MAIN_VARIANT (type) = lookup_member_type (domain, to_type);
+}
+
+/* Smash TYPE to be a type of method of DOMAIN with type TO_TYPE.  */
+
+void
+smash_to_method_type (type, domain, to_type, args)
+     struct type *type, *domain, *to_type, **args;
+{
+  bzero (type, sizeof (struct type));
+  TYPE_TARGET_TYPE (type) = to_type;
+  TYPE_DOMAIN_TYPE (type) = domain;
+  TYPE_ARG_TYPES (type) = args;
+
+  /* In practice, this is never needed.  */
+  TYPE_LENGTH (type) = 1;
+  TYPE_CODE (type) = TYPE_CODE_METHOD;
+
+  TYPE_MAIN_VARIANT (type) = lookup_method_type (domain, to_type, args);
+}
+\f
+/* Find which partial symtab on the partial_symtab_list contains
+   PC.  Return 0 if none.  */
+
+struct partial_symtab *
+find_pc_psymtab (pc)
+     register CORE_ADDR pc;
+{
+  register struct partial_symtab *ps;
+
+  for (ps = partial_symtab_list; ps; ps = ps->next)
+    if (pc >= ps->textlow && pc < ps->texthigh)
+      return ps;
+
+  return 0;
+}
+
+/* Find which partial symbol within a psymtab contains PC.  Return 0
+   if none.  Check all psymtabs if PSYMTAB is 0.  */
+struct partial_symbol *
+find_pc_psymbol (psymtab, pc)
+     struct partial_symtab *psymtab;
+     CORE_ADDR pc;
+{
+  struct partial_symbol *best, *p;
+  CORE_ADDR best_pc;
+  
+  if (!psymtab)
+    psymtab = find_pc_psymtab (pc);
+  if (!psymtab)
+    return 0;
+
+  best_pc = psymtab->textlow - 1;
+
+  for (p = static_psymbols.list + psymtab->statics_offset;
+       (p - (static_psymbols.list + psymtab->statics_offset)
+       < psymtab->n_static_syms);
+       p++)
+    if (SYMBOL_NAMESPACE (p) == VAR_NAMESPACE
+       && SYMBOL_CLASS (p) == LOC_BLOCK
+       && pc >= SYMBOL_VALUE_ADDRESS (p)
+       && SYMBOL_VALUE_ADDRESS (p) > best_pc)
+      {
+       best_pc = SYMBOL_VALUE_ADDRESS (p);
+       best = p;
+      }
+  if (best_pc == psymtab->textlow - 1)
+    return 0;
+  return best;
+}
+
+\f
+/* Find the definition for a specified symbol name NAME
+   in namespace NAMESPACE, visible from lexical block BLOCK.
+   Returns the struct symbol pointer, or zero if no symbol is found.
+   If SYMTAB is non-NULL, store the symbol table in which the
+   symbol was found there, or NULL if not found.
+   C++: if IS_A_FIELD_OF_THIS is nonzero on entry, check to see if
+   NAME is a field of the current implied argument `this'.  If so set
+   *IS_A_FIELD_OF_THIS to 1, otherwise set it to zero. 
+   BLOCK_FOUND is set to the block in which NAME is found (in the case of
+   a field of `this', value_of_this sets BLOCK_FOUND to the proper value.) */
+
+struct symbol *
+lookup_symbol (name, block, namespace, is_a_field_of_this, symtab)
+     char *name;
+     register struct block *block;
+     enum namespace namespace;
+     int *is_a_field_of_this;
+     struct symtab **symtab;
+{
+  register struct symbol *sym;
+  register struct symtab *s;
+  register struct partial_symtab *ps;
+  struct blockvector *bv;
+
+  /* Search specified block and its superiors.  */
+
+  while (block != 0)
+    {
+      sym = lookup_block_symbol (block, name, namespace);
+      if (sym) 
+       {
+         block_found = block;
+         if (symtab != NULL)
+           {
+             /* Search the list of symtabs for one which contains the
+                address of the start of this block.  */
+             struct block *b;
+             for (s = symtab_list; s; s = s->next)
+               {
+                 bv = BLOCKVECTOR (s);
+                 b = BLOCKVECTOR_BLOCK (bv, 0);
+                 if (BLOCK_START (b) <= BLOCK_START (block)
+                     && BLOCK_END (b) > BLOCK_START (block))
+                   break;
+               }
+             *symtab = s;
+           }
+
+         return sym;
+       }
+      block = BLOCK_SUPERBLOCK (block);
+    }
+
+  /* C++: If requested to do so by the caller, 
+     check to see if NAME is a field of `this'. */
+  if (is_a_field_of_this)
+    {
+      struct value *v = value_of_this (0);
+      
+      *is_a_field_of_this = 0;
+      if (v && check_field (v, name))
+       {
+         *is_a_field_of_this = 1;
+         if (symtab != NULL)
+           *symtab = NULL;
+         return 0;
+       }
+    }
+
+  /* Now search all global blocks.  Do the symtab's first, then
+     check the psymtab's */
+
+  for (s = symtab_list; s; s = s->next)
+    {
+      bv = BLOCKVECTOR (s);
+      block = BLOCKVECTOR_BLOCK (bv, 0);
+      sym = lookup_block_symbol (block, name, namespace);
+      if (sym) 
+       {
+         block_found = block;
+         if (symtab != NULL)
+           *symtab = s;
+         return sym;
+       }
+    }
+
+  /* Check for the possibility of the symbol being a global function
+     that is stored on the misc function vector.  Eventually, all
+     global symbols might be resolved in this way.  */
+  
+  if (namespace == VAR_NAMESPACE)
+    {
+      int ind = lookup_misc_func (name);
+
+      /* Look for a mangled C++ name for NAME. */
+      if (ind == -1)
+       {
+         int name_len = strlen (name);
+
+         for (ind = misc_function_count; --ind >= 0; )
+             /* Assume orginal name is prefix of mangled name. */
+             if (!strncmp (misc_function_vector[ind].name, name, name_len))
+               {
+                 char *demangled =
+                     cplus_demangle(misc_function_vector[ind].name, -1);
+                 if (demangled != NULL)
+                   {
+                     int cond = strcmp (demangled, name);
+                     free (demangled);
+                     if (!cond)
+                         break;
+                   }
+               }
+         /* Loop terminates on no match with ind == -1. */
+        }
+
+      if (ind != -1)
+       {
+         s = find_pc_symtab (misc_function_vector[ind].address);
+         if (s)
+           {
+             bv = BLOCKVECTOR (s);
+             block = BLOCKVECTOR_BLOCK (bv, 0);
+             sym = lookup_block_symbol (block, misc_function_vector[ind].name,
+                                        namespace);
+             /* sym == 0 if symbol was found in the misc_function_vector
+                but not in the symtab.
+                Return 0 to use the misc_function definition of "foo_".
+
+                This happens for Fortran  "foo_" symbols,
+                which are "foo" in the symtab.
+
+                This can also happen if "asm" is used to make a
+                regular symbol but not a debugging symbol, e.g.
+                asm(".globl _main");
+                asm("_main:");
+                */
+
+             if (symtab != NULL)
+               *symtab = s;
+             return sym;
+           }
+       }
+    }
+      
+  for (ps = partial_symtab_list; ps; ps = ps->next)
+    if (!ps->readin && lookup_partial_symbol (ps, name, 1, namespace))
+      {
+       s = PSYMTAB_TO_SYMTAB(ps);
+       bv = BLOCKVECTOR (s);
+       block = BLOCKVECTOR_BLOCK (bv, 0);
+       sym = lookup_block_symbol (block, name, namespace);
+       if (!sym)
+         fatal ("Internal: global symbol found in psymtab but not in symtab");
+       if (symtab != NULL)
+         *symtab = s;
+       return sym;
+      }
+
+  /* Now search all per-file blocks.
+     Not strictly correct, but more useful than an error.
+     Do the symtabs first, then check the psymtabs */
+
+  for (s = symtab_list; s; s = s->next)
+    {
+      bv = BLOCKVECTOR (s);
+      block = BLOCKVECTOR_BLOCK (bv, 1);
+      sym = lookup_block_symbol (block, name, namespace);
+      if (sym) 
+       {
+         block_found = block;
+         if (symtab != NULL)
+           *symtab = s;
+         return sym;
+       }
+    }
+
+  for (ps = partial_symtab_list; ps; ps = ps->next)
+    if (!ps->readin && lookup_partial_symbol (ps, name, 0, namespace))
+      {
+       s = PSYMTAB_TO_SYMTAB(ps);
+       bv = BLOCKVECTOR (s);
+       block = BLOCKVECTOR_BLOCK (bv, 1);
+       sym = lookup_block_symbol (block, name, namespace);
+       if (!sym)
+         fatal ("Internal: static symbol found in psymtab but not in symtab");
+       if (symtab != NULL)
+         *symtab = s;
+       return sym;
+      }
+
+  if (symtab != NULL)
+    *symtab = NULL;
+  return 0;
+}
+
+/* Look, in partial_symtab PST, for symbol NAME.  Check the global
+   symbols if GLOBAL, the static symbols if not */
+
+static struct partial_symbol *
+lookup_partial_symbol (pst, name, global, namespace)
+     struct partial_symtab *pst;
+     char *name;
+     int global;
+     enum namespace namespace;
+{
+  struct partial_symbol *start, *psym;
+  int length = (global ? pst->n_global_syms : pst->n_static_syms);
+
+  if (!length)
+    return (struct partial_symbol *) 0;
+  
+  start = (global ?
+          global_psymbols.list + pst->globals_offset :
+          static_psymbols.list + pst->statics_offset  );
+
+  if (global)                  /* This means we can use a binary */
+                               /* search.  */
+    {
+      struct partial_symbol *top, *bottom, *center;
+
+      /* Binary search.  This search is guaranteed to end with center
+         pointing at the earliest partial symbol with the correct
+        name.  At that point *all* partial symbols with that name
+        will be checked against the correct namespace. */
+      bottom = start;
+      top = start + length - 1;
+      while (top > bottom)
+       {
+         center = bottom + (top - bottom) / 2;
+
+         assert (center < top);
+         
+         if (strcmp (SYMBOL_NAME (center), name) >= 0)
+           top = center;
+         else
+           bottom = center + 1;
+       }
+      assert (top == bottom);
+      
+      while (!strcmp (SYMBOL_NAME (top), name))
+       {
+         if (SYMBOL_NAMESPACE (top) == namespace)
+           return top;
+         top ++;
+       }
+    }
+  else
+    {
+      /* Can't use a binary search */
+      for (psym = start; psym < start + length; psym++)
+       if (namespace == SYMBOL_NAMESPACE (psym)
+           && !strcmp (name, SYMBOL_NAME (psym)))
+         return psym;
+    }
+
+  return (struct partial_symbol *) 0;
+}
+
+/* Look for a symbol in block BLOCK.  */
+
+struct symbol *
+lookup_block_symbol (block, name, namespace)
+     register struct block *block;
+     char *name;
+     enum namespace namespace;
+{
+  register int bot, top, inc;
+  register struct symbol *sym, *parameter_sym;
+
+  top = BLOCK_NSYMS (block);
+  bot = 0;
+
+  /* If the blocks's symbols were sorted, start with a binary search.  */
+
+  if (BLOCK_SHOULD_SORT (block))
+    {
+      /* First, advance BOT to not far before
+        the first symbol whose name is NAME.  */
+
+      while (1)
+       {
+         inc = (top - bot + 1);
+         /* No need to keep binary searching for the last few bits worth.  */
+         if (inc < 4)
+           break;
+         inc = (inc >> 1) + bot;
+         sym = BLOCK_SYM (block, inc);
+         if (SYMBOL_NAME (sym)[0] < name[0])
+           bot = inc;
+         else if (SYMBOL_NAME (sym)[0] > name[0])
+           top = inc;
+         else if (strcmp (SYMBOL_NAME (sym), name) < 0)
+           bot = inc;
+         else
+           top = inc;
+       }
+
+      /* Now scan forward until we run out of symbols,
+        find one whose name is greater than NAME,
+        or find one we want.
+        If there is more than one symbol with the right name and namespace,
+        we return the first one.  dbxread.c is careful to make sure
+        that if one is a register then it comes first.  */
+
+      top = BLOCK_NSYMS (block);
+      while (bot < top)
+       {
+         sym = BLOCK_SYM (block, bot);
+         inc = SYMBOL_NAME (sym)[0] - name[0];
+         if (inc == 0)
+           inc = strcmp (SYMBOL_NAME (sym), name);
+         if (inc == 0 && SYMBOL_NAMESPACE (sym) == namespace)
+           return sym;
+         if (inc > 0)
+           return 0;
+         bot++;
+       }
+      return 0;
+    }
+
+  /* Here if block isn't sorted.
+     This loop is equivalent to the loop above,
+     but hacked greatly for speed.
+
+     Note that parameter symbols do not always show up last in the
+     list; this loop makes sure to take anything else other than
+     parameter symbols first; it only uses parameter symbols as a
+     last resort.  Note that this only takes up extra computation
+     time on a match.  */
+
+  parameter_sym = (struct symbol *) 0;
+  top = BLOCK_NSYMS (block);
+  inc = name[0];
+  while (bot < top)
+    {
+      sym = BLOCK_SYM (block, bot);
+      if (SYMBOL_NAME (sym)[0] == inc
+         && !strcmp (SYMBOL_NAME (sym), name)
+         && SYMBOL_NAMESPACE (sym) == namespace)
+       {
+         if (SYMBOL_CLASS (sym) == LOC_ARG
+             || SYMBOL_CLASS (sym) == LOC_LOCAL_ARG
+             || SYMBOL_CLASS (sym) == LOC_REF_ARG
+             || SYMBOL_CLASS (sym) == LOC_REGPARM)
+           parameter_sym = sym;
+         else
+           return sym;
+       }
+      bot++;
+    }
+  return parameter_sym;                /* Will be 0 if not found. */
+}
+\f
+/* Return the symbol for the function which contains a specified
+   lexical block, described by a struct block BL.  */
+
+struct symbol *
+block_function (bl)
+     struct block *bl;
+{
+  while (BLOCK_FUNCTION (bl) == 0 && BLOCK_SUPERBLOCK (bl) != 0)
+    bl = BLOCK_SUPERBLOCK (bl);
+
+  return BLOCK_FUNCTION (bl);
+}
+
+/* Subroutine of find_pc_line */
+
+struct symtab *
+find_pc_symtab (pc)
+     register CORE_ADDR pc;
+{
+  register struct block *b;
+  struct blockvector *bv;
+  register struct symtab *s;
+  register struct partial_symtab *ps;
+
+  /* Search all symtabs for one whose file contains our pc */
+
+  for (s = symtab_list; s; s = s->next)
+    {
+      bv = BLOCKVECTOR (s);
+      b = BLOCKVECTOR_BLOCK (bv, 0);
+      if (BLOCK_START (b) <= pc
+         && BLOCK_END (b) > pc)
+       break;
+    }
+
+  if (!s)
+    {
+      ps = find_pc_psymtab (pc);
+      if (ps && ps->readin)
+       fatal ("Internal error: pc in read in psymtab, but not in symtab.");
+
+      if (ps)
+       s = PSYMTAB_TO_SYMTAB (ps);
+    }
+
+  return s;
+}
+
+/* Find the source file and line number for a given PC value.
+   Return a structure containing a symtab pointer, a line number,
+   and a pc range for the entire source line.
+   The value's .pc field is NOT the specified pc.
+   NOTCURRENT nonzero means, if specified pc is on a line boundary,
+   use the line that ends there.  Otherwise, in that case, the line
+   that begins there is used.  */
+
+struct symtab_and_line
+find_pc_line (pc, notcurrent)
+     CORE_ADDR pc;
+     int notcurrent;
+{
+  struct symtab *s;
+  register struct linetable *l;
+  register int len;
+  register int i;
+  register struct linetable_entry *item;
+  struct symtab_and_line val;
+  struct blockvector *bv;
+
+  /* Info on best line seen so far, and where it starts, and its file.  */
+
+  int best_line = 0;
+  CORE_ADDR best_pc = 0;
+  CORE_ADDR best_end = 0;
+  struct symtab *best_symtab = 0;
+
+  /* Store here the first line number
+     of a file which contains the line at the smallest pc after PC.
+     If we don't find a line whose range contains PC,
+     we will use a line one less than this,
+     with a range from the start of that file to the first line's pc.  */
+  int alt_line = 0;
+  CORE_ADDR alt_pc = 0;
+  struct symtab *alt_symtab = 0;
+
+  /* Info on best line seen in this file.  */
+
+  int prev_line;
+  CORE_ADDR prev_pc;
+
+  /* Info on first line of this file.  */
+
+  int first_line;
+  CORE_ADDR first_pc;
+
+  /* If this pc is not from the current frame,
+     it is the address of the end of a call instruction.
+     Quite likely that is the start of the following statement.
+     But what we want is the statement containing the instruction.
+     Fudge the pc to make sure we get that.  */
+
+  if (notcurrent) pc -= 1;
+
+  s = find_pc_symtab (pc);
+  if (s == 0)
+    {
+      val.symtab = 0;
+      val.line = 0;
+      val.pc = pc;
+      val.end = 0;
+      return val;
+    }
+
+  bv = BLOCKVECTOR (s);
+
+  /* Look at all the symtabs that share this blockvector.
+     They all have the same apriori range, that we found was right;
+     but they have different line tables.  */
+
+  for (; s && BLOCKVECTOR (s) == bv; s = s->next)
+    {
+      /* Find the best line in this symtab.  */
+      l = LINETABLE (s);
+      len = l->nitems;
+      prev_line = -1;
+      first_line = -1;
+      for (i = 0; i < len; i++)
+       {
+         item = &(l->item[i]);
+         
+         if (first_line < 0)
+           {
+             first_line = item->line;
+             first_pc = item->pc;
+           }
+         /* Return the last line that did not start after PC.  */
+         if (pc >= item->pc)
+           {
+             prev_line = item->line;
+             prev_pc = item->pc;
+           }
+         else
+           break;
+       }
+
+      /* Is this file's best line closer than the best in the other files?
+        If so, record this file, and its best line, as best so far.  */
+      if (prev_line >= 0 && prev_pc > best_pc)
+       {
+         best_pc = prev_pc;
+         best_line = prev_line;
+         best_symtab = s;
+         if (i < len)
+           best_end = item->pc;
+         else
+           best_end = 0;
+       }
+      /* Is this file's first line closer than the first lines of other files?
+        If so, record this file, and its first line, as best alternate.  */
+      if (first_line >= 0 && first_pc > pc
+         && (alt_pc == 0 || first_pc < alt_pc))
+       {
+         alt_pc = first_pc;
+         alt_line = first_line;
+         alt_symtab = s;
+       }
+    }
+  if (best_symtab == 0)
+    {
+      val.symtab = alt_symtab;
+      val.line = alt_line - 1;
+      val.pc = BLOCK_END (BLOCKVECTOR_BLOCK (bv, 0));
+      val.end = alt_pc;
+    }
+  else
+    {
+      val.symtab = best_symtab;
+      val.line = best_line;
+      val.pc = best_pc;
+      val.end = (best_end ? best_end
+                  : (alt_pc ? alt_pc
+                     : BLOCK_END (BLOCKVECTOR_BLOCK (bv, 0))));
+    }
+  return val;
+}
+\f
+/* Find the PC value for a given source file and line number.
+   Returns zero for invalid line number.
+   The source file is specified with a struct symtab.  */
+
+CORE_ADDR
+find_line_pc (symtab, line)
+     struct symtab *symtab;
+     int line;
+{
+  register struct linetable *l;
+  register int ind;
+  int dummy;
+
+  if (symtab == 0)
+    return 0;
+  l = LINETABLE (symtab);
+  ind = find_line_common(l, line, &dummy);
+  return ind ? l->item[ind].pc : 0;
+}
+
+/* Find the range of pc values in a line.
+   Store the starting pc of the line into *STARTPTR
+   and the ending pc (start of next line) into *ENDPTR.
+   Returns 1 to indicate success.
+   Returns 0 if could not find the specified line.  */
+
+int
+find_line_pc_range (symtab, thisline, startptr, endptr)
+     struct symtab *symtab;
+     int thisline;
+     CORE_ADDR *startptr, *endptr;
+{
+  register struct linetable *l;
+  register int ind;
+  int exact_match;             /* did we get an exact linenumber match */
+
+  if (symtab == 0)
+    return 0;
+
+  l = LINETABLE (symtab);
+  ind = find_line_common (l, thisline, &exact_match);
+  if (ind)
+    {
+      *startptr = l->item[ind].pc;
+      /* If we have not seen an entry for the specified line,
+        assume that means the specified line has zero bytes.  */
+      if (!exact_match || ind == l->nitems-1)
+       *endptr = *startptr;
+      else
+       /* Perhaps the following entry is for the following line.
+          It's worth a try.  */
+       if (ind+1 < l->nitems
+        && l->item[ind+1].line == thisline + 1)
+         *endptr = l->item[ind+1].pc;
+       else
+         *endptr = find_line_pc (symtab, thisline+1);
+      return 1;
+    }
+
+  return 0;
+}
+
+/* Given a line table and a line number, return the index into the line
+   table for the pc of the nearest line whose number is >= the specified one.
+   Return 0 if none is found.  The value is never zero is it is an index.
+
+   Set *EXACT_MATCH nonzero if the value returned is an exact match.  */
+
+static int
+find_line_common (l, lineno, exact_match)
+     register struct linetable *l;
+     register int lineno;
+     int *exact_match;
+{
+  register int i;
+  register int len;
+
+  /* BEST is the smallest linenumber > LINENO so far seen,
+     or 0 if none has been seen so far.
+     BEST_INDEX identifies the item for it.  */
+
+  int best_index = 0;
+  int best = 0;
+
+  if (lineno <= 0)
+    return 0;
+
+  len = l->nitems;
+  for (i = 0; i < len; i++)
+    {
+      register struct linetable_entry *item = &(l->item[i]);
+
+      if (item->line == lineno)
+       {
+         *exact_match = 1;
+         return i;
+       }
+
+      if (item->line > lineno && (best == 0 || item->line < best))
+       {
+         best = item->line;
+         best_index = i;
+       }
+    }
+
+  /* If we got here, we didn't get an exact match.  */
+
+  *exact_match = 0;
+  return best_index;
+}
+
+int
+find_pc_line_pc_range (pc, startptr, endptr)
+     CORE_ADDR pc;
+     CORE_ADDR *startptr, *endptr;
+{
+  struct symtab_and_line sal;
+  sal = find_pc_line (pc, 0);
+  *startptr = sal.pc;
+  *endptr = sal.end;
+  return sal.symtab != 0;
+}
+\f
+/* Recursive helper function for decode_line_1.
+ * Look for methods named NAME in type T.
+ * Return number of matches.
+ * Put matches in PHYSNAMES and SYM_ARR (which better be big enough!).
+ * These allocations seem to define "big enough":
+ * sym_arr = (struct symbol **) alloca(TYPE_NFN_FIELDS_TOTAL (t) * sizeof(struct symbol*));
+ * physnames = (char **) alloca (TYPE_NFN_FIELDS_TOTAL (t) * sizeof(char*));
+ */
+
+int
+find_methods(t, name, physnames, sym_arr)
+     struct type *t;
+     char *name;
+     char **physnames;
+     struct symbol **sym_arr;
+{
+  int i1 = 0;
+  int ibase;
+  struct symbol *sym_class;
+  char *class_name = type_name_no_tag (t);
+  /* Ignore this class if it doesn't have a name.
+     This prevents core dumps, but is just a workaround
+     because we might not find the function in
+     certain cases, such as
+     struct D {virtual int f();}
+     struct C : D {virtual int g();}
+     (in this case g++ 1.35.1- does not put out a name
+     for D as such, it defines type 19 (for example) in
+     the same stab as C, and then does a
+     .stabs "D:T19" and a .stabs "D:t19".
+     Thus
+     "break C::f" should not be looking for field f in
+     the class named D, 
+     but just for the field f in the baseclasses of C
+     (no matter what their names).
+     
+     However, I don't know how to replace the code below
+     that depends on knowing the name of D.  */
+  if (class_name
+      && (sym_class = lookup_symbol (class_name,
+                                    (struct block *)NULL,
+                                    STRUCT_NAMESPACE,
+                                    (int *)NULL,
+                                    (struct symtab **)NULL)))
+    {
+      int method_counter;
+      t = SYMBOL_TYPE (sym_class);
+      for (method_counter = TYPE_NFN_FIELDS (t) - 1;
+          method_counter >= 0;
+          --method_counter)
+       {
+         int field_counter;
+         struct fn_field *f = TYPE_FN_FIELDLIST1 (t, method_counter);
+
+         char *method_name = TYPE_FN_FIELDLIST_NAME (t, method_counter);
+         if (!strcmp (name, method_name))
+           /* Find all the fields with that name.  */
+           for (field_counter = TYPE_FN_FIELDLIST_LENGTH (t, method_counter) - 1;
+                field_counter >= 0;
+                --field_counter)
+             {
+               char *phys_name;
+               if (TYPE_FLAGS (TYPE_FN_FIELD_TYPE (f, field_counter)) & TYPE_FLAG_STUB)
+                 check_stub_method (t, method_counter, field_counter);
+               phys_name = TYPE_FN_FIELD_PHYSNAME (f, field_counter);
+               physnames[i1] = (char*) alloca (strlen (phys_name) + 1);
+               strcpy (physnames[i1], phys_name);
+               sym_arr[i1] = lookup_symbol (phys_name,
+                                            SYMBOL_BLOCK_VALUE (sym_class),
+                                            VAR_NAMESPACE,
+                                            (int *) NULL,
+                                            (struct symtab **) NULL);
+               if (sym_arr[i1]) i1++;
+             }
+       }
+    }
+  /* Only search baseclasses if there is no match yet,
+   * since names in derived classes override those in baseclasses.
+   */
+  if (i1)
+    return i1;
+  for (ibase = 0; ibase < TYPE_N_BASECLASSES (t); ibase++)
+    i1 += find_methods(TYPE_BASECLASS(t, ibase), name,
+                      physnames + i1, sym_arr + i1);
+  return i1;
+}
+
+/* Parse a string that specifies a line number.
+   Pass the address of a char * variable; that variable will be
+   advanced over the characters actually parsed.
+
+   The string can be:
+
+   LINENUM -- that line number in current file.  PC returned is 0.
+   FILE:LINENUM -- that line in that file.  PC returned is 0.
+   FUNCTION -- line number of openbrace of that function.
+      PC returned is the start of the function.
+   VARIABLE -- line number of definition of that variable.
+      PC returned is 0.
+   FILE:FUNCTION -- likewise, but prefer functions in that file.
+   *EXPR -- line in which address EXPR appears.
+
+   FUNCTION may be an undebuggable function found in misc_function_vector.
+
+   If the argument FUNFIRSTLINE is nonzero, we want the first line
+   of real code inside a function when a function is specified.
+
+   DEFAULT_SYMTAB specifies the file to use if none is specified.
+   It defaults to current_source_symtab.
+   DEFAULT_LINE specifies the line number to use for relative
+   line numbers (that start with signs).  Defaults to current_source_line.
+
+   Note that it is possible to return zero for the symtab
+   if no file is validly specified.  Callers must check that.
+   Also, the line number returned may be invalid.  */
+
+struct symtabs_and_lines
+decode_line_1 (argptr, funfirstline, default_symtab, default_line)
+     char **argptr;
+     int funfirstline;
+     struct symtab *default_symtab;
+     int default_line;
+{
+  struct symtabs_and_lines decode_line_2 ();
+  struct symtabs_and_lines values;
+  struct symtab_and_line val;
+  register char *p, *p1;
+  register struct symtab *s;
+
+  register struct symbol *sym;
+  /* The symtab that SYM was found in.  */
+  struct symtab *sym_symtab;
+
+  register CORE_ADDR pc;
+  register int i;
+  char *copy;
+  struct symbol *sym_class;
+  int i1;
+  struct symbol **sym_arr;
+  struct type *t;
+  char **physnames;
+  
+  /* Defaults have defaults.  */
+
+  if (default_symtab == 0)
+    {
+      default_symtab = current_source_symtab;
+      default_line = current_source_line;
+    }
+
+  /* See if arg is *PC */
+
+  if (**argptr == '*')
+    {
+      (*argptr)++;
+      pc = parse_and_eval_address_1 (argptr);
+      values.sals = (struct symtab_and_line *)
+       xmalloc (sizeof (struct symtab_and_line));
+      values.nelts = 1;
+      values.sals[0] = find_pc_line (pc, 0);
+      values.sals[0].pc = pc;
+      return values;
+    }
+
+  /* Maybe arg is FILE : LINENUM or FILE : FUNCTION */
+
+  s = 0;
+
+  for (p = *argptr; *p; p++)
+    {
+      if (p[0] == ':' || p[0] == ' ' || p[0] == '\t')
+       break;
+    }
+  while (p[0] == ' ' || p[0] == '\t') p++;
+
+  if (p[0] == ':')
+    {
+
+      /*  C++  */
+      if (p[1] ==':')
+       {
+         /* Extract the class name.  */
+         p1 = p;
+         while (p != *argptr && p[-1] == ' ') --p;
+         copy = (char *) alloca (p - *argptr + 1);
+         bcopy (*argptr, copy, p - *argptr);
+         copy[p - *argptr] = 0;
+
+         /* Discard the class name from the arg.  */
+         p = p1 + 2;
+         while (*p == ' ' || *p == '\t') p++;
+         *argptr = p;
+
+         sym_class = lookup_symbol (copy, 0, STRUCT_NAMESPACE, 0, 
+                                    (struct symtab **)NULL);
+       
+         if (sym_class &&
+             (TYPE_CODE (SYMBOL_TYPE (sym_class)) == TYPE_CODE_STRUCT
+              || TYPE_CODE (SYMBOL_TYPE (sym_class)) == TYPE_CODE_UNION))
+           {
+             /* Arg token is not digits => try it as a function name
+                Find the next token (everything up to end or next whitespace). */
+             p = *argptr;
+             while (*p && *p != ' ' && *p != '\t' && *p != ',' && *p !=':') p++;
+             copy = (char *) alloca (p - *argptr + 1);
+             bcopy (*argptr, copy, p - *argptr);
+             copy[p - *argptr] = '\0';
+
+             /* no line number may be specified */
+             while (*p == ' ' || *p == '\t') p++;
+             *argptr = p;
+
+             sym = 0;
+             i1 = 0;           /*  counter for the symbol array */
+             t = SYMBOL_TYPE (sym_class);
+             sym_arr = (struct symbol **) alloca(TYPE_NFN_FIELDS_TOTAL (t) * sizeof(struct symbol*));
+             physnames = (char **) alloca (TYPE_NFN_FIELDS_TOTAL (t) * sizeof(char*));
+
+             if (destructor_name_p (copy, t))
+               {
+                 /* destructors are a special case.  */
+                 struct fn_field *f = TYPE_FN_FIELDLIST1 (t, 0);
+                 int len = TYPE_FN_FIELDLIST_LENGTH (t, 0) - 1;
+                 char *phys_name = TYPE_FN_FIELD_PHYSNAME (f, len);
+                 physnames[i1] = (char *)alloca (strlen (phys_name) + 1);
+                 strcpy (physnames[i1], phys_name);
+                 sym_arr[i1] =
+                   lookup_symbol (phys_name, SYMBOL_BLOCK_VALUE (sym_class),
+                                  VAR_NAMESPACE, 0, (struct symtab **)NULL);
+                 if (sym_arr[i1]) i1++;
+               }
+             else
+               i1 = find_methods (t, copy, physnames, sym_arr);
+             if (i1 == 1)
+               {
+                 /* There is exactly one field with that name.  */
+                 sym = sym_arr[0];
+
+                 if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK)
+                   {
+                     /* Arg is the name of a function */
+                     pc = BLOCK_START (SYMBOL_BLOCK_VALUE (sym)) + FUNCTION_START_OFFSET;
+                     if (funfirstline)
+                       SKIP_PROLOGUE (pc);
+                     values.sals = (struct symtab_and_line *)xmalloc (sizeof (struct symtab_and_line));
+                     values.nelts = 1;
+                     values.sals[0] = find_pc_line (pc, 0);
+                     values.sals[0].pc = (values.sals[0].end && values.sals[0].pc != pc) ? values.sals[0].end : pc;
+                   }
+                 else
+                   {
+                     values.nelts = 0;
+                   }
+                 return values;
+               }
+             if (i1 > 0)
+               {
+                 /* There is more than one field with that name
+                    (overloaded).  Ask the user which one to use.  */
+                 return decode_line_2 (sym_arr, i1, funfirstline);
+               }
+             else
+               error ("that class does not have any method named %s",copy);
+           }
+         else
+           /* The quotes are important if copy is empty.  */
+           error("No class, struct, or union named \"%s\"", copy );
+       }
+      /*  end of C++  */
+
+
+      /* Extract the file name.  */
+      p1 = p;
+      while (p != *argptr && p[-1] == ' ') --p;
+      copy = (char *) alloca (p - *argptr + 1);
+      bcopy (*argptr, copy, p - *argptr);
+      copy[p - *argptr] = 0;
+
+      /* Find that file's data.  */
+      s = lookup_symtab (copy);
+      if (s == 0)
+       {
+         if (symtab_list == 0 && partial_symtab_list == 0)
+           error (no_symtab_msg);
+         error ("No source file named %s.", copy);
+       }
+
+      /* Discard the file name from the arg.  */
+      p = p1 + 1;
+      while (*p == ' ' || *p == '\t') p++;
+      *argptr = p;
+    }
+
+  /* S is specified file's symtab, or 0 if no file specified.
+     arg no longer contains the file name.  */
+
+  /* Check whether arg is all digits (and sign) */
+
+  p = *argptr;
+  if (*p == '-' || *p == '+') p++;
+  while (*p >= '0' && *p <= '9')
+    p++;
+
+  if (p != *argptr && (*p == 0 || *p == ' ' || *p == '\t' || *p == ','))
+    {
+      /* We found a token consisting of all digits -- at least one digit.  */
+      enum sign {none, plus, minus} sign = none;
+
+      /* This is where we need to make sure that we have good defaults.
+        We must guarantee that this section of code is never executed
+        when we are called with just a function name, since
+        select_source_symtab calls us with such an argument  */
+
+      if (s == 0 && default_symtab == 0)
+       {
+         if (symtab_list == 0 && partial_symtab_list == 0)
+           error (no_symtab_msg);
+         select_source_symtab (0);
+         default_symtab = current_source_symtab;
+         default_line = current_source_line;
+       }
+
+      if (**argptr == '+')
+       sign = plus, (*argptr)++;
+      else if (**argptr == '-')
+       sign = minus, (*argptr)++;
+      val.line = atoi (*argptr);
+      switch (sign)
+       {
+       case plus:
+         if (p == *argptr)
+           val.line = 5;
+         if (s == 0)
+           val.line = default_line + val.line;
+         break;
+       case minus:
+         if (p == *argptr)
+           val.line = 15;
+         if (s == 0)
+           val.line = default_line - val.line;
+         else
+           val.line = 1;
+         break;
+       case none:
+         break;        /* No need to adjust val.line.  */
+       }
+
+      while (*p == ' ' || *p == '\t') p++;
+      *argptr = p;
+      if (s == 0)
+       s = default_symtab;
+      val.symtab = s;
+      val.pc = 0;
+      values.sals = (struct symtab_and_line *)xmalloc (sizeof (struct symtab_and_line));
+      values.sals[0] = val;
+      values.nelts = 1;
+      return values;
+    }
+
+  /* Arg token is not digits => try it as a variable name
+     Find the next token (everything up to end or next whitespace).  */
+  p = *argptr;
+  while (*p && *p != ' ' && *p != '\t' && *p != ',') p++;
+  copy = (char *) alloca (p - *argptr + 1);
+  bcopy (*argptr, copy, p - *argptr);
+  copy[p - *argptr] = 0;
+  while (*p == ' ' || *p == '\t') p++;
+  *argptr = p;
+
+  /* Look up that token as a variable.
+     If file specified, use that file's per-file block to start with.  */
+
+  sym = lookup_symbol (copy,
+                      (s ? BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), 1)
+                       : get_selected_block ()),
+                      VAR_NAMESPACE, 0, &sym_symtab);
+
+  if (sym != NULL)
+    {
+      if (SYMBOL_CLASS (sym) == LOC_BLOCK)
+       {
+         /* Arg is the name of a function */
+         pc = BLOCK_START (SYMBOL_BLOCK_VALUE (sym)) + FUNCTION_START_OFFSET;
+         if (funfirstline)
+           SKIP_PROLOGUE (pc);
+         val = find_pc_line (pc, 0);
+#ifdef PROLOGUE_FIRSTLINE_OVERLAP
+         /* Convex: no need to suppress code on first line, if any */
+         val.pc = pc;
+#else
+         val.pc = (val.end && val.pc != pc) ? val.end : pc;
+#endif
+         values.sals = (struct symtab_and_line *)xmalloc (sizeof (struct symtab_and_line));
+         values.sals[0] = val;
+         values.nelts = 1;
+         
+         /* I think this is always the same as the line that
+            we calculate above, but the general principle is
+            "trust the symbols more than stuff like
+            SKIP_PROLOGUE".  */
+         if (SYMBOL_LINE (sym) != 0)
+           values.sals[0].line = SYMBOL_LINE (sym);
+         
+         return values;
+       }
+      else if (SYMBOL_LINE (sym) != 0)
+       {
+         /* We know its line number.  */
+         values.sals = (struct symtab_and_line *)
+           xmalloc (sizeof (struct symtab_and_line));
+         values.nelts = 1;
+         bzero (&values.sals[0], sizeof (values.sals[0]));
+         values.sals[0].symtab = sym_symtab;
+         values.sals[0].line = SYMBOL_LINE (sym);
+         return values;
+       }
+      else
+       /* This can happen if it is compiled with a compiler which doesn't
+          put out line numbers for variables.  */
+       error ("Line number not known for symbol \"%s\"", copy);
+    }
+
+  if (symtab_list == 0 && partial_symtab_list == 0)
+    error (no_symtab_msg);
+
+  if ((i = lookup_misc_func (copy)) >= 0)
+    {
+      val.symtab = 0;
+      val.line = 0;
+      val.pc = misc_function_vector[i].address + FUNCTION_START_OFFSET;
+      if (funfirstline)
+       SKIP_PROLOGUE (val.pc);
+      values.sals = (struct symtab_and_line *)xmalloc (sizeof (struct symtab_and_line));
+      values.sals[0] = val;
+      values.nelts = 1;
+      return values;
+    }
+
+  error ("Function %s not defined.", copy);
+  return values;       /* for lint */
+}
+
+struct symtabs_and_lines
+decode_line_spec (string, funfirstline)
+     char *string;
+     int funfirstline;
+{
+  struct symtabs_and_lines sals;
+  if (string == 0)
+    error ("Empty line specification.");
+  sals = decode_line_1 (&string, funfirstline,
+                       current_source_symtab, current_source_line);
+  if (*string)
+    error ("Junk at end of line specification: %s", string);
+  return sals;
+}
+
+/* Given a list of NELTS symbols in sym_arr (with corresponding
+   mangled names in physnames), return a list of lines to operate on
+   (ask user if necessary).  */
+struct symtabs_and_lines
+decode_line_2 (sym_arr, nelts, funfirstline)
+     struct symbol *sym_arr[];
+     int nelts;
+     int funfirstline;
+{
+  char *getenv();
+  struct symtabs_and_lines values, return_values;
+  register CORE_ADDR pc;
+  char *args, *arg1, *command_line_input ();
+  int i;
+  char *prompt;
+
+  values.sals = (struct symtab_and_line *) alloca (nelts * sizeof(struct symtab_and_line));
+  return_values.sals = (struct symtab_and_line *) xmalloc (nelts * sizeof(struct symtab_and_line));
+
+  i = 0;
+  printf("[0] cancel\n[1] all\n");
+  while (i < nelts)
+    {
+      if (sym_arr[i] && SYMBOL_CLASS (sym_arr[i]) == LOC_BLOCK)
+       {
+         /* Arg is the name of a function */
+         pc = BLOCK_START (SYMBOL_BLOCK_VALUE (sym_arr[i])) 
+              + FUNCTION_START_OFFSET;
+         if (funfirstline)
+           SKIP_PROLOGUE (pc);
+         values.sals[i] = find_pc_line (pc, 0);
+         values.sals[i].pc = (values.sals[i].end && values.sals[i].pc != pc) ?
+                              values.sals[i].end                      :  pc;
+         printf("[%d] file:%s; line number:%d\n",
+                (i+2), values.sals[i].symtab->filename, values.sals[i].line);
+       }
+      else printf ("?HERE\n");
+      i++;
+    }
+  
+  if ((prompt = getenv ("PS2")) == NULL)
+    {
+      prompt = ">";
+    }
+  printf("%s ",prompt);
+  fflush(stdout);
+
+  args = command_line_input (0, 0);
+  
+  if (args == 0)
+    error_no_arg ("one or more choice numbers");
+
+  i = 0;
+  while (*args)
+    {
+      int num;
+
+      arg1 = args;
+      while (*arg1 >= '0' && *arg1 <= '9') arg1++;
+      if (*arg1 && *arg1 != ' ' && *arg1 != '\t')
+       error ("Arguments must be choice numbers.");
+
+      num = atoi (args);
+
+      if (num == 0)
+       error ("cancelled");
+      else if (num == 1)
+       {
+         bcopy (values.sals, return_values.sals, (nelts * sizeof(struct symtab_and_line)));
+         return_values.nelts = nelts;
+         return return_values;
+       }
+
+      if (num > nelts + 2)
+       {
+         printf ("No choice number %d.\n", num);
+       }
+      else
+       {
+         num -= 2;
+         if (values.sals[num].pc)
+           {
+             return_values.sals[i++] = values.sals[num];
+             values.sals[num].pc = 0;
+           }
+         else
+           {
+             printf ("duplicate request for %d ignored.\n", num);
+           }
+       }
+
+      args = arg1;
+      while (*args == ' ' || *args == '\t') args++;
+    }
+  return_values.nelts = i;
+  return return_values;
+}
+
+/* Return the index of misc function named NAME.  */
+
+int
+lookup_misc_func (name)
+     register char *name;
+{
+  register int i;
+
+  for (i = 0; i < misc_function_count; i++)
+    if (!strcmp (misc_function_vector[i].name, name))
+      return i;
+  return -1;           /* not found */
+}
+\f
+/* Slave routine for sources_info.  Force line breaks at ,'s.
+   NAME is the name to print and *FIRST is nonzero if this is the first
+   name printed.  Set *FIRST to zero.  */
+static void
+output_source_filename (name, first)
+     char *name;
+     int *first;
+{
+  static int column;
+  /* Table of files printed so far.  Since a single source file can
+     result in several partial symbol tables, we need to avoid printing
+     it more than once.  Note: if some of the psymtabs are read in and
+     some are not, it gets printed both under "Source files for which
+     symbols have been read" and "Source files for which symbols will
+     be read in on demand".  I consider this a reasonable way to deal
+     with the situation.  I'm not sure whether this can also happen for
+     symtabs; it doesn't hurt to check.  */
+  static char **tab = NULL;
+  /* Allocated size of tab in elements.
+     Start with one 256-byte block (when using GNU malloc.c).
+     24 is the malloc overhead when range checking is in effect.  */
+  static int tab_alloc_size = (256 - 24) / sizeof (char *);
+  /* Current size of tab in elements.  */
+  static int tab_cur_size;
+
+  char **p;
+
+  if (*first)
+    {
+      if (tab == NULL)
+       tab = (char **) xmalloc (tab_alloc_size * sizeof (*tab));
+      tab_cur_size = 0;
+    }
+
+  /* Is NAME in tab?  */
+  for (p = tab; p < tab + tab_cur_size; p++)
+    if (strcmp (*p, name) == 0)
+      /* Yes; don't print it again.  */
+      return;
+  /* No; add it to tab.  */
+  if (tab_cur_size == tab_alloc_size)
+    {
+      tab_alloc_size *= 2;
+      tab = (char **) xrealloc (tab, tab_alloc_size * sizeof (*tab));
+    }
+  tab[tab_cur_size++] = name;
+
+  if (*first)
+    {
+      column = 0;
+      *first = 0;
+    }
+  else
+    {
+      printf_filtered (",");
+      column++;
+    }
+
+  if (column != 0 && column + strlen (name) >= 70)
+    {
+      printf_filtered ("\n");
+      column = 0;
+    }
+  else if (column != 0)
+    {
+      printf_filtered (" ");
+      column++;
+    }
+  fputs_filtered (name, stdout);
+  column += strlen (name);
+}  
+
+static void
+sources_info ()
+{
+  register struct symtab *s;
+  register struct partial_symtab *ps;
+  int first;
+  
+  if (symtab_list == 0 && partial_symtab_list == 0)
+    {
+      printf (no_symtab_msg);
+      return;
+    }
+  
+  printf_filtered ("Source files for which symbols have been read in:\n\n");
+
+  first = 1;
+  for (s = symtab_list; s; s = s->next)
+    output_source_filename (s->filename, &first);
+  printf_filtered ("\n\n");
+  
+  printf_filtered ("Source files for which symbols will be read in on demand:\n\n");
+
+  first = 1;
+  for (ps = partial_symtab_list; ps; ps = ps->next)
+    if (!ps->readin)
+      output_source_filename (ps->filename, &first);
+  printf_filtered ("\n");
+}
+
+/* List all symbols (if REGEXP is 0) or all symbols matching REGEXP.
+   If CLASS is zero, list all symbols except functions and type names.
+   If CLASS is 1, list only functions.
+   If CLASS is 2, list only type names.
+
+   BPT is non-zero if we should set a breakpoint at the functions
+   we find.  */
+
+static void
+list_symbols (regexp, class, bpt)
+     char *regexp;
+     int class;
+     int bpt;
+{
+  register struct symtab *s;
+  register struct partial_symtab *ps;
+  register struct blockvector *bv;
+  struct blockvector *prev_bv = 0;
+  register struct block *b;
+  register int i, j;
+  register struct symbol *sym;
+  struct partial_symbol *psym;
+  char *val;
+  static char *classnames[]
+    = {"variable", "function", "type", "method"};
+  int found_in_file = 0;
+
+  if (regexp)
+    if (0 != (val = (char *) re_comp (regexp)))
+      error ("Invalid regexp (%s): %s", val, regexp);
+
+  /* Search through the partial_symtab_list *first* for all symbols
+     matching the regexp.  That way we don't have to reproduce all of
+     the machinery below. */
+  for (ps = partial_symtab_list; ps; ps = ps->next)
+    {
+      struct partial_symbol *bound, *gbound, *sbound;
+      int keep_going = 1;
+
+      if (ps->readin) continue;
+      
+      gbound = global_psymbols.list + ps->globals_offset + ps->n_global_syms;
+      sbound = static_psymbols.list + ps->statics_offset + ps->n_static_syms;
+      bound = gbound;
+
+      /* Go through all of the symbols stored in a partial
+        symtab in one loop. */
+      psym = global_psymbols.list + ps->globals_offset;
+      while (keep_going)
+       {
+         if (psym >= bound)
+           {
+             if (bound == gbound && ps->n_static_syms != 0)
+               {
+                 psym = static_psymbols.list + ps->statics_offset;
+                 bound = sbound;
+               }
+             else
+               keep_going = 0;
+           }
+         else
+           {
+             QUIT;
+
+             /* If it would match (logic taken from loop below)
+                load the file and go on to the next one */
+             if ((regexp == 0 || re_exec (SYMBOL_NAME (psym)))
+                 && ((class == 0 && SYMBOL_CLASS (psym) != LOC_TYPEDEF
+                      && SYMBOL_CLASS (psym) != LOC_BLOCK)
+                     || (class == 1 && SYMBOL_CLASS (psym) == LOC_BLOCK)
+                     || (class == 2 && SYMBOL_CLASS (psym) == LOC_TYPEDEF)
+                     || (class == 3 && SYMBOL_CLASS (psym) == LOC_BLOCK)))
+               {
+                 (void) PSYMTAB_TO_SYMTAB(ps);
+                 keep_going = 0;
+               }
+           }
+         psym++;
+       }
+    }
+
+  /* Here, *if* the class is correct (function only, right now), we
+     search through the misc function vector for symbols that
+     match, and call find_pc_symtab on them to force their symbols to
+     be read.  The symbol will then be found during the scan of symtabs
+     below.  */
+
+  if (class == 1)
+    {
+      for (i = 0; i < misc_function_count; i++)
+       if (regexp == 0 || re_exec (misc_function_vector[i].name))
+         {
+           (void) find_pc_symtab (misc_function_vector[i].address);
+         }
+    }
+
+  /* Printout here so as to get after the "Reading in symbols"
+     messages which will be generated above.  */
+  if (!bpt)
+    printf_filtered (regexp
+         ? "All %ss matching regular expression \"%s\":\n"
+         : "All defined %ss:\n",
+         classnames[class],
+         regexp);
+
+  for (s = symtab_list; s; s = s->next)
+    {
+      found_in_file = 0;
+      bv = BLOCKVECTOR (s);
+      /* Often many files share a blockvector.
+        Scan each blockvector only once so that
+        we don't get every symbol many times.
+        It happens that the first symtab in the list
+        for any given blockvector is the main file.  */
+      if (bv != prev_bv)
+       for (i = 0; i < 2; i++)
+         {
+           b = BLOCKVECTOR_BLOCK (bv, i);
+           /* Skip the sort if this block is always sorted.  */
+           if (!BLOCK_SHOULD_SORT (b))
+             sort_block_syms (b);
+           for (j = 0; j < BLOCK_NSYMS (b); j++)
+             {
+               QUIT;
+               sym = BLOCK_SYM (b, j);
+               if ((regexp == 0 || re_exec (SYMBOL_NAME (sym)))
+                   && ((class == 0 && SYMBOL_CLASS (sym) != LOC_TYPEDEF
+                        && SYMBOL_CLASS (sym) != LOC_BLOCK)
+                       || (class == 1 && SYMBOL_CLASS (sym) == LOC_BLOCK)
+                       || (class == 2 && SYMBOL_CLASS (sym) == LOC_TYPEDEF)
+                       || (class == 3 && SYMBOL_CLASS (sym) == LOC_BLOCK)))
+                 {
+                   if (bpt)
+                     {
+                       /* Set a breakpoint here, if it's a function */
+                       if (class == 1)
+                         break_command (SYMBOL_NAME(sym), 0);
+                     }
+                   else if (!found_in_file)
+                     {
+                       fputs_filtered ("\nFile ", stdout);
+                       fputs_filtered (s->filename, stdout);
+                       fputs_filtered (":\n", stdout);
+                     }
+                   found_in_file = 1;
+
+                   if (class != 2 && i == 1)
+                     printf_filtered ("static ");
+                   if (class == 2
+                       && SYMBOL_NAMESPACE (sym) != STRUCT_NAMESPACE)
+                     printf_filtered ("typedef ");
+
+                   if (class < 3)
+                     {
+                       type_print (SYMBOL_TYPE (sym),
+                                   (SYMBOL_CLASS (sym) == LOC_TYPEDEF
+                                    ? "" : SYMBOL_NAME (sym)),
+                                   stdout, 0);
+
+                       if (class == 2
+                           && SYMBOL_NAMESPACE (sym) != STRUCT_NAMESPACE
+                           && (TYPE_NAME ((SYMBOL_TYPE (sym))) == 0
+                               || 0 != strcmp (TYPE_NAME ((SYMBOL_TYPE (sym))),
+                                               SYMBOL_NAME (sym))))
+                         {
+                           fputs_filtered (" ", stdout);
+                           fprint_symbol (stdout, SYMBOL_NAME (sym));
+                         }
+
+                       printf_filtered (";\n");
+                     }
+                   else
+                     {
+# if 0
+                       char buf[1024];
+                       type_print_base (TYPE_FN_FIELD_TYPE(t, i), stdout, 0, 0); 
+                       type_print_varspec_prefix (TYPE_FN_FIELD_TYPE(t, i), stdout, 0); 
+                       sprintf (buf, " %s::", type_name_no_tag (t));
+                       type_print_method_args (TYPE_FN_FIELD_ARGS (t, i), buf, name, stdout);
+# endif
+                     }
+                 }
+             }
+         }
+      prev_bv = bv;
+    }
+}
+
+static void
+variables_info (regexp)
+     char *regexp;
+{
+  list_symbols (regexp, 0, 0);
+}
+
+static void
+functions_info (regexp)
+     char *regexp;
+{
+  list_symbols (regexp, 1, 0);
+}
+
+#if 0
+static void
+types_info (regexp)
+     char *regexp;
+{
+  list_symbols (regexp, 2, 0);
+}
+#endif
+
+#if 0
+/* Tiemann says: "info methods was never implemented."  */
+static void
+methods_info (regexp)
+     char *regexp;
+{
+  list_symbols (regexp, 3, 0);
+}
+#endif /* 0 */
+
+/* Breakpoint all functions matching regular expression. */
+static void
+rbreak_command (regexp)
+     char *regexp;
+{
+  list_symbols (regexp, 1, 1);
+}
+\f
+/* Initialize the standard C scalar types.  */
+
+static
+struct type *
+init_type (code, length, uns, name)
+     enum type_code code;
+     int length, uns;
+     char *name;
+{
+  register struct type *type;
+
+  type = (struct type *) xmalloc (sizeof (struct type));
+  bzero (type, sizeof *type);
+  TYPE_MAIN_VARIANT (type) = type;
+  TYPE_CODE (type) = code;
+  TYPE_LENGTH (type) = length;
+  TYPE_FLAGS (type) = uns ? TYPE_FLAG_UNSIGNED : 0;
+  TYPE_FLAGS (type) |= TYPE_FLAG_PERM;
+  TYPE_NFIELDS (type) = 0;
+  TYPE_NAME (type) = name;
+
+  /* C++ fancies.  */
+  TYPE_NFN_FIELDS (type) = 0;
+  TYPE_N_BASECLASSES (type) = 0;
+  return type;
+}
+
+/* Return Nonzero if block a is lexically nested within block b,
+   or if a and b have the same pc range.
+   Return zero otherwise. */
+int
+contained_in (a, b)
+     struct block *a, *b;
+{
+  if (!a || !b)
+    return 0;
+  return BLOCK_START (a) >= BLOCK_START (b)
+      && BLOCK_END (a)   <= BLOCK_END (b);
+}
+
+\f
+/* Helper routine for make_symbol_completion_list.  */
+
+int return_val_size, return_val_index;
+char **return_val;
+
+void
+completion_list_add_symbol (symname)
+     char *symname;
+{
+  if (return_val_index + 3 > return_val_size)
+    return_val =
+      (char **)xrealloc (return_val,
+                        (return_val_size *= 2) * sizeof (char *));
+  
+  return_val[return_val_index] =
+    (char *)xmalloc (1 + strlen (symname));
+  
+  strcpy (return_val[return_val_index], symname);
+  
+  return_val[++return_val_index] = (char *)NULL;
+}
+
+/* Return a NULL terminated array of all symbols (regardless of class) which
+   begin by matching TEXT.  If the answer is no symbols, then the return value
+   is an array which contains only a NULL pointer.
+
+   Problem: All of the symbols have to be copied because readline
+   frees them.  I'm not going to worry about this; hopefully there
+   won't be that many.  */
+
+char **
+make_symbol_completion_list (text)
+  char *text;
+{
+  register struct symtab *s;
+  register struct partial_symtab *ps;
+  register struct block *b, *surrounding_static_block = 0;
+  extern struct block *get_selected_block ();
+  register int i, j;
+  struct partial_symbol *psym;
+
+  int text_len = strlen (text);
+  return_val_size = 100;
+  return_val_index = 0;
+  return_val =
+    (char **)xmalloc ((1 + return_val_size) *sizeof (char *));
+  return_val[0] = (char *)NULL;
+
+  /* Look through the partial symtabs for all symbols which begin
+     by matching TEXT.  Add each one that you find to the list.  */
+
+  for (ps = partial_symtab_list; ps; ps = ps->next)
+    {
+      /* If the psymtab's been read in we'll get it when we search
+        through the blockvector.  */
+      if (ps->readin) continue;
+
+      for (psym = global_psymbols.list + ps->globals_offset;
+          psym < (global_psymbols.list + ps->globals_offset
+                  + ps->n_global_syms);
+          psym++)
+       {
+         QUIT;                 /* If interrupted, then quit. */
+         if ((strncmp (SYMBOL_NAME (psym), text, text_len) == 0))
+           completion_list_add_symbol (SYMBOL_NAME (psym));
+       }
+      
+      for (psym = static_psymbols.list + ps->statics_offset;
+          psym < (static_psymbols.list + ps->statics_offset
+                  + ps->n_static_syms);
+          psym++)
+       {
+         QUIT;
+         if ((strncmp (SYMBOL_NAME (psym), text, text_len) == 0))
+           completion_list_add_symbol (SYMBOL_NAME (psym));
+       }
+    }
+
+  /* At this point scan through the misc function vector and add each
+     symbol you find to the list.  Eventually we want to ignore
+     anything that isn't a text symbol (everything else will be
+     handled by the psymtab code above).  */
+
+  for (i = 0; i < misc_function_count; i++)
+    if (!strncmp (text, misc_function_vector[i].name, text_len))
+      completion_list_add_symbol (misc_function_vector[i].name);
+
+  /* Search upwards from currently selected frame (so that we can
+     complete on local vars.  */
+  for (b = get_selected_block (); b; b = BLOCK_SUPERBLOCK (b))
+    {
+      if (!BLOCK_SUPERBLOCK (b))
+       surrounding_static_block = b; /* For elmin of dups */
+      
+      /* Also catch fields of types defined in this places which
+        match our text string.  Only complete on types visible
+        from current context.  */
+      for (i = 0; i < BLOCK_NSYMS (b); i++)
+       {
+         register struct symbol *sym = BLOCK_SYM (b, i);
+         
+         if (!strncmp (SYMBOL_NAME (sym), text, text_len))
+           completion_list_add_symbol (SYMBOL_NAME (sym));
+
+         if (SYMBOL_CLASS (sym) == LOC_TYPEDEF)
+           {
+             struct type *t = SYMBOL_TYPE (sym);
+             enum type_code c = TYPE_CODE (t);
+
+             if (c == TYPE_CODE_UNION || c == TYPE_CODE_STRUCT)
+               for (j = TYPE_N_BASECLASSES (t); j < TYPE_NFIELDS (t); j++)
+                 if (TYPE_FIELD_NAME (t, j) &&
+                     !strncmp (TYPE_FIELD_NAME (t, j), text, text_len))
+                   completion_list_add_symbol (TYPE_FIELD_NAME (t, j));
+           }
+       }
+    }
+
+  /* Go through the symtabs and check the externs and statics for
+     symbols which match.  */
+
+  for (s = symtab_list; s; s = s->next)
+    {
+      b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), 0);
+      
+      for (i = 0; i < BLOCK_NSYMS (b); i++)
+       if (!strncmp (SYMBOL_NAME (BLOCK_SYM (b, i)), text, text_len))
+         completion_list_add_symbol (SYMBOL_NAME (BLOCK_SYM (b, i)));
+    }
+
+  for (s = symtab_list; s; s = s->next)
+    {
+      b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), 1);
+
+      /* Don't do this block twice.  */
+      if (b == surrounding_static_block) continue;
+      
+      for (i = 0; i < BLOCK_NSYMS (b); i++)
+       if (!strncmp (SYMBOL_NAME (BLOCK_SYM (b, i)), text, text_len))
+         completion_list_add_symbol (SYMBOL_NAME (BLOCK_SYM (b, i)));
+    }
+
+  return (return_val);
+}
+\f
+void
+_initialize_symtab ()
+{
+  add_info ("variables", variables_info,
+           "All global and static variable names, or those matching REGEXP.");
+  add_info ("functions", functions_info,
+           "All function names, or those matching REGEXP.");
+#if 0
+  /* This command has at least the following problems:
+     1.  It prints builtin types (in a very strange and confusing fashion).
+     2.  It doesn't print right, e.g. with
+         typedef struct foo *FOO
+        type_print prints "FOO" when we want to make it (in this situation)
+        print "struct foo *".
+     I also think "ptype" or "whatis" is more likely to be useful (but if
+     there is much disagreement "info types" can be fixed).  */
+  add_info ("types", types_info,
+           "All types names, or those matching REGEXP.");
+#endif
+#if 0
+  add_info ("methods", methods_info,
+           "All method names, or those matching REGEXP::REGEXP.\n\
+If the class qualifier is ommited, it is assumed to be the current scope.\n\
+If the first REGEXP is ommited, then all methods matching the second REGEXP\n\
+are listed.");
+#endif
+  add_info ("sources", sources_info,
+           "Source files in the program.");
+
+  add_com ("rbreak", no_class, rbreak_command,
+           "Set a breakpoint for all functions matching REGEXP.");
+
+  /* FIXME:  The code below assumes that the sizes of the basic data
+     types are the same on the host and target machines!!!  */
+
+  builtin_type_void = init_type (TYPE_CODE_VOID, 1, 0, "void");
+
+  builtin_type_float = init_type (TYPE_CODE_FLT, sizeof (float), 0, "float");
+  builtin_type_double = init_type (TYPE_CODE_FLT, sizeof (double), 0, "double");
+
+  builtin_type_char = init_type (TYPE_CODE_INT, sizeof (char), 0, "char");
+  builtin_type_short = init_type (TYPE_CODE_INT, sizeof (short), 0, "short");
+  builtin_type_long = init_type (TYPE_CODE_INT, sizeof (long), 0, "long");
+  builtin_type_int = init_type (TYPE_CODE_INT, sizeof (int), 0, "int");
+
+  builtin_type_unsigned_char = init_type (TYPE_CODE_INT, sizeof (char), 1, "unsigned char");
+  builtin_type_unsigned_short = init_type (TYPE_CODE_INT, sizeof (short), 1, "unsigned short");
+  builtin_type_unsigned_long = init_type (TYPE_CODE_INT, sizeof (long), 1, "unsigned long");
+  builtin_type_unsigned_int = init_type (TYPE_CODE_INT, sizeof (int), 1, "unsigned int");
+#ifdef LONG_LONG
+  builtin_type_long_long =
+    init_type (TYPE_CODE_INT, sizeof (long long), 0, "long long");
+  builtin_type_unsigned_long_long = 
+    init_type (TYPE_CODE_INT, sizeof (long long), 1, "unsigned long long");
+#endif
+  builtin_type_error = init_type (TYPE_CODE_ERROR, 0, 0, "<unknown type>");
+}
+
diff --git a/gdb/symtab.h b/gdb/symtab.h
new file mode 100644 (file)
index 0000000..e63c879
--- /dev/null
@@ -0,0 +1,884 @@
+/* Symbol table definitions for GDB.
+   Copyright (C) 1986, 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.  */
+
+#if !defined (SYMTAB_H)
+#define SYMTAB_H 1
+#include <obstack.h>
+
+/* An obstack to hold objects that should be freed
+   when we load a new symbol table.
+   This includes the symbols made by dbxread
+   and the types that are not permanent.  */
+
+extern struct obstack *symbol_obstack;
+extern struct obstack *psymbol_obstack;
+
+/* Some definitions and declarations to go with use of obstacks.  */
+#define obstack_chunk_alloc xmalloc
+#define obstack_chunk_free free
+#ifdef __STDC__
+extern void *xmalloc ();
+#else
+extern char *xmalloc ();
+#endif
+extern void free ();
+
+/* Some macros for char-based bitfields.  */
+#define B_SET(a,x) (a[x>>3] |= (1 << (x&7)))
+#define B_CLR(a,x) (a[x>>3] &= ~(1 << (x&7)))
+#define B_TST(a,x) (a[x>>3] & (1 << (x&7)))
+#define B_TYPE         unsigned char
+#define        B_BYTES(x)      ( 1 + ((x)>>3) )
+#define        B_CLRALL(a,x) bzero (a, B_BYTES(x))
+
+/* gdb can know one or several symbol tables at the same time;
+   the ultimate intent is to have one for each separately-compiled module.
+   Each such symbol table is recorded by a struct symtab, and they
+   are all chained together.  */
+
+/* In addition, gdb can record any number of miscellaneous undebuggable
+   functions' addresses.  In a system that appends _ to function names,
+   the _'s are removed from the names stored in this table.  */
+
+/* Actually, the misc function list is used to store *all* of the
+   global symbols (text, data, bss, and abs).  It is sometimes used
+   to figure out what symtabs to read in.  The "type" field is used
+   occasionally.
+
+   The misc_info field is available for machine-specific information
+   that can be cached along with a misc function vector entry.  The
+   AMD 29000 tdep.c uses it to remember things it has decoded from the
+   instructions in the function header, so it doesn't have to rederive
+   the info constantly (over a serial line).  It is initialized to zero
+   and stays that way until target-dependent code sets it.  */
+
+enum misc_function_type {mf_unknown = 0, mf_text, mf_data, mf_bss, mf_abs};
+
+struct misc_function
+{
+  char *name;
+  CORE_ADDR address;
+  char *misc_info;     /* Random pointer to misc info.  void * but for old C */
+  enum misc_function_type type;
+};
+
+/* Address and length of the vector recording all misc function names/addresses.  */
+
+struct misc_function *misc_function_vector;
+int misc_function_count;
+\f
+enum language {language_unknown, language_c};
+
+/* All data types of symbols in the compiled program
+   are represented by `struct type' objects.
+   All of these objects are pointed to by the typevector.
+   The type vector may have empty slots that contain zero.  */
+
+struct typevector
+{
+  int length;                  /* Number of types described */
+  struct type *type[1];
+};
+
+/* Different kinds of data types are distinguished by the `code' field.  */
+
+enum type_code
+{
+  TYPE_CODE_UNDEF,             /* Not used; catches errors */
+  TYPE_CODE_PTR,               /* Pointer type */
+  TYPE_CODE_ARRAY,             /* Array type, lower bound zero */
+  TYPE_CODE_STRUCT,            /* C struct or Pascal record */
+  TYPE_CODE_UNION,             /* C union or Pascal variant part */
+  TYPE_CODE_ENUM,              /* Enumeration type */
+  TYPE_CODE_FUNC,              /* Function type */
+  TYPE_CODE_INT,               /* Integer type */
+  TYPE_CODE_FLT,               /* Floating type */
+  TYPE_CODE_VOID,              /* Void type (values zero length) */
+  TYPE_CODE_SET,               /* Pascal sets */
+  TYPE_CODE_RANGE,             /* Range (integers within spec'd bounds) */
+  TYPE_CODE_PASCAL_ARRAY,      /* Array with explicit type of index */
+  TYPE_CODE_ERROR,              /* Unknown type */
+
+  /* C++ */
+  TYPE_CODE_MEMBER,            /* Member type */
+  TYPE_CODE_METHOD,            /* Method type */
+  TYPE_CODE_REF,               /* C++ Reference types */
+};
+
+/* This appears in a type's flags word for an unsigned integer type.  */
+#define TYPE_FLAG_UNSIGNED 1
+/* This appears in a type's flags word
+   if it is a (pointer to a|function returning a)* built in scalar type.
+   These types are never freed.  */
+#define TYPE_FLAG_PERM 4
+/* This appears in a type's flags word if it is a stub type (eg. if
+   someone referenced a type that wasn't definined in a source file
+   via (struct sir_not_appearing_in_this_film *)).  */
+#define TYPE_FLAG_STUB 8
+/* Set when a class has a constructor defined */
+#define        TYPE_FLAG_HAS_CONSTRUCTOR       256
+/* Set when a class has a destructor defined */
+#define        TYPE_FLAG_HAS_DESTRUCTOR        512
+
+struct type
+{
+  /* Code for kind of type */
+  enum type_code code;
+  /* Name of this type, or zero if none.
+     This is used for printing only, except by poorly designed C++ code.
+     Type names specified as input are defined by symbols.  */
+  char *name;
+  /* Length in bytes of storage for a value of this type */
+  unsigned length;
+  /* For a pointer type, describes the type of object pointed to.
+     For an array type, describes the type of the elements.
+     For a function or method type, describes the type of the value.
+     For a range type, describes the type of the full range.
+     Unused otherwise.  */
+  struct type *target_type;
+  /* Type that is a pointer to this type.
+     Zero if no such pointer-to type is known yet.
+     The debugger may add the address of such a type
+     if it has to construct one later.  */ 
+  struct type *pointer_type;
+  /* C++: also need a reference type.  */
+  struct type *reference_type;
+  struct type **arg_types;
+  
+  /* Type that is a function returning this type.
+     Zero if no such function type is known here.
+     The debugger may add the address of such a type
+     if it has to construct one later.  */
+  struct type *function_type;
+
+/* Handling of pointers to members:
+   TYPE_MAIN_VARIANT is used for pointer and pointer
+   to member types.  Normally it the value of the address of its
+   containing type.  However, for pointers to members, we must be
+   able to allocate pointer to member types and look them up
+   from some place of reference.
+   NEXT_VARIANT is the next element in the chain.
+
+   A long time ago (Jul 88; GDB 2.5) Tiemann said that main_variant
+   may no longer be necessary and that he might eliminate it.  I don't
+   know whether this is still true (or ever was).  */
+  struct type *main_variant, *next_variant;
+
+  /* Flags about this type.  */
+  short flags;
+  /* Number of fields described for this type */
+  short nfields;
+  /* For structure and union types, a description of each field.
+     For set and pascal array types, there is one "field",
+     whose type is the domain type of the set or array.
+     For range types, there are two "fields",
+     the minimum and maximum values (both inclusive).
+     For enum types, each possible value is described by one "field".
+
+     Using a pointer to a separate array of fields
+     allows all types to have the same size, which is useful
+     because we can allocate the space for a type before
+     we know what to put in it.  */
+  struct field
+    {
+      /* Position of this field, counting in bits from start of
+        containing structure.  For a function type, this is the
+        position in the argument list of this argument.
+        For a range bound or enum value, this is the value itself.  */
+      int bitpos;
+      /* Size of this field, in bits, or zero if not packed.
+        For an unpacked field, the field's type's length
+        says how many bytes the field occupies.  */
+      int bitsize;
+      /* In a struct or enum type, type of this field.
+        In a function type, type of this argument.
+        In an array type, the domain-type of the array.  */
+      struct type *type;
+      /* Name of field, value or argument.
+        Zero for range bounds and array domains.  */
+      char *name;
+    } *fields;
+
+  /* C++ */
+  B_TYPE *virtual_field_bits; /* if base class is virtual */
+  B_TYPE *private_field_bits;
+  B_TYPE *protected_field_bits;
+
+  /* Number of methods described for this type */
+  short nfn_fields;
+  /* Number of base classes this type derives from. */
+  short n_baseclasses;
+
+  /* Number of methods described for this type plus all the
+     methods that it derives from.  */
+  int nfn_fields_total;
+
+  /* For classes, structures, and unions, a description of each field,
+     which consists of an overloaded name, followed by the types of
+     arguments that the method expects, and then the name after it
+     has been renamed to make it distinct.  */
+  struct fn_fieldlist
+    {
+      /* The overloaded name.  */
+      char *name;
+      /* The number of methods with this name.  */
+      int length;
+      /* The list of methods.  */
+      struct fn_field
+       {
+#if 0
+         /* The overloaded name */
+         char *name;
+#endif
+         /* The return value of the method */
+         struct type *type;
+         /* The argument list */
+         struct type **args;
+         /* The name after it has been processed */
+         char *physname;
+
+         /* For virtual functions.   */
+         /* First baseclass that defines this virtual function.   */
+         struct type *fcontext;
+         /* Index into that baseclass's virtual function table,
+            minus 1; else if static: VOFFSET_STATIC; else: 0.  */
+         int voffset;
+#        define VOFFSET_STATIC (-1)
+       } *fn_fields;
+
+      B_TYPE *private_fn_field_bits;
+      B_TYPE *protected_fn_field_bits;
+
+    } *fn_fieldlists;
+
+  unsigned char via_protected;
+  unsigned char via_public;
+
+  /* For types with virtual functions, VPTR_BASETYPE is the base class which
+     defined the virtual function table pointer.  VPTR_FIELDNO is
+     the field number of that pointer in the structure.
+
+     For types that are pointer to member types, VPTR_BASETYPE
+     ifs the type that this pointer is a member of.
+
+     Unused otherwise.  */
+  struct type *vptr_basetype;
+
+  int vptr_fieldno;
+};
+\f
+/* All of the name-scope contours of the program
+   are represented by `struct block' objects.
+   All of these objects are pointed to by the blockvector.
+
+   Each block represents one name scope.
+   Each lexical context has its own block.
+
+   The first two blocks in the blockvector are special.
+   The first one contains all the symbols defined in this compilation
+   whose scope is the entire program linked together.
+   The second one contains all the symbols whose scope is the
+   entire compilation excluding other separate compilations.
+   In C, these correspond to global symbols and static symbols.
+
+   Each block records a range of core addresses for the code that
+   is in the scope of the block.  The first two special blocks
+   give, for the range of code, the entire range of code produced
+   by the compilation that the symbol segment belongs to.
+
+   The blocks appear in the blockvector
+   in order of increasing starting-address,
+   and, within that, in order of decreasing ending-address.
+
+   This implies that within the body of one function
+   the blocks appear in the order of a depth-first tree walk.  */
+
+struct blockvector
+{
+  /* Number of blocks in the list.  */
+  int nblocks;
+  /* The blocks themselves.  */
+  struct block *block[1];
+};
+
+struct block
+{
+  /* Addresses in the executable code that are in this block.
+     Note: in an unrelocated symbol segment in a file,
+     these are always zero.  They can be filled in from the
+     N_LBRAC and N_RBRAC symbols in the loader symbol table.  */
+  CORE_ADDR startaddr, endaddr;
+  /* The symbol that names this block,
+     if the block is the body of a function;
+     otherwise, zero.
+     Note: In an unrelocated symbol segment in an object file,
+     this field may be zero even when the block has a name.
+     That is because the block is output before the name
+     (since the name resides in a higher block).
+     Since the symbol does point to the block (as its value),
+     it is possible to find the block and set its name properly.  */
+  struct symbol *function;
+  /* The `struct block' for the containing block, or 0 if none.  */
+  /* Note that in an unrelocated symbol segment in an object file
+     this pointer may be zero when the correct value should be
+     the second special block (for symbols whose scope is one compilation).
+     This is because the compiler ouptuts the special blocks at the
+     very end, after the other blocks.   */
+  struct block *superblock;
+  /* A flag indicating whether or not the fucntion corresponding
+     to this block was compiled with gcc or not.  If there is no
+     function corresponding to this block, this meaning of this flag
+     is undefined.  (In practice it will be 1 if the block was created
+     while processing a file compiled with gcc and 0 when not). */
+  unsigned char gcc_compile_flag;
+  /* Number of local symbols.  */
+  int nsyms;
+  /* The symbols.  */
+  struct symbol *sym[1];
+};
+\f
+/* Represent one symbol name; a variable, constant, function or typedef.  */
+
+/* Different name spaces for symbols.  Looking up a symbol specifies
+   a namespace and ignores symbol definitions in other name spaces.
+
+   VAR_NAMESPACE is the usual namespace.
+   In C, this contains variables, function names, typedef names
+   and enum type values.
+
+   STRUCT_NAMESPACE is used in C to hold struct, union and enum type names.
+   Thus, if `struct foo' is used in a C program,
+   it produces a symbol named `foo' in the STRUCT_NAMESPACE.
+
+   LABEL_NAMESPACE may be used for names of labels (for gotos);
+   currently it is not used and labels are not recorded at all.  */
+
+/* For a non-global symbol allocated statically,
+   the correct core address cannot be determined by the compiler.
+   The compiler puts an index number into the symbol's value field.
+   This index number can be matched with the "desc" field of
+   an entry in the loader symbol table.  */
+
+enum namespace
+{
+  UNDEF_NAMESPACE, VAR_NAMESPACE, STRUCT_NAMESPACE, LABEL_NAMESPACE,
+};
+
+/* An address-class says where to find the value of a symbol.  */
+
+enum address_class
+{
+  LOC_UNDEF,           /* Not used; catches errors */
+  LOC_CONST,           /* Value is constant int SYMBOL_VALUE, host byteorder */
+  LOC_STATIC,          /* Value is at fixed address SYMBOL_VALUE_ADDRESS */
+  LOC_REGISTER,                /* Value is in register */
+  LOC_ARG,             /* Value is at spec'd offset in arglist */
+  LOC_REF_ARG,         /* Value address is at spec'd offset in arglist. */
+  LOC_REGPARM,         /* Value is at spec'd offset in register window */
+  LOC_LOCAL,           /* Value is at spec'd offset in stack frame */
+  LOC_TYPEDEF,         /* Value not used; definition in SYMBOL_TYPE
+                          Symbols in the namespace STRUCT_NAMESPACE
+                          all have this class.  */
+  LOC_LABEL,           /* Value is address SYMBOL_VALUE_ADDRESS in the code */
+  LOC_BLOCK,           /* Value is address SYMBOL_VALUE_BLOCK of a
+                          `struct block'.  Function names have this class. */
+  LOC_EXTERNAL,                /* Value is at address SYMBOL_VALUE_ADDRESS not in
+                          this compilation.
+                          This is used only in psymtabs; in symtabs
+                          LOC_STATIC is used instead (since in that case
+                          we take the time to find the address).  */
+  LOC_CONST_BYTES,     /* Value is a constant byte-sequence pointed to by
+                          SYMBOL_VALUE_ADDRESS, in target byte order.  */
+  LOC_LOCAL_ARG,       /* Value is arg at spec'd offset in stack frame.
+                          Differs from LOC_LOCAL in that symbol is an
+                          argument; differs from LOC_ARG in that we find it
+                          in the frame (FRAME_LOCALS_ADDRESS), not in the
+                          arglist (FRAME_ARGS_ADDRESS).  Added for i960,
+                          which passes args in regs then copies to frame.  */
+};
+
+struct symbol
+{
+  /* Symbol name */
+  char *name;
+  /* Name space code.  */
+  enum namespace namespace;
+  /* Address class */
+  enum address_class class;
+  /* Data type of value */
+  struct type *type;
+
+  /* Line number of definition.  */
+  unsigned short line;
+  
+  /* constant value, or address if static, or register number,
+     or offset in arguments, or offset in stack frame.  All of
+     these are in host byte order (though what they point to might
+     be in target byte order, e.g. LOC_CONST_BYTES).  */
+  union
+    {
+      long value;              /* for LOC_CONST, LOC_REGISTER, LOC_ARG, 
+                                  LOC_REF_ARG, LOC_REGPARM, LOC_LOCAL */
+      struct block *block;      /* for LOC_BLOCK */
+      char *bytes;             /* for LOC_CONST_BYTES */
+      CORE_ADDR address;       /* for LOC_STATIC, LOC_LABEL, LOC_EXTERNAL */
+      struct symbol *chain;    /* for opaque typedef struct chain */
+    }
+  value;
+};
+
+
+/* A partial_symbol records the name, namespace, and address class of
+   symbols whose types we have not parsed yet.  For functions, it also
+   contains their memory address, so we can find them from a PC value.
+   Each partial_symbol sits in a partial_symtab, all of which are chained
+   on the partial_symtab_list and which points to the corresponding 
+   normal symtab once the partial_symtab has been referenced.  */
+
+struct partial_symbol
+{
+  /* Symbol name */
+  char *name;
+  /* Name space code.  */
+  enum namespace namespace;
+  /* Address class (for info_symbols) */
+  enum address_class class;
+  /* Value (only used for static functions currently).  Done this
+     way so that we can use the struct symbol macros.
+     Note that the address of a function is SYMBOL_VALUE_ADDRESS (pst)
+     in a partial symbol table, but BLOCK_START (SYMBOL_BLOCK_VALUE (st))
+     in a symbol table.  */
+  union
+    {
+      long value;
+      CORE_ADDR address;
+    }
+  value;
+};
+\f
+/* Source-file information.
+   This describes the relation between source files and line numbers
+   and addresses in the program text.  */
+
+struct sourcevector
+{
+  int length;                  /* Number of source files described */
+  struct source *source[1];    /* Descriptions of the files */
+};
+
+/* Each item represents a line-->pc (or the reverse) mapping.  This is
+   somewhat more wasteful of space than one might wish, but since only
+   the files which are actually debugged are read in to core, we don't
+   waste much space.
+
+   Each item used to be an int; either minus a line number, or a
+   program counter.  If it represents a line number, that is the line
+   described by the next program counter value.  If it is positive, it
+   is the program counter at which the code for the next line starts.  */
+
+struct linetable_entry
+{
+  int line;
+  CORE_ADDR pc;
+};
+
+struct linetable
+{
+  int nitems;
+  struct linetable_entry item[1];
+};
+
+/* All the information on one source file.  */
+
+struct source
+{
+  char *name;                  /* Name of file */
+  struct linetable contents;
+};
+
+/* Each source file is represented by a struct symtab. 
+   These objects are chained through the `next' field.  */
+
+struct symtab
+  {
+    /* Chain of all existing symtabs.  */
+    struct symtab *next;
+    /* List of all symbol scope blocks for this symtab.  */
+    struct blockvector *blockvector;
+    /* Table mapping core addresses to line numbers for this file.  */
+    struct linetable *linetable;
+    /* Vector containing all types defined for this symtab.  */
+    struct typevector *typevector;
+    /* Name of this source file.  */
+    char *filename;
+    /* Directory in which it was compiled, or NULL if we don't know.  */
+    char *dirname;
+    /* This component says how to free the data we point to:
+       free_contents => do a tree walk and free each object.
+       free_nothing => do nothing; some other symtab will free
+         the data this one uses.
+       free_linetable => free just the linetable.  */
+    enum free_code {free_nothing, free_contents, free_linetable}
+      free_code;
+    /* Pointer to one block of storage to be freed, if nonzero.  */
+    /* This is IN ADDITION to the action indicated by free_code.  */
+    char *free_ptr;
+    /* Total number of lines found in source file.  */
+    int nlines;
+    /* Array mapping line number to character position.  */
+    int *line_charpos;
+    /* Language of this source file.  */
+    enum language language;
+    /* String of version information.  May be zero.  */
+    char *version;
+    /* Full name of file as found by searching the source path.
+       0 if not yet known.  */
+    char *fullname;
+  };
+
+/* Each source file that has not been fully read in is represented by
+   a partial_symtab.  This contains the information on where in the
+   executable the debugging symbols for a specific file are, and a
+   list of names of global symbols which are located in this file.
+   They are all chained on partial_symtab_list.
+
+   Even after the source file has been read into a symtab, the
+   partial_symtab remains around.  They are allocated on an obstack,
+   psymbol_obstack.  FIXME, this is bad for dynamic linking or VxWorks-
+   style execution of a bunch of .o's.  */
+struct partial_symtab
+{
+  /* Chain of all existing partial symtabs.  */
+  struct partial_symtab *next;
+  /* Name of the source file which this partial_symtab defines */
+  char *filename;
+
+  /* Name of the symbol file from which symbols should be read.  */
+  char *symfile_name;
+  /* Address relative to which the symbols in this file are.  Need to
+     relocate by this amount when reading in symbols from the symbol
+     file.  */
+  CORE_ADDR addr;
+
+  /* Offset within loader symbol table of first local symbol for this
+     file and length (in bytes) of the section of the symbol table
+     devoted to this file's symbols (actually, the section bracketed
+     may contain more than just this files symbols
+     If ldsymlen is 0, the only reason for this things existence is
+     the dependency list below.  Nothing else will happen when it is
+     read in.  */
+  int ldsymoff, ldsymlen;
+  /* Range of text addresses covered by this file; texthigh is the
+     beginning of the next section. */
+  CORE_ADDR textlow, texthigh;
+  /* Array of pointers to all of the partial_symtab's which this one
+     depends on.  Since this array can only be set to previous or
+     the current (?) psymtab, this dependency tree is guaranteed not
+     to have any loops. */
+  struct partial_symtab **dependencies;
+  int number_of_dependencies;
+  /* Global symbol list.  This list will be sorted after readin to
+     improve access.  Binary search will be the usual method of
+     finding a symbol within it. globals_offset is an integer offset
+     within ps_globals */
+  int globals_offset, n_global_syms;
+  /* Static symbol list.  This list will *not* be sorted after readin;
+     to find a symbol in it, exhaustive search must be used.  This is
+     reasonable because searches through this list will eventually
+     lead to either the read in of a files symbols for real (assumed
+     to take a *lot* of time; check) or an error (and we don't care
+     how long errors take). */
+  int statics_offset, n_static_syms;
+  /* Pointer to symtab eventually allocated for this source file, 0 if
+     !readin or if we haven't looked for the symtab after it was readin.  */
+  struct symtab *symtab;
+  /* Pointer to function which will read in the symtab corresponding to
+     this psymtab.  */
+  void (*read_symtab) ();
+  /* Non-zero if the symtab corresponding to this psymtab has been
+     readin */
+  unsigned char readin;
+};
+
+/* A fast way to get from a psymtab to its symtab (after the first time).  */
+#define        PSYMTAB_TO_SYMTAB(pst)  ((pst)->symtab?                 \
+                                (pst)->symtab:                 \
+                                psymtab_to_symtab (pst) )
+
+/* This is the list of struct symtab's that gdb considers current.  */
+
+struct symtab *symtab_list;
+
+/* This is the list of struct partial_symtab's that gdb may need to access */
+
+struct partial_symtab *partial_symtab_list;
+
+/* This symtab variable specifies the current file for printing source lines */
+
+struct symtab *current_source_symtab;
+
+/* This is the next line to print for listing source lines.  */
+
+int current_source_line;
+
+#define BLOCKLIST(symtab) (symtab)->blockvector
+#define BLOCKVECTOR(symtab) (symtab)->blockvector
+
+#define TYPEVECTOR(symtab) (symtab)->typevector
+
+#define LINELIST(symtab) (symtab)->linetable
+#define LINETABLE(symtab) (symtab)->linetable
+\f
+/* Macros normally used to access components of symbol table structures.  */
+
+#define BLOCKLIST_NBLOCKS(blocklist) (blocklist)->nblocks
+#define BLOCKLIST_BLOCK(blocklist,n) (blocklist)->block[n]
+#define BLOCKVECTOR_NBLOCKS(blocklist) (blocklist)->nblocks
+#define BLOCKVECTOR_BLOCK(blocklist,n) (blocklist)->block[n]
+
+#define TYPEVECTOR_NTYPES(typelist) (typelist)->length
+#define TYPEVECTOR_TYPE(typelist,n) (typelist)->type[n]
+
+#define BLOCK_START(bl) (bl)->startaddr
+#define BLOCK_END(bl) (bl)->endaddr
+#define BLOCK_NSYMS(bl) (bl)->nsyms
+#define BLOCK_SYM(bl, n) (bl)->sym[n]
+#define BLOCK_FUNCTION(bl) (bl)->function
+#define BLOCK_SUPERBLOCK(bl) (bl)->superblock
+#define BLOCK_GCC_COMPILED(bl) (bl)->gcc_compile_flag
+
+/* Nonzero if symbols of block BL should be sorted alphabetically.  */
+#define BLOCK_SHOULD_SORT(bl) ((bl)->nsyms >= 40)
+
+#define SYMBOL_NAME(symbol) (symbol)->name
+#define SYMBOL_NAMESPACE(symbol) (symbol)->namespace
+#define SYMBOL_CLASS(symbol) (symbol)->class
+#define SYMBOL_VALUE(symbol) (symbol)->value.value
+#define SYMBOL_VALUE_ADDRESS(symbol) (symbol)->value.address
+#define SYMBOL_VALUE_BYTES(symbol) (symbol)->value.bytes
+#define SYMBOL_BLOCK_VALUE(symbol) (symbol)->value.block
+#define SYMBOL_VALUE_CHAIN(symbol) (symbol)->value.chain
+#define SYMBOL_TYPE(symbol) (symbol)->type
+#define SYMBOL_LINE(symbol) (symbol)->line
+
+#define TYPE_NAME(thistype) (thistype)->name
+#define TYPE_TARGET_TYPE(thistype) (thistype)->target_type
+#define TYPE_POINTER_TYPE(thistype) (thistype)->pointer_type
+#define TYPE_REFERENCE_TYPE(thistype) (thistype)->reference_type
+#define TYPE_FUNCTION_TYPE(thistype) (thistype)->function_type
+#define TYPE_MAIN_VARIANT(thistype) (thistype)->main_variant
+#define TYPE_NEXT_VARIANT(thistype) (thistype)->next_variant
+#define TYPE_LENGTH(thistype) (thistype)->length
+#define TYPE_FLAGS(thistype) (thistype)->flags
+#define TYPE_UNSIGNED(thistype) ((thistype)->flags & TYPE_FLAG_UNSIGNED)
+#define TYPE_CODE(thistype) (thistype)->code
+#define TYPE_NFIELDS(thistype) (thistype)->nfields
+#define TYPE_FIELDS(thistype) (thistype)->fields
+/* C++ */
+#define TYPE_VPTR_BASETYPE(thistype) (thistype)->vptr_basetype
+#define TYPE_DOMAIN_TYPE(thistype) (thistype)->vptr_basetype
+#define TYPE_VPTR_FIELDNO(thistype) (thistype)->vptr_fieldno
+#define TYPE_FN_FIELDS(thistype) (thistype)->fn_fields
+#define TYPE_NFN_FIELDS(thistype) (thistype)->nfn_fields
+#define TYPE_NFN_FIELDS_TOTAL(thistype) (thistype)->nfn_fields_total
+#define TYPE_ARG_TYPES(thistype) (thistype)->arg_types
+#define TYPE_BASECLASS(thistype,index) (thistype)->fields[index].type
+#define TYPE_N_BASECLASSES(thistype) (thistype)->n_baseclasses
+#define TYPE_BASECLASS_NAME(thistype,index) (thistype)->fields[index].name
+#define TYPE_BASECLASS_BITPOS(thistype,index) (thistype)->fields[index].bitpos
+#define BASETYPE_VIA_PUBLIC(thistype, index) (!TYPE_FIELD_PRIVATE(thistype, index))
+#define BASETYPE_VIA_VIRTUAL(thistype, index) B_TST((thistype)->virtual_field_bits, (index))
+
+#define TYPE_FIELD(thistype, n) (thistype)->fields[n]
+#define TYPE_FIELD_TYPE(thistype, n) (thistype)->fields[n].type
+#define TYPE_FIELD_NAME(thistype, n) (thistype)->fields[n].name
+#define TYPE_FIELD_VALUE(thistype, n) (* (int*) &(thistype)->fields[n].type)
+#define TYPE_FIELD_BITPOS(thistype, n) (thistype)->fields[n].bitpos
+#define TYPE_FIELD_BITSIZE(thistype, n) (thistype)->fields[n].bitsize
+#define TYPE_FIELD_PACKED(thistype, n) (thistype)->fields[n].bitsize
+
+#define TYPE_FIELD_PRIVATE_BITS(thistype) (thistype)->private_field_bits
+#define TYPE_FIELD_PROTECTED_BITS(thistype) (thistype)->protected_field_bits
+#define TYPE_FIELD_VIRTUAL_BITS(thistype) (thistype)->virtual_field_bits
+#define SET_TYPE_FIELD_PRIVATE(thistype, n) B_SET ((thistype)->private_field_bits, (n))
+#define SET_TYPE_FIELD_PROTECTED(thistype, n) B_SET ((thistype)->protected_field_bits, (n))
+#define SET_TYPE_FIELD_VIRTUAL(thistype, n) B_SET ((thistype)->virtual_field_bits, (n))
+#define TYPE_FIELD_PRIVATE(thistype, n) B_TST((thistype)->private_field_bits, (n))
+#define TYPE_FIELD_PROTECTED(thistype, n) B_TST((thistype)->protected_field_bits, (n))
+#define TYPE_FIELD_VIRTUAL(thistype, n) B_TST((thistype)->virtual_field_bits, (n))
+
+#define TYPE_HAS_DESTRUCTOR(thistype) ((thistype)->flags & TYPE_FLAG_HAS_DESTRUCTOR)
+#define TYPE_HAS_CONSTRUCTOR(thistype) ((thistype)->flags & TYPE_FLAG_HAS_CONSTRUCTOR)
+
+#define TYPE_FIELD_STATIC(thistype, n) ((thistype)->fields[n].bitpos == -1)
+#define TYPE_FIELD_STATIC_PHYSNAME(thistype, n) ((char *)(thistype)->fields[n].bitsize)
+
+#define TYPE_FN_FIELDLISTS(thistype) (thistype)->fn_fieldlists
+#define TYPE_FN_FIELDLIST(thistype, n) (thistype)->fn_fieldlists[n]
+#define TYPE_FN_FIELDLIST1(thistype, n) (thistype)->fn_fieldlists[n].fn_fields
+#define TYPE_FN_FIELDLIST_NAME(thistype, n) (thistype)->fn_fieldlists[n].name
+#define TYPE_FN_FIELDLIST_LENGTH(thistype, n) (thistype)->fn_fieldlists[n].length
+
+#define TYPE_FN_FIELD(thistype, n) (thistype)[n]
+#define TYPE_FN_FIELD_NAME(thistype, n) (thistype)[n].name
+#define TYPE_FN_FIELD_TYPE(thistype, n) (thistype)[n].type
+#define TYPE_FN_FIELD_ARGS(thistype, n) TYPE_ARG_TYPES ((thistype)[n].type)
+#define TYPE_FN_FIELD_PHYSNAME(thistype, n) (thistype)[n].physname
+#define TYPE_FN_FIELD_VIRTUAL_P(thistype, n) ((thistype)[n].voffset > 0)
+#define TYPE_FN_FIELD_STATIC_P(thistype, n) ((thistype)[n].voffset == VOFFSET_STATIC)
+#define TYPE_FN_FIELD_VOFFSET(thistype, n) ((thistype)[n].voffset-1)
+#define TYPE_FN_FIELD_FCONTEXT(thistype, n) ((thistype)[n].fcontext)
+
+#define TYPE_FN_PRIVATE_BITS(thistype) (thistype).private_fn_field_bits
+#define TYPE_FN_PROTECTED_BITS(thistype) (thistype).protected_fn_field_bits
+#define SET_TYPE_FN_PRIVATE(thistype, n) B_SET ((thistype).private_fn_field_bits, n)
+#define SET_TYPE_FN_PROTECTED(thistype, n) B_SET ((thistype).protected_fn_field_bits, n)
+#define TYPE_FN_PRIVATE(thistype, n) B_TST ((thistype).private_fn_field_bits, n)
+#define TYPE_FN_PROTECTED(thistype, n) B_TST ((thistype).protected_fn_field_bits, n)
+
+/* The virtual function table is now an array of structures
+   which have the form { int16 offset, delta; void *pfn; }. 
+   Gee, can we have more documentation than that?   FIXME.  -- gnu */
+  
+#define VTBL_FNADDR_OFFSET 2
+\f
+/* Functions that work on the objects described above */
+
+extern struct symtab *lookup_symtab ();
+extern struct symbol *lookup_symbol ();
+extern struct symbol *lookup_block_symbol ();
+extern int lookup_misc_func ();
+extern void check_stub_type ();
+extern void check_stub_method ();
+extern struct type *lookup_primitive_typename ();
+extern struct type *lookup_typename ();
+extern struct type *lookup_unsigned_typename ();
+extern struct type *lookup_struct ();
+extern struct type *lookup_union ();
+extern struct type *lookup_enum ();
+extern struct type *lookup_struct_elt_type ();
+extern struct type *lookup_pointer_type ();
+extern struct type *lookup_function_type ();
+extern struct type *lookup_basetype_type ();
+extern struct type *create_array_type ();
+extern struct symbol *block_function ();
+extern struct symbol *find_pc_function ();
+extern int find_pc_partial_function ();
+extern void clearpc_function_cache ();
+extern struct partial_symtab *lookup_partial_symtab ();
+extern struct partial_symtab *find_pc_psymtab ();
+extern struct symtab *find_pc_symtab ();
+extern struct partial_symbol *find_pc_psymbol ();
+extern int find_pc_misc_function ();
+extern int find_pc_line_pc_range ();
+extern char *type_name_no_tag ();
+extern int contained_in();
+
+/* C++ stuff.  */
+extern struct type *lookup_reference_type ();
+extern struct type *lookup_member_type ();
+extern struct type *lookup_class ();
+extern void smash_to_method_type ();
+/* end of C++ stuff.  */
+
+extern void free_all_symtabs ();
+extern void free_all_psymtabs ();
+extern void free_inclink_symtabs ();
+extern void reread_symbols ();
+
+extern struct type *builtin_type_void;
+extern struct type *builtin_type_char;
+extern struct type *builtin_type_short;
+extern struct type *builtin_type_int;
+extern struct type *builtin_type_long;
+extern struct type *builtin_type_unsigned_char;
+extern struct type *builtin_type_unsigned_short;
+extern struct type *builtin_type_unsigned_int;
+extern struct type *builtin_type_unsigned_long;
+extern struct type *builtin_type_float;
+extern struct type *builtin_type_double;
+/* This type represents a type that was unrecognized in symbol
+   read-in.  */
+extern struct type *builtin_type_error;
+
+#ifdef LONG_LONG
+extern struct type *builtin_type_long_long;
+extern struct type *builtin_type_unsigned_long_long;
+
+#define BUILTIN_TYPE_LONGEST builtin_type_long_long
+#define BUILTIN_TYPE_UNSIGNED_LONGEST builtin_type_unsigned_long_long
+/* This should not be a typedef, because "unsigned LONGEST" needs
+   to work.  */
+#define LONGEST long long
+
+#else /* not LONG_LONG.  */
+
+#define BUILTIN_TYPE_LONGEST builtin_type_long
+#define BUILTIN_TYPE_UNSIGNED_LONGEST builtin_type_unsigned_long
+#define LONGEST long
+
+#endif /* not LONG_LONG.  */
+
+struct symtab_and_line
+{
+  struct symtab *symtab;
+  int line;
+  CORE_ADDR pc;
+  CORE_ADDR end;
+};
+
+struct symtabs_and_lines
+{
+  struct symtab_and_line *sals;
+  int nelts;
+};
+
+/* Given a pc value, return line number it is in.
+   Second arg nonzero means if pc is on the boundary
+   use the previous statement's line number.  */
+
+struct symtab_and_line find_pc_line ();
+
+/* Given a symtab and line number, return the pc there.  */
+extern CORE_ADDR find_line_pc ();
+extern int find_line_pc_range ();
+
+/* Given a string, return the line specified by it.
+   For commands like "list" and "breakpoint".  */
+
+struct symtabs_and_lines decode_line_spec ();
+struct symtabs_and_lines decode_line_spec_1 ();
+struct symtabs_and_lines decode_line_1 ();
+
+/* Symbol-reading stuff in symfile.c and solib.c.  */
+struct symtab *psymtab_to_symtab ();
+void clear_solib ();
+void symbol_file_add ();
+
+/* source.c */
+int identify_source_line ();
+void print_source_lines ();
+
+char **make_symbol_completion_list ();
+
+/* The entry point of a file we are reading.  */
+extern CORE_ADDR entry_point;
+
+#endif /* symtab.h not already included.  */
diff --git a/gdb/target.c b/gdb/target.c
new file mode 100644 (file)
index 0000000..a58d0cd
--- /dev/null
@@ -0,0 +1,563 @@
+/* Select target systems and architectures at runtime for GDB.
+   Copyright (C) 1990 Free Software Foundation, Inc.
+   Contributed by Cygnus Support.
+
+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 <errno.h>
+#include <ctype.h>
+#include "defs.h"
+#include "target.h"
+#include "gdbcmd.h"
+#include "symtab.h"
+#include "inferior.h"
+#include "bfd.h"
+#include "symfile.h"
+
+extern int memory_insert_breakpoint(), memory_remove_breakpoint();
+extern void host_convert_to_virtual(), host_convert_from_virtual();
+
+static void cleanup_target ();
+
+/* Pointer to array of target architecture structures; the size of the
+   array; the current index into the array; the allocated size of the 
+   array.  */
+struct target_ops **target_structs;
+unsigned target_struct_size;
+unsigned target_struct_index;
+unsigned target_struct_allocsize;
+#define        DEFAULT_ALLOCSIZE       10
+
+/* The initial current target, so that there is always a semi-valid
+   current target.  */
+
+struct target_ops dummy_target = {"None", "None",
+    0, 0, 0, 0,                /* open, close, attach, detach */
+    0, 0,              /* resume, wait */
+    0, 0, 0, 0, 0,     /* registers */
+    0, 0,              /* memory */
+    0, 0,              /* bkpts */
+    0, 0, 0, 0, 0,     /* terminal */
+    0, 0, 0,           /* kill, load, add_syms */
+    0, 0,              /* call_function, lookup_symbol */
+    0, 0,              /* create_inferior, mourn_inferior */
+    dummy_stratum, 0,  /* stratum, next */
+    0, 0, 0, 0, 0,     /* all mem, mem, stack, regs, exec */
+    OPS_MAGIC,
+};
+
+/* The target structure we are currently using to talk to a process
+   or file or whatever "inferior" we have.  */
+
+struct target_ops *current_target;
+
+/* The stack of target structures that have been pushed.  */
+
+struct target_ops **current_target_stack;
+
+
+/* Add a possible target architecture to the list.  */
+
+void
+add_target (t)
+     struct target_ops *t;
+{
+  if (t->to_magic != OPS_MAGIC)
+    {
+      fprintf(stderr, "Magic number of %s target struct wrong\n", 
+       t->to_shortname);
+      abort();
+    }
+
+  if (!target_structs)
+    {
+      target_struct_allocsize = DEFAULT_ALLOCSIZE;
+      target_structs = (struct target_ops **) xmalloc
+       (target_struct_allocsize * sizeof (*target_structs));
+    }
+  if (target_struct_size >= target_struct_allocsize)
+    {
+      target_struct_allocsize *= 2;
+      target_structs = (struct target_ops **) xrealloc (target_structs, 
+       target_struct_allocsize * sizeof (*target_structs));
+    }
+  target_structs[target_struct_size++] = t;
+  cleanup_target (t);
+}
+
+/* Stub functions */
+
+static void
+ignore ()
+{
+}
+
+/* ARGSUSED */
+static int
+nomemory (memaddr, myaddr, len, write)
+     CORE_ADDR memaddr;
+     char *myaddr;
+     int len;
+     int write;
+{
+  return 0;            /* No bytes handled */
+}
+
+static void
+tcomplain ()
+{
+  error ("You can't do that when your target is `%s'",
+        current_target->to_shortname);
+}
+
+static int
+noprocess ()
+{
+  error ("You can't do that without a process to debug");
+}
+
+static int
+nosymbol (name, addrp)
+     char *name;
+     CORE_ADDR *addrp;
+{
+  return 1;            /* Symbol does not exist in target env */
+}
+
+static void
+default_terminal_info (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  printf("No saved terminal information.\n");
+}
+
+#if 0
+/* With strata, this function is no longer needed.  FIXME.  */
+/* This is the default target_create_inferior function.  It looks up
+   the stack for some target that cares to create inferiors, then
+   calls it -- or complains if not found.  */
+
+static void
+upstack_create_inferior (exec, args, env)
+     char *exec;
+     char *args;
+     char **env;
+{
+  struct target_ops *t;
+
+  for (t = current_target;
+       t;
+       t = t->to_next)
+    {
+      if (t->to_create_inferior != upstack_create_inferior)
+       {
+          t->to_create_inferior (exec, args, env);
+         return;
+       }
+
+    }
+  tcomplain();
+}
+#endif
+
+/* This is the default target_create_inferior and target_attach function.
+   If the current target is executing, it asks whether to kill it off.
+   If this function returns without calling error(), it has killed off
+   the target, and the operation should be attempted.  */
+
+static void
+kill_or_be_killed (from_tty)
+     int from_tty;
+{
+  struct target_ops *savecur;
+
+  if (target_has_execution)
+    {
+      printf ("You are already running a program:\n");
+      target_files_info ();
+      if (query ("Kill it? ")) {
+       savecur = current_target;
+       target_kill (0, from_tty);
+       if (target_has_execution)
+         error ("Killing the program did not help.");
+       return;
+      } else {
+       error ("Program not killed.");
+      }
+    }
+  tcomplain();
+}
+
+static void
+maybe_kill_then_attach (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  kill_or_be_killed (from_tty);
+  target_attach (args, from_tty);
+}
+
+static void
+maybe_kill_then_create_inferior (exec, args, env)
+     char *exec;
+     char *args;
+     char **env;
+{
+  kill_or_be_killed (0);
+  target_create_inferior (exec, args, env);
+}
+
+/* Clean up a target struct so it no longer has any zero pointers in it.
+   We default entries, at least to stubs that print error messages.  */
+
+static void
+cleanup_target (t)
+     struct target_ops *t;
+{
+
+  /* Check magic number.  If wrong, it probably means someone changed
+     the struct definition, but not all the places that initialize one.  */
+  if (t->to_magic != OPS_MAGIC)
+    {
+      fprintf(stderr, "Magic number of %s target struct wrong\n", 
+       t->to_shortname);
+      abort();
+    }
+
+#define de_fault(field, value) \
+  if (!t->field)       t->field = value
+
+  /*        FIELD                      DEFAULT VALUE        */
+
+  de_fault (to_open,                   tcomplain);
+  de_fault (to_close,                  (void (*)())ignore);
+  de_fault (to_attach,                         maybe_kill_then_attach);
+  de_fault (to_detach,                         (void (*)())ignore);
+  de_fault (to_resume,                         (void (*)())noprocess);
+  de_fault (to_wait,                   noprocess);
+  de_fault (to_fetch_registers,        noprocess);
+  de_fault (to_store_registers,                noprocess);
+  de_fault (to_prepare_to_store,       (void (*)())noprocess);
+  de_fault (to_convert_to_virtual,     host_convert_to_virtual);
+  de_fault (to_convert_from_virtual,   host_convert_from_virtual);
+  de_fault (to_xfer_memory,            nomemory);
+  de_fault (to_files_info,             ignore);
+  de_fault (to_insert_breakpoint,      memory_insert_breakpoint);
+  de_fault (to_remove_breakpoint,      memory_remove_breakpoint);
+  de_fault (to_terminal_init,          ignore);
+  de_fault (to_terminal_inferior,      ignore);
+  de_fault (to_terminal_ours_for_output,ignore);
+  de_fault (to_terminal_ours,          ignore);
+  de_fault (to_terminal_info,          default_terminal_info);
+  de_fault (to_kill,                   (void (*)())noprocess);
+  de_fault (to_load,                   tcomplain);
+  de_fault (to_add_syms,               tcomplain);
+  de_fault (to_call_function,          (struct value *(*)())noprocess);
+  de_fault (to_lookup_symbol,          nosymbol);
+  de_fault (to_create_inferior,                maybe_kill_then_create_inferior);
+  de_fault (to_mourn_inferior,         (void (*)())noprocess);
+  de_fault (to_next,                   0);
+  de_fault (to_has_all_memory,         0);
+  de_fault (to_has_memory,             0);
+  de_fault (to_has_stack,              0);
+  de_fault (to_has_registers,          0);
+  de_fault (to_has_execution,          0);
+
+#undef de_fault
+}
+
+/* Push a new target type into the stack of the existing target accessors,
+   possibly superseding some of the existing accessors.
+
+   Result is zero if the pushed target ended up on top of the stack,
+   nonzero if at least one target is on top of it.
+
+   Rather than allow an empty stack, we always have the dummy target at
+   the bottom stratum, so we can call the function vectors without
+   checking them.  */
+
+int
+push_target (t)
+     struct target_ops *t;
+{
+  struct target_ops *st, *prev;
+
+  for (prev = 0, st = current_target;
+       st;
+       prev = st, st = st->to_next) {
+    if ((int)(t->to_stratum) >= (int)(st->to_stratum))
+      break;
+  }
+
+  while (t->to_stratum == st->to_stratum) {
+    /* There's already something on this stratum.  Close it off.  */
+    (st->to_close) (0);
+    if (prev)
+      prev->to_next = st->to_next;     /* Unchain old target_ops */
+    else
+      current_target = st->to_next;    /* Unchain first on list */
+    st = st->to_next;
+  }
+
+  /* We have removed all targets in our stratum, now add ourself.  */
+  t->to_next = st;
+  if (prev)
+    prev->to_next = t;
+  else
+    current_target = t;
+
+  cleanup_target (current_target);
+  return prev != 0;
+}
+
+/* Remove a target_ops vector from the stack, wherever it may be. 
+   Return how many times it was removed (0 or 1 unless bug).  */
+
+int
+unpush_target (t)
+     struct target_ops *t;
+{
+  struct target_ops *u, *v;
+  int result = 0;
+
+  for (u = current_target, v = 0;
+       u;
+       v = u, u = u->to_next)
+    if (u == t)
+      {
+       if (v == 0)
+         pop_target();                 /* unchain top copy */
+       else {
+         (t->to_close)(0);             /* Let it clean up */
+         v->to_next = t->to_next;      /* unchain middle copy */
+       }
+       result++;
+      }
+  return result;
+}
+
+void
+pop_target ()
+{
+  (current_target->to_close)(0);       /* Let it clean up */
+  current_target = current_target->to_next;
+  if (!current_target)         /* At bottom, push dummy.  */
+    push_target (&dummy_target);
+}
+
+/* Print things about the whole set of targets and about the
+   current target stack.  */
+static void
+targets_info ()
+{
+  int i;
+
+  printf("Possible targets:\n\n");
+  for (i = 0; i < target_struct_size; i++)
+    printf ("%-15s %s\n",
+      target_structs[i]->to_shortname, 
+      target_structs[i]->to_longname);
+}
+
+/* Move memory to or from the targets.  Iterate until all of it has
+   been moved, if necessary.  The top target gets priority; anything
+   it doesn't want, is offered to the next one down, etc.  Note the
+   business with curlen:  if an early target says "no, but I have a
+   boundary overlapping this xfer" then we shorten what we offer to
+   the subsequent targets so the early guy will get a chance at the
+   tail before the subsequent ones do. 
+
+   Result is 0 or errno value.  */
+
+int
+target_read_memory (memaddr, myaddr, len)
+     CORE_ADDR memaddr;
+     char *myaddr;
+     int len;
+{
+  return target_xfer_memory (memaddr, myaddr, len, 0);
+}
+
+int
+target_write_memory (memaddr, myaddr, len)
+     CORE_ADDR memaddr;
+     char *myaddr;
+     int len;
+{
+  return target_xfer_memory (memaddr, myaddr, len, 1);
+}
+int
+target_xfer_memory (memaddr, myaddr, len, write)
+     CORE_ADDR memaddr;
+     char *myaddr;
+     int len;
+     int write;
+{
+  int curlen;
+  int res;
+  struct target_ops *t;
+  
+  /* The quick case is that the top target does it all.  */
+  res = current_target->to_xfer_memory(memaddr, myaddr, len, write);
+  if (res == len)
+    return 0;
+
+  if (res > 0)
+    goto bump;
+  /* If res <= 0 then we call it again in the loop.  Ah well.  */
+
+  for (; len > 0;)
+    {
+      curlen = len;            /* Want to do it all */
+      for (t = current_target;
+          t;
+          t = t->to_has_all_memory? 0: t->to_next)
+       {
+         res = t->to_xfer_memory(memaddr, myaddr, curlen, write);
+         if (res > 0) break;   /* Handled all or part of xfer */
+         if (res == 0) continue;       /* Handled none */
+         curlen = -res;        /* Could handle once we get past res bytes */
+       }
+      if (res <= 0)
+       {
+         /* If this address is for nonexistent memory,
+            read zeros if reading, or do nothing if writing.  Return error. */
+         if (!write)
+           bzero (myaddr, len);
+         return EIO;
+       }
+bump:
+      memaddr += res;
+      myaddr  += res;
+      len     -= res;
+    }
+  return 0;                    /* We managed to cover it all somehow. */
+}
+
+
+static void
+target_info (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  struct target_ops *t;
+  int has_all_mem = 0;
+  
+  if (symfile != 0)
+    printf ("Symbols from \"%s\".\n", symfile);
+
+#ifdef FILES_INFO_HOOK
+  if (FILES_INFO_HOOK ())
+    return;
+#endif
+
+  for (t = current_target;
+       t;
+       t = t->to_next)
+    {
+      if ((int)(t->to_stratum) <= (int)dummy_stratum)
+       continue;
+      if (has_all_mem)
+       printf("\tWhile running this, gdb does not access memory from...\n");
+      printf("%s:\n", t->to_longname);
+      (t->to_files_info)();
+      has_all_mem = t->to_has_all_memory;
+    }
+}
+
+/* The target command selects a target and calls its open routine.
+   The open routine takes the rest of the parameters from the command,
+   and (if successful) pushes a new target onto the stack.  */
+
+static void
+target_command (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  int i;
+  char *rest;
+
+  dont_repeat();
+
+  if (!args)
+    error (
+     "Argument required (target name).  `info targets' lists possible targets");
+
+  if (target_has_execution)
+    {   
+      if (query ("A program is being debugged already.  Kill it? "))
+        target_kill ((char *)0, from_tty);
+      else
+        error ("Program not killed.");
+    }
+        
+  /* Skip to first space, or end of args */
+  for (rest = args; *rest && !isspace(*rest); rest++) ;
+  if (*rest == '\0')
+    rest = 0;          /* Only one word in args */
+  else
+    {
+      *rest = '\0';    /* Terminate first word, scan for next */
+      for (rest++; isspace (*rest); rest++) ;
+      if (*rest == '\0')       /* Only one word w/trailing blanks */
+       rest = 0;
+    }
+
+  /* Search target list for a match */
+
+  for (i = 0; i < target_struct_size; i++)
+    {
+      if (!strcmp (args, target_structs[i]->to_shortname))
+       goto gotit;
+    }
+  error ("No such target.  `info targets' will list all targets");
+
+gotit:
+  (*target_structs[i]->to_open) (rest, from_tty);
+}
+
+static char targ_desc[] = 
+    "Names of targets and files being debugged.\n\
+Shows the entire stack of targets currently in use (including the exec-file,\n\
+core-file, and process, if any), as well as the symbol file name.";
+
+void
+_initialize_targets ()
+{
+  current_target = &dummy_target;
+  cleanup_target (current_target);
+
+  add_info ("targets", targets_info,
+    "Names of all possible targets.\n\
+A target is typically a protocol for talking to debugging facilities;\n\
+for example, `child' for Unix child processes, or `vxworks' for a\n\
+TCP/IP link to a VxWorks system.");
+
+  add_info ("target", target_info, targ_desc);
+  add_info ("files", target_info, targ_desc);
+
+  add_com ("target", class_run, target_command,
+"Connect to a target machine or process.\n\
+The first argument is the type or protocol of the target machine.  Remaining\n\
+arguments are interpreted by the target protocol, but typically include\n\
+things like device names or host names to connect with, process numbers,\n\
+baud rates, etc.  You can list all possible targets with the `info targets'\n\
+command.");
+}
diff --git a/gdb/target.h b/gdb/target.h
new file mode 100644 (file)
index 0000000..924f4aa
--- /dev/null
@@ -0,0 +1,406 @@
+/* Interface between GDB and target environments, including files and processes
+   Copyright 1990, 1991 Free Software Foundation, Inc.
+   Contributed by Cygnus Support.  Written by John Gilmore.
+
+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.  */
+
+/* This include file defines the interface between the main part
+   of the debugger, and the part which is target-specific, or
+   specific to the communications interface between us and the
+   target.
+
+   A TARGET is an interface between the debugger and a particular 
+   kind of file or process.  Targets can be STACKED in STRATA, 
+   so that more than one target can potentially respond to a request.
+   In particular, memory accesses will walk down the stack of targets
+   until they find a target that is interested in handling that particular
+   address.  STRATA are artificial boundaries on the stack, within
+   which particular kinds of targets live.  Strata exist so that
+   people don't get confused by pushing e.g. a process target and then
+   a file target, and wondering why they can't see the current values
+   of variables any more (the file target is handling them and they
+   never get to the process target).  So when you push a file target,
+   it goes into the file stratum, which is always below the process
+   stratum.  */
+
+enum strata {
+       dummy_stratum,          /* The lowest of the low */
+       file_stratum,           /* Executable files, etc */
+       core_stratum,           /* Core dump files */
+       process_stratum,        /* Executing processes */
+};
+
+struct target_ops {
+       char  *to_shortname;            /* Name this target type */
+       char  *to_longname;             /* Name for printing */
+#ifdef __STDC__
+       void (*to_open) (char *name, int from_tty);
+       void (*to_close) (int quitting);
+       void (*to_attach) (char *name, int from_tty);
+       void (*to_detach) (char *args, int from_tty);
+       void (*to_resume) (int step, int siggnal);
+       int  (*to_wait)   (int *status);
+       int  (*to_fetch_registers) (int regno);
+       int  (*to_store_registers) (int regno);
+       void (*to_prepare_to_store) ();
+       void (*to_convert_to_virtual) (int regnum, char *from, char *to);
+       void (*to_convert_from_virtual) (int regnum, char *from, char *to);
+       int  (*to_xfer_memory) (CORE_ADDR memaddr, char *myaddr, int len, int w);
+       void (*to_files_info) ();
+       int  (*to_insert_breakpoint) (CORE_ADDR addr, char *save);
+       int  (*to_remove_breakpoint) (CORE_ADDR addr, char *save);
+       void  (*to_terminal_init) ();
+       void  (*to_terminal_inferior) ();
+       void  (*to_terminal_ours_for_output) ();
+       void  (*to_terminal_ours) ();
+       void  (*to_terminal_info) (char *arg, int from_tty);
+       void  (*to_kill) (char *arg, int from_tty);
+       void  (*to_load) (char *arg, int from_tty);
+       void  (*to_add_syms) (char *arg, int from_tty);
+struct value *(*to_call_function) (struct value *function,
+                                  int nargs, struct value **args);
+       int   (*to_lookup_symbol) (char *name, CORE_ADDR *addrp);
+       void  (*to_create_inferior) (char *exec, char *args, char **env);
+       void  (*to_mourn_inferior) ();
+    enum strata to_stratum;
+struct target_ops *to_next;
+       int     to_has_all_memory;
+       int     to_has_memory;
+       int     to_has_stack;
+       int     to_has_registers;
+       int     to_has_execution;
+       int     to_magic;
+/* Need sub-structure for target machine related rather than comm related? */
+#else  /* STDC */
+       void (*to_open) ();
+       void (*to_close) ();
+       void (*to_attach) ();
+       void (*to_detach) ();
+       void (*to_resume) ();
+       int  (*to_wait)   ();
+       int  (*to_fetch_registers) ();
+       int  (*to_store_registers) ();
+       void (*to_prepare_to_store) ();
+       void (*to_convert_to_virtual) ();
+       void (*to_convert_from_virtual) ();
+       int  (*to_xfer_memory) ();
+       void (*to_files_info) ();
+       int  (*to_insert_breakpoint) ();
+       int  (*to_remove_breakpoint) ();
+       void  (*to_terminal_init) ();
+       void  (*to_terminal_inferior) ();
+       void  (*to_terminal_ours_for_output) ();
+       void  (*to_terminal_ours) ();
+       void  (*to_terminal_info) ();
+       void  (*to_kill) ();
+       void  (*to_load) ();
+       void  (*to_add_syms) ();
+struct value *(*to_call_function) ();
+       int   (*to_lookup_symbol) ();
+       void  (*to_create_inferior) ();
+       void  (*to_mourn_inferior) ();
+    enum strata to_stratum;
+struct target_ops *to_next;
+       int     to_has_all_memory;
+       int     to_has_memory;
+       int     to_has_stack;
+       int     to_has_registers;
+       int     to_has_execution;
+       int     to_magic;
+/* Need sub-structure for target machine related rather than comm related? */
+#endif
+};
+
+/* Magic number for checking ops size.  If a struct doesn't end with this
+   number, somebody changed the declaration but didn't change all the
+   places that initialize one.  */
+
+#define        OPS_MAGIC       3840
+
+/* The ops structure for our "current" target process.  */
+
+extern struct target_ops       *current_target;
+
+/* Define easy words for doing these operations on our current target.  */
+
+#define        target_shortname        (current_target->to_shortname)
+#define        target_longname         (current_target->to_longname)
+
+#define        target_open(name, from_tty)     \
+       (*current_target->to_open) (name, from_tty)
+
+/* Does whatever cleanup is required for a target that we are no longer
+   going to be calling.  Argument says whether we are quitting gdb and
+   should not get hung in case of errors, or whether we want a clean
+   termination even if it takes a while.  This routine is automatically
+   always called just before a routine is popped off the target stack.
+   Closing file descriptors and freeing memory are typical things it should
+   do.  */
+
+#define        target_close(quitting)  \
+       (*current_target->to_close) (quitting)
+
+/* Attaches to a process on the target side.  */
+
+#define        target_attach(args, from_tty)   \
+       (*current_target->to_attach) (args, from_tty)
+
+/* Takes a program previously attached to and detaches it.
+   The program may resume execution (some targets do, some don't) and will
+   no longer stop on signals, etc.  We better not have left any breakpoints
+   in the program or it'll die when it hits one.  ARGS is arguments
+   typed by the user (e.g. a signal to send the process).  FROM_TTY
+   says whether to be verbose or not.  */
+
+#define        target_detach(args, from_tty)           \
+       (*current_target->to_detach) (args, from_tty)
+
+/* Resume execution of the target process.  STEP says whether to single-step
+   or to run free; SIGGNAL is the signal value (e.g. SIGINT) to be given
+   to the target, or zero for no signal.  */
+
+#define        target_resume(step, siggnal)    \
+       (*current_target->to_resume) (step, siggnal)
+
+/* Wait for inferior process to do something.  Return pid of child,
+   or -1 in case of error; store status through argument pointer STATUS.  */
+
+#define        target_wait(status)             \
+       (*current_target->to_wait) (status)
+
+/* Fetch register REGNO, or all regs if regno == -1.  Result is 0
+   for success, -1 for problems.  */
+
+#define        target_fetch_registers(regno)   \
+       (*current_target->to_fetch_registers) (regno)
+
+/* Store at least register REGNO, or all regs if REGNO == -1.
+   It can store as many registers as it wants to, so the entire registers
+   array must be valid.  Result is 0 for success, -1 for problems.  */
+
+#define        target_store_registers(regs)    \
+       (*current_target->to_store_registers) (regs)
+
+/* Get ready to modify the registers array.  On machines which store
+   individual registers, this doesn't need to do anything.  On machines
+   which store all the registers in one fell swoop, this makes sure
+   that REGISTERS contains all the registers from the program being
+   debugged.  */
+
+#define        target_prepare_to_store()       \
+       (*current_target->to_prepare_to_store) ()
+
+/* Convert data from raw format for register REGNUM
+   to virtual format for register REGNUM.  */
+
+#define        target_convert_to_virtual(regnum, from, to)     \
+       (*current_target->to_convert_to_virtual) (regnum, from, to)
+       
+/* Convert data from virtual format for register REGNUM
+   to raw format for register REGNUM.  */
+
+#define        target_convert_from_virtual(regnum, from, to)   \
+       (*current_target->to_convert_from_virtual) (regnum, from, to)
+
+/* Reading and writing memory actually happens through a glue
+   function which iterates across the various targets.  Result is
+   0 for success, or an errno value.  */
+
+#ifdef __STDC__
+/* Needs defs.h for CORE_ADDR */
+extern int target_read_memory(CORE_ADDR memaddr, char *myaddr, int len);
+extern int target_write_memory(CORE_ADDR memaddr, char *myaddr, int len);
+extern int target_xfer_memory(CORE_ADDR memaddr, char *myaddr, int len,
+                             int write);
+#else
+extern int target_read_memory();
+extern int target_write_memory();
+extern int target_xfer_memory();
+#endif
+
+/* Print a line about the current target.  */
+
+#define        target_files_info()     \
+       (*current_target->to_files_info) ()
+
+/* Insert a breakpoint at address ADDR in the target machine.
+   SAVE is a pointer to memory allocated for saving the
+   target contents.  It is guaranteed by the caller to be long enough
+   to save "sizeof BREAKPOINT" bytes.  Result is 0 for success, or
+   an errno value.  */
+
+#define        target_insert_breakpoint(addr, save)    \
+       (*current_target->to_insert_breakpoint) (addr, save)
+
+/* Remove a breakpoint at address ADDR in the target machine.
+   SAVE is a pointer to the same save area 
+   that was previously passed to target_insert_breakpoint.  
+   Result is 0 for success, or an errno value.  */
+
+#define        target_remove_breakpoint(addr, save)    \
+       (*current_target->to_remove_breakpoint) (addr, save)
+
+/* Initialize the terminal settings we record for the inferior,
+   before we actually run the inferior.  */
+
+#define target_terminal_init() \
+       (*current_target->to_terminal_init) ()
+       
+/* Put the inferior's terminal settings into effect.
+   This is preparation for starting or resuming the inferior.  */
+
+#define target_terminal_inferior() \
+       (*current_target->to_terminal_inferior) ()
+
+/* Put some of our terminal settings into effect,
+   enough to get proper results from our output,
+   but do not change into or out of RAW mode
+   so that no input is discarded.
+
+   After doing this, either terminal_ours or terminal_inferior
+   should be called to get back to a normal state of affairs.  */
+
+#define target_terminal_ours_for_output() \
+       (*current_target->to_terminal_ours_for_output) ()
+
+/* Put our terminal settings into effect.
+   First record the inferior's terminal settings
+   so they can be restored properly later.  */
+
+#define target_terminal_ours() \
+       (*current_target->to_terminal_ours) ()
+
+/* Print useful information about our terminal status, if such a thing
+   exists.  */
+
+#define target_terminal_info(arg, from_tty) \
+       (*current_target->to_terminal_info) (arg, from_tty)
+
+/* Kill the inferior process.   Make it go away.  */
+
+#define target_kill(arg, from_tty) \
+       (*current_target->to_kill) (arg, from_tty)
+
+/* Load an executable file into the target process.  This is expected to
+   not only bring new code into the target process, but also to update
+   GDB's symbol tables to match.  */
+
+#define target_load(arg, from_tty) \
+       (*current_target->to_load) (arg, from_tty)
+
+/* Add the symbols from an executable file into GDB's symbol table, as if
+   the file had been loaded at a particular address (or set of addresses).
+   This does not change any state in the target system, only in GDB.  */
+
+#define target_add_syms(arg, from_tty) \
+       (*current_target->to_add_syms) (arg, from_tty)
+
+/* Perform a function call in the inferior.
+   ARGS is a vector of values of arguments (NARGS of them).
+   FUNCTION is a value, the function to be called.
+   Returns a value representing what the function returned.
+   May fail to return, if a breakpoint or signal is hit
+   during the execution of the function.  */
+
+#define target_call_function(function, nargs, args)    \
+  (*current_target->to_call_function) (function, nargs, args)
+
+/* Look up a symbol in the target's symbol table.  NAME is the symbol
+   name.  ADDRP is a CORE_ADDR * pointing to where the value of the symbol
+   should be returned.  The result is 0 if successful, nonzero if the
+   symbol does not exist in the target environment.  This function should
+   not call error() if communication with the target is interrupted, since
+   it is called from symbol reading, but should return nonzero, possibly
+   doing a complain().  */
+
+#define target_lookup_symbol(name, addrp)      \
+  (*current_target->to_lookup_symbol) (name, addrp)
+
+/* Start an inferior process and set inferior_pid to its pid.
+   EXEC_FILE is the file to run.
+   ALLARGS is a string containing the arguments to the program.
+   ENV is the environment vector to pass.  Errors reported with error().
+   On VxWorks and various standalone systems, we ignore exec_file.  */
+#define        target_create_inferior(exec_file, args, env)    \
+       (*current_target->to_create_inferior) (exec_file, args, env)
+
+/* The inferior process has died.  Do what is right.  */
+
+#define        target_mourn_inferior() \
+       (*current_target->to_mourn_inferior) ()
+
+/* Pointer to next target in the chain, e.g. a core file and an exec file.  */
+
+#define        target_next \
+       (current_target->to_next)
+
+/* Does the target include all of memory, or only part of it?  This
+   determines whether we look up the target chain for other parts of
+   memory if this target can't satisfy a request.  */
+
+#define        target_has_all_memory   \
+       (current_target->to_has_all_memory)
+
+/* Does the target include memory?  (Dummy targets don't.)  */
+
+#define        target_has_memory       \
+       (current_target->to_has_memory)
+
+/* Does the target have a stack?  (Exec files don't, VxWorks doesn't, until
+   we start a process.)  */
+   
+#define        target_has_stack        \
+       (current_target->to_has_stack)
+
+/* Does the target have registers?  (Exec files don't.)  */
+
+#define        target_has_registers    \
+       (current_target->to_has_registers)
+
+/* Does the target have execution?  Can we make it jump (through hoops),
+   or pop its stack a few times, or set breakpoints?  */
+
+#define        target_has_execution    \
+       (current_target->to_has_execution)
+
+/* Routines for maintenance of the target structures...
+
+   add_target:   Add a target to the list of all possible targets.
+
+   push_target:  Make this target the top of the stack of currently used
+                targets, within its particular stratum of the stack.  Result
+                is 0 if now atop the stack, nonzero if not on top (maybe
+                should warn user).
+
+   unpush_target: Remove this from the stack of currently used targets,
+                no matter where it is on the list.  Returns 0 if no
+                change, 1 if removed from stack.
+
+   pop_target:  Remove the top thing on the stack of current targets.  */
+
+#ifdef __STDC__
+void add_target (struct target_ops *);
+int push_target (struct target_ops *);
+int unpush_target (struct target_ops *);
+void pop_target ();
+#else
+void add_target ();
+int push_target ();
+int unpush_target ();
+void pop_target ();
+#endif
diff --git a/gdb/terminal.h b/gdb/terminal.h
new file mode 100644 (file)
index 0000000..4658c7a
--- /dev/null
@@ -0,0 +1,50 @@
+/* Terminal interface definitions for GDB, the GNU Debugger.
+   Copyright (C) 1986, 1989, 1991 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 a common set of macros -- BSD based -- and redefine whatever
+   the system offers to make it look like that.  */
+
+#ifdef HAVE_TERMIO
+
+#include <termio.h>
+
+#undef TIOCGETP
+#define TIOCGETP TCGETA
+#undef TIOCSETN
+#define TIOCSETN TCSETA
+#undef TIOCSETP
+#define TIOCSETP TCSETAF
+#define TERMINAL struct termio
+
+#ifdef NO_JOB_CONTROL
+# undef TIOCGPGRP
+# undef TIOCGPGRP
+#endif
+
+#else /* no termio */
+
+#include <fcntl.h>
+#include <sgtty.h>
+#include <sys/ioctl.h>
+#define TERMINAL struct sgttyb
+
+#endif /* no termio */
+
+extern void new_tty ();
diff --git a/gdb/utils.c b/gdb/utils.c
new file mode 100644 (file)
index 0000000..1441db1
--- /dev/null
@@ -0,0 +1,1294 @@
+/* General utility routines for GDB, the GNU debugger.
+   Copyright (C) 1986, 1989, 1990, 1991 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 <stdio.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <pwd.h>
+#include "defs.h"
+#include "param.h"
+#include "signals.h"
+#include "gdbcmd.h"
+#include "terminal.h"
+#include <varargs.h>
+#include <ctype.h>
+#include <string.h>
+#include "bfd.h"
+#include "target.h"
+
+extern volatile void return_to_top_level ();
+extern volatile void exit ();
+extern char *gdb_readline ();
+extern char *getenv();
+extern char *malloc();
+extern char *realloc();
+
+/* If this definition isn't overridden by the header files, assume
+   that isatty and fileno exist on this system.  */
+#ifndef ISATTY
+#define ISATTY(FP)     (isatty (fileno (FP)))
+#endif
+
+#ifdef MISSING_VPRINTF
+#ifdef __GNU_LIBRARY
+#undef MISSING_VPRINTF
+#else  /* !__GNU_LIBRARY */
+
+#ifndef vfprintf
+#define vfprintf(file, format, ap) _doprnt (format, ap, file)
+#endif /* vfprintf */
+
+#ifndef vprintf
+/* Can't #define it since printcmd.c needs it */
+void
+vprintf (format, ap)
+     char *format; void *ap;
+{
+  vfprintf (stdout, format, ap);
+}
+#endif /* vprintf */
+
+#endif /* GNU_LIBRARY */
+#endif /* MISSING_VPRINTF */
+
+void error ();
+void fatal ();
+
+/* Chain of cleanup actions established with make_cleanup,
+   to be executed if an error happens.  */
+
+static struct cleanup *cleanup_chain;
+
+/* Nonzero means a quit has been requested.  */
+
+int quit_flag;
+
+/* Nonzero means quit immediately if Control-C is typed now,
+   rather than waiting until QUIT is executed.  */
+
+int immediate_quit;
+
+/* Nonzero means that encoded C++ names should be printed out in their
+   C++ form rather than raw.  */
+
+int demangle = 1;
+
+/* Nonzero means that encoded C++ names should be printed out in their
+   C++ form even in assembler language displays.  If this is set, but
+   DEMANGLE is zero, names are printed raw, i.e. DEMANGLE controls.  */
+
+int asm_demangle = 0;
+
+/* Nonzero means that strings with character values >0x7F should be printed
+   as octal escapes.  Zero means just print the value (e.g. it's an
+   international character, and the terminal or window can cope.)  */
+
+int sevenbit_strings = 0;
+\f
+/* Add a new cleanup to the cleanup_chain,
+   and return the previous chain pointer
+   to be passed later to do_cleanups or discard_cleanups.
+   Args are FUNCTION to clean up with, and ARG to pass to it.  */
+
+struct cleanup *
+make_cleanup (function, arg)
+     void (*function) ();
+     int arg;
+{
+  register struct cleanup *new
+    = (struct cleanup *) xmalloc (sizeof (struct cleanup));
+  register struct cleanup *old_chain = cleanup_chain;
+
+  new->next = cleanup_chain;
+  new->function = function;
+  new->arg = arg;
+  cleanup_chain = new;
+
+  return old_chain;
+}
+
+/* Discard cleanups and do the actions they describe
+   until we get back to the point OLD_CHAIN in the cleanup_chain.  */
+
+void
+do_cleanups (old_chain)
+     register struct cleanup *old_chain;
+{
+  register struct cleanup *ptr;
+  while ((ptr = cleanup_chain) != old_chain)
+    {
+      (*ptr->function) (ptr->arg);
+      cleanup_chain = ptr->next;
+      free (ptr);
+    }
+}
+
+/* Discard cleanups, not doing the actions they describe,
+   until we get back to the point OLD_CHAIN in the cleanup_chain.  */
+
+void
+discard_cleanups (old_chain)
+     register struct cleanup *old_chain;
+{
+  register struct cleanup *ptr;
+  while ((ptr = cleanup_chain) != old_chain)
+    {
+      cleanup_chain = ptr->next;
+      free (ptr);
+    }
+}
+
+/* Set the cleanup_chain to 0, and return the old cleanup chain.  */
+struct cleanup *
+save_cleanups ()
+{
+  struct cleanup *old_chain = cleanup_chain;
+
+  cleanup_chain = 0;
+  return old_chain;
+}
+
+/* Restore the cleanup chain from a previously saved chain.  */
+void
+restore_cleanups (chain)
+     struct cleanup *chain;
+{
+  cleanup_chain = chain;
+}
+
+/* This function is useful for cleanups.
+   Do
+
+     foo = xmalloc (...);
+     old_chain = make_cleanup (free_current_contents, &foo);
+
+   to arrange to free the object thus allocated.  */
+
+void
+free_current_contents (location)
+     char **location;
+{
+  free (*location);
+}
+\f
+/* Print an error message and return to command level.
+   The first argument STRING is the error message, used as a fprintf string,
+   and the remaining args are passed as arguments to it.  */
+
+/* VARARGS */
+void
+error (va_alist)
+     va_dcl
+{
+  va_list args;
+  char *string;
+
+  va_start (args);
+  target_terminal_ours ();
+  fflush (stdout);
+  string = va_arg (args, char *);
+  vfprintf (stderr, string, args);
+  fprintf (stderr, "\n");
+  va_end (args);
+  return_to_top_level ();
+}
+
+/* Print an error message and exit reporting failure.
+   This is for a error that we cannot continue from.
+   The arguments are printed a la printf.  */
+
+/* VARARGS */
+void
+fatal (va_alist)
+     va_dcl
+{
+  va_list args;
+  char *string;
+
+  va_start (args);
+  string = va_arg (args, char *);
+  fprintf (stderr, "gdb: ");
+  vfprintf (stderr, string, args);
+  fprintf (stderr, "\n");
+  va_end (args);
+  exit (1);
+}
+
+/* Print an error message and exit, dumping core.
+   The arguments are printed a la printf ().  */
+/* VARARGS */
+void
+fatal_dump_core (va_alist)
+     va_dcl
+{
+  va_list args;
+  char *string;
+
+  va_start (args);
+  string = va_arg (args, char *);
+  /* "internal error" is always correct, since GDB should never dump
+     core, no matter what the input.  */
+  fprintf (stderr, "gdb internal error: ");
+  vfprintf (stderr, string, args);
+  fprintf (stderr, "\n");
+  va_end (args);
+
+  signal (SIGQUIT, SIG_DFL);
+  kill (getpid (), SIGQUIT);
+  /* We should never get here, but just in case...  */
+  exit (1);
+}
+\f
+/* Memory management stuff (malloc friends).  */
+
+#if defined (NO_MALLOC_CHECK)
+void
+init_malloc ()
+{}
+#else /* Have mcheck().  */
+static void
+malloc_botch ()
+{
+  fatal_dump_core ("Memory corruption");
+}
+
+void
+init_malloc ()
+{
+  mcheck (malloc_botch);
+}
+#endif /* Have mcheck().  */
+
+/* Like malloc but get error if no storage available.  */
+
+#ifdef __STDC__
+void *
+#else
+char *
+#endif
+xmalloc (size)
+     long size;
+{
+  register char *val;
+
+  /* At least one place (dbxread.c:condense_misc_bunches where misc_count == 0)
+     GDB wants to allocate zero bytes.  */
+  if (size == 0)
+    return NULL;
+  
+  val = (char *) malloc (size);
+  if (!val)
+    fatal ("virtual memory exhausted.", 0);
+  return val;
+}
+
+/* Like realloc but get error if no storage available.  */
+
+#ifdef __STDC__
+void *
+#else
+char *
+#endif
+xrealloc (ptr, size)
+     char *ptr;
+     long size;
+{
+  register char *val = (char *) realloc (ptr, size);
+  if (!val)
+    fatal ("virtual memory exhausted.", 0);
+  return val;
+}
+
+/* Print the system error message for errno, and also mention STRING
+   as the file name for which the error was encountered.
+   Then return to command level.  */
+
+void
+perror_with_name (string)
+     char *string;
+{
+  extern int sys_nerr;
+  extern char *sys_errlist[];
+  char *err;
+  char *combined;
+
+  if (errno < sys_nerr)
+    err = sys_errlist[errno];
+  else
+    err = "unknown error";
+
+  combined = (char *) alloca (strlen (err) + strlen (string) + 3);
+  strcpy (combined, string);
+  strcat (combined, ": ");
+  strcat (combined, err);
+
+  /* I understand setting these is a matter of taste.  Still, some people
+     may clear errno but not know about bfd_error.  Doing this here is not
+     unreasonable. */
+  bfd_error = no_error;
+  errno = 0;
+
+  error ("%s.", combined);
+}
+
+/* Print the system error message for ERRCODE, and also mention STRING
+   as the file name for which the error was encountered.  */
+
+void
+print_sys_errmsg (string, errcode)
+     char *string;
+     int errcode;
+{
+  extern int sys_nerr;
+  extern char *sys_errlist[];
+  char *err;
+  char *combined;
+
+  if (errcode < sys_nerr)
+    err = sys_errlist[errcode];
+  else
+    err = "unknown error";
+
+  combined = (char *) alloca (strlen (err) + strlen (string) + 3);
+  strcpy (combined, string);
+  strcat (combined, ": ");
+  strcat (combined, err);
+
+  printf ("%s.\n", combined);
+}
+
+/* Control C eventually causes this to be called, at a convenient time.  */
+
+void
+quit ()
+{
+  target_terminal_ours ();
+#ifdef HAVE_TERMIO
+  ioctl (fileno (stdout), TCFLSH, 1);
+#else /* not HAVE_TERMIO */
+  ioctl (fileno (stdout), TIOCFLUSH, 0);
+#endif /* not HAVE_TERMIO */
+#ifdef TIOCGPGRP
+  error ("Quit");
+#else
+  error ("Quit (expect signal %d when inferior is resumed)", SIGINT);
+#endif /* TIOCGPGRP */
+}
+
+/* Control C comes here */
+
+void
+request_quit ()
+{
+  quit_flag = 1;
+
+#ifdef USG
+  /* Restore the signal handler.  */
+  signal (SIGINT, request_quit);
+#endif
+
+  if (immediate_quit)
+    quit ();
+}
+\f
+/* My replacement for the read system call.
+   Used like `read' but keeps going if `read' returns too soon.  */
+
+int
+myread (desc, addr, len)
+     int desc;
+     char *addr;
+     int len;
+{
+  register int val;
+  int orglen = len;
+
+  while (len > 0)
+    {
+      val = read (desc, addr, len);
+      if (val < 0)
+       return val;
+      if (val == 0)
+       return orglen - len;
+      len -= val;
+      addr += val;
+    }
+  return orglen;
+}
+\f
+/* Make a copy of the string at PTR with SIZE characters
+   (and add a null character at the end in the copy).
+   Uses malloc to get the space.  Returns the address of the copy.  */
+
+char *
+savestring (ptr, size)
+     char *ptr;
+     int size;
+{
+  register char *p = (char *) xmalloc (size + 1);
+  bcopy (ptr, p, size);
+  p[size] = 0;
+  return p;
+}
+
+char *
+strsave (ptr)
+     char *ptr;
+{
+  return savestring (ptr, strlen (ptr));
+}
+
+char *
+concat (s1, s2, s3)
+     char *s1, *s2, *s3;
+{
+  register int len = strlen (s1) + strlen (s2) + strlen (s3) + 1;
+  register char *val = (char *) xmalloc (len);
+  strcpy (val, s1);
+  strcat (val, s2);
+  strcat (val, s3);
+  return val;
+}
+
+void
+print_spaces (n, file)
+     register int n;
+     register FILE *file;
+{
+  while (n-- > 0)
+    fputc (' ', file);
+}
+
+/* Ask user a y-or-n question and return 1 iff answer is yes.
+   Takes three args which are given to printf to print the question.
+   The first, a control string, should end in "? ".
+   It should not say how to answer, because we do that.  */
+
+/* VARARGS */
+int
+query (va_alist)
+     va_dcl
+{
+  va_list args;
+  char *ctlstr;
+  register int answer;
+  register int ans2;
+
+  /* Automatically answer "yes" if input is not from a terminal.  */
+  if (!input_from_terminal_p ())
+    return 1;
+
+  while (1)
+    {
+      va_start (args);
+      ctlstr = va_arg (args, char *);
+      vfprintf (stdout, ctlstr, args);
+      va_end (args);
+      printf ("(y or n) ");
+      fflush (stdout);
+      answer = fgetc (stdin);
+      clearerr (stdin);                /* in case of C-d */
+      if (answer == EOF)       /* C-d */
+        return 1;
+      if (answer != '\n')      /* Eat rest of input line, to EOF or newline */
+       do 
+         {
+           ans2 = fgetc (stdin);
+           clearerr (stdin);
+         }
+        while (ans2 != EOF && ans2 != '\n');
+      if (answer >= 'a')
+       answer -= 040;
+      if (answer == 'Y')
+       return 1;
+      if (answer == 'N')
+       return 0;
+      printf ("Please answer y or n.\n");
+    }
+}
+\f
+/* Parse a C escape sequence.  STRING_PTR points to a variable
+   containing a pointer to the string to parse.  That pointer
+   should point to the character after the \.  That pointer
+   is updated past the characters we use.  The value of the
+   escape sequence is returned.
+
+   A negative value means the sequence \ newline was seen,
+   which is supposed to be equivalent to nothing at all.
+
+   If \ is followed by a null character, we return a negative
+   value and leave the string pointer pointing at the null character.
+
+   If \ is followed by 000, we return 0 and leave the string pointer
+   after the zeros.  A value of 0 does not mean end of string.  */
+
+int
+parse_escape (string_ptr)
+     char **string_ptr;
+{
+  register int c = *(*string_ptr)++;
+  switch (c)
+    {
+    case 'a':
+      return '\a';
+    case 'b':
+      return '\b';
+    case 'e':
+      return 033;
+    case 'f':
+      return '\f';
+    case 'n':
+      return '\n';
+    case 'r':
+      return '\r';
+    case 't':
+      return '\t';
+    case 'v':
+      return '\v';
+    case '\n':
+      return -2;
+    case 0:
+      (*string_ptr)--;
+      return 0;
+    case '^':
+      c = *(*string_ptr)++;
+      if (c == '\\')
+       c = parse_escape (string_ptr);
+      if (c == '?')
+       return 0177;
+      return (c & 0200) | (c & 037);
+      
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+    case '6':
+    case '7':
+      {
+       register int i = c - '0';
+       register int count = 0;
+       while (++count < 3)
+         {
+           if ((c = *(*string_ptr)++) >= '0' && c <= '7')
+             {
+               i *= 8;
+               i += c - '0';
+             }
+           else
+             {
+               (*string_ptr)--;
+               break;
+             }
+         }
+       return i;
+      }
+    default:
+      return c;
+    }
+}
+\f
+/* Print the character CH on STREAM as part of the contents
+   of a literal string whose delimiter is QUOTER.  */
+
+void
+printchar (ch, stream, quoter)
+     unsigned char ch;
+     FILE *stream;
+     int quoter;
+{
+  register int c = ch;
+
+  if (c < 040 || (sevenbit_strings && c >= 0177))
+    switch (c)
+      {
+      case '\n':
+       fputs_filtered ("\\n", stream);
+       break;
+      case '\b':
+       fputs_filtered ("\\b", stream);
+       break;
+      case '\t':
+       fputs_filtered ("\\t", stream);
+       break;
+      case '\f':
+       fputs_filtered ("\\f", stream);
+       break;
+      case '\r':
+       fputs_filtered ("\\r", stream);
+       break;
+      case '\033':
+       fputs_filtered ("\\e", stream);
+       break;
+      case '\007':
+       fputs_filtered ("\\a", stream);
+       break;
+      default:
+       fprintf_filtered (stream, "\\%.3o", (unsigned int) c);
+       break;
+      }
+  else
+    {
+      if (c == '\\' || c == quoter)
+       fputs_filtered ("\\", stream);
+      fprintf_filtered (stream, "%c", c);
+    }
+}
+\f
+/* Number of lines per page or UINT_MAX if paging is disabled.  */
+static unsigned int lines_per_page;
+/* Number of chars per line or UNIT_MAX is line folding is disabled.  */
+static unsigned int chars_per_line;
+/* Current count of lines printed on this page, chars on this line.  */
+static unsigned int lines_printed, chars_printed;
+
+/* Buffer and start column of buffered text, for doing smarter word-
+   wrapping.  When someone calls wrap_here(), we start buffering output
+   that comes through fputs_filtered().  If we see a newline, we just
+   spit it out and forget about the wrap_here().  If we see another
+   wrap_here(), we spit it out and remember the newer one.  If we see
+   the end of the line, we spit out a newline, the indent, and then
+   the buffered output.
+
+   wrap_column is the column number on the screen where wrap_buffer begins.
+     When wrap_column is zero, wrapping is not in effect.
+   wrap_buffer is malloc'd with chars_per_line+2 bytes. 
+     When wrap_buffer[0] is null, the buffer is empty.
+   wrap_pointer points into it at the next character to fill.
+   wrap_indent is the string that should be used as indentation if the
+     wrap occurs.  */
+
+static char *wrap_buffer, *wrap_pointer, *wrap_indent;
+static int wrap_column;
+
+/* Get the number of lines to print with commands like "list".
+   This is based on guessing how many long (i.e. more than chars_per_line
+   characters) lines there will be.  To be completely correct, "list"
+   and friends should be rewritten to count characters and see where
+   things are wrapping, but that would be a fair amount of work.  */
+int
+lines_to_list ()
+{
+  /* RMS didn't like the following algorithm.  Let's set it back to
+     10 and see if anyone else complains.  */
+  /* return lines_per_page == UINT_MAX ? 10 : lines_per_page / 2; */
+  return 10;
+}
+
+static void 
+set_width_command (args, from_tty, c)
+     char *args;
+     int from_tty;
+     struct cmd_list_element *c;
+{
+  if (!wrap_buffer)
+    {
+      wrap_buffer = (char *) xmalloc (chars_per_line + 2);
+      wrap_buffer[0] = '\0';
+    }
+  else
+    wrap_buffer = (char *) xrealloc (wrap_buffer, chars_per_line + 2);
+  wrap_pointer = wrap_buffer;  /* Start it at the beginning */
+}
+
+static void
+prompt_for_continue ()
+{
+  immediate_quit++;
+  gdb_readline ("---Type <return> to continue---", 0);
+  chars_printed = lines_printed = 0;
+  immediate_quit--;
+}
+
+/* Reinitialize filter; ie. tell it to reset to original values.  */
+
+void
+reinitialize_more_filter ()
+{
+  lines_printed = 0;
+  chars_printed = 0;
+}
+
+/* Indicate that if the next sequence of characters overflows the line,
+   a newline should be inserted here rather than when it hits the end. 
+   If INDENT is nonzero, it is a string to be printed to indent the
+   wrapped part on the next line.  INDENT must remain accessible until
+   the next call to wrap_here() or until a newline is printed through
+   fputs_filtered().
+
+   If the line is already overfull, we immediately print a newline and
+   the indentation, and disable further wrapping.
+
+   INDENT should not contain tabs, as that
+   will mess up the char count on the next line.  FIXME.  */
+
+void
+wrap_here(indent)
+  char *indent;
+{
+  if (wrap_buffer[0])
+    {
+      *wrap_pointer = '\0';
+      fputs (wrap_buffer, stdout);
+    }
+  wrap_pointer = wrap_buffer;
+  wrap_buffer[0] = '\0';
+  if (chars_printed >= chars_per_line)
+    {
+      puts_filtered ("\n");
+      puts_filtered (indent);
+      wrap_column = 0;
+    }
+  else
+    {
+      wrap_column = chars_printed;
+      wrap_indent = indent;
+    }
+}
+
+/* Like fputs but pause after every screenful, and can wrap at points
+   other than the final character of a line.
+   Unlike fputs, fputs_filtered does not return a value.
+   It is OK for LINEBUFFER to be NULL, in which case just don't print
+   anything.
+
+   Note that a longjmp to top level may occur in this routine
+   (since prompt_for_continue may do so) so this routine should not be
+   called when cleanups are not in place.  */
+
+void
+fputs_filtered (linebuffer, stream)
+     char *linebuffer;
+     FILE *stream;
+{
+  char *lineptr;
+
+  if (linebuffer == 0)
+    return;
+  
+  /* Don't do any filtering if it is disabled.  */
+  if (stream != stdout
+   || (lines_per_page == UINT_MAX && chars_per_line == UINT_MAX))
+    {
+      fputs (linebuffer, stream);
+      return;
+    }
+
+  /* Go through and output each character.  Show line extension
+     when this is necessary; prompt user for new page when this is
+     necessary.  */
+  
+  lineptr = linebuffer;
+  while (*lineptr)
+    {
+      /* Possible new page.  */
+      if (lines_printed >= lines_per_page - 1)
+       prompt_for_continue ();
+
+      while (*lineptr && *lineptr != '\n')
+       {
+         /* Print a single line.  */
+         if (*lineptr == '\t')
+           {
+             if (wrap_column)
+               *wrap_pointer++ = '\t';
+             else
+               putc ('\t', stream);
+             /* Shifting right by 3 produces the number of tab stops
+                we have already passed, and then adding one and
+                shifting left 3 advances to the next tab stop.  */
+             chars_printed = ((chars_printed >> 3) + 1) << 3;
+             lineptr++;
+           }
+         else
+           {
+             if (wrap_column)
+               *wrap_pointer++ = *lineptr;
+             else
+               putc (*lineptr, stream);
+             chars_printed++;
+             lineptr++;
+           }
+      
+         if (chars_printed >= chars_per_line)
+           {
+             unsigned int save_chars = chars_printed;
+
+             chars_printed = 0;
+             lines_printed++;
+             /* If we aren't actually wrapping, don't output newline --
+                if chars_per_line is right, we probably just overflowed
+                anyway; if it's wrong, let us keep going.  */
+             if (wrap_column)
+               putc ('\n', stream);
+
+             /* Possible new page.  */
+             if (lines_printed >= lines_per_page - 1)
+               prompt_for_continue ();
+
+             /* Now output indentation and wrapped string */
+             if (wrap_column)
+               {
+                 if (wrap_indent)
+                   fputs (wrap_indent, stream);
+                 *wrap_pointer = '\0';         /* Null-terminate saved stuff */
+                 fputs (wrap_buffer, stream);  /* and eject it */
+                 /* FIXME, this strlen is what prevents wrap_indent from
+                    containing tabs.  However, if we recurse to print it
+                    and count its chars, we risk trouble if wrap_indent is
+                    longer than (the user settable) chars_per_line. 
+                    Note also that this can set chars_printed > chars_per_line
+                    if we are printing a long string.  */
+                 chars_printed = strlen (wrap_indent)
+                               + (save_chars - wrap_column);
+                 wrap_pointer = wrap_buffer;   /* Reset buffer */
+                 wrap_buffer[0] = '\0';
+                 wrap_column = 0;              /* And disable fancy wrap */
+               }
+           }
+       }
+
+      if (*lineptr == '\n')
+       {
+         chars_printed = 0;
+         wrap_here ("");       /* Spit out chars, cancel further wraps */
+         lines_printed++;
+         putc ('\n', stream);
+         lineptr++;
+       }
+    }
+}
+
+
+/* fputs_demangled is a variant of fputs_filtered that
+   demangles g++ names.*/
+
+void
+fputs_demangled (linebuffer, stream, arg_mode)
+     char *linebuffer;
+     FILE *stream;
+     int arg_mode;
+{
+#ifdef __STDC__
+  extern char *cplus_demangle (const char *, int);
+#else
+  extern char *cplus_demangle ();
+#endif
+#define SYMBOL_MAX 1024
+
+#define SYMBOL_CHAR(c) (isascii(c) && (isalnum(c) || (c) == '_' || (c) == '$'))
+
+  char buf[SYMBOL_MAX+1];
+# define SLOP 5                /* How much room to leave in buf */
+  char *p;
+
+  if (linebuffer == NULL)
+    return;
+
+  /* If user wants to see raw output, no problem.  */
+  if (!demangle) {
+    fputs_filtered (linebuffer, stream);
+  }
+
+  p = linebuffer;
+
+  while ( *p != (char) 0 ) {
+    int i = 0;
+
+    /* collect non-interesting characters into buf */
+    while ( *p != (char) 0 && !SYMBOL_CHAR(*p) && i < (int)sizeof(buf)-SLOP ) {
+      buf[i++] = *p;
+      p++;
+    }
+    if (i > 0) {
+      /* output the non-interesting characters without demangling */
+      buf[i] = (char) 0;
+      fputs_filtered(buf, stream);
+      i = 0;  /* reset buf */
+    }
+
+    /* and now the interesting characters */
+    while (i < SYMBOL_MAX
+     && *p != (char) 0
+     && SYMBOL_CHAR(*p)
+     && i < (int)sizeof(buf) - SLOP) {
+      buf[i++] = *p;
+      p++;
+    }
+    buf[i] = (char) 0;
+    if (i > 0) {
+      char * result;
+      
+      if ( (result = cplus_demangle(buf, arg_mode)) != NULL ) {
+       fputs_filtered(result, stream);
+       free(result);
+      }
+      else {
+       fputs_filtered(buf, stream);
+      }
+    }
+  }
+}
+
+/* Print a variable number of ARGS using format FORMAT.  If this
+   information is going to put the amount written (since the last call
+   to INITIALIZE_MORE_FILTER or the last page break) over the page size,
+   print out a pause message and do a gdb_readline to get the users
+   permision to continue.
+
+   Unlike fprintf, this function does not return a value.
+
+   We implement three variants, vfprintf (takes a vararg list and stream),
+   fprintf (takes a stream to write on), and printf (the usual).
+
+   Note that this routine has a restriction that the length of the
+   final output line must be less than 255 characters *or* it must be
+   less than twice the size of the format string.  This is a very
+   arbitrary restriction, but it is an internal restriction, so I'll
+   put it in.  This means that the %s format specifier is almost
+   useless; unless the caller can GUARANTEE that the string is short
+   enough, fputs_filtered should be used instead.
+
+   Note also that a longjmp to top level may occur in this routine
+   (since prompt_for_continue may do so) so this routine should not be
+   called when cleanups are not in place.  */
+
+#if !defined(MISSING_VPRINTF) || defined (vsprintf)
+/* VARARGS */
+void
+vfprintf_filtered (stream, format, args)
+     va_list args;
+#else
+void fprintf_filtered (stream, format, arg1, arg2, arg3, arg4, arg5, arg6)
+#endif
+     FILE *stream;
+     char *format;
+{
+  static char *linebuffer = (char *) 0;
+  static int line_size;
+  int format_length;
+
+  format_length = strlen (format);
+
+  /* Allocated linebuffer for the first time.  */
+  if (!linebuffer)
+    {
+      linebuffer = (char *) xmalloc (255);
+      line_size = 255;
+    }
+
+  /* Reallocate buffer to a larger size if this is necessary.  */
+  if (format_length * 2 > line_size)
+    {
+      line_size = format_length * 2;
+
+      /* You don't have to copy.  */
+      free (linebuffer);
+      linebuffer = (char *) xmalloc (line_size);
+    }
+
+
+  /* This won't blow up if the restrictions described above are
+     followed.   */
+#if !defined(MISSING_VPRINTF) || defined (vsprintf)
+  (void) vsprintf (linebuffer, format, args);
+#else
+  (void) sprintf (linebuffer, format, arg1, arg2, arg3, arg4, arg5, arg6);
+#endif
+
+  fputs_filtered (linebuffer, stream);
+}
+
+#if !defined(MISSING_VPRINTF) || defined (vsprintf)
+/* VARARGS */
+void
+fprintf_filtered (va_alist)
+     va_dcl
+{
+  va_list args;
+  FILE *stream;
+  char *format;
+
+  va_start (args);
+  stream = va_arg (args, FILE *);
+  format = va_arg (args, char *);
+
+  /* This won't blow up if the restrictions described above are
+     followed.   */
+  (void) vfprintf_filtered (stream, format, args);
+  va_end (args);
+}
+
+/* VARARGS */
+void
+printf_filtered (va_alist)
+     va_dcl
+{
+  va_list args;
+  char *format;
+
+  va_start (args);
+  format = va_arg (args, char *);
+
+  (void) vfprintf_filtered (stdout, format, args);
+  va_end (args);
+}
+#else
+void
+printf_filtered (format, arg1, arg2, arg3, arg4, arg5, arg6)
+     char *format;
+     int arg1, arg2, arg3, arg4, arg5, arg6;
+{
+  fprintf_filtered (stdout, format, arg1, arg2, arg3, arg4, arg5, arg6);
+}
+#endif
+
+/* Easy */
+
+void
+puts_filtered (string)
+     char *string;
+{
+  fputs_filtered (string, stdout);
+}
+
+/* Return a pointer to N spaces and a null.  The pointer is good
+   until the next call to here.  */
+char *
+n_spaces (n)
+     int n;
+{
+  register char *t;
+  static char *spaces;
+  static int max_spaces;
+
+  if (n > max_spaces)
+    {
+      if (spaces)
+       free (spaces);
+      spaces = malloc (n+1);
+      for (t = spaces+n; t != spaces;)
+       *--t = ' ';
+      spaces[n] = '\0';
+      max_spaces = n;
+    }
+
+  return spaces + max_spaces - n;
+}
+
+/* Print N spaces.  */
+void
+print_spaces_filtered (n, stream)
+     int n;
+     FILE *stream;
+{
+  fputs_filtered (n_spaces (n), stream);
+}
+\f
+/* C++ demangler stuff.  */
+char *cplus_demangle ();
+
+/* Print NAME on STREAM, demangling if necessary.  */
+void
+fprint_symbol (stream, name)
+     FILE *stream;
+     char *name;
+{
+  char *demangled;
+  if ((!demangle) || NULL == (demangled = cplus_demangle (name, 1)))
+    fputs_filtered (name, stream);
+  else
+    {
+      fputs_filtered (demangled, stream);
+      free (demangled);
+    }
+}
+\f
+#if !defined (USG_UTILS)
+#define USG_UTILS defined (USG)
+#endif
+
+#if USG_UTILS
+bcopy (from, to, count)
+char *from, *to;
+{
+       memcpy (to, from, count);
+}
+
+bcmp (from, to, count)
+{
+       return (memcmp (to, from, count));
+}
+
+bzero (to, count)
+char *to;
+{
+       while (count--)
+               *to++ = 0;
+}
+
+getwd (buf)
+char *buf;
+{
+  getcwd (buf, MAXPATHLEN);
+}
+
+char *
+index (s, c)
+     char *s;
+{
+  char *strchr ();
+  return strchr (s, c);
+}
+
+char *
+rindex (s, c)
+     char *s;
+{
+  char *strrchr ();
+  return strrchr (s, c);
+}
+#endif /* USG_UTILS.  */
+
+#if !defined (QUEUE_MISSING)
+#define QUEUE_MISSING defined (USG)
+#endif
+
+#if QUEUE_MISSING
+/* Queue routines */
+
+struct queue {
+       struct queue *forw;
+       struct queue *back;
+};
+
+insque (item, after)
+struct queue *item;
+struct queue *after;
+{
+       item->forw = after->forw;
+       after->forw->back = item;
+
+       item->back = after;
+       after->forw = item;
+}
+
+remque (item)
+struct queue *item;
+{
+       item->forw->back = item->back;
+       item->back->forw = item->forw;
+}
+#endif /* QUEUE_MISSING */
+\f
+/* Simple implementation of strstr, since some implementations lack it. */
+char *
+strstr (in, find)
+     const char *in, *find;
+{
+  register char *p = in - 1;
+
+  while (0 != (p = strchr (p+1, *find))) {
+    if (strcmp (p, find))
+      return p;
+  }
+  return 0;
+}
+\f
+void
+_initialize_utils ()
+{
+  struct cmd_list_element *c;
+
+  c = add_set_cmd ("width", class_support, var_uinteger, 
+                 (char *)&chars_per_line,
+                 "Set number of characters gdb thinks are in a line.",
+                 &setlist);
+  add_show_from_set (c, &showlist);
+  c->function = set_width_command;
+
+  add_show_from_set
+    (add_set_cmd ("height", class_support,
+                 var_uinteger, (char *)&lines_per_page,
+                 "Set number of lines gdb thinks are in a page.", &setlist),
+     &showlist);
+  
+  /* These defaults will be used if we are unable to get the correct
+     values from termcap.  */
+  lines_per_page = 24;
+  chars_per_line = 80;
+  /* Initialize the screen height and width from termcap.  */
+  {
+    char *termtype = getenv ("TERM");
+
+    /* Positive means success, nonpositive means failure.  */
+    int status;
+
+    /* 2048 is large enough for all known terminals, according to the
+       GNU termcap manual.  */
+    char term_buffer[2048];
+
+    if (termtype)
+      {
+       status = tgetent (term_buffer, termtype);
+       if (status > 0)
+         {
+           int val;
+           
+           val = tgetnum ("li");
+           if (val >= 0)
+             lines_per_page = val;
+           else
+             /* The number of lines per page is not mentioned
+                in the terminal description.  This probably means
+                that paging is not useful (e.g. emacs shell window),
+                so disable paging.  */
+             lines_per_page = UINT_MAX;
+           
+           val = tgetnum ("co");
+           if (val >= 0)
+             chars_per_line = val;
+         }
+      }
+  }
+
+  set_width_command ((char *)NULL, 0, c);
+
+  add_show_from_set
+    (add_set_cmd ("demangle", class_support, var_boolean, 
+                 (char *)&demangle,
+               "Set demangling of encoded C++ names when displaying symbols.",
+                 &setlist),
+     &showlist);
+
+  add_show_from_set
+    (add_set_cmd ("sevenbit-strings", class_support, var_boolean, 
+                 (char *)&sevenbit_strings,
+   "Set printing of 8-bit characters in strings as \\nnn.",
+                 &setlist),
+     &showlist);
+
+  add_show_from_set
+    (add_set_cmd ("asm-demangle", class_support, var_boolean, 
+                 (char *)&asm_demangle,
+       "Set demangling of C++ names in disassembly listings.",
+                 &setlist),
+     &showlist);
+}
diff --git a/gdb/valarith.c b/gdb/valarith.c
new file mode 100644 (file)
index 0000000..6269def
--- /dev/null
@@ -0,0 +1,694 @@
+/* Perform arithmetic and other operations on values, for GDB.
+   Copyright (C) 1986, 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 "defs.h"
+#include "param.h"
+#include "value.h"
+#include "expression.h"
+#include "target.h"
+#include <string.h>
+
+\f
+value value_x_binop ();
+value value_subscripted_rvalue ();
+
+value
+value_add (arg1, arg2)
+       value arg1, arg2;
+{
+  register value val, valint, valptr;
+  register int len;
+
+  COERCE_ARRAY (arg1);
+  COERCE_ARRAY (arg2);
+
+  if ((TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_PTR
+       || TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_PTR)
+      &&
+      (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_INT
+       || TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_INT))
+    /* Exactly one argument is a pointer, and one is an integer.  */
+    {
+      if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_PTR)
+       {
+         valptr = arg1;
+         valint = arg2;
+       }
+      else
+       {
+         valptr = arg2;
+         valint = arg1;
+       }
+      len = TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (valptr)));
+      if (len == 0) len = 1;   /* For (void *) */
+      val = value_from_long (builtin_type_long,
+                            value_as_long (valptr)
+                            + (len * value_as_long (valint)));
+      VALUE_TYPE (val) = VALUE_TYPE (valptr);
+      return val;
+    }
+
+  return value_binop (arg1, arg2, BINOP_ADD);
+}
+
+value
+value_sub (arg1, arg2)
+       value arg1, arg2;
+{
+  register value val;
+
+  COERCE_ARRAY (arg1);
+  COERCE_ARRAY (arg2);
+
+  if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_PTR)
+    {
+      if (TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_INT)
+       {
+         /* pointer - integer.  */
+         val = value_from_long
+           (builtin_type_long,
+            value_as_long (arg1)
+            - (TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (arg1)))
+               * value_as_long (arg2)));
+         VALUE_TYPE (val) = VALUE_TYPE (arg1);
+         return val;
+       }
+      else if (VALUE_TYPE (arg1) == VALUE_TYPE (arg2))
+       {
+         /* pointer to <type x> - pointer to <type x>.  */
+         val = value_from_long
+           (builtin_type_long,
+            (value_as_long (arg1) - value_as_long (arg2))
+            / TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (arg1))));
+         return val;
+       }
+      else
+       {
+         error ("\
+First argument of `-' is a pointer and second argument is neither\n\
+an integer nor a pointer of the same type.");
+       }
+    }
+
+  return value_binop (arg1, arg2, BINOP_SUB);
+}
+
+/* Return the value of ARRAY[IDX].  */
+
+value
+value_subscript (array, idx)
+     value array, idx;
+{
+  if (TYPE_CODE (VALUE_TYPE (array)) == TYPE_CODE_ARRAY
+      && VALUE_LVAL (array) != lval_memory)
+    return value_subscripted_rvalue (array, idx);
+  else
+    return value_ind (value_add (array, idx));
+}
+
+/* Return the value of EXPR[IDX], expr an aggregate rvalue
+   (eg, a vector register).  This routine used to promote floats
+   to doubles, but no longer does.  */
+
+value
+value_subscripted_rvalue (array, idx)
+     value array, idx;
+{
+  struct type *elt_type = TYPE_TARGET_TYPE (VALUE_TYPE (array));
+  int elt_size = TYPE_LENGTH (elt_type);
+  int elt_offs = elt_size * value_as_long (idx);
+  value v;
+
+  if (elt_offs >= TYPE_LENGTH (VALUE_TYPE (array)))
+    error ("no such vector element");
+
+  v = allocate_value (elt_type);
+  bcopy (VALUE_CONTENTS (array) + elt_offs, VALUE_CONTENTS (v), elt_size);
+
+  if (VALUE_LVAL (array) == lval_internalvar)
+    VALUE_LVAL (v) = lval_internalvar_component;
+  else
+    VALUE_LVAL (v) = not_lval;
+  VALUE_ADDRESS (v) = VALUE_ADDRESS (array);
+  VALUE_OFFSET (v) = VALUE_OFFSET (array) + elt_offs;
+  VALUE_BITSIZE (v) = elt_size * 8;
+  return v;
+}
+\f
+/* Check to see if either argument is a structure.  This is called so
+   we know whether to go ahead with the normal binop or look for a 
+   user defined function instead.
+
+   For now, we do not overload the `=' operator.  */
+
+int
+binop_user_defined_p (op, arg1, arg2)
+     enum exp_opcode op;
+     value arg1, arg2;
+{
+  if (op == BINOP_ASSIGN)
+    return 0;
+  return (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_STRUCT
+         || TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_STRUCT
+         || (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_REF
+             && TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (arg1))) == TYPE_CODE_STRUCT)
+         || (TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_REF
+             && TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (arg2))) == TYPE_CODE_STRUCT));
+}
+
+/* Check to see if argument is a structure.  This is called so
+   we know whether to go ahead with the normal unop or look for a 
+   user defined function instead.
+
+   For now, we do not overload the `&' operator.  */
+
+int unop_user_defined_p (op, arg1)
+     enum exp_opcode op;
+     value arg1;
+{
+  if (op == UNOP_ADDR)
+    return 0;
+  return (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_STRUCT
+         || (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_REF
+             && TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (arg1))) == TYPE_CODE_STRUCT));
+}
+
+/* We know either arg1 or arg2 is a structure, so try to find the right
+   user defined function.  Create an argument vector that calls 
+   arg1.operator @ (arg1,arg2) and return that value (where '@' is any
+   binary operator which is legal for GNU C++).  */
+
+value
+value_x_binop (arg1, arg2, op, otherop)
+     value arg1, arg2;
+     enum exp_opcode op, otherop;
+{
+  value * argvec;
+  char *ptr;
+  char tstr[13];
+  int static_memfuncp;
+
+  COERCE_ENUM (arg1);
+  COERCE_ENUM (arg2);
+
+  /* now we know that what we have to do is construct our
+     arg vector and find the right function to call it with.  */
+
+  if (TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_STRUCT)
+    error ("Can't do that binary op on that type");  /* FIXME be explicit */
+
+  argvec = (value *) alloca (sizeof (value) * 4);
+  argvec[1] = value_addr (arg1);
+  argvec[2] = arg2;
+  argvec[3] = 0;
+
+  /* make the right function name up */  
+  strcpy(tstr, "operator__");
+  ptr = tstr+8;
+  switch (op)
+    {
+    case BINOP_ADD:    strcpy(ptr,"+"); break;
+    case BINOP_SUB:    strcpy(ptr,"-"); break;
+    case BINOP_MUL:    strcpy(ptr,"*"); break;
+    case BINOP_DIV:    strcpy(ptr,"/"); break;
+    case BINOP_REM:    strcpy(ptr,"%"); break;
+    case BINOP_LSH:    strcpy(ptr,"<<"); break;
+    case BINOP_RSH:    strcpy(ptr,">>"); break;
+    case BINOP_LOGAND: strcpy(ptr,"&"); break;
+    case BINOP_LOGIOR: strcpy(ptr,"|"); break;
+    case BINOP_LOGXOR: strcpy(ptr,"^"); break;
+    case BINOP_AND:    strcpy(ptr,"&&"); break;
+    case BINOP_OR:     strcpy(ptr,"||"); break;
+    case BINOP_MIN:    strcpy(ptr,"<?"); break;
+    case BINOP_MAX:    strcpy(ptr,">?"); break;
+    case BINOP_ASSIGN: strcpy(ptr,"="); break;
+    case BINOP_ASSIGN_MODIFY:  
+      switch (otherop)
+       {
+       case BINOP_ADD:      strcpy(ptr,"+="); break;
+       case BINOP_SUB:      strcpy(ptr,"-="); break;
+       case BINOP_MUL:      strcpy(ptr,"*="); break;
+       case BINOP_DIV:      strcpy(ptr,"/="); break;
+       case BINOP_REM:      strcpy(ptr,"%="); break;
+       case BINOP_LOGAND:   strcpy(ptr,"&="); break;
+       case BINOP_LOGIOR:   strcpy(ptr,"|="); break;
+       case BINOP_LOGXOR:   strcpy(ptr,"^="); break;
+       default:
+         error ("Invalid binary operation specified.");
+       }
+      break;
+    case BINOP_SUBSCRIPT: strcpy(ptr,"[]"); break;
+    case BINOP_EQUAL:    strcpy(ptr,"=="); break;
+    case BINOP_NOTEQUAL:  strcpy(ptr,"!="); break;
+    case BINOP_LESS:      strcpy(ptr,"<"); break;
+    case BINOP_GTR:       strcpy(ptr,">"); break;
+    case BINOP_GEQ:       strcpy(ptr,">="); break;
+    case BINOP_LEQ:       strcpy(ptr,"<="); break;
+    default:
+      error ("Invalid binary operation specified.");
+    }
+  argvec[0] = value_struct_elt (&arg1, argvec+1, tstr, &static_memfuncp, "structure");
+  if (argvec[0])
+    {
+      if (static_memfuncp)
+       {
+         argvec[1] = argvec[0];
+         argvec++;
+       }
+      return target_call_function (argvec[0], 2 - static_memfuncp, argvec + 1);
+    }
+  error ("member function %s not found", tstr);
+#ifdef lint
+  return target_call_function (argvec[0], 2 - static_memfuncp, argvec + 1);
+#endif
+}
+
+/* We know that arg1 is a structure, so try to find a unary user
+   defined operator that matches the operator in question.  
+   Create an argument vector that calls arg1.operator @ (arg1)
+   and return that value (where '@' is (almost) any unary operator which
+   is legal for GNU C++).  */
+
+value
+value_x_unop (arg1, op)
+     value arg1;
+     enum exp_opcode op;
+{
+  value * argvec;
+  char *ptr;
+  char tstr[13];
+  int static_memfuncp;
+
+  COERCE_ENUM (arg1);
+
+  /* now we know that what we have to do is construct our
+     arg vector and find the right function to call it with.  */
+
+  if (TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_STRUCT)
+    error ("Can't do that unary op on that type");  /* FIXME be explicit */
+
+  argvec = (value *) alloca (sizeof (value) * 3);
+  argvec[1] = value_addr (arg1);
+  argvec[2] = 0;
+
+  /* make the right function name up */  
+  strcpy(tstr,"operator__");
+  ptr = tstr+8;
+  switch (op)
+    {
+    case UNOP_PREINCREMENT:    strcpy(ptr,"++"); break;
+    case UNOP_PREDECREMENT:    strcpy(ptr,"++"); break;
+    case UNOP_POSTINCREMENT:   strcpy(ptr,"++"); break;
+    case UNOP_POSTDECREMENT:   strcpy(ptr,"++"); break;
+    case UNOP_ZEROP:   strcpy(ptr,"!"); break;
+    case UNOP_LOGNOT:  strcpy(ptr,"~"); break;
+    case UNOP_NEG:     strcpy(ptr,"-"); break;
+    default:
+      error ("Invalid binary operation specified.");
+    }
+  argvec[0] = value_struct_elt (&arg1, argvec+1, tstr, &static_memfuncp, "structure");
+  if (argvec[0])
+    {
+      if (static_memfuncp)
+       {
+         argvec[1] = argvec[0];
+         argvec++;
+       }
+      return target_call_function (argvec[0], 1 - static_memfuncp, argvec + 1);
+    }
+  error ("member function %s not found", tstr);
+  return 0;  /* For lint -- never reached */
+}
+\f
+/* Perform a binary operation on two integers or two floats.
+   Does not support addition and subtraction on pointers;
+   use value_add or value_sub if you want to handle those possibilities.  */
+
+value
+value_binop (arg1, arg2, op)
+     value arg1, arg2;
+     int op;
+{
+  register value val;
+
+  COERCE_ENUM (arg1);
+  COERCE_ENUM (arg2);
+
+  if ((TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_FLT
+       &&
+       TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_INT)
+      ||
+      (TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_FLT
+       &&
+       TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_INT))
+    error ("Argument to arithmetic operation not a number.");
+
+  if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_FLT
+      ||
+      TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_FLT)
+    {
+      double v1, v2, v;
+      v1 = value_as_double (arg1);
+      v2 = value_as_double (arg2);
+      switch (op)
+       {
+       case BINOP_ADD:
+         v = v1 + v2;
+         break;
+
+       case BINOP_SUB:
+         v = v1 - v2;
+         break;
+
+       case BINOP_MUL:
+         v = v1 * v2;
+         break;
+
+       case BINOP_DIV:
+         v = v1 / v2;
+         break;
+
+       default:
+         error ("Integer-only operation on floating point number.");
+       }
+
+      val = allocate_value (builtin_type_double);
+      SWAP_TARGET_AND_HOST (&v, sizeof (v));
+      *(double *) VALUE_CONTENTS_RAW (val) = v;
+    }
+  else
+    /* Integral operations here.  */
+    {
+      /* Should we promote to unsigned longest?  */
+      if ((TYPE_UNSIGNED (VALUE_TYPE (arg1))
+          || TYPE_UNSIGNED (VALUE_TYPE (arg2)))
+         && (TYPE_LENGTH (VALUE_TYPE (arg1)) >= sizeof (unsigned LONGEST)
+             || TYPE_LENGTH (VALUE_TYPE (arg1)) >= sizeof (unsigned LONGEST)))
+       {
+         unsigned LONGEST v1, v2, v;
+         v1 = (unsigned LONGEST) value_as_long (arg1);
+         v2 = (unsigned LONGEST) value_as_long (arg2);
+         
+         switch (op)
+           {
+           case BINOP_ADD:
+             v = v1 + v2;
+             break;
+             
+           case BINOP_SUB:
+             v = v1 - v2;
+             break;
+             
+           case BINOP_MUL:
+             v = v1 * v2;
+             break;
+             
+           case BINOP_DIV:
+             v = v1 / v2;
+             break;
+             
+           case BINOP_REM:
+             v = v1 % v2;
+             break;
+             
+           case BINOP_LSH:
+             v = v1 << v2;
+             break;
+             
+           case BINOP_RSH:
+             v = v1 >> v2;
+             break;
+             
+           case BINOP_LOGAND:
+             v = v1 & v2;
+             break;
+             
+           case BINOP_LOGIOR:
+             v = v1 | v2;
+             break;
+             
+           case BINOP_LOGXOR:
+             v = v1 ^ v2;
+             break;
+             
+           case BINOP_AND:
+             v = v1 && v2;
+             break;
+             
+           case BINOP_OR:
+             v = v1 || v2;
+             break;
+             
+           case BINOP_MIN:
+             v = v1 < v2 ? v1 : v2;
+             break;
+             
+           case BINOP_MAX:
+             v = v1 > v2 ? v1 : v2;
+             break;
+             
+           default:
+             error ("Invalid binary operation on numbers.");
+           }
+
+         val = allocate_value (BUILTIN_TYPE_UNSIGNED_LONGEST);
+         SWAP_TARGET_AND_HOST (&v, sizeof (v));
+         *(unsigned LONGEST *) VALUE_CONTENTS_RAW (val) = v;
+       }
+      else
+       {
+         LONGEST v1, v2, v;
+         v1 = value_as_long (arg1);
+         v2 = value_as_long (arg2);
+         
+         switch (op)
+           {
+           case BINOP_ADD:
+             v = v1 + v2;
+             break;
+             
+           case BINOP_SUB:
+             v = v1 - v2;
+             break;
+             
+           case BINOP_MUL:
+             v = v1 * v2;
+             break;
+             
+           case BINOP_DIV:
+             v = v1 / v2;
+             break;
+             
+           case BINOP_REM:
+             v = v1 % v2;
+             break;
+             
+           case BINOP_LSH:
+             v = v1 << v2;
+             break;
+             
+           case BINOP_RSH:
+             v = v1 >> v2;
+             break;
+             
+           case BINOP_LOGAND:
+             v = v1 & v2;
+             break;
+             
+           case BINOP_LOGIOR:
+             v = v1 | v2;
+             break;
+             
+           case BINOP_LOGXOR:
+             v = v1 ^ v2;
+             break;
+             
+           case BINOP_AND:
+             v = v1 && v2;
+             break;
+             
+           case BINOP_OR:
+             v = v1 || v2;
+             break;
+             
+           case BINOP_MIN:
+             v = v1 < v2 ? v1 : v2;
+             break;
+             
+           case BINOP_MAX:
+             v = v1 > v2 ? v1 : v2;
+             break;
+             
+           default:
+             error ("Invalid binary operation on numbers.");
+           }
+         
+         val = allocate_value (BUILTIN_TYPE_LONGEST);
+         SWAP_TARGET_AND_HOST (&v, sizeof (v));
+         *(LONGEST *) VALUE_CONTENTS_RAW (val) = v;
+       }
+    }
+
+  return val;
+}
+\f
+/* Simulate the C operator ! -- return 1 if ARG1 contains zeros.  */
+
+int
+value_zerop (arg1)
+     value arg1;
+{
+  register int len;
+  register char *p;
+
+  COERCE_ARRAY (arg1);
+
+  len = TYPE_LENGTH (VALUE_TYPE (arg1));
+  p = VALUE_CONTENTS (arg1);
+
+  while (--len >= 0)
+    {
+      if (*p++)
+       break;
+    }
+
+  return len < 0;
+}
+
+/* Simulate the C operator == by returning a 1
+   iff ARG1 and ARG2 have equal contents.  */
+
+int
+value_equal (arg1, arg2)
+     register value arg1, arg2;
+
+{
+  register int len;
+  register char *p1, *p2;
+  enum type_code code1;
+  enum type_code code2;
+
+  COERCE_ARRAY (arg1);
+  COERCE_ARRAY (arg2);
+
+  code1 = TYPE_CODE (VALUE_TYPE (arg1));
+  code2 = TYPE_CODE (VALUE_TYPE (arg2));
+
+  if (code1 == TYPE_CODE_INT && code2 == TYPE_CODE_INT)
+    return value_as_long (arg1) == value_as_long (arg2);
+  else if ((code1 == TYPE_CODE_FLT || code1 == TYPE_CODE_INT)
+          && (code2 == TYPE_CODE_FLT || code2 == TYPE_CODE_INT))
+    return value_as_double (arg1) == value_as_double (arg2);
+  else if ((code1 == TYPE_CODE_PTR && code2 == TYPE_CODE_INT)
+          || (code2 == TYPE_CODE_PTR && code1 == TYPE_CODE_INT))
+    return (char *) value_as_long (arg1) == (char *) value_as_long (arg2);
+  else if (code1 == code2
+          && ((len = TYPE_LENGTH (VALUE_TYPE (arg1)))
+              == TYPE_LENGTH (VALUE_TYPE (arg2))))
+    {
+      p1 = VALUE_CONTENTS (arg1);
+      p2 = VALUE_CONTENTS (arg2);
+      while (--len >= 0)
+       {
+         if (*p1++ != *p2++)
+           break;
+       }
+      return len < 0;
+    }
+  else
+    {
+      error ("Invalid type combination in equality test.");
+      return 0;  /* For lint -- never reached */
+    }
+}
+
+/* Simulate the C operator < by returning 1
+   iff ARG1's contents are less than ARG2's.  */
+
+int
+value_less (arg1, arg2)
+     register value arg1, arg2;
+{
+  register enum type_code code1;
+  register enum type_code code2;
+
+  COERCE_ARRAY (arg1);
+  COERCE_ARRAY (arg2);
+
+  code1 = TYPE_CODE (VALUE_TYPE (arg1));
+  code2 = TYPE_CODE (VALUE_TYPE (arg2));
+
+  if (code1 == TYPE_CODE_INT && code2 == TYPE_CODE_INT)
+    {
+      if (TYPE_UNSIGNED (VALUE_TYPE (arg1))
+       || TYPE_UNSIGNED (VALUE_TYPE (arg2)))
+       return (unsigned)value_as_long (arg1) < (unsigned)value_as_long (arg2);
+      else
+       return value_as_long (arg1) < value_as_long (arg2);
+    }
+  else if ((code1 == TYPE_CODE_FLT || code1 == TYPE_CODE_INT)
+          && (code2 == TYPE_CODE_FLT || code2 == TYPE_CODE_INT))
+    return value_as_double (arg1) < value_as_double (arg2);
+  else if ((code1 == TYPE_CODE_PTR || code1 == TYPE_CODE_INT)
+          && (code2 == TYPE_CODE_PTR || code2 == TYPE_CODE_INT))
+    {
+      /* FIXME, this assumes that host and target char *'s are the same! */
+      return (char *) value_as_long (arg1) < (char *) value_as_long (arg2);
+    }
+  else
+    {
+      error ("Invalid type combination in ordering comparison.");
+      return 0;
+    }
+}
+\f
+/* The unary operators - and ~.  Both free the argument ARG1.  */
+
+value
+value_neg (arg1)
+     register value arg1;
+{
+  register struct type *type;
+
+  COERCE_ENUM (arg1);
+
+  type = VALUE_TYPE (arg1);
+
+  if (TYPE_CODE (type) == TYPE_CODE_FLT)
+    return value_from_double (type, - value_as_double (arg1));
+  else if (TYPE_CODE (type) == TYPE_CODE_INT)
+    return value_from_long (type, - value_as_long (arg1));
+  else {
+    error ("Argument to negate operation not a number.");
+    return 0;  /* For lint -- never reached */
+  }
+}
+
+value
+value_lognot (arg1)
+     register value arg1;
+{
+  COERCE_ENUM (arg1);
+
+  if (TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_INT)
+    error ("Argument to complement operation not an integer.");
+
+  return value_from_long (VALUE_TYPE (arg1), ~ value_as_long (arg1));
+}
+\f
diff --git a/gdb/valops.c b/gdb/valops.c
new file mode 100644 (file)
index 0000000..8031471
--- /dev/null
@@ -0,0 +1,1478 @@
+/* Perform non-arithmetic operations on values, for GDB.
+   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.  */
+
+#include <stdio.h>
+#include "defs.h"
+#include "param.h"
+#include "symtab.h"
+#include "value.h"
+#include "frame.h"
+#include "inferior.h"
+#include "gdbcore.h"
+#include "target.h"
+
+#include <errno.h>
+
+/* Local functions.  */
+static value search_struct_field ();
+\f
+/* Cast value ARG2 to type TYPE and return as a value.
+   More general than a C cast: accepts any two types of the same length,
+   and if ARG2 is an lvalue it can be cast into anything at all.  */
+/* In C++, casts may change pointer representations.  */
+
+value
+value_cast (type, arg2)
+     struct type *type;
+     register value arg2;
+{
+  register enum type_code code1;
+  register enum type_code code2;
+  register int scalar;
+
+  /* Coerce arrays but not enums.  Enums will work as-is
+     and coercing them would cause an infinite recursion.  */
+  if (TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_ENUM)
+    COERCE_ARRAY (arg2);
+
+  code1 = TYPE_CODE (type);
+  code2 = TYPE_CODE (VALUE_TYPE (arg2));
+  scalar = (code2 == TYPE_CODE_INT || code2 == TYPE_CODE_FLT
+           || code2 == TYPE_CODE_ENUM);
+
+  if (code1 == TYPE_CODE_FLT && scalar)
+    return value_from_double (type, value_as_double (arg2));
+  else if ((code1 == TYPE_CODE_INT || code1 == TYPE_CODE_ENUM)
+          && (scalar || code2 == TYPE_CODE_PTR))
+    return value_from_long (type, value_as_long (arg2));
+  else if (TYPE_LENGTH (type) == TYPE_LENGTH (VALUE_TYPE (arg2)))
+    {
+      if (code1 == TYPE_CODE_PTR && code2 == TYPE_CODE_PTR)
+       {
+         /* Look in the type of the source to see if it contains the
+            type of the target as a superclass.  If so, we'll need to
+            offset the pointer rather than just change its type.  */
+         struct type *t1 = TYPE_TARGET_TYPE (type);
+         struct type *t2 = TYPE_TARGET_TYPE (VALUE_TYPE (arg2));
+         if (TYPE_CODE (t1) == TYPE_CODE_STRUCT
+             && TYPE_CODE (t2) == TYPE_CODE_STRUCT
+             && TYPE_NAME (t1) != 0) /* if name unknown, can't have supercl */
+           {
+             value v = search_struct_field (type_name_no_tag (t1),
+                                            value_ind (arg2), 0, t2);
+             if (v)
+               {
+                 v = value_addr (v);
+                 VALUE_TYPE (v) = type;
+                 return v;
+               }
+           }
+         /* No superclass found, just fall through to change ptr type.  */
+       }
+      VALUE_TYPE (arg2) = type;
+      return arg2;
+    }
+  else if (VALUE_LVAL (arg2) == lval_memory)
+    {
+      return value_at_lazy (type, VALUE_ADDRESS (arg2) + VALUE_OFFSET (arg2));
+    }
+  else
+    {
+      error ("Invalid cast.");
+      return 0;
+    }
+}
+
+/* Create a value of type TYPE that is zero, and return it.  */
+
+value
+value_zero (type, lv)
+     struct type *type;
+     enum lval_type lv;
+{
+  register value val = allocate_value (type);
+
+  bzero (VALUE_CONTENTS (val), TYPE_LENGTH (type));
+  VALUE_LVAL (val) = lv;
+
+  return val;
+}
+
+/* Return a value with type TYPE located at ADDR.  
+
+   Call value_at only if the data needs to be fetched immediately;
+   if we can be 'lazy' and defer the fetch, perhaps indefinately, call
+   value_at_lazy instead.  value_at_lazy simply records the address of
+   the data and sets the lazy-evaluation-required flag.  The lazy flag 
+   is tested in the VALUE_CONTENTS macro, which is used if and when 
+   the contents are actually required.  */
+
+value
+value_at (type, addr)
+     struct type *type;
+     CORE_ADDR addr;
+{
+  register value val = allocate_value (type);
+
+  read_memory (addr, VALUE_CONTENTS_RAW (val), TYPE_LENGTH (type));
+
+  VALUE_LVAL (val) = lval_memory;
+  VALUE_ADDRESS (val) = addr;
+
+  return val;
+}
+
+/* Return a lazy value with type TYPE located at ADDR (cf. value_at).  */
+
+value
+value_at_lazy (type, addr)
+     struct type *type;
+     CORE_ADDR addr;
+{
+  register value val = allocate_value (type);
+
+  VALUE_LVAL (val) = lval_memory;
+  VALUE_ADDRESS (val) = addr;
+  VALUE_LAZY (val) = 1;
+
+  return val;
+}
+
+/* Called only from the VALUE_CONTENTS macro, if the current data for
+   a variable needs to be loaded into VALUE_CONTENTS(VAL).  Fetches the
+   data from the user's process, and clears the lazy flag to indicate
+   that the data in the buffer is valid.
+
+   This function returns a value because it is used in the VALUE_CONTENTS
+   macro as part of an expression, where a void would not work.  The
+   value is ignored.  */
+
+int
+value_fetch_lazy (val)
+     register value val;
+{
+  CORE_ADDR addr = VALUE_ADDRESS (val) + VALUE_OFFSET (val);
+
+  read_memory (addr, VALUE_CONTENTS_RAW (val), 
+              TYPE_LENGTH (VALUE_TYPE (val)));
+  VALUE_LAZY (val) = 0;
+  return 0;
+}
+
+
+/* Store the contents of FROMVAL into the location of TOVAL.
+   Return a new value with the location of TOVAL and contents of FROMVAL.  */
+
+value
+value_assign (toval, fromval)
+     register value toval, fromval;
+{
+  register struct type *type = VALUE_TYPE (toval);
+  register value val;
+  char raw_buffer[MAX_REGISTER_RAW_SIZE];
+  char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE];
+  int use_buffer = 0;
+
+  COERCE_ARRAY (fromval);
+
+  if (VALUE_LVAL (toval) != lval_internalvar)
+    fromval = value_cast (type, fromval);
+
+  /* If TOVAL is a special machine register requiring conversion
+     of program values to a special raw format,
+     convert FROMVAL's contents now, with result in `raw_buffer',
+     and set USE_BUFFER to the number of bytes to write.  */
+
+  if (VALUE_REGNO (toval) >= 0
+      && REGISTER_CONVERTIBLE (VALUE_REGNO (toval)))
+    {
+      int regno = VALUE_REGNO (toval);
+      if (VALUE_TYPE (fromval) != REGISTER_VIRTUAL_TYPE (regno))
+       fromval = value_cast (REGISTER_VIRTUAL_TYPE (regno), fromval);
+      bcopy (VALUE_CONTENTS (fromval), virtual_buffer,
+            REGISTER_VIRTUAL_SIZE (regno));
+      target_convert_from_virtual (regno, virtual_buffer, raw_buffer);
+      use_buffer = REGISTER_RAW_SIZE (regno);
+    }
+
+  switch (VALUE_LVAL (toval))
+    {
+    case lval_internalvar:
+      set_internalvar (VALUE_INTERNALVAR (toval), fromval);
+      break;
+
+    case lval_internalvar_component:
+      set_internalvar_component (VALUE_INTERNALVAR (toval),
+                                VALUE_OFFSET (toval),
+                                VALUE_BITPOS (toval),
+                                VALUE_BITSIZE (toval),
+                                fromval);
+      break;
+
+    case lval_memory:
+      if (VALUE_BITSIZE (toval))
+       {
+         int v;                /* FIXME, this won't work for large bitfields */
+         read_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+                      &v, sizeof v);
+         modify_field (&v, (int) value_as_long (fromval),
+                       VALUE_BITPOS (toval), VALUE_BITSIZE (toval));
+         write_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+                       (char *)&v, sizeof v);
+       }
+      else if (use_buffer)
+       write_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+                     raw_buffer, use_buffer);
+      else
+       write_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+                     VALUE_CONTENTS (fromval), TYPE_LENGTH (type));
+      break;
+
+    case lval_register:
+      if (VALUE_BITSIZE (toval))
+       {
+         int v;
+
+         read_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+                              &v, sizeof v);
+         modify_field (&v, (int) value_as_long (fromval),
+                       VALUE_BITPOS (toval), VALUE_BITSIZE (toval));
+         write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+                               &v, sizeof v);
+       }
+      else if (use_buffer)
+       write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+                             raw_buffer, use_buffer);
+      else
+       write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval),
+                             VALUE_CONTENTS (fromval), TYPE_LENGTH (type));
+      break;
+
+    case lval_reg_frame_relative:
+      {
+       /* value is stored in a series of registers in the frame
+          specified by the structure.  Copy that value out, modify
+          it, and copy it back in.  */
+       int amount_to_copy = (VALUE_BITSIZE (toval) ? 1 : TYPE_LENGTH (type));
+       int reg_size = REGISTER_RAW_SIZE (VALUE_FRAME_REGNUM (toval));
+       int byte_offset = VALUE_OFFSET (toval) % reg_size;
+       int reg_offset = VALUE_OFFSET (toval) / reg_size;
+       int amount_copied;
+       char *buffer = (char *) alloca (amount_to_copy);
+       int regno;
+       FRAME frame;
+
+       /* Figure out which frame this is in currently.  */
+       for (frame = get_current_frame ();
+            frame && FRAME_FP (frame) != VALUE_FRAME (toval);
+            frame = get_prev_frame (frame))
+         ;
+
+       if (!frame)
+         error ("Value being assigned to is no longer active.");
+
+       amount_to_copy += (reg_size - amount_to_copy % reg_size);
+
+       /* Copy it out.  */
+       for ((regno = VALUE_FRAME_REGNUM (toval) + reg_offset,
+             amount_copied = 0);
+            amount_copied < amount_to_copy;
+            amount_copied += reg_size, regno++)
+         {
+           get_saved_register (buffer + amount_copied,
+                               (int *)NULL, (CORE_ADDR)NULL,
+                               frame, regno, (enum lval_type *)NULL);
+         }
+
+       /* Modify what needs to be modified.  */
+       if (VALUE_BITSIZE (toval))
+         modify_field (buffer + byte_offset,
+                       (int) value_as_long (fromval),
+                       VALUE_BITPOS (toval), VALUE_BITSIZE (toval));
+       else if (use_buffer)
+         bcopy (raw_buffer, buffer + byte_offset, use_buffer);
+       else
+         bcopy (VALUE_CONTENTS (fromval), buffer + byte_offset,
+                TYPE_LENGTH (type));
+
+       /* Copy it back.  */
+       for ((regno = VALUE_FRAME_REGNUM (toval) + reg_offset,
+             amount_copied = 0);
+            amount_copied < amount_to_copy;
+            amount_copied += reg_size, regno++)
+         {
+           enum lval_type lval;
+           CORE_ADDR addr;
+           int optim;
+
+           /* Just find out where to put it.  */
+           get_saved_register ((char *)NULL,
+                               &optim, &addr, frame, regno, &lval);
+           
+           if (optim)
+             error ("Attempt to assign to a value that was optimized out.");
+           if (lval == lval_memory)
+             write_memory (addr, buffer + amount_copied, reg_size);
+           else if (lval == lval_register)
+             write_register_bytes (addr, buffer + amount_copied, reg_size);
+           else
+             error ("Attempt to assign to an unmodifiable value.");
+         }
+      }
+      break;
+       
+
+    default:
+      error ("Left side of = operation is not an lvalue.");
+    }
+
+  /* Return a value just like TOVAL except with the contents of FROMVAL
+     (except in the case of the type if TOVAL is an internalvar).  */
+
+  if (VALUE_LVAL (toval) == lval_internalvar
+      || VALUE_LVAL (toval) == lval_internalvar_component)
+    {
+      type = VALUE_TYPE (fromval);
+    }
+
+  val = allocate_value (type);
+  bcopy (toval, val, VALUE_CONTENTS_RAW (val) - (char *) val);
+  bcopy (VALUE_CONTENTS (fromval), VALUE_CONTENTS_RAW (val), TYPE_LENGTH (type));
+  VALUE_TYPE (val) = type;
+  
+  return val;
+}
+
+/* Extend a value VAL to COUNT repetitions of its type.  */
+
+value
+value_repeat (arg1, count)
+     value arg1;
+     int count;
+{
+  register value val;
+
+  if (VALUE_LVAL (arg1) != lval_memory)
+    error ("Only values in memory can be extended with '@'.");
+  if (count < 1)
+    error ("Invalid number %d of repetitions.", count);
+
+  val = allocate_repeat_value (VALUE_TYPE (arg1), count);
+
+  read_memory (VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1),
+              VALUE_CONTENTS_RAW (val),
+              TYPE_LENGTH (VALUE_TYPE (val)) * count);
+  VALUE_LVAL (val) = lval_memory;
+  VALUE_ADDRESS (val) = VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1);
+
+  return val;
+}
+
+value
+value_of_variable (var)
+     struct symbol *var;
+{
+  value val;
+
+  val = read_var_value (var, (FRAME) 0);
+  if (val == 0)
+    error ("Address of symbol \"%s\" is unknown.", SYMBOL_NAME (var));
+  return val;
+}
+
+/* Given a value which is an array, return a value which is
+   a pointer to its first element.  */
+
+value
+value_coerce_array (arg1)
+     value arg1;
+{
+  register struct type *type;
+  register value val;
+
+  if (VALUE_LVAL (arg1) != lval_memory)
+    error ("Attempt to take address of value not located in memory.");
+
+  /* Get type of elements.  */
+  if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_ARRAY)
+    type = TYPE_TARGET_TYPE (VALUE_TYPE (arg1));
+  else
+    /* A phony array made by value_repeat.
+       Its type is the type of the elements, not an array type.  */
+    type = VALUE_TYPE (arg1);
+
+  /* Get the type of the result.  */
+  type = lookup_pointer_type (type);
+  val = value_from_long (builtin_type_long,
+                      (LONGEST) (VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1)));
+  VALUE_TYPE (val) = type;
+  return val;
+}
+
+/* Given a value which is a function, return a value which is a pointer
+   to it.  */
+
+value
+value_coerce_function (arg1)
+     value arg1;
+{
+  register struct type *type;
+  register value val;
+
+  if (VALUE_LVAL (arg1) != lval_memory)
+    error ("Attempt to take address of value not located in memory.");
+
+  /* Get the type of the result.  */
+  type = lookup_pointer_type (VALUE_TYPE (arg1));
+  val = value_from_long (builtin_type_long,
+               (LONGEST) (VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1)));
+  VALUE_TYPE (val) = type;
+  return val;
+}  
+
+/* Return a pointer value for the object for which ARG1 is the contents.  */
+
+value
+value_addr (arg1)
+     value arg1;
+{
+  register struct type *type;
+  register value val;
+
+  COERCE_REF(arg1);
+  /* Taking the address of an array is really a no-op
+     once the array is coerced to a pointer to its first element.  */
+  if (VALUE_REPEATED (arg1)
+      || TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_ARRAY)
+    return value_coerce_array (arg1);
+  if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_FUNC)
+    return value_coerce_function (arg1);
+
+  if (VALUE_LVAL (arg1) != lval_memory)
+    error ("Attempt to take address of value not located in memory.");
+
+  /* Get the type of the result.  */
+  type = lookup_pointer_type (VALUE_TYPE (arg1));
+  val = value_from_long (builtin_type_long,
+               (LONGEST) (VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1)));
+  VALUE_TYPE (val) = type;
+  return val;
+}
+
+/* Given a value of a pointer type, apply the C unary * operator to it.  */
+
+value
+value_ind (arg1)
+     value arg1;
+{
+  COERCE_ARRAY (arg1);
+
+  if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_MEMBER)
+    error ("not implemented: member types in value_ind");
+
+  /* Allow * on an integer so we can cast it to whatever we want.
+     This returns an int, which seems like the most C-like thing
+     to do.  "long long" variables are rare enough that
+     BUILTIN_TYPE_LONGEST would seem to be a mistake.  */
+  if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_INT)
+    return value_at (builtin_type_int,
+                    (CORE_ADDR) value_as_long (arg1));
+  else if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_PTR)
+    return value_at_lazy (TYPE_TARGET_TYPE (VALUE_TYPE (arg1)),
+                    (CORE_ADDR) value_as_long (arg1));
+  error ("Attempt to take contents of a non-pointer value.");
+  return 0;  /* For lint -- never reached */
+}
+\f
+/* Pushing small parts of stack frames.  */
+
+/* Push one word (the size of object that a register holds).  */
+
+CORE_ADDR
+push_word (sp, buffer)
+     CORE_ADDR sp;
+     REGISTER_TYPE buffer;
+{
+  register int len = sizeof (REGISTER_TYPE);
+
+#if 1 INNER_THAN 2
+  sp -= len;
+  write_memory (sp, (char *)&buffer, len);
+#else /* stack grows upward */
+  write_memory (sp, (char *)&buffer, len);
+  sp += len;
+#endif /* stack grows upward */
+
+  return sp;
+}
+
+/* Push LEN bytes with data at BUFFER.  */
+
+CORE_ADDR
+push_bytes (sp, buffer, len)
+     CORE_ADDR sp;
+     char *buffer;
+     int len;
+{
+#if 1 INNER_THAN 2
+  sp -= len;
+  write_memory (sp, buffer, len);
+#else /* stack grows upward */
+  write_memory (sp, buffer, len);
+  sp += len;
+#endif /* stack grows upward */
+
+  return sp;
+}
+
+/* Push onto the stack the specified value VALUE.  */
+
+CORE_ADDR
+value_push (sp, arg)
+     register CORE_ADDR sp;
+     value arg;
+{
+  register int len = TYPE_LENGTH (VALUE_TYPE (arg));
+
+#if 1 INNER_THAN 2
+  sp -= len;
+  write_memory (sp, VALUE_CONTENTS (arg), len);
+#else /* stack grows upward */
+  write_memory (sp, VALUE_CONTENTS (arg), len);
+  sp += len;
+#endif /* stack grows upward */
+
+  return sp;
+}
+
+/* Perform the standard coercions that are specified
+   for arguments to be passed to C functions.  */
+
+value
+value_arg_coerce (arg)
+     value arg;
+{
+  register struct type *type;
+
+  COERCE_ENUM (arg);
+
+  type = VALUE_TYPE (arg);
+
+  if (TYPE_CODE (type) == TYPE_CODE_INT
+      && TYPE_LENGTH (type) < sizeof (int))
+    return value_cast (builtin_type_int, arg);
+
+  if (type == builtin_type_float)
+    return value_cast (builtin_type_double, arg);
+
+  return arg;
+}
+
+/* Push the value ARG, first coercing it as an argument
+   to a C function.  */
+
+CORE_ADDR
+value_arg_push (sp, arg)
+     register CORE_ADDR sp;
+     value arg;
+{
+  return value_push (sp, value_arg_coerce (arg));
+}
+
+/* Determine a function's address and its return type from its value. 
+   Calls error() if the function is not valid for calling.  */
+
+CORE_ADDR
+find_function_addr (function, retval_type)
+     value function;
+     struct type **retval_type;
+{
+  register struct type *ftype = VALUE_TYPE (function);
+  register enum type_code code = TYPE_CODE (ftype);
+  struct type *value_type;
+  CORE_ADDR funaddr;
+
+  /* If it's a member function, just look at the function
+     part of it.  */
+
+  /* Determine address to call.  */
+  if (code == TYPE_CODE_FUNC || code == TYPE_CODE_METHOD)
+    {
+      funaddr = VALUE_ADDRESS (function);
+      value_type = TYPE_TARGET_TYPE (ftype);
+    }
+  else if (code == TYPE_CODE_PTR)
+    {
+      funaddr = value_as_long (function);
+      if (TYPE_CODE (TYPE_TARGET_TYPE (ftype)) == TYPE_CODE_FUNC
+         || TYPE_CODE (TYPE_TARGET_TYPE (ftype)) == TYPE_CODE_METHOD)
+       value_type = TYPE_TARGET_TYPE (TYPE_TARGET_TYPE (ftype));
+      else
+       value_type = builtin_type_int;
+    }
+  else if (code == TYPE_CODE_INT)
+    {
+      /* Handle the case of functions lacking debugging info.
+        Their values are characters since their addresses are char */
+      if (TYPE_LENGTH (ftype) == 1)
+       funaddr = value_as_long (value_addr (function));
+      else
+       /* Handle integer used as address of a function.  */
+       funaddr = value_as_long (function);
+
+      value_type = builtin_type_int;
+    }
+  else
+    error ("Invalid data type for function to be called.");
+
+  *retval_type = value_type;
+  return funaddr;
+}
+
+#if defined (CALL_DUMMY)
+/* All this stuff with a dummy frame may seem unnecessarily complicated
+   (why not just save registers in GDB?).  The purpose of pushing a dummy
+   frame which looks just like a real frame is so that if you call a
+   function and then hit a breakpoint (get a signal, etc), "backtrace"
+   will look right.  Whether the backtrace needs to actually show the
+   stack at the time the inferior function was called is debatable, but
+   it certainly needs to not display garbage.  So if you are contemplating
+   making dummy frames be different from normal frames, consider that.  */
+
+/* Perform a function call in the inferior.
+   ARGS is a vector of values of arguments (NARGS of them).
+   FUNCTION is a value, the function to be called.
+   Returns a value representing what the function returned.
+   May fail to return, if a breakpoint or signal is hit
+   during the execution of the function.  */
+
+value
+call_function_by_hand (function, nargs, args)
+     value function;
+     int nargs;
+     value *args;
+{
+  register CORE_ADDR sp;
+  register int i;
+  CORE_ADDR start_sp;
+  static REGISTER_TYPE dummy[] = CALL_DUMMY;
+  REGISTER_TYPE dummy1[sizeof dummy / sizeof (REGISTER_TYPE)];
+  CORE_ADDR old_sp;
+  struct type *value_type;
+  unsigned char struct_return;
+  CORE_ADDR struct_addr;
+  struct inferior_status inf_status;
+  struct cleanup *old_chain;
+  CORE_ADDR funaddr;
+  int using_gcc;
+
+  save_inferior_status (&inf_status, 1);
+  old_chain = make_cleanup (restore_inferior_status, &inf_status);
+
+  /* PUSH_DUMMY_FRAME is responsible for saving the inferior registers
+     (and POP_FRAME for restoring them).  (At least on most machines)
+     they are saved on the stack in the inferior.  */
+  PUSH_DUMMY_FRAME;
+
+  old_sp = sp = read_register (SP_REGNUM);
+
+#if 1 INNER_THAN 2             /* Stack grows down */
+  sp -= sizeof dummy;
+  start_sp = sp;
+#else                          /* Stack grows up */
+  start_sp = sp;
+  sp += sizeof dummy;
+#endif
+
+  funaddr = find_function_addr (function, &value_type);
+
+  {
+    struct block *b = block_for_pc (funaddr);
+    /* If compiled without -g, assume GCC.  */
+    using_gcc = b == NULL || BLOCK_GCC_COMPILED (b);
+  }
+
+  /* Are we returning a value using a structure return or a normal
+     value return? */
+
+  struct_return = using_struct_return (function, funaddr, value_type,
+                                      using_gcc);
+
+  /* Create a call sequence customized for this function
+     and the number of arguments for it.  */
+  bcopy (dummy, dummy1, sizeof dummy);
+  FIX_CALL_DUMMY (dummy1, start_sp, funaddr, nargs, args,
+                 value_type, using_gcc);
+
+#if CALL_DUMMY_LOCATION == ON_STACK
+  write_memory (start_sp, (char *)dummy1, sizeof dummy);
+
+#else /* Not on stack.  */
+#if CALL_DUMMY_LOCATION == BEFORE_TEXT_END
+  /* Convex Unix prohibits executing in the stack segment. */
+  /* Hope there is empty room at the top of the text segment. */
+  {
+    static checked = 0;
+    if (!checked)
+      for (start_sp = text_end - sizeof dummy; start_sp < text_end; ++start_sp)
+       if (read_memory_integer (start_sp, 1) != 0)
+         error ("text segment full -- no place to put call");
+    checked = 1;
+    sp = old_sp;
+    start_sp = text_end - sizeof dummy;
+    write_memory (start_sp, (char *)dummy1, sizeof dummy);
+  }
+#else /* After text_end.  */
+  {
+    int errcode;
+    sp = old_sp;
+    start_sp = text_end;
+    errcode = target_write_memory (start_sp, (char *)dummy1, sizeof dummy);
+    if (errcode != 0)
+      error ("Cannot write text segment -- call_function failed");
+  }
+#endif /* After text_end.  */
+#endif /* Not on stack.  */
+
+#ifdef lint
+  sp = old_sp;         /* It really is used, for some ifdef's... */
+#endif
+
+#ifdef STACK_ALIGN
+  /* If stack grows down, we must leave a hole at the top. */
+  {
+    int len = 0;
+
+    /* Reserve space for the return structure to be written on the
+       stack, if necessary */
+
+    if (struct_return)
+      len += TYPE_LENGTH (value_type);
+    
+    for (i = nargs - 1; i >= 0; i--)
+      len += TYPE_LENGTH (VALUE_TYPE (value_arg_coerce (args[i])));
+#ifdef CALL_DUMMY_STACK_ADJUST
+    len += CALL_DUMMY_STACK_ADJUST;
+#endif
+#if 1 INNER_THAN 2
+    sp -= STACK_ALIGN (len) - len;
+#else
+    sp += STACK_ALIGN (len) - len;
+#endif
+  }
+#endif /* STACK_ALIGN */
+
+    /* Reserve space for the return structure to be written on the
+       stack, if necessary */
+
+    if (struct_return)
+      {
+#if 1 INNER_THAN 2
+       sp -= TYPE_LENGTH (value_type);
+       struct_addr = sp;
+#else
+       struct_addr = sp;
+       sp += TYPE_LENGTH (value_type);
+#endif
+      }
+
+#if defined (REG_STRUCT_HAS_ADDR)
+  {
+    /* This is a machine like the sparc, where we need to pass a pointer
+       to the structure, not the structure itself.  */
+    if (REG_STRUCT_HAS_ADDR (using_gcc))
+      for (i = nargs - 1; i >= 0; i--)
+       if (TYPE_CODE (VALUE_TYPE (args[i])) == TYPE_CODE_STRUCT)
+         {
+           CORE_ADDR addr;
+#if !(1 INNER_THAN 2)
+           /* The stack grows up, so the address of the thing we push
+              is the stack pointer before we push it.  */
+           addr = sp;
+#endif
+           /* Push the structure.  */
+           sp = value_push (sp, args[i]);
+#if 1 INNER_THAN 2
+           /* The stack grows down, so the address of the thing we push
+              is the stack pointer after we push it.  */
+           addr = sp;
+#endif
+           /* The value we're going to pass is the address of the thing
+              we just pushed.  */
+           args[i] = value_from_long (builtin_type_long, (LONGEST) addr);
+         }
+  }
+#endif /* REG_STRUCT_HAS_ADDR.  */
+
+#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]);
+#endif /* !PUSH_ARGUMENTS */
+
+#ifdef CALL_DUMMY_STACK_ADJUST
+#if 1 INNER_THAN 2
+  sp -= CALL_DUMMY_STACK_ADJUST;
+#else
+  sp += CALL_DUMMY_STACK_ADJUST;
+#endif
+#endif /* CALL_DUMMY_STACK_ADJUST */
+
+  /* Store the address at which the structure is supposed to be
+     written.  Note that this (and the code which reserved the space
+     above) assumes that gcc was used to compile this function.  Since
+     it doesn't cost us anything but space and if the function is pcc
+     it will ignore this value, we will make that assumption.
+
+     Also note that on some machines (like the sparc) pcc uses a 
+     convention like gcc's.  */
+
+  if (struct_return)
+    STORE_STRUCT_RETURN (struct_addr, sp);
+
+  /* Write the stack pointer.  This is here because the statements above
+     might fool with it.  On SPARC, this write also stores the register
+     window into the right place in the new stack frame, which otherwise
+     wouldn't happen.  (See write_inferior_registers in sparc-xdep.c.)  */
+  write_register (SP_REGNUM, sp);
+
+  /* Figure out the value returned by the function.  */
+  {
+    char retbuf[REGISTER_BYTES];
+
+    /* Execute the stack dummy routine, calling FUNCTION.
+       When it is done, discard the empty frame
+       after storing the contents of all regs into retbuf.  */
+    run_stack_dummy (start_sp + CALL_DUMMY_START_OFFSET, retbuf);
+
+    do_cleanups (old_chain);
+
+    return value_being_returned (value_type, retbuf, struct_return);
+  }
+}
+#else /* no CALL_DUMMY.  */
+value
+call_function_by_hand (function, nargs, args)
+     value function;
+     int nargs;
+     value *args;
+{
+  error ("Cannot invoke functions on this machine.");
+}
+#endif /* no CALL_DUMMY.  */
+\f
+/* Create a value for a string constant:
+   Call the function malloc in the inferior to get space for it,
+   then copy the data into that space
+   and then return the address with type char *.
+   PTR points to the string constant data; LEN is number of characters.  */
+
+value
+value_string (ptr, len)
+     char *ptr;
+     int len;
+{
+  register value val;
+  register struct symbol *sym;
+  value blocklen;
+  register char *copy = (char *) alloca (len + 1);
+  char *i = ptr;
+  register char *o = copy, *ibeg = ptr;
+  register int c;
+
+  /* Copy the string into COPY, processing escapes.
+     We could not conveniently process them in expread
+     because the string there wants to be a substring of the input.  */
+
+  while (i - ibeg < len)
+    {
+      c = *i++;
+      if (c == '\\')
+       {
+         c = parse_escape (&i);
+         if (c == -1)
+           continue;
+       }
+      *o++ = c;
+    }
+  *o = 0;
+
+  /* Get the length of the string after escapes are processed.  */
+
+  len = o - copy;
+
+  /* Find the address of malloc in the inferior.  */
+
+  sym = lookup_symbol ("malloc", 0, VAR_NAMESPACE, 0, NULL);
+  if (sym != 0)
+    {
+      if (SYMBOL_CLASS (sym) != LOC_BLOCK)
+       error ("\"malloc\" exists in this program but is not a function.");
+      val = value_of_variable (sym);
+    }
+  else
+    {
+      register int j;
+      for (j = 0; j < misc_function_count; j++)
+       if (!strcmp (misc_function_vector[j].name, "malloc"))
+         break;
+      if (j < misc_function_count)
+       val = value_from_long (builtin_type_long,
+                            (LONGEST) misc_function_vector[j].address);
+      else
+       error ("String constants require the program to have a function \"malloc\".");
+    }
+
+  blocklen = value_from_long (builtin_type_int, (LONGEST) (len + 1));
+  val = target_call_function (val, 1, &blocklen);
+  if (value_zerop (val))
+    error ("No memory available for string constant.");
+  write_memory ((CORE_ADDR) value_as_long (val), copy, len + 1);
+  VALUE_TYPE (val) = lookup_pointer_type (builtin_type_char);
+  return val;
+}
+\f
+/* Helper function used by value_struct_elt to recurse through baseclasses.
+   Look for a field NAME in ARG1. Adjust the address of ARG1 by OFFSET bytes,
+   and treat the result as having type TYPE.
+   If found, return value, else return NULL. */
+
+static value
+search_struct_field (name, arg1, offset, type)
+     char *name;
+     register value arg1;
+     int offset;
+     register struct type *type;
+{
+  int i;
+
+  check_stub_type (type);
+
+  for (i = TYPE_NFIELDS (type) - 1; i >= TYPE_N_BASECLASSES (type); i--)
+    {
+      char *t_field_name = TYPE_FIELD_NAME (type, i);
+      if (t_field_name && !strcmp (t_field_name, name))
+         return TYPE_FIELD_STATIC (type, i)
+             ? value_static_field (type, name, i)
+             : value_primitive_field (arg1, offset, i, type);
+    }
+
+  for (i = TYPE_N_BASECLASSES (type) - 1; i >= 0; i--)
+    {
+      value v;
+      /* If we are looking for baseclasses, this is what we get when we
+        hit them.  */
+      int found_baseclass = !strcmp (name, TYPE_BASECLASS_NAME (type, i));
+
+      if (BASETYPE_VIA_VIRTUAL (type, i))
+       {
+         value v2;
+         baseclass_addr (type, i, VALUE_CONTENTS (arg1) + offset, &v2);
+         if (v2 == 0)
+           error ("virtual baseclass botch");
+         if (found_baseclass)
+           return v2;
+         v = search_struct_field (name, v2, 0, TYPE_BASECLASS (type, i));
+         if (v) return v;
+         else continue;
+       }
+      if (found_baseclass)
+       v = value_primitive_field (arg1, offset, i, type);
+      else
+       v = search_struct_field (name, arg1,
+                                offset + TYPE_BASECLASS_BITPOS (type, i) / 8,
+                                TYPE_BASECLASS (type, i));
+      if (v) return v;
+    }
+  return NULL;
+}
+
+/* Helper function used by value_struct_elt to recurse through baseclasses.
+   Look for a field NAME in ARG1. Adjust the address of ARG1 by OFFSET bytes,
+   and treat the result as having type TYPE.
+   If found, return value, else return NULL. */
+
+static value
+search_struct_method (name, arg1, args, offset, static_memfuncp, type)
+     char *name;
+     register value arg1, *args;
+     int offset, *static_memfuncp;
+     register struct type *type;
+{
+  int i;
+
+  check_stub_type (type);
+  for (i = TYPE_NFN_FIELDS (type) - 1; i >= 0; i--)
+    {
+      char *t_field_name = TYPE_FN_FIELDLIST_NAME (type, i);
+      if (t_field_name && !strcmp (t_field_name, name))
+       {
+         int j;
+         struct fn_field *f = TYPE_FN_FIELDLIST1 (type, i);
+
+         for (j = TYPE_FN_FIELDLIST_LENGTH (type, i) - 1; j >= 0; --j)
+           {
+             if (TYPE_FLAGS (TYPE_FN_FIELD_TYPE (f, j)) & TYPE_FLAG_STUB)
+               check_stub_method (type, i, j);
+             if (!typecmp (TYPE_FN_FIELD_STATIC_P (f, j),
+                           TYPE_FN_FIELD_ARGS (f, j), args))
+               {
+                 if (TYPE_FN_FIELD_VIRTUAL_P (f, j))
+                   return (value)value_virtual_fn_field (arg1, f, j);
+                 if (TYPE_FN_FIELD_STATIC_P (f, j) && static_memfuncp)
+                   *static_memfuncp = 1;
+                 return (value)value_fn_field (arg1, i, j);
+               }
+           }
+       }
+    }
+
+  for (i = TYPE_N_BASECLASSES (type) - 1; i >= 0; i--)
+    {
+      value v;
+
+      if (BASETYPE_VIA_VIRTUAL (type, i))
+       {
+         value v2;
+         baseclass_addr (type, i, VALUE_CONTENTS (arg1) + offset, &v2);
+         if (v2 == 0)
+           error ("virtual baseclass botch");
+         v = search_struct_method (name, v2, args, 0,
+                                   static_memfuncp, TYPE_BASECLASS (type, i));
+         if (v) return v;
+         else continue;
+       }
+
+      v = search_struct_method (name, arg1, args,
+                               TYPE_BASECLASS_BITPOS (type, i) / 8,
+                               static_memfuncp, TYPE_BASECLASS (type, i));
+      if (v) return v;
+    }
+  return NULL;
+}
+
+/* Given *ARGP, a value of type (pointer to a)* structure/union,
+   extract the component named NAME from the ultimate target structure/union
+   and return it as a value with its appropriate type.
+   ERR is used in the error message if *ARGP's type is wrong.
+
+   C++: ARGS is a list of argument types to aid in the selection of
+   an appropriate method. Also, handle derived types.
+
+   STATIC_MEMFUNCP, if non-NULL, points to a caller-supplied location
+   where the truthvalue of whether the function that was resolved was
+   a static member function or not is stored.
+
+   ERR is an error message to be printed in case the field is not found.  */
+
+value
+value_struct_elt (argp, args, name, static_memfuncp, err)
+     register value *argp, *args;
+     char *name;
+     int *static_memfuncp;
+     char *err;
+{
+  register struct type *t;
+  int found = 0;       /* FIXME, half the time this doesn't get set */
+  value arg1_as_ptr = *argp;   /* FIXME, set but not used! */
+  value v;
+
+  COERCE_ARRAY (*argp);
+
+  t = VALUE_TYPE (*argp);
+
+  /* Follow pointers until we get to a non-pointer.  */
+
+  while (TYPE_CODE (t) == TYPE_CODE_PTR || TYPE_CODE (t) == TYPE_CODE_REF)
+    {
+      arg1_as_ptr = *argp;
+      *argp = value_ind (*argp);
+      COERCE_ARRAY (*argp);
+      t = VALUE_TYPE (*argp);
+    }
+
+  if (TYPE_CODE (t) == TYPE_CODE_MEMBER)
+    error ("not implemented: member type in value_struct_elt");
+
+  if (TYPE_CODE (t) != TYPE_CODE_STRUCT
+      && TYPE_CODE (t) != TYPE_CODE_UNION)
+    error ("Attempt to extract a component of a value that is not a %s.", err);
+
+  /* Assume it's not, unless we see that it is.  */
+  if (static_memfuncp)
+    *static_memfuncp =0;
+
+  if (!args)
+    {
+      /* if there are no arguments ...do this...  */
+
+      /* Try as a variable first, because if we succeed, there
+        is less work to be done.  */
+      v = search_struct_field (name, *argp, 0, t);
+      if (v)
+       return v;
+
+      /* C++: If it was not found as a data field, then try to
+         return it as a pointer to a method.  */
+
+      if (destructor_name_p (name, t))
+       error ("Cannot get value of destructor");
+
+      v = search_struct_method (name, *argp, args, 0, static_memfuncp, t);
+
+      if (v == 0)
+       {
+         if (TYPE_NFN_FIELDS (t))
+           error ("There is no member or method named %s.", name);
+         else
+           error ("There is no member named %s.", name);
+       }
+      return v;
+    }
+
+  if (destructor_name_p (name, t))
+    {
+      if (!args[1])
+       {
+         /* destructors are a special case.  */
+         return (value)value_fn_field (*argp, 0,
+                                       TYPE_FN_FIELDLIST_LENGTH (t, 0));
+       }
+      else
+       {
+         error ("destructor should not have any argument");
+       }
+    }
+  else
+    v = search_struct_method (name, *argp, args, 0, static_memfuncp, t);
+
+  if (v == 0)
+    {
+      /* See if user tried to invoke data as function.  If so,
+        hand it back.  If it's not callable (i.e., a pointer to function),
+        gdb should give an error.  */
+      v = search_struct_field (name, *argp, 0, t);
+    }
+
+  if (!v)
+    error ("Structure has no component named %s.", name);
+  return v;
+}
+
+/* C++: return 1 is NAME is a legitimate name for the destructor
+   of type TYPE.  If TYPE does not have a destructor, or
+   if NAME is inappropriate for TYPE, an error is signaled.  */
+int
+destructor_name_p (name, type)
+     char *name;
+     struct type *type;
+{
+  /* destructors are a special case.  */
+
+  if (name[0] == '~')
+    {
+      char *dname = type_name_no_tag (type);
+
+      if (! TYPE_HAS_DESTRUCTOR (type))
+       error ("type `%s' does not have destructor defined", dname);
+      if (strcmp (dname, name+1))
+       error ("name of destructor must equal name of class");
+      else
+       return 1;
+    }
+  return 0;
+}
+
+/* Helper function for check_field: Given TYPE, a structure/union,
+   return 1 if the component named NAME from the ultimate
+   target structure/union is defined, otherwise, return 0. */
+
+static int
+check_field_in (type, name)
+     register struct type *type;
+     char *name;
+{
+  register int i;
+
+  for (i = TYPE_NFIELDS (type) - 1; i >= TYPE_N_BASECLASSES (type); i--)
+    {
+      char *t_field_name = TYPE_FIELD_NAME (type, i);
+      if (t_field_name && !strcmp (t_field_name, name))
+       return 1;
+    }
+
+  /* C++: If it was not found as a data field, then try to
+     return it as a pointer to a method.  */
+
+  /* Destructors are a special case.  */
+  if (destructor_name_p (name, type))
+    return 1;
+
+  for (i = TYPE_NFN_FIELDS (type) - 1; i >= 0; --i)
+    {
+      if (!strcmp (TYPE_FN_FIELDLIST_NAME (type, i), name))
+       return 1;
+    }
+
+  for (i = TYPE_N_BASECLASSES (type) - 1; i >= 0; i--)
+    if (check_field_in (TYPE_BASECLASS (type, i), name))
+      return 1;
+      
+  return 0;
+}
+
+
+/* C++: Given ARG1, a value of type (pointer to a)* structure/union,
+   return 1 if the component named NAME from the ultimate
+   target structure/union is defined, otherwise, return 0.  */
+
+int
+check_field (arg1, name)
+     register value arg1;
+     char *name;
+{
+  register struct type *t;
+
+  COERCE_ARRAY (arg1);
+
+  t = VALUE_TYPE (arg1);
+
+  /* Follow pointers until we get to a non-pointer.  */
+
+  while (TYPE_CODE (t) == TYPE_CODE_PTR || TYPE_CODE (t) == TYPE_CODE_REF)
+    t = TYPE_TARGET_TYPE (t);
+
+  if (TYPE_CODE (t) == TYPE_CODE_MEMBER)
+    error ("not implemented: member type in check_field");
+
+  if (TYPE_CODE (t) != TYPE_CODE_STRUCT
+      && TYPE_CODE (t) != TYPE_CODE_UNION)
+    error ("Internal error: `this' is not an aggregate");
+
+  return check_field_in (t, name);
+}
+
+/* C++: Given an aggregate type DOMAIN, and a member name NAME,
+   return the address of this member as a pointer to member
+   type.  If INTYPE is non-null, then it will be the type
+   of the member we are looking for.  This will help us resolve
+   pointers to member functions.  */
+
+value
+value_struct_elt_for_address (domain, intype, name)
+     struct type *domain, *intype;
+     char *name;
+{
+  register struct type *t = domain;
+  register int i;
+  value v;
+
+  struct type *baseclass;
+
+  if (TYPE_CODE (t) != TYPE_CODE_STRUCT
+      && TYPE_CODE (t) != TYPE_CODE_UNION)
+    error ("Internal error: non-aggregate type to value_struct_elt_for_address");
+
+  baseclass = t;
+
+  while (t)
+    {
+      for (i = TYPE_NFIELDS (t) - 1; i >= TYPE_N_BASECLASSES (t); i--)
+       {
+         char *t_field_name = TYPE_FIELD_NAME (t, i);
+         if (t_field_name && !strcmp (t_field_name, name))
+           {
+             if (TYPE_FIELD_STATIC (t, i))
+               {
+                 char *phys_name = TYPE_FIELD_STATIC_PHYSNAME (t, i);
+                 struct symbol *sym =
+                     lookup_symbol (phys_name, 0, VAR_NAMESPACE, 0, NULL);
+                 if (! sym) error ("Internal error: could not find physical static variable named %s", phys_name);
+                 v = value_from_long(builtin_type_long,
+                                     (CORE_ADDR)SYMBOL_BLOCK_VALUE (sym));
+                 VALUE_TYPE(v) = lookup_pointer_type (TYPE_FIELD_TYPE (t, i));
+                 return v;
+               }
+             if (TYPE_FIELD_PACKED (t, i))
+               error ("pointers to bitfield members not allowed");
+
+             v = value_from_long (builtin_type_int,
+                                  (LONGEST) (TYPE_FIELD_BITPOS (t, i) >> 3));
+             VALUE_TYPE (v)
+               = lookup_pointer_type (lookup_member_type (TYPE_FIELD_TYPE (t, i), baseclass));
+             return v;
+           }
+       }
+
+      if (TYPE_N_BASECLASSES (t) == 0)
+       break;
+
+      t = TYPE_BASECLASS (t, 0);
+    }
+
+  /* C++: If it was not found as a data field, then try to
+     return it as a pointer to a method.  */
+  t = baseclass;
+
+  /* Destructors are a special case.  */
+  if (destructor_name_p (name, t))
+    {
+      error ("pointers to destructors not implemented yet");
+    }
+
+  /* Perform all necessary dereferencing.  */
+  while (intype && TYPE_CODE (intype) == TYPE_CODE_PTR)
+    intype = TYPE_TARGET_TYPE (intype);
+
+  while (t)
+    {
+      for (i = TYPE_NFN_FIELDS (t) - 1; i >= 0; --i)
+       {
+         if (!strcmp (TYPE_FN_FIELDLIST_NAME (t, i), name))
+           {
+             int j = TYPE_FN_FIELDLIST_LENGTH (t, i);
+             struct fn_field *f = TYPE_FN_FIELDLIST1 (t, i);
+
+             if (intype == 0 && j > 1)
+               error ("non-unique member `%s' requires type instantiation", name);
+             if (intype)
+               {
+                 while (j--)
+                   if (TYPE_FN_FIELD_TYPE (f, j) == intype)
+                     break;
+                 if (j < 0)
+                   error ("no member function matches that type instantiation");
+               }
+             else
+               j = 0;
+
+             if (TYPE_FN_FIELD_VIRTUAL_P (f, j))
+               {
+                 v = value_from_long (builtin_type_long,
+                                      (LONGEST) TYPE_FN_FIELD_VOFFSET (f, j));
+               }
+             else
+               {
+                 struct symbol *s = lookup_symbol (TYPE_FN_FIELD_PHYSNAME (f, j),
+                                                   0, VAR_NAMESPACE, 0, NULL);
+                 v = locate_var_value (s, 0);
+               }
+             VALUE_TYPE (v) = lookup_pointer_type (lookup_member_type (TYPE_FN_FIELD_TYPE (f, j), baseclass));
+             return v;
+           }
+       }
+
+      if (TYPE_N_BASECLASSES (t) == 0)
+       break;
+
+      t = TYPE_BASECLASS (t, 0);
+    }
+  return 0;
+}
+
+/* Compare two argument lists and return the position in which they differ,
+   or zero if equal.
+
+   STATICP is nonzero if the T1 argument list came from a
+   static member function.
+
+   For non-static member functions, we ignore the first argument,
+   which is the type of the instance variable.  This is because we want
+   to handle calls with objects from derived classes.  This is not
+   entirely correct: we should actually check to make sure that a
+   requested operation is type secure, shouldn't we?  FIXME.  */
+
+int
+typecmp (staticp, t1, t2)
+     int staticp;
+     struct type *t1[];
+     value t2[];
+{
+  int i;
+
+  if (staticp && t1 == 0)
+    return t2[1] != 0;
+  if (t1 == 0)
+    return 1;
+  if (t1[0]->code == TYPE_CODE_VOID) return 0;
+  if (t1[!staticp] == 0) return 0;
+  for (i = !staticp; t1[i] && t1[i]->code != TYPE_CODE_VOID; i++)
+    {
+      if (! t2[i]
+         || t1[i]->code != t2[i]->type->code
+/* Too pessimistic:  || t1[i]->target_type != t2[i]->type->target_type */
+ )
+       return i+1;
+    }
+  if (!t1[i]) return 0;
+  return t2[i] ? i+1 : 0;
+}
+
+/* C++: return the value of the class instance variable, if one exists.
+   Flag COMPLAIN signals an error if the request is made in an
+   inappropriate context.  */
+value
+value_of_this (complain)
+     int complain;
+{
+  extern FRAME selected_frame;
+  struct symbol *func, *sym;
+  struct block *b;
+  int i;
+  static const char funny_this[] = "this";
+  value this;
+
+  if (selected_frame == 0)
+    if (complain)
+      error ("no frame selected");
+    else return 0;
+
+  func = get_frame_function (selected_frame);
+  if (!func)
+    {
+      if (complain)
+       error ("no `this' in nameless context");
+      else return 0;
+    }
+
+  b = SYMBOL_BLOCK_VALUE (func);
+  i = BLOCK_NSYMS (b);
+  if (i <= 0)
+    if (complain)
+      error ("no args, no `this'");
+    else return 0;
+
+  /* Calling lookup_block_symbol is necessary to get the LOC_REGISTER
+     symbol instead of the LOC_ARG one (if both exist).  */
+  sym = lookup_block_symbol (b, funny_this, VAR_NAMESPACE);
+  if (sym == NULL)
+    {
+      if (complain)
+       error ("current stack frame not in method");
+      else
+       return NULL;
+    }
+
+  this = read_var_value (sym, selected_frame);
+  if (this == 0 && complain)
+    error ("`this' argument at unknown address");
+  return this;
+}
diff --git a/gdb/valprint.c b/gdb/valprint.c
new file mode 100644 (file)
index 0000000..9a3ab90
--- /dev/null
@@ -0,0 +1,1915 @@
+/* Print values for GNU debugger gdb.
+   Copyright (C) 1986, 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 <stdio.h>
+#include <string.h>
+#include "defs.h"
+#include "param.h"
+#include "symtab.h"
+#include "value.h"
+#include "gdbcore.h"
+#include "gdbcmd.h"
+#include "target.h"
+#include "obstack.h"
+
+#include <errno.h>
+extern int sys_nerr;
+extern char *sys_errlist[];
+
+extern void print_scalar_formatted();  /* printcmd.c */
+extern void print_address_demangle();  /* printcmd.c */
+extern int demangle;   /* whether to print C++ syms raw or source-form */
+
+/* Maximum number of chars to print for a string pointer value
+   or vector contents, or UINT_MAX for no limit.  */
+
+static unsigned int print_max;
+
+static void type_print_varspec_suffix ();
+static void type_print_varspec_prefix ();
+static void type_print_base ();
+static void type_print_method_args ();
+
+/* Default input and output radixes, and output format letter.  */
+
+unsigned input_radix = 10;
+unsigned output_radix = 10;
+int output_format = 0;
+
+
+char **unsigned_type_table;
+char **signed_type_table;
+char **float_type_table;
+
+
+/* Print repeat counts if there are more than this
+   many repetitions of an element in an array.  */
+#define        REPEAT_COUNT_THRESHOLD  10
+\f
+/* Print the character string STRING, printing at most LENGTH characters.
+   Printing stops early if the number hits print_max; repeat counts
+   are printed as appropriate.  Print ellipses at the end if we
+   had to stop before printing LENGTH characters, or if FORCE_ELLIPSES.  */
+
+void
+print_string (stream, string, length, force_ellipses)
+     FILE *stream;
+     char *string;
+     unsigned int length;
+     int force_ellipses;
+{
+  register unsigned int i;
+  unsigned int things_printed = 0;
+  int in_quotes = 0;
+  int need_comma = 0;
+  extern int inspect_it;
+
+  if (length == 0)
+    {
+      fputs_filtered ("\"\"", stdout);
+      return;
+    }
+
+  for (i = 0; i < length && things_printed < print_max; ++i)
+    {
+      /* Position of the character we are examining
+        to see whether it is repeated.  */
+      unsigned int rep1;
+      /* Number of repetitions we have detected so far.  */
+      unsigned int reps;
+
+      QUIT;
+
+      if (need_comma)
+       {
+         fputs_filtered (", ", stream);
+         need_comma = 0;
+       }
+
+      rep1 = i + 1;
+      reps = 1;
+      while (rep1 < length && string[rep1] == string[i])
+       {
+         ++rep1;
+         ++reps;
+       }
+
+      if (reps > REPEAT_COUNT_THRESHOLD)
+       {
+         if (in_quotes)
+           {
+             if (inspect_it)
+               fputs_filtered ("\\\", ", stream);
+             else
+               fputs_filtered ("\", ", stream);
+             in_quotes = 0;
+           }
+         fputs_filtered ("'", stream);
+         printchar (string[i], stream, '\'');
+         fprintf_filtered (stream, "' <repeats %u times>", reps);
+         i = rep1 - 1;
+         things_printed += REPEAT_COUNT_THRESHOLD;
+         need_comma = 1;
+       }
+      else
+       {
+         if (!in_quotes)
+           {
+             if (inspect_it)
+               fputs_filtered ("\\\"", stream);
+             else
+               fputs_filtered ("\"", stream);
+             in_quotes = 1;
+           }
+         printchar (string[i], stream, '"');
+         ++things_printed;
+       }
+    }
+
+  /* Terminate the quotes if necessary.  */
+  if (in_quotes)
+    {
+      if (inspect_it)
+       fputs_filtered ("\\\"", stream);
+      else
+       fputs_filtered ("\"", stream);
+    }
+
+  if (force_ellipses || i < length)
+    fputs_filtered ("...", stream);
+}
+
+/* Print a floating point value of type TYPE, pointed to in GDB by VALADDR,
+   on STREAM.  */
+
+void
+print_floating (valaddr, type, stream)
+     char *valaddr;
+     struct type *type;
+     FILE *stream;
+{
+  double doub;
+  int inv;
+  unsigned len = TYPE_LENGTH (type);
+  
+#if defined (IEEE_FLOAT)
+
+  /* Check for NaN's.  Note that this code does not depend on us being
+     on an IEEE conforming system.  It only depends on the target
+     machine using IEEE representation.  This means (a)
+     cross-debugging works right, and (2) IEEE_FLOAT can (and should)
+     be defined for systems like the 68881, which uses IEEE
+     representation, but is not IEEE conforming.  */
+
+  {
+    long low, high;
+    /* Is the sign bit 0?  */
+    int nonnegative;
+    /* Is it is a NaN (i.e. the exponent is all ones and
+       the fraction is nonzero)?  */
+    int is_nan;
+
+    if (len == sizeof (float))
+      {
+       /* It's single precision. */
+       bcopy (valaddr, &low, sizeof (low));
+       /* target -> host.  */
+       SWAP_TARGET_AND_HOST (&low, sizeof (float));
+       nonnegative = low >= 0;
+       is_nan = ((((low >> 23) & 0xFF) == 0xFF) 
+                 && 0 != (low & 0x7FFFFF));
+       low &= 0x7fffff;
+       high = 0;
+      }
+    else
+      {
+       /* It's double precision.  Get the high and low words.  */
+
+#if TARGET_BYTE_ORDER == BIG_ENDIAN
+         bcopy (valaddr+4, &low,  sizeof (low));
+         bcopy (valaddr+0, &high, sizeof (high));
+#else
+         bcopy (valaddr+0, &low,  sizeof (low));
+         bcopy (valaddr+4, &high, sizeof (high));
+#endif
+         SWAP_TARGET_AND_HOST (&low, sizeof (low));
+         SWAP_TARGET_AND_HOST (&high, sizeof (high));
+         nonnegative = high >= 0;
+         is_nan = (((high >> 20) & 0x7ff) == 0x7ff
+                   && ! ((((high & 0xfffff) == 0)) && (low == 0)));
+         high &= 0xfffff;
+       }
+
+    if (is_nan)
+      {
+       /* The meaning of the sign and fraction is not defined by IEEE.
+          But the user might know what they mean.  For example, they
+          (in an implementation-defined manner) distinguish between
+          signaling and quiet NaN's.  */
+       if (high)
+         fprintf_filtered (stream, "-NaN(0x%lx%.8lx)" + nonnegative,
+                           high, low);
+       else
+         fprintf_filtered (stream, "-NaN(0x%lx)" + nonnegative, low);
+       return;
+      }
+  }
+#endif /* IEEE_FLOAT.  */
+
+  doub = unpack_double (type, valaddr, &inv);
+  if (inv)
+    fprintf_filtered (stream, "<invalid float value>");
+  else
+    fprintf_filtered (stream, len <= sizeof(float) ? "%.6g" : "%.17g", doub);
+}
+
+/* VALADDR points to an integer of LEN bytes.  Print it in hex on stream.  */
+static void
+print_hex_chars (stream, valaddr, len)
+     FILE *stream;
+     unsigned char *valaddr;
+     unsigned len;
+{
+  unsigned char *p;
+  
+  fprintf_filtered (stream, "0x");
+#if TARGET_BYTE_ORDER == BIG_ENDIAN
+  for (p = valaddr;
+       p < valaddr + len;
+       p++)
+#else /* Little endian.  */
+  for (p = valaddr + len - 1;
+       p >= valaddr;
+       p--)
+#endif
+    {
+      fprintf_filtered (stream, "%02x", *p);
+    }
+}
+\f
+/* Print the value VAL in C-ish syntax on stream STREAM.
+   FORMAT is a format-letter, or 0 for print in natural format of data type.
+   If the object printed is a string pointer, returns
+   the number of string bytes printed.  */
+
+int
+value_print (val, stream, format, pretty)
+     value val;
+     FILE *stream;
+     char format;
+     enum val_prettyprint pretty;
+{
+  register unsigned int i, n, typelen;
+
+  if (val == 0)
+    {
+      printf_filtered ("<address of value unknown>");
+      return 0;
+    }
+  if (VALUE_OPTIMIZED_OUT (val))
+    {
+      printf_filtered ("<value optimized out>");
+      return 0;
+    }
+  
+  /* A "repeated" value really contains several values in a row.
+     They are made by the @ operator.
+     Print such values as if they were arrays.  */
+
+  else if (VALUE_REPEATED (val))
+    {
+      n = VALUE_REPETITIONS (val);
+      typelen = TYPE_LENGTH (VALUE_TYPE (val));
+      fprintf_filtered (stream, "{");
+      /* Print arrays of characters using string syntax.  */
+      if (typelen == 1 && TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_INT
+         && format == 0)
+       print_string (stream, VALUE_CONTENTS (val), n, 0);
+      else
+       {
+         unsigned int things_printed = 0;
+         
+         for (i = 0; i < n && things_printed < print_max; i++)
+           {
+             /* Position of the array element we are examining to see
+                whether it is repeated.  */
+             unsigned int rep1;
+             /* Number of repetitions we have detected so far.  */
+             unsigned int reps;
+
+             if (i != 0)
+               fprintf_filtered (stream, ", ");
+             wrap_here ("");
+
+             rep1 = i + 1;
+             reps = 1;
+             while (rep1 < n
+                    && !bcmp (VALUE_CONTENTS (val) + typelen * i,
+                              VALUE_CONTENTS (val) + typelen * rep1, typelen))
+               {
+                 ++reps;
+                 ++rep1;
+               }
+
+             if (reps > REPEAT_COUNT_THRESHOLD)
+               {
+                 val_print (VALUE_TYPE (val),
+                            VALUE_CONTENTS (val) + typelen * i,
+                            VALUE_ADDRESS (val) + typelen * i,
+                            stream, format, 1, 0, pretty);
+                 fprintf (stream, " <repeats %u times>", reps);
+                 i = rep1 - 1;
+                 things_printed += REPEAT_COUNT_THRESHOLD;
+               }
+             else
+               {
+                 val_print (VALUE_TYPE (val),
+                            VALUE_CONTENTS (val) + typelen * i,
+                            VALUE_ADDRESS (val) + typelen * i,
+                            stream, format, 1, 0, pretty);
+                 things_printed++;
+               }
+           }
+         if (i < n)
+           fprintf_filtered (stream, "...");
+       }
+      fprintf_filtered (stream, "}");
+      return n * typelen;
+    }
+  else
+    {
+      /* If it is a pointer, indicate what it points to.
+
+        Print type also if it is a reference.
+
+         C++: if it is a member pointer, we will take care
+        of that when we print it.  */
+      if (TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_PTR
+         || TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_REF)
+       {
+         /* Hack:  remove (char *) for char strings.  Their
+            type is indicated by the quoted string anyway. */
+          if (TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_PTR
+           && TYPE_LENGTH   (TYPE_TARGET_TYPE (VALUE_TYPE (val)))
+                        == sizeof(char)
+           && TYPE_CODE     (TYPE_TARGET_TYPE (VALUE_TYPE (val)))
+                        == TYPE_CODE_INT
+           && !TYPE_UNSIGNED (TYPE_TARGET_TYPE (VALUE_TYPE (val))))
+           {
+               /* Print nothing */
+           }
+         else
+           {
+             fprintf_filtered (stream, "(");
+             type_print (VALUE_TYPE (val), "", stream, -1);
+             fprintf_filtered (stream, ") ");
+           }
+       }
+      return val_print (VALUE_TYPE (val), VALUE_CONTENTS (val),
+                       VALUE_ADDRESS (val), stream, format, 1, 0, pretty);
+    }
+}
+
+/* Return truth value for assertion that TYPE is of the type
+   "pointer to virtual function".  */
+static int
+is_vtbl_ptr_type(type)
+     struct type *type;
+{
+  char *typename = TYPE_NAME(type);
+  static const char vtbl_ptr_name[] =
+    { CPLUS_MARKER,'v','t','b','l','_','p','t','r','_','t','y','p','e' };
+
+  return (typename != NULL && !strcmp(typename, vtbl_ptr_name));
+}
+
+/* Return truth value for the assertion that TYPE is of the type
+   "pointer to virtual function table".  */
+static int
+is_vtbl_member(type)
+     struct type *type;
+{
+  if (TYPE_CODE (type) == TYPE_CODE_PTR
+      && TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_ARRAY
+      && TYPE_CODE (TYPE_TARGET_TYPE (TYPE_TARGET_TYPE (type))) == TYPE_CODE_STRUCT)
+    /* Virtual functions tables are full of pointers to virtual functions.  */
+    return is_vtbl_ptr_type (TYPE_TARGET_TYPE (TYPE_TARGET_TYPE (type)));
+  return 0;
+}
+\f
+/* Define a mess of print controls.  */
+
+int prettyprint;       /* Controls pretty printing of structures */
+int vtblprint;         /* Controls printing of vtbl's */
+int unionprint;                /* Controls printing of nested unions.  */
+int arrayprint;                /* Controls pretty printing of arrays.  */
+int addressprint;      /* Controls pretty printing of addresses.  */
+
+struct obstack dont_print_obstack;
+
+static void cplus_val_print ();
+
+/* Mutually recursive subroutines of cplus_val_print and val_print to print out
+   a structure's fields: val_print_fields and cplus_val_print.
+
+   TYPE, VALADDR, STREAM, RECURSE, and PRETTY have the
+   same meanings as in cplus_val_print and val_print.
+
+   DONT_PRINT is an array of baseclass types that we
+   should not print, or zero if called from top level.  */
+static void
+val_print_fields (type, valaddr, stream, format, recurse, pretty, dont_print)
+     struct type *type;
+     char *valaddr;
+     FILE *stream;
+     char format;
+     int recurse;
+     enum val_prettyprint pretty;
+     struct type **dont_print;
+{
+  int i, len, n_baseclasses;
+
+  fprintf_filtered (stream, "{");
+  len = TYPE_NFIELDS (type);
+  n_baseclasses = TYPE_N_BASECLASSES (type);
+
+  /* Print out baseclasses such that we don't print
+     duplicates of virtual baseclasses.  */
+  if (n_baseclasses > 0)
+    cplus_val_print (type, valaddr, stream, format, recurse+1, pretty, dont_print);
+
+  if (!len && n_baseclasses == 1)
+    fprintf_filtered (stream, "<No data fields>");
+  else
+    {
+      extern int inspect_it;
+      int fields_seen = 0;
+
+      for (i = n_baseclasses; i < len; i++)
+       {
+         /* Check if static field */
+         if (TYPE_FIELD_STATIC (type, i))
+           continue;
+         if (fields_seen)
+           fprintf_filtered (stream, ", ");
+         else if (n_baseclasses > 0)
+           {
+             fprintf_filtered (stream, "\n");
+             print_spaces_filtered (2 + 2 * recurse, stream);
+             fputs_filtered ("members of ", stream);
+             fputs_filtered (type_name_no_tag (type), stream);
+             fputs_filtered (": ", stream);
+           }
+         fields_seen = 1;
+
+         if (pretty)
+           {
+             fprintf_filtered (stream, "\n");
+             print_spaces_filtered (2 + 2 * recurse, stream);
+           }
+         else 
+           {
+             wrap_here (n_spaces (2 + 2 * recurse));
+           }
+         if (inspect_it)
+           {
+             if (TYPE_CODE (TYPE_FIELD_TYPE (type, i)) == TYPE_CODE_PTR)
+               fputs_filtered ("\"( ptr \"", stream);
+             else
+               fputs_filtered ("\"( nodef \"", stream);
+             fputs_filtered (TYPE_FIELD_NAME (type, i), stream);
+             fputs_filtered ("\" \"", stream);
+             fputs_filtered (TYPE_FIELD_NAME (type, i), stream);
+             fputs_filtered ("\") \"", stream);
+           }
+         else
+           {
+             fputs_filtered (TYPE_FIELD_NAME (type, i), stream);
+             fputs_filtered (" = ", stream);
+           }
+         if (TYPE_FIELD_PACKED (type, i))
+           {
+             LONGEST val;
+             char *valp = (char *) & val;
+
+             val = unpack_field_as_long (type, valaddr, i);
+
+             /* Since we have moved the bitfield into a long,
+                if it is declared with a smaller type, we need to
+                offset its address *in gdb* to match the type we
+                are passing to val_print.  */
+#if HOST_BYTE_ORDER == BIG_ENDIAN
+             valp += sizeof val - TYPE_LENGTH (TYPE_FIELD_TYPE (type, i));
+#endif
+             val_print (TYPE_FIELD_TYPE (type, i), valp, 0,
+                        stream, format, 0, recurse + 1, pretty);
+           }
+         else
+           {
+             val_print (TYPE_FIELD_TYPE (type, i), 
+                        valaddr + TYPE_FIELD_BITPOS (type, i) / 8,
+                        0, stream, format, 0, recurse + 1, pretty);
+           }
+       }
+      if (pretty)
+       {
+         fprintf_filtered (stream, "\n");
+         print_spaces_filtered (2 * recurse, stream);
+       }
+    }
+  fprintf_filtered (stream, "}");
+}
+
+/* Special val_print routine to avoid printing multiple copies of virtual
+   baseclasses.  */
+
+static void
+cplus_val_print (type, valaddr, stream, format, recurse, pretty, dont_print)
+     struct type *type;
+     char *valaddr;
+     FILE *stream;
+     char format;
+     int recurse;
+     enum val_prettyprint pretty;
+     struct type **dont_print;
+{
+  struct obstack tmp_obstack;
+  struct type **last_dont_print
+    = (struct type **)obstack_next_free (&dont_print_obstack);
+  int i, n_baseclasses = TYPE_N_BASECLASSES (type);
+
+  if (dont_print == 0)
+    {
+      /* If we're at top level, carve out a completely fresh
+        chunk of the obstack and use that until this particular
+        invocation returns.  */
+      tmp_obstack = dont_print_obstack;
+      /* Bump up the high-water mark.  Now alpha is omega.  */
+      obstack_finish (&dont_print_obstack);
+    }
+
+  for (i = 0; i < n_baseclasses; i++)
+    {
+      char *baddr;
+
+      if (BASETYPE_VIA_VIRTUAL (type, i))
+       {
+         struct type **first_dont_print
+           = (struct type **)obstack_base (&dont_print_obstack);
+
+         int j = (struct type **)obstack_next_free (&dont_print_obstack)
+           - first_dont_print;
+
+         while (--j >= 0)
+           if (TYPE_BASECLASS (type, i) == first_dont_print[j])
+             goto flush_it;
+
+         obstack_ptr_grow (&dont_print_obstack, TYPE_BASECLASS (type, i));
+       }
+
+      baddr = baseclass_addr (type, i, valaddr, 0);
+      if (baddr == 0)
+       error ("could not find virtual baseclass `%s'\n",
+              type_name_no_tag (TYPE_BASECLASS (type, i)));
+
+      fprintf_filtered (stream, "\n");
+      if (pretty)
+       print_spaces_filtered (2 + 2 * recurse, stream);
+      fputs_filtered ("<", stream);
+      fputs_filtered (type_name_no_tag (TYPE_BASECLASS (type, i)), stream);
+      fputs_filtered ("> = ", stream);
+      val_print_fields (TYPE_BASECLASS (type, i), baddr, stream, format,
+                       recurse, pretty,
+                       (struct type **)obstack_base (&dont_print_obstack));
+    flush_it:
+      ;
+    }
+
+  if (dont_print == 0)
+    {
+      /* Free the space used to deal with the printing
+        of this type from top level.  */
+      obstack_free (&dont_print_obstack, last_dont_print);
+      /* Reset watermark so that we can continue protecting
+        ourselves from whatever we were protecting ourselves.  */
+      dont_print_obstack = tmp_obstack;
+    }
+}
+
+/* Print data of type TYPE located at VALADDR (within GDB),
+   which came from the inferior at address ADDRESS,
+   onto stdio stream STREAM according to FORMAT
+   (a letter or 0 for natural format).  The data at VALADDR
+   is in target byte order.
+
+   If the data are a string pointer, returns the number of
+   sting characters printed.
+
+   if DEREF_REF is nonzero, then dereference references,
+   otherwise just print them like pointers.
+
+   The PRETTY parameter controls prettyprinting.  */
+
+int
+val_print (type, valaddr, address, stream, format,
+          deref_ref, recurse, pretty)
+     struct type *type;
+     char *valaddr;
+     CORE_ADDR address;
+     FILE *stream;
+     char format;
+     int deref_ref;
+     int recurse;
+     enum val_prettyprint pretty;
+{
+  register unsigned int i;
+  unsigned len;
+  struct type *elttype;
+  unsigned eltlen;
+  LONGEST val;
+  unsigned char c;
+
+  if (pretty == Val_pretty_default)
+    {
+      pretty = prettyprint ? Val_prettyprint : Val_no_prettyprint;
+    }
+  
+  QUIT;
+
+  check_stub_type (type);
+  
+  if (TYPE_FLAGS (type) & TYPE_FLAG_STUB)
+    {
+      fprintf_filtered (stream, "<unknown struct>");
+      fflush (stream);
+      return 0;
+    }
+  
+  switch (TYPE_CODE (type))
+    {
+    case TYPE_CODE_ARRAY:
+      if (TYPE_LENGTH (type) >= 0
+         && TYPE_LENGTH (TYPE_TARGET_TYPE (type)) > 0)
+       {
+         elttype = TYPE_TARGET_TYPE (type);
+         eltlen = TYPE_LENGTH (elttype);
+         len = TYPE_LENGTH (type) / eltlen;
+         if (arrayprint)
+           print_spaces_filtered (2 + 2 * recurse, stream);
+         fprintf_filtered (stream, "{");
+         /* For an array of chars, print with string syntax.  */
+         if (eltlen == 1 && TYPE_CODE (elttype) == TYPE_CODE_INT
+             && (format == 0 || format == 's') )
+           print_string (stream, valaddr, len, 0);
+         else
+           {
+             unsigned int things_printed = 0;
+             
+             for (i = 0; i < len && things_printed < print_max; i++)
+               {
+                 /* Position of the array element we are examining to see
+                    whether it is repeated.  */
+                 unsigned int rep1;
+                 /* Number of repetitions we have detected so far.  */
+                 unsigned int reps;
+                 
+                 if (i != 0)
+                   if (arrayprint)
+                     {
+                       fprintf_filtered (stream, ",\n");
+                       print_spaces_filtered (2 + 2 * recurse, stream);
+                     }
+                   else
+                     fprintf_filtered (stream, ", ");
+                   wrap_here (n_spaces (2 + 2 * recurse));
+                 
+                 rep1 = i + 1;
+                 reps = 1;
+                 while (rep1 < len
+                        && !bcmp (valaddr + i * eltlen,
+                                  valaddr + rep1 * eltlen, eltlen))
+                   {
+                     ++reps;
+                     ++rep1;
+                   }
+
+                 if (reps > REPEAT_COUNT_THRESHOLD)
+                   {
+                     val_print (elttype, valaddr + i * eltlen,
+                                0, stream, format, deref_ref,
+                                recurse + 1, pretty);
+                     fprintf_filtered (stream, " <repeats %u times>", reps);
+                     i = rep1 - 1;
+                     things_printed += REPEAT_COUNT_THRESHOLD;
+                   }
+                 else
+                   {
+                     val_print (elttype, valaddr + i * eltlen,
+                                0, stream, format, deref_ref,
+                                recurse + 1, pretty);
+                     things_printed++;
+                   }
+               }
+             if (i < len)
+               fprintf_filtered (stream, "...");
+           }
+         fprintf_filtered (stream, "}");
+         break;
+       }
+      /* Array of unspecified length: treat like pointer to first elt.  */
+      valaddr = (char *) &address;
+
+    case TYPE_CODE_PTR:
+      if (format && format != 's')
+       {
+         print_scalar_formatted (valaddr, type, format, 0, stream);
+         break;
+       }
+      if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_METHOD)
+       {
+         struct type *domain = TYPE_DOMAIN_TYPE (TYPE_TARGET_TYPE (type));
+         struct fn_field *f;
+         int j, len2;
+         char *kind = "";
+
+         val = unpack_long (builtin_type_int, valaddr);
+         if (val < 128)
+           {
+             len = TYPE_NFN_FIELDS (domain);
+             for (i = 0; i < len; i++)
+               {
+                 f = TYPE_FN_FIELDLIST1 (domain, i);
+                 len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i);
+
+                 for (j = 0; j < len2; j++)
+                   {
+                     QUIT;
+                     if (TYPE_FN_FIELD_VOFFSET (f, j) == val)
+                       {
+                         kind = "virtual";
+                         goto common;
+                       }
+                   }
+               }
+           }
+         else
+           {
+             struct symbol *sym = find_pc_function ((CORE_ADDR) val);
+             if (sym == 0)
+               error ("invalid pointer to member function");
+             len = TYPE_NFN_FIELDS (domain);
+             for (i = 0; i < len; i++)
+               {
+                 f = TYPE_FN_FIELDLIST1 (domain, i);
+                 len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i);
+
+                 for (j = 0; j < len2; j++)
+                   {
+                     QUIT;
+                     if (!strcmp (SYMBOL_NAME (sym), TYPE_FN_FIELD_PHYSNAME (f, j)))
+                       goto common;
+                   }
+               }
+           }
+       common:
+         if (i < len)
+           {
+             fprintf_filtered (stream, "&");
+             type_print_varspec_prefix (TYPE_FN_FIELD_TYPE (f, j), stream, 0, 0);
+             fprintf (stream, kind);
+             if (TYPE_FN_FIELD_PHYSNAME (f, j)[0] == '_'
+                 && TYPE_FN_FIELD_PHYSNAME (f, j)[1] == CPLUS_MARKER)
+               type_print_method_args
+                 (TYPE_FN_FIELD_ARGS (f, j) + 1, "~",
+                  TYPE_FN_FIELDLIST_NAME (domain, i), 0, stream);
+             else
+               type_print_method_args
+                 (TYPE_FN_FIELD_ARGS (f, j), "",
+                  TYPE_FN_FIELDLIST_NAME (domain, i), 0, stream);
+             break;
+           }
+         fprintf_filtered (stream, "(");
+         type_print (type, "", stream, -1);
+         fprintf_filtered (stream, ") %d", (int) val >> 3);
+       }
+      else if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_MEMBER)
+       {
+         struct type *domain = TYPE_DOMAIN_TYPE (TYPE_TARGET_TYPE (type));
+
+         /* VAL is a byte offset into the structure type DOMAIN.
+            Find the name of the field for that offset and
+            print it.  */
+         int extra = 0;
+         int bits = 0;
+         len = TYPE_NFIELDS (domain);
+         /* @@ Make VAL into bit offset */
+         val = unpack_long (builtin_type_int, valaddr) << 3;
+         for (i = TYPE_N_BASECLASSES (domain); i < len; i++)
+           {
+             int bitpos = TYPE_FIELD_BITPOS (domain, i);
+             QUIT;
+             if (val == bitpos)
+               break;
+             if (val < bitpos && i != 0)
+               {
+                 /* Somehow pointing into a field.  */
+                 i -= 1;
+                 extra = (val - TYPE_FIELD_BITPOS (domain, i));
+                 if (extra & 0x3)
+                   bits = 1;
+                 else
+                   extra >>= 3;
+                 break;
+               }
+           }
+         if (i < len)
+           {
+             fprintf_filtered (stream, "&");
+             type_print_base (domain, stream, 0, 0);
+             fprintf_filtered (stream, "::");
+             fputs_filtered (TYPE_FIELD_NAME (domain, i), stream);
+             if (extra)
+               fprintf_filtered (stream, " + %d bytes", extra);
+             if (bits)
+               fprintf_filtered (stream, " (offset in bits)");
+             break;
+           }
+         fprintf_filtered (stream, "%d", val >> 3);
+       }
+      else
+       {
+         CORE_ADDR addr = (CORE_ADDR) unpack_long (type, valaddr);
+         elttype = TYPE_TARGET_TYPE (type);
+
+         if (TYPE_CODE (elttype) == TYPE_CODE_FUNC)
+           {
+             /* Try to print what function it points to.  */
+             print_address_demangle (addr, stream, demangle);
+             /* Return value is irrelevant except for string pointers.  */
+             return 0;
+           }
+
+         if (addressprint && format != 's')
+           fprintf_filtered (stream, "0x%x", addr);
+
+         /* For a pointer to char or unsigned char,
+            also print the string pointed to, unless pointer is null.  */
+         i = 0;                /* Number of characters printed.  */
+         if (TYPE_LENGTH (elttype) == 1 
+             && TYPE_CODE (elttype) == TYPE_CODE_INT
+             && (format == 0 || format == 's')
+             && addr != 0
+             /* If print_max is UINT_MAX, the alloca below will fail.
+                In that case don't try to print the string.  */
+             && print_max < UINT_MAX)
+           {
+             int first_addr_err = 0;
+             int errcode = 0;
+             
+             /* Get first character.  */
+             errcode = target_read_memory (addr, (char *)&c, 1);
+             if (errcode != 0)
+               {
+                 /* First address out of bounds.  */
+                 first_addr_err = 1;
+               }
+             else
+               {
+                 /* A real string.  */
+                 char *string = (char *) alloca (print_max);
+
+                 /* If the loop ends by us hitting print_max characters,
+                    we need to have elipses at the end.  */
+                 int force_ellipses = 1;
+
+                 /* This loop always fetches print_max characters, even
+                    though print_string might want to print more or fewer
+                    (with repeated characters).  This is so that
+                    we don't spend forever fetching if we print
+                    a long string consisting of the same character
+                    repeated.  Also so we can do it all in one memory
+                    operation, which is faster.  However, this will be
+                    slower if print_max is set high, e.g. if you set
+                    print_max to 1000, not only will it take a long
+                    time to fetch short strings, but if you are near
+                    the end of the address space, it might not work.
+                    FIXME.  */
+                 QUIT;
+                 errcode = target_read_memory (addr, string, print_max);
+                 if (errcode != 0)
+                     force_ellipses = 0;
+                 else 
+                   for (i = 0; i < print_max; i++)
+                     if (string[i] == '\0')
+                       {
+                         force_ellipses = 0;
+                         break;
+                       }
+                 QUIT;
+
+                 if (addressprint)
+                   fputs_filtered (" ", stream);
+                 print_string (stream, string, i, force_ellipses);
+               }
+
+             if (errcode != 0)
+               {
+                 if (errcode == EIO)
+                   {
+                     fprintf_filtered (stream,
+                                       (" <Address 0x%x out of bounds>"
+                                        + first_addr_err),
+                                       addr + i);
+                   }
+                 else
+                   {
+                     if (errcode >= sys_nerr || errcode < 0)
+                       error ("Error reading memory address 0x%x: unknown error (%d).",
+                              addr + i, errcode);
+                     else
+                       error ("Error reading memory address 0x%x: %s.",
+                              addr + i, sys_errlist[errcode]);
+                   }
+               }
+
+             fflush (stream);
+           }
+         else /* print vtbl's nicely */
+         if (is_vtbl_member(type))
+           {
+             CORE_ADDR vt_address = (CORE_ADDR) unpack_long (type, valaddr);
+
+             int vt_index = find_pc_misc_function (vt_address);
+             if (vt_index >= 0
+                 && vt_address == misc_function_vector[vt_index].address)
+               {
+                 fputs_filtered (" <", stream);
+                 fputs_demangled (misc_function_vector[vt_index].name,
+                                  stream, 1);
+                 fputs_filtered (">", stream);
+               }
+             if (vtblprint)
+               {
+                 value val;
+
+                 val = value_at (TYPE_TARGET_TYPE (type), vt_address);
+                 val_print (VALUE_TYPE (val), VALUE_CONTENTS (val),
+                            VALUE_ADDRESS (val), stream, format,
+                            deref_ref, recurse + 1, pretty);
+                 if (pretty)
+                   {
+                     fprintf_filtered (stream, "\n");
+                     print_spaces_filtered (2 + 2 * recurse, stream);
+                   }
+               }
+             }
+
+         /* Return number of characters printed, plus one for the
+            terminating null if we have "reached the end".  */
+         return i + (print_max && i != print_max);
+       }
+      break;
+
+    case TYPE_CODE_MEMBER:
+      error ("not implemented: member type in val_print");
+      break;
+
+    case TYPE_CODE_REF:
+      if (addressprint)
+        {
+         fprintf_filtered (stream, "@0x%lx",
+                           unpack_long (builtin_type_int, valaddr));
+         if (deref_ref)
+           fputs_filtered (": ", stream);
+        }
+      /* De-reference the reference.  */
+      if (deref_ref)
+       {
+         if (TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_UNDEF)
+           {
+             value val = value_at (TYPE_TARGET_TYPE (type),
+                                   (CORE_ADDR) unpack_long (builtin_type_int,
+                                                            valaddr));
+             val_print (VALUE_TYPE (val), VALUE_CONTENTS (val),
+                        VALUE_ADDRESS (val), stream, format,
+                        deref_ref, recurse + 1, pretty);
+           }
+         else
+           fputs_filtered ("???", stream);
+       }
+      break;
+
+    case TYPE_CODE_UNION:
+      if (recurse && !unionprint)
+       {
+         fprintf_filtered (stream, "{...}");
+         break;
+       }
+      /* Fall through.  */
+    case TYPE_CODE_STRUCT:
+      if (vtblprint && is_vtbl_ptr_type(type))
+       {
+          /* Print the unmangled name if desired.  */
+         print_address_demangle(*((int *) (valaddr +   /* FIXME bytesex */
+             TYPE_FIELD_BITPOS (type, VTBL_FNADDR_OFFSET) / 8)),
+             stream, demangle);
+         break;
+       }
+      val_print_fields (type, valaddr, stream, format, recurse, pretty, 0);
+      break;
+
+    case TYPE_CODE_ENUM:
+      if (format)
+       {
+         print_scalar_formatted (valaddr, type, format, 0, stream);
+         break;
+       }
+      len = TYPE_NFIELDS (type);
+      val = unpack_long (builtin_type_int, valaddr);
+      for (i = 0; i < len; i++)
+       {
+         QUIT;
+         if (val == TYPE_FIELD_BITPOS (type, i))
+           break;
+       }
+      if (i < len)
+       fputs_filtered (TYPE_FIELD_NAME (type, i), stream);
+      else
+       fprintf_filtered (stream, "%d", (int) val);
+      break;
+
+    case TYPE_CODE_FUNC:
+      if (format)
+       {
+         print_scalar_formatted (valaddr, type, format, 0, stream);
+         break;
+       }
+      fprintf_filtered (stream, "{");
+      type_print (type, "", stream, -1);
+      fprintf_filtered (stream, "} ");
+      if (addressprint)
+       fprintf_filtered (stream, "0x%x", address);
+      break;
+
+    case TYPE_CODE_INT:
+      if (format || output_format)
+       {
+         print_scalar_formatted (valaddr, type,
+                                 format? format: output_format,
+                                 0, stream);
+         break;
+       }
+      if (TYPE_LENGTH (type) > sizeof (LONGEST))
+       {
+         if (TYPE_UNSIGNED (type))
+           {
+             /* First figure out whether the number in fact has zeros
+                in all its bytes more significant than least significant
+                sizeof (LONGEST) ones.  */
+             char *p;
+             /* Pointer to first (i.e. lowest address) nonzero character.  */
+             char *first_addr;
+             unsigned len = TYPE_LENGTH (type);
+
+#if TARGET_BYTE_ORDER == BIG_ENDIAN
+             for (p = valaddr;
+                  len > sizeof (LONGEST)
+                  && p < valaddr + TYPE_LENGTH (type);
+                  p++)
+#else /* Little endian.  */
+             first_addr = valaddr;
+             for (p = valaddr + TYPE_LENGTH (type);
+                  len > sizeof (LONGEST) && p >= valaddr;
+                  p--)
+#endif /* Little endian.  */
+               {
+                 if (*p == 0)
+                   len--;
+                 else
+                   break;
+               }
+#if TARGET_BYTE_ORDER == BIG_ENDIAN
+             first_addr = p;
+#endif
+             
+             if (len <= sizeof (LONGEST))
+               {
+                 /* We can print it in decimal.  */
+                 fprintf_filtered
+                   (stream, 
+#if defined (LONG_LONG)
+                    "%llu",
+#else
+                    "%lu",
+#endif
+                    unpack_long (BUILTIN_TYPE_LONGEST, first_addr));
+               }
+             else
+               {
+                 /* It is big, so print it in hex.  */
+                 print_hex_chars (stream, (unsigned char *)first_addr, len);
+               }
+           }
+         else
+           {
+             /* Signed.  One could assume two's complement (a reasonable
+                assumption, I think) and do better than this.  */
+             print_hex_chars (stream, (unsigned char *)valaddr,
+                              TYPE_LENGTH (type));
+           }
+         break;
+       }
+#ifdef PRINT_TYPELESS_INTEGER
+      PRINT_TYPELESS_INTEGER (stream, type, unpack_long (type, valaddr));
+#else
+#ifndef LONG_LONG
+      fprintf_filtered (stream,
+                       TYPE_UNSIGNED (type) ? "%u" : "%d",
+                       unpack_long (type, valaddr));
+#else
+      fprintf_filtered (stream,
+                       TYPE_UNSIGNED (type) ? "%llu" : "%lld",
+                       unpack_long (type, valaddr));
+#endif
+#endif
+                       
+      if (TYPE_LENGTH (type) == 1)
+       {
+         fprintf_filtered (stream, " '");
+         printchar ((unsigned char) unpack_long (type, valaddr), 
+                    stream, '\'');
+         fprintf_filtered (stream, "'");
+       }
+      break;
+
+    case TYPE_CODE_FLT:
+      if (format)
+       print_scalar_formatted (valaddr, type, format, 0, stream);
+      else
+       print_floating (valaddr, type, stream);
+      break;
+
+    case TYPE_CODE_VOID:
+      fprintf_filtered (stream, "void");
+      break;
+
+    case TYPE_CODE_UNDEF:
+      /* This happens (without TYPE_FLAG_STUB set) on systems which don't use
+        dbx xrefs (NO_DBX_XREFS in gcc) if a file has a "struct foo *bar"
+        and no complete type for struct foo in that file.  */
+      fprintf_filtered (stream, "<unknown struct>");
+      break;
+
+    case TYPE_CODE_ERROR:
+      fprintf_filtered (stream, "?");
+      break;
+
+    default:
+      error ("Invalid type code in symbol table.");
+    }
+  fflush (stream);
+  return 0;
+}
+\f
+/* Print a description of a type TYPE
+   in the form of a declaration of a variable named VARSTRING.
+   (VARSTRING is demangled if necessary.)
+   Output goes to STREAM (via stdio).
+   If SHOW is positive, we show the contents of the outermost level
+   of structure even if there is a type name that could be used instead.
+   If SHOW is negative, we never show the details of elements' types.  */
+
+void
+type_print (type, varstring, stream, show)
+     struct type *type;
+     char *varstring;
+     FILE *stream;
+     int show;
+{
+  type_print_1 (type, varstring, stream, show, 0);
+}
+
+/* LEVEL is the depth to indent lines by.  */
+
+void
+type_print_1 (type, varstring, stream, show, level)
+     struct type *type;
+     char *varstring;
+     FILE *stream;
+     int show;
+     int level;
+{
+  register enum type_code code;
+  type_print_base (type, stream, show, level);
+  code = TYPE_CODE (type);
+  if ((varstring && *varstring)
+      ||
+      /* Need a space if going to print stars or brackets;
+        but not if we will print just a type name.  */
+      ((show > 0 || TYPE_NAME (type) == 0)
+       &&
+       (code == TYPE_CODE_PTR || code == TYPE_CODE_FUNC
+       || code == TYPE_CODE_METHOD
+       || code == TYPE_CODE_ARRAY
+       || code == TYPE_CODE_MEMBER
+       || code == TYPE_CODE_REF)))
+    fprintf_filtered (stream, " ");
+  type_print_varspec_prefix (type, stream, show, 0);
+  fputs_demangled (varstring, stream, -1);     /* Print demangled name
+                                                  without arguments */
+  type_print_varspec_suffix (type, stream, show, 0);
+}
+
+/* Print the method arguments ARGS to the file STREAM.  */
+static void
+type_print_method_args (args, prefix, varstring, staticp, stream)
+     struct type **args;
+     char *prefix, *varstring;
+     int staticp;
+     FILE *stream;
+{
+  int i;
+
+  fputs_filtered (" ", stream);
+  fputs_demangled (prefix, stream, 1);
+  fputs_demangled (varstring, stream, 1);
+  fputs_filtered (" (", stream);
+  if (args && args[!staticp] && args[!staticp]->code != TYPE_CODE_VOID)
+    {
+      i = !staticp;            /* skip the class variable */
+      while (1)
+       {
+         type_print (args[i++], "", stream, 0);
+         if (!args[i]) 
+           {
+             fprintf_filtered (stream, " ...");
+             break;
+           }
+         else if (args[i]->code != TYPE_CODE_VOID)
+           {
+             fprintf_filtered (stream, ", ");
+           }
+         else break;
+       }
+    }
+  fprintf_filtered (stream, ")");
+}
+  
+/* If TYPE is a derived type, then print out derivation
+   information.  Print out all layers of the type heirarchy
+   until we encounter one with multiple inheritance.
+   At that point, print out that ply, and return.  */
+static void
+type_print_derivation_info (stream, type)
+     FILE *stream;
+     struct type *type;
+{
+  char *name;
+  int i, n_baseclasses = TYPE_N_BASECLASSES (type);
+  struct type *basetype = 0;
+
+  while (type && n_baseclasses > 0)
+    {
+      /* Not actually sure about this one -- Bryan. */
+      check_stub_type (type);
+      
+      fprintf_filtered (stream, ": ");
+      for (i = 0; ;)
+       {
+         basetype = TYPE_BASECLASS (type, i);
+         if (name = type_name_no_tag (basetype))
+           {
+             fprintf_filtered (stream, "%s%s ",
+                      BASETYPE_VIA_PUBLIC(type, i) ? "public" : "private",
+                      BASETYPE_VIA_VIRTUAL(type, i) ? " virtual" : "");
+             fputs_filtered (name, stream);
+           }
+         i++;
+         if (i >= n_baseclasses)
+             break;
+         fprintf_filtered (stream, ", ");
+       }
+
+      fprintf_filtered (stream, " ");
+      if (n_baseclasses != 1)
+       break;
+      n_baseclasses = TYPE_N_BASECLASSES (basetype);
+      type = basetype;
+    }
+}
+
+/* Print any asterisks or open-parentheses needed before the
+   variable name (to describe its type).
+
+   On outermost call, pass 0 for PASSED_A_PTR.
+   On outermost call, SHOW > 0 means should ignore
+   any typename for TYPE and show its details.
+   SHOW is always zero on recursive calls.  */
+
+static void
+type_print_varspec_prefix (type, stream, show, passed_a_ptr)
+     struct type *type;
+     FILE *stream;
+     int show;
+     int passed_a_ptr;
+{
+  if (type == 0)
+    return;
+
+  if (TYPE_NAME (type) && show <= 0)
+    return;
+
+  QUIT;
+
+  switch (TYPE_CODE (type))
+    {
+    case TYPE_CODE_PTR:
+      type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 1);
+      fprintf_filtered (stream, "*");
+      break;
+
+    case TYPE_CODE_MEMBER:
+      if (passed_a_ptr)
+       fprintf_filtered (stream, "(");
+      type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0,
+                                0);
+      fprintf_filtered (stream, " ");
+      type_print_base (TYPE_DOMAIN_TYPE (type), stream, 0,
+                      passed_a_ptr);
+      fprintf_filtered (stream, "::");
+      break;
+
+    case TYPE_CODE_METHOD:
+      if (passed_a_ptr)
+       fprintf (stream, "(");
+      type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0,
+                                0);
+      fprintf_filtered (stream, " ");
+      type_print_base (TYPE_DOMAIN_TYPE (type), stream, 0,
+                      passed_a_ptr);
+      fprintf_filtered (stream, "::");
+      break;
+
+    case TYPE_CODE_REF:
+      type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 1);
+      fprintf_filtered (stream, "&");
+      break;
+
+    case TYPE_CODE_FUNC:
+      type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0,
+                                0);
+      if (passed_a_ptr)
+       fprintf_filtered (stream, "(");
+      break;
+
+    case TYPE_CODE_ARRAY:
+      type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0,
+                                0);
+      if (passed_a_ptr)
+       fprintf_filtered (stream, "(");
+
+    case TYPE_CODE_UNDEF:
+    case TYPE_CODE_STRUCT:
+    case TYPE_CODE_UNION:
+    case TYPE_CODE_ENUM:
+    case TYPE_CODE_INT:
+    case TYPE_CODE_FLT:
+    case TYPE_CODE_VOID:
+    case TYPE_CODE_ERROR:
+      /* These types need no prefix.  They are listed here so that
+        gcc -Wall will reveal any types that haven't been handled.  */
+      break;
+    }
+}
+
+/* Print any array sizes, function arguments or close parentheses
+   needed after the variable name (to describe its type).
+   Args work like type_print_varspec_prefix.  */
+
+static void
+type_print_varspec_suffix (type, stream, show, passed_a_ptr)
+     struct type *type;
+     FILE *stream;
+     int show;
+     int passed_a_ptr;
+{
+  if (type == 0)
+    return;
+
+  if (TYPE_NAME (type) && show <= 0)
+    return;
+
+  QUIT;
+
+  switch (TYPE_CODE (type))
+    {
+    case TYPE_CODE_ARRAY:
+      if (passed_a_ptr)
+       fprintf_filtered (stream, ")");
+      
+      fprintf_filtered (stream, "[");
+      if (TYPE_LENGTH (type) >= 0
+         && TYPE_LENGTH (TYPE_TARGET_TYPE (type)) > 0)
+       fprintf_filtered (stream, "%d",
+                         (TYPE_LENGTH (type)
+                          / TYPE_LENGTH (TYPE_TARGET_TYPE (type))));
+      fprintf_filtered (stream, "]");
+      
+      type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0,
+                                0);
+      break;
+
+    case TYPE_CODE_MEMBER:
+      if (passed_a_ptr)
+       fprintf_filtered (stream, ")");
+      type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 0);
+      break;
+
+    case TYPE_CODE_METHOD:
+      if (passed_a_ptr)
+       fprintf_filtered (stream, ")");
+      type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 0);
+      if (passed_a_ptr)
+       {
+         int i;
+         struct type **args = TYPE_ARG_TYPES (type);
+
+         fprintf_filtered (stream, "(");
+         if (args[1] == 0)
+           fprintf_filtered (stream, "...");
+         else for (i = 1; args[i] != 0 && args[i]->code != TYPE_CODE_VOID; i++)
+           {
+             type_print_1 (args[i], "", stream, -1, 0);
+             if (args[i+1] == 0)
+               fprintf_filtered (stream, "...");
+             else if (args[i+1]->code != TYPE_CODE_VOID)
+               fprintf_filtered (stream, ",");
+           }
+         fprintf_filtered (stream, ")");
+       }
+      break;
+
+    case TYPE_CODE_PTR:
+    case TYPE_CODE_REF:
+      type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 1);
+      break;
+
+    case TYPE_CODE_FUNC:
+      type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0,
+                                passed_a_ptr);
+      if (passed_a_ptr)
+       fprintf_filtered (stream, ")");
+      fprintf_filtered (stream, "()");
+      break;
+
+    case TYPE_CODE_UNDEF:
+    case TYPE_CODE_STRUCT:
+    case TYPE_CODE_UNION:
+    case TYPE_CODE_ENUM:
+    case TYPE_CODE_INT:
+    case TYPE_CODE_FLT:
+    case TYPE_CODE_VOID:
+    case TYPE_CODE_ERROR:
+      /* These types do not need a suffix.  They are listed so that
+        gcc -Wall will report types that may not have been considered.  */
+      break;
+    }
+}
+
+/* Print the name of the type (or the ultimate pointer target,
+   function value or array element), or the description of a
+   structure or union.
+
+   SHOW nonzero means don't print this type as just its name;
+   show its real definition even if it has a name.
+   SHOW zero means print just typename or struct tag if there is one
+   SHOW negative means abbreviate structure elements.
+   SHOW is decremented for printing of structure elements.
+
+   LEVEL is the depth to indent by.
+   We increase it for some recursive calls.  */
+
+static void
+type_print_base (type, stream, show, level)
+     struct type *type;
+     FILE *stream;
+     int show;
+     int level;
+{
+  char *name;
+  register int i;
+  register int len;
+  register int lastval;
+
+  QUIT;
+
+  if (type == 0)
+    {
+      fprintf_filtered (stream, "type unknown");
+      return;
+    }
+
+  if (TYPE_NAME (type) && show <= 0)
+    {
+      fputs_filtered (TYPE_NAME (type), stream);
+      return;
+    }
+
+  switch (TYPE_CODE (type))
+    {
+    case TYPE_CODE_ARRAY:
+    case TYPE_CODE_PTR:
+    case TYPE_CODE_MEMBER:
+    case TYPE_CODE_REF:
+    case TYPE_CODE_FUNC:
+    case TYPE_CODE_METHOD:
+      type_print_base (TYPE_TARGET_TYPE (type), stream, show, level);
+      break;
+
+    case TYPE_CODE_STRUCT:
+      fprintf_filtered (stream, "struct ");
+      goto struct_union;
+
+    case TYPE_CODE_UNION:
+      fprintf_filtered (stream, "union ");
+    struct_union:
+      if (name = type_name_no_tag (type))
+       {
+         fputs_filtered (name, stream);
+         fputs_filtered (" ", stream);
+       }
+      if (show < 0)
+       fprintf_filtered (stream, "{...}");
+      else
+       {
+         check_stub_type (type);
+         
+         type_print_derivation_info (stream, type);
+         
+         fprintf_filtered (stream, "{");
+         len = TYPE_NFIELDS (type);
+         if (len)
+           fprintf_filtered (stream, "\n");
+         else
+           {
+             if (TYPE_FLAGS (type) & TYPE_FLAG_STUB)
+               fprintf_filtered (stream, "<incomplete type>\n");
+             else
+               fprintf_filtered (stream, "<no data fields>\n");
+           }
+
+         /* If there is a base class for this type,
+            do not print the field that it occupies.  */
+         for (i = TYPE_N_BASECLASSES (type); i < len; i++)
+           {
+             QUIT;
+             /* Don't print out virtual function table.  */
+             if ((TYPE_FIELD_NAME (type, i))[5] == CPLUS_MARKER &&
+                 !strncmp (TYPE_FIELD_NAME (type, i), "_vptr", 5))
+               continue;
+
+             print_spaces_filtered (level + 4, stream);
+             if (TYPE_FIELD_STATIC (type, i))
+               {
+                 fprintf_filtered (stream, "static ");
+               }
+             type_print_1 (TYPE_FIELD_TYPE (type, i),
+                           TYPE_FIELD_NAME (type, i),
+                           stream, show - 1, level + 4);
+             if (!TYPE_FIELD_STATIC (type, i)
+                 && TYPE_FIELD_PACKED (type, i))
+               {
+                 /* It is a bitfield.  This code does not attempt
+                    to look at the bitpos and reconstruct filler,
+                    unnamed fields.  This would lead to misleading
+                    results if the compiler does not put out fields
+                    for such things (I don't know what it does).  */
+                 fprintf_filtered (stream, " : %d",
+                                   TYPE_FIELD_BITSIZE (type, i));
+               }
+             fprintf_filtered (stream, ";\n");
+           }
+
+         /* C++: print out the methods */
+         len = TYPE_NFN_FIELDS (type);
+         if (len) fprintf_filtered (stream, "\n");
+         for (i = 0; i < len; i++)
+           {
+             struct fn_field *f = TYPE_FN_FIELDLIST1 (type, i);
+             int j, len2 = TYPE_FN_FIELDLIST_LENGTH (type, i);
+
+             for (j = 0; j < len2; j++)
+               {
+                 QUIT;
+                 print_spaces_filtered (level + 4, stream);
+                 if (TYPE_FN_FIELD_VIRTUAL_P (f, j))
+                   fprintf_filtered (stream, "virtual ");
+                 else if (TYPE_FN_FIELD_STATIC_P (f, j))
+                   fprintf_filtered (stream, "static ");
+                 type_print (TYPE_TARGET_TYPE (TYPE_FN_FIELD_TYPE (f, j)), "", stream, 0);
+                 if (TYPE_FLAGS (TYPE_FN_FIELD_TYPE (f, j)) & TYPE_FLAG_STUB)
+                   {
+                     /* Build something we can demangle.  */
+                     char *strchr (), *gdb_mangle_typename ();
+                     char *inner_name = gdb_mangle_typename (type);
+                     char *mangled_name
+                       = (char *)xmalloc (strlen (TYPE_FN_FIELDLIST_NAME (type, i))
+                                         + strlen (inner_name)
+                                         + strlen (TYPE_FN_FIELD_PHYSNAME (f, j))
+                                         + 1);
+                     char *demangled_name, *cplus_demangle ();
+                     strcpy (mangled_name, TYPE_FN_FIELDLIST_NAME (type, i));
+                     strcat (mangled_name, inner_name);
+                     strcat (mangled_name, TYPE_FN_FIELD_PHYSNAME (f, j));
+                     demangled_name = cplus_demangle (mangled_name, 1);
+                     if (demangled_name == 0)
+                       fprintf_filtered (stream, " <badly mangled name %s>",
+                           mangled_name);
+                     else 
+                       {
+                         fprintf_filtered (stream, " %s",
+                             strchr (demangled_name, ':') + 2);
+                         free (demangled_name);
+                       }
+                     free (mangled_name);
+                   }
+                 else if (TYPE_FN_FIELD_PHYSNAME (f, j)[0] == '_'
+                       && TYPE_FN_FIELD_PHYSNAME (f, j)[1] == CPLUS_MARKER)
+                   type_print_method_args
+                     (TYPE_FN_FIELD_ARGS (f, j) + 1, "~",
+                      TYPE_FN_FIELDLIST_NAME (type, i), 0, stream);
+                 else
+                   type_print_method_args
+                     (TYPE_FN_FIELD_ARGS (f, j), "",
+                      TYPE_FN_FIELDLIST_NAME (type, i),
+                      TYPE_FN_FIELD_STATIC_P (f, j), stream);
+
+                 fprintf_filtered (stream, ";\n");
+               }
+           }
+
+         print_spaces_filtered (level, stream);
+         fprintf_filtered (stream, "}");
+       }
+      break;
+
+    case TYPE_CODE_ENUM:
+      fprintf_filtered (stream, "enum ");
+      if (name = type_name_no_tag (type))
+       {
+         fputs_filtered (name, stream);
+         fputs_filtered (" ", stream);
+       }
+      if (show < 0)
+       fprintf_filtered (stream, "{...}");
+      else
+       {
+         fprintf_filtered (stream, "{");
+         len = TYPE_NFIELDS (type);
+         lastval = 0;
+         for (i = 0; i < len; i++)
+           {
+             QUIT;
+             if (i) fprintf_filtered (stream, ", ");
+             fputs_filtered (TYPE_FIELD_NAME (type, i), stream);
+             if (lastval != TYPE_FIELD_BITPOS (type, i))
+               {
+                 fprintf_filtered (stream, " = %d", TYPE_FIELD_BITPOS (type, i));
+                 lastval = TYPE_FIELD_BITPOS (type, i);
+               }
+             lastval++;
+           }
+         fprintf_filtered (stream, "}");
+       }
+      break;
+
+    case TYPE_CODE_INT:
+      if (TYPE_LENGTH (type) > sizeof (LONGEST))
+       {
+         fprintf_filtered (stream, "<%d bit integer>",
+                           TYPE_LENGTH (type) * TARGET_CHAR_BIT);
+       }
+      else
+       {
+         if (TYPE_UNSIGNED (type))
+           name = unsigned_type_table[TYPE_LENGTH (type)];
+         else
+           name = signed_type_table[TYPE_LENGTH (type)];
+       }
+      fputs_filtered (name, stream);
+      break;
+
+    case TYPE_CODE_FLT:
+      name = float_type_table[TYPE_LENGTH (type)];
+      fputs_filtered (name, stream);
+      break;
+
+    case TYPE_CODE_VOID:
+      fprintf_filtered (stream, "void");
+      break;
+
+    case 0:
+      fprintf_filtered (stream, "struct unknown");
+      break;
+
+    case TYPE_CODE_ERROR:
+      fprintf_filtered (stream, "<unknown type>");
+      break;
+
+    default:
+      error ("Invalid type code in symbol table.");
+    }
+}
+\f
+/* Validate an input or output radix setting, and make sure the user
+   knows what they really did here.  Radix setting is confusing, e.g.
+   setting the input radix to "10" never changes it!  */
+
+static void
+set_input_radix (args, from_tty, c)
+     char *args;
+     int from_tty;
+     struct cmd_list_element *c;
+{
+  unsigned radix = *(unsigned *)c->var;
+
+  if (from_tty)
+    printf_filtered ("Input radix set to decimal %d, hex %x, octal %o\n",
+       radix, radix, radix);
+}
+
+static void
+set_output_radix (args, from_tty, c)
+     char *args;
+     int from_tty;
+     struct cmd_list_element *c;
+{
+  unsigned radix = *(unsigned *)c->var;
+
+  if (from_tty)
+    printf_filtered ("Output radix set to decimal %d, hex %x, octal %o\n",
+       radix, radix, radix);
+
+  /* FIXME, we really should be able to validate the setting BEFORE
+     it takes effect.  */
+  switch (radix)
+    {
+    case 16:
+      output_format = 'x';
+      break;
+    case 10:
+      output_format = 0;
+      break;
+    case 8:
+      output_format = 'o';             /* octal */
+      break;
+    default:
+      output_format = 0;
+      error ("Unsupported radix ``decimal %d''; using decimal output",
+             radix);
+    }
+}
+
+/* Both at once */
+static void
+set_radix (arg, from_tty, c)
+     char *arg;
+     int from_tty;
+     struct cmd_list_element *c;
+{
+  unsigned radix = *(unsigned *)c->var;
+
+  if (from_tty)
+    printf_filtered ("Radix set to decimal %d, hex %x, octal %o\n",
+       radix, radix, radix);
+
+  input_radix = radix;
+  output_radix = radix;
+
+  set_output_radix (arg, 0, c);
+}
+\f
+void
+_initialize_valprint ()
+{
+  struct cmd_list_element *c;
+
+  add_show_from_set
+    (add_set_cmd ("array-max", class_vars, var_uinteger, (char *)&print_max,
+                 "Set limit on string chars or array elements to print.\n\
+\"set array-max 0\" causes there to be no limit.",
+                 &setlist),
+     &showlist);
+
+  add_show_from_set
+    (add_set_cmd ("prettyprint", class_support, var_boolean, (char *)&prettyprint,
+                 "Set prettyprinting of structures.",
+                 &setlist),
+     &showlist);
+
+  add_alias_cmd ("pp", "prettyprint", class_support, 1, &setlist);
+
+  add_show_from_set
+    (add_set_cmd ("unionprint", class_support, var_boolean, (char *)&unionprint,
+                 "Set printing of unions interior to structures.",
+                 &setlist),
+     &showlist);
+  
+  add_show_from_set
+    (add_set_cmd ("vtblprint", class_support, var_boolean, (char *)&vtblprint,
+                 "Set printing of C++ virtual function tables.",
+                 &setlist),
+     &showlist);
+
+  add_show_from_set
+    (add_set_cmd ("arrayprint", class_support, var_boolean, (char *)&arrayprint,
+                 "Set prettyprinting of arrays.",
+                 &setlist),
+     &showlist);
+
+  add_show_from_set
+    (add_set_cmd ("addressprint", class_support, var_boolean, (char *)&addressprint,
+                 "Set printing of addresses.",
+                 &setlist),
+     &showlist);
+
+#if 0
+  /* The "show radix" cmd isn't good enough to show two separate values.
+     The rest of the code works, but the show part is confusing, so don't
+     let them be set separately 'til we work out "show".  */
+  c = add_set_cmd ("input-radix", class_support, var_uinteger,
+                  (char *)&input_radix,
+                 "Set default input radix for entering numbers.",
+                 &setlist);
+  add_show_from_set (c, &showlist);
+  c->function = set_input_radix;
+
+  c = add_set_cmd ("output-radix", class_support, var_uinteger,
+                  (char *)&output_radix,
+                 "Set default output radix for printing of values.",
+                 &setlist);
+  add_show_from_set (c, &showlist);
+  c->function = set_output_radix;
+#endif 
+
+  c = add_set_cmd ("radix", class_support, var_uinteger,
+                  (char *)&output_radix,
+                 "Set default input and output number radix.",
+                 &setlist);
+  add_show_from_set (c, &showlist);
+  c->function = set_radix;
+
+  /* Give people the defaults which they are used to.  */
+  prettyprint = 0;
+  unionprint = 1;
+  vtblprint = 0;
+  arrayprint = 0;
+  addressprint = 1;
+
+  print_max = 200;
+
+  unsigned_type_table
+    = (char **) xmalloc ((1 + sizeof (unsigned LONGEST)) * sizeof (char *));
+  bzero (unsigned_type_table, (1 + sizeof (unsigned LONGEST)));
+  unsigned_type_table[sizeof (unsigned char)] = "unsigned char";
+  unsigned_type_table[sizeof (unsigned short)] = "unsigned short";
+  unsigned_type_table[sizeof (unsigned long)] = "unsigned long";
+  unsigned_type_table[sizeof (unsigned int)] = "unsigned int";
+#ifdef LONG_LONG
+  unsigned_type_table[sizeof (unsigned long long)] = "unsigned long long";
+#endif
+
+  signed_type_table
+    = (char **) xmalloc ((1 + sizeof (LONGEST)) * sizeof (char *));
+  bzero (signed_type_table, (1 + sizeof (LONGEST)));
+  signed_type_table[sizeof (char)] = "char";
+  signed_type_table[sizeof (short)] = "short";
+  signed_type_table[sizeof (long)] = "long";
+  signed_type_table[sizeof (int)] = "int";
+#ifdef LONG_LONG
+  signed_type_table[sizeof (long long)] = "long long";
+#endif
+
+  float_type_table
+    = (char **) xmalloc ((1 + sizeof (double)) * sizeof (char *));
+  bzero (float_type_table, (1 + sizeof (double)));
+  float_type_table[sizeof (float)] = "float";
+  float_type_table[sizeof (double)] = "double";
+  obstack_begin (&dont_print_obstack, 32 * sizeof (struct type *));
+}
diff --git a/gdb/value.h b/gdb/value.h
new file mode 100644 (file)
index 0000000..e4ac101
--- /dev/null
@@ -0,0 +1,289 @@
+/* Definitions for values of C expressions, for GDB.
+   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.  */
+
+#if !defined (VALUE_H)
+#define VALUE_H 1
+/*
+ * The structure which defines the type of a value.  It should never
+ * be possible for a program lval value to survive over a call to the inferior
+ * (ie to be put into the history list or an internal variable).
+ */
+enum lval_type {
+  /* Not an lval.  */
+  not_lval,
+  /* In memory.  Could be a saved register.  */
+  lval_memory,
+  /* In a register.  */
+  lval_register,
+  /* In a gdb internal variable.  */
+  lval_internalvar,
+  /* Part of a gdb internal variable (structure field).  */
+  lval_internalvar_component,
+  /* In a register series in a frame not the current one, which may have been
+     partially saved or saved in different places (otherwise would be
+     lval_register or lval_memory).  */
+  lval_reg_frame_relative,
+};
+
+struct value
+  {
+    /* Type of value; either not an lval, or one of the various
+       different possible kinds of lval.  */
+    enum lval_type lval;
+    /* Location of value (if lval).  */
+    union
+      {
+       /* Address in inferior or byte of registers structure.  */
+       CORE_ADDR address;
+       /* Pointer to interrnal variable.  */
+       struct internalvar *internalvar;
+       /* Number of register.  Only used with
+          lval_reg_frame_relative.  */
+       int regnum;
+      } location;
+    /* Describes offset of a value within lval a structure in bytes.  */
+    int offset;        
+    /* Only used for bitfields; number of bits contained in them.  */
+    int bitsize;
+    /* Only used for bitfields; position of start of field.  */
+    int bitpos;
+    /* Frame value is relative to.  In practice, this address is only
+       used if the value is stored in several registers in other than
+       the current frame, and these registers have not all been saved
+       at the same place in memory.  This will be described in the
+       lval enum above as "lval_reg_frame_relative".  */
+    CORE_ADDR frame_addr;
+    /* Type of the value.  */
+    struct type *type;
+    /* Values are stored in a chain, so that they can be deleted
+       easily over calls to the inferior.  Values assigned to internal
+       variables or put into the value history are taken off this
+       list.  */
+    struct value *next;
+    /* If an lval is forced to repeat, a new value is created with
+       these fields set.  The new value is not an lval.  */
+    short repeated;
+    short repetitions;
+    /* Register number if the value is from a register.  Is not kept
+       if you take a field of a structure that is stored in a
+       register.  Shouldn't it be?  */
+    short regno;
+    /* If zero, contents of this value are in the contents field.
+       If nonzero, contents are in inferior memory at address
+       in the location.address field plus the offset field
+       (and the lval field should be lval_memory).  */
+    char lazy;
+    /* If nonzero, this is the value of a variable which does not
+       actually exist in the program.  */
+    char optimized_out;
+    /* Actual contents of the value.  For use of this value; setting
+       it uses the stuff above.  Not valid if lazy is nonzero.
+       Target byte-order.  We force it to be aligned properly for any
+       possible value.  */
+    union {
+      long contents[1];
+      double force_double_align;
+#ifdef LONG_LONG
+      long long force_longlong_align;
+#endif
+    } aligner;
+
+  };
+
+typedef struct value *value;
+
+#define VALUE_TYPE(val) (val)->type
+#define VALUE_LAZY(val) (val)->lazy
+/* VALUE_CONTENTS and VALUE_CONTENTS_RAW both return the address of
+   the gdb buffer used to hold a copy of the contents of the lval.  
+   VALUE_CONTENTS is used when the contents of the buffer are needed --
+   it uses value_fetch_lazy() to load the buffer from the process being 
+   debugged if it hasn't already been loaded.  VALUE_CONTENTS_RAW is 
+   used when data is being stored into the buffer, or when it is 
+   certain that the contents of the buffer are valid.  */
+#define VALUE_CONTENTS_RAW(val) ((char *) (val)->aligner.contents)
+#define VALUE_CONTENTS(val) ((void)(VALUE_LAZY(val) && value_fetch_lazy(val)),\
+                            VALUE_CONTENTS_RAW(val))
+extern int value_fetch_lazy ();
+#define VALUE_LVAL(val) (val)->lval
+#define VALUE_ADDRESS(val) (val)->location.address
+#define VALUE_INTERNALVAR(val) (val)->location.internalvar
+#define VALUE_FRAME_REGNUM(val) ((val)->location.regnum)
+#define VALUE_FRAME(val) ((val)->frame_addr)
+#define VALUE_OFFSET(val) (val)->offset
+#define VALUE_BITSIZE(val) (val)->bitsize
+#define VALUE_BITPOS(val) (val)->bitpos
+#define VALUE_NEXT(val) (val)->next
+#define VALUE_REPEATED(val) (val)->repeated
+#define VALUE_REPETITIONS(val) (val)->repetitions
+#define VALUE_REGNO(val) (val)->regno
+#define VALUE_OPTIMIZED_OUT(val) ((val)->optimized_out)
+
+/* Convert a REF to the object referenced. */
+
+#define COERCE_REF(arg)    \
+{ if (TYPE_CODE ( VALUE_TYPE (arg)) == TYPE_CODE_REF)                  \
+    arg = value_at_lazy (TYPE_TARGET_TYPE (VALUE_TYPE (arg)),          \
+                        unpack_long (VALUE_TYPE (arg),                 \
+                                     VALUE_CONTENTS (arg)));}
+
+/* If ARG is an array, convert it to a pointer.
+   If ARG is an enum, convert it to an integer.
+   If ARG is a function, convert it to a function pointer.
+
+   References are dereferenced.  */
+
+#define COERCE_ARRAY(arg)    \
+{ COERCE_REF(arg);                                                     \
+  if (VALUE_REPEATED (arg)                                             \
+      || TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_ARRAY)              \
+    arg = value_coerce_array (arg);                                    \
+  if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_FUNC)                   \
+    arg = value_coerce_function (arg);                                  \
+  if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_ENUM)                  \
+    arg = value_cast (builtin_type_unsigned_int, arg);                 \
+}
+
+/* If ARG is an enum, convert it to an integer.  */
+
+#define COERCE_ENUM(arg)    \
+{ if (TYPE_CODE ( VALUE_TYPE (arg)) == TYPE_CODE_REF)                  \
+    arg = value_ind (arg);                                             \
+  if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_ENUM)                  \
+    arg = value_cast (builtin_type_unsigned_int, arg);                 \
+}
+
+/* Internal variables (variables for convenience of use of debugger)
+   are recorded as a chain of these structures.  */
+
+struct internalvar
+{
+  struct internalvar *next;
+  char *name;
+  value value;
+};
+\f
+#include "symtab.h"
+LONGEST value_as_long ();
+double value_as_double ();
+LONGEST unpack_long ();
+double unpack_double ();
+long unpack_field_as_long ();
+value value_from_long ();
+value value_from_double ();
+value value_at ();
+value value_at_lazy ();
+value value_from_register ();
+value value_of_variable ();
+value value_of_register ();
+value read_var_value ();
+value locate_var_value ();
+value allocate_value ();
+value allocate_repeat_value ();
+value value_string ();
+
+value value_binop ();
+value value_add ();
+value value_sub ();
+value value_coerce_array ();
+value value_coerce_function ();
+value value_ind ();
+value value_addr ();
+value value_assign ();
+value value_neg ();
+value value_lognot ();
+value value_struct_elt (), value_struct_elt_for_address ();
+value value_field (), value_primitive_field ();
+value value_cast ();
+value value_zero ();
+value value_repeat ();
+value value_subscript ();
+
+value value_being_returned ();
+int using_struct_return ();
+void set_return_value ();
+
+value evaluate_expression ();
+value evaluate_type ();
+value parse_and_eval ();
+value parse_to_comma_and_eval ();
+extern CORE_ADDR parse_and_eval_address ();
+extern CORE_ADDR parse_and_eval_address_1 ();
+
+value access_value_history ();
+value value_of_internalvar ();
+void set_internalvar ();
+void set_internalvar_component ();
+struct internalvar *lookup_internalvar ();
+
+int value_equal ();
+int value_less ();
+int value_zerop ();
+
+/* C++ */
+value value_of_this ();
+value value_static_field ();
+value value_x_binop ();
+value value_x_unop ();
+value value_fn_field ();
+value value_virtual_fn_field ();
+value value_static_field ();
+int binop_user_defined_p ();
+int unop_user_defined_p ();
+int typecmp ();
+int fill_in_vptr_fieldno ();
+int destructor_name_p ();
+
+#define value_free(val) free (val)
+void free_all_values ();
+void release_value ();
+int record_latest_value ();
+
+void registers_changed ();
+void read_register_bytes ();
+void write_register_bytes ();
+void read_register_gen ();
+CORE_ADDR read_register ();
+void write_register ();
+void supply_register ();
+void get_saved_register ();
+
+void modify_field ();
+void type_print ();
+void type_print_1 ();
+
+/* Possibilities for prettyprint parameters to routines which print
+   things.  */
+enum val_prettyprint {
+  Val_no_prettyprint = 0,
+  Val_prettyprint,
+  /* Use the default setting which the user has specified.  */
+  Val_pretty_default
+  };
+
+char *baseclass_addr ();
+void print_floating ();
+int value_print ();
+int val_print ();
+void print_variable_value ();
+char *internalvar_name ();
+void clear_value_history ();
+void clear_internalvars ();
+
+#endif /* value.h not already included.  */
diff --git a/readline/COPYING b/readline/COPYING
new file mode 100644 (file)
index 0000000..9a17037
--- /dev/null
@@ -0,0 +1,249 @@
+
+                   GNU GENERAL PUBLIC LICENSE
+                    Version 1, February 1989
+
+ Copyright (C) 1989 Free Software Foundation, Inc.
+                    675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The license agreements of most software companies try to keep users
+at the mercy of those companies.  By contrast, our General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  The
+General Public License applies to the Free Software Foundation's
+software and to any other program whose authors commit to using it.
+You can use it for your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Specifically, the General Public License is designed to make
+sure that you have the freedom to give away or sell copies of free
+software, that you receive source code or can get it if you want it,
+that you can change the software or use pieces of it in new free
+programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of a such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must tell them their rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any program or other work which
+contains a notice placed by the copyright holder saying it may be
+distributed under the terms of this General Public License.  The
+"Program", below, refers to any such program or work, and a "work based
+on the Program" means either the Program or any work containing the
+Program or a portion of it, either verbatim or with modifications.  Each
+licensee is addressed as "you".
+
+  1. You may copy and distribute verbatim copies of the Program's source
+code as you receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice and
+disclaimer of warranty; keep intact all the notices that refer to this
+General Public License and to the absence of any warranty; and give any
+other recipients of the Program a copy of this General Public License
+along with the Program.  You may charge a fee for the physical act of
+transferring a copy.
+
+  2. You may modify your copy or copies of the Program or any portion of
+it, and copy and distribute such modifications under the terms of Paragraph
+1 above, provided that you also do the following:
+
+    a) cause the modified files to carry prominent notices stating that
+    you changed the files and the date of any change; and
+
+    b) cause the whole of any work that you distribute or publish, that
+    in whole or in part contains the Program or any part thereof, either
+    with or without modifications, to be licensed at no charge to all
+    third parties under the terms of this General Public License (except
+    that you may choose to grant warranty protection to some or all
+    third parties, at your option).
+
+    c) If the modified program normally reads commands interactively when
+    run, you must cause it, when started running for such interactive use
+    in the simplest and most usual way, to print or display an
+    announcement including an appropriate copyright notice and a notice
+    that there is no warranty (or else, saying that you provide a
+    warranty) and that users may redistribute the program under these
+    conditions, and telling the user how to view a copy of this General
+    Public License.
+
+    d) You may charge a fee for the physical act of transferring a
+    copy, and you may at your option offer warranty protection in
+    exchange for a fee.
+
+Mere aggregation of another independent work with the Program (or its
+derivative) on a volume of a storage or distribution medium does not bring
+the other work under the scope of these terms.
+\f
+  3. You may copy and distribute the Program (or a portion or derivative of
+it, under Paragraph 2) in object code or executable form under the terms of
+Paragraphs 1 and 2 above provided that you also do one of the following:
+
+    a) accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of
+    Paragraphs 1 and 2 above; or,
+
+    b) accompany it with a written offer, valid for at least three
+    years, to give any third party free (except for a nominal charge
+    for the cost of distribution) a complete machine-readable copy of the
+    corresponding source code, to be distributed under the terms of
+    Paragraphs 1 and 2 above; or,
+
+    c) accompany it with the information you received as to where the
+    corresponding source code may be obtained.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form alone.)
+
+Source code for a work means the preferred form of the work for making
+modifications to it.  For an executable file, complete source code means
+all the source code for all modules it contains; but, as a special
+exception, it need not include source code for modules which are standard
+libraries that accompany the operating system on which the executable
+file runs, or for standard header files or definitions files that
+accompany that operating system.
+
+  4. You may not copy, modify, sublicense, distribute or transfer the
+Program except as expressly provided under this General Public License.
+Any attempt otherwise to copy, modify, sublicense, distribute or transfer
+the Program is void, and will automatically terminate your rights to use
+the Program under this License.  However, parties who have received
+copies, or rights to use copies, from you under this General Public
+License will not have their licenses terminated so long as such parties
+remain in full compliance.
+
+  5. By copying, distributing or modifying the Program (or any work based
+on the Program) you indicate your acceptance of this license to do so,
+and all its terms and conditions.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the original
+licensor to copy, distribute or modify the Program subject to these
+terms and conditions.  You may not impose any further restrictions on the
+recipients' exercise of the rights granted herein.
+\f
+  7. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of the license which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+the license, you may choose any version ever published by the Free Software
+Foundation.
+
+  8. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+       Appendix: How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to humanity, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these
+terms.
+
+  To do so, attach the following notices to the program.  It is safest to
+attach them to the start of each source file to most effectively convey
+the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 1, or (at your option)
+    any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19xx name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the
+appropriate parts of the General Public License.  Of course, the
+commands you use may be called something other than `show w' and `show
+c'; they could even be mouse-clicks or menu items--whatever suits your
+program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  program `Gnomovision' (a program to direct compilers to make passes
+  at assemblers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/readline/Makefile.in b/readline/Makefile.in
new file mode 100644 (file)
index 0000000..4fb6ceb
--- /dev/null
@@ -0,0 +1,103 @@
+## -*- text -*- ####################################################
+#                                                                 #
+# Makefile for readline and history libraries.                    #
+#                                                                 #
+####################################################################
+
+# Here is a rule for making .o files from .c files that doesn't force
+# the type of the machine (like -sun3) into the flags.
+.c.o:
+       $(CC) -c $(CFLAGS) $(LOCAL_INCLUDES) $(CPPFLAGS) $(READLINE_DEFINES) $<
+
+# Destination installation directory.  The libraries are copied to DESTDIR
+# when you do a `make install', and the header files to INCDIR/readline/*.h.
+DESTDIR = /usr/local/lib
+INCDIR = /usr/local/include
+
+# Define TYPES as -DVOID_SIGHANDLER if your operating system uses
+# a return type of "void" for signal handlers.
+TYPES = -DVOID_SIGHANDLER
+
+# Define SYSV as -DSYSV if you are using a System V operating system.
+#SYSV = -DSYSV
+
+# HP-UX compilation requires the BSD library.
+#LOCAL_LIBS = -lBSD
+
+# Xenix compilation requires -ldir -lx
+#LOCAL_LIBS = -ldir -lx
+
+# Comment out "-DVI_MODE" if you don't think that anyone will ever desire
+# the vi line editing mode and features.
+READLINE_DEFINES = $(TYPES) -DVI_MODE
+
+DEBUG_FLAGS = -g
+LDFLAGS = $(DEBUG_FLAGS) 
+CFLAGS = $(DEBUG_FLAGS) $(SYSV) -I.
+
+# A good alternative is gcc -traditional.
+#CC = gcc -traditional
+CC = cc
+RANLIB = /usr/bin/ranlib
+AR = ar
+RM = rm
+CP = cp
+
+LOCAL_INCLUDES = -I../
+
+CSOURCES = readline.c history.c funmap.c keymaps.c vi_mode.c \
+          emacs_keymap.c vi_keymap.c
+
+HSOURCES = readline.h chardefs.h history.h keymaps.h
+SOURCES  = $(CSOURCES) $(HSOURCES)
+
+DOCUMENTATION = readline.texinfo inc-readline.texinfo \
+               history.texinfo inc-history.texinfo
+
+SUPPORT = COPYING Makefile $(DOCUMENTATION) ChangeLog
+
+THINGS_TO_TAR = $(SOURCES) $(SUPPORT)
+
+##########################################################################
+
+all: libreadline.a
+
+libreadline.a: readline.o history.o funmap.o keymaps.o
+               $(RM) -f libreadline.a
+               $(AR) clq libreadline.a readline.o history.o funmap.o keymaps.o
+               -if [ -f $(RANLIB) ]; then $(RANLIB) libreadline.a; fi
+
+readline.o:    readline.h chardefs.h  keymaps.h history.h readline.c vi_mode.c
+history.o:     history.c history.h
+funmap.o:      readline.h
+keymaps.o:     emacs_keymap.c vi_keymap.c keymaps.h chardefs.h keymaps.c
+
+libtest:       libreadline.a libtest.c
+               $(CC) -o libtest $(CFLAGS) $(CPPFLAGS) -L. libtest.c -lreadline -ltermcap
+
+readline: readline.c history.o keymaps.o funmap.o readline.h chardefs.h
+       $(CC) $(CFLAGS) $(CPPFLAGS) $(READLINE_DEFINES) \
+               $(LOCAL_INCLUDES) -DTEST -o readline readline.c funmap.o \
+                keymaps.o history.o -L. -ltermcap
+
+readline.tar:  $(THINGS_TO_TAR)
+               tar -cf readline.tar $(THINGS_TO_TAR)
+
+readline.tar.Z:        readline.tar
+               compress -f readline.tar
+
+install:       $(DESTDIR)/libreadline.a includes
+
+includes:
+               if [ ! -r $(INCDIR)/readline ]; then\
+                mkdir $(INCDIR)/readline;\
+                chmod a+r $(INCDIR)/readline;\
+               fi
+               $(CP) readline.h keymaps.h chardefs.h $(INCDIR)/readline/
+clean:
+               rm -f *.o *.a *.log *.cp *.tp *.vr *.fn *.aux *.pg *.toc
+
+$(DESTDIR)/libreadline.a: libreadline.a
+               -mv $(DESTDIR)/libreadline.a $(DESTDIR)/libreadline.old
+               cp libreadline.a $(DESTDIR)/libreadline.a
+               $(RANLIB) -t $(DESTDIR)/libreadline.a
diff --git a/readline/chardefs.h b/readline/chardefs.h
new file mode 100644 (file)
index 0000000..9749ae4
--- /dev/null
@@ -0,0 +1,50 @@
+/* chardefs.h -- Character definitions for readline. */
+#ifndef _CHARDEFS_
+
+#ifndef savestring
+#define savestring(x) (char *)strcpy (xmalloc (1 + strlen (x)), (x))
+#endif
+
+#ifndef whitespace
+#define whitespace(c) (((c) == ' ') || ((c) == '\t'))
+#endif
+
+#ifdef CTRL
+#undef CTRL
+#endif
+
+/* Some character stuff. */
+#define control_character_threshold 0x020   /* smaller than this is control */
+#define meta_character_threshold 0x07f     /* larger than this is Meta. */
+#define control_character_bit 0x40         /* 0x000000, must be off. */
+#define meta_character_bit 0x080           /* x0000000, must be on. */
+
+#define CTRL(c) ((c) & (~control_character_bit))
+#define META(c) ((c) | meta_character_bit)
+
+#define UNMETA(c) ((c) & (~meta_character_bit))
+#define UNCTRL(c) to_upper(((c)|control_character_bit))
+
+#define lowercase_p(c) (((c) > ('a' - 1) && (c) < ('z' + 1)))
+#define uppercase_p(c) (((c) > ('A' - 1) && (c) < ('Z' + 1)))
+
+#define pure_alphabetic(c) (lowercase_p(c) || uppercase_p(c))
+
+#ifndef to_upper
+#define to_upper(c) (lowercase_p(c) ? ((c) - 32) : (c))
+#define to_lower(c) (uppercase_p(c) ? ((c) + 32) : (c))
+#endif
+
+#define CTRL_P(c) ((c) < control_character_threshold)
+#define META_P(c) ((c) > meta_character_threshold)
+
+#define NEWLINE '\n'
+#define RETURN CTRL('M')
+#define RUBOUT 0x07f
+#define TAB '\t'
+#define ABORT_CHAR CTRL('G')
+#define PAGE CTRL('L')
+#define SPACE 0x020
+#define ESC CTRL('[')
+
+#endif  /* _CHARDEFS_ */
diff --git a/readline/emacs_keymap.c b/readline/emacs_keymap.c
new file mode 100644 (file)
index 0000000..24961de
--- /dev/null
@@ -0,0 +1,472 @@
+/* emacs_keymap.c -- the keymap for emacs_mode in readline (). */
+
+/* Copyright (C) 1988,1989 Free Software Foundation, Inc.
+
+   This file is part of GNU Readline, a library for reading lines
+   of text with interactive input and history editing.
+
+   Readline 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.
+
+   Readline 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 Readline; see the file COPYING.  If not, write to the Free
+   Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef BUFSIZ
+#include <stdio.h>
+#endif /* BUFSIZ */
+
+#include "readline.h"
+
+/* An array of function pointers, one for each possible key.
+   If the type byte is ISKMAP, then the pointer is the address of
+   a keymap. */
+
+KEYMAP_ENTRY_ARRAY emacs_standard_keymap = {
+
+  /* Control keys. */
+  { ISFUNC, (Function *)0x0 },         /* Control-@ */
+  { ISFUNC, rl_beg_of_line },          /* Control-a */
+  { ISFUNC, rl_backward },             /* Control-b */
+  { ISFUNC, (Function *)0x0 },         /* Control-c */
+  { ISFUNC, rl_delete },               /* Control-d */
+  { ISFUNC, rl_end_of_line },          /* Control-e */
+  { ISFUNC, rl_forward },              /* Control-f */
+  { ISFUNC, rl_abort },                        /* Control-g */
+  { ISFUNC, rl_backward },             /* Control-h */
+  { ISFUNC, rl_complete },             /* Control-i */
+  { ISFUNC, rl_newline },              /* Control-j */
+  { ISFUNC, rl_kill_line },            /* Control-k */
+  { ISFUNC, rl_clear_screen },         /* Control-l */
+  { ISFUNC, rl_newline },              /* Control-m */
+  { ISFUNC, rl_get_next_history },     /* Control-n */
+  { ISFUNC, (Function *)0x0 },         /* Control-o */
+  { ISFUNC, rl_get_previous_history }, /* Control-p */
+  { ISFUNC, rl_quoted_insert },                /* Control-q */
+  { ISFUNC, rl_reverse_search_history }, /* Control-r */
+  { ISFUNC, rl_forward_search_history }, /* Control-s */
+  { ISFUNC, rl_transpose_chars },      /* Control-t */
+  { ISFUNC, rl_unix_line_discard },    /* Control-u */
+  { ISFUNC, rl_quoted_insert },                /* Control-v */
+  { ISFUNC, rl_unix_word_rubout },     /* Control-w */
+  { ISKMAP, (Function *)emacs_ctlx_keymap },   /* Control-x */
+  { ISFUNC, rl_yank },                 /* Control-y */
+  { ISFUNC, (Function *)0x0 },         /* Control-z */
+  { ISKMAP, (Function *)emacs_meta_keymap }, /* Control-[ */
+  { ISFUNC, (Function *)0x0 },         /* Control-\ */
+  { ISFUNC, (Function *)0x0 },         /* Control-] */
+  { ISFUNC, (Function *)0x0 },         /* Control-^ */
+  { ISFUNC, rl_undo_command },         /* Control-_ */
+
+  /* The start of printing characters. */
+  { ISFUNC, rl_insert },       /* SPACE */
+  { ISFUNC, rl_insert },       /* ! */
+  { ISFUNC, rl_insert },       /* " */
+  { ISFUNC, rl_insert },       /* # */
+  { ISFUNC, rl_insert },       /* $ */
+  { ISFUNC, rl_insert },       /* % */
+  { ISFUNC, rl_insert },       /* & */
+  { ISFUNC, rl_insert },       /* ' */
+  { ISFUNC, rl_insert },       /* ( */
+  { ISFUNC, rl_insert },       /* ) */
+  { ISFUNC, rl_insert },       /* * */
+  { ISFUNC, rl_insert },       /* + */
+  { ISFUNC, rl_insert },       /* , */
+  { ISFUNC, rl_insert },       /* - */
+  { ISFUNC, rl_insert },       /* . */
+  { ISFUNC, rl_insert },       /* / */
+
+  /* Regular digits. */
+  { ISFUNC, rl_insert },       /* 0 */
+  { ISFUNC, rl_insert },       /* 1 */
+  { ISFUNC, rl_insert },       /* 2 */
+  { ISFUNC, rl_insert },       /* 3 */
+  { ISFUNC, rl_insert },       /* 4 */
+  { ISFUNC, rl_insert },       /* 5 */
+  { ISFUNC, rl_insert },       /* 6 */
+  { ISFUNC, rl_insert },       /* 7 */
+  { ISFUNC, rl_insert },       /* 8 */
+  { ISFUNC, rl_insert },       /* 9 */
+
+  /* A little more punctuation. */
+  { ISFUNC, rl_insert },       /* : */
+  { ISFUNC, rl_insert },       /* ; */
+  { ISFUNC, rl_insert },       /* < */
+  { ISFUNC, rl_insert },       /* = */
+  { ISFUNC, rl_insert },       /* > */
+  { ISFUNC, rl_insert },       /* ? */
+  { ISFUNC, rl_insert },       /* @ */
+
+  /* Uppercase alphabet. */
+  { ISFUNC, rl_insert },       /* A */
+  { ISFUNC, rl_insert },       /* B */
+  { ISFUNC, rl_insert },       /* C */
+  { ISFUNC, rl_insert },       /* D */
+  { ISFUNC, rl_insert },       /* E */
+  { ISFUNC, rl_insert },       /* F */
+  { ISFUNC, rl_insert },       /* G */
+  { ISFUNC, rl_insert },       /* H */
+  { ISFUNC, rl_insert },       /* I */
+  { ISFUNC, rl_insert },       /* J */
+  { ISFUNC, rl_insert },       /* K */
+  { ISFUNC, rl_insert },       /* L */
+  { ISFUNC, rl_insert },       /* M */
+  { ISFUNC, rl_insert },       /* N */
+  { ISFUNC, rl_insert },       /* O */
+  { ISFUNC, rl_insert },       /* P */
+  { ISFUNC, rl_insert },       /* Q */
+  { ISFUNC, rl_insert },       /* R */
+  { ISFUNC, rl_insert },       /* S */
+  { ISFUNC, rl_insert },       /* T */
+  { ISFUNC, rl_insert },       /* U */
+  { ISFUNC, rl_insert },       /* V */
+  { ISFUNC, rl_insert },       /* W */
+  { ISFUNC, rl_insert },       /* X */
+  { ISFUNC, rl_insert },       /* Y */
+  { ISFUNC, rl_insert },       /* Z */
+
+  /* Some more punctuation. */
+  { ISFUNC, rl_insert },       /* [ */
+  { ISFUNC, rl_insert },       /* \ */
+  { ISFUNC, rl_insert },       /* ] */
+  { ISFUNC, rl_insert },       /* ^ */
+  { ISFUNC, rl_insert },       /* _ */
+  { ISFUNC, rl_insert },       /* ` */
+
+  /* Lowercase alphabet. */
+  { ISFUNC, rl_insert },       /* a */
+  { ISFUNC, rl_insert },       /* b */
+  { ISFUNC, rl_insert },       /* c */
+  { ISFUNC, rl_insert },       /* d */
+  { ISFUNC, rl_insert },       /* e */
+  { ISFUNC, rl_insert },       /* f */
+  { ISFUNC, rl_insert },       /* g */
+  { ISFUNC, rl_insert },       /* h */
+  { ISFUNC, rl_insert },       /* i */
+  { ISFUNC, rl_insert },       /* j */
+  { ISFUNC, rl_insert },       /* k */
+  { ISFUNC, rl_insert },       /* l */
+  { ISFUNC, rl_insert },       /* m */
+  { ISFUNC, rl_insert },       /* n */
+  { ISFUNC, rl_insert },       /* o */
+  { ISFUNC, rl_insert },       /* p */
+  { ISFUNC, rl_insert },       /* q */
+  { ISFUNC, rl_insert },       /* r */
+  { ISFUNC, rl_insert },       /* s */
+  { ISFUNC, rl_insert },       /* t */
+  { ISFUNC, rl_insert },       /* u */
+  { ISFUNC, rl_insert },       /* v */
+  { ISFUNC, rl_insert },       /* w */
+  { ISFUNC, rl_insert },       /* x */
+  { ISFUNC, rl_insert },       /* y */
+  { ISFUNC, rl_insert },       /* z */
+
+  /* Final punctuation. */
+  { ISFUNC, rl_insert },       /* { */
+  { ISFUNC, rl_insert },       /* | */
+  { ISFUNC, rl_insert },       /* } */
+  { ISFUNC, rl_insert },       /* ~ */
+  { ISFUNC, rl_rubout }                /* RUBOUT */
+};
+
+KEYMAP_ENTRY_ARRAY emacs_meta_keymap = {
+
+  /* Meta keys.  Just like above, but the high bit is set. */
+  { ISFUNC, (Function *)0x0 }, /* Meta-Control-@ */
+  { ISFUNC, (Function *)0x0 }, /* Meta-Control-a */
+  { ISFUNC, (Function *)0x0 }, /* Meta-Control-b */
+  { ISFUNC, (Function *)0x0 }, /* Meta-Control-c */
+  { ISFUNC, (Function *)0x0 }, /* Meta-Control-d */
+  { ISFUNC, (Function *)0x0 }, /* Meta-Control-e */
+  { ISFUNC, (Function *)0x0 }, /* Meta-Control-f */
+  { ISFUNC, rl_abort },                /* Meta-Control-g */
+  { ISFUNC, (Function *)0x0 }, /* Meta-Control-h */
+  { ISFUNC, (Function *)0x0 }, /* Meta-Control-i */
+  { ISFUNC, rl_vi_editing_mode }, /* Meta-Control-j */
+  { ISFUNC, (Function *)0x0 }, /* Meta-Control-k */
+  { ISFUNC, (Function *)0x0 }, /* Meta-Control-l */
+  { ISFUNC, rl_vi_editing_mode }, /* Meta-Control-m */
+  { ISFUNC, (Function *)0x0 }, /* Meta-Control-n */
+  { ISFUNC, (Function *)0x0 }, /* Meta-Control-o */
+  { ISFUNC, (Function *)0x0 }, /* Meta-Control-p */
+  { ISFUNC, (Function *)0x0 }, /* Meta-Control-q */
+  { ISFUNC, rl_revert_line },  /* Meta-Control-r */
+  { ISFUNC, (Function *)0x0 }, /* Meta-Control-s */
+  { ISFUNC, (Function *)0x0 }, /* Meta-Control-t */
+  { ISFUNC, (Function *)0x0 }, /* Meta-Control-u */
+  { ISFUNC, (Function *)0x0 }, /* Meta-Control-v */
+  { ISFUNC, (Function *)0x0 }, /* Meta-Control-w */
+  { ISFUNC, (Function *)0x0 }, /* Meta-Control-x */
+  { ISFUNC, rl_yank_nth_arg }, /* Meta-Control-y */
+  { ISFUNC, (Function *)0x0 }, /* Meta-Control-z */
+
+  { ISFUNC, (Function *)0x0 }, /* Meta-Control-[ */
+  { ISFUNC, (Function *)0x0 }, /* Meta-Control-\ */
+  { ISFUNC, (Function *)0x0 }, /* Meta-Control-] */
+  { ISFUNC, (Function *)0x0 }, /* Meta-Control-^ */
+  { ISFUNC, (Function *)0x0 }, /* Meta-Control-_ */
+
+  /* The start of printing characters. */
+  { ISFUNC, (Function *)0x0 }, /* Meta-SPACE */
+  { ISFUNC, (Function *)0x0 }, /* Meta-! */
+  { ISFUNC, (Function *)0x0 }, /* Meta-" */
+  { ISFUNC, (Function *)0x0 }, /* Meta-# */
+  { ISFUNC, (Function *)0x0 }, /* Meta-$ */
+  { ISFUNC, (Function *)0x0 }, /* Meta-% */
+  { ISFUNC, (Function *)0x0 }, /* Meta-& */
+  { ISFUNC, (Function *)0x0 }, /* Meta-' */
+  { ISFUNC, (Function *)0x0 }, /* Meta-( */
+  { ISFUNC, (Function *)0x0 }, /* Meta-) */
+  { ISFUNC, (Function *)0x0 }, /* Meta-* */
+  { ISFUNC, (Function *)0x0 }, /* Meta-+ */
+  { ISFUNC, (Function *)0x0 }, /* Meta-, */
+  { ISFUNC, rl_digit_argument }, /* Meta-- */
+  { ISFUNC, (Function *)0x0 }, /* Meta-. */
+  { ISFUNC, (Function *)0x0 }, /* Meta-/ */
+
+  /* Regular digits. */
+  { ISFUNC, rl_digit_argument }, /* Meta-0 */
+  { ISFUNC, rl_digit_argument }, /* Meta-1 */
+  { ISFUNC, rl_digit_argument }, /* Meta-2 */
+  { ISFUNC, rl_digit_argument }, /* Meta-3 */
+  { ISFUNC, rl_digit_argument }, /* Meta-4 */
+  { ISFUNC, rl_digit_argument }, /* Meta-5 */
+  { ISFUNC, rl_digit_argument }, /* Meta-6 */
+  { ISFUNC, rl_digit_argument }, /* Meta-7 */
+  { ISFUNC, rl_digit_argument }, /* Meta-8 */
+  { ISFUNC, rl_digit_argument }, /* Meta-9 */
+
+  /* A little more punctuation. */
+  { ISFUNC, (Function *)0x0 },         /* Meta-: */
+  { ISFUNC, (Function *)0x0 },         /* Meta-; */
+  { ISFUNC, rl_beginning_of_history }, /* Meta-< */
+  { ISFUNC, (Function *)0x0 },         /* Meta-= */
+  { ISFUNC, rl_end_of_history },       /* Meta-> */
+  { ISFUNC, rl_possible_completions }, /* Meta-? */
+  { ISFUNC, (Function *)0x0 },         /* Meta-@ */
+
+  /* Uppercase alphabet. */
+  { ISFUNC, rl_do_lowercase_version }, /* Meta-A */
+  { ISFUNC, rl_do_lowercase_version }, /* Meta-B */
+  { ISFUNC, rl_do_lowercase_version }, /* Meta-C */
+  { ISFUNC, rl_do_lowercase_version }, /* Meta-D */
+  { ISFUNC, rl_do_lowercase_version }, /* Meta-E */
+  { ISFUNC, rl_do_lowercase_version }, /* Meta-F */
+  { ISFUNC, rl_do_lowercase_version }, /* Meta-G */
+  { ISFUNC, rl_do_lowercase_version }, /* Meta-H */
+  { ISFUNC, rl_do_lowercase_version }, /* Meta-I */
+  { ISFUNC, rl_do_lowercase_version }, /* Meta-J */
+  { ISFUNC, rl_do_lowercase_version }, /* Meta-K */
+  { ISFUNC, rl_do_lowercase_version }, /* Meta-L */
+  { ISFUNC, rl_do_lowercase_version }, /* Meta-M */
+  { ISFUNC, rl_do_lowercase_version }, /* Meta-N */
+  { ISFUNC, rl_do_lowercase_version }, /* Meta-O */
+  { ISFUNC, rl_do_lowercase_version }, /* Meta-P */
+  { ISFUNC, rl_do_lowercase_version }, /* Meta-Q */
+  { ISFUNC, rl_do_lowercase_version }, /* Meta-R */
+  { ISFUNC, rl_do_lowercase_version }, /* Meta-S */
+  { ISFUNC, rl_do_lowercase_version }, /* Meta-T */
+  { ISFUNC, rl_do_lowercase_version }, /* Meta-U */
+  { ISFUNC, rl_do_lowercase_version }, /* Meta-V */
+  { ISFUNC, rl_do_lowercase_version }, /* Meta-W */
+  { ISFUNC, rl_do_lowercase_version }, /* Meta-X */
+  { ISFUNC, rl_do_lowercase_version }, /* Meta-Y */
+  { ISFUNC, rl_do_lowercase_version }, /* Meta-Z */
+
+  /* Some more punctuation. */
+  { ISFUNC, (Function *)0x0 }, /* Meta-[ */
+  { ISFUNC, (Function *)0x0 }, /* Meta-\ */
+  { ISFUNC, (Function *)0x0 }, /* Meta-] */
+  { ISFUNC, (Function *)0x0 }, /* Meta-^ */
+  { ISFUNC, (Function *)0x0 }, /* Meta-_ */
+  { ISFUNC, (Function *)0x0 }, /* Meta-` */
+
+  /* Lowercase alphabet. */
+  { ISFUNC, (Function *)0x0 }, /* Meta-a */
+  { ISFUNC, rl_backward_word },        /* Meta-b */
+  { ISFUNC, rl_capitalize_word }, /* Meta-c */
+  { ISFUNC, rl_kill_word },    /* Meta-d */
+  { ISFUNC, (Function *)0x0 }, /* Meta-e */
+  { ISFUNC, rl_forward_word }, /* Meta-f */
+  { ISFUNC, (Function *)0x0 }, /* Meta-g */
+  { ISFUNC, (Function *)0x0 }, /* Meta-h */
+  { ISFUNC, (Function *)0x0 }, /* Meta-i */
+  { ISFUNC, (Function *)0x0 }, /* Meta-j */
+  { ISFUNC, (Function *)0x0 }, /* Meta-k */
+  { ISFUNC, rl_downcase_word },        /* Meta-l */
+  { ISFUNC, (Function *)0x0 }, /* Meta-m */
+  { ISFUNC, (Function *)0x0 }, /* Meta-n */
+  { ISFUNC, (Function *)0x0 }, /* Meta-o */
+  { ISFUNC, (Function *)0x0 }, /* Meta-p */
+  { ISFUNC, (Function *)0x0 }, /* Meta-q */
+  { ISFUNC, rl_revert_line },  /* Meta-r */
+  { ISFUNC, (Function *)0x0 }, /* Meta-s */
+  { ISFUNC, rl_transpose_words }, /* Meta-t */
+  { ISFUNC, rl_upcase_word },  /* Meta-u */
+  { ISFUNC, (Function *)0x0 }, /* Meta-v */
+  { ISFUNC, (Function *)0x0 }, /* Meta-w */
+  { ISFUNC, (Function *)0x0 }, /* Meta-x */
+  { ISFUNC, rl_yank_pop },     /* Meta-y */
+  { ISFUNC, (Function *)0x0 }, /* Meta-z */
+
+  /* Final punctuation. */
+  { ISFUNC, (Function *)0x0 }, /* Meta-{ */
+  { ISFUNC, (Function *)0x0 }, /* Meta-| */
+  { ISFUNC, (Function *)0x0 }, /* Meta-} */
+  { ISFUNC, (Function *)0x0 }, /* Meta-~ */
+  { ISFUNC, rl_backward_kill_word } /* Meta-rubout */
+};
+
+KEYMAP_ENTRY_ARRAY emacs_ctlx_keymap = {
+
+  /* Control keys. */
+  { ISFUNC, (Function *)0x0 },         /* Control-@ */
+  { ISFUNC, (Function *)0x0 },         /* Control-a */
+  { ISFUNC, (Function *)0x0 },         /* Control-b */
+  { ISFUNC, (Function *)0x0 },         /* Control-c */
+  { ISFUNC, (Function *)0x0 },         /* Control-d */
+  { ISFUNC, (Function *)0x0 },         /* Control-e */
+  { ISFUNC, (Function *)0x0 },         /* Control-f */
+  { ISFUNC, rl_abort },                        /* Control-g */
+  { ISFUNC, (Function *)0x0 },         /* Control-h */
+  { ISFUNC, (Function *)0x0 },         /* Control-i */
+  { ISFUNC, (Function *)0x0 },         /* Control-j */
+  { ISFUNC, (Function *)0x0 },         /* Control-k */
+  { ISFUNC, (Function *)0x0 },         /* Control-l */
+  { ISFUNC, (Function *)0x0 },         /* Control-m */
+  { ISFUNC, (Function *)0x0 },         /* Control-n */
+  { ISFUNC, (Function *)0x0 },         /* Control-o */
+  { ISFUNC, (Function *)0x0 },         /* Control-p */
+  { ISFUNC, (Function *)0x0 },         /* Control-q */
+  { ISFUNC, rl_re_read_init_file },    /* Control-r */
+  { ISFUNC, (Function *)0x0 },         /* Control-s */
+  { ISFUNC, (Function *)0x0 },         /* Control-t */
+  { ISFUNC, rl_undo_command },         /* Control-u */
+  { ISFUNC, (Function *)0x0 },         /* Control-v */
+  { ISFUNC, (Function *)0x0 },         /* Control-w */
+  { ISFUNC, (Function *)0x0 },         /* Control-x */
+  { ISFUNC, (Function *)0x0 },         /* Control-y */
+  { ISFUNC, (Function *)0x0 },         /* Control-z */
+  { ISFUNC, (Function *)0x0 },         /* Control-[ */
+  { ISFUNC, (Function *)0x0 },         /* Control-\ */
+  { ISFUNC, (Function *)0x0 },         /* Control-] */
+  { ISFUNC, (Function *)0x0 },         /* Control-^ */
+  { ISFUNC, (Function *)0x0 },         /* Control-_ */
+
+  /* The start of printing characters. */
+  { ISFUNC, (Function *)0x0 },         /* SPACE */
+  { ISFUNC, (Function *)0x0 },         /* ! */
+  { ISFUNC, (Function *)0x0 },         /* " */
+  { ISFUNC, (Function *)0x0 },         /* # */
+  { ISFUNC, (Function *)0x0 },         /* $ */
+  { ISFUNC, (Function *)0x0 },         /* % */
+  { ISFUNC, (Function *)0x0 },         /* & */
+  { ISFUNC, (Function *)0x0 },         /* ' */
+  { ISFUNC, rl_start_kbd_macro },      /* ( */
+  { ISFUNC, rl_end_kbd_macro  },       /* ) */
+  { ISFUNC, (Function *)0x0 },         /* * */
+  { ISFUNC, (Function *)0x0 },         /* + */
+  { ISFUNC, (Function *)0x0 },         /* , */
+  { ISFUNC, (Function *)0x0 },         /* - */
+  { ISFUNC, (Function *)0x0 },         /* . */
+  { ISFUNC, (Function *)0x0 },         /* / */
+
+  /* Regular digits. */
+  { ISFUNC, (Function *)0x0 },         /* 0 */
+  { ISFUNC, (Function *)0x0 },         /* 1 */
+  { ISFUNC, (Function *)0x0 },         /* 2 */
+  { ISFUNC, (Function *)0x0 },         /* 3 */
+  { ISFUNC, (Function *)0x0 },         /* 4 */
+  { ISFUNC, (Function *)0x0 },         /* 5 */
+  { ISFUNC, (Function *)0x0 },         /* 6 */
+  { ISFUNC, (Function *)0x0 },         /* 7 */
+  { ISFUNC, (Function *)0x0 },         /* 8 */
+  { ISFUNC, (Function *)0x0 },         /* 9 */
+
+  /* A little more punctuation. */
+  { ISFUNC, (Function *)0x0 }, /* : */
+  { ISFUNC, (Function *)0x0 }, /* ; */
+  { ISFUNC, (Function *)0x0 }, /* < */
+  { ISFUNC, (Function *)0x0 }, /* = */
+  { ISFUNC, (Function *)0x0 }, /* > */
+  { ISFUNC, (Function *)0x0 }, /* ? */
+  { ISFUNC, (Function *)0x0 }, /* @ */
+
+  /* Uppercase alphabet. */
+  { ISFUNC, rl_do_lowercase_version }, /* A */
+  { ISFUNC, rl_do_lowercase_version }, /* B */
+  { ISFUNC, rl_do_lowercase_version }, /* C */
+  { ISFUNC, rl_do_lowercase_version }, /* D */
+  { ISFUNC, rl_do_lowercase_version }, /* E */
+  { ISFUNC, rl_do_lowercase_version }, /* F */
+  { ISFUNC, rl_do_lowercase_version }, /* G */
+  { ISFUNC, rl_do_lowercase_version }, /* H */
+  { ISFUNC, rl_do_lowercase_version }, /* I */
+  { ISFUNC, rl_do_lowercase_version }, /* J */
+  { ISFUNC, rl_do_lowercase_version }, /* K */
+  { ISFUNC, rl_do_lowercase_version }, /* L */
+  { ISFUNC, rl_do_lowercase_version }, /* M */
+  { ISFUNC, rl_do_lowercase_version }, /* N */
+  { ISFUNC, rl_do_lowercase_version }, /* O */
+  { ISFUNC, rl_do_lowercase_version }, /* P */
+  { ISFUNC, rl_do_lowercase_version }, /* Q */
+  { ISFUNC, rl_do_lowercase_version }, /* R */
+  { ISFUNC, rl_do_lowercase_version }, /* S */
+  { ISFUNC, rl_do_lowercase_version }, /* T */
+  { ISFUNC, rl_do_lowercase_version }, /* U */
+  { ISFUNC, rl_do_lowercase_version }, /* V */
+  { ISFUNC, rl_do_lowercase_version }, /* W */
+  { ISFUNC, rl_do_lowercase_version }, /* X */
+  { ISFUNC, rl_do_lowercase_version }, /* Y */
+  { ISFUNC, rl_do_lowercase_version }, /* Z */
+
+  /* Some more punctuation. */
+  { ISFUNC, (Function *)0x0 },         /* [ */
+  { ISFUNC, (Function *)0x0 },         /* \ */
+  { ISFUNC, (Function *)0x0 },         /* ] */
+  { ISFUNC, (Function *)0x0 },         /* ^ */
+  { ISFUNC, (Function *)0x0 },         /* _ */
+  { ISFUNC, (Function *)0x0 },         /* ` */
+
+  /* Lowercase alphabet. */
+  { ISFUNC, (Function *)0x0 },         /* a */
+  { ISFUNC, (Function *)0x0 },         /* b */
+  { ISFUNC, (Function *)0x0 },         /* c */
+  { ISFUNC, (Function *)0x0 },         /* d */
+  { ISFUNC, rl_call_last_kbd_macro },  /* e */
+  { ISFUNC, (Function *)0x0 },         /* f */
+  { ISFUNC, (Function *)0x0 },         /* g */
+  { ISFUNC, (Function *)0x0 },         /* h */
+  { ISFUNC, (Function *)0x0 },         /* i */
+  { ISFUNC, (Function *)0x0 },         /* j */
+  { ISFUNC, (Function *)0x0 },         /* k */
+  { ISFUNC, (Function *)0x0 },         /* l */
+  { ISFUNC, (Function *)0x0 },         /* m */
+  { ISFUNC, (Function *)0x0 },         /* n */
+  { ISFUNC, (Function *)0x0 },         /* o */
+  { ISFUNC, (Function *)0x0 },         /* p */
+  { ISFUNC, (Function *)0x0 },         /* q */
+  { ISFUNC, (Function *)0x0 },         /* r */
+  { ISFUNC, (Function *)0x0 },         /* s */
+  { ISFUNC, (Function *)0x0 },         /* t */
+  { ISFUNC, (Function *)0x0 },         /* u */
+  { ISFUNC, (Function *)0x0 },         /* v */
+  { ISFUNC, (Function *)0x0 },         /* w */
+  { ISFUNC, (Function *)0x0 },         /* x */
+  { ISFUNC, (Function *)0x0 },         /* y */
+  { ISFUNC, (Function *)0x0 },         /* z */
+
+  /* Final punctuation. */
+  { ISFUNC, (Function *)0x0 },         /* { */
+  { ISFUNC, (Function *)0x0 },         /* | */
+  { ISFUNC, (Function *)0x0 },         /* } */
+  { ISFUNC, (Function *)0x0 },         /* ~ */
+  { ISFUNC, rl_backward_kill_line }    /* RUBOUT */
+};
diff --git a/readline/funmap.c b/readline/funmap.c
new file mode 100644 (file)
index 0000000..54af607
--- /dev/null
@@ -0,0 +1,212 @@
+/* funmap.c -- attach names to functions. */
+
+/* Copyright (C) 1988,1989 Free Software Foundation, Inc.
+
+   This file is part of GNU Readline, a library for reading lines
+   of text with interactive input and history editing.
+
+   Readline 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.
+
+   Readline 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 Readline; see the file COPYING.  If not, write to the Free
+   Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define STATIC_MALLOC
+#ifndef STATIC_MALLOC
+extern char *xmalloc (), *xrealloc ();
+#else
+static char *xmalloc (), *xrealloc ();
+#endif
+
+#ifndef FILE
+#include <stdio.h>
+#endif /* FILE */
+
+#include "readline.h"
+
+FUNMAP **funmap = (FUNMAP **)NULL;
+static int funmap_size = 0;
+static int funmap_entry = 0;
+
+static FUNMAP default_funmap[] = {
+  { "beginning-of-line", rl_beg_of_line },
+  { "backward-char", rl_backward },
+  { "delete-char", rl_delete },
+  { "end-of-line", rl_end_of_line },
+  { "forward-char", rl_forward },
+  { "accept-line", rl_newline },
+  { "kill-line", rl_kill_line },
+  { "clear-screen", rl_clear_screen },
+  { "next-history", rl_get_next_history },
+  { "previous-history", rl_get_previous_history },
+  { "quoted-insert", rl_quoted_insert },
+  { "reverse-search-history", rl_reverse_search_history },
+  { "forward-search-history", rl_forward_search_history },
+  { "transpose-chars", rl_transpose_chars },
+  { "unix-line-discard", rl_unix_line_discard },
+  { "unix-word-rubout", rl_unix_word_rubout },
+  { "yank", rl_yank },
+  { "yank-pop", rl_yank_pop },
+  { "yank-nth-arg", rl_yank_nth_arg },
+  { "backward-delete-char", rl_rubout },
+  { "backward-word", rl_backward_word },
+  { "kill-word", rl_kill_word },
+  { "forward-word", rl_forward_word },
+  { "tab-insert", rl_tab_insert },
+  { "backward-kill-word", rl_backward_kill_word },
+  { "backward-kill-line", rl_backward_kill_line },
+  { "transpose-words", rl_transpose_words },
+  { "digit-argument", rl_digit_argument },
+  { "complete", rl_complete },
+  { "possible-completions", rl_possible_completions },
+  { "do-lowercase-version", rl_do_lowercase_version },
+  { "digit-argument", rl_digit_argument },
+  { "universal-argument", rl_universal_argument },
+  { "abort", rl_abort },
+  { "undo", rl_undo_command },
+  { "upcase-word", rl_upcase_word },
+  { "downcase-word", rl_downcase_word },
+  { "capitalize-word", rl_capitalize_word },
+  { "revert-line", rl_revert_line },
+  { "beginning-of-history", rl_beginning_of_history },
+  { "end-of-history", rl_end_of_history },
+  { "self-insert", rl_insert },
+  { "start-kbd-macro", rl_start_kbd_macro },
+  { "end-kbd-macro", rl_end_kbd_macro },
+  { "re-read-init-file", rl_re_read_init_file },
+#ifdef VI_MODE
+  { "vi-movement-mode", rl_vi_movement_mode },
+  { "vi-insertion-mode", rl_vi_insertion_mode },
+  { "vi-arg-digit", rl_vi_arg_digit },
+  { "vi-prev-word", rl_vi_prev_word },
+  { "vi-next-word", rl_vi_next_word },
+  { "vi-char-search", rl_vi_char_search },
+  { "vi-editing-mode", rl_vi_editing_mode },
+  { "vi-eof-maybe", rl_vi_eof_maybe },
+  { "vi-append-mode", rl_vi_append_mode },
+  { "vi-put", rl_vi_put },
+  { "vi-append-eol", rl_vi_append_eol },
+  { "vi-insert-beg", rl_vi_insert_beg },
+  { "vi-delete", rl_vi_delete },
+  { "vi-comment", rl_vi_comment },
+  { "vi-first-print", rl_vi_first_print },
+  { "vi-fword", rl_vi_fword },
+  { "vi-fWord", rl_vi_fWord },
+  { "vi-bword", rl_vi_bword },
+  { "vi-bWord", rl_vi_bWord },
+  { "vi-eword", rl_vi_eword },
+  { "vi-eWord", rl_vi_eWord },
+  { "vi-end-word", rl_vi_end_word },
+  { "vi-change-case", rl_vi_change_case },
+  { "vi-match", rl_vi_match },
+  { "vi-bracktype", rl_vi_bracktype },
+  { "vi-change-char", rl_vi_change_char },
+  { "vi-yank-arg", rl_vi_yank_arg },
+  { "vi-search", rl_vi_search },
+  { "vi-search-again", rl_vi_search_again },
+  { "vi-dosearch", rl_vi_dosearch },
+  { "vi-subst", rl_vi_subst },
+  { "vi-overstrike", rl_vi_overstrike },
+  { "vi-overstrike-delete", rl_vi_overstrike_delete },
+  { "vi-replace, ", rl_vi_replace },
+  { "vi-column", rl_vi_column },
+  { "vi-delete-to", rl_vi_delete_to },
+  { "vi-change-to", rl_vi_change_to },
+  { "vi-yank-to", rl_vi_yank_to },
+  { "vi-complete", rl_vi_complete },
+#endif /* VI_MODE */
+
+ {(char *)NULL, (Function *)NULL }
+};
+
+rl_add_funmap_entry (name, function)
+     char *name;
+     Function *function;
+{
+  if (funmap_entry + 2 >= funmap_size)
+    if (!funmap)
+      funmap = (FUNMAP **)xmalloc ((funmap_size = 80) * sizeof (FUNMAP *));
+    else
+      funmap =
+       (FUNMAP **)xrealloc (funmap, (funmap_size += 80) * sizeof (FUNMAP *));
+  
+  funmap[funmap_entry] = (FUNMAP *)xmalloc (sizeof (FUNMAP));
+  funmap[funmap_entry]->name = name;
+  funmap[funmap_entry]->function = function;
+
+  funmap[++funmap_entry] = (FUNMAP *)NULL;
+}
+
+static int funmap_initialized = 0;
+
+/* Make the funmap contain all of the default entries. */
+rl_initialize_funmap ()
+{
+  register int i;
+
+  if (funmap_initialized)
+    return;
+
+  for (i = 0; default_funmap[i].name; i++)
+    rl_add_funmap_entry (default_funmap[i].name, default_funmap[i].function);
+
+  funmap_initialized = 1;
+}
+
+/* Things that mean `Control'. */
+char *possible_control_prefixes[] = {
+  "Control-", "C-", "CTRL-", (char *)NULL
+};
+
+char *possible_meta_prefixes[] = {
+  "Meta", "M-", (char *)NULL
+};
+
+#ifdef STATIC_MALLOC
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                     xmalloc and xrealloc ()                     */
+/*                                                                 */
+/* **************************************************************** */
+
+static void memory_error_and_abort ();
+
+static char *
+xmalloc (bytes)
+     int bytes;
+{
+  char *temp = (char *)malloc (bytes);
+
+  if (!temp)
+    memory_error_and_abort ();
+  return (temp);
+}
+
+static char *
+xrealloc (pointer, bytes)
+     char *pointer;
+     int bytes;
+{
+  char *temp = (char *)realloc (pointer, bytes);
+
+  if (!temp)
+    memory_error_and_abort ();
+  return (temp);
+}
+
+static void
+memory_error_and_abort ()
+{
+  fprintf (stderr, "history: Out of virtual memory!\n");
+  abort ();
+}
+#endif /* STATIC_MALLOC */
diff --git a/readline/history.c b/readline/history.c
new file mode 100644 (file)
index 0000000..3c07d11
--- /dev/null
@@ -0,0 +1,1478 @@
+/* History.c -- standalone history library */
+
+/* Copyright (C) 1989 Free Software Foundation, Inc.
+
+   This file contains the GNU History Library (the Library), a set of
+   routines for managing the text of previously typed lines.
+
+   The Library 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.
+
+   The Library 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.
+
+   The GNU General Public License is often shipped with GNU software, and
+   is generally kept in a file called COPYING or LICENSE.  If you do not
+   have a copy of the license, write to the Free Software Foundation,
+   675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* The goal is to make the implementation transparent, so that you
+   don't have to know what data types are used, just what functions
+   you can call.  I think I have done that. */
+
+/* Remove these declarations when we have a complete libgnu.a. */
+#define STATIC_MALLOC
+#ifndef STATIC_MALLOC
+extern char *xmalloc (), *xrealloc ();
+#else
+static char *xmalloc (), *xrealloc ();
+#endif
+
+#include <stdio.h>
+
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else
+#if defined (sparc) && defined (sun)
+#include <alloca.h>
+#else
+extern char *alloca ();
+#endif
+#endif
+
+#include "history.h"
+
+#ifndef savestring
+#define savestring(x) (char *)strcpy (xmalloc (1 + strlen (x)), (x))
+#endif
+
+#ifndef whitespace
+#define whitespace(c) (((c) == ' ') || ((c) == '\t'))
+#endif
+
+#ifndef digit
+#define digit(c)  ((c) >= '0' && (c) <= '9')
+#endif
+
+#ifndef member
+#define member(c, s) ((c) ? index ((s), (c)) : 0)
+#endif
+
+/* **************************************************************** */
+/*                                                                 */
+/*                     History functions                           */
+/*                                                                 */
+/* **************************************************************** */
+
+/* An array of HIST_ENTRY.  This is where we store the history. */
+static HIST_ENTRY **the_history = (HIST_ENTRY **)NULL;
+
+/* Non-zero means that we have enforced a limit on the amount of
+   history that we save. */
+static int history_stifled = 0;
+
+/* If HISTORY_STIFLED is non-zero, then this is the maximum number of
+   entries to remember. */
+static int max_input_history;
+
+/* The current location of the interactive history pointer.  Just makes
+   life easier for outside callers. */
+static int history_offset = 0;
+
+/* The number of strings currently stored in the input_history list. */
+static int history_length = 0;
+
+/* The current number of slots allocated to the input_history. */
+static int history_size = 0;
+
+/* The number of slots to increase the_history by. */
+#define DEFAULT_HISTORY_GROW_SIZE 50
+
+/* The character that represents the start of a history expansion
+   request.  This is usually `!'. */
+char history_expansion_char = '!';
+
+/* The character that invokes word substitution if found at the start of
+   a line.  This is usually `^'. */
+char history_subst_char = '^';
+
+/* During tokenization, if this character is seen as the first character
+   of a word, then it, and all subsequent characters upto a newline are
+   ignored.  For a Bourne shell, this should be '#'.  Bash special cases
+   the interactive comment character to not be a comment delimiter. */
+char history_comment_char = '\0';
+
+/* The list of characters which inhibit the expansion of text if found
+   immediately following history_expansion_char. */
+char *history_no_expand_chars = " \t\n\r=";
+
+/* The logical `base' of the history array.  It defaults to 1. */
+int history_base = 1;
+
+/* Begin a session in which the history functions might be used.  This
+   initializes interactive variables. */
+void
+using_history ()
+{
+  history_offset = history_length;
+}
+
+/* Place STRING at the end of the history list.  The data field
+   is  set to NULL. */
+void
+add_history (string)
+     char *string;
+{
+  HIST_ENTRY *temp;
+
+  if (history_stifled && (history_length == max_input_history)) {
+    register int i;
+
+    /* If the history is stifled, and history_length is zero,
+       and it equals max_input_history, we don't save items. */
+    if (!history_length)
+      return;
+
+    /* If there is something in the slot, then remove it. */
+    if (the_history[0]) {
+      free (the_history[0]->line);
+      free (the_history[0]);
+    }
+
+    for (i = 0; i < history_length; i++)
+      the_history[i] = the_history[i + 1];
+
+    history_base++;
+
+  } else {
+
+    if (!history_size) {
+      the_history =
+       (HIST_ENTRY **)xmalloc ((history_size = DEFAULT_HISTORY_GROW_SIZE)
+                         * sizeof (HIST_ENTRY *));
+      history_length = 1;
+
+    } else {
+      if (history_length == (history_size - 1)) {
+       the_history =
+         (HIST_ENTRY **)xrealloc (the_history,
+                                  ((history_size += DEFAULT_HISTORY_GROW_SIZE)
+                                   * sizeof (HIST_ENTRY *)));
+      }
+      history_length++;
+    }
+  }
+
+  temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
+  temp->line = savestring (string);
+  temp->data = (char *)NULL;
+
+  the_history[history_length] = (HIST_ENTRY *)NULL;
+  the_history[history_length - 1] = temp;
+}
+
+/* Make the history entry at WHICH have LINE and DATA.  This returns
+   the old entry so you can dispose of the data.  In the case of an
+   invalid WHICH, a NULL pointer is returned. */
+HIST_ENTRY *
+replace_history_entry (which, line, data)
+     int which;
+     char *line;
+     char *data;
+{
+  HIST_ENTRY *temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
+  HIST_ENTRY *old_value;
+
+  if (which >= history_length)
+    return ((HIST_ENTRY *)NULL);
+
+  old_value = the_history[which];
+
+  temp->line = savestring (line);
+  temp->data = data;
+  the_history[which] = temp;
+
+  return (old_value);
+}
+
+/* Returns the magic number which says what history element we are
+   looking at now.  In this implementation, it returns history_offset. */
+int
+where_history ()
+{
+  return (history_offset);
+}
+
+/* Search the history for STRING, starting at history_offset.
+   If DIRECTION < 0, then the search is through previous entries,
+   else through subsequent.  If the string is found, then
+   current_history () is the history entry, and the value of this function
+   is the offset in the line of that history entry that the string was
+   found in.  Otherwise, nothing is changed, and a -1 is returned. */
+int
+history_search (string, direction)
+     char *string;
+     int direction;
+{
+  register int i = history_offset;
+  register int reverse = (direction < 0);
+  register char *line;
+  register int index;
+  int string_len = strlen (string);
+
+  /* Take care of trivial cases first. */
+
+  if (!history_length || ((i == history_length) && !reverse))
+    return (-1);
+
+  if (reverse && (i == history_length))
+    i--;
+
+  while (1)
+    {
+      /* Search each line in the history list for STRING. */
+
+      /* At limit for direction? */
+      if ((reverse && i < 0) ||
+         (!reverse && i == history_length))
+       return (-1);
+
+      line = the_history[i]->line;
+      index = strlen (line);
+
+      /* If STRING is longer than line, no match. */
+      if (string_len > index)
+       goto next_line;
+
+      /* Do the actual search. */
+      if (reverse)
+       {
+         index -= string_len;
+
+         while (index >= 0)
+           {
+             if (strncmp (string, line + index, string_len) == 0)
+               {
+                 history_offset = i;
+                 return (index);
+               }
+             index--;
+           }
+       }
+      else
+       {
+         register int limit = (string_len - index) + 1;
+         index = 0;
+
+         while (index < limit)
+           {
+             if (strncmp (string, line + index, string_len) == 0)
+               {
+                 history_offset = i;
+                 return (index);
+               }
+             index++;
+           }
+       }
+    next_line:
+      if (reverse)
+       i--;
+      else
+       i++;
+    }
+}
+
+/* Remove history element WHICH from the history.  The removed
+   element is returned to you so you can free the line, data,
+   and containing structure. */
+HIST_ENTRY *
+remove_history (which)
+     int which;
+{
+  HIST_ENTRY *return_value;
+
+  if (which >= history_length || !history_length)
+    return_value = (HIST_ENTRY *)NULL;
+  else
+    {
+      register int i;
+      return_value = the_history[which];
+
+      for (i = which; i < history_length; i++)
+       the_history[i] = the_history[i + 1];
+
+      history_length--;
+    }
+  return (return_value);
+}
+
+/* Stifle the history list, remembering only MAX number of lines. */
+void
+stifle_history (max)
+     int max;
+{
+  if (history_length > max)
+    {
+      register int i, j;
+
+      /* This loses because we cannot free the data. */
+      for (i = 0; i < (history_length - max); i++)
+       {
+         free (the_history[i]->line);
+         free (the_history[i]);
+       }
+      history_base = i;
+      for (j = 0, i = history_length - max; j < max; i++, j++)
+       the_history[j] = the_history[i];
+      the_history[j] = (HIST_ENTRY *)NULL;
+      history_length = j;
+    }
+  history_stifled = 1;
+  max_input_history = max;
+}
+
+/* Stop stifling the history.  This returns the previous amount the history
+ was stifled by.  The value is positive if the history was stifled, negative
+ if it wasn't. */
+int
+unstifle_history ()
+{
+  int result = max_input_history;
+  if (history_stifled)
+    {
+      result = - result;
+      history_stifled = 0;
+    }
+  return (result);
+}
+
+/* Return the string that should be used in the place of this
+   filename.  This only matters when you don't specify the
+   filename to read_history (), or write_history (). */
+static char *
+history_filename (filename)
+     char *filename;
+{
+  char *return_val = filename ? savestring (filename) : (char *)NULL;
+
+  if (!return_val)
+    {
+      char *home = (char *)getenv ("HOME");
+      if (!home) home = ".";
+      return_val = (char *)xmalloc (2 + strlen (home) + strlen (".history"));
+      strcpy (return_val, home);
+      strcat (return_val, "/");
+      strcat (return_val, ".history");
+    }
+  return (return_val);
+}
+
+/* What to use until the line gets too big. */
+#define TYPICAL_LINE_SIZE 2048
+
+/* Add the contents of FILENAME to the history list, a line at a time.
+   If FILENAME is NULL, then read from ~/.history.  Returns 0 if
+   successful, or errno if not. */
+int
+read_history (filename)
+     char *filename;
+{
+  char *input = history_filename (filename);
+  FILE *file = fopen (input, "r");
+  char *line = (char *)xmalloc (TYPICAL_LINE_SIZE);
+  int line_size = TYPICAL_LINE_SIZE;
+  int done = 0;
+
+  if (!file)
+    {
+      extern int errno;
+      free (line);
+      return (errno);
+    }
+
+  while (!done)
+    {
+      int c;
+      int i;
+
+      i = 0;
+      while (!(done = ((c = getc (file)) == EOF)))
+       {
+         if (c == '\n')
+           break;
+
+         line [i++] = c;
+         if (i == line_size)
+           line = (char *)xrealloc (line, line_size += TYPICAL_LINE_SIZE);
+       }
+      line[i] = '\0';
+      if (line[0])
+       add_history (line);
+    }
+  free (line);
+  fclose (file);
+  return (0);
+}
+
+/* Overwrite FILENAME with the current history.  If FILENAME is NULL,
+   then write the history list to ~/.history.  Values returned
+   are as in read_history ().*/
+int
+write_history (filename)
+     char *filename;
+{
+  extern int errno;
+  char *output = history_filename (filename);
+  FILE *file = fopen (output, "w");
+  register int i;
+
+  if (!file) return (errno);
+  if (!history_length) return (0);
+
+  for (i = 0; i < history_length; i++)
+    fprintf (file, "%s\n", the_history[i]->line);
+
+  fclose (file);
+  return (0);
+}
+
+/* Return the history entry at the current position, as determined by
+   history_offset.  If there is no entry there, return a NULL pointer. */
+HIST_ENTRY *
+current_history ()
+{
+  if ((history_offset == history_length) || !the_history)
+    return ((HIST_ENTRY *)NULL);
+  else
+    return (the_history[history_offset]);
+}
+
+/* Back up history_offset to the previous history entry, and return
+   a pointer to that entry.  If there is no previous entry then return
+   a NULL pointer. */
+HIST_ENTRY *
+previous_history ()
+{
+  if (!history_offset)
+    return ((HIST_ENTRY *)NULL);
+  else
+    return (the_history[--history_offset]);
+}
+
+/* Move history_offset forward to the next history entry, and return
+   a pointer to that entry.  If there is no next entry then return a
+   NULL pointer. */
+HIST_ENTRY *
+next_history ()
+{
+  if (history_offset == history_length)
+    return ((HIST_ENTRY *)NULL);
+  else
+    return (the_history[++history_offset]);
+}
+
+/* Return the current history array.  The caller has to be carefull, since this
+   is the actual array of data, and could be bashed or made corrupt easily.
+   The array is terminated with a NULL pointer. */
+HIST_ENTRY **
+history_list ()
+{
+  return (the_history);
+}
+
+/* Return the history entry which is logically at OFFSET in the history array.
+   OFFSET is relative to history_base. */
+HIST_ENTRY *
+history_get (offset)
+     int offset;
+{
+  int index = offset - history_base;
+
+  if (index >= history_length ||
+      index < 0 ||
+      !the_history)
+    return ((HIST_ENTRY *)NULL);
+  return (the_history[index]);
+}
+
+/* Search for STRING in the history list.  DIR is < 0 for searching
+   backwards.  POS is an absolute index into the history list at
+   which point to begin searching. */
+int
+history_search_pos (string, dir, pos)
+     char *string;
+     int dir, pos;
+{
+  int ret, old = where_history ();
+  history_set_pos (pos);
+  if (history_search (string, dir) == -1)
+    {
+      history_set_pos (old);
+      return (-1);
+    }
+  ret = where_history ();
+  history_set_pos (old);
+  return ret;
+}
+
+/* Make the current history item be the one at POS, an absolute index.
+   Returns zero if POS is out of range, else non-zero. */
+int
+history_set_pos (pos)
+     int pos;
+{
+  if (pos > history_length || pos < 0 || !the_history)
+    return (0);
+  history_offset = pos;
+  return (1);
+}
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                     History Expansion                           */
+/*                                                                 */
+/* **************************************************************** */
+
+/* Hairy history expansion on text, not tokens.  This is of general
+   use, and thus belongs in this library. */
+
+/* The last string searched for in a !?string? search. */
+static char *search_string = (char *)NULL;
+
+/* Return the event specified at TEXT + OFFSET modifying OFFSET to
+   point to after the event specifier.  Just a pointer to the history
+   line is returned; NULL is returned in the event of a bad specifier.
+   You pass STRING with *INDEX equal to the history_expansion_char that
+   begins this specification.
+   DELIMITING_QUOTE is a character that is allowed to end the string
+   specification for what to search for in addition to the normal
+   characters `:', ` ', `\t', `\n', and sometimes `?'.
+   So you might call this function like:
+   line = get_history_event ("!echo:p", &index, 0);  */
+char *
+get_history_event (string, caller_index, delimiting_quote)
+     char *string;
+     int *caller_index;
+     int delimiting_quote;
+{
+  register int i = *caller_index;
+  int which, sign = 1;
+  HIST_ENTRY *entry;
+
+  /* The event can be specified in a number of ways.
+
+     !!   the previous command
+     !n   command line N
+     !-n  current command-line minus N
+     !str the most recent command starting with STR
+     !?str[?]
+         the most recent command containing STR
+
+     All values N are determined via HISTORY_BASE. */
+
+  if (string[i] != history_expansion_char)
+    return ((char *)NULL);
+
+  /* Move on to the specification. */
+  i++;
+
+  /* Handle !! case. */
+  if (string[i] == history_expansion_char)
+    {
+      i++;
+      which = history_base + (history_length - 1);
+      *caller_index = i;
+      goto get_which;
+    }
+
+  /* Hack case of numeric line specification. */
+ read_which:
+  if (string[i] == '-')
+    {
+      sign = -1;
+      i++;
+    }
+
+  if (digit (string[i]))
+    {
+      int start = i;
+
+      /* Get the extent of the digits. */
+      for (; digit (string[i]); i++);
+
+      /* Get the digit value. */
+      sscanf (string + start, "%d", &which);
+
+      *caller_index = i;
+
+      if (sign < 0)
+       which = (history_length + history_base) - which;
+
+    get_which:
+      if (entry = history_get (which))
+       return (entry->line);
+
+      return ((char *)NULL);
+    }
+
+  /* This must be something to search for.  If the spec begins with
+     a '?', then the string may be anywhere on the line.  Otherwise,
+     the string must be found at the start of a line. */
+  {
+    int index;
+    char *temp;
+    int substring_okay = 0;
+
+    if (string[i] == '?')
+      {
+       substring_okay++;
+       i++;
+      }
+
+    for (index = i; string[i]; i++)
+      if (whitespace (string[i]) ||
+         string[i] == '\n' ||
+         string[i] == ':' ||
+         (substring_okay && string[i] == '?') ||
+         string[i] == delimiting_quote)
+       break;
+
+    temp = (char *)alloca (1 + (i - index));
+    strncpy (temp, &string[index], (i - index));
+    temp[i - index] = '\0';
+
+    if (string[i] == '?')
+      i++;
+
+    *caller_index = i;
+
+  search_again:
+
+    index = history_search (temp, -1);
+
+    if (index < 0)
+    search_lost:
+      {
+       history_offset = history_length;
+       return ((char *)NULL);
+      }
+
+    if (index == 0 || substring_okay || 
+       (strncmp (temp, the_history[history_offset]->line,
+                 strlen (temp)) == 0))
+      {
+      search_won:
+       entry = current_history ();
+       history_offset = history_length;
+       
+       /* If this was a substring search, then remember the string that
+          we matched for word substitution. */
+       if (substring_okay)
+         {
+           if (search_string)
+             free (search_string);
+           search_string = savestring (temp);
+         }
+
+       return (entry->line);
+      }
+
+    if (history_offset)
+      history_offset--;
+    else
+      goto search_lost;
+    
+    goto search_again;
+  }
+}
+
+/* Expand the string STRING, placing the result into OUTPUT, a pointer
+   to a string.  Returns:
+
+   0) If no expansions took place (or, if the only change in
+      the text was the de-slashifying of the history expansion
+      character)
+   1) If expansions did take place
+  -1) If there was an error in expansion.
+
+  If an error ocurred in expansion, then OUTPUT contains a descriptive
+  error message. */
+int
+history_expand (string, output)
+     char *string;
+     char **output;
+{
+  register int j, l = strlen (string);
+  int i, word_spec_error = 0;
+  int cc, modified = 0;
+  char *word_spec, *event;
+  int starting_index, only_printing = 0, substitute_globally = 0;
+
+  char *get_history_word_specifier (), *rindex ();
+
+  /* The output string, and its length. */
+  int len = 0;
+  char *result = (char *)NULL;
+
+  /* Used in add_string; */
+  char *temp, tt[2], tbl[3];
+
+  /* Prepare the buffer for printing error messages. */
+  result = (char *)xmalloc (len = 255);
+
+  result[0] = tt[1] = tbl[2] = '\0';
+  tbl[0] = '\\';
+  tbl[1] = history_expansion_char;
+
+  /* Grovel the string.  Only backslash can quote the history escape
+     character.  We also handle arg specifiers. */
+
+  /* Before we grovel forever, see if the history_expansion_char appears
+     anywhere within the text. */
+
+  /* The quick substitution character is a history expansion all right.  That
+     is to say, "^this^that^" is equivalent to "!!:s^this^that^", and in fact,
+     that is the substitution that we do. */
+  if (string[0] == history_subst_char)
+    {
+      char *format_string = (char *)alloca (10 + strlen (string));
+
+      sprintf (format_string, "%c%c:s%s",
+              history_expansion_char, history_expansion_char,
+              string);
+      string = format_string;
+      l += 4;
+      goto grovel;
+    }
+
+  /* If not quick substitution, still maybe have to do expansion. */
+
+  /* `!' followed by one of the characters in history_no_expand_chars
+     is NOT an expansion. */
+  for (i = 0; string[i]; i++)
+    if (string[i] == history_expansion_char)
+      if (!string[i + 1] || member (string[i + 1], history_no_expand_chars))
+       continue;
+      else
+       goto grovel;
+
+  free (result);
+  *output = savestring (string);
+  return (0);
+
+ grovel:
+
+  for (i = j = 0; i < l; i++)
+    {
+      int tchar = string[i];
+      if (tchar == history_expansion_char)
+       tchar = -3;
+
+      switch (tchar)
+       {
+       case '\\':
+         if (string[i + 1] == history_expansion_char)
+           {
+             i++;
+             temp = tbl;
+             goto do_add;
+           }
+         else
+           goto add_char;
+
+         /* case history_expansion_char: */
+       case -3:
+         starting_index = i + 1;
+         cc = string[i + 1];
+
+         /* If the history_expansion_char is followed by one of the
+            characters in history_no_expand_chars, then it is not a
+            candidate for expansion of any kind. */
+         if (member (cc, history_no_expand_chars))
+           goto add_char;
+
+         /* There is something that is listed as a `word specifier' in csh
+            documentation which means `the expanded text to this point'.
+            That is not a word specifier, it is an event specifier. */
+
+         if (cc == '#')
+           goto hack_pound_sign;
+
+         /* If it is followed by something that starts a word specifier,
+            then !! is implied as the event specifier. */
+
+         if (member (cc, ":$*%^"))
+           {
+             char fake_s[3];
+             int fake_i = 0;
+             i++;
+             fake_s[0] = fake_s[1] = history_expansion_char;
+             fake_s[2] = '\0';
+             event = get_history_event (fake_s, &fake_i, 0);
+           }
+         else
+           {
+             int quoted_search_delimiter = 0;
+
+             /* If the character before this `!' is a double or single
+                quote, then this expansion takes place inside of the
+                quoted string.  If we have to search for some text ("!foo"),
+                allow the delimiter to end the search string. */
+             if (i && (string[i - 1] == '\'' || string[i - 1] == '"'))
+               quoted_search_delimiter = string[i - 1];
+
+             event = get_history_event (string, &i, quoted_search_delimiter);
+           }
+         
+         if (!event)
+         event_not_found:
+           {
+           int l = 1 + (i - starting_index);
+
+           temp = (char *)alloca (1 + l);
+           strncpy (temp, string + starting_index, l);
+           temp[l - 1] = 0;
+           sprintf (result, "%s: %s.", temp,
+                    word_spec_error ? "Bad word specifier" : "Event not found");
+         error_exit:
+           *output = result;
+           return (-1);
+         }
+
+         /* If a word specifier is found, then do what that requires. */
+         starting_index = i;
+
+         word_spec = get_history_word_specifier (string, event, &i);
+
+         /* There is no such thing as a `malformed word specifier'.  However,
+            it is possible for a specifier that has no match.  In that case,
+            we complain. */
+         if (word_spec == (char *)-1)
+         bad_word_spec:
+         {
+           word_spec_error++;
+           goto event_not_found;
+         }
+
+         /* If no word specifier, than the thing of interest was the event. */
+         if (!word_spec)
+           temp = event;
+         else
+           {
+             temp = (char *)alloca (1 + strlen (word_spec));
+             strcpy (temp, word_spec);
+             free (word_spec);
+           }
+
+         /* Perhaps there are other modifiers involved.  Do what they say. */
+
+       hack_specials:
+
+         if (string[i] == ':')
+           {
+             char *tstr;
+
+             switch (string[i + 1])
+               {
+                 /* :p means make this the last executed line.  So we
+                    return an error state after adding this line to the
+                    history. */
+               case 'p':
+                 only_printing++;
+                 goto next_special;
+
+                 /* :t discards all but the last part of the pathname. */
+               case 't':
+                 tstr = rindex (temp, '/');
+                 if (tstr)
+                   temp = ++tstr;
+                 goto next_special;
+
+                 /* :h discards the last part of a pathname. */
+               case 'h':
+                 tstr = rindex (temp, '/');
+                 if (tstr)
+                   *tstr = '\0';
+                 goto next_special;
+
+                 /* :r discards the suffix. */
+               case 'r':
+                 tstr = rindex (temp, '.');
+                 if (tstr)
+                   *tstr = '\0';
+                 goto next_special;
+
+                 /* :e discards everything but the suffix. */
+               case 'e':
+                 tstr = rindex (temp, '.');
+                 if (tstr)
+                   temp = tstr;
+                 goto next_special;
+
+                 /* :s/this/that substitutes `this' for `that'. */
+                 /* :gs/this/that substitutes `this' for `that' globally. */
+               case 'g':
+                 if (string[i + 2] == 's')
+                   {
+                     i++;
+                     substitute_globally = 1;
+                     goto substitute;
+                   }
+                 else
+                   
+               case 's':
+                 substitute:
+                 {
+                   char *this, *that, *new_event;
+                   int delimiter = 0;
+                   int si, l_this, l_that, l_temp = strlen (temp);
+
+                   if (i + 2 < strlen (string))
+                     delimiter = string[i + 2];
+
+                   if (!delimiter)
+                     break;
+
+                   i += 3;
+
+                   /* Get THIS. */
+                   for (si = i; string[si] && string[si] != delimiter; si++);
+                   l_this = (si - i);
+                   this = (char *)alloca (1 + l_this);
+                   strncpy (this, string + i, l_this);
+                   this[l_this] = '\0';
+
+                   i = si;
+                   if (string[si])
+                     i++;
+
+                   /* Get THAT. */
+                   for (si = i; string[si] && string[si] != delimiter; si++);
+                   l_that = (si - i);
+                   that = (char *)alloca (1 + l_that);
+                   strncpy (that, string + i, l_that);
+                   that[l_that] = '\0';
+
+                   i = si;
+                   if (string[si]) i++;
+
+                   /* Ignore impossible cases. */
+                   if (l_this > l_temp)
+                     goto cant_substitute;
+
+                   /* Find the first occurrence of THIS in TEMP. */
+                   si = 0;
+                   for (; (si + l_this) <= l_temp; si++)
+                     if (strncmp (temp + si, this, l_this) == 0)
+                       {
+                         new_event =
+                           (char *)alloca (1 + (l_that - l_this) + l_temp);
+                         strncpy (new_event, temp, si);
+                         strncpy (new_event + si, that, l_that);
+                         strncpy (new_event + si + l_that,
+                                  temp + si + l_this,
+                                  l_temp - (si + l_this));
+                         new_event[(l_that - l_this) + l_temp] = '\0';
+                         temp = new_event;
+
+                         if (substitute_globally)
+                           {
+                             si += l_that;
+                             l_temp = strlen (temp);
+                             substitute_globally++;
+                             continue;
+                           }
+
+                         goto hack_specials;
+                       }
+
+                 cant_substitute:
+
+                   if (substitute_globally > 1)
+                     {
+                       substitute_globally = 0;
+                       goto hack_specials;
+                     }
+
+                   goto event_not_found;
+                 }
+
+                 /* :# is the line so far.  Note that we have to
+                    alloca () it since RESULT could be realloc ()'ed
+                    below in add_string. */
+               case '#':
+               hack_pound_sign:
+                 if (result)
+                   {
+                     temp = (char *)alloca (1 + strlen (result));
+                     strcpy (temp, result);
+                   }
+                 else
+                   temp = "";
+
+               next_special:
+                 i += 2;
+                 goto hack_specials;
+               }
+
+           }
+         /* Believe it or not, we have to back the pointer up by one. */
+         --i;
+         goto add_string;
+
+         /* A regular character.  Just add it to the output string. */
+       default:
+       add_char:
+         tt[0] = string[i];
+         temp = tt;
+         goto do_add;
+
+       add_string:
+         modified++;
+
+       do_add:
+         j += strlen (temp);
+         while (j > len)
+           result = (char *)xrealloc (result, (len += 255));
+
+         strcpy (result + (j - strlen (temp)), temp);
+       }
+    }
+
+  *output = result;
+
+  if (only_printing)
+    {
+      add_history (result);
+      return (-1);
+    }
+
+  return (modified != 0);
+}
+
+/* Return a consed string which is the word specified in SPEC, and found
+   in FROM.  NULL is returned if there is no spec.  -1 is returned if
+   the word specified cannot be found.  CALLER_INDEX is the offset in
+   SPEC to start looking; it is updated to point to just after the last
+   character parsed. */
+char *
+get_history_word_specifier (spec, from, caller_index)
+     char *spec, *from;
+     int *caller_index;
+{
+  register int i = *caller_index;
+  int first, last;
+  int expecting_word_spec = 0;
+  char *history_arg_extract ();
+
+  /* The range of words to return doesn't exist yet. */
+  first = last = 0;
+
+  /* If we found a colon, then this *must* be a word specification.  If
+     it isn't, then it is an error. */
+  if (spec[i] == ':')
+    i++, expecting_word_spec++;
+
+  /* Handle special cases first. */
+
+  /* `%' is the word last searched for. */
+  if (spec[i] == '%')
+    {
+      *caller_index = i + 1;
+      if (search_string)
+       return (savestring (search_string));
+      else
+       return (savestring (""));
+    }
+
+  /* `*' matches all of the arguments, but not the command. */
+  if (spec[i] == '*')
+    {
+      char *star_result;
+
+      *caller_index = i + 1;
+      star_result = history_arg_extract (1, '$', from);
+
+      if (!star_result)
+       star_result = savestring ("");
+
+      return (star_result);
+    }
+
+  /* `$' is last arg. */
+  if (spec[i] == '$')
+    {
+      *caller_index = i + 1;
+      return (history_arg_extract ('$', '$', from));
+    }
+
+  /* Try to get FIRST and LAST figured out. */
+  if (spec[i] == '-' || spec[i] == '^')
+    {
+      first = 1;
+      goto get_last;
+    }
+
+ get_first:
+  if (digit (spec[i]) && expecting_word_spec)
+    {
+      sscanf (spec + i, "%d", &first);
+      for (; digit (spec[i]); i++);
+    }
+  else
+    return ((char *)NULL);
+
+ get_last:
+  if (spec[i] == '^')
+    {
+      i++;
+      last = 1;
+      goto get_args;
+    }
+
+  if (spec[i] != '-')
+    {
+      last = first;
+      goto get_args;
+    }
+
+  i++;
+
+  if (digit (spec[i]))
+    {
+      sscanf (spec + i, "%d", &last);
+      for (; digit (spec[i]); i++);
+    }
+  else
+    if (spec[i] == '$')
+      {
+       i++;
+       last = '$';
+      }
+
+ get_args:
+  {
+    char *result = (char *)NULL;
+
+    *caller_index = i;
+
+    if (last >= first)
+      result = history_arg_extract (first, last, from);
+
+    if (result)
+      return (result);
+    else
+      return ((char *)-1);
+  }
+}
+
+/* Extract the args specified, starting at FIRST, and ending at LAST.
+   The args are taken from STRING.  If either FIRST or LAST is < 0,
+   then make that arg count from the right (subtract from the number of
+   tokens, so that FIRST = -1 means the next to last token on the line. */
+char *
+history_arg_extract (first, last, string)
+     int first, last;
+     char *string;
+{
+  register int i, len;
+  char *result = (char *)NULL;
+  int size = 0, offset = 0;
+
+  char **history_tokenize (), **list;
+
+  if (!(list = history_tokenize (string)))
+    return ((char *)NULL);
+
+  for (len = 0; list[len]; len++);
+
+  if (last < 0)
+    last = len + last - 1;
+
+  if (first < 0)
+    first = len + first - 1;
+
+  if (last == '$')
+    last = len - 1;
+
+  if (first == '$')
+    first = len - 1;
+
+  last++;
+
+  if (first > len || last > len)
+    result = ((char *)NULL);
+  else
+    {
+      for (i = first; i < last; i++)
+       {
+         int l = strlen (list[i]);
+
+         if (!result)
+           result = (char *)xmalloc ((size = (2 + l)));
+         else
+           result = (char *)xrealloc (result, (size += (2 + l)));
+         strcpy (result + offset, list[i]);
+         offset += l;
+         if (i + 1 < last)
+           {
+             strcpy (result + offset, " ");
+             offset++;
+           }
+       }
+    }
+
+  for (i = 0; i < len; i++)
+    free (list[i]);
+
+  free (list);
+
+  return (result);
+}
+
+#define slashify_in_quotes "\\`\"$"
+
+/* Return an array of tokens, much as the shell might.  The tokens are
+   parsed out of STRING. */
+char **
+history_tokenize (string)
+     char *string;
+{
+  char **result = (char **)NULL;
+  register int i, start, result_index, size;
+  int len;
+
+  i = result_index = size = 0;
+
+  /* Get a token, and stuff it into RESULT.  The tokens are split
+     exactly where the shell would split them. */
+ get_token:
+
+  /* Skip leading whitespace. */
+  for (; string[i] && whitespace(string[i]); i++);
+
+  start = i;
+
+  if (!string[i] || string[i] == history_comment_char)
+    return (result);
+
+  if (member (string[i], "()\n")) {
+    i++;
+    goto got_token;
+  }
+
+  if (member (string[i], "<>;&|")) {
+    int peek = string[i + 1];
+
+    if (peek == string[i]) {
+      if (peek ==  '<') {
+       if (string[1 + 2] == '-')
+         i++;
+       i += 2;
+       goto got_token;
+      }
+
+      if (member (peek, ">:&|")) {
+       i += 2;
+       goto got_token;
+      }
+    } else {
+      if ((peek == '&' &&
+         (string[i] == '>' || string[i] == '<')) ||
+         ((peek == '>') &&
+         (string[i] == '&'))) {
+       i += 2;
+       goto got_token;
+      }
+    }
+    i++;
+    goto got_token;
+  }
+
+  /* Get word from string + i; */
+  {
+    int delimiter = 0;
+
+    if (member (string[i], "\"'`"))
+      delimiter = string[i++];
+
+    for (;string[i]; i++) {
+
+      if (string[i] == '\\') {
+
+       if (string[i + 1] == '\n') {
+         i++;
+         continue;
+       } else {
+         if (delimiter != '\'')
+           if ((delimiter != '"') ||
+               (member (string[i], slashify_in_quotes))) {
+             i++;
+             continue;
+           }
+       }
+      }
+
+      if (delimiter && string[i] == delimiter) {
+       delimiter = 0;
+       continue;
+      }
+
+      if (!delimiter && (member (string[i], " \t\n;&()|<>")))
+       goto got_token;
+
+      if (!delimiter && member (string[i], "\"'`")) {
+       delimiter = string[i];
+       continue;
+      }
+    }
+    got_token:
+
+    len = i - start;
+    if (result_index + 2 >= size) {
+      if (!size)
+       result = (char **)xmalloc ((size = 10) * (sizeof (char *)));
+      else
+       result =
+         (char **)xrealloc (result, ((size += 10) * (sizeof (char *))));
+    }
+    result[result_index] = (char *)xmalloc (1 + len);
+    strncpy (result[result_index], string + start, len);
+    result[result_index][len] = '\0';
+    result_index++;
+    result[result_index] = (char *)NULL;
+  }
+  if (string[i])
+    goto get_token;
+
+  return (result);
+}
+
+#ifdef STATIC_MALLOC
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                     xmalloc and xrealloc ()                     */
+/*                                                                 */
+/* **************************************************************** */
+
+static void memory_error_and_abort ();
+
+static char *
+xmalloc (bytes)
+     int bytes;
+{
+  char *temp = (char *)malloc (bytes);
+
+  if (!temp)
+    memory_error_and_abort ();
+  return (temp);
+}
+
+static char *
+xrealloc (pointer, bytes)
+     char *pointer;
+     int bytes;
+{
+  char *temp = (char *)realloc (pointer, bytes);
+
+  if (!temp)
+    memory_error_and_abort ();
+  return (temp);
+}
+
+static void
+memory_error_and_abort ()
+{
+  fprintf (stderr, "history: Out of virtual memory!\n");
+  abort ();
+}
+#endif /* STATIC_MALLOC */
+
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                             Test Code                           */
+/*                                                                 */
+/* **************************************************************** */
+#ifdef TEST
+main ()
+{
+  char line[1024], *t;
+  int done = 0;
+
+  line[0] = 0;
+
+  while (!done)
+    {
+      fprintf (stdout, "history%% ");
+      t = gets (line);
+
+      if (!t)
+       strcpy (line, "quit");
+
+      if (line[0])
+       {
+         char *expansion;
+         int result;
+
+         using_history ();
+
+         result = history_expand (line, &expansion);
+         strcpy (line, expansion);
+         free (expansion);
+         if (result)
+           fprintf (stderr, "%s\n", line);
+
+         if (result < 0)
+           continue;
+
+         add_history (line);
+       }
+
+      if (strcmp (line, "quit") == 0) done = 1;
+      if (strcmp (line, "save") == 0) write_history (0);
+      if (strcmp (line, "read") == 0) read_history (0);
+      if (strcmp (line, "list") == 0)
+       {
+         register HIST_ENTRY **the_list = history_list ();
+         register int i;
+
+         if (the_list)
+           for (i = 0; the_list[i]; i++)
+             fprintf (stdout, "%d: %s\n", i + history_base, the_list[i]->line);
+       }
+      if (strncmp (line, "delete", strlen ("delete")) == 0)
+       {
+         int which;
+         if ((sscanf (line + strlen ("delete"), "%d", &which)) == 1)
+           {
+             HIST_ENTRY *entry = remove_history (which);
+             if (!entry)
+               fprintf (stderr, "No such entry %d\n", which);
+             else
+               {
+                 free (entry->line);
+                 free (entry);
+               }
+           }
+         else
+           {
+             fprintf (stderr, "non-numeric arg given to `delete'\n");
+           }
+       }
+    }
+}
+
+#endif                         /* TEST */
+\f
+/*
+* Local variables:
+* compile-command: "gcc -g -DTEST -o history history.c"
+* end:
+*/
diff --git a/readline/history.h b/readline/history.h
new file mode 100644 (file)
index 0000000..0bac209
--- /dev/null
@@ -0,0 +1,108 @@
+/* History.h -- the names of functions that you can call in history. */
+
+typedef struct _hist_entry {
+  char *line;
+  char *data;
+} HIST_ENTRY;
+
+/* For convenience only.  You set this when interpreting history commands.
+   It is the logical offset of the first history element. */
+extern int history_base;
+
+/* Begin a session in which the history functions might be used.  This
+   just initializes the interactive variables. */
+extern void using_history ();
+
+/* Place STRING at the end of the history list.
+   The associated data field (if any) is set to NULL. */
+extern void add_history ();
+
+/* Returns the number which says what history element we are now
+   looking at.  */
+extern int where_history ();
+  
+/* Set the position in the history list to POS. */
+int history_set_pos ();
+   
+/* Search for STRING in the history list, starting at POS, an
+   absolute index into the list.  DIR, if negative, says to search
+   backwards from POS, else forwards.
+   Returns the absolute index of the history element where STRING
+   was found, or -1 otherwise. */
+extern int history_search_pos ();
+
+/* A reasonably useless function, only here for completeness.  WHICH
+   is the magic number that tells us which element to delete.  The
+   elements are numbered from 0. */
+extern HIST_ENTRY *remove_history ();
+
+/* Stifle the history list, remembering only MAX number of entries. */
+extern void stifle_history ();
+
+/* Stop stifling the history.  This returns the previous amount the
+   history was stifled by.  The value is positive if the history was
+   stifled, negative if it wasn't. */
+extern int unstifle_history ();
+
+/* Add the contents of FILENAME to the history list, a line at a time.
+   If FILENAME is NULL, then read from ~/.history.  Returns 0 if
+   successful, or errno if not. */
+extern int read_history ();
+
+/* Append the current history to FILENAME.  If FILENAME is NULL,
+   then append the history list to ~/.history.  Values returned
+   are as in read_history ().  */
+extern int write_history ();
+
+
+/* Make the history entry at WHICH have LINE and DATA.  This returns
+   the old entry so you can dispose of the data.  In the case of an
+   invalid WHICH, a NULL pointer is returned. */
+extern HIST_ENTRY *replace_history_entry ();
+
+/* Return the history entry at the current position, as determined by
+   history_offset.  If there is no entry there, return a NULL pointer. */
+HIST_ENTRY *current_history ();
+
+/* Back up history_offset to the previous history entry, and return
+   a pointer to that entry.  If there is no previous entry, return
+   a NULL pointer. */
+extern HIST_ENTRY *previous_history ();
+
+/* Move history_offset forward to the next item in the input_history,
+   and return the a pointer to that entry.  If there is no next entry,
+   return a NULL pointer. */
+extern HIST_ENTRY *next_history ();
+
+/* Return a NULL terminated array of HIST_ENTRY which is the current input
+   history.  Element 0 of this list is the beginning of time.  If there
+   is no history, return NULL. */
+extern HIST_ENTRY **history_list ();
+
+/* Search the history for STRING, starting at history_offset.
+   If DIRECTION < 0, then the search is through previous entries,
+   else through subsequent.  If the string is found, then
+   current_history () is the history entry, and the value of this function
+   is the offset in the line of that history entry that the string was
+   found in.  Otherwise, nothing is changed, and a -1 is returned. */
+extern int history_search ();
+
+/* Expand the string STRING, placing the result into OUTPUT, a pointer
+   to a string.  Returns:
+
+   0) If no expansions took place (or, if the only change in
+      the text was the de-slashifying of the history expansion
+      character)
+   1) If expansions did take place
+  -1) If there was an error in expansion.
+
+  If an error ocurred in expansion, then OUTPUT contains a descriptive
+  error message. */
+extern int history_expand ();
+
+/* Extract a string segment consisting of the FIRST through LAST
+   arguments present in STRING.  Arguments are broken up as in
+   the shell. */
+extern char *history_arg_extract ();
+
+
diff --git a/readline/keymaps.c b/readline/keymaps.c
new file mode 100644 (file)
index 0000000..b7c79ce
--- /dev/null
@@ -0,0 +1,172 @@
+/* keymaps.c -- Functions and keymaps for the GNU Readline library. */
+
+/* Copyright (C) 1988,1989 Free Software Foundation, Inc.
+
+   This file is part of GNU Readline, a library for reading lines
+   of text with interactive input and history editing.
+
+   Readline 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.
+
+   Readline 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 Readline; see the file COPYING.  If not, write to the Free
+   Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "keymaps.h"
+#include "emacs_keymap.c"
+
+#ifdef VI_MODE
+#include "vi_keymap.c"
+#endif
+
+/* Remove these declarations when we have a complete libgnu.a. */
+#define STATIC_MALLOC
+#ifndef STATIC_MALLOC
+extern char *xmalloc (), *xrealloc ();
+#else
+static char *xmalloc (), *xrealloc ();
+#endif
+
+/* **************************************************************** */
+/*                                                                 */
+/*                   Functions for manipulating Keymaps.           */
+/*                                                                 */
+/* **************************************************************** */
+
+
+/* Return a new, empty keymap.
+   Free it with free() when you are done. */
+Keymap
+rl_make_bare_keymap ()
+{
+  register int i;
+  Keymap keymap = (Keymap)xmalloc (128 * sizeof (KEYMAP_ENTRY));
+
+  for (i = 0; i < 128; i++)
+    {
+      keymap[i].type = ISFUNC;
+      keymap[i].function = (Function *)NULL;
+    }
+
+  for (i = 'A'; i < ('Z' + 1); i++)
+    {
+      keymap[i].type = ISFUNC;
+      keymap[i].function = rl_do_lowercase_version;
+    }
+
+  return (keymap);
+}
+
+/* Return a new keymap which is a copy of MAP. */
+Keymap
+rl_copy_keymap (map)
+     Keymap map;
+{
+  register int i;
+  Keymap temp = rl_make_bare_keymap ();
+
+  for (i = 0; i < 128; i++)
+    {
+      temp[i].type = map[i].type;
+      temp[i].function = map[i].function;
+    }
+  return (temp);
+}
+
+/* Return a new keymap with the printing characters bound to rl_insert,
+   the uppercase Meta characters bound to run their lowercase equivalents,
+   and the Meta digits bound to produce numeric arguments. */
+Keymap
+rl_make_keymap ()
+{
+  extern rl_insert (), rl_rubout (), rl_do_lowercase_version ();
+  extern rl_digit_argument ();
+  register int i;
+  Keymap newmap;
+
+  newmap = rl_make_bare_keymap ();
+
+  /* All printing characters are self-inserting. */
+  for (i = ' '; i < 126; i++)
+    newmap[i].function = rl_insert;
+
+  newmap[TAB].function = rl_insert;
+  newmap[RUBOUT].function = rl_rubout;
+
+  return (newmap);
+}
+
+/* Free the storage associated with MAP. */
+rl_discard_keymap (map)
+     Keymap (map);
+{
+  int i;
+
+  if (!map)
+    return;
+
+  for (i = 0; i < 128; i++)
+    {
+      switch (map[i].type)
+       {
+       case ISFUNC:
+         break;
+
+       case ISKMAP:
+         rl_discard_keymap ((Keymap)map[i].function);
+         break;
+
+       case ISMACR:
+         free ((char *)map[i].function);
+         break;
+       }
+    }
+}
+
+#ifdef STATIC_MALLOC
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                     xmalloc and xrealloc ()                     */
+/*                                                                 */
+/* **************************************************************** */
+
+static void memory_error_and_abort ();
+
+static char *
+xmalloc (bytes)
+     int bytes;
+{
+  char *temp = (char *)malloc (bytes);
+
+  if (!temp)
+    memory_error_and_abort ();
+  return (temp);
+}
+
+static char *
+xrealloc (pointer, bytes)
+     char *pointer;
+     int bytes;
+{
+  char *temp = (char *)realloc (pointer, bytes);
+
+  if (!temp)
+    memory_error_and_abort ();
+  return (temp);
+}
+
+static void
+memory_error_and_abort ()
+{
+  fprintf (stderr, "readline: Out of virtual memory!\n");
+  abort ();
+}
+#endif /* STATIC_MALLOC */
diff --git a/readline/keymaps.h b/readline/keymaps.h
new file mode 100644 (file)
index 0000000..3c577b3
--- /dev/null
@@ -0,0 +1,53 @@
+/* keymaps.h -- Manipulation of readline keymaps. */
+
+#ifndef _KEYMAPS_H_
+#define _KEYMAPS_H_
+
+#include <readline/chardefs.h>
+
+#ifndef __FUNCTION_DEF
+typedef int Function ();
+#define __FUNCTION_DEF
+#endif
+
+/* A keymap contains one entry for each key in the ASCII set.
+   Each entry consists of a type and a pointer.
+   POINTER is the address of a function to run, or the
+   address of a keymap to indirect through.
+   TYPE says which kind of thing POINTER is. */
+typedef struct _keymap_entry {
+  char type;
+  Function *function;
+} KEYMAP_ENTRY;
+
+/* I wanted to make the above structure contain a union of:
+   union { Function *function; struct _keymap_entry *keymap; } value;
+   but this made it impossible for me to create a static array.
+   Maybe I need C lessons. */
+
+typedef KEYMAP_ENTRY KEYMAP_ENTRY_ARRAY[128];
+typedef KEYMAP_ENTRY *Keymap;
+
+/* The values that TYPE can have in a keymap entry. */
+#define ISFUNC 0
+#define ISKMAP 1
+#define ISMACR 2
+
+extern KEYMAP_ENTRY_ARRAY emacs_standard_keymap, emacs_meta_keymap, emacs_ctlx_keymap;
+extern KEYMAP_ENTRY_ARRAY vi_insertion_keymap, vi_movement_keymap;
+
+/* Return a new, empty keymap.
+   Free it with free() when you are done. */
+Keymap rl_make_bare_keymap ();
+
+/* Return a new keymap which is a copy of MAP. */
+Keymap rl_copy_keymap ();
+
+/* Return a new keymap with the printing characters bound to rl_insert,
+   the lowercase Meta characters bound to run their equivalents, and
+   the Meta digits bound to produce numeric arguments. */
+Keymap rl_make_keymap ();
+
+#endif /* _KEYMAPS_H_ */
+
+
diff --git a/readline/readline.c b/readline/readline.c
new file mode 100644 (file)
index 0000000..b05a7c9
--- /dev/null
@@ -0,0 +1,5641 @@
+/* readline.c -- a general facility for reading lines of input
+   with emacs style editing and completion. */
+
+/* Copyright (C) 1987,1989 Free Software Foundation, Inc.
+
+   This file contains the Readline Library (the Library), a set of
+   routines for providing Emacs style line input to programs that ask
+   for it.
+
+   The Library 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.
+
+   The Library 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.
+
+   The GNU General Public License is often shipped with GNU software, and
+   is generally kept in a file called COPYING or LICENSE.  If you do not
+   have a copy of the license, write to the Free Software Foundation,
+   675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Remove these declarations when we have a complete libgnu.a. */
+#define STATIC_MALLOC
+#ifndef STATIC_MALLOC
+extern char *xmalloc (), *xrealloc ();
+#else
+static char *xmalloc (), *xrealloc ();
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/file.h>
+#include <signal.h>
+
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else
+#if defined (sparc) && defined (sun)
+#include <alloca.h>
+#endif
+#endif
+
+#define NEW_TTY_DRIVER
+#if defined (SYSV) || defined (hpux)  || defined (Xenix)
+#undef NEW_TTY_DRIVER
+#include <termio.h>
+#else
+#include <sgtty.h>
+#endif
+
+#include <errno.h>
+extern int errno;
+
+#include <setjmp.h>
+
+/* These next are for filename completion.  Perhaps this belongs
+   in a different place. */
+#include <sys/stat.h>
+
+#include <pwd.h>
+#ifdef SYSV
+struct passwd *getpwuid (), *getpwent ();
+#endif
+
+#define HACK_TERMCAP_MOTION
+
+#ifndef SYSV
+#include <sys/dir.h>
+#else  /* SYSV */
+#if defined (Xenix)
+#include <sys/ndir.h>
+#else
+#ifdef hpux
+#include <ndir.h>
+#else
+#include <dirent.h>
+#define direct dirent
+#define d_namlen d_reclen
+#endif  /* hpux */
+#endif  /* xenix */
+#endif  /* SYSV */
+
+/* Some standard library routines. */
+#include "readline.h"
+#include "history.h"
+
+#ifndef digit
+#define digit(c)  ((c) >= '0' && (c) <= '9')
+#endif
+
+#ifndef isletter
+#define isletter(c) (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z'))
+#endif
+
+#ifndef digit_value
+#define digit_value(c) ((c) - '0')
+#endif
+
+#ifndef member
+char *index ();
+#define member(c, s) ((c) ? index ((s), (c)) : 0)
+#endif
+
+#ifndef isident
+#define isident(c) ((isletter(c) || digit(c) || c == '_'))
+#endif
+
+#ifndef exchange
+#define exchange(x, y) {int temp = x; x = y; y = temp;}
+#endif
+
+static update_line ();
+static void output_character_function ();
+static delete_chars ();
+static delete_chars ();
+static insert_some_chars ();
+
+#ifdef VOID_SIGHANDLER
+#define sighandler void
+#else
+#define sighandler int
+#endif
+
+/* This typedef is equivalant to the one for Function; it allows us
+   to say SigHandler *foo = signal (SIGKILL, SIG_IGN); */
+typedef sighandler SigHandler ();
+
+/* If on, then readline handles signals in a way that doesn't screw. */
+#define HANDLE_SIGNALS
+
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                     Line editing input utility                  */
+/*                                                                 */
+/* **************************************************************** */
+
+/* A pointer to the keymap that is currently in use.
+   By default, it is the standard emacs keymap. */
+Keymap keymap = emacs_standard_keymap;
+
+#define vi_mode 0
+#define emacs_mode 1
+
+/* The current style of editing. */
+int rl_editing_mode = emacs_mode;
+
+/* Non-zero if the previous command was a kill command. */
+static int last_command_was_kill = 0;
+
+/* The current value of the numeric argument specified by the user. */
+int rl_numeric_arg = 1;
+
+/* Non-zero if an argument was typed. */
+int rl_explicit_arg = 0;
+
+/* Temporary value used while generating the argument. */
+static int arg_sign = 1;
+
+/* Non-zero means we have been called at least once before. */
+static int rl_initialized = 0;
+
+/* If non-zero, this program is running in an EMACS buffer. */
+static char *running_in_emacs = (char *)NULL;
+
+/* The current offset in the current input line. */
+int rl_point;
+
+/* Mark in the current input line. */
+int rl_mark;
+
+/* Length of the current input line. */
+int rl_end;
+
+/* Make this non-zero to return the current input_line. */
+int rl_done;
+
+/* The last function executed by readline. */
+Function *rl_last_func = (Function *)NULL;
+
+/* Top level environment for readline_internal (). */
+static jmp_buf readline_top_level;
+
+/* The streams we interact with. */
+static FILE *in_stream, *out_stream;
+
+/* The names of the streams that we do input and output to. */
+FILE *rl_instream = stdin, *rl_outstream = stdout;
+
+/* Non-zero means echo characters as they are read. */
+int readline_echoing_p = 1;
+
+/* Current prompt. */
+char *rl_prompt;
+
+/* The number of characters read in order to type this complete command. */
+int rl_key_sequence_length = 0;
+
+/* If non-zero, then this is the address of a function to call just
+   before readline_internal () prints the first prompt. */
+Function *rl_startup_hook = (Function *)NULL;
+
+/* If non-zero, then this is the address of a function to call when
+   completing on a directory name.  The function is called with
+   the address of a string (the current directory name) as an arg. */
+Function *rl_symbolic_link_hook = (Function *)NULL;
+
+/* What we use internally.  You should always refer to RL_LINE_BUFFER. */
+static char *the_line;
+
+/* The character that can generate an EOF.  Really read from
+   the terminal driver... just defaulted here. */
+static int eof_char = CTRL ('D');
+
+/* Non-zero makes this the next keystroke to read. */
+int rl_pending_input = 0;
+
+/* Pointer to a useful terminal name. */
+char *rl_terminal_name = (char *)NULL;
+
+/* Line buffer and maintenence. */
+char *rl_line_buffer = (char *)NULL;
+static int rl_line_buffer_len = 0;
+#define DEFAULT_BUFFER_SIZE 256
+
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                     `Forward' declarations                      */
+/*                                                                 */
+/* **************************************************************** */
+
+/* Non-zero means do not parse any lines other than comments and
+   parser directives. */
+static unsigned char parsing_conditionalized_out = 0;
+
+/* Caseless strcmp (). */
+static int stricmp (), strnicmp ();
+
+/* Non-zero means to save keys that we dispatch on in a kbd macro. */
+static int defining_kbd_macro = 0;
+
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                     Top Level Functions                         */
+/*                                                                 */
+/* **************************************************************** */
+
+/* Read a line of input.  Prompt with PROMPT.  A NULL PROMPT means
+   none.  A return value of NULL means that EOF was encountered. */
+char *
+readline (prompt)
+     char *prompt;
+{
+  static rl_prep_terminal (), rl_deprep_terminal ();
+  char *readline_internal ();
+  char *value;
+
+  rl_prompt = prompt;
+
+  /* If we are at EOF return a NULL string. */
+  if (rl_pending_input == EOF)
+    {
+      rl_pending_input = 0;
+      return ((char *)NULL);
+    }
+
+  rl_initialize ();
+  rl_prep_terminal ();
+
+#ifdef HANDLE_SIGNALS
+  rl_set_signals ();
+#endif
+
+  value = readline_internal ();
+  rl_deprep_terminal ();
+
+#ifdef HANDLE_SIGNALS
+  rl_clear_signals ();
+#endif
+
+  return (value);
+}
+
+/* Read a line of input from the global rl_instream, doing output on
+   the global rl_outstream.
+   If rl_prompt is non-null, then that is our prompt. */
+char *
+readline_internal ()
+{
+  int lastc, c, eof_found;
+
+  in_stream = rl_instream; out_stream = rl_outstream;
+  lastc = eof_found = 0;
+
+  if (rl_startup_hook)
+    (*rl_startup_hook) ();
+
+  if (!readline_echoing_p)
+    {
+      if (rl_prompt)
+       {
+         fprintf (out_stream, "%s", rl_prompt);
+         fflush (out_stream);
+       }
+    }
+  else
+    {
+      rl_on_new_line ();
+      rl_redisplay ();
+#ifdef VI_MODE
+      if (rl_editing_mode == vi_mode)
+       rl_vi_insertion_mode ();
+#endif /* VI_MODE */
+    }
+
+  while (!rl_done)
+    {
+      int lk = last_command_was_kill;
+      int code = setjmp (readline_top_level);
+
+      if (code)
+       rl_redisplay ();
+
+      if (!rl_pending_input)
+       {
+         /* Then initialize the argument and number of keys read. */
+         rl_init_argument ();
+         rl_key_sequence_length = 0;
+       }
+
+      c = rl_read_key ();
+
+      /* EOF typed to a non-blank line is a <NL>. */
+      if (c == EOF && rl_end)
+       c = NEWLINE;
+
+      /* The character eof_char typed to blank line, and not as the
+        previous character is interpreted as EOF. */
+      if (((c == eof_char && lastc != c) || c == EOF) && !rl_end)
+       {
+         eof_found = 1;
+         break;
+       }
+
+      lastc = c;
+      rl_dispatch (c, keymap);
+
+      /* If there was no change in last_command_was_kill, then no kill
+        has taken place.  Note that if input is pending we are reading
+        a prefix command, so nothing has changed yet. */
+      if (!rl_pending_input)
+       {
+         if (lk == last_command_was_kill)
+           last_command_was_kill = 0;
+       }
+
+#ifdef VI_MODE
+      /* In vi mode, when you exit insert mode, the cursor moves back
+        over the previous character.  We explicitly check for that here. */
+      if (rl_editing_mode == vi_mode && keymap == vi_movement_keymap)
+       rl_vi_check ();
+#endif
+
+      if (!rl_done)
+       rl_redisplay ();
+    }
+
+  /* Restore the original of this history line, iff the line that we
+     are editing was originally in the history, AND the line has changed. */
+  {
+    HIST_ENTRY *entry = current_history ();
+
+    if (entry && rl_undo_list)
+      {
+       char *temp = savestring (the_line);
+       rl_revert_line ();
+       entry = replace_history_entry (where_history (), the_line,
+                                      (HIST_ENTRY *)NULL);
+       free_history_entry (entry);
+
+       strcpy (the_line, temp);
+       free (temp);
+      }
+  }
+
+  /* At any rate, it is highly likely that this line has an undo list.  Get
+     rid of it now. */
+  if (rl_undo_list)
+    free_undo_list ();
+
+  if (eof_found)
+    return (char *)NULL;
+  else
+    return (savestring (the_line));
+}
+
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                        Signal Handling                          */
+/*                                                                 */
+/* **************************************************************** */
+
+#ifdef SIGWINCH
+static SigHandler *old_sigwinch = (SigHandler *)NULL;
+
+static sighandler
+rl_handle_sigwinch (sig, code, scp)
+     int sig, code;
+     struct sigcontext *scp;
+{
+  char *term = rl_terminal_name, *getenv ();
+
+  if (readline_echoing_p)
+    {
+      if (!term)
+       term = getenv ("TERM");
+      if (!term)
+       term = "dumb";
+      rl_reset_terminal (term);
+#ifdef NEVER
+      crlf ();
+      rl_forced_update_display ();
+#endif
+    }
+
+  if (old_sigwinch &&
+      old_sigwinch != (SigHandler *)SIG_IGN &&
+      old_sigwinch != (SigHandler *)SIG_DFL)
+    (*old_sigwinch)(sig, code, scp);
+}
+#endif  /* SIGWINCH */
+
+#ifdef HANDLE_SIGNALS
+/* Interrupt handling. */
+static SigHandler *old_int  = (SigHandler *)NULL,
+                 *old_tstp = (SigHandler *)NULL,
+                 *old_ttou = (SigHandler *)NULL,
+                 *old_ttin = (SigHandler *)NULL,
+                 *old_cont = (SigHandler *)NULL;
+
+/* Handle an interrupt character. */
+static sighandler
+rl_signal_handler (sig, code, scp)
+     int sig, code;
+     struct sigcontext *scp;
+{
+  static rl_prep_terminal (), rl_deprep_terminal ();
+
+  switch (sig)
+    {
+    case SIGINT:
+      free_undo_list ();
+      rl_clear_message ();
+      rl_init_argument ();
+
+#ifdef SIGTSTP
+    case SIGTSTP:
+    case SIGTTOU:
+    case SIGTTIN:
+#endif
+
+      rl_clean_up_for_exit ();
+      rl_deprep_terminal ();
+      rl_clear_signals ();
+      rl_pending_input = 0;
+
+      kill (getpid (), sig);
+      sigsetmask (0);
+
+      rl_prep_terminal ();
+      rl_set_signals ();
+    }
+}
+
+rl_set_signals ()
+{
+  old_int = (SigHandler *)signal (SIGINT, rl_signal_handler);
+  if (old_int == (SigHandler *)SIG_IGN)
+    signal (SIGINT, SIG_IGN);
+
+#ifdef SIGTSTP
+  old_tstp = (SigHandler *)signal (SIGTSTP, rl_signal_handler);
+  if (old_tstp == (SigHandler *)SIG_IGN)
+    signal (SIGTSTP, SIG_IGN);
+#endif
+#ifdef SIGTTOU
+  old_ttou = (SigHandler *)signal (SIGTTOU, rl_signal_handler);
+  old_ttin = (SigHandler *)signal (SIGTTIN, rl_signal_handler);
+
+  if (old_tstp == (SigHandler *)SIG_IGN)
+    {
+      signal (SIGTTOU, SIG_IGN);
+      signal (SIGTTIN, SIG_IGN);
+    }
+#endif
+
+#ifdef SIGWINCH
+  old_sigwinch = (SigHandler *)signal (SIGWINCH, rl_handle_sigwinch);
+#endif
+}
+
+rl_clear_signals ()
+{
+  signal (SIGINT, old_int);
+
+#ifdef SIGTSTP
+  signal (SIGTSTP, old_tstp);
+#endif
+
+#ifdef SIGTTOU
+  signal (SIGTTOU, old_ttou);
+  signal (SIGTTIN, old_ttin);
+#endif
+
+#ifdef SIGWINCH
+      signal (SIGWINCH, old_sigwinch);
+#endif
+}
+#endif  /* HANDLE_SIGNALS */
+
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                     Character Input Buffering                   */
+/*                                                                 */
+/* **************************************************************** */
+
+/* If the terminal was in xoff state when we got to it, then xon_char
+   contains the character that is supposed to start it again. */
+static int xon_char, xoff_state;
+static int pop_index = 0, push_index = 0, ibuffer_len = 511;
+static unsigned char ibuffer[512];
+
+/* Non-null means it is a pointer to a function to run while waiting for
+   character input. */
+Function *rl_event_hook = (Function *)NULL;
+
+#define any_typein (push_index != pop_index)
+
+/* Add KEY to the buffer of characters to be read. */
+rl_stuff_char (key)
+     int key;
+{
+  if (key == EOF)
+    {
+      key = NEWLINE;
+      rl_pending_input = EOF;
+    }
+  ibuffer[push_index++] = key;
+  if (push_index >= ibuffer_len)
+    push_index = 0;
+}
+
+/* Return the amount of space available in the
+   buffer for stuffing characters. */
+int
+ibuffer_space ()
+{
+  if (pop_index > push_index)
+    return (pop_index - push_index);
+  else
+    return (ibuffer_len - (push_index - pop_index));
+}
+
+/* Get a key from the buffer of characters to be read.
+   Return the key in KEY.
+   Result is KEY if there was a key, or 0 if there wasn't. */
+int
+rl_get_char (key)
+     int *key;
+{
+  if (push_index == pop_index)
+    return (0);
+
+  *key = ibuffer[pop_index++];
+
+  if (pop_index >= ibuffer_len)
+    pop_index = 0;
+
+  return (1);
+}
+
+/* Stuff KEY into the *front* of the input buffer.
+   Returns non-zero if successful, zero if there is
+   no space left in the buffer. */
+int
+rl_unget_char (key)
+     int key;
+{
+  if (ibuffer_space ())
+    {
+      pop_index--;
+      if (pop_index < 0)
+       pop_index = ibuffer_len - 1;
+      ibuffer[pop_index] = key;
+      return (1);
+    }
+  return (0);
+}
+
+/* If a character is available to be read, then read it
+   and stuff it into IBUFFER.  Otherwise, just return. */
+rl_gather_tyi ()
+{
+  int tty = fileno (in_stream);
+  register int tem, result = -1;
+  long chars_avail;
+  char input;
+
+#ifdef FIONREAD
+  result = ioctl (tty, FIONREAD, &chars_avail);
+#endif
+
+  if (result == -1)
+    {
+      fcntl (tty, F_SETFL, O_NDELAY);
+      chars_avail = read (tty, &input, 1);
+      fcntl (tty, F_SETFL, 0);
+      if (chars_avail == -1 && errno == EAGAIN)
+       return;
+    }
+
+  tem = ibuffer_space ();
+
+  if (chars_avail > tem)
+    chars_avail = tem;
+
+  /* One cannot read all of the available input.  I can only read a single
+     character at a time, or else programs which require input can be
+     thwarted.  If the buffer is larger than one character, I lose.
+     Damn! */
+  if (tem < ibuffer_len)
+    chars_avail = 0;
+
+  if (result != -1)
+    {
+      while (chars_avail--)
+       rl_stuff_char (rl_getc (in_stream));
+    }
+  else
+    {
+      if (chars_avail)
+       rl_stuff_char (input);
+    }
+}
+
+/* Read a key, including pending input. */
+int
+rl_read_key ()
+{
+  int c;
+
+  rl_key_sequence_length++;
+
+  if (rl_pending_input)
+    {
+      c = rl_pending_input;
+      rl_pending_input = 0;
+    }
+  else
+    {
+      static int next_macro_key ();
+
+      /* If input is coming from a macro, then use that. */
+      if (c = next_macro_key ())
+       return (c);
+
+      /* If the user has an event function, then call it periodically. */
+      if (rl_event_hook)
+       {
+         while (rl_event_hook && !rl_get_char (&c))
+           {
+             (*rl_event_hook) ();
+             rl_gather_tyi ();
+           }
+       }
+      else
+       {
+         if (!rl_get_char (&c))
+           c = rl_getc (in_stream);
+       }
+    }
+
+#ifdef NEVER  /* This breaks supdup to 4.0.3c machines. */
+#ifdef TIOCSTART
+  /* Ugh.  But I can't think of a better way. */
+  if (xoff_state && c == xon_char)
+    {
+      ioctl (fileno (in_stream), TIOCSTART, 0);
+      xoff_state = 0;
+      return (rl_read_key ());
+    }
+#endif /* TIOCSTART */
+#endif
+
+  return (c);
+}
+
+/* I'm beginning to hate the declaration rules for various compilers. */
+static void add_macro_char ();
+
+/* Do the command associated with KEY in MAP.
+   If the associated command is really a keymap, then read
+   another key, and dispatch into that map. */
+rl_dispatch (key, map)
+     register int key;
+     Keymap map;
+{
+
+  if (defining_kbd_macro)
+    add_macro_char (key);
+
+  if (key > 127 && key < 256)
+    {
+      if (map[ESC].type == ISKMAP)
+       {
+         map = (Keymap)map[ESC].function;
+         key -= 128;
+         rl_dispatch (key, map);
+       }
+      else
+       ding ();
+      return;
+    }
+
+  switch (map[key].type)
+    {
+    case ISFUNC:
+      {
+       Function *func = map[key].function;
+
+       if (func != (Function *)NULL)
+         {
+           /* Special case rl_do_lowercase_version (). */
+           if (func == rl_do_lowercase_version)
+             {
+               rl_dispatch (to_lower (key), map);
+               return;
+             }
+
+           (*map[key].function)(rl_numeric_arg * arg_sign, key);
+         }
+       else
+         {
+           ding ();
+           return;
+         }
+      }
+      break;
+
+    case ISKMAP:
+      if (map[key].function != (Function *)NULL)
+       {
+         int newkey;
+
+         rl_key_sequence_length++;
+         newkey = rl_read_key ();
+         rl_dispatch (newkey, (Keymap)map[key].function);
+       }
+      else
+       {
+         ding ();
+         return;
+       }
+      break;
+
+    case ISMACR:
+      if (map[key].function != (Function *)NULL)
+       {
+         static with_macro_input ();
+         char *macro = savestring ((char *)map[key].function);
+
+         with_macro_input (macro);
+         return;
+       }
+      break;
+    }
+
+  /* If we have input pending, then the last command was a prefix
+     command.  Don't change the state of rl_last_func. */
+  if (!rl_pending_input)
+    rl_last_func = map[key].function;
+}
+
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                     Hacking Keyboard Macros                     */
+/*                                                                 */
+/* **************************************************************** */
+
+/* The currently executing macro string.  If this is non-zero,
+   then it is a malloc ()'ed string where input is coming from. */
+static char *executing_macro = (char *)NULL;
+
+/* The offset in the above string to the next character to be read. */
+static int executing_macro_index = 0;
+
+/* The current macro string being built.  Characters get stuffed
+   in here by add_macro_char (). */
+static char *current_macro = (char *)NULL;
+
+/* The size of the buffer allocated to current_macro. */
+static int current_macro_size = 0;
+
+/* The index at which characters are being added to current_macro. */
+static int current_macro_index = 0;
+
+/* A structure used to save nested macro strings.
+   It is a linked list of string/index for each saved macro. */
+struct saved_macro {
+  struct saved_macro *next;
+  char *string;
+  int index;
+};
+
+/* The list of saved macros. */
+struct saved_macro *macro_list = (struct saved_macro *)NULL;
+
+/* Forward declarations of static functions.  Thank you C. */
+static void push_executing_macro (), pop_executing_macro ();
+
+/* This one has to be declared earlier in the file. */
+/* static void add_macro_char (); */
+
+/* Set up to read subsequent input from STRING.
+   STRING is free ()'ed when we are done with it. */
+static
+with_macro_input (string)
+     char *string;
+{
+  push_executing_macro ();
+  executing_macro = string;
+  executing_macro_index = 0;
+}
+
+/* Return the next character available from a macro, or 0 if
+   there are no macro characters. */
+static int
+next_macro_key ()
+{
+  if (!executing_macro)
+    return (0);
+
+  if (!executing_macro[executing_macro_index])
+    {
+      pop_executing_macro ();
+      return (next_macro_key ());
+    }
+
+  return (executing_macro[executing_macro_index++]);
+}
+
+/* Save the currently executing macro on a stack of saved macros. */
+static void
+push_executing_macro ()
+{
+  struct saved_macro *saver;
+
+  saver = (struct saved_macro *)xmalloc (sizeof (struct saved_macro));
+  saver->next = macro_list;
+  saver->index = executing_macro_index;
+  saver->string = executing_macro;
+
+  macro_list = saver;
+}
+
+/* Discard the current macro, replacing it with the one
+   on the top of the stack of saved macros. */
+static void
+pop_executing_macro ()
+{
+  if (executing_macro)
+    free (executing_macro);
+
+  executing_macro = (char *)NULL;
+  executing_macro_index = 0;
+
+  if (macro_list)
+    {
+      struct saved_macro *disposer = macro_list;
+      executing_macro = macro_list->string;
+      executing_macro_index = macro_list->index;
+      macro_list = macro_list->next;
+      free (disposer);
+    }
+}
+
+/* Add a character to the macro being built. */
+static void
+add_macro_char (c)
+     int c;
+{
+  if (current_macro_index + 1 >= current_macro_size)
+    {
+      if (!current_macro)
+       current_macro = (char *)xmalloc (current_macro_size = 25);
+      else
+       current_macro =
+         (char *)xrealloc (current_macro, current_macro_size += 25);
+    }
+
+  current_macro[current_macro_index++] = c;
+  current_macro[current_macro_index] = '\0';
+}
+
+/* Begin defining a keyboard macro.
+   Keystrokes are recorded as they are executed.
+   End the definition with rl_end_kbd_macro ().
+   If a numeric argument was explicitly typed, then append this
+   definition to the end of the existing macro, and start by
+   re-executing the existing macro. */
+rl_start_kbd_macro (ignore1, ignore2)
+     int ignore1, ignore2;
+{
+  if (defining_kbd_macro)
+    rl_abort ();
+
+  if (rl_explicit_arg)
+    {
+      if (current_macro)
+       with_macro_input (savestring (current_macro));
+    }
+  else
+    current_macro_index = 0;
+
+  defining_kbd_macro = 1;
+}
+
+/* Stop defining a keyboard macro.
+   A numeric argument says to execute the macro right now,
+   that many times, counting the definition as the first time. */
+rl_end_kbd_macro (count, ignore)
+     int count, ignore;
+{
+  if (!defining_kbd_macro)
+    rl_abort ();
+
+  current_macro_index -= (rl_key_sequence_length - 1);
+  current_macro[current_macro_index] = '\0';
+
+  defining_kbd_macro = 0;
+
+  rl_call_last_kbd_macro (--count, 0);
+}
+
+/* Execute the most recently defined keyboard macro.
+   COUNT says how many times to execute it. */
+rl_call_last_kbd_macro (count, ignore)
+     int count, ignore;
+{
+  if (!current_macro)
+    rl_abort ();
+
+  while (count--)
+    with_macro_input (savestring (current_macro));
+}
+
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                     Initializations                             */
+/*                                                                 */
+/* **************************************************************** */
+
+/* Initliaze readline (and terminal if not already). */
+rl_initialize ()
+{
+  extern char *rl_display_prompt;
+
+  /* If we have never been called before, initialize the
+     terminal and data structures. */
+  if (!rl_initialized)
+    {
+      readline_initialize_everything ();
+      rl_initialized++;
+    }
+
+  /* Initalize the current line information. */
+  rl_point = rl_end = 0;
+  the_line = rl_line_buffer;
+  the_line[0] = 0;
+
+  /* We aren't done yet.  We haven't even gotten started yet! */
+  rl_done = 0;
+
+  /* Tell the history routines what is going on. */
+  start_using_history ();
+
+  /* Make the display buffer match the state of the line. */
+  {
+    extern char *rl_display_prompt;
+    extern int forced_display;
+
+    rl_on_new_line ();
+
+    rl_display_prompt = rl_prompt ? rl_prompt : "";
+    forced_display = 1;
+  }
+
+  /* No such function typed yet. */
+  rl_last_func = (Function *)NULL;
+
+  /* Parsing of key-bindings begins in an enabled state. */
+  parsing_conditionalized_out = 0;
+}
+
+/* Initialize the entire state of the world. */
+readline_initialize_everything ()
+{
+  /* Find out if we are running in Emacs. */
+  running_in_emacs = (char *)getenv ("EMACS");
+
+  /* Allocate data structures. */
+  if (!rl_line_buffer)
+    rl_line_buffer =
+      (char *)xmalloc (rl_line_buffer_len = DEFAULT_BUFFER_SIZE);
+
+  /* Initialize the terminal interface. */
+  init_terminal_io ((char *)NULL);
+
+  /* Bind tty characters to readline functions. */
+  readline_default_bindings ();
+
+  /* Initialize the function names. */
+  rl_initialize_funmap ();
+
+  /* Read in the init file. */
+  rl_read_init_file ((char *)NULL);
+
+  /* If the completion parser's default word break characters haven't
+     been set yet, then do so now. */
+  {
+    extern char *rl_completer_word_break_characters;
+    extern char *rl_basic_word_break_characters;
+
+    if (rl_completer_word_break_characters == (char *)NULL)
+      rl_completer_word_break_characters = rl_basic_word_break_characters;
+  }
+}
+
+/* If this system allows us to look at the values of the regular
+   input editing characters, then bind them to their readline
+   equivalents. */
+readline_default_bindings ()
+{
+
+#ifdef NEW_TTY_DRIVER
+  struct sgttyb ttybuff;
+  int tty = fileno (rl_instream);
+
+  if (ioctl (tty, TIOCGETP, &ttybuff) != -1)
+    {
+      int erase = ttybuff.sg_erase, kill = ttybuff.sg_kill;
+
+      if (erase != -1 && keymap[erase].type == ISFUNC)
+       keymap[erase].function = rl_rubout;
+
+      if (kill != -1 && keymap[kill].type == ISFUNC)
+       keymap[kill].function = rl_unix_line_discard;
+    }
+
+#ifdef TIOCGLTC
+  {
+    struct ltchars lt;
+
+    if (ioctl (tty, TIOCGLTC, &lt) != -1)
+      {
+       int erase = lt.t_werasc, nextc = lt.t_lnextc;
+
+       if (erase != -1 && keymap[erase].type == ISFUNC)
+         keymap[erase].function = rl_unix_word_rubout;
+
+       if (nextc != -1 && keymap[nextc].type == ISFUNC)
+         keymap[nextc].function = rl_quoted_insert;
+      }
+  }
+#endif /* TIOCGLTC */
+#else /* not NEW_TTY_DRIVER */
+  struct termio ttybuff;
+  int tty = fileno (rl_instream);
+
+  if (ioctl (tty, TCGETA, &ttybuff) != -1)
+    {
+      int erase = ttybuff.c_cc[VERASE];
+      int kill = ttybuff.c_cc[VKILL];
+
+      if (erase != -1 && keymap[(unsigned char)erase].type == ISFUNC)
+       keymap[(unsigned char)erase].function = rl_rubout;
+
+      if (kill != -1 && keymap[(unsigned char)kill].type == ISFUNC)
+       keymap[(unsigned char)kill].function = rl_unix_line_discard;
+    }
+#endif /* NEW_TTY_DRIVER */
+}
+
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                     Numeric Arguments                           */
+/*                                                                 */
+/* **************************************************************** */
+
+/* Handle C-u style numeric args, as well as M--, and M-digits. */
+
+/* Add the current digit to the argument in progress. */
+rl_digit_argument (ignore, key)
+     int ignore, key;
+{
+  rl_pending_input = key;
+  rl_digit_loop ();
+}
+
+/* What to do when you abort reading an argument. */
+rl_discard_argument ()
+{
+  ding ();
+  rl_clear_message ();
+  rl_init_argument ();
+}
+
+/* Create a default argument. */
+rl_init_argument ()
+{
+  rl_numeric_arg = arg_sign = 1;
+  rl_explicit_arg = 0;
+}
+
+/* C-u, universal argument.  Multiply the current argument by 4.
+   Read a key.  If the key has nothing to do with arguments, then
+   dispatch on it.  If the key is the abort character then abort. */
+rl_universal_argument ()
+{
+  rl_numeric_arg *= 4;
+  rl_digit_loop ();
+}
+
+rl_digit_loop ()
+{
+  int key, c;
+  while (1)
+    {
+      rl_message ("(arg: %d) ", arg_sign * rl_numeric_arg);
+      key = c = rl_read_key ();
+
+      if (keymap[c].type == ISFUNC &&
+         keymap[c].function == rl_universal_argument)
+       {
+         rl_numeric_arg *= 4;
+         continue;
+       }
+      c = UNMETA (c);
+      if (numeric (c))
+       {
+         if (rl_explicit_arg)
+           rl_numeric_arg = (rl_numeric_arg * 10) + (c - '0');
+         else
+           rl_numeric_arg = (c - '0');
+         rl_explicit_arg = 1;
+       }
+      else
+       {
+         if (c == '-' && !rl_explicit_arg)
+           {
+             rl_numeric_arg = 1;
+             arg_sign = -1;
+           }
+         else
+           {
+             rl_clear_message ();
+             rl_dispatch (key, keymap);
+             return;
+           }
+       }
+    }
+}
+
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                     Display stuff                               */
+/*                                                                 */
+/* **************************************************************** */
+
+/* This is the stuff that is hard for me.  I never seem to write good
+   display routines in C.  Let's see how I do this time. */
+
+/* (PWP) Well... Good for a simple line updater, but totally ignores
+   the problems of input lines longer than the screen width.
+
+   update_line and the code that calls it makes a multiple line,
+   automatically wrapping line update.  Carefull attention needs
+   to be paid to the vertical position variables.
+
+   handling of terminals with autowrap on (incl. DEC braindamage)
+   could be improved a bit.  Right now I just cheat and decrement
+   screenwidth by one. */
+
+/* Keep two buffers; one which reflects the current contents of the
+   screen, and the other to draw what we think the new contents should
+   be.  Then compare the buffers, and make whatever changes to the
+   screen itself that we should.  Finally, make the buffer that we
+   just drew into be the one which reflects the current contents of the
+   screen, and place the cursor where it belongs.
+
+   Commands that want to can fix the display themselves, and then let
+   this function know that the display has been fixed by setting the
+   RL_DISPLAY_FIXED variable.  This is good for efficiency. */
+
+/* Termcap variables: */
+extern char *term_up, *term_dc, *term_cr;
+extern int screenheight, screenwidth, terminal_can_insert;
+
+/* What YOU turn on when you have handled all redisplay yourself. */
+int rl_display_fixed = 0;
+
+/* The visible cursor position.  If you print some text, adjust this. */
+int last_c_pos = 0;
+int last_v_pos = 0;
+
+/* The last left edge of text that was displayed.  This is used when
+   doing horizontal scrolling.  It shifts in thirds of a screenwidth. */
+static int last_lmargin = 0;
+
+/* The line display buffers.  One is the line currently displayed on
+   the screen.  The other is the line about to be displayed. */
+static char *visible_line = (char *)NULL;
+static char *invisible_line = (char *)NULL;
+
+/* Number of lines currently on screen minus 1. */
+int vis_botlin = 0;
+
+/* A buffer for `modeline' messages. */
+char msg_buf[128];
+
+/* Non-zero forces the redisplay even if we thought it was unnecessary. */
+int forced_display = 0;
+
+/* The stuff that gets printed out before the actual text of the line.
+   This is usually pointing to rl_prompt. */
+char *rl_display_prompt = (char *)NULL;
+
+/* Default and initial buffer size.  Can grow. */
+static int line_size = 1024;
+
+/* Non-zero means to always use horizontal scrolling in line display. */
+static int horizontal_scroll_mode = 0;
+
+/* Non-zero means to display an asterisk at the starts of history lines
+   which have been modified. */
+static int mark_modified_lines = 0;
+
+/* I really disagree with this, but my boss (among others) insists that we
+   support compilers that don't work.  I don't think we are gaining by doing
+   so; what is the advantage in producing better code if we can't use it? */
+/* The following two declarations belong inside the
+   function block, not here. */
+static void move_cursor_relative ();
+static void output_some_chars ();
+static void output_character_function ();
+static int compare_strings ();
+
+/* Basic redisplay algorithm. */
+rl_redisplay ()
+{
+  register int in, out, c, linenum;
+  register char *line = invisible_line;
+  int c_pos = 0;
+  int inv_botlin = 0;          /* Number of lines in newly drawn buffer. */
+
+  extern int readline_echoing_p;
+
+  if (!readline_echoing_p)
+    return;
+
+  if (!rl_display_prompt)
+    rl_display_prompt = "";
+
+  if (!invisible_line)
+    {
+      visible_line = (char *)xmalloc (line_size);
+      invisible_line = (char *)xmalloc (line_size);
+      line = invisible_line;
+      for (in = 0; in < line_size; in++)
+       {
+         visible_line[in] = 0;
+         invisible_line[in] = 1;
+       }
+      rl_on_new_line ();
+    }
+
+  /* Draw the line into the buffer. */
+  c_pos = -1;
+
+  /* Mark the line as modified or not.  We only do this for history
+     lines. */
+  out = 0;
+  if (mark_modified_lines && current_history () && rl_undo_list)
+    {
+      line[out++] = '*';
+      line[out] = '\0';
+    }
+
+  /* If someone thought that the redisplay was handled, but the currently
+     visible line has a different modification state than the one about
+     to become visible, then correct the callers misconception. */
+  if (visible_line[0] != invisible_line[0])
+    rl_display_fixed = 0;
+
+  strncpy (line + out,  rl_display_prompt, strlen (rl_display_prompt));
+  out += strlen (rl_display_prompt);
+  line[out] = '\0';
+
+  for (in = 0; in < rl_end; in++)
+    {
+      c = the_line[in];
+
+      if (out + 1 >= line_size)
+       {
+         line_size *= 2;
+         visible_line = (char *)xrealloc (visible_line, line_size);
+         invisible_line = (char *)xrealloc (invisible_line, line_size);
+         line = invisible_line;
+       }
+
+      if (in == rl_point)
+       c_pos = out;
+
+      if (c > 127)
+       {
+         line[out++] = 'M';
+         line[out++] = '-';
+         line[out++] = c - 128;
+       }
+#define DISPLAY_TABS
+#ifdef DISPLAY_TABS
+      else if (c == '\t')
+       {
+         register int newout = (out | (int)7) + 1;
+         while (out < newout)
+           line[out++] = ' ';
+       }
+#endif
+      else if (c < 32)
+       {
+         line[out++] = 'C';
+         line[out++] = '-';
+         line[out++] = c + 64;
+       }
+      else
+       line[out++] = c;
+    }
+  line[out] = '\0';
+  if (c_pos < 0)
+    c_pos = out;
+
+  /* PWP: now is when things get a bit hairy.  The visible and invisible
+     line buffers are really multiple lines, which would wrap every
+     (screenwidth - 1) characters.  Go through each in turn, finding
+     the changed region and updating it.  The line order is top to bottom. */
+
+  /* If we can move the cursor up and down, then use multiple lines,
+     otherwise, let long lines display in a single terminal line, and
+     horizontally scroll it. */
+
+  if (!horizontal_scroll_mode && term_up && *term_up)
+    {
+      int total_screen_chars = (screenwidth * screenheight);
+
+      if (!rl_display_fixed || forced_display)
+       {
+         forced_display = 0;
+
+         /* If we have more than a screenful of material to display, then
+            only display a screenful.  We should display the last screen,
+            not the first.  I'll fix this in a minute. */
+         if (out >= total_screen_chars)
+           out = total_screen_chars - 1;
+
+         /* Number of screen lines to display. */
+         inv_botlin = out / screenwidth;
+
+         /* For each line in the buffer, do the updating display. */
+         for (linenum = 0; linenum <= inv_botlin; linenum++)
+           update_line (linenum > vis_botlin ? ""
+                        : &visible_line[linenum * screenwidth],
+                        &invisible_line[linenum * screenwidth],
+                        linenum);
+
+         /* We may have deleted some lines.  If so, clear the left over
+            blank ones at the bottom out. */
+         if (vis_botlin > inv_botlin)
+           {
+             char *tt;
+             for (; linenum <= vis_botlin; linenum++)
+               {
+                 tt = &visible_line[linenum * screenwidth];
+                 move_vert (linenum);
+                 move_cursor_relative (0, tt);
+                 clear_to_eol ((linenum == vis_botlin)?
+                               strlen (tt) : screenwidth);
+               }
+           }
+         vis_botlin = inv_botlin;
+
+         /* Move the cursor where it should be. */
+         move_vert (c_pos / screenwidth);
+         move_cursor_relative (c_pos % screenwidth,
+                               &invisible_line[(c_pos / screenwidth) * screenwidth]);
+       }
+    }
+  else                         /* Do horizontal scrolling. */
+    {
+      int lmargin;
+
+      /* Always at top line. */
+      last_v_pos = 0;
+
+      /* If the display position of the cursor would be off the edge
+        of the screen, start the display of this line at an offset that
+        leaves the cursor on the screen. */
+      if (c_pos - last_lmargin > screenwidth - 2)
+       lmargin = (c_pos / (screenwidth / 3) - 2) * (screenwidth / 3);
+      else if (c_pos - last_lmargin < 1)
+       lmargin = ((c_pos - 1) / (screenwidth / 3)) * (screenwidth / 3);
+      else
+       lmargin = last_lmargin;
+
+      /* If the first character on the screen isn't the first character
+        in the display line, indicate this with a special character. */
+      if (lmargin > 0)
+       line[lmargin] = '<';
+
+      if (lmargin + screenwidth < out)
+       line[lmargin + screenwidth - 1] = '>';
+
+      if (!rl_display_fixed || forced_display || lmargin != last_lmargin)
+       {
+         forced_display = 0;
+         update_line (&visible_line[last_lmargin],
+                      &invisible_line[lmargin], 0);
+
+         move_cursor_relative (c_pos - lmargin, &invisible_line[lmargin]);
+         last_lmargin = lmargin;
+       }
+    }
+  fflush (out_stream);
+
+  /* Swap visible and non-visible lines. */
+  {
+    char *temp = visible_line;
+    visible_line = invisible_line;
+    invisible_line = temp;
+    rl_display_fixed = 0;
+  }
+}
+
+/* PWP: update_line() is based on finding the middle difference of each
+   line on the screen; vis:
+
+                            /old first difference
+       /beginning of line   |              /old last same       /old EOL
+       v                    v              v                    v
+old:   eddie> Oh, my little gruntle-buggy is to me, as lurgid as
+new:   eddie> Oh, my little buggy says to me, as lurgid as
+       ^                    ^        ^                    ^
+       \beginning of line   |        \new last same       \new end of line
+                            \new first difference
+
+   All are character pointers for the sake of speed.  Special cases for
+   no differences, as well as for end of line additions must be handeled.
+
+   Could be made even smarter, but this works well enough */
+static
+update_line (old, new, current_line)
+     register char *old, *new;
+     int current_line;
+{
+  register char *ofd, *ols, *oe, *nfd, *nls, *ne;
+  int lendiff, wsatend;
+
+  /* Find first difference. */
+  for (ofd = old, nfd = new;
+       (ofd - old < screenwidth) && *ofd && (*ofd == *nfd);
+       ofd++, nfd++)
+    ;
+
+  /* Move to the end of the screen line. */
+  for (oe = ofd; ((oe - old) < screenwidth) && *oe; oe++);
+  for (ne = nfd; ((ne - new) < screenwidth) && *ne; ne++);
+
+  /* If no difference, continue to next line. */
+  if (ofd == oe && nfd == ne)
+    return;
+
+  wsatend = 1;                 /* flag for trailing whitespace */
+  ols = oe - 1;                        /* find last same */
+  nls = ne - 1;
+  while ((*ols == *nls) && (ols > ofd) && (nls > nfd))
+    {
+      if (*ols != ' ')
+       wsatend = 0;
+      ols--;
+      nls--;
+    }
+
+  if (wsatend)
+    {
+      ols = oe;
+      nls = ne;
+    }
+  else if (*ols != *nls)
+    {
+      if (*ols)                        /* don't step past the NUL */
+       ols++;
+      if (*nls)
+       nls++;
+    }
+
+  move_vert (current_line);
+  move_cursor_relative (ofd - old, old);
+
+  /* if (len (new) > len (old)) */
+  lendiff = (nls - nfd) - (ols - ofd);
+
+  /* Insert (diff(len(old),len(new)) ch */
+  if (lendiff > 0)
+    {
+      if (terminal_can_insert)
+       {
+         extern char *term_IC;
+
+         /* Sometimes it is cheaper to print the characters rather than
+            use the terminal's capabilities. */
+         if ((2 * (ne - nfd)) < lendiff && !term_IC)
+           {
+             output_some_chars (nfd, (ne - nfd));
+             last_c_pos += (ne - nfd);
+           }
+         else
+           {
+             if (*ols)
+               {
+                 insert_some_chars (nfd, lendiff);
+                 last_c_pos += lendiff;
+               }
+             else
+               {
+                 /* At the end of a line the characters do not have to
+                    be "inserted".  They can just be placed on the screen. */
+                 output_some_chars (nfd, lendiff);
+                 last_c_pos += lendiff;
+               }
+             /* Copy (new) chars to screen from first diff to last match. */
+             if (((nls - nfd) - lendiff) > 0)
+               {
+                 output_some_chars (&nfd[lendiff], ((nls - nfd) - lendiff));
+                 last_c_pos += ((nls - nfd) - lendiff);
+               }
+           }
+       }
+      else
+       {               /* cannot insert chars, write to EOL */
+         output_some_chars (nfd, (ne - nfd));
+         last_c_pos += (ne - nfd);
+       }
+    }
+  else                         /* Delete characters from line. */
+    {
+      /* If possible and inexpensive to use terminal deletion, then do so. */
+      if (term_dc && (2 * (ne - nfd)) >= (-lendiff))
+       {
+         if (lendiff)
+           delete_chars (-lendiff); /* delete (diff) characters */
+
+         /* Copy (new) chars to screen from first diff to last match */
+         if ((nls - nfd) > 0)
+           {
+             output_some_chars (nfd, (nls - nfd));
+             last_c_pos += (nls - nfd);
+           }
+       }
+      /* Otherwise, print over the existing material. */
+      else
+       {
+         output_some_chars (nfd, (ne - nfd));
+         last_c_pos += (ne - nfd);
+         clear_to_eol ((oe - old) - (ne - new));
+       }
+    }
+}
+
+/* (PWP) tell the update routines that we have moved onto a
+   new (empty) line. */
+rl_on_new_line ()
+{
+  if (visible_line)
+    visible_line[0] = '\0';
+
+  last_c_pos = last_v_pos = 0;
+  vis_botlin = last_lmargin = 0;
+}
+
+/* Actually update the display, period. */
+rl_forced_update_display ()
+{
+  if (visible_line)
+    {
+      register char *temp = visible_line;
+
+      while (*temp) *temp++ = '\0';
+    }
+  rl_on_new_line ();
+  forced_display++;
+  rl_redisplay ();
+}
+
+/* Move the cursor from last_c_pos to NEW, which are buffer indices.
+   DATA is the contents of the screen line of interest; i.e., where
+   the movement is being done. */
+static void
+move_cursor_relative (new, data)
+     int new;
+     char *data;
+{
+  register int i;
+
+  /* It may be faster to output a CR, and then move forwards instead
+     of moving backwards. */
+  if (new + 1 < last_c_pos - new)
+    {
+      tputs (term_cr, 1, output_character_function);
+      last_c_pos = 0;
+    }
+
+  if (last_c_pos == new) return;
+
+  if (last_c_pos < new)
+    {
+      /* Move the cursor forward.  We do it by printing the command
+        to move the cursor forward if there is one, else print that
+        portion of the output buffer again.  Which is cheaper? */
+
+      /* The above comment is left here for posterity.  It is faster
+        to print one character (non-control) than to print a control
+        sequence telling the terminal to move forward one character.
+        That kind of control is for people who don't know what the
+        data is underneath the cursor. */
+#ifdef HACK_TERMCAP_MOTION
+      extern char *term_forward_char;
+
+      if (term_forward_char)
+       for (i = last_c_pos; i < new; i++)
+         tputs (term_forward_char, 1, output_character_function);
+      else
+       for (i = last_c_pos; i < new; i++)
+         putc (data[i], out_stream);
+#else
+      for (i = last_c_pos; i < new; i++)
+       putc (data[i], out_stream);
+#endif                         /* HACK_TERMCAP_MOTION */
+    }
+  else
+    backspace (last_c_pos - new);
+  last_c_pos = new;
+}
+
+/* PWP: move the cursor up or down. */
+move_vert (to)
+     int to;
+{
+  void output_character_function ();
+  register int delta, i;
+
+  if (last_v_pos == to) return;
+
+  if (to > screenheight)
+    return;
+
+  if ((delta = to - last_v_pos) > 0)
+    {
+      for (i = 0; i < delta; i++)
+       putc ('\n', out_stream);
+      tputs (term_cr, 1, output_character_function);
+      last_c_pos = 0;          /* because crlf() will do \r\n */
+    }
+  else
+    {                  /* delta < 0 */
+      if (term_up && *term_up)
+       for (i = 0; i < -delta; i++)
+         tputs (term_up, 1, output_character_function);
+    }
+  last_v_pos = to;             /* now to is here */
+}
+
+/* Physically print C on out_stream.  This is for functions which know
+   how to optimize the display. */
+rl_show_char (c)
+     int c;
+{
+  if (c > 127)
+    {
+      fprintf (out_stream, "M-");
+      c -= 128;
+    }
+
+#ifdef DISPLAY_TABS
+  if (c < 32 && c != '\t')
+#else
+  if (c < 32)
+#endif
+    {
+
+      c += 64;
+    }
+
+  putc (c, out_stream);
+  fflush (out_stream);
+}
+
+#ifdef DISPLAY_TABS
+int
+rl_character_len (c, pos)
+     register int c, pos;
+{
+  if (c < ' ' || c > 126)
+    {
+      if (c == '\t')
+       return (((pos | (int)7) + 1) - pos);
+      else
+       return (3);
+    }
+  else
+    return (1);
+}
+#else
+int
+rl_character_len (c)
+     int c;
+{
+  if (c < ' ' || c > 126)
+    return (3);
+  else
+    return (1);
+}
+#endif  /* DISPLAY_TAB */
+
+/* How to print things in the "echo-area".  The prompt is treated as a
+   mini-modeline. */
+rl_message (string, arg1, arg2)
+     char *string;
+{
+  sprintf (msg_buf, string, arg1, arg2);
+  rl_display_prompt = msg_buf;
+  rl_redisplay ();
+}
+
+/* How to clear things from the "echo-area". */
+rl_clear_message ()
+{
+  rl_display_prompt = rl_prompt;
+  rl_redisplay ();
+}
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                     Terminal and Termcap                        */
+/*                                                                 */
+/* **************************************************************** */
+
+static char *term_buffer = (char *)NULL;
+static char *term_string_buffer = (char *)NULL;
+
+/* Non-zero means this terminal can't really do anything. */
+int dumb_term = 0;
+
+char PC;
+char *BC, *UP;
+
+/* Some strings to control terminal actions.  These are output by tputs (). */
+char *term_goto, *term_clreol, *term_cr, *term_clrpag, *term_backspace;
+
+int screenwidth, screenheight;
+
+/* Non-zero if we determine that the terminal can do character insertion. */
+int terminal_can_insert = 0;
+
+/* How to insert characters. */
+char *term_im, *term_ei, *term_ic, *term_ip, *term_IC;
+
+/* How to delete characters. */
+char *term_dc, *term_DC;
+
+#ifdef HACK_TERMCAP_MOTION
+char *term_forward_char;
+#endif  /* HACK_TERMCAP_MOTION */
+
+/* How to go up a line. */
+char *term_up;
+
+/* Re-initialize the terminal considering that the TERM/TERMCAP variable
+   has changed. */
+rl_reset_terminal (terminal_name)
+     char *terminal_name;
+{
+  init_terminal_io (terminal_name);
+}
+
+init_terminal_io (terminal_name)
+     char *terminal_name;
+{
+  char *term = (terminal_name? terminal_name : (char *)getenv ("TERM"));
+  char *tgetstr (), *buffer;
+
+
+  if (!term_string_buffer)
+    term_string_buffer = (char *)xmalloc (2048);
+
+  if (!term_buffer)
+    term_buffer = (char *)xmalloc (2048);
+
+  buffer = term_string_buffer;
+
+  term_clrpag = term_cr = term_clreol = (char *)NULL;
+
+  if (!term)
+    term = "dumb";
+
+  if (tgetent (term_buffer, term) < 0)
+    {
+      dumb_term = 1;
+      return;
+    }
+
+  BC = tgetstr ("pc", &buffer);
+  PC = buffer ? *buffer : 0;
+
+  term_backspace = tgetstr ("le", &buffer);
+
+  term_cr = tgetstr ("cr", &buffer);
+  term_clreol = tgetstr ("ce", &buffer);
+  term_clrpag = tgetstr ("cl", &buffer);
+
+  if (!term_cr)
+    term_cr =  "\r";
+
+#ifdef HACK_TERMCAP_MOTION
+  term_forward_char = tgetstr ("nd", &buffer);
+#endif  /* HACK_TERMCAP_MOTION */
+
+  screenwidth = tgetnum ("co");
+  if (screenwidth <= 0)
+    screenwidth = 80;
+  screenwidth--;               /* PWP: avoid autowrap bugs */
+
+  screenheight = tgetnum ("li");
+  if (screenheight <= 0)
+    screenheight = 24;
+
+  term_im = tgetstr ("im", &buffer);
+  term_ei = tgetstr ("ei", &buffer);
+  term_IC = tgetstr ("IC", &buffer);
+  term_ic = tgetstr ("ic", &buffer);
+
+  /* "An application program can assume that the terminal can do
+      character insertion if *any one of* the capabilities `IC',
+      `im', `ic' or `ip' is provided."  But we can't do anything if
+      only `ip' is provided, so... */
+  terminal_can_insert = (term_IC || term_im || term_ic);
+
+  term_up = tgetstr ("up", &buffer);
+  term_dc = tgetstr ("dc", &buffer);
+  term_DC = tgetstr ("DC", &buffer);
+}
+
+/* A function for the use of tputs () */
+static void
+output_character_function (c)
+     int c;
+{
+  putc (c, out_stream);
+}
+
+/* Write COUNT characters from STRING to the output stream. */
+static void
+output_some_chars (string, count)
+     char *string;
+     int count;
+{
+  fwrite (string, 1, count, out_stream);
+}
+
+
+/* Delete COUNT characters from the display line. */
+static
+delete_chars (count)
+     int count;
+{
+  if (count > screenwidth)
+    return;
+
+  if (term_DC && *term_DC)
+    {
+      char *tgoto (), *buffer;
+      buffer = tgoto (term_DC, 0, count);
+      tputs (buffer, 1, output_character_function);
+    }
+  else
+    {
+      if (term_dc && *term_dc)
+       while (count--)
+         tputs (term_dc, 1, output_character_function);
+    }
+}
+
+/* Insert COUNT character from STRING to the output stream. */
+static
+insert_some_chars (string, count)
+     char *string;
+     int count;
+{
+  /* If IC is defined, then we do not have to "enter" insert mode. */
+  if (term_IC)
+    {
+      char *tgoto (), *buffer;
+      buffer = tgoto (term_IC, 0, count);
+      tputs (buffer, 1, output_character_function);
+      output_some_chars (string, count);
+    }
+  else
+    {
+      register int i;
+
+      /* If we have to turn on insert-mode, then do so. */
+      if (term_im && *term_im)
+       tputs (term_im, 1, output_character_function);
+
+      /* If there is a special command for inserting characters, then
+        use that first to open up the space. */
+      if (term_ic && *term_ic)
+       {
+         for (i = count; i--; )
+           tputs (term_ic, 1, output_character_function);
+       }
+
+      /* Print the text. */
+      output_some_chars (string, count);
+
+      /* If there is a string to turn off insert mode, we had best use
+        it now. */
+      if (term_ei && *term_ei)
+       tputs (term_ei, 1, output_character_function);
+    }
+}
+
+/* Move the cursor back. */
+backspace (count)
+     int count;
+{
+  register int i;
+
+  if (term_backspace)
+    for (i = 0; i < count; i++)
+      tputs (term_backspace, 1, output_character_function);
+  else
+    for (i = 0; i < count; i++)
+      putc ('\b', out_stream);
+}
+
+/* Move to the start of the next line. */
+crlf ()
+{
+  tputs (term_cr, 1, output_character_function);
+  putc ('\n', out_stream);
+}
+
+/* Clear to the end of the line.  COUNT is the minimum
+   number of character spaces to clear, */
+clear_to_eol (count)
+     int count;
+{
+  if (term_clreol)
+    {
+      tputs (term_clreol, 1, output_character_function);
+    }
+  else
+    {
+      register int i;
+
+      /* Do one more character space. */
+      count++;
+
+      for (i = 0; i < count; i++)
+       putc (' ', out_stream);
+
+      backspace (count);
+    }
+}
+
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                   Saving and Restoring the TTY                  */
+/*                                                                 */
+/* **************************************************************** */
+
+/* Non-zero means that the terminal is in a prepped state. */
+static int terminal_prepped = 0;
+
+#ifdef NEW_TTY_DRIVER
+
+/* Standard flags, including ECHO. */
+static int original_tty_flags = 0;
+
+/* Local mode flags, like LPASS8. */
+static int local_mode_flags = 0;
+
+/* Terminal characters.  This has C-s and C-q in it. */
+static struct tchars original_tchars;
+
+/* Local special characters.  This has the interrupt characters in it. */
+static struct ltchars original_ltchars;
+
+/* We use this to get and set the tty_flags. */
+static struct sgttyb the_ttybuff;
+
+/* Put the terminal in CBREAK mode so that we can detect key presses. */
+static
+rl_prep_terminal ()
+{
+  int tty = fileno (rl_instream);
+  int oldmask = sigblock (sigmask (SIGINT));
+
+  if (!terminal_prepped)
+    {
+      /* We always get the latest tty values.  Maybe stty changed them. */
+      ioctl (tty, TIOCGETP, &the_ttybuff);
+      original_tty_flags = the_ttybuff.sg_flags;
+
+      readline_echoing_p = (original_tty_flags & ECHO);
+
+       
+#if defined (TIOCLGET)
+      ioctl (tty, TIOCLGET, &local_mode_flags);
+#endif
+
+      /* If this terminal doesn't care how the 8th bit is used,
+        then we can use it for the meta-key.
+        We check by seeing if BOTH odd and even parity are allowed. */
+      if ((the_ttybuff.sg_flags & ODDP) && (the_ttybuff.sg_flags & EVENP))
+       {
+#ifdef PASS8
+         the_ttybuff.sg_flags |= PASS8;
+#endif
+         /* Hack on local mode flags if we can. */
+#if defined (TIOCLGET) && defined (LPASS8)
+         {
+           int flags;
+           flags = local_mode_flags | LPASS8;
+           ioctl (tty, TIOCLSET, &flags);
+         }
+#endif
+       }
+
+#ifdef TIOCGETC
+      {
+       struct tchars temp;
+
+       ioctl (tty, TIOCGETC, &original_tchars);
+       bcopy (&original_tchars, &temp, sizeof (struct tchars));
+
+       /* Get rid of C-s and C-q.
+          We remember the value of startc (C-q) so that if the terminal is in
+          xoff state, the user can xon it by pressing that character. */
+       xon_char = temp.t_startc;
+       temp.t_stopc = -1;
+       temp.t_startc = -1;
+
+       /* If there is an XON character, bind it to restart the output. */
+       if (xon_char != -1)
+         rl_bind_key (xon_char, rl_restart_output);
+
+       /* If there is an EOF char, bind eof_char to it. */
+       if (temp.t_eofc != -1)
+         eof_char = temp.t_eofc;
+
+#ifdef NEVER
+       /* Get rid of C-\ and C-c. */
+       temp.t_intrc = temp.t_quitc = -1;
+#endif
+
+       ioctl (tty, TIOCSETC, &temp);
+      }
+#endif /* TIOCGETC */
+
+#ifdef TIOCGLTC
+      {
+       struct ltchars temp;
+
+       ioctl (tty, TIOCGLTC, &original_ltchars);
+       bcopy (&original_ltchars, &temp, sizeof (struct ltchars));
+
+       /* Make the interrupt keys go away.  Just enough to make people happy. */
+       temp.t_dsuspc = -1;     /* C-y */
+       temp.t_lnextc = -1;     /* C-v */
+
+       ioctl (tty, TIOCSLTC, &temp);
+      }
+#endif /* TIOCGLTC */
+
+      the_ttybuff.sg_flags &= ~ECHO;
+      the_ttybuff.sg_flags |= CBREAK;
+      ioctl (tty, TIOCSETN, &the_ttybuff);
+
+      terminal_prepped = 1;
+    }
+  sigsetmask (oldmask);
+}
+
+/* Restore the terminal to its original state. */
+static
+rl_deprep_terminal ()
+{
+  int tty = fileno (rl_instream);
+  int oldmask = sigblock (sigmask (SIGINT));
+
+  if (terminal_prepped)
+    {
+      the_ttybuff.sg_flags = original_tty_flags;
+      ioctl (tty, TIOCSETN, &the_ttybuff);
+      readline_echoing_p = 1;
+
+#if defined (TIOCLGET)
+      ioctl (tty, TIOCLSET, &local_mode_flags);
+#endif
+
+#ifdef TIOCSLTC
+      ioctl (tty, TIOCSLTC, &original_ltchars);
+#endif
+
+#ifdef TIOCSETC
+      ioctl (tty, TIOCSETC, &original_tchars);
+#endif
+      terminal_prepped = 0;
+    }
+
+  sigsetmask (oldmask);
+}
+
+#else  /* !defined (NEW_TTY_DRIVER) */
+
+#if !defined (VMIN)
+#define VMIN VEOF
+#endif
+
+#if !defined (VTIME)
+#define VTIME VEOL
+#endif
+
+static struct termio otio;
+
+static
+rl_prep_terminal ()
+{
+  int tty = fileno (rl_instream);
+  struct termio tio;
+
+  ioctl (tty, TCGETA, &tio);
+  ioctl (tty, TCGETA, &otio);
+
+  readline_echoing_p = (tio.c_lflag & ECHO);
+
+  tio.c_lflag &= ~(ICANON|ECHO);
+  tio.c_iflag &= ~(IXON|IXOFF|IXANY|ISTRIP|INPCK);
+
+#if !defined (HANDLE_SIGNALS)
+  tio.c_lflag &= ~ISIG;
+#endif
+
+  tio.c_cc[VMIN] = 1;
+  tio.c_cc[VTIME] = 0;
+  ioctl (tty, TCSETAW, &tio);
+  ioctl (tty, TCXONC, 1);      /* Simulate a ^Q. */
+}
+
+static
+rl_deprep_terminal ()
+{
+  int tty = fileno (rl_instream);
+  ioctl (tty, TCSETAW, &otio);
+  ioctl (tty, TCXONC, 1);      /* Simulate a ^Q. */
+}
+#endif  /* NEW_TTY_DRIVER */
+
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                     Utility Functions                           */
+/*                                                                 */
+/* **************************************************************** */
+
+/* Return 0 if C is not a member of the class of characters that belong
+   in words, or 1 if it is. */
+
+int allow_pathname_alphabetic_chars = 0;
+char *pathname_alphabetic_chars = "/-_=~.#$";
+
+int
+alphabetic (c)
+     int c;
+{
+  char *rindex ();
+  if (pure_alphabetic (c) || (numeric (c)))
+    return (1);
+
+  if (allow_pathname_alphabetic_chars)
+    return ((int)rindex (pathname_alphabetic_chars, c));
+  else
+    return (0);
+}
+
+/* Return non-zero if C is a numeric character. */
+int
+numeric (c)
+     int c;
+{
+  return (c >= '0' && c <= '9');
+}
+
+/* Ring the terminal bell. */
+int
+ding ()
+{
+  if (readline_echoing_p)
+    {
+      fprintf (stderr, "\007");
+      fflush (stderr);
+    }
+  return (-1);
+}
+
+/* How to abort things. */
+rl_abort ()
+{
+  ding ();
+  rl_clear_message ();
+  rl_init_argument ();
+  rl_pending_input = 0;
+
+  defining_kbd_macro = 0;
+  while (executing_macro)
+    pop_executing_macro ();
+
+  longjmp (readline_top_level, 1);
+}
+
+/* Return a copy of the string between FROM and TO.
+   FROM is inclusive, TO is not. */
+static char *
+rl_copy (from, to)
+     int from, to;
+{
+  register int length;
+  char *copy;
+
+  /* Fix it if the caller is confused. */
+  if (from > to) {
+    int t = from;
+    from = to;
+    to = t;
+  }
+
+  length = to - from;
+  copy = (char *)xmalloc (1 + length);
+  strncpy (copy, the_line + from, length);
+  copy[length] = '\0';
+  return (copy);
+}
+
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                     Insert and Delete                           */
+/*                                                                 */
+/* **************************************************************** */
+
+
+/* Insert a string of text into the line at point.  This is the only
+   way that you should do insertion.  rl_insert () calls this
+   function. */
+rl_insert_text (string)
+     char *string;
+{
+  extern int doing_an_undo;
+  register int i, l = strlen (string);
+  while (rl_end + l >= rl_line_buffer_len)
+    {
+      rl_line_buffer =
+       (char *)xrealloc (rl_line_buffer,
+                         rl_line_buffer_len += DEFAULT_BUFFER_SIZE);
+      the_line = rl_line_buffer;
+    }
+
+  for (i = rl_end; i >= rl_point; i--)
+    the_line[i + l] = the_line[i];
+  strncpy (the_line + rl_point, string, l);
+
+  /* Remember how to undo this if we aren't undoing something. */
+  if (!doing_an_undo)
+    {
+      /* If possible and desirable, concatenate the undos. */
+      if ((strlen (string) == 1) &&
+         rl_undo_list &&
+         (rl_undo_list->what == UNDO_INSERT) &&
+         (rl_undo_list->end == rl_point) &&
+         (rl_undo_list->end - rl_undo_list->start < 20))
+       rl_undo_list->end++;
+      else
+       rl_add_undo (UNDO_INSERT, rl_point, rl_point + l, (char *)NULL);
+    }
+  rl_point += l;
+  rl_end += l;
+  the_line[rl_end] = '\0';
+}
+
+/* Delete the string between FROM and TO.  FROM is
+   inclusive, TO is not. */
+rl_delete_text (from, to)
+     int from, to;
+{
+  extern int doing_an_undo;
+  register char *text;
+
+  /* Fix it if the caller is confused. */
+  if (from > to) {
+    int t = from;
+    from = to;
+    to = t;
+  }
+  text = rl_copy (from, to);
+  strncpy (the_line + from, the_line + to, rl_end - to);
+
+  /* Remember how to undo this delete. */
+  if (!doing_an_undo)
+    rl_add_undo (UNDO_DELETE, from, to, text);
+  else
+    free (text);
+
+  rl_end -= (to - from);
+  the_line[rl_end] = '\0';
+}
+
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                     Readline character functions                */
+/*                                                                 */
+/* **************************************************************** */
+
+/* This is not a gap editor, just a stupid line input routine.  No hair
+   is involved in writing any of the functions, and none should be. */
+
+/* Note that:
+
+   rl_end is the place in the string that we would place '\0';
+   i.e., it is always safe to place '\0' there.
+
+   rl_point is the place in the string where the cursor is.  Sometimes
+   this is the same as rl_end.
+
+   Any command that is called interactively receives two arguments.
+   The first is a count: the numeric arg pased to this command.
+   The second is the key which invoked this command.
+*/
+
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                     Movement Commands                           */
+/*                                                                 */
+/* **************************************************************** */
+
+/* Note that if you `optimize' the display for these functions, you cannot
+   use said functions in other functions which do not do optimizing display.
+   I.e., you will have to update the data base for rl_redisplay, and you
+   might as well let rl_redisplay do that job. */
+
+/* Move forward COUNT characters. */
+rl_forward (count)
+     int count;
+{
+  if (count < 0)
+    rl_backward (-count);
+  else
+    while (count)
+      {
+#ifdef VI_MODE
+       if (rl_point == (rl_end - (rl_editing_mode == vi_mode)))
+#else
+       if (rl_point == rl_end)
+#endif
+         {
+           ding ();
+           return;
+         }
+       else
+         rl_point++;
+       --count;
+      }
+}
+
+/* Move backward COUNT characters. */
+rl_backward (count)
+     int count;
+{
+  if (count < 0)
+    rl_forward (-count);
+  else
+    while (count)
+      {
+       if (!rl_point)
+         {
+           ding ();
+           return;
+         }
+       else
+         --rl_point;
+       --count;
+      }
+}
+
+/* Move to the beginning of the line. */
+rl_beg_of_line ()
+{
+  rl_point = 0;
+}
+
+/* Move to the end of the line. */
+rl_end_of_line ()
+{
+  rl_point = rl_end;
+}
+
+/* Move forward a word.  We do what Emacs does. */
+rl_forward_word (count)
+     int count;
+{
+  int c;
+
+  if (count < 0)
+    {
+      rl_backward_word (-count);
+      return;
+    }
+
+  while (count)
+    {
+      if (rl_point == rl_end)
+       return;
+
+      /* If we are not in a word, move forward until we are in one.
+        Then, move forward until we hit a non-alphabetic character. */
+      c = the_line[rl_point];
+      if (!alphabetic (c))
+       {
+         while (++rl_point < rl_end)
+           {
+             c = the_line[rl_point];
+             if (alphabetic (c)) break;
+           }
+       }
+      if (rl_point == rl_end) return;
+      while (++rl_point < rl_end)
+       {
+         c = the_line[rl_point];
+         if (!alphabetic (c)) break;
+       }
+      --count;
+    }
+}
+
+/* Move backward a word.  We do what Emacs does. */
+rl_backward_word (count)
+     int count;
+{
+  int c;
+
+  if (count < 0)
+    {
+      rl_forward_word (-count);
+      return;
+    }
+
+  while (count)
+    {
+      if (!rl_point)
+       return;
+
+      /* Like rl_forward_word (), except that we look at the characters
+        just before point. */
+
+      c = the_line[rl_point - 1];
+      if (!alphabetic (c))
+       {
+         while (--rl_point)
+           {
+             c = the_line[rl_point - 1];
+             if (alphabetic (c)) break;
+           }
+       }
+
+      while (rl_point)
+       {
+         c = the_line[rl_point - 1];
+         if (!alphabetic (c))
+           break;
+         else --rl_point;
+       }
+      --count;
+    }
+}
+
+/* Clear the current line.  Numeric argument to C-l does this. */
+rl_refresh_line ()
+{
+  int curr_line = last_c_pos / screenwidth;
+  extern char *term_clreol;
+
+  move_vert(curr_line);
+  move_cursor_relative (0, the_line);   /* XXX is this right */
+
+  if (term_clreol)
+    tputs (term_clreol, 1, output_character_function);
+
+  rl_forced_update_display ();
+  rl_display_fixed = 1;
+}
+
+/* C-l typed to a line without quoting clears the screen, and then reprints
+   the prompt and the current input line.  Given a numeric arg, redraw only
+   the current line. */
+rl_clear_screen ()
+{
+  extern char *term_clrpag;
+
+  if (rl_explicit_arg)
+    {
+      rl_refresh_line ();
+      return;
+    }
+
+  if (term_clrpag)
+    tputs (term_clrpag, 1, output_character_function);
+  else
+    crlf ();
+
+  rl_forced_update_display ();
+  rl_display_fixed = 1;
+}
+
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                     Text commands                               */
+/*                                                                 */
+/* **************************************************************** */
+
+/* Insert the character C at the current location, moving point forward. */
+rl_insert (count, c)
+     int count, c;
+{
+  register int i;
+  char *string;
+
+  if (count <= 0)
+    return;
+
+  /* If we can optimize, then do it.  But don't let people crash
+     readline because of extra large arguments. */
+  if (count > 1 && count < 1024)
+    {
+      string = (char *)alloca (1 + count);
+
+      for (i = 0; i < count; i++)
+       string[i] = c;
+
+      string[i] = '\0';
+      rl_insert_text (string);
+      return;
+    }
+
+  if (count > 1024)
+    {
+      int decreaser;
+
+      string = (char *)alloca (1024 + 1);
+
+      for (i = 0; i < 1024; i++)
+       string[i] = c;
+
+      while (count)
+       {
+         decreaser = (count > 1024 ? 1024 : count);
+         string[decreaser] = '\0';
+         rl_insert_text (string);
+         count -= decreaser;
+       }
+      return;
+    }
+
+  /* We are inserting a single character.
+     If there is pending input, then make a string of all of the
+     pending characters that are bound to rl_insert, and insert
+     them all. */
+  if (any_typein)
+    {
+      int key = 0, t;
+
+      i = 0;
+      string = (char *)alloca (ibuffer_len + 1);
+      string[i++] = c;
+
+      while ((t = rl_get_char (&key)) &&
+            (keymap[key].type == ISFUNC &&
+             keymap[key].function == rl_insert))
+       string[i++] = key;
+
+      if (t)
+       rl_unget_char (key);
+
+      string[i] = '\0';
+      rl_insert_text (string);
+      return;
+    }
+  else
+    {
+      /* Inserting a single character. */
+      string = (char *)alloca (2);
+
+      string[1] = '\0';
+      string[0] = c;
+      rl_insert_text (string);
+    }
+}
+
+/* Insert the next typed character verbatim. */
+rl_quoted_insert (count)
+     int count;
+{
+  int c = rl_read_key ();
+  rl_insert (count, c);
+}
+
+/* Insert a tab character. */
+rl_tab_insert (count)
+     int count;
+{
+  rl_insert (count, '\t');
+}
+
+/* What to do when a NEWLINE is pressed.  We accept the whole line.
+   KEY is the key that invoked this command.  I guess it could have
+   meaning in the future. */
+rl_newline (count, key)
+     int count, key;
+{
+
+  rl_done = 1;
+
+#ifdef VI_MODE
+  {
+    extern int vi_doing_insert;
+    if (vi_doing_insert)
+      {
+       rl_end_undo_group ();
+       vi_doing_insert = 0;
+      }
+  }
+#endif /* VI_MODE */
+
+  if (readline_echoing_p)
+    {
+      move_vert (vis_botlin);
+      vis_botlin = 0;
+      crlf ();
+      fflush (out_stream);
+      rl_display_fixed++;
+    }
+}
+
+rl_clean_up_for_exit ()
+{
+  if (readline_echoing_p)
+    {
+      move_vert (vis_botlin);
+      vis_botlin = 0;
+      fflush (out_stream);
+      rl_restart_output ();
+    }
+}
+
+/* What to do for some uppercase characters, like meta characters,
+   and some characters appearing in emacs_ctlx_keymap.  This function
+   is just a stub, you bind keys to it and the code in rl_dispatch ()
+   is special cased. */
+rl_do_lowercase_version (ignore1, ignore2)
+     int ignore1, ignore2;
+{
+}
+
+/* Rubout the character behind point. */
+rl_rubout (count)
+     int count;
+{
+  if (count < 0)
+    {
+      rl_delete (-count);
+      return;
+    }
+
+  if (!rl_point)
+    {
+      ding ();
+      return;
+    }
+
+  if (count > 1)
+    {
+      int orig_point = rl_point;
+      rl_backward (count);
+      rl_kill_text (orig_point, rl_point);
+    }
+  else
+    {
+      int c = the_line[--rl_point];
+      rl_delete_text (rl_point, rl_point + 1);
+
+      if (rl_point == rl_end && alphabetic (c) && last_c_pos)
+       {
+         backspace (1);
+         putc (' ', out_stream);
+         backspace (1);
+         last_c_pos--;
+         visible_line[last_c_pos] = '\0';
+         rl_display_fixed++;
+       }
+    }
+}
+
+/* Delete the character under the cursor.  Given a numeric argument,
+   kill that many characters instead. */
+rl_delete (count, invoking_key)
+     int count, invoking_key;
+{
+  if (count < 0)
+    {
+      rl_rubout (-count);
+      return;
+    }
+
+  if (rl_point == rl_end)
+    {
+      ding ();
+      return;
+    }
+
+  if (count > 1)
+    {
+      int orig_point = rl_point;
+      rl_forward (count);
+      rl_kill_text (orig_point, rl_point);
+      rl_point = orig_point;
+    }
+  else
+    rl_delete_text (rl_point, rl_point + 1);
+}
+
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                     Kill commands                               */
+/*                                                                 */
+/* **************************************************************** */
+
+/* The next two functions mimic unix line editing behaviour, except they
+   save the deleted text on the kill ring.  This is safer than not saving
+   it, and since we have a ring, nobody should get screwed. */
+
+/* This does what C-w does in Unix.  We can't prevent people from
+   using behaviour that they expect. */
+rl_unix_word_rubout ()
+{
+  if (!rl_point) ding ();
+  else {
+    int orig_point = rl_point;
+    while (rl_point && whitespace (the_line[rl_point - 1]))
+      rl_point--;
+    while (rl_point && !whitespace (the_line[rl_point - 1]))
+      rl_point--;
+    rl_kill_text (rl_point, orig_point);
+  }
+}
+
+/* Here is C-u doing what Unix does.  You don't *have* to use these
+   key-bindings.  We have a choice of killing the entire line, or
+   killing from where we are to the start of the line.  We choose the
+   latter, because if you are a Unix weenie, then you haven't backspaced
+   into the line at all, and if you aren't, then you know what you are
+   doing. */
+rl_unix_line_discard ()
+{
+  if (!rl_point) ding ();
+  else {
+    rl_kill_text (rl_point, 0);
+    rl_point = 0;
+  }
+}
+
+\f
+
+/* **************************************************************** */
+/*                                                                 */
+/*                     Commands For Typos                          */
+/*                                                                 */
+/* **************************************************************** */
+
+/* Random and interesting things in here.  */
+
+
+/* **************************************************************** */
+/*                                                                 */
+/*                     Changing Case                               */
+/*                                                                 */
+/* **************************************************************** */
+
+/* The three kinds of things that we know how to do. */
+#define UpCase 1
+#define DownCase 2
+#define CapCase 3
+
+/* Uppercase the word at point. */
+rl_upcase_word (count)
+     int count;
+{
+  rl_change_case (count, UpCase);
+}
+
+/* Lowercase the word at point. */
+rl_downcase_word (count)
+     int count;
+{
+  rl_change_case (count, DownCase);
+}
+
+/* Upcase the first letter, downcase the rest. */
+rl_capitalize_word (count)
+     int count;
+{
+  rl_change_case (count, CapCase);
+}
+
+/* The meaty function.
+   Change the case of COUNT words, performing OP on them.
+   OP is one of UpCase, DownCase, or CapCase.
+   If a negative argument is given, leave point where it started,
+   otherwise, leave it where it moves to. */
+rl_change_case (count, op)
+     int count, op;
+{
+  register int start = rl_point, end;
+  int state = 0;
+
+  rl_forward_word (count);
+  end = rl_point;
+
+  if (count < 0)
+    {
+      int temp = start;
+      start = end;
+      end = temp;
+    }
+
+  /* We are going to modify some text, so let's prepare to undo it. */
+  rl_modifying (start, end);
+
+  for (; start < end; start++)
+    {
+      switch (op)
+       {
+       case UpCase:
+         the_line[start] = to_upper (the_line[start]);
+         break;
+
+       case DownCase:
+         the_line[start] = to_lower (the_line[start]);
+         break;
+
+       case CapCase:
+         if (state == 0)
+           {
+             the_line[start] = to_upper (the_line[start]);
+             state = 1;
+           }
+         else
+           {
+             the_line[start] = to_lower (the_line[start]);
+           }
+         if (!pure_alphabetic (the_line[start]))
+           state = 0;
+         break;
+
+       default:
+         abort ();
+       }
+    }
+  rl_point = end;
+}
+
+/* **************************************************************** */
+/*                                                                 */
+/*                     Transposition                               */
+/*                                                                 */
+/* **************************************************************** */
+
+/* Transpose the words at point. */
+rl_transpose_words (count)
+     int count;
+{
+  char *word1, *word2;
+  int w1_beg, w1_end, w2_beg, w2_end;
+  int orig_point = rl_point;
+
+  if (!count) return;
+
+  /* Find the two words. */
+  rl_forward_word (count);
+  w2_end = rl_point;
+  rl_backward_word (1);
+  w2_beg = rl_point;
+  rl_backward_word (count);
+  w1_beg = rl_point;
+  rl_forward_word (1);
+  w1_end = rl_point;
+
+  /* Do some check to make sure that there really are two words. */
+  if ((w1_beg == w2_beg) || (w2_beg < w1_end))
+    {
+      ding ();
+      rl_point = orig_point;
+      return;
+    }
+
+  /* Get the text of the words. */
+  word1 = rl_copy (w1_beg, w1_end);
+  word2 = rl_copy (w2_beg, w2_end);
+
+  /* We are about to do many insertions and deletions.  Remember them
+     as one operation. */
+  rl_begin_undo_group ();
+
+  /* Do the stuff at word2 first, so that we don't have to worry
+     about word1 moving. */
+  rl_point = w2_beg;
+  rl_delete_text (w2_beg, w2_end);
+  rl_insert_text (word1);
+
+  rl_point = w1_beg;
+  rl_delete_text (w1_beg, w1_end);
+  rl_insert_text (word2);
+
+  /* This is exactly correct since the text before this point has not
+     changed in length. */
+  rl_point = w2_end;
+
+  /* I think that does it. */
+  rl_end_undo_group ();
+  free (word1); free (word2);
+}
+
+/* Transpose the characters at point.  If point is at the end of the line,
+   then transpose the characters before point. */
+rl_transpose_chars (count)
+     int count;
+{
+  if (!count)
+    return;
+
+  if (!rl_point || rl_end < 2) {
+    ding ();
+    return;
+  }
+
+  while (count) {
+    if (rl_point == rl_end) {
+      int t = the_line[rl_point - 1];
+      the_line[rl_point - 1] = the_line[rl_point - 2];
+      the_line[rl_point - 2] = t;
+    } else {
+      int t = the_line[rl_point];
+      the_line[rl_point] = the_line[rl_point - 1];
+      the_line[rl_point - 1] = t;
+      if (count < 0 && rl_point)
+       rl_point--;
+      else
+       rl_point++;
+    }
+    if (count < 0)
+      count++;
+    else
+      count--;
+  }
+}
+
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                     Bogus Flow Control                          */
+/*                                                                 */
+/* **************************************************************** */
+
+rl_restart_output (count, key)
+     int count, key;
+{
+  int fildes = fileno (stdin);
+#ifdef TIOCSTART
+  ioctl (fildes, TIOCSTART, 0);
+#endif /* TIOCSTART */
+}
+
+/* **************************************************************** */
+/*                                                                 */
+/*     Completion matching, from readline's point of view.         */
+/*                                                                 */
+/* **************************************************************** */
+
+/* Pointer to the generator function for completion_matches ().
+   NULL means to use filename_entry_function (), the default filename
+   completer. */
+Function *rl_completion_entry_function = (Function *)NULL;
+
+/* Pointer to alternative function to create matches.
+   Function is called with TEXT, START, and END.
+   START and END are indices in RL_LINE_BUFFER saying what the boundaries
+   of TEXT are.
+   If this function exists and returns NULL then call the value of
+   rl_completion_entry_function to try to match, otherwise use the
+   array of strings returned. */
+Function *rl_attempted_completion_function = (Function *)NULL;
+
+/* Complete the word at or before point.  You have supplied the function
+   that does the initial simple matching selection algorithm (see
+   completion_matches ()).  The default is to do filename completion. */
+rl_complete (ignore, invoking_key)
+     int ignore, invoking_key;
+{
+  rl_complete_internal (TAB);
+}
+
+/* List the possible completions.  See description of rl_complete (). */
+rl_possible_completions ()
+{
+  rl_complete_internal ('?');
+}
+
+/* The user must press "y" or "n". Non-zero return means "y" pressed. */
+get_y_or_n ()
+{
+  int c;
+ loop:
+  c = rl_read_key ();
+  if (c == 'y' || c == 'Y') return (1);
+  if (c == 'n' || c == 'N') return (0);
+  if (c == ABORT_CHAR) rl_abort ();
+  ding (); goto loop;
+}
+
+/* Up to this many items will be displayed in response to a
+   possible-completions call.  After that, we ask the user if
+   she is sure she wants to see them all. */
+int rl_completion_query_items = 100;
+
+/* The basic list of characters that signal a break between words for the
+   completer routine.  The contents of this variable is what breaks words
+   in the shell, i.e. " \t\n\"\\'`@$><=" */
+char *rl_basic_word_break_characters = " \t\n\"\\'`@$><=";
+
+/* The list of characters that signal a break between words for
+   rl_complete_internal.  The default list is the contents of
+   rl_basic_word_break_characters.  */
+char *rl_completer_word_break_characters = (char *)NULL;
+
+/* List of characters that are word break characters, but should be left
+   in TEXT when it is passed to the completion function.  The shell uses
+   this to help determine what kind of completing to do. */
+char *rl_special_prefixes = (char *)NULL;
+
+/* If non-zero, then disallow duplicates in the matches. */
+int rl_ignore_completion_duplicates = 1;
+
+/* Non-zero means that the results of the matches are to be treated
+   as filenames.  This is ALWAYS zero on entry, and can only be changed
+   within a completion entry finder function. */
+int rl_filename_completion_desired = 0;
+
+/* Complete the word at or before point.
+   WHAT_TO_DO says what to do with the completion.
+   `?' means list the possible completions.
+   TAB means do standard completion.
+   `*' means insert all of the possible completions. */
+rl_complete_internal (what_to_do)
+     int what_to_do;
+{
+  char *filename_completion_function ();
+  char **completion_matches (), **matches;
+  Function *our_func;
+  int start, end, delimiter = 0;
+  char *text;
+
+  if (rl_completion_entry_function)
+    our_func = rl_completion_entry_function;
+  else
+    our_func = (int (*)())filename_completion_function;
+
+  /* Only the completion entry function can change this. */
+  rl_filename_completion_desired = 0;
+
+  /* We now look backwards for the start of a filename/variable word. */
+  end = rl_point;
+  if (rl_point)
+    {
+      while (--rl_point &&
+            !rindex (rl_completer_word_break_characters, the_line[rl_point]));
+
+      /* If we are at a word break, then advance past it. */
+      if (rindex (rl_completer_word_break_characters,  (the_line[rl_point])))
+       {
+         /* If the character that caused the word break was a quoting
+            character, then remember it as the delimiter. */
+         if (rindex ("\"'", the_line[rl_point]) && (end - rl_point) > 1)
+           delimiter = the_line[rl_point];
+
+         /* If the character isn't needed to determine something special
+            about what kind of completion to perform, then advance past it. */
+
+         if (!rl_special_prefixes ||
+             !rindex (rl_special_prefixes, the_line[rl_point]))
+           rl_point++;
+       }
+    }
+
+  start = rl_point;
+  rl_point = end;
+  text = rl_copy (start, end);
+
+  /* If the user wants to TRY to complete, but then wants to give
+     up and use the default completion function, they set the
+     variable rl_attempted_completion_function. */
+  if (rl_attempted_completion_function)
+    {
+      matches =
+       (char **)(*rl_attempted_completion_function) (text, start, end);
+
+      if (matches)
+       goto after_usual_completion;
+    }
+
+  matches = completion_matches (text, our_func, start, end);
+
+ after_usual_completion:
+  free (text);
+
+  if (!matches)
+    ding ();
+  else
+    {
+      register int i;
+
+    some_matches:
+
+      /* It seems to me that in all the cases we handle we would like
+        to ignore duplicate possiblilities.  Scan for the text to
+        insert being identical to the other completions. */
+      if (rl_ignore_completion_duplicates)
+       {
+         char *lowest_common;
+         int j, newlen = 0;
+
+         /* Sort the items. */
+         /* It is safe to sort this array, because the lowest common
+            denominator found in matches[0] will remain in place. */
+         for (i = 0; matches[i]; i++);
+         qsort (matches, i, sizeof (char *), compare_strings);
+
+         /* Remember the lowest common denimator for it may be unique. */
+         lowest_common = savestring (matches[0]);
+
+         for (i = 0; matches[i + 1]; i++)
+           {
+             if (strcmp (matches[i], matches[i + 1]) == 0)
+               {
+                 free (matches[i]);
+                 matches[i] = (char *)-1;
+               }
+             else
+               newlen++;
+           }
+
+         /* We have marked all the dead slots with (char *)-1.
+            Copy all the non-dead entries into a new array. */
+         {
+           char **temp_array =
+             (char **)malloc ((3 + newlen) * sizeof (char *));
+
+           for (i = 1, j = 1; matches[i]; i++)
+             if (matches[i] != (char *)-1)
+               temp_array[j++] = matches[i];
+           temp_array[j] = (char *)NULL;
+
+           if (matches[0] != (char *)-1)
+             free (matches[0]);
+           free (matches);
+
+           matches = temp_array;
+         }
+
+         /* Place the lowest common denominator back in [0]. */
+         matches[0] = lowest_common;
+
+         /* If there is one string left, and it is identical to the
+            lowest common denominator, then the LCD is the string to
+            insert. */
+         if (j == 2 && strcmp (matches[0], matches[1]) == 0)
+           {
+             free (matches[1]);
+             matches[1] = (char *)NULL;
+           }
+       }
+
+      switch (what_to_do)
+       {
+       case TAB:
+         if (matches[0])
+           {
+             rl_delete_text (start, rl_point);
+             rl_point = start;
+             rl_insert_text (matches[0]);
+           }
+
+         /* If there are more matches, ring the bell to indicate.
+            If this was the only match, and we are hacking files,
+            check the file to see if it was a directory.  If so,
+            add a '/' to the name.  If not, and we are at the end
+            of the line, then add a space. */
+         if (matches[1])
+           {
+             ding ();          /* There are other matches remaining. */
+           }
+         else
+           {
+             char temp_string[2];
+
+             temp_string[0] = delimiter ? delimiter : ' ';
+             temp_string[1] = '\0';
+
+             if (rl_filename_completion_desired)
+               {
+                 struct stat finfo;
+                 char *tilde_expand ();
+                 char *filename = tilde_expand (matches[0]);
+
+                 if ((stat (filename, &finfo) == 0) &&
+                     ((finfo.st_mode & S_IFMT) == S_IFDIR))
+                   {
+                     if (the_line[rl_point] != '/')
+                       rl_insert_text ("/");
+                   }
+                 else
+                   {
+                     if (rl_point == rl_end)
+                       rl_insert_text (temp_string);
+                   }
+                 free (filename);
+               }
+             else
+               {
+                 if (rl_point == rl_end)
+                   rl_insert_text (temp_string);
+               }
+           }
+         break;
+
+       case '*':
+         {
+           int i = 1;
+
+           rl_delete_text (start, rl_point);
+           rl_point = start;
+           rl_begin_undo_group ();
+           if (matches[1])
+             {
+               while (matches[i])
+                 {
+                   rl_insert_text (matches[i++]);
+                   rl_insert_text (" ");
+                 }
+             }
+           else
+             {
+               rl_insert_text (matches[0]);
+               rl_insert_text (" ");
+             }
+           rl_end_undo_group ();
+         }
+         break;
+
+
+       case '?':
+         {
+           int len, count, limit, max = 0;
+           int j, k, l;
+
+           /* Handle simple case first.  What if there is only one answer? */
+           if (!matches[1])
+             {
+               char *rindex (), *temp;
+
+               if (rl_filename_completion_desired)
+                 temp = rindex (matches[0], '/');
+               else
+                 temp = (char *)NULL;
+
+               if (!temp)
+                 temp = matches[0];
+               else
+                 temp++;
+
+               crlf ();
+               fprintf (out_stream, "%s", temp);
+               crlf ();
+               goto restart;
+             }
+
+           /* There is more than one answer.  Find out how many there are,
+              and find out what the maximum printed length of a single entry
+              is. */
+           for (i = 1; matches[i]; i++)
+             {
+               char *rindex (), *temp = (char *)NULL;
+
+               /* If we are hacking filenames, then only count the characters
+                  after the last slash in the pathname. */
+               if (rl_filename_completion_desired)
+                 temp = rindex (matches[i], '/');
+               else
+                 temp = (char *)NULL;
+
+               if (!temp)
+                 temp = matches[i];
+               else
+                 temp++;
+
+               if (strlen (temp) > max)
+                 max = strlen (temp);
+             }
+
+           len = i;
+
+           /* If there are many items, then ask the user if she
+              really wants to see them all. */
+           if (len >= rl_completion_query_items)
+             {
+               crlf ();
+               fprintf (out_stream,
+                        "There are %d possibilities.  Do you really", len);
+               crlf ();
+               fprintf (out_stream, "wish to see them all? (y or n)");
+               fflush (out_stream);
+               if (!get_y_or_n ())
+                 {
+                   crlf ();
+                   goto restart;
+                 }
+             }
+           /* How many items of MAX length can we fit in the screen window? */
+           max += 2;
+           limit = screenwidth / max;
+           if (limit != 1 && (limit * max == screenwidth))
+             limit--;
+
+           /* How many iterations of the printing loop? */
+           count = (len + (limit - 1)) / limit;
+
+           /* Watch out for special case.  If LEN is less than LIMIT, then
+              just do the inner printing loop. */
+           if (len < limit) count = 1;
+
+           /* Sort the items if they are not already sorted. */
+           if (!rl_ignore_completion_duplicates)
+             qsort (matches, len, sizeof (char *), compare_strings);
+
+           /* Print the sorted items, up-and-down alphabetically, like
+              ls might. */
+           crlf ();
+
+           for (i = 1; i < count + 1; i++)
+             {
+               for (j = 0, l = i; j < limit; j++)
+                 {
+                   if (l > len || !matches[l])
+                     {
+                       break;
+                     }
+                   else
+                     {
+                       char *rindex (), *temp = (char *)NULL;
+
+                       if (rl_filename_completion_desired)
+                         temp = rindex (matches[l], '/');
+                       else
+                         temp = (char *)NULL;
+
+                       if (!temp)
+                         temp = matches[l];
+                       else
+                         temp++;
+
+                       fprintf (out_stream, "%s", temp);
+                       for (k = 0; k < max - strlen (temp); k++)
+                         putc (' ', out_stream);
+                     }
+                   l += count;
+                 }
+               crlf ();
+             }
+         restart:
+
+           rl_on_new_line ();
+         }
+         break;
+
+       default:
+         abort ();
+       }
+
+      for (i = 0; matches[i]; i++)
+       free (matches[i]);
+      free (matches);
+    }
+}
+
+/* Stupid comparison routine for qsort () ing strings. */
+static int
+compare_strings (s1, s2)
+  char **s1, **s2;
+{
+  return (strcmp (*s1, *s2));
+}
+
+/* A completion function for usernames.
+   TEXT contains a partial username preceded by a random
+   character (usually `~').  */
+char *
+username_completion_function (text, state)
+     int state;
+     char *text;
+{
+  static char *username = (char *)NULL;
+  static struct passwd *entry;
+  static int namelen;
+
+  if (!state)
+    {
+      if (username)
+       free (username);
+      username = savestring (&text[1]);
+      namelen = strlen (username);
+      setpwent ();
+    }
+
+  while (entry = getpwent ())
+    {
+      if (strncmp (username, entry->pw_name, namelen) == 0)
+       break;
+    }
+
+  if (!entry)
+    {
+      endpwent ();
+      return ((char *)NULL);
+    }
+  else
+    {
+      char *value = (char *)xmalloc (2 + strlen (entry->pw_name));
+      *value = *text;
+      strcpy (value + 1, entry->pw_name);
+      rl_filename_completion_desired = 1;
+      return (value);
+    }
+}
+
+/* If non-null, this contains the address of a function to call if the
+   standard meaning for expanding a tilde fails.  The function is called
+   with the text (sans tilde, as in "foo"), and returns a malloc()'ed string
+   which is the expansion, or a NULL pointer if there is no expansion. */
+Function *rl_tilde_expander = (Function *)NULL;
+
+/* Expand FILENAME if it begins with a tilde.  This always returns
+   a new string. */
+char *
+tilde_expand (filename)
+     char *filename;
+{
+  char *dirname = filename ? savestring (filename) : (char *)NULL;
+
+  if (dirname && *dirname == '~')
+    {
+      char *temp_name;
+      if (!dirname[1] || dirname[1] == '/')
+       {
+         /* Prepend $HOME to the rest of the string. */
+         char *temp_home = (char *)getenv ("HOME");
+
+         temp_name = (char *)alloca (1 + strlen (&dirname[1])
+                                     + (temp_home? strlen (temp_home) : 0));
+         temp_name[0] = '\0';
+         if (temp_home)
+           strcpy (temp_name, temp_home);
+         strcat (temp_name, &dirname[1]);
+         free (dirname);
+         dirname = savestring (temp_name);
+       }
+      else
+       {
+         struct passwd *getpwnam (), *user_entry;
+         char *username = (char *)alloca (257);
+         int i, c;
+
+         for (i = 1; c = dirname[i]; i++)
+           {
+             if (c == '/') break;
+             else username[i - 1] = c;
+           }
+         username[i - 1] = '\0';
+
+         if (!(user_entry = getpwnam (username)))
+           {
+             /* If the calling program has a special syntax for
+                expanding tildes, and we couldn't find a standard
+                expansion, then let them try. */
+             if (rl_tilde_expander)
+               {
+                 char *expansion;
+
+                 expansion = (char *)(*rl_tilde_expander) (username);
+
+                 if (expansion)
+                   {
+                     temp_name = (char *)alloca (1 + strlen (expansion)
+                                                 + strlen (&dirname[i]));
+                     strcpy (temp_name, expansion);
+                     strcat (temp_name, &dirname[i]);
+                     free (expansion);
+                     goto return_name;
+                   }
+               }
+             /*
+              * We shouldn't report errors.
+              */
+           }
+         else
+           {
+             temp_name = (char *)alloca (1 + strlen (user_entry->pw_dir)
+                                         + strlen (&dirname[i]));
+             strcpy (temp_name, user_entry->pw_dir);
+             strcat (temp_name, &dirname[i]);
+           return_name:
+             free (dirname);
+             dirname = savestring (temp_name);
+           }
+       }
+    }
+  return (dirname);
+}
+
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                     Undo, and Undoing                           */
+/*                                                                 */
+/* **************************************************************** */
+
+/* Non-zero tells rl_delete_text and rl_insert_text to not add to
+   the undo list. */
+int doing_an_undo = 0;
+
+/* The current undo list for THE_LINE. */
+UNDO_LIST *rl_undo_list = (UNDO_LIST *)NULL;
+
+/* Remember how to undo something.  Concatenate some undos if that
+   seems right. */
+rl_add_undo (what, start, end, text)
+     enum undo_code what;
+     int start, end;
+     char *text;
+{
+  UNDO_LIST *temp = (UNDO_LIST *)xmalloc (sizeof (UNDO_LIST));
+  temp->what = what;
+  temp->start = start;
+  temp->end = end;
+  temp->text = text;
+  temp->next = rl_undo_list;
+  rl_undo_list = temp;
+}
+
+/* Free the existing undo list. */
+free_undo_list ()
+{
+  while (rl_undo_list) {
+    UNDO_LIST *release = rl_undo_list;
+    rl_undo_list = rl_undo_list->next;
+
+    if (release->what == UNDO_DELETE)
+      free (release->text);
+
+    free (release);
+  }
+}
+
+/* Undo the next thing in the list.  Return 0 if there
+   is nothing to undo, or non-zero if there was. */
+int
+rl_do_undo ()
+{
+  UNDO_LIST *release;
+  int waiting_for_begin = 0;
+
+undo_thing:
+  if (!rl_undo_list)
+    return (0);
+
+  doing_an_undo = 1;
+
+  switch (rl_undo_list->what) {
+
+    /* Undoing deletes means inserting some text. */
+  case UNDO_DELETE:
+    rl_point = rl_undo_list->start;
+    rl_insert_text (rl_undo_list->text);
+    free (rl_undo_list->text);
+    break;
+
+    /* Undoing inserts means deleting some text. */
+  case UNDO_INSERT:
+    rl_delete_text (rl_undo_list->start, rl_undo_list->end);
+    rl_point = rl_undo_list->start;
+    break;
+
+    /* Undoing an END means undoing everything 'til we get to
+       a BEGIN. */
+  case UNDO_END:
+    waiting_for_begin++;
+    break;
+
+    /* Undoing a BEGIN means that we are done with this group. */
+  case UNDO_BEGIN:
+    if (waiting_for_begin)
+      waiting_for_begin--;
+    else
+      abort ();
+    break;
+  }
+
+  doing_an_undo = 0;
+
+  release = rl_undo_list;
+  rl_undo_list = rl_undo_list->next;
+  free (release);
+
+  if (waiting_for_begin)
+    goto undo_thing;
+
+  return (1);
+}
+
+/* Begin a group.  Subsequent undos are undone as an atomic operation. */
+rl_begin_undo_group ()
+{
+  rl_add_undo (UNDO_BEGIN, 0, 0, 0);
+}
+
+/* End an undo group started with rl_begin_undo_group (). */
+rl_end_undo_group ()
+{
+  rl_add_undo (UNDO_END, 0, 0, 0);
+}
+
+/* Save an undo entry for the text from START to END. */
+rl_modifying (start, end)
+     int start, end;
+{
+  if (start > end)
+    {
+      int t = start;
+      start = end;
+      end = t;
+    }
+
+  if (start != end)
+    {
+      char *temp = rl_copy (start, end);
+      rl_begin_undo_group ();
+      rl_add_undo (UNDO_DELETE, start, end, temp);
+      rl_add_undo (UNDO_INSERT, start, end, (char *)NULL);
+      rl_end_undo_group ();
+    }
+}
+
+/* Revert the current line to its previous state. */
+rl_revert_line ()
+{
+  if (!rl_undo_list) ding ();
+  else {
+    while (rl_undo_list)
+      rl_do_undo ();
+  }
+}
+
+/* Do some undoing of things that were done. */
+rl_undo_command (count)
+{
+  if (count < 0) return;       /* Nothing to do. */
+
+  while (count)
+    {
+      if (rl_do_undo ())
+       {
+         count--;
+       }
+      else
+       {
+         ding ();
+         break;
+       }
+    }
+}
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                     History Utilities                           */
+/*                                                                 */
+/* **************************************************************** */
+
+/* We already have a history library, and that is what we use to control
+   the history features of readline.  However, this is our local interface
+   to the history mechanism. */
+
+/* While we are editing the history, this is the saved
+   version of the original line. */
+HIST_ENTRY *saved_line_for_history = (HIST_ENTRY *)NULL;
+
+/* Set the history pointer back to the last entry in the history. */
+start_using_history ()
+{
+  using_history ();
+  if (saved_line_for_history)
+    free_history_entry (saved_line_for_history);
+
+  saved_line_for_history = (HIST_ENTRY *)NULL;
+}
+
+/* Free the contents (and containing structure) of a HIST_ENTRY. */
+free_history_entry (entry)
+     HIST_ENTRY *entry;
+{
+  if (!entry) return;
+  if (entry->line)
+    free (entry->line);
+  free (entry);
+}
+
+/* Perhaps put back the current line if it has changed. */
+maybe_replace_line ()
+{
+  HIST_ENTRY *temp = current_history ();
+
+  /* If the current line has changed, save the changes. */
+  if (temp && ((UNDO_LIST *)(temp->data) != rl_undo_list)) {
+    temp = replace_history_entry (where_history (), the_line, rl_undo_list);
+    free (temp->line);
+    free (temp);
+  }
+}
+
+/* Put back the saved_line_for_history if there is one. */
+maybe_unsave_line ()
+{
+  if (saved_line_for_history) {
+    strcpy (the_line, saved_line_for_history->line);
+    rl_undo_list = (UNDO_LIST *)saved_line_for_history->data;
+    free_history_entry (saved_line_for_history);
+    saved_line_for_history = (HIST_ENTRY *)NULL;
+    rl_end = rl_point = strlen (the_line);
+  } else {
+    ding ();
+  }
+}
+
+/* Save the current line in saved_line_for_history. */
+maybe_save_line ()
+{
+  if (!saved_line_for_history) {
+    saved_line_for_history = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
+    saved_line_for_history->line = savestring (the_line);
+    saved_line_for_history->data = (char *)rl_undo_list;
+  }
+}
+
+
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                     History Commands                            */
+/*                                                                 */
+/* **************************************************************** */
+
+/* Meta-< goes to the start of the history. */
+rl_beginning_of_history ()
+{
+  rl_get_previous_history (1 + where_history ());
+}
+
+/* Meta-> goes to the end of the history.  (The current line). */
+rl_end_of_history ()
+{
+  maybe_replace_line ();
+  using_history ();
+  maybe_unsave_line ();
+}
+
+/* Move down to the next history line. */
+rl_get_next_history (count)
+     int count;
+{
+  HIST_ENTRY *temp = (HIST_ENTRY *)NULL;
+
+  if (count < 0)
+    {
+      rl_get_previous_history (-count);
+      return;
+    }
+
+  if (!count)
+    return;
+
+  maybe_replace_line ();
+
+  while (count)
+    {
+      temp = next_history ();
+      if (!temp)
+       break;
+      --count;
+    }
+
+  if (!temp)
+    maybe_unsave_line ();
+  else
+    {
+      strcpy (the_line, temp->line);
+      rl_undo_list = (UNDO_LIST *)temp->data;
+      rl_end = rl_point = strlen (the_line);
+    }
+}
+
+/* Get the previous item out of our interactive history, making it the current
+   line.  If there is no previous history, just ding. */
+rl_get_previous_history (count)
+     int count;
+{
+  HIST_ENTRY *old_temp = (HIST_ENTRY *)NULL;
+  HIST_ENTRY *temp = (HIST_ENTRY *)NULL;
+
+  if (count < 0)
+    {
+      rl_get_next_history (-count);
+      return;
+    }
+
+  if (!count)
+    return;
+
+  /* If we don't have a line saved, then save this one. */
+  maybe_save_line ();
+
+  /* If the current line has changed, save the changes. */
+  maybe_replace_line ();
+
+  while (count)
+    {
+      temp = previous_history ();
+      if (!temp)
+       break;
+      else
+       old_temp = temp;
+      --count;
+    }
+
+  /* If there was a large argument, and we moved back to the start of the
+     history, that is not an error.  So use the last value found. */
+  if (!temp && old_temp)
+    temp = old_temp;
+
+  if (!temp)
+    ding ();
+  else
+    {
+      strcpy (the_line, temp->line);
+      rl_undo_list = (UNDO_LIST *)temp->data;
+      rl_end = rl_point = strlen (the_line);
+#ifdef VI_MODE
+      if (rl_editing_mode == vi_mode)
+       rl_point = 0;
+#endif /* VI_MODE */
+    }
+}
+
+/* There is a command in ksh which yanks into this line, the last word
+   of the previous line.  Here it is.  We left it on M-. */
+rl_yank_previous_last_arg (ignore)
+     int ignore;
+{
+}
+
+
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                     I-Search and Searching                      */
+/*                                                                 */
+/* **************************************************************** */
+
+/* Search backwards through the history looking for a string which is typed
+   interactively.  Start with the current line. */
+rl_reverse_search_history (sign, key)
+     int sign;
+     int key;
+{
+  rl_search_history (-sign, key);
+}
+
+/* Search forwards through the history looking for a string which is typed
+   interactively.  Start with the current line. */
+rl_forward_search_history (sign, key)
+     int sign;
+     int key;
+{
+  rl_search_history (sign, key);
+}
+
+/* Display the current state of the search in the echo-area.
+   SEARCH_STRING contains the string that is being searched for,
+   DIRECTION is zero for forward, or 1 for reverse,
+   WHERE is the history list number of the current line.  If it is
+   -1, then this line is the starting one. */
+rl_display_search (search_string, reverse_p, where)
+     char *search_string;
+     int reverse_p, where;
+{
+  char *message = (char *)NULL;
+
+  message =
+    (char *)alloca (1 + (search_string ? strlen (search_string) : 0) + 30);
+
+  *message = '\0';
+
+#ifdef NEVER
+  if (where != -1)
+    sprintf (message, "[%d]", where + history_base);
+#endif
+
+  strcat (message, "(");
+
+  if (reverse_p)
+    strcat (message, "reverse-");
+
+  strcat (message, "i-search)`");
+
+  if (search_string)
+    strcat (message, search_string);
+
+  strcat (message, "': ");
+  rl_message (message, 0, 0);
+  rl_redisplay ();
+}
+
+/* Search through the history looking for an interactively typed string.
+   This is analogous to i-search.  We start the search in the current line.
+   DIRECTION is which direction to search; > 0 means forward, < 0 means
+   backwards. */
+rl_search_history (direction, invoking_key)
+     int direction;
+     int invoking_key;
+{
+  /* The string that the user types in to search for. */
+  char *search_string = (char *)alloca (128);
+
+  /* The current length of SEARCH_STRING. */
+  int search_string_index;
+
+  /* The list of lines to search through. */
+  char **lines;
+
+  /* The length of LINES. */
+  int hlen;
+
+  /* Where we get LINES from. */
+  HIST_ENTRY **hlist = history_list ();
+
+  int orig_point = rl_point;
+  int orig_line = where_history ();
+  int last_found_line = orig_line;
+  int c, done = 0;
+  register int i = 0;
+
+
+  /* The line currently being searched. */
+  char *sline;
+
+  /* Offset in that line. */
+  int index;
+
+  /* Non-zero if we are doing a reverse search. */
+  int reverse = (direction < 0);
+
+  /* Create an arrary of pointers to the lines that we want to search. */
+
+  maybe_replace_line ();
+  if (hlist)
+    for (i = 0; hlist[i]; i++);
+
+  /* Allocate space for this many lines, +1 for the current input line,
+     and remember those lines. */
+  lines = (char **)alloca ((1 + (hlen = i)) * sizeof (char *));
+  for (i = 0; i < hlen; i++)
+    lines[i] = hlist[i]->line;
+
+  if (saved_line_for_history)
+    lines[i] = saved_line_for_history->line;
+  else
+    {
+      /* So I have to type it in this way instead. */
+      lines[i] = (char *)alloca (1 + strlen (the_line));
+      strcpy (lines[i], &the_line[0]);
+    }
+
+  hlen++;
+
+  /* The line where we start the search. */
+  i = orig_line;
+
+  /* Initialize search parameters. */
+  *search_string = '\0';
+  search_string_index = 0;
+
+  rl_display_search (search_string, reverse, -1);
+
+  sline = the_line;
+  index = rl_point;
+
+  while (!done)
+    {
+      c = rl_read_key ();
+
+      /* Hack C to Do What I Mean. */
+      {
+       Function *f = (Function *)NULL;
+
+       if (keymap[c].type == ISFUNC)
+         f = keymap[c].function;
+
+       if (f == rl_reverse_search_history)
+         c = reverse ? -1 : -2;
+       else if (f == rl_forward_search_history)
+         c =  !reverse ? -1 : -2;
+      }
+
+      switch (c)
+       {
+       case ESC:
+         done = 1;
+         continue;
+
+         /* case invoking_key: */
+       case -1:
+         goto search_again;
+
+         /* switch directions */
+       case -2:
+         direction = -direction;
+         reverse = (direction < 0);
+
+         goto do_search;
+
+       case CTRL ('G'):
+         strcpy (the_line, lines[orig_line]);
+         rl_point = orig_point;
+         rl_end = strlen (the_line);
+         rl_clear_message ();
+         return;
+
+       default:
+         if (c < 32 || c > 126)
+           {
+             rl_execute_next (c);
+             done = 1;
+             continue;
+           }
+         else
+           {
+             search_string[search_string_index++] = c;
+             search_string[search_string_index] = '\0';
+             goto do_search;
+
+           search_again:
+
+             if (!search_string_index)
+               continue;
+             else
+               {
+                 if (reverse)
+                   --index;
+                 else
+                   if (index != strlen (sline))
+                     ++index;
+                   else
+                     ding ();
+               }
+           do_search:
+
+             while (1)
+               {
+                 if (reverse)
+                   {
+                     while (index >= 0)
+                       if (strncmp
+                           (search_string,
+                            sline + index,
+                            search_string_index) == 0)
+                         goto string_found;
+                       else
+                         index--;
+                   }
+                 else
+                   {
+                     register int limit =
+                       (strlen (sline) - search_string_index) + 1;
+
+                     while (index < limit)
+                       {
+                         if (strncmp (search_string,
+                                      sline + index,
+                                      search_string_index) == 0)
+                           goto string_found;
+                         index++;
+                       }
+                   }
+
+               next_line:
+                 i += direction;
+
+                 /* At limit for direction? */
+                 if ((reverse && i < 0) ||
+                     (!reverse && i == hlen))
+                   goto search_failed;
+
+                 sline = lines[i];
+                 if (reverse)
+                   index = strlen (sline);
+                 else
+                   index = 0;
+
+                 /* If the search string is longer than the current
+                    line, no match. */
+                 if (search_string_index > strlen (sline))
+                   goto next_line;
+
+                 /* Start actually searching. */
+                 if (reverse)
+                   index -= search_string_index;
+               }
+
+           search_failed:
+             /* We cannot find the search string.  Ding the bell. */
+             ding ();
+             i = last_found_line;
+             break;
+
+           string_found:
+             /* We have found the search string.  Just display it.  But don't
+                actually move there in the history list until the user accepts
+                the location. */
+             strcpy (the_line, lines[i]);
+             rl_point = index;
+             rl_end = strlen (the_line);
+             last_found_line = i;
+             rl_display_search (search_string, reverse,
+                                (i == orig_line) ? -1 : i);
+           }
+       }
+      continue;
+    }
+  /* The user has won.  They found the string that they wanted.  Now all
+     we have to do is place them there. */
+  {
+    int now = last_found_line;
+
+    /* First put back the original state. */
+    strcpy (the_line, lines[orig_line]);
+
+    if (now < orig_line)
+      rl_get_previous_history (orig_line - now);
+    else
+      rl_get_next_history (now - orig_line);
+
+    rl_point = index;
+    rl_clear_message ();
+  }
+}
+
+/* Make C be the next command to be executed. */
+rl_execute_next (c)
+     int c;
+{
+  rl_pending_input = c;
+}
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                     Killing Mechanism                           */
+/*                                                                 */
+/* **************************************************************** */
+
+/* What we assume for a max number of kills. */
+#define DEFAULT_MAX_KILLS 10
+
+/* The real variable to look at to find out when to flush kills. */
+int rl_max_kills = DEFAULT_MAX_KILLS;
+
+/* Where to store killed text. */
+char **rl_kill_ring = (char **)NULL;
+
+/* Where we are in the kill ring. */
+int rl_kill_index = 0;
+
+/* How many slots we have in the kill ring. */
+int rl_kill_ring_length = 0;
+
+/* How to say that you only want to save a certain amount
+   of kill material. */
+rl_set_retained_kills (num)
+     int num;
+{}
+
+/* The way to kill something.  This appends or prepends to the last
+   kill, if the last command was a kill command.  if FROM is less
+   than TO, then the text is appended, otherwise prepended.  If the
+   last command was not a kill command, then a new slot is made for
+   this kill. */
+rl_kill_text (from, to)
+     int from, to;
+{
+  int slot;
+  char *text = rl_copy (from, to);
+
+  /* Is there anything to kill? */
+  if (from == to) {
+    free (text);
+    last_command_was_kill++;
+    return;
+  }
+
+  /* Delete the copied text from the line. */
+  rl_delete_text (from, to);
+
+  /* First, find the slot to work with. */
+  if (!last_command_was_kill) {
+
+    /* Get a new slot.  */
+    if (!rl_kill_ring) {
+
+      /* If we don't have any defined, then make one. */
+      rl_kill_ring =
+       (char **)xmalloc (((rl_kill_ring_length = 1) + 1) * sizeof (char *));
+      slot = 1;
+
+    } else {
+
+      /* We have to add a new slot on the end, unless we have exceeded
+        the max limit for remembering kills. */
+      slot = rl_kill_ring_length;
+      if (slot == rl_max_kills) {
+       register int i;
+       free (rl_kill_ring[0]);
+       for (i = 0; i < slot; i++)
+         rl_kill_ring[i] = rl_kill_ring[i + 1];
+      } else {
+       rl_kill_ring =
+         (char **)xrealloc (rl_kill_ring,
+                            ((slot = (rl_kill_ring_length += 1)) + 1)
+                            * sizeof (char *));
+      }
+    }
+    slot--;
+  } else {
+    slot = rl_kill_ring_length - 1;
+  }
+
+  /* If the last command was a kill, prepend or append. */
+  if (last_command_was_kill) {
+    char *old = rl_kill_ring[slot];
+    char *new = (char *)xmalloc (1 + strlen (old) + strlen (text));
+
+    if (from < to) {
+      strcpy (new, old);
+      strcat (new, text);
+    } else {
+      strcpy (new, text);
+      strcat (new, old);
+    }
+    free (old);
+    free (text);
+    rl_kill_ring[slot] = new;
+  } else {
+    rl_kill_ring[slot] = text;
+  }
+  rl_kill_index = slot;
+  last_command_was_kill++;
+}
+
+/* Now REMEMBER!  In order to do prepending or appending correctly, kill
+   commands always make rl_point's original position be the FROM argument,
+   and rl_point's extent be the TO argument. */
+
+
+/* **************************************************************** */
+/*                                                                 */
+/*                     Killing Commands                            */
+/*                                                                 */
+/* **************************************************************** */
+
+/* Delete the word at point, saving the text in the kill ring. */
+rl_kill_word (count)
+     int count;
+{
+  int orig_point = rl_point;
+
+  if (count < 0)
+    rl_backward_kill_word (-count);
+  else
+    {
+      rl_forward_word (count);
+
+      if (rl_point != orig_point)
+       rl_kill_text (orig_point, rl_point);
+
+      rl_point = orig_point;
+    }
+}
+
+/* Rubout the word before point, placing it on the kill ring. */
+rl_backward_kill_word (count)
+     int count;
+{
+  int orig_point = rl_point;
+
+  if (count < 0)
+    rl_kill_word (-count);
+  else
+    {
+      rl_backward_word (count);
+
+      if (rl_point != orig_point)
+       rl_kill_text (orig_point, rl_point);
+    }
+}
+
+/* Kill from here to the end of the line.  If DIRECTION is negative, kill
+   back to the line start instead. */
+rl_kill_line (direction)
+     int direction;
+{
+  int orig_point = rl_point;
+
+  if (direction < 0)
+    rl_backward_kill_line (1);
+  else
+    {
+      rl_end_of_line ();
+      if (orig_point != rl_point)
+       rl_kill_text (orig_point, rl_point);
+      rl_point = orig_point;
+    }
+}
+
+/* Kill backwards to the start of the line.  If DIRECTION is negative, kill
+   forwards to the line end instead. */
+rl_backward_kill_line (direction)
+     int direction;
+{
+  int orig_point = rl_point;
+
+  if (direction < 0)
+    rl_kill_line (1);
+  else
+    {
+      if (!rl_point)
+       ding ();
+      else
+       {
+         rl_beg_of_line ();
+         rl_kill_text (orig_point, rl_point);
+       }
+    }
+}
+
+/* Yank back the last killed text.  This ignores arguments. */
+rl_yank ()
+{
+  if (!rl_kill_ring) rl_abort ();
+  rl_insert_text (rl_kill_ring[rl_kill_index]);
+}
+
+/* If the last command was yank, or yank_pop, and the text just
+   before point is identical to the current kill item, then
+   delete that text from the line, rotate the index down, and
+   yank back some other text. */
+rl_yank_pop ()
+{
+  int l;
+
+  if (((rl_last_func != rl_yank_pop) && (rl_last_func != rl_yank)) ||
+      !rl_kill_ring)
+    {
+      rl_abort ();
+    }
+
+  l = strlen (rl_kill_ring[rl_kill_index]);
+  if (((rl_point - l) >= 0) &&
+      (strncmp (the_line + (rl_point - l),
+               rl_kill_ring[rl_kill_index], l) == 0))
+    {
+      rl_delete_text ((rl_point - l), rl_point);
+      rl_point -= l;
+      rl_kill_index--;
+      if (rl_kill_index < 0)
+       rl_kill_index = rl_kill_ring_length - 1;
+      rl_yank ();
+    }
+  else
+    rl_abort ();
+
+}
+
+/* Yank the COUNTth argument from the previous history line. */
+rl_yank_nth_arg (count, ignore)
+     int count;
+{
+  register HIST_ENTRY *entry = previous_history ();
+  char *arg;
+
+  if (entry)
+    next_history ();
+  else
+    {
+      ding ();
+      return;
+    }
+
+  arg = history_arg_extract (count, count, entry->line);
+  if (!arg || !*arg)
+    {
+      ding ();
+      return;
+    }
+
+  rl_begin_undo_group ();
+  if (rl_point && the_line[rl_point - 1] != ' ')
+    rl_insert_text (" ");
+  rl_insert_text (arg);
+  free (arg);
+  rl_end_undo_group ();
+}
+
+/* Vi Mode. */
+#ifdef VI_MODE
+#include "vi_mode.c"
+#endif /* VI_MODE */
+
+/* How to toggle back and forth between editing modes. */
+rl_vi_editing_mode ()
+{
+#ifdef VI_MODE
+  rl_editing_mode = vi_mode;
+  rl_vi_insertion_mode ();
+#endif /* VI_MODE */
+}
+
+rl_emacs_editing_mode ()
+{
+  rl_editing_mode = emacs_mode;
+  keymap = emacs_standard_keymap;
+}
+
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                          Completion                             */
+/*                                                                 */
+/* **************************************************************** */
+
+/* Non-zero means that case is not significant in completion. */
+int completion_case_fold = 0;
+
+/* Return an array of (char *) which is a list of completions for TEXT.
+   If there are no completions, return a NULL pointer.
+   The first entry in the returned array is the substitution for TEXT.
+    The remaining entries are the possible completions.
+   The array is terminated with a NULL pointer.
+
+   ENTRY_FUNCTION is a function of two args, and returns a (char *).
+     The first argument is TEXT.
+     The second is a state argument; it should be zero on the first call, and
+     non-zero on subsequent calls.  It returns a NULL pointer to the caller
+     when there are no more matches.
+ */
+char **
+completion_matches (text, entry_function)
+     char *text;
+     char *(*entry_function) ();
+{
+  /* Number of slots in match_list. */
+  int match_list_size;
+
+  /* The list of matches. */
+  char **match_list =
+    (char **)xmalloc (((match_list_size = 10) + 1) * sizeof (char *));
+
+  /* Number of matches actually found. */
+  int matches = 0;
+
+  /* Temporary string binder. */
+  char *string;
+
+  match_list[1] = (char *)NULL;
+
+  while (string = (*entry_function) (text, matches))
+    {
+      if (matches + 1 == match_list_size)
+       match_list =
+         (char **)xrealloc (match_list,
+                            ((match_list_size += 10) + 1) * sizeof (char *));
+
+      match_list[++matches] = string;
+      match_list[matches + 1] = (char *)NULL;
+    }
+
+  /* If there were any matches, then look through them finding out the
+     lowest common denominator.  That then becomes match_list[0]. */
+  if (matches)
+    {
+      register int i = 1;
+      int low = 100000;                /* Count of max-matched characters. */
+
+      /* If only one match, just use that. */
+      if (matches == 1)
+       {
+         match_list[0] = match_list[1];
+         match_list[1] = (char *)NULL;
+       }
+      else
+       {
+         /* Otherwise, compare each member of the list with
+            the next, finding out where they stop matching. */
+
+         while (i < matches)
+           {
+             register int c1, c2, si;
+
+             if (completion_case_fold)
+               {
+                 for (si = 0;
+                      (c1 = to_lower(match_list[i][si])) &&
+                      (c2 = to_lower(match_list[i + 1][si]));
+                      si++)
+                   if (c1 != c2) break;
+               }
+             else
+               {
+                 for (si = 0;
+                      (c1 = match_list[i][si]) &&
+                      (c2 = match_list[i + 1][si]);
+                      si++)
+                   if (c1 != c2) break;
+               }
+
+             if (low > si) low = si;
+             i++;
+           }
+         match_list[0] = (char *)xmalloc (low + 1);
+         strncpy (match_list[0], match_list[1], low);
+         match_list[0][low] = '\0';
+       }
+    }
+  else                         /* There were no matches. */
+    {
+      free (match_list);
+      match_list = (char **)NULL;
+    }
+  return (match_list);
+}
+
+/* Okay, now we write the entry_function for filename completion.  In the
+   general case.  Note that completion in the shell is a little different
+   because of all the pathnames that must be followed when looking up the
+   completion for a command. */
+char *
+filename_completion_function (text, state)
+     int state;
+     char *text;
+{
+  static DIR *directory;
+  static char *filename = (char *)NULL;
+  static char *dirname = (char *)NULL;
+  static char *users_dirname = (char *)NULL;
+  static int filename_len;
+
+  struct direct *entry = (struct direct *)NULL;
+
+  /* If we don't have any state, then do some initialization. */
+  if (!state)
+    {
+      char *rindex (), *temp;
+
+      if (dirname) free (dirname);
+      if (filename) free (filename);
+      if (users_dirname) free (users_dirname);
+
+      filename = savestring (text);
+      if (!*text) text = ".";
+      dirname = savestring (text);
+
+      temp = rindex (dirname, '/');
+
+      if (temp)
+       {
+         strcpy (filename, ++temp);
+         *temp = '\0';
+       }
+      else
+       strcpy (dirname, ".");
+
+      /* We aren't done yet.  We also support the "~user" syntax. */
+
+      /* Save the version of the directory that the user typed. */
+      users_dirname = savestring (dirname);
+      {
+       char *tilde_expand (), *temp_dirname = tilde_expand (dirname);
+       free (dirname);
+       dirname = temp_dirname;
+
+       if (rl_symbolic_link_hook)
+         (*rl_symbolic_link_hook) (&dirname);
+      }
+      directory = opendir (dirname);
+      filename_len = strlen (filename);
+
+      rl_filename_completion_desired = 1;
+    }
+
+  /* At this point we should entertain the possibility of hacking wildcarded
+     filenames, like /usr/man*\/te<TAB>.  If the directory name contains
+     globbing characters, then build an array of directories to glob on, and
+     glob on the first one. */
+
+  /* Now that we have some state, we can read the directory. */
+
+  while (directory && (entry = readdir (directory)))
+    {
+      /* Special case for no filename.
+        All entries except "." and ".." match. */
+      if (!filename_len)
+       {
+         if ((strcmp (entry->d_name, ".") != 0) &&
+             (strcmp (entry->d_name, "..") != 0))
+           break;
+       }
+      else
+       {
+         /* Otherwise, if these match upto the length of filename, then
+            it is a match. */
+#ifdef TMB_SYSV
+         if ((strlen (entry->d_name) >= filename_len) &&
+             (strncmp (filename, entry->d_name, filename_len) == 0))
+#else
+           if ((entry->d_namlen >= filename_len) &&
+               (strncmp (filename, entry->d_name, filename_len) == 0))
+#endif /* TMB_SYSV */
+             {
+               break;
+             }
+       }
+    }
+
+  if (!entry)
+    {
+      if (directory)
+       {
+         closedir (directory);
+         directory = (DIR *)NULL;
+       }
+      return (char *)NULL;
+    }
+  else
+    {
+      char *temp;
+
+      if (dirname && (strcmp (dirname, ".") != 0))
+       {
+#ifdef TMB_SYSV
+         temp = (char *)xmalloc (1 + strlen (users_dirname)
+                                 + strlen (entry->d_name));
+#else
+         temp = (char *)xmalloc (1 + strlen (users_dirname)
+                                 + entry->d_namlen);
+#endif /* TMB_SYSV */
+         strcpy (temp, users_dirname);
+         strcat (temp, entry->d_name);
+       }
+      else
+       {
+         temp = (savestring (entry->d_name));
+       }
+      return (temp);
+    }
+}
+
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                     Binding keys                                */
+/*                                                                 */
+/* **************************************************************** */
+
+/* rl_add_defun (char *name, Function *function, int key)
+   Add NAME to the list of named functions.  Make FUNCTION
+   be the function that gets called.
+   If KEY is not -1, then bind it. */
+rl_add_defun (name, function, key)
+     char *name;
+     Function *function;
+     int key;
+{
+  if (key != -1)
+    rl_bind_key (key, function);
+  rl_add_funmap_entry (name, function);
+}
+
+/* Bind KEY to FUNCTION.  Returns non-zero if KEY is out of range. */
+int
+rl_bind_key (key, function)
+     int key;
+     Function *function;
+{
+  if (key < 0)
+    return (key);
+
+  if (key > 127 && key < 256)
+    {
+      if (keymap[ESC].type == ISKMAP)
+       {
+         Keymap escmap = (Keymap)keymap[ESC].function;
+
+         key -= 128;
+         escmap[key].type = ISFUNC;
+         escmap[key].function = function;
+         return (0);
+       }
+      return (key);
+    }
+
+  keymap[key].type = ISFUNC;
+  keymap[key].function = function;
+ return (0);
+}
+
+/* Bind KEY to FUNCTION in MAP.  Returns non-zero in case of invalid
+   KEY. */
+int
+rl_bind_key_in_map (key, function, map)
+     int key;
+     Function *function;
+     Keymap map;
+{
+  int result;
+  Keymap oldmap = keymap;
+
+  keymap = map;
+  result = rl_bind_key (key, function);
+  keymap = oldmap;
+  return (result);
+}
+
+/* Make KEY do nothing in the currently selected keymap.
+   Returns non-zero in case of error. */
+int
+rl_unbind_key (key)
+     int key;
+{
+  return (rl_bind_key (key, (Function *)NULL));
+}
+
+/* Make KEY do nothing in MAP.
+   Returns non-zero in case of error. */
+int
+rl_unbind_key_in_map (key, map)
+     int key;
+     Keymap map;
+{
+  return (rl_bind_key_in_map (key, (Function *)NULL, map));
+}
+
+/* Bind the key sequence represented by the string KEYSEQ to
+   FUNCTION.  This makes new keymaps as necessary.  The initial
+   place to do bindings is in MAP. */
+rl_set_key (keyseq, function, map)
+     char *keyseq;
+     Function *function;
+     Keymap map;
+{
+  rl_generic_bind (ISFUNC, keyseq, function, map);
+}
+
+/* Bind the key sequence represented by the string KEYSEQ to
+   the string of characters MACRO.  This makes new keymaps as
+   necessary.  The initial place to do bindings is in MAP. */
+rl_macro_bind (keyseq, macro, map)
+     char *keyseq, *macro;
+     Keymap map;
+{
+  char *macro_keys = (char *)xmalloc (2 * (strlen (macro)));
+  int macro_keys_len;
+
+  if (rl_translate_keyseq (macro, macro_keys, &macro_keys_len))
+    {
+      free (macro_keys);
+      return;
+    }
+  rl_generic_bind (ISMACR, keyseq, macro_keys, map);
+}
+
+/* Bind the key sequence represented by the string KEYSEQ to
+   the arbitrary pointer DATA.  TYPE says what kind of data is
+   pointed to by DATA, right now this can be a function (ISFUNC),
+   a macro (ISMACR), or a keymap (ISKMAP).  This makes new keymaps
+   as necessary.  The initial place to do bindings is in MAP. */
+rl_generic_bind (type, keyseq, data, map)
+     int type;
+     char *keyseq, *data;
+     Keymap map;
+{
+  char *keys;
+  int keys_len;
+  register int i;
+
+  /* If no keys to bind to, exit right away. */
+  if (!keyseq || !*keyseq)
+    {
+      if (type == ISMACR)
+       free (data);
+      return;
+    }
+
+  keys = (char *)alloca (1 + (2 * strlen (keyseq)));
+
+  /* Translate the ASCII representation of KEYSEQ into an array
+     of characters.  Stuff the characters into ARRAY, and the
+     length of ARRAY into LENGTH. */
+  if (rl_translate_keyseq (keyseq, keys, &keys_len))
+    return;
+
+  /* Bind keys, making new keymaps as necessary. */
+  for (i = 0; i < keys_len; i++)
+    {
+      if (i + 1 < keys_len)
+       {
+         if (map[keys[i]].type != ISKMAP)
+           {
+             if (map[i].type == ISMACR)
+               free ((char *)map[i].function);
+
+             map[keys[i]].type = ISKMAP;
+             map[keys[i]].function = (Function *)rl_make_bare_keymap ();
+           }
+         map = (Keymap)map[keys[i]].function;
+       }
+      else
+       {
+         if (map[keys[i]].type == ISMACR)
+           free ((char *)map[keys[i]].function);
+
+         map[keys[i]].function = (Function *)data;
+         map[keys[i]].type = type;
+       }
+    }
+}
+
+/* Translate the ASCII representation of SEQ, stuffing the
+   values into ARRAY, an array of characters.  LEN gets the
+   final length of ARRAY.  Return non-zero if there was an
+   error parsing SEQ. */
+rl_translate_keyseq (seq, array, len)
+     char *seq, *array;
+     int *len;
+{
+  register int i, c, l = 0;
+
+  for (i = 0; c = seq[i]; i++)
+    {
+      if (c == '\\')
+       {
+         c = seq[++i];
+
+         if (!c)
+           break;
+
+         if (((c == 'C' || c == 'M') &&  seq[i + 1] == '-') ||
+             (c == 'e'))
+           {
+             /* Handle special case of backwards define. */
+             if (strncmp (&seq[i], "C-\\M-", 5) == 0)
+               {
+                 array[l++] = ESC;
+                 i += 5;
+                 array[l++] = CTRL (to_upper (seq[i]));
+                 if (!seq[i])
+                   i--;
+                 continue;
+               }
+
+             switch (c)
+               {
+               case 'M':
+                 i++;
+                 array[l++] = ESC;
+                 break;
+
+               case 'C':
+                 i += 2;
+                 array[l++] = CTRL (to_upper (seq[i]));
+                 break;
+
+               case 'e':
+                 array[l++] = ESC;
+               }
+
+             continue;
+           }
+       }
+      array[l++] = c;
+    }
+
+  *len = l;
+  array[l] = '\0';
+  return (0);
+}
+
+/* Return a pointer to the function that STRING represents.
+   If STRING doesn't have a matching function, then a NULL pointer
+   is returned. */
+Function *
+rl_named_function (string)
+     char *string;
+{
+  register int i;
+
+  for (i = 0; funmap[i]; i++)
+    if (stricmp (funmap[i]->name, string) == 0)
+      return (funmap[i]->function);
+  return ((Function *)NULL);
+}
+
+/* The last key bindings file read. */
+static char *last_readline_init_file = "~/.inputrc";
+
+/* Re-read the current keybindings file. */
+rl_re_read_init_file (count, ignore)
+     int count, ignore;
+{
+  rl_read_init_file (last_readline_init_file);
+}
+
+/* Do key bindings from a file.  If FILENAME is NULL it defaults
+   to `~/.inputrc'.  If the file existed and could be opened and
+   read, 0 is returned, otherwise errno is returned. */
+int
+rl_read_init_file (filename)
+     char *filename;
+{
+  extern int errno;
+  int line_size, line_index;
+  char *line = (char *)xmalloc (line_size = 100);
+  char *openname;
+  FILE *file;
+
+  int c;
+
+  /* Default the filename. */
+  if (!filename)
+    filename = "~/.inputrc";
+
+  openname = tilde_expand (filename);
+
+  /* Open the file. */
+  file = fopen (openname, "r");
+  free (openname);
+
+  if (!file)
+    return (errno);
+
+  last_readline_init_file = filename;
+
+  /* Loop reading lines from the file.  Lines that start with `#' are
+     comments, all other lines are commands for readline initialization. */
+  while ((c = rl_getc (file)) != EOF)
+    {
+      /* If comment, flush to EOL. */
+      if (c == '#')
+       {
+         while ((c = rl_getc (file)) != EOF && c != '\n');
+         if (c == EOF)
+           goto function_exit;
+         continue;
+       }
+
+      /* Otherwise, this is the start of a line.  Read the
+        line from the file. */
+      line_index = 0;
+      while (c != EOF && c != '\n')
+       {
+         line[line_index++] = c;
+         if (line_index == line_size)
+           line = (char *)xrealloc (line, line_size += 100);
+         c = rl_getc (file);
+       }
+      line[line_index] = '\0';
+
+      /* Parse the line. */
+      rl_parse_and_bind (line);
+    }
+
+function_exit:
+
+  free (line);
+  /* Close up the file and exit. */
+  fclose (file);
+  return (0);
+}
+
+
+/* **************************************************************** */
+/*                                                                 */
+/*                     Parser Directives                           */
+/*                                                                 */
+/* **************************************************************** */
+
+/* Conditionals. */
+
+/* Calling programs set this to have their argv[0]. */
+char *rl_readline_name = "other";
+
+/* Stack of previous values of parsing_conditionalized_out. */
+static unsigned char *if_stack = (unsigned char *)NULL;
+static int if_stack_depth = 0;
+static int if_stack_size = 0;
+
+/* Push parsing_conditionalized_out, and set parser state based on ARGS. */
+parser_if (args)
+     char *args;
+{
+  register int i;
+
+  /* Push parser state. */
+  if (if_stack_depth + 1 >= if_stack_size)
+    {
+      if (!if_stack)
+       if_stack = (unsigned char *)xmalloc (if_stack_size = 20);
+      else
+       if_stack = (unsigned char *)xrealloc (if_stack, if_stack_size += 20);
+    }
+  if_stack[if_stack_depth++] = parsing_conditionalized_out;
+
+  /* We only check to see if the first word in ARGS is the same as the
+     value stored in rl_readline_name. */
+
+  /* Isolate first argument. */
+  for (i = 0; args[i] && !whitespace (args[i]); i++);
+
+  if (args[i])
+    args[i++] = '\0';
+
+  if (stricmp (args, rl_readline_name) == 0)
+    parsing_conditionalized_out = 0;
+  else
+    parsing_conditionalized_out = 1;
+}
+
+/* Invert the current parser state if there is anything on the stack. */
+parser_else (args)
+     char *args;
+{
+  if (if_stack_depth)
+    parsing_conditionalized_out = !parsing_conditionalized_out;
+  else
+    {
+      /* *** What, no error message? *** */
+    }
+}
+
+/* Terminate a conditional, popping the value of
+   parsing_conditionalized_out from the stack. */
+parser_endif (args)
+     char *args;
+{
+  if (if_stack_depth)
+    parsing_conditionalized_out = if_stack[--if_stack_depth];
+  else
+    {
+      /* *** What, no error message? *** */
+    }
+}
+
+/* Associate textual names with actual functions. */
+static struct {
+  char *name;
+  Function *function;
+} parser_directives [] = {
+  { "if", parser_if },
+  { "endif", parser_endif },
+  { "else", parser_else },
+  { (char *)0x0, (Function *)0x0 }
+};
+
+/* Handle a parser directive.  STATEMENT is the line of the directive
+   without any leading `$'. */
+static int
+handle_parser_directive (statement)
+     char *statement;
+{
+  register int i;
+  char *directive, *args;
+
+  /* Isolate the actual directive. */
+
+  /* Skip whitespace. */
+  for (i = 0; whitespace (statement[i]); i++);
+
+  directive = &statement[i];
+
+  for (; statement[i] && !whitespace (statement[i]); i++);
+
+  if (statement[i])
+    statement[i++] = '\0';
+
+  for (; statement[i] && whitespace (statement[i]); i++);
+
+  args = &statement[i];
+
+  /* Lookup the command, and act on it. */
+  for (i = 0; parser_directives[i].name; i++)
+    if (stricmp (directive, parser_directives[i].name) == 0)
+      {
+       (*parser_directives[i].function) (args);
+       return (0);
+      }
+
+  /* *** Should an error message be output? */
+  return (1);
+}
+
+/* Read the binding command from STRING and perform it.
+   A key binding command looks like: Keyname: function-name\0,
+   a variable binding command looks like: set variable value.
+   A new-style keybinding looks like "\C-x\C-x": exchange-point-and-mark. */
+rl_parse_and_bind (string)
+     char *string;
+{
+  extern char *possible_control_prefixes[], *possible_meta_prefixes[];
+  char *rindex (), *funname, *kname;
+  static int substring_member_of_array ();
+  register int c;
+  int key, i;
+
+  if (!string || !*string || *string == '#')
+    return;
+
+  /* If this is a parser directive, act on it. */
+  if (*string == '$')
+    {
+      handle_parser_directive (&string[1]);
+      return;
+    }
+
+  /* If we are supposed to be skipping parsing right now, then do it. */
+  if (parsing_conditionalized_out)
+    return;
+
+  i = 0;
+  /* If this keyname is a complex key expression surrounded by quotes,
+     advance to after the matching close quote. */
+  if (*string == '"')
+    {
+      for (i = 1; c = string[i]; i++)
+       {
+         if (c == '"' && string[i - 1] != '\\')
+           break;
+       }
+    }
+
+  /* Advance to the colon (:) or whitespace which separates the two objects. */
+  for (; (c = string[i]) && c != ':' && c != ' ' && c != '\t'; i++ );
+
+  /* Mark the end of the command (or keyname). */
+  if (string[i])
+    string[i++] = '\0';
+
+  /* If this is a command to set a variable, then do that. */
+  if (stricmp (string, "set") == 0)
+    {
+      char *var = string + i;
+      char *value;
+
+      /* Make VAR point to start of variable name. */
+      while (*var && whitespace (*var)) var++;
+
+      /* Make value point to start of value string. */
+      value = var;
+      while (*value && !whitespace (*value)) value++;
+      if (*value)
+       *value++ = '\0';
+      while (*value && whitespace (*value)) value++;
+
+      rl_variable_bind (var, value);
+      return;
+    }
+
+  /* Skip any whitespace between keyname and funname. */
+  for (; string[i] && whitespace (string[i]); i++);
+  funname = &string[i];
+
+  /* Now isolate funname.
+     For straight function names just look for whitespace, since
+     that will signify the end of the string.  But this could be a
+     macro definition.  In that case, the string is quoted, so skip
+     to the matching delimiter. */
+  if (*funname == '\'' || *funname == '"')
+    {
+      int delimiter = string[i++];
+
+      for (; c = string[i]; i++)
+       {
+         if (c == delimiter && string[i - 1] != '\\')
+           break;
+       }
+      if (c)
+       i++;
+    }
+
+  /* Advance to the end of the string.  */
+  for (; string[i] && !whitespace (string[i]); i++);
+
+  /* No extra whitespace at the end of the string. */
+  string[i] = '\0';
+
+  /* If this is a new-style key-binding, then do the binding with
+     rl_set_key ().  Otherwise, let the older code deal with it. */
+  if (*string == '"')
+    {
+      char *seq = (char *)alloca (1 + strlen (string));
+      register int j, k = 0;
+
+      for (j = 1; string[j]; j++)
+       {
+         if (string[j] == '"' && string[j - 1] != '\\')
+           break;
+
+         seq[k++] = string[j];
+       }
+      seq[k] = '\0';
+
+      /* Binding macro? */
+      if (*funname == '\'' || *funname == '"')
+       {
+         j = strlen (funname);
+
+         if (j && funname[j - 1] == *funname)
+           funname[j - 1] = '\0';
+
+         rl_macro_bind (seq, &funname[1], keymap);
+       }
+      else
+       rl_set_key (seq, rl_named_function (funname), keymap);
+
+      return;
+    }
+
+  /* Get the actual character we want to deal with. */
+  kname = rindex (string, '-');
+  if (!kname)
+    kname = string;
+  else
+    kname++;
+
+  key = glean_key_from_name (kname);
+
+  /* Add in control and meta bits. */
+  if (substring_member_of_array (string, possible_control_prefixes))
+    key = CTRL (to_upper (key));
+
+  if (substring_member_of_array (string, possible_meta_prefixes))
+    key = META (key);
+
+  /* Temporary.  Handle old-style keyname with macro-binding. */
+  if (*funname == '\'' || *funname == '"')
+    {
+      char seq[2];
+      int fl = strlen (funname);
+
+      seq[0] = key; seq[1] = '\0';
+      if (fl && funname[fl - 1] == *funname)
+       funname[fl - 1] = '\0';
+
+      rl_macro_bind (seq, &funname[1], keymap);
+    }
+  else
+    rl_bind_key (key, rl_named_function (funname));
+}
+
+rl_variable_bind (name, value)
+     char *name, *value;
+{
+  if (stricmp (name, "editing-mode") == 0)
+    {
+      if (strnicmp (value, "vi", 2) == 0)
+       {
+#ifdef VI_MODE
+         keymap = vi_insertion_keymap;
+         rl_editing_mode = vi_mode;
+#endif /* VI_MODE */
+       }
+      else if (strnicmp (value, "emacs", 5) == 0)
+       {
+         keymap = emacs_standard_keymap;
+         rl_editing_mode = emacs_mode;
+       }
+    }
+  else if (stricmp (name, "horizontal-scroll-mode") == 0)
+    {
+      if (!*value || stricmp (value, "On") == 0)
+       horizontal_scroll_mode = 1;
+      else
+       horizontal_scroll_mode = 0;
+    }
+  else if (stricmp (name, "mark-modified-lines") == 0)
+    {
+      if (!*value || stricmp (value, "On") == 0)
+       mark_modified_lines = 1;
+      else
+       mark_modified_lines = 0;
+    }
+}
+
+/* Return the character which matches NAME.
+   For example, `Space' returns ' '. */
+
+typedef struct {
+  char *name;
+  int value;
+} assoc_list;
+
+assoc_list name_key_alist[] = {
+  { "Space", ' ' },
+  { "SPC", ' ' },
+  { "Rubout", 0x7f },
+  { "DEL", 0x7f },
+  { "Tab", 0x09 },
+  { "Newline", '\n' },
+  { "Return", '\r' },
+  { "RET", '\r' },
+  { "LFD", '\n' },
+  { "Escape", '\033' },
+  { "ESC", '\033' },
+
+  { (char *)0x0, 0 }
+};
+
+int
+glean_key_from_name (name)
+     char *name;
+{
+  register int i;
+
+  for (i = 0; name_key_alist[i].name; i++)
+    if (stricmp (name, name_key_alist[i].name) == 0)
+      return (name_key_alist[i].value);
+
+  return (*name);
+}
+
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                     String Utility Functions                    */
+/*                                                                 */
+/* **************************************************************** */
+
+/* Return non-zero if any members of ARRAY are a substring in STRING. */
+static int
+substring_member_of_array (string, array)
+     char *string, **array;
+{
+  static char *strindex ();
+
+  while (*array)
+    {
+      if (strindex (string, *array))
+       return (1);
+      array++;
+    }
+  return (0);
+}
+
+/* Whoops, Unix doesn't have strnicmp. */
+
+/* Compare at most COUNT characters from string1 to string2.  Case
+   doesn't matter. */
+static int
+strnicmp (string1, string2, count)
+     char *string1, *string2;
+{
+  register char ch1, ch2;
+
+  while (count)
+    {
+      ch1 = *string1++;
+      ch2 = *string2++;
+      if (to_upper(ch1) == to_upper(ch2))
+       count--;
+      else break;
+    }
+  return (count);
+}
+
+/* strcmp (), but caseless. */
+static int
+stricmp (string1, string2)
+     char *string1, *string2;
+{
+  register char ch1, ch2;
+
+  while (*string1 && *string2)
+    {
+      ch1 = *string1++;
+      ch2 = *string2++;
+      if (to_upper(ch1) != to_upper(ch2))
+       return (1);
+    }
+  return (*string1 | *string2);
+}
+
+/* Determine if s2 occurs in s1.  If so, return a pointer to the
+   match in s1.  The compare is case insensitive. */
+static char *
+strindex (s1, s2)
+     register char *s1, *s2;
+{
+  register int i, l = strlen (s2);
+  register int len = strlen (s1);
+
+  for (i = 0; (len - i) >= l; i++)
+    if (strnicmp (&s1[i], s2, l) == 0)
+      return (s1 + i);
+  return ((char *)NULL);
+}
+
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                     SYSV Support                                */
+/*                                                                 */
+/* **************************************************************** */
+
+/* Since system V reads input differently than we do, I have to
+   make a special version of getc for that. */
+
+#ifdef SYSV
+
+extern int errno;
+#include <sys/errno.h>
+
+int
+rl_getc (stream)
+     FILE *stream;
+{
+  int result;
+  unsigned char c;
+
+  while (1)
+    {
+      result = read (fileno (stream), &c, sizeof (char));
+      if (result == sizeof (char))
+       return (c);
+
+      if (errno != EINTR)
+       return (EOF);
+    }
+}
+#else
+int
+rl_getc (stream)
+     FILE *stream;
+{
+  return (getc (stream));
+}
+#endif
+
+#ifdef STATIC_MALLOC
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                     xmalloc and xrealloc ()                     */
+/*                                                                 */
+/* **************************************************************** */
+
+static void memory_error_and_abort ();
+
+static char *
+xmalloc (bytes)
+     int bytes;
+{
+  char *temp = (char *)malloc (bytes);
+
+  if (!temp)
+    memory_error_and_abort ();
+  return (temp);
+}
+
+static char *
+xrealloc (pointer, bytes)
+     char *pointer;
+     int bytes;
+{
+  char *temp = (char *)realloc (pointer, bytes);
+
+  if (!temp)
+    memory_error_and_abort ();
+  return (temp);
+}
+
+static void
+memory_error_and_abort ()
+{
+  fprintf (stderr, "readline: Out of virtual memory!\n");
+  abort ();
+}
+#endif /* STATIC_MALLOC */
+
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                     Testing Readline                            */
+/*                                                                 */
+/* **************************************************************** */
+
+#ifdef TEST
+
+main ()
+{
+  HIST_ENTRY **history_list ();
+  char *temp = (char *)NULL;
+  char *prompt = "readline% ";
+  int done = 0;
+
+  while (!done)
+    {
+      temp = readline (prompt);
+
+      /* Test for EOF. */
+      if (!temp)
+       exit (1);
+
+      /* If there is anything on the line, print it and remember it. */
+      if (*temp)
+       {
+         fprintf (stderr, "%s\r\n", temp);
+         add_history (temp);
+       }
+
+      /* Check for `command' that we handle. */
+      if (strcmp (temp, "quit") == 0)
+       done = 1;
+
+      if (strcmp (temp, "list") == 0) {
+       HIST_ENTRY **list = history_list ();
+       register int i;
+       if (list) {
+         for (i = 0; list[i]; i++) {
+           fprintf (stderr, "%d: %s\r\n", i, list[i]->line);
+           free (list[i]->line);
+         }
+         free (list);
+       }
+      }
+      free (temp);
+    }
+}
+
+#endif /* TEST */
+
+\f
+/*
+ * Local variables:
+ * compile-command: "gcc -g -traditional -I. -I.. -DTEST -o readline readline.c keymaps.o funmap.o history.o -ltermcap"
+ * end:
+ */
diff --git a/readline/readline.h b/readline/readline.h
new file mode 100644 (file)
index 0000000..3e62976
--- /dev/null
@@ -0,0 +1,170 @@
+/* Readline.h -- the names of functions callable from within readline. */
+
+#ifndef _READLINE_H_
+#define _READLINE_H_
+
+#include <readline/keymaps.h>
+
+#ifndef __FUNCTION_DEF
+typedef int Function ();
+#define __FUNCTION_DEF
+#endif
+
+/* The functions for manipulating the text of the line within readline.
+Most of these functions are bound to keys by default. */
+extern int
+rl_beg_of_line (), rl_backward (), rl_delete (), rl_end_of_line (),
+rl_forward (), ding (), rl_backward (), rl_newline (), rl_kill_line (),
+rl_clear_screen (), rl_get_next_history (), rl_get_previous_history (),
+rl_quoted_insert (), rl_reverse_search_history (), rl_transpose_chars
+(), rl_unix_line_discard (), rl_quoted_insert (), rl_unix_word_rubout
+(), rl_yank (), rl_rubout (), rl_backward_word (), rl_kill_word (),
+rl_forward_word (), rl_tab_insert (), rl_yank_pop (), rl_yank_nth_arg (),
+rl_backward_kill_word (), rl_backward_kill_line (), rl_transpose_words
+(), rl_complete (), rl_possible_completions (), rl_do_lowercase_version
+(), rl_digit_argument (), rl_universal_argument (), rl_abort (),
+rl_undo_command (), rl_revert_line (), rl_beginning_of_history (),
+rl_end_of_history (), rl_forward_search_history (), rl_insert (),
+rl_upcase_word (), rl_downcase_word (), rl_capitalize_word (),
+rl_restart_output (), rl_re_read_init_file ();
+
+/* These are *both* defined even when VI_MODE is not. */
+extern int rl_vi_editing_mode (), rl_emacs_editing_mode ();
+
+#ifdef VI_MODE
+/* Things for vi mode. */
+extern int rl_vi_movement_mode (), rl_vi_insertion_mode (), rl_vi_arg_digit (),
+rl_vi_prev_word (), rl_vi_next_word (), rl_vi_char_search (),
+rl_vi_eof_maybe (), rl_vi_append_mode (), rl_vi_put (),
+rl_vi_append_eol (), rl_vi_insert_beg (), rl_vi_delete (), rl_vi_comment (),
+rl_vi_first_print (), rl_vi_fword (), rl_vi_fWord (), rl_vi_bword (),
+rl_vi_bWord (), rl_vi_eword (), rl_vi_eWord (), rl_vi_end_word (),
+rl_vi_change_case (), rl_vi_match (), rl_vi_bracktype (), rl_vi_change_char (),
+rl_vi_yank_arg (), rl_vi_search (), rl_vi_search_again (),
+rl_vi_dosearch (), rl_vi_subst (), rl_vi_overstrike (),
+rl_vi_overstrike_delete (), rl_vi_replace(), rl_vi_column (),
+rl_vi_delete_to (), rl_vi_change_to (), rl_vi_yank_to (), rl_vi_complete ();
+#endif /* VI_MODE */
+
+/* Keyboard macro commands. */
+extern int
+rl_start_kbd_macro (), rl_end_kbd_macro (), rl_call_last_kbd_macro ();
+
+/* Maintaining the state of undo.  We remember individual deletes and inserts
+   on a chain of things to do. */
+
+/* The actions that undo knows how to undo.  Notice that UNDO_DELETE means
+   to insert some text, and UNDO_INSERT means to delete some text.   I.e.,
+   the code tells undo what to undo, not how to undo it. */
+enum undo_code { UNDO_DELETE, UNDO_INSERT, UNDO_BEGIN, UNDO_END };
+
+/* What an element of THE_UNDO_LIST looks like. */
+typedef struct undo_list {
+  struct undo_list *next;
+  int start, end;              /* Where the change took place. */
+  char *text;                  /* The text to insert, if undoing a delete. */
+  enum undo_code what;         /* Delete, Insert, Begin, End. */
+} UNDO_LIST;
+
+/* The current undo list for RL_LINE_BUFFER. */
+extern UNDO_LIST *rl_undo_list;
+
+/* The data structure for mapping textual names to code addresses. */
+typedef struct {
+  char *name;
+  Function *function;
+} FUNMAP;
+
+extern FUNMAP **funmap;
+
+/* **************************************************************** */
+/*                                                                 */
+/*                     Well Published Variables                    */
+/*                                                                 */
+/* **************************************************************** */
+
+/* The name of the calling program.  You should initialize this to
+   whatever was in argv[0].  It is used when parsing conditionals. */
+extern char *rl_readline_name;
+
+/* The line buffer that is in use. */
+extern char *rl_line_buffer;
+
+/* The location of point, and end. */
+extern int rl_point, rl_end;
+
+/* The name of the terminal to use. */
+extern char *rl_terminal_name;
+
+/* The input and output streams. */
+extern FILE *rl_instream, *rl_outstream;
+
+/* The basic list of characters that signal a break between words for the
+   completer routine.  The contents of this variable is what breaks words
+   in the shell, i.e. "n\"\\'`@$>". */
+extern char *rl_basic_word_break_characters;
+
+/* The list of characters that signal a break between words for
+   rl_complete_internal.  The default list is the contents of
+   rl_basic_word_break_characters.  */
+extern char *rl_completer_word_break_characters;
+
+/* List of characters that are word break characters, but should be left
+   in TEXT when it is passed to the completion function.  The shell uses
+   this to help determine what kind of completing to do. */
+extern char *rl_special_prefixes;
+
+/* Pointer to the generator function for completion_matches ().
+   NULL means to use filename_entry_function (), the default filename
+   completer. */
+extern Function *rl_completion_entry_function;
+
+/* Pointer to alternative function to create matches.
+   Function is called with TEXT, START, and END.
+   START and END are indices in RL_LINE_BUFFER saying what the boundaries
+   of TEXT are.
+   If this function exists and returns NULL then call the value of
+   rl_completion_entry_function to try to match, otherwise use the
+   array of strings returned. */
+extern Function *rl_attempted_completion_function;
+
+/* If non-null, this contains the address of a function to call if the
+   standard meaning for expanding a tilde fails.  The function is called
+   with the text (sans tilde, as in "foo"), and returns a malloc()'ed string
+   which is the expansion, or a NULL pointer if there is no expansion. */
+extern Function *rl_tilde_expander;
+
+/* If non-zero, then this is the address of a function to call just
+   before readline_internal () prints the first prompt. */
+extern Function *rl_startup_hook;
+
+/* If non-zero, then this is the address of a function to call when
+   completing on a directory name.  The function is called with
+   the address of a string (the current directory name) as an arg. */
+extern Function *rl_symbolic_link_hook;
+
+/* Non-zero means that modified history lines are preceded
+   with an asterisk. */
+extern int rl_show_star;
+
+/* **************************************************************** */
+/*                                                                 */
+/*                     Well Published Functions                    */
+/*                                                                 */
+/* **************************************************************** */
+
+/* Read a line of input.  Prompt with PROMPT.  A NULL PROMPT means none. */
+extern char *readline ();
+
+/* Return an array of strings which are the result of repeatadly calling
+   FUNC with TEXT. */
+extern char **completion_matches ();
+
+/* rl_add_defun (char *name, Function *function, int key)
+   Add NAME to the list of named functions.  Make FUNCTION
+   be the function that gets called.
+   If KEY is not -1, then bind it. */
+extern int rl_add_defun ();
+
+#endif /* _READLINE_H_ */
+
diff --git a/readline/vi_keymap.c b/readline/vi_keymap.c
new file mode 100644 (file)
index 0000000..81fbb9b
--- /dev/null
@@ -0,0 +1,474 @@
+/* vi_keymap.c -- the keymap for vi_mode in readline (). */
+
+/* Copyright (C) 1988,1989 Free Software Foundation, Inc.
+
+   This file is part of GNU Readline, a library for reading lines
+   of text with interactive input and history editing.
+
+   Readline 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.
+
+   Readline 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 Readline; see the file COPYING.  If not, write to the Free
+   Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef FILE
+#include <stdio.h>
+#endif /* FILE */
+
+#include "readline.h"
+
+extern KEYMAP_ENTRY_ARRAY vi_escape_keymap;
+
+/* The keymap arrays for handling vi mode. */
+KEYMAP_ENTRY_ARRAY vi_movement_keymap = {
+
+  /* The regular control keys come first. */
+  { ISFUNC, (Function *)0x0 },         /* Control-@ */
+  { ISFUNC, (Function *)0x0 },         /* Control-a */
+  { ISFUNC, (Function *)0x0 },         /* Control-b */
+  { ISFUNC, (Function *)0x0 },         /* Control-c */
+  { ISFUNC, rl_vi_eof_maybe },         /* Control-d */
+  { ISFUNC, rl_emacs_editing_mode },   /* Control-e */
+  { ISFUNC, (Function *)0x0 },         /* Control-f */
+  { ISFUNC, rl_abort },                        /* Control-g */
+  { ISFUNC, rl_backward },             /* Control-h */
+  { ISFUNC, (Function *)0x0 },         /* Control-i */
+  { ISFUNC, rl_newline },              /* Control-j */
+  { ISFUNC, rl_kill_line },            /* Control-k */
+  { ISFUNC, rl_clear_screen },         /* Control-l */
+  { ISFUNC, rl_newline },              /* Control-m */
+  { ISFUNC, rl_get_next_history },     /* Control-n */
+  { ISFUNC, (Function *)0x0 },         /* Control-o */
+  { ISFUNC, rl_get_previous_history }, /* Control-p */
+  { ISFUNC, rl_quoted_insert },                /* Control-q */
+  { ISFUNC, rl_reverse_search_history }, /* Control-r */
+  { ISFUNC, rl_forward_search_history }, /* Control-s */
+  { ISFUNC, rl_transpose_chars },      /* Control-t */
+  { ISFUNC, rl_unix_line_discard },    /* Control-u */
+  { ISFUNC, rl_quoted_insert },                /* Control-v */
+  { ISFUNC, rl_unix_word_rubout },     /* Control-w */
+  { ISFUNC, (Function *)0x0 },         /* Control-x */
+  { ISFUNC, rl_yank },                 /* Control-y */
+  { ISFUNC, (Function *)0x0 },         /* Control-z */
+
+  { ISKMAP, (Function *)vi_escape_keymap }, /* Control-[ */
+  { ISFUNC, (Function *)0x0 },         /* Control-\ */
+  { ISFUNC, (Function *)0x0 },         /* Control-] */
+  { ISFUNC, (Function *)0x0 },         /* Control-^ */
+  { ISFUNC, rl_undo_command },         /* Control-_ */
+
+  /* The start of printing characters. */
+  { ISFUNC, rl_forward },              /* SPACE */
+  { ISFUNC, (Function *)0x0 },         /* ! */
+  { ISFUNC, (Function *)0x0 },         /* " */
+  { ISFUNC, rl_vi_comment },           /* # */
+  { ISFUNC, rl_end_of_line },          /* $ */
+  { ISFUNC, rl_vi_match },             /* % */
+  { ISFUNC, (Function *)0x0 },         /* & */
+  { ISFUNC, (Function *)0x0 },         /* ' */
+  { ISFUNC, (Function *)0x0 },         /* ( */
+  { ISFUNC, (Function *)0x0 },         /* ) */
+  { ISFUNC, rl_vi_complete },          /* * */
+  { ISFUNC, rl_get_next_history},      /* + */
+  { ISFUNC, rl_vi_char_search },       /* , */
+  { ISFUNC, rl_get_previous_history }, /* - */
+  { ISFUNC, (Function *)0x0 },         /* . */
+  { ISFUNC, rl_vi_search },            /* / */
+
+  /* Regular digits. */
+  { ISFUNC, rl_vi_arg_digit },         /* 0 */
+  { ISFUNC, rl_vi_arg_digit },         /* 1 */
+  { ISFUNC, rl_vi_arg_digit },         /* 2 */
+  { ISFUNC, rl_vi_arg_digit },         /* 3 */
+  { ISFUNC, rl_vi_arg_digit },         /* 4 */
+  { ISFUNC, rl_vi_arg_digit },         /* 5 */
+  { ISFUNC, rl_vi_arg_digit },         /* 6 */
+  { ISFUNC, rl_vi_arg_digit },         /* 7 */
+  { ISFUNC, rl_vi_arg_digit },         /* 8 */
+  { ISFUNC, rl_vi_arg_digit },         /* 9 */
+
+  /* A little more punctuation. */
+  { ISFUNC, (Function *)0x0 },         /* : */
+  { ISFUNC, rl_vi_char_search },       /* ; */
+  { ISFUNC, (Function *)0x0 },         /* < */
+  { ISFUNC, (Function *)0x0 },         /* = */
+  { ISFUNC, (Function *)0x0 },         /* > */
+  { ISFUNC, rl_vi_search },            /* ? */
+  { ISFUNC, (Function *)0x0 },         /* @ */
+
+  /* Uppercase alphabet. */
+  { ISFUNC, rl_vi_append_eol },                /* A */
+  { ISFUNC, rl_vi_prev_word},          /* B */
+  { ISFUNC, rl_vi_change_to },         /* C */
+  { ISFUNC, rl_vi_delete_to },         /* D */
+  { ISFUNC, rl_vi_end_word },          /* E */
+  { ISFUNC, rl_vi_char_search },       /* F */
+  { ISFUNC, (Function *)0x0 },         /* G */
+  { ISFUNC, (Function *)0x0 },         /* H */
+  { ISFUNC, rl_vi_insert_beg },                /* I */
+  { ISFUNC, (Function *)0x0 },         /* J */
+  { ISFUNC, (Function *)0x0 },         /* K */
+  { ISFUNC, (Function *)0x0 },         /* L */
+  { ISFUNC, (Function *)0x0 },         /* M */
+  { ISFUNC, rl_vi_search_again },      /* N */
+  { ISFUNC, (Function *)0x0 },         /* O */
+  { ISFUNC, rl_vi_put },               /* P */
+  { ISFUNC, (Function *)0x0 },         /* Q */
+  { ISFUNC, rl_vi_replace },           /* R */
+  { ISFUNC, rl_vi_subst },             /* S */
+  { ISFUNC, rl_vi_char_search },       /* T */
+  { ISFUNC, rl_revert_line },          /* U */
+  { ISFUNC, (Function *)0x0 },         /* V */
+  { ISFUNC, rl_vi_next_word },         /* W */
+  { ISFUNC, rl_rubout },               /* X */
+  { ISFUNC, rl_vi_yank_to },           /* Y */
+  { ISFUNC, (Function *)0x0 },         /* Z */
+
+  /* Some more punctuation. */
+  { ISFUNC, (Function *)0x0 },         /* [ */
+  { ISFUNC, (Function *)0x0 },         /* \ */
+  { ISFUNC, (Function *)0x0 },         /* ] */
+  { ISFUNC, rl_vi_first_print },       /* ^ */
+  { ISFUNC, rl_vi_yank_arg },          /* _ */
+  { ISFUNC, (Function *)0x0 },         /* ` */
+
+  /* Lowercase alphabet. */
+  { ISFUNC, rl_vi_append_mode },       /* a */
+  { ISFUNC, rl_vi_prev_word },         /* b */
+  { ISFUNC, rl_vi_change_to },         /* c */
+  { ISFUNC, rl_vi_delete_to },         /* d */
+  { ISFUNC, rl_vi_end_word },          /* e */
+  { ISFUNC, rl_vi_char_search },       /* f */
+  { ISFUNC, (Function *)0x0 },         /* g */
+  { ISFUNC, rl_backward },             /* h */
+  { ISFUNC, rl_vi_insertion_mode },    /* i */
+  { ISFUNC, rl_get_next_history },     /* j */
+  { ISFUNC, rl_get_previous_history }, /* k */
+  { ISFUNC, rl_forward },              /* l */
+  { ISFUNC, (Function *)0x0 },         /* m */
+  { ISFUNC, rl_vi_search_again },      /* n */
+  { ISFUNC, (Function *)0x0 },         /* o */
+  { ISFUNC, rl_vi_put },               /* p */
+  { ISFUNC, (Function *)0x0 },         /* q */
+  { ISFUNC, rl_vi_change_char },       /* r */
+  { ISFUNC, rl_vi_subst },             /* s */
+  { ISFUNC, rl_vi_char_search },       /* t */
+  { ISFUNC, rl_undo_command },         /* u */
+  { ISFUNC, (Function *)0x0 },         /* v */
+  { ISFUNC, rl_vi_next_word },         /* w */
+  { ISFUNC, rl_vi_delete },            /* x */
+  { ISFUNC, rl_vi_yank_to },           /* y */
+  { ISFUNC, (Function *)0x0 },         /* z */
+
+  /* Final punctuation. */
+  { ISFUNC, (Function *)0x0 },         /* { */
+  { ISFUNC, rl_vi_column },            /* | */
+  { ISFUNC, (Function *)0x0 },         /* } */
+  { ISFUNC, rl_vi_change_case },       /* ~ */
+  { ISFUNC, rl_backward }              /* RUBOUT */
+};
+
+
+KEYMAP_ENTRY_ARRAY vi_insertion_keymap = {
+
+  /* The regular control keys come first. */
+  { ISFUNC, (Function *)0x0 },         /* Control-@ */
+  { ISFUNC, rl_insert },               /* Control-a */
+  { ISFUNC, rl_insert },               /* Control-b */
+  { ISFUNC, rl_insert },               /* Control-c */
+  { ISFUNC, rl_vi_eof_maybe },         /* Control-d */
+  { ISFUNC, rl_insert },               /* Control-e */
+  { ISFUNC, rl_insert },               /* Control-f */
+  { ISFUNC, rl_insert },               /* Control-g */
+  { ISFUNC, rl_rubout },               /* Control-h */
+  { ISFUNC, rl_complete },             /* Control-i */
+  { ISFUNC, rl_newline },              /* Control-j */
+  { ISFUNC, rl_insert },               /* Control-k */
+  { ISFUNC, rl_insert },               /* Control-l */
+  { ISFUNC, rl_newline },              /* Control-m */
+  { ISFUNC, rl_insert },               /* Control-n */
+  { ISFUNC, rl_insert },               /* Control-o */
+  { ISFUNC, rl_insert },               /* Control-p */
+  { ISFUNC, rl_insert },               /* Control-q */
+  { ISFUNC, rl_reverse_search_history }, /* Control-r */
+  { ISFUNC, rl_forward_search_history }, /* Control-s */
+  { ISFUNC, rl_transpose_chars },      /* Control-t */
+  { ISFUNC, rl_unix_line_discard },    /* Control-u */
+  { ISFUNC, rl_quoted_insert },                /* Control-v */
+  { ISFUNC, rl_unix_word_rubout },     /* Control-w */
+  { ISFUNC, rl_insert },               /* Control-x */
+  { ISFUNC, rl_yank },                 /* Control-y */
+  { ISFUNC, rl_insert },               /* Control-z */
+
+  { ISFUNC, rl_vi_movement_mode },     /* Control-[ */
+  { ISFUNC, rl_insert },               /* Control-\ */
+  { ISFUNC, rl_insert },               /* Control-] */
+  { ISFUNC, rl_insert },               /* Control-^ */
+  { ISFUNC, rl_undo_command },         /* Control-_ */
+
+  /* The start of printing characters. */
+  { ISFUNC, rl_insert },               /* SPACE */
+  { ISFUNC, rl_insert },               /* ! */
+  { ISFUNC, rl_insert },               /* " */
+  { ISFUNC, rl_insert },               /* # */
+  { ISFUNC, rl_insert },               /* $ */
+  { ISFUNC, rl_insert },               /* % */
+  { ISFUNC, rl_insert },               /* & */
+  { ISFUNC, rl_insert },               /* ' */
+  { ISFUNC, rl_insert },               /* ( */
+  { ISFUNC, rl_insert },               /* ) */
+  { ISFUNC, rl_insert },               /* * */
+  { ISFUNC, rl_insert },               /* + */
+  { ISFUNC, rl_insert },               /* , */
+  { ISFUNC, rl_insert },               /* - */
+  { ISFUNC, rl_insert },               /* . */
+  { ISFUNC, rl_insert },               /* / */
+
+  /* Regular digits. */
+  { ISFUNC, rl_insert },               /* 0 */
+  { ISFUNC, rl_insert },               /* 1 */
+  { ISFUNC, rl_insert },               /* 2 */
+  { ISFUNC, rl_insert },               /* 3 */
+  { ISFUNC, rl_insert },               /* 4 */
+  { ISFUNC, rl_insert },               /* 5 */
+  { ISFUNC, rl_insert },               /* 6 */
+  { ISFUNC, rl_insert },               /* 7 */
+  { ISFUNC, rl_insert },               /* 8 */
+  { ISFUNC, rl_insert },               /* 9 */
+
+  /* A little more punctuation. */
+  { ISFUNC, rl_insert },               /* : */
+  { ISFUNC, rl_insert },               /* ; */
+  { ISFUNC, rl_insert },               /* < */
+  { ISFUNC, rl_insert },               /* = */
+  { ISFUNC, rl_insert },               /* > */
+  { ISFUNC, rl_insert },               /* ? */
+  { ISFUNC, rl_insert },               /* @ */
+
+  /* Uppercase alphabet. */
+  { ISFUNC, rl_insert },               /* A */
+  { ISFUNC, rl_insert },               /* B */
+  { ISFUNC, rl_insert },               /* C */
+  { ISFUNC, rl_insert },               /* D */
+  { ISFUNC, rl_insert },               /* E */
+  { ISFUNC, rl_insert },               /* F */
+  { ISFUNC, rl_insert },               /* G */
+  { ISFUNC, rl_insert },               /* H */
+  { ISFUNC, rl_insert },               /* I */
+  { ISFUNC, rl_insert },               /* J */
+  { ISFUNC, rl_insert },               /* K */
+  { ISFUNC, rl_insert },               /* L */
+  { ISFUNC, rl_insert },               /* M */
+  { ISFUNC, rl_insert },               /* N */
+  { ISFUNC, rl_insert },               /* O */
+  { ISFUNC, rl_insert },               /* P */
+  { ISFUNC, rl_insert },               /* Q */
+  { ISFUNC, rl_insert },               /* R */
+  { ISFUNC, rl_insert },               /* S */
+  { ISFUNC, rl_insert },               /* T */
+  { ISFUNC, rl_insert },               /* U */
+  { ISFUNC, rl_insert },               /* V */
+  { ISFUNC, rl_insert },               /* W */
+  { ISFUNC, rl_insert },               /* X */
+  { ISFUNC, rl_insert },               /* Y */
+  { ISFUNC, rl_insert },               /* Z */
+
+  /* Some more punctuation. */
+  { ISFUNC, rl_insert },               /* [ */
+  { ISFUNC, rl_insert },               /* \ */
+  { ISFUNC, rl_insert },               /* ] */
+  { ISFUNC, rl_insert },               /* ^ */
+  { ISFUNC, rl_insert },               /* _ */
+  { ISFUNC, rl_insert },               /* ` */
+
+  /* Lowercase alphabet. */
+  { ISFUNC, rl_insert },               /* a */
+  { ISFUNC, rl_insert },               /* b */
+  { ISFUNC, rl_insert },               /* c */
+  { ISFUNC, rl_insert },               /* d */
+  { ISFUNC, rl_insert },               /* e */
+  { ISFUNC, rl_insert },               /* f */
+  { ISFUNC, rl_insert },               /* g */
+  { ISFUNC, rl_insert },               /* h */
+  { ISFUNC, rl_insert },               /* i */
+  { ISFUNC, rl_insert },               /* j */
+  { ISFUNC, rl_insert },               /* k */
+  { ISFUNC, rl_insert },               /* l */
+  { ISFUNC, rl_insert },               /* m */
+  { ISFUNC, rl_insert },               /* n */
+  { ISFUNC, rl_insert },               /* o */
+  { ISFUNC, rl_insert },               /* p */
+  { ISFUNC, rl_insert },               /* q */
+  { ISFUNC, rl_insert },               /* r */
+  { ISFUNC, rl_insert },               /* s */
+  { ISFUNC, rl_insert },               /* t */
+  { ISFUNC, rl_insert },               /* u */
+  { ISFUNC, rl_insert },               /* v */
+  { ISFUNC, rl_insert },               /* w */
+  { ISFUNC, rl_insert },               /* x */
+  { ISFUNC, rl_insert },               /* y */
+  { ISFUNC, rl_insert },               /* z */
+
+  /* Final punctuation. */
+  { ISFUNC, rl_insert },               /* { */
+  { ISFUNC, rl_insert },               /* | */
+  { ISFUNC, rl_insert },               /* } */
+  { ISFUNC, rl_insert },               /* ~ */
+  { ISFUNC, rl_rubout }                        /* RUBOUT */
+};
+
+KEYMAP_ENTRY_ARRAY vi_escape_keymap = {
+
+  /* The regular control keys come first. */
+  { ISFUNC, (Function *)0x0 },         /* Control-@ */
+  { ISFUNC, (Function *)0x0 },         /* Control-a */
+  { ISFUNC, (Function *)0x0 },         /* Control-b */
+  { ISFUNC, (Function *)0x0 },         /* Control-c */
+  { ISFUNC, (Function *)0x0 },         /* Control-d */
+  { ISFUNC, (Function *)0x0 },         /* Control-e */
+  { ISFUNC, (Function *)0x0 },         /* Control-f */
+  { ISFUNC, (Function *)0x0 },         /* Control-g */
+  { ISFUNC, (Function *)0x0 },         /* Control-h */
+  { ISFUNC, rl_tab_insert},            /* Control-i */
+  { ISFUNC, rl_emacs_editing_mode},    /* Control-j */
+  { ISFUNC, rl_kill_line },            /* Control-k */
+  { ISFUNC, (Function *)0x0 },         /* Control-l */
+  { ISFUNC, rl_emacs_editing_mode},    /* Control-m */
+  { ISFUNC, (Function *)0x0 },         /* Control-n */
+  { ISFUNC, (Function *)0x0 },         /* Control-o */
+  { ISFUNC, (Function *)0x0 },         /* Control-p */
+  { ISFUNC, (Function *)0x0 },         /* Control-q */
+  { ISFUNC, (Function *)0x0 },         /* Control-r */
+  { ISFUNC, (Function *)0x0 },         /* Control-s */
+  { ISFUNC, (Function *)0x0 },         /* Control-t */
+  { ISFUNC, (Function *)0x0 },         /* Control-u */
+  { ISFUNC, (Function *)0x0 },         /* Control-v */
+  { ISFUNC, (Function *)0x0 },         /* Control-w */
+  { ISFUNC, (Function *)0x0 },         /* Control-x */
+  { ISFUNC, (Function *)0x0 },         /* Control-y */
+  { ISFUNC, (Function *)0x0 },         /* Control-z */
+
+  { ISFUNC, rl_vi_movement_mode },     /* Control-[ */
+  { ISFUNC, (Function *)0x0 },         /* Control-\ */
+  { ISFUNC, (Function *)0x0 },         /* Control-] */
+  { ISFUNC, (Function *)0x0 },         /* Control-^ */
+  { ISFUNC, rl_undo_command },         /* Control-_ */
+
+  /* The start of printing characters. */
+  { ISFUNC, (Function *)0x0 },         /* SPACE */
+  { ISFUNC, (Function *)0x0 },         /* ! */
+  { ISFUNC, (Function *)0x0 },         /* " */
+  { ISFUNC, (Function *)0x0 },         /* # */
+  { ISFUNC, (Function *)0x0 },         /* $ */
+  { ISFUNC, (Function *)0x0 },         /* % */
+  { ISFUNC, (Function *)0x0 },         /* & */
+  { ISFUNC, (Function *)0x0 },         /* ' */
+  { ISFUNC, (Function *)0x0 },         /* ( */
+  { ISFUNC, (Function *)0x0 },         /* ) */
+  { ISFUNC, (Function *)0x0 },         /* * */
+  { ISFUNC, (Function *)0x0 },         /* + */
+  { ISFUNC, (Function *)0x0 },         /* , */
+  { ISFUNC, (Function *)0x0 },         /* - */
+  { ISFUNC, (Function *)0x0 },         /* . */
+  { ISFUNC, (Function *)0x0 },         /* / */
+
+  /* Regular digits. */
+  { ISFUNC, rl_vi_arg_digit },         /* 0 */
+  { ISFUNC, rl_vi_arg_digit },         /* 1 */
+  { ISFUNC, rl_vi_arg_digit },         /* 2 */
+  { ISFUNC, rl_vi_arg_digit },         /* 3 */
+  { ISFUNC, rl_vi_arg_digit },         /* 4 */
+  { ISFUNC, rl_vi_arg_digit },         /* 5 */
+  { ISFUNC, rl_vi_arg_digit },         /* 6 */
+  { ISFUNC, rl_vi_arg_digit },         /* 7 */
+  { ISFUNC, rl_vi_arg_digit },         /* 8 */
+  { ISFUNC, rl_vi_arg_digit },         /* 9 */
+
+  /* A little more punctuation. */
+  { ISFUNC, (Function *)0x0 },         /* : */
+  { ISFUNC, (Function *)0x0 },         /* ; */
+  { ISFUNC, (Function *)0x0 },         /* < */
+  { ISFUNC, (Function *)0x0 },         /* = */
+  { ISFUNC, (Function *)0x0 },         /* > */
+  { ISFUNC, (Function *)0x0 },         /* ? */
+  { ISFUNC, (Function *)0x0 },         /* @ */
+
+  /* Uppercase alphabet. */
+  { ISFUNC, rl_do_lowercase_version }, /* A */
+  { ISFUNC, rl_do_lowercase_version }, /* B */
+  { ISFUNC, rl_do_lowercase_version }, /* C */
+  { ISFUNC, rl_do_lowercase_version }, /* D */
+  { ISFUNC, rl_do_lowercase_version }, /* E */
+  { ISFUNC, rl_do_lowercase_version }, /* F */
+  { ISFUNC, rl_do_lowercase_version }, /* G */
+  { ISFUNC, rl_do_lowercase_version }, /* H */
+  { ISFUNC, rl_do_lowercase_version }, /* I */
+  { ISFUNC, rl_do_lowercase_version }, /* J */
+  { ISFUNC, rl_do_lowercase_version }, /* K */
+  { ISFUNC, rl_do_lowercase_version }, /* L */
+  { ISFUNC, rl_do_lowercase_version }, /* M */
+  { ISFUNC, rl_do_lowercase_version }, /* N */
+  { ISFUNC, rl_do_lowercase_version }, /* O */
+  { ISFUNC, rl_do_lowercase_version }, /* P */
+  { ISFUNC, rl_do_lowercase_version }, /* Q */
+  { ISFUNC, rl_do_lowercase_version }, /* R */
+  { ISFUNC, rl_do_lowercase_version }, /* S */
+  { ISFUNC, rl_do_lowercase_version }, /* T */
+  { ISFUNC, rl_do_lowercase_version }, /* U */
+  { ISFUNC, rl_do_lowercase_version }, /* V */
+  { ISFUNC, rl_do_lowercase_version }, /* W */
+  { ISFUNC, rl_do_lowercase_version }, /* X */
+  { ISFUNC, rl_do_lowercase_version }, /* Y */
+  { ISFUNC, rl_do_lowercase_version }, /* Z */
+
+  /* Some more punctuation. */
+  { ISFUNC, (Function *)0x0 },         /* [ */
+  { ISFUNC, (Function *)0x0 },         /* \ */
+  { ISFUNC, (Function *)0x0 },         /* ] */
+  { ISFUNC, (Function *)0x0 },         /* ^ */
+  { ISFUNC, (Function *)0x0 },         /* _ */
+  { ISFUNC, (Function *)0x0 },         /* ` */
+
+  /* Lowercase alphabet. */
+  { ISFUNC, (Function *)0x0 },         /* a */
+  { ISFUNC, (Function *)0x0 },         /* b */
+  { ISFUNC, (Function *)0x0 },         /* c */
+  { ISFUNC, (Function *)0x0 },         /* d */
+  { ISFUNC, (Function *)0x0 },         /* e */
+  { ISFUNC, (Function *)0x0 },         /* f */
+  { ISFUNC, (Function *)0x0 },         /* g */
+  { ISFUNC, (Function *)0x0 },         /* h */
+  { ISFUNC, (Function *)0x0 },         /* i */
+  { ISFUNC, (Function *)0x0 },         /* j */
+  { ISFUNC, (Function *)0x0 },         /* k */
+  { ISFUNC, (Function *)0x0 },         /* l */
+  { ISFUNC, (Function *)0x0 },         /* m */
+  { ISFUNC, (Function *)0x0 },         /* n */
+  { ISFUNC, (Function *)0x0 },         /* o */
+  { ISFUNC, (Function *)0x0 },         /* p */
+  { ISFUNC, (Function *)0x0 },         /* q */
+  { ISFUNC, (Function *)0x0 },         /* r */
+  { ISFUNC, (Function *)0x0 },         /* s */
+  { ISFUNC, (Function *)0x0 },         /* t */
+  { ISFUNC, (Function *)0x0 },         /* u */
+  { ISFUNC, (Function *)0x0 },         /* v */
+  { ISFUNC, (Function *)0x0 },         /* w */
+  { ISFUNC, (Function *)0x0 },         /* x */
+  { ISFUNC, (Function *)0x0 },         /* y */
+  { ISFUNC, (Function *)0x0 },         /* z */
+
+  /* Final punctuation. */
+  { ISFUNC, (Function *)0x0 },         /* { */
+  { ISFUNC, (Function *)0x0 },         /* | */
+  { ISFUNC, (Function *)0x0 },         /* } */
+  { ISFUNC, (Function *)0x0 },         /* ~ */
+  { ISFUNC, rl_backward_kill_word }    /* RUBOUT */
+};
diff --git a/readline/vi_mode.c b/readline/vi_mode.c
new file mode 100644 (file)
index 0000000..478af91
--- /dev/null
@@ -0,0 +1,925 @@
+/* vi_mode.c -- A vi emulation mode for Bash.
+
+   Derived from code written by Jeff Sparkes (jeff1@????).
+ */
+
+\f
+/* **************************************************************** */
+/*                                                                 */
+/*                     VI Emulation Mode                           */
+/*                                                                 */
+/* **************************************************************** */
+
+/* Last string searched for from `/' or `?'. */
+static char *vi_last_search = (char *)NULL;
+static int vi_histpos;
+
+/* Non-zero means enter insertion mode. */
+int vi_doing_insert = 0;
+
+/* *** UNCLEAN *** */
+/* Command keys which do movement for xxx_to commands. */
+static char *vi_motion = " hl^$0ftFt;,%wbeWBE|";
+
+/* Keymap used for vi replace characters.  Created dynamically since
+   rarely used. */
+static Keymap vi_replace_map = (Keymap)NULL;
+
+/* The number of characters inserted in the last replace operation. */
+static vi_replace_count = 0;
+
+/* Yank the nth arg from the previous line into this line at point. */
+rl_vi_yank_arg (count)
+     int count;
+{
+  rl_yank_nth_arg (count, 0);
+}
+
+/* Search again for the last thing searched for. */
+rl_vi_search_again (ignore, key)
+     int ignore, key;
+{
+  switch (key)
+    {
+    case 'n':
+      rl_vi_dosearch (vi_last_search, -1);
+      break;
+
+    case 'N':
+      rl_vi_dosearch (vi_last_search, 1);
+      break;
+    }
+}
+
+/* Do a vi style search. */
+rl_vi_search (count, key)
+     int count, key;
+{
+  int dir, c, save_pos;
+  char *p;
+
+  switch (key)
+    {
+    case '?':
+      dir = 1;
+      break;
+
+    case '/':
+      dir = -1;
+      break;
+
+    default:
+      ding ();
+      return;
+    }
+
+  vi_histpos = where_history ();
+  maybe_save_line ();
+  save_pos = rl_point;
+
+  /* Reuse the line input buffer to read the search string. */
+  the_line[0] = 0;
+  rl_end = rl_point = 0;
+  p = (char *)alloca (2 + (rl_prompt ? strlen (rl_prompt) : 0));
+
+  sprintf (p, "%s%c", rl_prompt ? rl_prompt : "", key);
+
+  rl_message (p, 0, 0);
+
+  while (c = rl_read_key ())
+    {
+      switch (c)
+       {
+       case CTRL('H'):
+       case RUBOUT:
+         if (rl_point == 0)
+           {
+             maybe_unsave_line ();
+             rl_clear_message ();
+             rl_point = save_pos;
+             return;
+           }
+
+       case CTRL('W'):
+       case CTRL('U'):
+         rl_dispatch (c, keymap);
+         break;
+
+       case ESC:
+       case RETURN:
+       case NEWLINE:
+         goto dosearch;
+         break;
+
+       case CTRL('C'):
+         maybe_unsave_line ();
+         rl_clear_message ();
+         rl_point = 0;
+         ding ();
+         return;
+
+       default:
+         rl_insert (1, c);
+         break;
+       }
+      rl_redisplay ();
+    }
+ dosearch:
+  if (vi_last_search)
+    free (vi_last_search);
+
+  vi_last_search = savestring (the_line);
+  rl_vi_dosearch (the_line, dir);
+}
+
+rl_vi_dosearch (string, dir)
+     char *string;
+     int dir;
+{
+  int old, save = vi_histpos;
+  HIST_ENTRY *h;
+
+  if (string == 0 || *string == 0 || vi_histpos < 0)
+    {
+      ding ();
+      return;
+    }
+
+  if ((save = history_search_pos (string, dir, vi_histpos + dir)) == -1)
+    {
+      maybe_unsave_line ();
+      rl_clear_message ();
+      rl_point = 0;
+      ding ();
+      return;
+    }
+
+  vi_histpos = save;
+
+  old = where_history ();
+  history_set_pos (vi_histpos);
+  h = current_history ();
+  history_set_pos (old);
+
+  strcpy (the_line, h->line);
+  rl_undo_list = (UNDO_LIST *)h->data;
+  rl_end = strlen (the_line);
+  rl_point = 0;
+  rl_clear_message ();
+}
+
+/* Completion, from vi's point of view. */
+rl_vi_complete (ignore, key)
+     int ignore, key;
+{
+  if (!whitespace (the_line[rl_point]))
+    {
+      if (!whitespace (the_line[rl_point + 1]))
+       rl_vi_end_word (1, 'E');
+      rl_point++;
+    }
+
+  if (key == '*')
+    rl_complete_internal ('*');
+  else
+    rl_complete (0, key);
+
+  rl_vi_insertion_mode ();
+}
+
+/* Previous word in vi mode. */
+rl_vi_prev_word (count, key)
+     int count, key;
+{
+  if (count < 0)
+    {
+      rl_vi_next_word (-count, key);
+      return;
+    }
+
+  if (uppercase_p (key))
+    rl_vi_bWord (count);
+  else
+    rl_vi_bword (count);
+}
+
+/* Next word in vi mode. */
+rl_vi_next_word (count, key)
+     int count;
+{
+  if (count < 0)
+    {
+      rl_vi_prev_word (-count, key);
+      return;
+    }
+
+  if (uppercase_p (key))
+    rl_vi_fWord (count);
+  else
+    rl_vi_fword (count);
+}
+
+/* Move to the end of the ?next? word. */
+rl_vi_end_word (count, key)
+     int count, key;
+{
+  if (count < 0)
+    {
+      ding ();
+      return;
+    }
+
+  if (uppercase_p (key))
+    rl_vi_eWord (count);
+  else
+    rl_vi_eword (count);
+}
+
+/* Move forward a word the way that 'W' does. */
+rl_vi_fWord (count)
+     int count;
+{
+  while (count-- && rl_point < (rl_end - 1))
+    {
+      /* Skip until whitespace. */
+      while (!whitespace (the_line[rl_point]) && rl_point < rl_end)
+       rl_point++;
+
+      /* Now skip whitespace. */
+      while (whitespace (the_line[rl_point]) && rl_point < rl_end)
+       rl_point++;
+    }
+}
+
+rl_vi_bWord (count)
+     int count;
+{
+  while (count-- && rl_point > 0)
+    {
+      while (rl_point-- >= 0 && whitespace (the_line[rl_point]));
+      while (rl_point >= 0 && !whitespace (the_line[rl_point]))
+       rl_point--;
+      rl_point++;
+    }
+}
+
+rl_vi_eWord (count)
+     int count;
+{
+  while (count -- && rl_point < (rl_end - 1))
+    {
+      while (rl_point++ < rl_end && whitespace (the_line[rl_point]));
+      while (rl_point++ < rl_end && !whitespace (the_line[rl_point]));
+      rl_point--;
+    }
+}
+
+rl_vi_fword (count)
+     int count;
+{
+  while (count -- && rl_point < (rl_end - 1))
+    {
+      if (isident (the_line[rl_point]))
+       {
+         while (isident (the_line[rl_point]) && rl_point < rl_end)
+           rl_point += 1;
+       }
+      else if (!whitespace (the_line[rl_point]))
+       {
+         while (!isident (the_line[rl_point]) &&
+                !whitespace (the_line[rl_point]) && rl_point < rl_end)
+           rl_point += 1;
+       }
+
+      while (whitespace (the_line[rl_point]) && rl_point < rl_end)
+       rl_point++;
+    }
+}
+
+rl_vi_bword (count)
+     int count;
+{
+  while (count -- && rl_point > 0)
+    {
+      while (--rl_point > 0 && whitespace (the_line[rl_point]));
+      if (rl_point > 0)
+       {
+         if (isident (the_line[rl_point]))
+           while (--rl_point >= 0 && isident (the_line[rl_point]));
+         else
+           while (--rl_point >= 0 && !isident (the_line[rl_point]) &&
+                  !whitespace (the_line[rl_point]));
+         rl_point++;
+       }
+    }
+}
+
+rl_vi_eword (count)
+     int count;
+{
+  while (count -- && rl_point < rl_end - 1)
+    {
+      while (++rl_point < rl_end && whitespace (the_line[rl_point]));
+
+      if (rl_point < rl_end)
+       {
+         if (isident (the_line[rl_point]))
+           while (++rl_point < rl_end && isident (the_line[rl_point]));
+         else
+           while (++rl_point < rl_end && !isident (the_line[rl_point])
+                  && !whitespace (the_line[rl_point]));
+         rl_point--;
+       }
+    }
+}
+
+rl_vi_insert_beg ()
+{
+  rl_beg_of_line ();
+  rl_vi_insertion_mode ();
+  return 0;
+}
+
+rl_vi_append_mode ()
+{
+  if (rl_point < rl_end)
+    rl_point += 1;
+  rl_vi_insertion_mode ();
+  return 0;
+}
+
+rl_vi_append_eol ()
+{
+  rl_end_of_line ();
+  rl_vi_append_mode ();
+  return 0;
+}
+
+/* What to do in the case of C-d. */
+rl_vi_eof_maybe (count, c)
+     int count, c;
+{
+  rl_newline (1, '\n');
+}
+
+/* Insertion mode stuff. */
+
+/* Switching from one mode to the other really just involves
+   switching keymaps. */
+rl_vi_insertion_mode ()
+{
+  keymap = vi_insertion_keymap;
+}
+
+rl_vi_movement_mode ()
+{
+  if (rl_point > 0)
+    rl_backward (1);
+
+  keymap = vi_movement_keymap;
+  vi_done_inserting ();
+}
+
+vi_done_inserting ()
+{
+  if (vi_doing_insert)
+    {
+      rl_end_undo_group ();
+      vi_doing_insert = 0;
+    }
+}
+
+rl_vi_arg_digit (count, c)
+     int count, c;
+{
+  if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg)
+    rl_beg_of_line ();
+  else
+    rl_digit_argument (count, c);
+}
+
+/* Doesn't take an arg count in vi */
+rl_vi_change_case (ignore1, ignore2)
+     int ignore1, ignore2;
+{
+  char c = 0;
+
+  if (uppercase_p (the_line[rl_point]))
+    c = to_lower (the_line[rl_point]);
+  else if (lowercase_p (the_line[rl_point]))
+    c = to_upper (the_line[rl_point]);
+
+  /* Vi is kind of strange here. */
+  if (c)
+    {
+      rl_begin_undo_group ();
+      rl_delete (1, c);
+      rl_insert (1, c);
+      rl_end_undo_group ();
+      rl_vi_check ();
+    }
+  else
+    rl_forward (1);
+}
+
+rl_vi_put (count, key)
+     int count, key;
+{
+  if (!uppercase_p (key))
+    rl_forward (1);
+
+  rl_yank ();
+  rl_backward (1);
+}
+
+rl_vi_check ()
+{
+  if (rl_point && rl_point == rl_end)
+    rl_point--;
+}
+
+rl_vi_column (count)
+{
+  if (count > rl_end)
+    rl_end_of_line ();
+  else
+    rl_point = count - 1;
+}
+
+int
+rl_vi_domove (key, nextkey)
+     int key, *nextkey;
+{
+  int c, save;
+
+  rl_mark = rl_point;
+  c = rl_read_key ();
+  *nextkey = c;
+
+  if (!member (c, vi_motion))
+    {
+      if (digit (c))
+       {
+         save = rl_numeric_arg;
+         rl_digit_loop1 ();
+         rl_numeric_arg *= save;
+       }
+      else if ((key == 'd' && c == 'd') ||
+              (key == 'c' && c == 'c'))
+       {
+         rl_mark = rl_end;
+         rl_beg_of_line ();
+         return (0);
+       }
+      else
+       return (-1);
+    }
+
+  rl_dispatch (c, keymap);
+
+  /* No change in position means the command failed. */
+  if (rl_mark == rl_point)
+    return (-1);
+
+  if ((c == 'w' || c == 'W') && rl_point < rl_end)
+    rl_point--;
+
+  if (rl_mark < rl_point)
+    exchange (rl_point, rl_mark);
+
+  return (0);
+}
+
+/* A simplified loop for vi. Don't dispatch key at end.
+   Don't recognize minus sign? */
+rl_digit_loop1 ()
+{
+  int key, c;
+
+  while (1)
+    {
+      rl_message ("(arg: %d) ", arg_sign * rl_numeric_arg, 0);
+      key = c = rl_read_key ();
+
+      if (keymap[c].type == ISFUNC &&
+         keymap[c].function == rl_universal_argument)
+       {
+         rl_numeric_arg *= 4;
+         continue;
+       }
+      c = UNMETA (c);
+      if (numeric (c))
+       {
+         if (rl_explicit_arg)
+           rl_numeric_arg = (rl_numeric_arg * 10) + (c - '0');
+         else
+           rl_numeric_arg = (c - '0');
+         rl_explicit_arg = 1;
+       }
+      else
+       {
+         rl_clear_message ();
+         rl_stuff_char (key);
+       }
+    }
+}
+
+rl_vi_delete_to (count, key)
+     int count, key;
+{
+  int c;
+
+  if (uppercase_p (key))
+    rl_stuff_char ('$');
+
+  if (rl_vi_domove (key, &c))
+    {
+      ding ();
+      return;
+    }
+
+  if ((c != '|') && (c != 'h') && rl_mark < rl_end)
+    rl_mark++;
+
+  rl_kill_text (rl_point, rl_mark);
+}
+
+rl_vi_change_to (count, key)
+     int count, key;
+{
+  int c;
+
+  if (uppercase_p (key))
+    rl_stuff_char ('$');
+
+  if (rl_vi_domove (key, &c))
+    {
+      ding ();
+      return;
+    }
+
+  if ((c != '|') && (c != 'h') && rl_mark < rl_end)
+    rl_mark++;
+
+  rl_begin_undo_group ();
+  vi_doing_insert = 1;
+  rl_kill_text (rl_point, rl_mark);
+  rl_vi_insertion_mode ();
+}
+
+rl_vi_yank_to (count, key)
+     int count, key;
+{
+  int c, save = rl_point;
+
+  if (uppercase_p (key))
+    rl_stuff_char ('$');
+
+  if (rl_vi_domove (key, &c))
+    {
+      ding ();
+      return;
+    }
+
+  rl_begin_undo_group ();
+  rl_kill_text (rl_point, rl_mark);
+  rl_end_undo_group ();
+  rl_do_undo ();
+  rl_point = save;
+}
+
+rl_vi_delete (count)
+{
+  if (rl_point >= rl_end - 1)
+    {
+      rl_delete (count, 0);
+      if (rl_point > 0)
+       rl_backward (1);
+    }
+  else
+    rl_delete (count, 0);
+}
+
+/* Turn the current line into a comment in shell history.  A ksh function */
+rl_vi_comment ()
+{
+  rl_beg_of_line ();
+  rl_insert_text (": ");       /* # doesn't work in interactive mode */
+  rl_redisplay ();
+  rl_newline (1, '\010');
+}
+
+rl_vi_first_print ()
+{
+  rl_back_to_indent ();
+}
+
+rl_back_to_indent (ignore1, ignore2)
+     int ignore1, ignore2;
+{
+  rl_beg_of_line ();
+  while (rl_point < rl_end && whitespace (the_line[rl_point]))
+    rl_point++;
+}
+
+/* NOTE: it is necessary that opposite directions are inverses */
+#define        FTO      1              /* forward to */
+#define BTO    -1              /* backward to */
+#define FFIND   2              /* forward find */
+#define BFIND  -2              /* backward find */
+
+rl_vi_char_search (count, key)
+     int count, key;
+{
+  static char target;
+  static int orig_dir, dir;
+  int pos;
+
+  if (key == ';' || key == ',')
+    dir = (key == ';' ? orig_dir : -orig_dir);
+  else
+    {
+      target = rl_getc (in_stream);
+
+      switch (key)
+       {
+       case 't':
+         orig_dir = dir = FTO;
+         break;
+
+       case 'T':
+         orig_dir = dir = BTO;
+         break;
+
+       case 'f':
+         orig_dir = dir = FFIND;
+         break;
+
+       case 'F':
+         orig_dir = dir = BFIND;
+         break;
+       }
+    }
+
+  pos = rl_point;
+
+  if (dir < 0)
+    {
+      pos--;
+      do
+       {
+         if (the_line[pos] == target)
+           {
+             if (dir == BTO)
+               rl_point = pos + 1;
+             else
+               rl_point = pos;
+             return;
+           }
+       }
+      while (pos--);
+
+      if (pos < 0)
+       {
+         ding ();
+         return;
+       }
+    }
+  else
+    {                  /* dir > 0 */
+      pos++;
+      do
+       {
+         if (the_line[pos] == target)
+           {
+             if (dir == FTO)
+               rl_point = pos - 1;
+             else
+               rl_point = pos;
+             return;
+           }
+       }
+      while (++pos < rl_end);
+
+      if (pos >= (rl_end - 1))
+       ding ();
+    }
+}
+
+/* Match brackets */
+rl_vi_match ()
+{
+  int count = 1, brack, pos;
+
+  pos = rl_point;
+  if ((brack = rl_vi_bracktype (the_line[rl_point])) == 0)
+    {
+      while ((brack = rl_vi_bracktype (the_line[rl_point])) == 0 &&
+            rl_point < rl_end - 1)
+       rl_forward (1);
+
+      if (brack <= 0)
+       {
+         rl_point = pos;
+         ding ();
+         return;
+       }
+    }
+
+  pos = rl_point;
+
+  if (brack < 0)
+    {
+      while (count)
+       {
+         if (--pos >= 0)
+           {
+             int b = rl_vi_bracktype (the_line[pos]);
+             if (b == -brack)
+               count--;
+             else if (b == brack)
+               count++;
+           }
+         else
+           {
+             ding ();
+             return;
+           }
+       }
+    }
+  else
+    {                  /* brack > 0 */
+      while (count)
+       {
+         if (++pos < rl_end)
+           {
+             int b = rl_vi_bracktype (the_line[pos]);
+             if (b == -brack)
+               count--;
+             else if (b == brack)
+               count++;
+           }
+         else
+           {
+             ding ();
+             return;
+           }
+       }
+    }
+  rl_point = pos;
+}
+
+int
+rl_vi_bracktype (c)
+     int c;
+{
+  switch (c)
+    {
+    case '(': return  1;
+    case ')': return -1;
+    case '[': return  2;
+    case ']': return -2;
+    case '{': return  3;
+    case '}': return -3;
+    default:  return  0;
+    }
+}
+
+rl_vi_change_char ()
+{
+  int c;
+
+  c = rl_getc (in_stream);
+
+  switch (c)
+    {
+    case '\033':
+    case CTRL('C'):
+      return;
+
+    default:
+      rl_begin_undo_group ();
+      rl_delete (1, c);
+      rl_insert (1, c);
+      rl_end_undo_group ();
+      break;
+    }
+}
+
+rl_vi_subst (count, key)
+     int count, key;
+{
+  rl_begin_undo_group ();
+  vi_doing_insert = 1;
+
+  if (uppercase_p (key))
+    {
+      rl_beg_of_line ();
+      rl_kill_line (1);
+    }
+  else
+    rl_delete (1, key);
+
+  rl_vi_insertion_mode ();
+}
+
+rl_vi_overstrike (count, key)
+     int count, key;
+{
+  int i;
+
+  if (vi_doing_insert == 0)
+    {
+      vi_doing_insert = 1;
+      rl_begin_undo_group ();
+    }
+
+  for (i = 0; i < count; i++)
+    {
+      vi_replace_count++;
+      rl_begin_undo_group ();
+
+      if (rl_point < rl_end)
+       {
+         rl_delete (1, key);
+         rl_insert (1, key);
+       }
+      else
+       rl_insert (1, key);
+
+      rl_end_undo_group ();
+    }
+}
+
+rl_vi_overstrike_delete (count)
+     int count;
+{
+  int i, s;
+
+  for (i = 0; i < count; i++)
+    {
+      if (vi_replace_count == 0)
+       {
+         ding ();
+         break;
+       }
+      s = rl_point;
+
+      if (rl_do_undo ())
+       vi_replace_count--;
+
+      if (rl_point == s)
+       rl_backward (1);
+    }
+
+  if (vi_replace_count == 0 && vi_doing_insert)
+    {
+      rl_end_undo_group ();
+      rl_do_undo ();
+      vi_doing_insert = 0;
+    }
+}
+
+rl_vi_replace ()
+{
+  int i;
+
+  vi_replace_count = 0;
+
+  vi_replace_map = rl_make_bare_keymap ();
+
+  for (i = ' '; i < 127; i++)
+    vi_replace_map[i].function = rl_vi_overstrike;
+
+  vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete;
+  vi_replace_map[ESC].function = rl_vi_movement_mode;
+  vi_replace_map[RETURN].function = rl_newline;
+  vi_replace_map[NEWLINE].function = rl_newline;
+  keymap = vi_replace_map;
+}
+
+/*
+ * Try to complete the word we are standing on or the word that ends with
+ * the previous character. A space matches everything.
+ * Word delimiters are space and ;.
+ */
+rl_vi_possible_completions()
+{
+  int save_pos = rl_point;
+
+  if (!index (" ;", the_line[rl_point]))
+    {
+      while (!index(" ;", the_line[++rl_point]))
+       ;
+    }
+  else if (the_line[rl_point-1] == ';')
+    {
+      ding ();
+      return (0);
+    }
+
+  rl_possible_completions ();
+  rl_point = save_pos;
+
+  return (0);
+}