--- /dev/null
+
+ 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!
--- /dev/null
+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 "®isters",
+ 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:
--- /dev/null
+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:
--- /dev/null
+##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,^\./,,'`
--- /dev/null
+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:
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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.");
+}
--- /dev/null
+/* 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. */
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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 */
--- /dev/null
+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 "}";
+ }
+
+
+
--- /dev/null
+/* 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.");
+}
--- /dev/null
+/* 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 *));
+}
--- /dev/null
+/* 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
--- /dev/null
+/* 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;
+ }
+}
--- /dev/null
+/* 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 ();
--- /dev/null
+/* 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)));
+ }
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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, ")");
+}
--- /dev/null
+/* 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 ();
--- /dev/null
+/* 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 (®isters[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 (®isters[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, ®isters[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 *) ®isters[REGISTER_BYTE (regno)];
+ SWAP_TARGET_AND_HOST (®, 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 *) ®isters[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, ®isters[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 */
+}
--- /dev/null
+/* 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. */
--- /dev/null
+\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
+
--- /dev/null
+/* 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 ();
--- /dev/null
+/* 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 ();
--- /dev/null
+/* 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 ()));
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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. */
--- /dev/null
+/* 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, <c_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, <c_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, <c_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 *)<c_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, <c_ours);
+#endif
+#ifdef TIOCLGET
+ ioctl (0, TIOCLGET, &lmode_ours);
+#endif
+
+#ifdef TIOCGPGRP
+ ioctl (0, TIOCGPGRP, &pgrp_ours);
+#endif /* TIOCGPGRP */
+
+ terminal_is_ours = 1;
+}
+
--- /dev/null
+/* 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 *) ®isters[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 *) ®isters[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;
+}
--- /dev/null
+/* 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 */
+}
+
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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 */
+};
--- /dev/null
+/* 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.");
+}
--- /dev/null
+/* 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 */
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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.");
+}
--- /dev/null
+# 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",®isters[ 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
+
--- /dev/null
+/* 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, ®s[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);
+}
--- /dev/null
+/* 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");
+
+}
--- /dev/null
+/* 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);
+}
+
--- /dev/null
+/* 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 */
+};
--- /dev/null
+/* 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
+}
+
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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();
--- /dev/null
+/* 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.");
+}
+
--- /dev/null
+/* 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>");
+}
+
--- /dev/null
+/* 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. */
--- /dev/null
+/* 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.");
+}
--- /dev/null
+/* 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
--- /dev/null
+/* 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 ();
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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 *));
+}
--- /dev/null
+/* 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. */
--- /dev/null
+
+ 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!
--- /dev/null
+## -*- 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
--- /dev/null
+/* 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_ */
--- /dev/null
+/* 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 */
+};
--- /dev/null
+/* 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 */
--- /dev/null
+/* 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:
+*/
--- /dev/null
+/* 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 ();
+
+
--- /dev/null
+/* 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 */
--- /dev/null
+/* 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_ */
+
+
--- /dev/null
+/* 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, <) != -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, ¯o_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:
+ */
--- /dev/null
+/* 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_ */
+
--- /dev/null
+/* 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 */
+};
--- /dev/null
+/* 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);
+}