From bd5635a1e2b38ee8432fcdaa6456079191375277 Mon Sep 17 00:00:00 2001 From: "K. Richard Pixley" Date: Thu, 28 Mar 1991 16:26:26 +0000 Subject: [PATCH] Initial revision --- gdb/COPYING | 249 ++ gdb/ChangeLog | 4297 +++++++++++++++++++++++++++++ gdb/ChangeLog-3.x | 4846 +++++++++++++++++++++++++++++++++ gdb/Makefile.in | 506 ++++ gdb/README | 259 ++ gdb/arm-tdep.c | 406 +++ gdb/blockframe.c | 650 +++++ gdb/breakpoint.c | 2259 ++++++++++++++++ gdb/breakpoint.h | 129 + gdb/coffread.c | 1969 ++++++++++++++ gdb/command.h | 151 ++ gdb/copying.awk | 55 + gdb/copying.c | 217 ++ gdb/dbxread.c | 5348 +++++++++++++++++++++++++++++++++++++ gdb/defs.h | 173 ++ gdb/environ.c | 187 ++ gdb/environ.h | 39 + gdb/eval.c | 1042 ++++++++ gdb/exec.c | 350 +++ gdb/expprint.c | 324 +++ gdb/expression.h | 200 ++ gdb/findvar.c | 684 +++++ gdb/frame.h | 128 + gdb/gdb-int.texinfo | 242 ++ gdb/gdbcmd.h | 63 + gdb/gdbcore.h | 82 + gdb/i386-tdep.c | 494 ++++ gdb/infcmd.c | 1088 ++++++++ gdb/inferior.h | 201 ++ gdb/inflow.c | 478 ++++ gdb/infptrace.c | 397 +++ gdb/infrun.c | 1690 ++++++++++++ gdb/inftarg.c | 182 ++ gdb/m68k-tdep.c | 26 + gdb/main.c | 2127 +++++++++++++++ gdb/mem-break.c | 178 ++ gdb/mips-tdep.c | 679 +++++ gdb/mipsread.c | 2879 ++++++++++++++++++++ gdb/printcmd.c | 1960 ++++++++++++++ gdb/remote-sa.m68k.shar | 893 +++++++ gdb/remote.c | 829 ++++++ gdb/solib.c | 245 ++ gdb/source.c | 1186 ++++++++ gdb/sparc-tdep.c | 586 ++++ gdb/stack.c | 1139 ++++++++ gdb/symfile.c | 746 ++++++ gdb/symfile.h | 170 ++ gdb/symmisc.c | 442 +++ gdb/symtab.c | 2622 ++++++++++++++++++ gdb/symtab.h | 884 ++++++ gdb/target.c | 563 ++++ gdb/target.h | 406 +++ gdb/terminal.h | 50 + gdb/utils.c | 1294 +++++++++ gdb/valarith.c | 694 +++++ gdb/valops.c | 1478 ++++++++++ gdb/valprint.c | 1915 +++++++++++++ gdb/value.h | 289 ++ readline/COPYING | 249 ++ readline/Makefile.in | 103 + readline/chardefs.h | 50 + readline/emacs_keymap.c | 472 ++++ readline/funmap.c | 212 ++ readline/history.c | 1478 ++++++++++ readline/history.h | 108 + readline/keymaps.c | 172 ++ readline/keymaps.h | 53 + readline/readline.c | 5641 +++++++++++++++++++++++++++++++++++++++ readline/readline.h | 170 ++ readline/vi_keymap.c | 474 ++++ readline/vi_mode.c | 925 +++++++ 71 files changed, 63772 insertions(+) create mode 100644 gdb/COPYING create mode 100644 gdb/ChangeLog create mode 100644 gdb/ChangeLog-3.x create mode 100644 gdb/Makefile.in create mode 100644 gdb/README create mode 100644 gdb/arm-tdep.c create mode 100644 gdb/blockframe.c create mode 100644 gdb/breakpoint.c create mode 100644 gdb/breakpoint.h create mode 100644 gdb/coffread.c create mode 100644 gdb/command.h create mode 100644 gdb/copying.awk create mode 100644 gdb/copying.c create mode 100644 gdb/dbxread.c create mode 100644 gdb/defs.h create mode 100644 gdb/environ.c create mode 100644 gdb/environ.h create mode 100644 gdb/eval.c create mode 100644 gdb/exec.c create mode 100644 gdb/expprint.c create mode 100644 gdb/expression.h create mode 100644 gdb/findvar.c create mode 100644 gdb/frame.h create mode 100755 gdb/gdb-int.texinfo create mode 100644 gdb/gdbcmd.h create mode 100644 gdb/gdbcore.h create mode 100644 gdb/i386-tdep.c create mode 100644 gdb/infcmd.c create mode 100644 gdb/inferior.h create mode 100644 gdb/inflow.c create mode 100644 gdb/infptrace.c create mode 100644 gdb/infrun.c create mode 100644 gdb/inftarg.c create mode 100644 gdb/m68k-tdep.c create mode 100644 gdb/main.c create mode 100644 gdb/mem-break.c create mode 100644 gdb/mips-tdep.c create mode 100644 gdb/mipsread.c create mode 100644 gdb/printcmd.c create mode 100755 gdb/remote-sa.m68k.shar create mode 100644 gdb/remote.c create mode 100644 gdb/solib.c create mode 100644 gdb/source.c create mode 100644 gdb/sparc-tdep.c create mode 100644 gdb/stack.c create mode 100644 gdb/symfile.c create mode 100644 gdb/symfile.h create mode 100644 gdb/symmisc.c create mode 100644 gdb/symtab.c create mode 100644 gdb/symtab.h create mode 100644 gdb/target.c create mode 100644 gdb/target.h create mode 100644 gdb/terminal.h create mode 100644 gdb/utils.c create mode 100644 gdb/valarith.c create mode 100644 gdb/valops.c create mode 100644 gdb/valprint.c create mode 100644 gdb/value.h create mode 100644 readline/COPYING create mode 100644 readline/Makefile.in create mode 100644 readline/chardefs.h create mode 100644 readline/emacs_keymap.c create mode 100644 readline/funmap.c create mode 100644 readline/history.c create mode 100644 readline/history.h create mode 100644 readline/keymaps.c create mode 100644 readline/keymaps.h create mode 100644 readline/readline.c create mode 100644 readline/readline.h create mode 100644 readline/vi_keymap.c create mode 100644 readline/vi_mode.c diff --git a/gdb/COPYING b/gdb/COPYING new file mode 100644 index 00000000000..9a170375811 --- /dev/null +++ b/gdb/COPYING @@ -0,0 +1,249 @@ + + GNU GENERAL PUBLIC LICENSE + Version 1, February 1989 + + Copyright (C) 1989 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The license agreements of most software companies try to keep users +at the mercy of those companies. By contrast, our General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. The +General Public License applies to the Free Software Foundation's +software and to any other program whose authors commit to using it. +You can use it for your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Specifically, the General Public License is designed to make +sure that you have the freedom to give away or sell copies of free +software, that you receive source code or can get it if you want it, +that you can change the software or use pieces of it in new free +programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of a such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must tell them their rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + The precise terms and conditions for copying, distribution and +modification follow. + + 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. + + 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. + + 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 + + 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. + + + Copyright (C) 19yy + + 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. + + , 1 April 1989 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/gdb/ChangeLog b/gdb/ChangeLog new file mode 100644 index 00000000000..12ec9ccc2f8 --- /dev/null +++ b/gdb/ChangeLog @@ -0,0 +1,4297 @@ +Sat Mar 23 10:02:21 1991 John Gilmore (gnu at cygint.cygnus.com) + + Cleanup for release 3.94.2: + + * Makefile.dist: Pull REMOTE_OBS. Fix saber includes for BFD + include files. Roll version to 3.94.2. + + * coffread.c (init_stringtab): Read length into unsigned char + array before swapping; don't assume 32-bit longs. + + * target.c (target_info): Don't bother with get_sym_file, just use + the symfile global variable. + * symtab.h, symfile.c (get_sym_file): Delete it. + + * dbxread.c (dbx_symfile_init): Don't depend on long == 4 bytes. + (define_symbol): Set symbol line number to 0 if not gcc-compiled. + (read_type): Replace one more error() with complain(). + + * mipsread.c (parse_partial_symbols): Replace printf with complain. + + * i960-tdep.c: Fix copyright attribution. + + * config.gdb: Quote all backquotes in doublequotes. You can + quote me on that. BSD 4.4 shell found this one. + + * infptrace.c (throughout): The third argument to ptrace is an + int *, not an int. + + * infrun.c (wait_for_inferior): When program has terminated, we + have to call target_terminal_ours before we pop that target off + the stack (e.g. before a call to target_kill or + target_mourn_inferior). This fixes problem where a program + terminates, then GDB stops for (tty output) and you have to type + "fg" to the shell to resume it. FIXME: This code for what to + do after termination really should be in normal_stop instead. + + * gdbcore.h (read_memory_check): Change declaration; it changed + names months ago. + + * terminal.h: Include before , 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 for UTek; Sun gets it via + and . + +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 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 + : 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 all the time. Now that BFD + doesn't include , old SunOS's require it for + . + +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 + + * 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 '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 . + 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 + 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 . + (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 , 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 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 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 " 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 not "mips/inst.h". + + * wait.h [HAVE_WAIT_STRUCT]: Put #defines in #if !defined so that + it's OK if they are defined in . + + * 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 , 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 not + Move include of a.out.h above . + (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 + . + + * 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 . + + * 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 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 . + [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 + +Local Variables: +mode: indented-text +left-margin: 8 +fill-column: 74 +version-control: never +End: diff --git a/gdb/ChangeLog-3.x b/gdb/ChangeLog-3.x new file mode 100644 index 00000000000..e8dbcd87bb0 --- /dev/null +++ b/gdb/ChangeLog-3.x @@ -0,0 +1,4846 @@ +Tue Jan 23 15:49:47 1990 Jim Kingdon (kingdon at pogo.ai.mit.edu) + + * dbxread.c (define_symbol): Deal with deftype 'X'. + + * convex-dep.c (wait): Make it pid_t. + + * convex-dep.c (comm_registers_info): accept decimal comm register + specification, as "i comm 32768". + + * dbxread.c (process_one_symbol): Make VARIABLES_INSIDE_BLOCK + macro say by itself where variables are. Pass it desc. + m-convex.h (VARIABLES_INSIDE_BLOCK): Nonzero for native compiler. + + * m-convex.h (SET_STACK_LIMIT_HUGE): Define. + (IGNORE_SYMBOL): Take out #ifdef N_MONPT and put in 0xc4. + +Fri Jan 19 20:04:15 1990 Jim Kingdon (kingdon at albert.ai.mit.edu) + + * printcmd.c (print_frame_args): Always set highest_offset to + current_offset when former is -1. + + * dbxread.c (read_struct_type): Print nice error message + when encountering multiple inheritance. + +Thu Jan 18 13:43:30 1990 Jim Kingdon (kingdon at mole.ai.mit.edu) + + * dbxread.c (read_dbx_symtab): Always treat N_FN as a potential + source for a x.o or -lx symbol, ignoring OFILE_FN_FLAGGED. + + * printcmd.c (print_frame_args): Cast -1 to (CORE_ADDR). + + * hp300bsd-dep.c (_initialize_hp300_dep): Get kernel_u_addr. + m-hp300bsd.h (KERNEL_U_ADDR): Use kernel_u_addr. + + * infcmd.c (run_command): #if 0 out call to + breakpoint_clear_ignore_counts. + +Thu Jan 11 12:58:12 1990 Jim Kingdon (kingdon at mole) + + * printcmd.c (print_frame_args) [STRUCT_ARG_SYM_GARBAGE]: + Try looking up name of var before giving up & printing '?'. + +Wed Jan 10 14:00:14 1990 Jim Kingdon (kingdon at pogo) + + * many files: Move stdio.h before param.h. + + * sun3-dep.c (store_inferior_registers): Only try to write FP + regs #ifdef FP0_REGNUM. + +Mon Jan 8 17:56:15 1990 Jim Kingdon (kingdon at pogo) + + * symtab.c: #if 0 out "info methods" code. + +Sat Jan 6 12:33:04 1990 Jim Kingdon (kingdon at pogo) + + * dbxread.c (read_struct_type): Set TYPE_NFN_FIELDS_TOTAL + from all baseclasses; remove vestigial variable baseclass. + + * findvar.c (read_var_value): Check REG_STRUCT_HAS_ADDR. + printcmd.c (print_frame_args): Check STRUCT_ARG_SYM_GARBAGE. + m-sparc.h: Define REG_STRUCT_HAS_ADDR and STRUCT_ARG_SYM_GARBAGE. + + * blockframe.c (get_frame_block): Subtract one from pc if not + innermost frame. + +Fri Dec 29 15:26:33 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * printcmd.c (print_frame_args): check highest_offset != -1, not i. + +Thu Dec 28 16:21:02 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * valops.c (value_struct_elt): Clean up error msg. + + * breakpoint.c (describe_other_breakpoints): + Delete extra space before "also set at" and add period at end. + +Tue Dec 19 10:28:42 1989 Jim Kingdon (kingdon at pogo) + + * source.c (print_source_lines): Tell user which line number + was out of range when printing error message. + +Sun Dec 17 14:14:09 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * blockframe.c (find_pc_partial_function): Use + BLOCK_START (SYMBOL_BLOCK_VALUE (f)) instead of + SYMBOL_VALUE (f) to get start of function. + + * dbxread.c: Make xxmalloc just a #define for xmalloc. + +Thu Dec 14 16:13:16 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * m68k-opcode.h (fseq & following fp instructions): + Change @ to $. + +Fri Dec 8 19:06:44 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * breakpoint.c (breakpoint_clear_ignore_counts): New function. + infcmd.c (run_command): Call it. + +Wed Dec 6 15:03:38 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * valprint.c: Change it so "array-max 0" means there is + no limit. + + * expread.y (yylex): Change error message "invalid token in + expression" to "invalid character '%c' in expression". + +Mon Dec 4 16:12:54 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * blockframe.c (find_pc_partial_function): Always return 1 + for success, 0 for failure, and set *NAME and *ADDRESS to + match the return value. + + * dbxread.c (symbol_file_command): Use perror_with_name on + error from stat. + (psymtab_to_symtab, add_file_command), + core.c (validate_files), source.c (find_source_lines), + default-dep.c (exec_file_command): Check for errors from stat, + fstat, and myread. + +Fri Dec 1 05:16:42 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * valops.c (check_field): When following pointers, just get + their types; don't call value_ind. + +Thu Nov 30 14:45:29 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * config.gdb (pyr): New machine. + core.c [REG_STACK_SEGMENT]: New code. + dbxread.c (process_one_symbol): Cast return from copy_pending + to long before casting to enum namespace. + infrun.c: Split registers_info into DO_REGISTERS_INFO + and registers_info. + m-pyr.h, pyr-{dep.c,opcode.h,pinsn.c}: New files. + + * hp300bsd-dep.c: Stay in sync with default-dep.c. + + * m-hp300bsd.h (IN_SIGTRAMP): Define. + +Mon Nov 27 23:48:21 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu) + + * m-sparc.h (EXTRACT_RETURN_VALUE, STORE_RETURN_VALUE): + Return floating point values in %f0. + +Tue Nov 21 00:34:46 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * dbxread.c (read_type): #if 0 out code which skips to + comma following x-ref. + +Sat Nov 18 20:10:54 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * valprint.c (val_print): Undo changes of Nov 11 & 16. + (print_string): Add parameter force_ellipses. + (val_print): Pass force_ellipses true when we stop fetching string + before we get to the end, else pass false. + +Thu Nov 16 11:59:50 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * infrun.c (restore_inferior_status): Don't try to restore + selected frame if the inferior no longer exists. + + * valprint.c (val_print): Rewrite string printing code not to + call print_string. + + * Makefile.dist (clean): Remove xgdb and xgdb.o. + +Tue Nov 14 12:41:47 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * Makefile.dist (XGDB, bindir, xbindir, install, all): New stuff. + +Sat Nov 11 15:29:38 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * valprint.c (val_print): chars_to_get: New variable. + +Thu Nov 9 12:31:47 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * main.c (main): Process "-help" as a switch that doesn't + take an argument. + +Wed Nov 8 13:07:02 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * Makefile.dist (gdb.tar.Z): Add "else true". + +Tue Nov 7 12:25:14 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * infrun.c (restore_inferior_status): Don't dereference fid if NULL. + + * config.gdb (sun3, sun4): Accept "sun3" and "sun4". + +Mon Nov 6 09:49:23 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * Makefile.dist (Makefile): Move comments after commands. + + * *-dep.c [READ_COFF_SYMTAB]: Pass optional header size to + read_section_hdr(). + + * inflow.c: Include 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 "*" 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 . + + * 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 + "". + +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 "" messages. + +Wed Aug 23 22:53:47 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * utils.c: Include . + + * 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 "" 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 . + + * 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 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 + + * 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 (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 ==> ). + + * 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 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 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 and + 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, -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. + + +Local Variables: +mode: indented-text +eval: (auto-fill-mode 1) +left-margin: 8 +fill-column: 74 +version-control: never +End: +ng 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, -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. + +Local Variables: +mode: indented-text +left-margin: 8 +fill-column: 74 +version-control: never +End: diff --git a/gdb/Makefile.in b/gdb/Makefile.in new file mode 100644 index 00000000000..7b4e3ce9fa8 --- /dev/null +++ b/gdb/Makefile.in @@ -0,0 +1,506 @@ +##Copyright (C) 1989-1991 Free Software Foundation, Inc. + +# This file is part of GDB. + +# GDB is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 1, or (at your option) +# any later version. + +# GDB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GDB; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +# Place to install binaries. +bindir=/usr/local/bin + +# System V: If you compile gdb with a compiler which uses the coff +# encapsulation feature (this is a function of the compiler used, NOT +# of the m-?.h file selected by config.gdb), you must make sure that +# the GNU nm is the one that is used by munch. + +# If you are compiling with GCC, make sure that either 1) You use the +# -traditional flag, or 2) You have the fixed include files where GCC +# can reach them. Otherwise the ioctl calls in inflow.c and readline.c +# will be incorrectly compiled. The "fixincludes" script in the gcc +# distribution will fix your include files up. +#CC=cc +#CC=gcc -traditional +GCC=gcc + +VPATH=$(srcdir) + +# It is also possible that you will need to add -I/usr/include/sys to the +# CFLAGS section if your system doesn't have fcntl.h in /usr/include (which +# is where it should be according to Posix). + +YACC=bison -y +# YACC=yacc +SHELL=/bin/sh +MAKE=make + +# Set this up with gcc if you have gnu ld and the loader will print out +# line numbers for undefinded refs. +#CC-LD=gcc -static +CC-LD=${CC} + +# define this to be "gmalloc.o" if you want to use the gnu malloc routine +# (useful for debugging memory allocation problems in gdb). To use your +# system malloc, uncomment the following two lines. +#GNU_MALLOC = +#MALLOC_CFLAGS = -DNO_MALLOC_CHECK +GNU_MALLOC = gmalloc.o mcheck.o +MALLOC_CFLAGS = + +# Where is the "include" directory? Traditionally ../include or ./include +INCLUDE_DIR = ${srcdir}/../include +INCLUDE_DEP = $$(INCLUDE_DIR) + +# Where is the BFD library? Traditionally ../bfd or ./bfd +BFD_DIR = ${srcdir}/../bfd +BFD_DEP = $$(BFD_DIR) + +# All the includes used for CFLAGS and for lint. +# -I. for config files. +# -I${srcdir} for , 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 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 >alldeps.mak; + sort >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 + $(MAKE_MAKEFILE) + rm depend.tmp + +config.status: + @echo "You must configure gdb. Look at the README file for details." + @false + +# These are not generated by "make depend" because they only are there +# for some machines. +tm-isi.h tm-sun3.h tm-news.h tm-hp300bsd.h tm-altos.h : tm-68k.h +tm-hp300hpux.h tm-sun2.h tm-3b1.h : tm-68k.h +xm-news1000.h : xm-news.h +xm-i386-sv32.h : xm-i386.h +tm-i386gas.h: tm-i386.h +xm-sun4os4.h : xm-sparc.h +tm-sun4os4.h : tm-sparc.h + +kdb : $(NTSSTART) $(OBS) $(NTSOBS) ${ADD_DEPS} ${RL_LIB_DEP} + rm -f init.c + $(srcdir)/munch ${MUNCH_DEFINE} $(OBS) $(NTSOBS) > init.c + $(CC) $(LDFLAGS) -c init.c $(CLIBS) + ld -o kdb $(NTSSTART) $(OBS) $(NTSOBS) init.o $(ADD_FILES) \ + ${RL_LIB} -lc $(CLIBS) + +# Put the proper machine-specific files first. +# createtags will edit the .o in DEPFILES into .c +TAGS: ${TAGFILES} + $(srcdir)/createtags $(TM_FILE) ${XM_FILE} $(DEPFILES) ${TAGFILES} +tags: TAGS + +# FIXME: Get alldeps.mak up to date, config.gdb none, THEN make gdb.tar.Z! +gdb.tar.Z: ${TARFILES} + rm -f gdb.tar; rm -rf $(DIST) + cd readline ; make readline.tar + mkdir $(DIST) + cd $(DIST) ; for i in ${TARFILES} ; do ln -s ../$$i . ; done + mkdir $(DIST)/readline + cd $(DIST)/readline ; tar xf ../../readline/readline.tar + mkdir $(DIST)/xconfig ${DIST}/tconfig + cd $(DIST)/tconfig ; \ + for i in $(ALLCONFIG) ; do ln -s ../../$$i ../$$i ; done + mkdir $(DIST)/vx-share $(DIST)/nindy-share + cd $(DIST)/tconfig ; \ + for i in $(SFILES_SUBDIR) $(ALLDEPFILES_SUBDIR); \ + do ln -s ../../$$i ../$$i ; done + tar chf - $(DIST) | compress >gdb.tar.Z + rm -rf $(DIST) + +clean: + rm -f ${OBS} ${TSOBS} ${NTSOBS} ${ADD_FILES} + rm -f init.c init.o version.c + rm -f gdb core gdb.tar gdb.tar.Z make.log + rm -f gdb[0-9] + cd readline ; make clean + +distclean: clean expread.tab.c TAGS + rm -f tm.h xm.h config.status + rm -f y.output yacc.acts yacc.tmp + rm -f ${TESTS} Makefile + +realclean: clean + rm -f expread.tab.c TAGS + rm -f tm.h xm.h config.status + rm -f Makefile + +gdb.dvi : gdb.texinfo + tex gdb.texinfo + texindex gdb.?? + tex gdb.texinfo + +# Make copying.c from COPYING +copying.c : COPYING copying.awk + awk -f copying.awk < COPYING > copying.c + +version.c : Makefile.dist + echo 'char *version = "$(VERSION)";' >version.c + +${srcdir}/expread.tab.c : $(srcdir)/expread.y + @echo 'Expect 4 shift/reduce conflict.' + ${YACC} $(srcdir)/expread.y + mv y.tab.c ${srcdir}/expread.tab.c + +expread.o : ${srcdir}/expread.tab.c defs.h param.h symtab.h \ + frame.h expression.h + $(CC) -c ${CFLAGS} `echo ${srcdir}/expread.tab.c | sed 's,^\./,,'` + mv expread.tab.o expread.o + +# dbxread, coffread, mipsread have dependencies on BFD header files. +dbxread.o: ${srcdir}/dbxread.c + ${CC} -c ${CFLAGS} -I$(BFD_DIR) ${srcdir}/dbxread.c + +coffread.o: ${srcdir}/coffread.c + ${CC} -c ${CFLAGS} -I$(BFD_DIR) ${srcdir}/coffread.c + +mipsread.o: ${srcdir}/mipsread.c + ${CC} -c ${CFLAGS} -I$(BFD_DIR) ${srcdir}/mipsread.c + +# Drag in the files that are in another directory. + +getopt1.o: $(GETOPT_DIR)/getopt1.c + ${CC} -c ${CFLAGS} $(GETOPT_DIR)/getopt1.c + +getopt.o: $(GETOPT_DIR)/getopt.c + ${CC} -c ${CFLAGS} $(GETOPT_DIR)/getopt.c + +xdr_ld.o: ${srcdir}/vx-share/xdr_ld.c + ${CC} -c ${CFLAGS} ${srcdir}/vx-share/xdr_ld.c + +xdr_ptrace.o: ${srcdir}/vx-share/xdr_ptrace.c + ${CC} -c ${CFLAGS} ${srcdir}/vx-share/xdr_ptrace.c + +xdr_rdb.o: ${srcdir}/vx-share/xdr_rdb.c + ${CC} -c ${CFLAGS} ${srcdir}/vx-share/xdr_rdb.c + +xdr_regs.o: ${srcdir}/vx-share/xdr_regs.c + ${CC} -c ${CFLAGS} ${srcdir}/vx-share/xdr_regs.c + +nindy.o: ${srcdir}/nindy-share/nindy.c + ${CC} -c ${CFLAGS} ${srcdir}/nindy-share/nindy.c + +Onindy.o: ${srcdir}/nindy-share/Onindy.c + ${CC} -c ${CFLAGS} ${srcdir}/nindy-share/Onindy.c + +ttybreak.o: ${srcdir}/nindy-share/ttybreak.c + ${CC} -c ${CFLAGS} ${srcdir}/nindy-share/ttybreak.c + +ttyflush.o: ${srcdir}/nindy-share/ttyflush.c + ${CC} -c ${CFLAGS} ${srcdir}/nindy-share/ttyflush.c + +tdesc-lib/libdc.o : force_update + cd tdesc-lib ; ${MAKE} "SYSV_DEFINE=${SYSV_DEFINE}" + +# In LOCAL_INCLUDES, -I${srcdir} is right if srcdir is an absolute path, +# and -I../${srcdir} is right if it is relative (e.g. ".."), so search both. +readline/libreadline.a : force_update + cd readline ; ${MAKE} "SYSV=${SYSV_DEFINE}"\ + "VPATH=${srcdir}/readline:../${srcdir}/readline"\ + "LOCAL_INCLUDES=-I../ -I${srcdir}/ -I../${srcdir}/"\ + "DEBUG_FLAGS=${GLOBAL_CFLAGS}" "CC=${CC}" libreadline.a + +lint: $(LINTFILES) + $(LINT) $(INCLUDE_CFLAGS) $(LINTFLAGS) $(LINTFILES) + +gdb.cxref: $(SFILES) + cxref -I. $(SFILES) >gdb.cxref + +force_update : + +# When used with GDB, the demangler should never look for leading underscores +# because GDB strips them off during symbol read-in. Thus -Dnounderscore. +cplus-dem.o : cplus-dem.c + ${CC} -c -Dnounderscore `echo ${srcdir}/cplus-dem.c | sed 's,^\./,,'` diff --git a/gdb/README b/gdb/README new file mode 100644 index 00000000000..999db4a12f7 --- /dev/null +++ b/gdb/README @@ -0,0 +1,259 @@ +This is GDB, the GNU source-level debugger, presently running under +un*x. This is a pre-alpha version of GDB version 4, and has NOT been +extensively tested. It surely has some bugs, both bugs that were +present in version 3 and new bugs. I have filed all the bug reports +and fixes mailed to bug-gdb, and the fixes in particular will move +into these sources as I find the time. + + => THIS VERSION IS PARTICULARLY FRAGILE! <= + + It depends on a preliminary version of a new "binary file + descriptor" library and a new global "include" directory, which + are packaged separately from GDB. You must obtain, configure + and build this library manually, then configure and build gdb. + When building gdb's for multiple platforms, you must manually + rebuild the bfd library separately for each platform. Yes, of + course, we are working on this! FIXME! + + Configure bfd for your host system by: + + cd ../bfd + edit Makefile + make + + Then you can cd ../gdb-whatever, and config and build gdb. + +This release moves the generic GNU include files, the BFD library, +and the getopt routines into the parent directory of gdb. The idea +is that a variety of GNU tools can share a common copy of these things. + +A summary of features new since gdb-3.5 is in the file `WHATS.NEW'. + +The best way to build GDB, in my opinion, is in a subdirectory. I use +a naming convention "=XXX" where XXX is the machine type I'm building +for. Nothing depends on this, it's just how I remember which +subdirectories are what. So, once you have the BFD library built for +that machine, you can do: + + cd gdb-x.yy (the directory where this README is) + mkdir =XXX (e.g. mkdir =vax) + cd =XXX + ../config.gdb machine + make + +Machine is like "vax" or "sun4". For more information type `../config.gdb'. + +Once you have done that, just `make' will do everything, producing an +executable `gdb' in this directory. + +You can also build gdb binaries in a completely different directory from its +sources, by specifying "srcdir=YYY" to config.gdb, giving it an absolute +or relative path to the source directory. + +GDB can be used as a cross-debugger, running on a machine of one type +while debugging a program running on a machine of another type. You +configure it this way by specifying `config.gdb host target' where host +is where GDB runs, and target is where your program runs. + +If you want a new (current to this release) version of the manual, you +will have to use the gdb.texinfo file provided with this distribution. +For details see the texinfo manual (distributed with emacs and as a +printed manual). + +About languages other than C... + +C++ support has been integrated into gdb. GDB should work with FORTRAN +programs (if you have problem, please send a bug report; note that you +may have to refer to some FORTRAN variables with a trailing +underscore), but I am not aware of anyone who is working on getting it +to use the syntax of any language other than C or C++. Pascal programs +which use sets, subranges, file variables, or nested functions will not +currently work. + +About kernel debugging... + +I have't done this myself so I can't really offer any advice. +Remote debugging over serial lines is more like to be in a currently +functioning state than the standalone gdb (kdb). FIXME. + +About remote debugging... + +[This section seems to be out of date, I have never seen the "rapp" +program, though I would like to. FIXME.] +`rapp' runs under unix and acts as a remote stub (like remote-multi.shar +distributed with GDB version 3). Currently it just works over UDP +(network), not over a serial line. To get it running +* Compile GDB on the host machine as usual +* Compile rapp on the target machine, giving for both host and target + the type of the target machine +* Install "gdb" in /etc/services on both machines. + +This will get reworked before the initial release of 4.x. FIXME. + +The two files remote-multi.shar and remote-sa.m68k.shar contain two +examples of a remote stub to be used with remote.c. The the -multi +file is a general stub that can probably be running on various +different flavors of unix to allow debugging over a serial line from +one machine to another. The remote-sa.m68k.shar is designed to run +standalone on a 68k type cpu and communicate properley with the +remote.c stub over a serial line. + +The files remote-eb.c and remote-nindy.c are two examples of remote +interfaces for talking to existing ROM monitors (for the AMD 29000 and the +Intel 960 repsectively). There is also a remote interface for the +VxWorks realtime kernel, which communicates over TCP/IP, in remote-vx.c +and the vx-share subdirectory. + +About reporting bugs... + +The correct address for reporting bugs found with gdb is +"bug-gdb@prep.ai.mit.edu". Please email all bugs to that address. + +About xgdb... + +Hopefully a new xgdb will be in 4.x. + +xgdb.c was provided to us by the user community; it is not an integral +part of the gdb distribution. The problem of providing visual +debugging support on top of gdb is peripheral to the GNU project and +(at least right now) we can't afford to put time into it. So while we +will be happy to incorporate user fixes to xgdb.c, we do not guarantee +that it will work and we will not fix bugs reported in it. See +XGDB-README for one person's opinion about what is wrong with the +current xgdb. Someone is working on writing a new XGDB, so improving +(e.g. by fixing it so that it will work, if it doesn't currently) the +current one is not worth it. + +For those intersted in auto display of source and the availability of +an editor while debugging I suggest trying gdb-mode in gnu-emacs +(Try typing M-x gdb RETURN). Comments on this mode are welcome. + +About the machine-dependent files... + +tconfig/ +This contains Makefile stuff for when the target system is . +It also specifies the name of the tm-XXX.h file for this machine. + +xconfig/ +This contains Makefile stuff for when the host system is . +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. + +-opcode.h +-pinsn.c +These files contain the information necessary to print instructions +for your cpu type. -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. -opcode.h is shared +between the debugger and the assembler (if the GNU assembler has been +ported to that machine), whereas -pinsn.c is specific to GDB. + +-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. + +-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 -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 -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 +-xdep.c. + +exec.c +Machine and system-dependent aspects of reading executable files. +Some machines use exec.c; some have the routines in -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. + +(this is for editing this file with GNU emacs) +Local Variables: +mode: text +End: diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c new file mode 100644 index 00000000000..b4fe1b56937 --- /dev/null +++ b/gdb/arm-tdep.c @@ -0,0 +1,406 @@ +/* Copyright (C) 1988, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" +#include "arm-opcode.h" + +#include +#include +#include +#include +#include +#include +#include + +#define N_TXTADDR(hdr) 0x8000 +#define N_DATADDR(hdr) (hdr.a_text + 0x8000) + +#include "gdbcore.h" +#include /* After a.out.h */ +#include +#include + +#include + + +/* 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; +} + +/* APCS (ARM procedure call standard) defines the following prologue: + + mov ip, sp + [stmfd sp!, {a1,a2,a3,a4}] + stmfd sp!, {...,fp,ip,lr,pc} + [stfe f7, [sp, #-12]!] + [stfe f6, [sp, #-12]!] + [stfe f5, [sp, #-12]!] + [stfe f4, [sp, #-12]!] + sub fp, ip, #nn // nn == 20 or 4 depending on second ins +*/ + +CORE_ADDR +skip_prologue(pc) +CORE_ADDR pc; +{ + union insn_fmt op; + CORE_ADDR skip_pc = pc; + + op.ins = read_memory_integer(skip_pc, 4); + /* look for the "mov ip,sp" */ + if (op.generic.type != TYPE_ARITHMETIC || + op.arith.opcode != OPCODE_MOV || + op.arith.dest != SPTEMP || + op.arith.operand2 != SP) return pc; + skip_pc += 4; + /* skip the "stmfd sp!,{a1,a2,a3,a4}" if its there */ + op.ins = read_memory_integer(skip_pc, 4); + if (op.generic.type == TYPE_BLOCK_BRANCH && + op.generic.subtype == SUBTYPE_BLOCK && + op.block.mask == 0xf && + op.block.base == SP && + op.block.is_load == 0 && + op.block.writeback == 1 && + op.block.increment == 0 && + op.block.before == 1) skip_pc += 4; + /* skip the "stmfd sp!,{...,fp,ip,lr,pc} */ + op.ins = read_memory_integer(skip_pc, 4); + if (op.generic.type != TYPE_BLOCK_BRANCH || + op.generic.subtype != SUBTYPE_BLOCK || + /* the mask should look like 110110xxxxxx0000 */ + (op.block.mask & 0xd800) != 0xd800 || + op.block.base != SP || + op.block.is_load != 0 || + op.block.writeback != 1 || + op.block.increment != 0 || + op.block.before != 1) return pc; + skip_pc += 4; + /* check for "sub fp,ip,#nn" */ + op.ins = read_memory_integer(skip_pc, 4); + if (op.generic.type != TYPE_ARITHMETIC || + op.arith.opcode != OPCODE_SUB || + op.arith.dest != FP || + op.arith.operand1 != SPTEMP) return pc; + return skip_pc + 4; +} + +static void +print_fpu_flags(flags) +int flags; +{ + if (flags & (1 << 0)) fputs("IVO ", stdout); + if (flags & (1 << 1)) fputs("DVZ ", stdout); + if (flags & (1 << 2)) fputs("OFL ", stdout); + if (flags & (1 << 3)) fputs("UFL ", stdout); + if (flags & (1 << 4)) fputs("INX ", stdout); + putchar('\n'); +} + +void +arm_float_info() +{ + register unsigned long status = read_register(FPS_REGNUM); + int type; + + type = (status >> 24) & 127; + printf("%s FPU type %d\n", + (status & (1<<31)) ? "Hardware" : "Software", + type); + fputs("mask: ", stdout); + print_fpu_flags(status >> 16); + fputs("flags: ", stdout); + print_fpu_flags(status); +} diff --git a/gdb/blockframe.c b/gdb/blockframe.c new file mode 100644 index 00000000000..7971166a3c0 --- /dev/null +++ b/gdb/blockframe.c @@ -0,0 +1,650 @@ +/* Get info from stack frames; + convert between frames, blocks, functions and pc values. + Copyright (C) 1986, 1987, 1988, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "defs.h" +#include "param.h" +#include "symtab.h" +#include "frame.h" +#include "gdbcore.h" +#include "value.h" /* for read_register */ +#include "target.h" /* for target_has_stack */ + +/* Required by INIT_EXTRA_FRAME_INFO on 88k. */ +#include +#include + +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); +} + +/* Return the blockvector immediately containing the innermost lexical block + containing the specified pc value, or 0 if there is none. + PINDEX is a pointer to the index value of the block. If PINDEX + is NULL, we don't pass this information back to the caller. */ + +struct blockvector * +blockvector_for_pc (pc, pindex) + register CORE_ADDR pc; + int *pindex; +{ + register struct block *b; + register int bot, top, half; + register struct symtab *s; + struct blockvector *bl; + + /* First search all symtabs for one whose file contains our pc */ + s = find_pc_symtab (pc); + if (s == 0) + return 0; + + bl = BLOCKVECTOR (s); + b = BLOCKVECTOR_BLOCK (bl, 0); + + /* Then search that symtab for the smallest block that wins. */ + /* Use binary search to find the last block that starts before PC. */ + + bot = 0; + top = BLOCKVECTOR_NBLOCKS (bl); + + while (top - bot > 1) + { + half = (top - bot + 1) >> 1; + b = BLOCKVECTOR_BLOCK (bl, bot + half); + if (BLOCK_START (b) <= pc) + bot += half; + else + top = bot + half; + } + + /* Now search backward for a block that ends after PC. */ + + while (bot >= 0) + { + b = BLOCKVECTOR_BLOCK (bl, bot); + if (BLOCK_END (b) > pc) + { + if (pindex) + *pindex = bot; + return bl; + } + bot--; + } + + return 0; +} + +/* Return the innermost lexical block containing the specified pc value, + or 0 if there is none. */ + +struct block * +block_for_pc (pc) + register CORE_ADDR pc; +{ + register struct blockvector *bl; + int index; + + bl = blockvector_for_pc (pc, &index); + if (bl) + return BLOCKVECTOR_BLOCK (bl, index); + return 0; +} + +/* Return the function containing pc value PC. + Returns 0 if function is not known. */ + +struct symbol * +find_pc_function (pc) + CORE_ADDR pc; +{ + register struct block *b = block_for_pc (pc); + if (b == 0) + return 0; + return block_function (b); +} + +/* These variables are used to cache the most recent result + * of find_pc_partial_function. */ + +static CORE_ADDR cache_pc_function_low = 0; +static CORE_ADDR cache_pc_function_high = 0; +static char *cache_pc_function_name = 0; + +/* Clear cache, e.g. when symbol table is discarded. */ + +void +clear_pc_function_cache() +{ + cache_pc_function_low = 0; + cache_pc_function_high = 0; + cache_pc_function_name = (char *)0; +} + +/* Finds the "function" (text symbol) that is smaller than PC + but greatest of all of the potential text symbols. Sets + *NAME and/or *ADDRESS conditionally if that pointer is non-zero. + Returns 0 if it couldn't find anything, 1 if it did. On a zero + return, *NAME and *ADDRESS are always set to zero. On a 1 return, + *NAME and *ADDRESS contain real information. */ + +int +find_pc_partial_function (pc, name, address) + CORE_ADDR pc; + char **name; + CORE_ADDR *address; +{ + struct partial_symtab *pst; + struct symbol *f; + int miscfunc; + struct partial_symbol *psb; + + if (pc >= cache_pc_function_low && pc < cache_pc_function_high) + { + if (address) + *address = cache_pc_function_low; + if (name) + *name = cache_pc_function_name; + return 1; + } + + pst = find_pc_psymtab (pc); + if (pst) + { + if (pst->readin) + { + /* The information we want has already been read in. + We can go to the already readin symbols and we'll get + the best possible answer. */ + f = find_pc_function (pc); + if (!f) + { + return_error: + /* No available symbol. */ + if (name != 0) + *name = 0; + if (address != 0) + *address = 0; + return 0; + } + + cache_pc_function_low = BLOCK_START (SYMBOL_BLOCK_VALUE (f)); + cache_pc_function_high = BLOCK_END (SYMBOL_BLOCK_VALUE (f)); + cache_pc_function_name = SYMBOL_NAME (f); + if (name) + *name = cache_pc_function_name; + if (address) + *address = cache_pc_function_low; + return 1; + } + + /* Get the information from a combination of the pst + (static symbols), and the misc function vector (extern + symbols). */ + miscfunc = find_pc_misc_function (pc); + psb = find_pc_psymbol (pst, pc); + + if (!psb && miscfunc == -1) + { + goto return_error; + } + if (psb + && (miscfunc == -1 + || (SYMBOL_VALUE_ADDRESS (psb) + >= misc_function_vector[miscfunc].address))) + { + /* This case isn't being cached currently. */ + if (address) + *address = SYMBOL_VALUE_ADDRESS (psb); + if (name) + *name = SYMBOL_NAME (psb); + return 1; + } + } + else + /* Must be in the misc function stuff. */ + { + miscfunc = find_pc_misc_function (pc); + if (miscfunc == -1) + goto return_error; + } + + { + if (misc_function_vector[miscfunc].type == mf_text) + cache_pc_function_low = misc_function_vector[miscfunc].address; + else + /* It is a transfer table for Sun shared libraries. */ + cache_pc_function_low = pc - FUNCTION_START_OFFSET; + } + cache_pc_function_name = misc_function_vector[miscfunc].name; + if (miscfunc < misc_function_count && 1 /* FIXME mf_text again? */ ) + cache_pc_function_high = misc_function_vector[miscfunc+1].address; + else + cache_pc_function_high = cache_pc_function_low + 1; + if (address) + *address = cache_pc_function_low; + if (name) + *name = cache_pc_function_name; + return 1; +} + +/* Find the misc function whose address is the largest + while being less than PC. Return its index in misc_function_vector. + Returns -1 if PC is not in suitable range. */ + +int +find_pc_misc_function (pc) + register CORE_ADDR pc; +{ + register int lo = 0; + register int hi = misc_function_count-1; + register int new; + + /* Note that the last thing in the vector is always _etext. */ + /* Actually, "end", now that non-functions + go on the misc_function_vector. */ + + /* Above statement is not *always* true - fix for case where there are */ + /* no misc functions at all (ie no symbol table has been read). */ + if (hi < 0) return -1; /* no misc functions recorded */ + + /* trivial reject range test */ + if (pc < misc_function_vector[0].address || + pc > misc_function_vector[hi].address) + return -1; + + /* Note that the following search will not return hi if + pc == misc_function_vector[hi].address. If "end" points to the + first unused location, this is correct and the above test + simply needs to be changed to + "pc >= misc_function_vector[hi].address". */ + do { + new = (lo + hi) >> 1; + if (misc_function_vector[new].address == pc) + return new; /* an exact match */ + else if (misc_function_vector[new].address > pc) + hi = new; + else + lo = new; + } while (hi-lo != 1); + + /* if here, we had no exact match, so return the lower choice */ + return lo; +} + +/* Return the innermost stack frame executing inside of the specified block, + or zero if there is no such frame. */ + +FRAME +block_innermost_frame (block) + struct block *block; +{ + struct frame_info *fi; + register FRAME frame; + register CORE_ADDR start = BLOCK_START (block); + register CORE_ADDR end = BLOCK_END (block); + + frame = 0; + while (1) + { + frame = get_prev_frame (frame); + if (frame == 0) + return 0; + fi = get_frame_info (frame); + if (fi->pc >= start && fi->pc < end) + return frame; + } +} + +void +_initialize_blockframe () +{ + obstack_init (&frame_cache_obstack); +} diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c new file mode 100644 index 00000000000..6bc621dbd77 --- /dev/null +++ b/gdb/breakpoint.c @@ -0,0 +1,2259 @@ +/* Everything about breakpoints, for GDB. + Copyright (C) 1986, 1987, 1989, 1990 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#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 + +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; + +/* *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; +} + +/* 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); +} + +/* 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; +} + +/* 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; +} + +/* 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); + } +} + +/* 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; + } +} + +/* 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 + +/* 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); +} + +/* + * 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); +} + +/* 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); +} + +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); +} + +/* 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"); +} + +/* 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"); +} + +/* 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); +} + +/* + * 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; +} + + +/* Chain containing all defined enable commands. */ + +extern struct cmd_list_element + *enablelist, *disablelist, + *deletelist, *enablebreaklist; + +extern struct cmd_list_element *cmdlist; + +void +_initialize_breakpoint () +{ + breakpoint_chain = 0; + /* Don't bother to call set_breakpoint_count. $bpnum isn't useful + before a breakpoint is set. */ + breakpoint_count = 0; + + add_com ("ignore", class_breakpoint, ignore_command, + "Set ignore-count of breakpoint number N to COUNT."); + + add_com ("commands", class_breakpoint, commands_command, + "Set commands to be executed when a breakpoint is hit.\n\ +Give breakpoint number as argument after \"commands\".\n\ +With no argument, the targeted breakpoint is the last one set.\n\ +The commands themselves follow starting on the next line.\n\ +Type a line containing \"end\" to indicate the end of them.\n\ +Give \"silent\" as the first line to make the breakpoint silent;\n\ +then no output is printed when it is hit, except what the commands print."); + + add_com ("condition", class_breakpoint, condition_command, + "Specify breakpoint number N to break only if COND is true.\n\ +N is an integer; COND is a C expression to be evaluated whenever\n\ +breakpoint N is reached. Actually break only when COND is nonzero."); + + add_com ("tbreak", class_breakpoint, tbreak_command, + "Set a temporary breakpoint. Args like \"break\" command.\n\ +Like \"break\" except the breakpoint is only enabled temporarily,\n\ +so it will be disabled when hit. Equivalent to \"break\" followed\n\ +by using \"enable once\" on the breakpoint number."); + + add_prefix_cmd ("enable", class_breakpoint, enable_command, + "Enable some breakpoints.\n\ +Give breakpoint numbers (separated by spaces) as arguments.\n\ +With no subcommand, breakpoints are enabled until you command otherwise.\n\ +This is used to cancel the effect of the \"disable\" command.\n\ +With a subcommand you can enable temporarily.", + &enablelist, "enable ", 1, &cmdlist); + + add_abbrev_prefix_cmd ("breakpoints", class_breakpoint, enable_command, + "Enable some breakpoints.\n\ +Give breakpoint numbers (separated by spaces) as arguments.\n\ +This is used to cancel the effect of the \"disable\" command.\n\ +May be abbreviated to simply \"enable\".\n", + &enablebreaklist, "enable breakpoints ", 1, &enablelist); + + add_cmd ("once", no_class, enable_once_command, + "Enable breakpoints for one hit. Give breakpoint numbers.\n\ +If a breakpoint is hit while enabled in this fashion, it becomes disabled.\n\ +See the \"tbreak\" command which sets a breakpoint and enables it once.", + &enablebreaklist); + + add_cmd ("delete", no_class, enable_delete_command, + "Enable breakpoints and delete when hit. Give breakpoint numbers.\n\ +If a breakpoint is hit while enabled in this fashion, it is deleted.", + &enablebreaklist); + + add_cmd ("delete", no_class, enable_delete_command, + "Enable breakpoints and delete when hit. Give breakpoint numbers.\n\ +If a breakpoint is hit while enabled in this fashion, it is deleted.", + &enablelist); + + add_cmd ("once", no_class, enable_once_command, + "Enable breakpoints for one hit. Give breakpoint numbers.\n\ +If a breakpoint is hit while enabled in this fashion, it becomes disabled.\n\ +See the \"tbreak\" command which sets a breakpoint and enables it once.", + &enablelist); + + add_prefix_cmd ("disable", class_breakpoint, disable_command, + "Disable some breakpoints.\n\ +Arguments are breakpoint numbers with spaces in between.\n\ +To disable all breakpoints, give no argument.\n\ +A disabled breakpoint is not forgotten, but has no effect until reenabled.", + &disablelist, "disable ", 1, &cmdlist); + add_com_alias ("dis", "disable", class_breakpoint, 1); + add_com_alias ("disa", "disable", class_breakpoint, 1); + + add_cmd ("breakpoints", class_alias, disable_command, + "Disable some breakpoints.\n\ +Arguments are breakpoint numbers with spaces in between.\n\ +To disable all breakpoints, give no argument.\n\ +A disabled breakpoint is not forgotten, but has no effect until reenabled.\n\ +This command may be abbreviated \"disable\".", + &disablelist); + + add_prefix_cmd ("delete", class_breakpoint, delete_command, + "Delete some breakpoints or auto-display expressions.\n\ +Arguments are breakpoint numbers with spaces in between.\n\ +To delete all breakpoints, give no argument.\n\ +\n\ +Also a prefix command for deletion of other GDB objects.\n\ +The \"unset\" command is also an alias for \"delete\".", + &deletelist, "delete ", 1, &cmdlist); + add_com_alias ("d", "delete", class_breakpoint, 1); + add_com_alias ("unset", "delete", class_alias, 1); + + add_cmd ("breakpoints", class_alias, delete_command, + "Delete some breakpoints or auto-display expressions.\n\ +Arguments are breakpoint numbers with spaces in between.\n\ +To delete all breakpoints, give no argument.\n\ +This command may be abbreviated \"delete\".", + &deletelist); + + add_com ("clear", class_breakpoint, clear_command, + "Clear breakpoint at specified line or function.\n\ +Argument may be line number, function name, or \"*\" and an address.\n\ +If line number is specified, all breakpoints in that line are cleared.\n\ +If function is specified, breakpoints at beginning of function are cleared.\n\ +If an address is specified, breakpoints at that address are cleared.\n\n\ +With no argument, clears all breakpoints in the line that the selected frame\n\ +is executing in.\n\ +\n\ +See also the \"delete\" command which clears breakpoints by number."); + + add_com ("break", class_breakpoint, break_command, + "Set breakpoint at specified line or function.\n\ +Argument may be line number, function name, or \"*\" and an address.\n\ +If line number is specified, break at start of code for that line.\n\ +If function is specified, break at start of code for that function.\n\ +If an address is specified, break at that exact address.\n\ +With no arg, uses current execution address of selected stack frame.\n\ +This is useful for breaking on return to a stack frame.\n\ +\n\ +Multiple breakpoints at one place are permitted, and useful if conditional.\n\ +\n\ +Do \"help breakpoints\" for info on other commands dealing with breakpoints."); + add_com_alias ("b", "break", class_run, 1); + add_com_alias ("br", "break", class_run, 1); + add_com_alias ("bre", "break", class_run, 1); + add_com_alias ("brea", "break", class_run, 1); + + add_info ("breakpoints", breakpoints_info, + "Status of all breakpoints, or breakpoint number NUMBER.\n\ +Second column is \"y\" for enabled breakpoint, \"n\" for disabled,\n\ +\"o\" for enabled once (disable when hit), \"d\" for enable but delete when hit.\n\ +Then come the address and the file/line number.\n\n\ +Convenience variable \"$_\" and default examine address for \"x\"\n\ +are set to the address of the last breakpoint listed.\n\n\ +Convenience variable \"$bpnum\" contains the number of the last\n\ +breakpoint set."); + + add_com ("catch", class_breakpoint, catch_command, + "Set breakpoints to catch exceptions that are raised.\n\ +Argument may be a single exception to catch, multiple exceptions\n\ +to catch, or the default exception \"default\". If no arguments\n\ +are given, breakpoints are set at all exception handlers catch clauses\n\ +within the current scope.\n\ +\n\ +A condition specified for the catch applies to all breakpoints set\n\ +with this command\n\ +\n\ +Do \"help breakpoints\" for info on other commands dealing with breakpoints."); + + add_com ("watch", class_breakpoint, watch_command, + "Set a watchpoint for an expression.\n\ +A watchpoint stops execution of your program whenever the value of\n\ +an expression changes."); + + add_info ("watchpoints", watchpoints_info, + "Status of all watchpoints, or watchpoint number NUMBER.\n\ +Second column is \"y\" for enabled watchpoints, \"n\" for disabled."); +} diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h new file mode 100644 index 00000000000..00ee8c594df --- /dev/null +++ b/gdb/breakpoint.h @@ -0,0 +1,129 @@ +/* Copyright (C) 1990 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#if !defined (BREAKPOINT_H) +#define BREAKPOINT_H 1 + +/* This is the maximum number of bytes a breakpoint instruction can take. + Feel free to increase it. It's just used in a few places to size + arrays that should be independent of the target architecture. */ + +#define BREAKPOINT_MAX 10 + +extern void breakpoint_re_set (); +extern void clear_momentary_breakpoints (); +extern void set_momentary_breakpoint (); +extern void set_ignore_count (); +extern void set_default_breakpoint (); + +extern void mark_breakpoints_out (); +extern void breakpoint_auto_delete (); +extern void breakpoint_clear_ignore_counts (); + +/* The following are for displays, which aren't really breakpoints, but + here is as good a place as any for them. */ + +extern void disable_current_display (); +extern void do_displays (); +extern void disable_display (); +extern void clear_displays (); + + +/* The follow stuff is an abstract data type "bpstat" ("breakpoint status"). + This provides the ability to determine whether we have stopped at a + breakpoint, and what we should do about it. */ + +typedef struct bpstat__struct *bpstat; + +/* Interface: */ + +/* Clear a bpstat so that it says we are not at any breakpoint. + Also free any storage that is part of a bpstat. */ +void bpstat_clear(); + +/* Return a copy of a bpstat. Like "bs1 = bs2" but all storage that + is part of the bpstat is copied as well. */ +bpstat bpstat_copy(); + +/* Get a bpstat associated with having just stopped at address *PC + and frame address FRAME_ADDRESS. Update *PC to point at the + breakpoint (if we hit a breakpoint). */ +bpstat bpstat_stop_status (/* CORE_ADDR *pc; FRAME_ADDR frame_address */); + +/* Nonzero if we should print the frame. */ +#define bpstat_should_print(bs) ((bs) != NULL && (bs)->print) + +/* Nonzero if we should stop. */ +#define bpstat_stop(bs) ((bs) != NULL && (bs)->stop) + +/* Nonzero if we hit a momentary breakpoint. */ +#define bpstat_momentary_breakpoint(bs) ((bs) != NULL && (bs)->momentary) + +/* Nonzero if a signal that we got in wait() was due to circumstances + explained by the BS. */ +/* Currently that is true iff we have hit a breakpoint. */ +#define bpstat_explains_signal(bs) ((bs) != NULL) + +/* Nonzero if we should step constantly (e.g. watchpoints on machines + without hardware support). This isn't related to a specific bpstat, + just to things like whether watchpoints are set. */ +int bpstat_should_step (/* void */); + +/* Print a message indicating what happened. Returns nonzero to + say that only the source line should be printed after this (zero + return means print the frame as well as the source line). */ +int bpstat_print (/* bpstat bs */); + +/* Return the breakpoint number of the first breakpoint we are stopped + at. *BSP upon return is a bpstat which points to the remaining + breakpoints stopped at (but which is not guaranteed to be good for + anything but further calls to bpstat_num). + Return 0 if passed a bpstat which does not indicate any breakpoints. */ +int bpstat_num (/* bpstat *bsp; */); + +/* Perform actions associated with having stopped at *BSP. */ +void bpstat_do_actions (/* bpstat bs; */); + +/* Modify BS so that the actions will not be performed. */ +void bpstat_clear_actions (/* bpstat bs; */); + + +/* Implementation: */ +#include "value.h" +struct bpstat__struct +{ + /* Linked list because there can be two breakpoints at the + same place, and a bpstat reflects the fact that both have been hit. */ + bpstat next; + /* Breakpoint that we are at. */ + struct breakpoint *breakpoint_at; + /* Commands left to be done. */ + struct command_line *commands; + /* Old value associated with a watchpoint. */ + value old_val; + /* Nonzero if we should print the frame. Only significant for the first + bpstat in the chain. */ + char print; + /* Nonzero if we should stop. Only significant for the first bpstat in + the chain. */ + char stop; + /* Nonzero if we hit a momentary breakpoint. Only significant for the + first bpstat in the chain. */ + char momentary; +}; +#endif /* breakpoint.h not already included. */ diff --git a/gdb/coffread.c b/gdb/coffread.c new file mode 100644 index 00000000000..0e6b2c7a37f --- /dev/null +++ b/gdb/coffread.c @@ -0,0 +1,1969 @@ +/* Read coff symbol tables and convert to internal format, for GDB. + Design and support routines derived from dbxread.c, and UMAX COFF + specific routines written 9/1/87 by David D. Johnson, Brown University. + Revised 11/27/87 ddj@cs.brown.edu + Copyright (C) 1987-1991 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#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 +#include +#include + +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}; + + +/* Look up a coff type-number index. Return the address of the slot + where the type for that index is stored. + The type-number is in INDEX. + + This can be used for finding the type associated with that index + or for associating a new type with the index. */ + +static struct type ** +coff_lookup_type (index) + register int index; +{ + if (index >= type_vector_length) + { + int old_vector_length = type_vector_length; + + type_vector_length *= 2; + if (type_vector_length < index) { + type_vector_length = index * 2; + } + type_vector = (struct typevector *) + xrealloc (type_vector, sizeof (struct typevector) + + type_vector_length * sizeof (struct type *)); + bzero (&type_vector->type[ old_vector_length ], + (type_vector_length - old_vector_length) * sizeof(struct type *)); + } + return &type_vector->type[index]; +} + +/* Make sure there is a type allocated for type number index + and return the type object. + This can create an empty (zeroed) type object. */ + +static struct type * +coff_alloc_type (index) + int index; +{ + register struct type **type_addr = coff_lookup_type (index); + register struct type *type = *type_addr; + + /* If we are referring to a type not known at all yet, + allocate an empty type for it. + We will fill it in later if we find out how. */ + if (type == 0) + { + type = (struct type *) obstack_alloc (symbol_obstack, + sizeof (struct type)); + bzero (type, sizeof (struct type)); + *type_addr = type; + } + return type; +} + +/* maintain the lists of symbols and blocks */ + +/* Add a symbol to one of the lists of symbols. */ +static void +add_symbol_to_list (symbol, listhead) + struct symbol *symbol; + struct pending **listhead; +{ + register struct pending *link + = (struct pending *) xmalloc (sizeof (struct pending)); + + link->next = *listhead; + link->symbol = symbol; + *listhead = link; +} + +/* Take one of the lists of symbols and make a block from it. + Put the block on the list of pending blocks. */ + +static void +finish_block (symbol, listhead, old_blocks, start, end) + struct symbol *symbol; + struct pending **listhead; + struct pending_block *old_blocks; + CORE_ADDR start, end; +{ + register struct pending *next, *next1; + register struct block *block; + register struct pending_block *pblock; + struct pending_block *opblock; + register int i; + + /* Count the length of the list of symbols. */ + + for (next = *listhead, i = 0; next; next = next->next, i++); + + block = (struct block *) + obstack_alloc (symbol_obstack, sizeof (struct block) + (i - 1) * sizeof (struct symbol *)); + + /* Copy the symbols into the block. */ + + BLOCK_NSYMS (block) = i; + for (next = *listhead; next; next = next->next) + BLOCK_SYM (block, --i) = next->symbol; + + BLOCK_START (block) = start; + BLOCK_END (block) = end; + BLOCK_SUPERBLOCK (block) = 0; /* Filled in when containing block is made */ + + /* Put the block in as the value of the symbol that names it. */ + + if (symbol) + { + SYMBOL_BLOCK_VALUE (symbol) = block; + BLOCK_FUNCTION (block) = symbol; + } + else + BLOCK_FUNCTION (block) = 0; + + /* Now free the links of the list, and empty the list. */ + + for (next = *listhead; next; next = next1) + { + next1 = next->next; + free (next); + } + *listhead = 0; + + /* Install this block as the superblock + of all blocks made since the start of this scope + that don't have superblocks yet. */ + + opblock = 0; + for (pblock = pending_blocks; pblock != old_blocks; pblock = pblock->next) + { + if (BLOCK_SUPERBLOCK (pblock->block) == 0) + BLOCK_SUPERBLOCK (pblock->block) = block; + opblock = pblock; + } + + /* Record this block on the list of all blocks in the file. + Put it after opblock, or at the beginning if opblock is 0. + This puts the block in the list after all its subblocks. */ + + pblock = (struct pending_block *) xmalloc (sizeof (struct pending_block)); + pblock->block = block; + if (opblock) + { + pblock->next = opblock->next; + opblock->next = pblock; + } + else + { + pblock->next = pending_blocks; + pending_blocks = pblock; + } +} + +static struct blockvector * +make_blockvector () +{ + register struct pending_block *next, *next1; + register struct blockvector *blockvector; + register int i; + + /* Count the length of the list of blocks. */ + + for (next = pending_blocks, i = 0; next; next = next->next, i++); + + blockvector = (struct blockvector *) + obstack_alloc (symbol_obstack, sizeof (struct blockvector) + (i - 1) * sizeof (struct block *)); + + /* Copy the blocks into the blockvector. + This is done in reverse order, which happens to put + the blocks into the proper order (ascending starting address). + finish_block has hair to insert each block into the list + after its subblocks in order to make sure this is true. */ + + BLOCKVECTOR_NBLOCKS (blockvector) = i; + for (next = pending_blocks; next; next = next->next) + BLOCKVECTOR_BLOCK (blockvector, --i) = next->block; + + /* Now free the links of the list, and empty the list. */ + + for (next = pending_blocks; next; next = next1) + { + next1 = next->next; + free (next); + } + pending_blocks = 0; + + return blockvector; +} + +/* Manage the vector of line numbers. */ + +static +record_line (line, pc) + int line; + CORE_ADDR pc; +{ + 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; +} + +/* 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; +} + +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); +} + +/* 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. */ +} + +/* 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); +} + +/* 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; +} + +/* 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); +} + +/* 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); + } +} + +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); + } + } + } + } + } +} + +#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; +} + +/* 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); +} + +/* 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 ", "", ""); + 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 ", "", ""); + 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; +} + +/* 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; +} + +/* Read a definition of an enumeration type, + and create and return a suitable type object. + Also defines the symbols that represent the values of the type. */ + +static struct type * +read_enum_type (index, length, lastsym) + int index; + int length; + int lastsym; +{ + register struct symbol *sym; + register struct type *type; + int nsyms = 0; + int done = 0; + struct pending **symlist; + struct coff_symbol member_sym; + register struct coff_symbol *ms = &member_sym; + SYMENT sub_sym; + AUXENT sub_aux; + struct pending *osyms, *syms; + register int n; + char *name; +#ifdef NAMES_HAVE_UNDERSCORE + int offset = 1; +#else + int offset = 0; +#endif + + type = coff_alloc_type (index); + if (within_function) + symlist = &local_symbols; + else + symlist = &file_symbols; + osyms = *symlist; + + while (!done && symnum < lastsym && symnum < nlist_nsyms_global) + { + read_one_sym (ms, &sub_sym, &sub_aux); + name = ms->c_name; + name = (name[0] == '_' ? name + offset : name); + + switch (ms->c_sclass) + { + case C_MOE: + sym = (struct symbol *) xmalloc (sizeof (struct symbol)); + bzero (sym, sizeof (struct symbol)); + + SYMBOL_NAME (sym) = savestring (name, strlen (name)); + SYMBOL_CLASS (sym) = LOC_CONST; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + SYMBOL_VALUE (sym) = ms->c_value; + add_symbol_to_list (sym, symlist); + nsyms++; + break; + + case C_EOS: + /* Sometimes the linker (on 386/ix 2.0.2 at least) screws + up the count of how many symbols to read. So stop + on .eos. */ + done = 1; + break; + } + } + + /* Now fill in the fields of the type-structure. */ + + TYPE_LENGTH (type) = sizeof (int); + TYPE_CODE (type) = TYPE_CODE_ENUM; + TYPE_NFIELDS (type) = nsyms; + TYPE_FIELDS (type) = (struct field *) + obstack_alloc (symbol_obstack, sizeof (struct field) * nsyms); + + /* Find the symbols for the values and put them into the type. + The symbols can be found in the symlist that we put them on + to cause them to be defined. osyms contains the old value + of that symlist; everything up to there was defined by us. */ + + for (syms = *symlist, n = nsyms; syms != osyms; syms = syms->next) + { + SYMBOL_TYPE (syms->symbol) = type; + TYPE_FIELD_NAME (type, --n) = SYMBOL_NAME (syms->symbol); + TYPE_FIELD_VALUE (type, n) = 0; + TYPE_FIELD_BITPOS (type, n) = SYMBOL_VALUE (syms->symbol); + TYPE_FIELD_BITSIZE (type, n) = 0; + } + return type; +} + +/* Register our ability to parse symbols for coff BFD files */ + +static struct sym_fns coff_sym_fns = +{ + "coff", 4, + coff_new_init, coff_symfile_init, + coff_symfile_read, coff_symfile_discard +}; + +void +_initialize_coffread () +{ + add_symtab_fns(&coff_sym_fns); +} diff --git a/gdb/command.h b/gdb/command.h new file mode 100644 index 00000000000..aa907fd9d1a --- /dev/null +++ b/gdb/command.h @@ -0,0 +1,151 @@ +/* Header file for command-reading library command.c. + Copyright (C) 1986, 1989, 1990 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef _COMMAND_H_INCLUDED +#define _COMMAND_H_INCLUDED + +/* Not a set/show command. Note that some commands which begin with + "set" or "show" might be in this category, if their syntax does + not fall into one of the following categories. */ +typedef enum cmd_types { + not_set_cmd, + set_cmd, + show_cmd, +} cmd_types; + +/* Types of "set" or "show" command. */ +typedef enum var_types { + /* "on" or "off". *VAR is an integer which is nonzero for on, + zero for off. */ + var_boolean, + /* Unsigned Integer. *VAR is an unsigned int. The user can type 0 + to mean "unlimited", which is stored in *VAR as UINT_MAX. */ + var_uinteger, + /* String which the user enters with escapes (e.g. the user types \n and + it is a real newline in the stored string). + *VAR is a malloc'd string, or NULL if the string is empty. */ + var_string, + /* String which stores what the user types verbatim. + *VAR is a malloc'd string, or NULL if the string is empty. */ + var_string_noescape, + /* String which stores a filename. + *VAR is a malloc'd string, or NULL if the string is empty. */ + var_filename, + /* ZeroableInteger. *VAR is an int. Like Unsigned Integer except + that zero really means zero. */ + var_zinteger, +} var_types; + +/* This structure records one command'd definition. */ + +struct cmd_list_element + { + /* Points to next command in this list. */ + struct cmd_list_element *next; + + /* Name of this command. */ + char *name; + + /* Command class; class values are chosen by application program. */ + enum command_class class; + + /* Function definition of this command. + Zero for command class names and for help topics that + are not really commands. */ + void (*function) (); +# define NO_FUNCTION ((void (*)()) 0 ) + + /* Documentation of this command (or help topic). + First line is brief documentation; remaining lines form, with it, + the full documentation. First line should end with a period. + Entire string should also end with a period, not a newline. */ + char *doc; + + /* Auxiliary information. + It is up to the calling program to decide what this means. */ + char *aux; + + /* Nonzero identifies a prefix command. For them, the address + of the variable containing the list of subcommands. */ + struct cmd_list_element **prefixlist; + + /* For prefix commands only: + String containing prefix commands to get here: this one + plus any others needed to get to it. Should end in a space. + It is used before the word "command" in describing the + commands reached through this prefix. */ + char *prefixname; + + /* For prefix commands only: + nonzero means do not get an error if subcommand is not + recognized; call the prefix's own function in that case. */ + char allow_unknown; + + /* Nonzero says this is an abbreviation, and should not + be mentioned in lists of commands. + This allows "br" to complete to "break", which it + otherwise wouldn't. */ + char abbrev_flag; + + /* Completion routine for this command. */ + char **(*completer)(); + + /* Type of "set" or "show" command (or SET_NOT_SET if not "set" + or "show"). */ + cmd_types type; + + /* Pointer to variable affected by "set" and "show". Doesn't matter + if type is not_set. */ + char *var; + + /* What kind of variable is *VAR? */ + var_types var_type; + + /* Pointer to command strings of user-defined commands */ + struct command_line *user_commands; + }; + +/* Forward-declarations of the entry-points of command.c. */ + +extern struct cmd_list_element *add_cmd (); +extern struct cmd_list_element *add_alias_cmd (); +extern struct cmd_list_element *add_prefix_cmd (); +extern struct cmd_list_element *add_abbrev_prefix_cmd (); +extern struct cmd_list_element *lookup_cmd (), *lookup_cmd_1 (); +extern void add_com (); +extern void add_com_alias (); +extern void add_info (); +extern void add_info_alias (); +extern char **complete_on_cmdlist (); +extern void delete_cmd (); +extern void help_cmd (); +extern struct cmd_list_element *add_set_cmd (); +extern struct cmd_list_element *add_show_from_set (); + +/* Do a "set" or "show" command. ARG is NULL if no argument, or the text + of the argument, and FROM_TTY is nonzero if this command is being entered + directly by the user (i.e. these are just like any other + command). C is the command list element for the command. */ +extern void do_setshow_command (); + +/* Do a "show" command for each thing on a command list. */ +extern void cmd_show_list (); + +extern void error_no_arg (); /* Print error for missing argument */ +extern void dont_repeat (); /* Avoid auto-repeat of command */ + +#endif /* _COMMAND_H_INCLUDED */ diff --git a/gdb/copying.awk b/gdb/copying.awk new file mode 100644 index 00000000000..378d62031ec --- /dev/null +++ b/gdb/copying.awk @@ -0,0 +1,55 @@ +BEGIN { + FS="\""; + print "/* Do not modify this file; it is created automatically"; + print " by copying.awk. */"; + print "#include \"defs.h\"" + print "#include \"command.h\"" + print "extern int immediate_quit;"; + print "static void"; + print "copying_info ()"; + print "{"; + print " immediate_quit++;"; + } +NR == 1,/^[ ]*NO WARRANTY[ ]*$/ { + if (! ($0 ~ /^[ ]*NO WARRANTY[ ]*$/)) + { + printf " printf_filtered (\""; + for (i = 1; i < NF; i++) + printf "%s\\\"", $i; + printf "%s\\n\");\n", $NF; + } + } +/^[ ]*NO WARRANTY[ ]*$/ { + print " immediate_quit--;"; + print "}"; + print ""; + print "static void"; + print "warranty_info ()"; + print "{"; + print " immediate_quit++;"; + } +/^[ ]*NO WARRANTY[ ]*$/, /^[ ]*END OF TERMS AND CONDITIONS[ ]*$/{ + if (! ($0 ~ /^[ ]*END OF TERMS AND CONDITIONS[ ]*$/)) + { + printf " printf_filtered (\""; + for (i = 1; i < NF; i++) + printf "%s\\\"", $i; + printf "%s\\n\");\n", $NF; + } + } +END { + print " immediate_quit--;"; + print "}"; + print ""; + print "void" + print "_initialize_copying ()"; + print "{"; + print " add_info (\"copying\", copying_info,"; + print " \"Conditions for redistributing copies of GDB.\");"; + print " add_info (\"warranty\", warranty_info,"; + print " \"Various kinds of warranty you do not have.\");"; + print "}"; + } + + + diff --git a/gdb/copying.c b/gdb/copying.c new file mode 100644 index 00000000000..91648916ae1 --- /dev/null +++ b/gdb/copying.c @@ -0,0 +1,217 @@ +/* Do not modify this file; it is created automatically + by copying.awk. */ +#include "defs.h" +#include "command.h" +extern int immediate_quit; +static void +copying_info () +{ + immediate_quit++; + printf_filtered ("\n"); + printf_filtered (" GNU GENERAL PUBLIC LICENSE\n"); + printf_filtered (" Version 1, February 1989\n"); + printf_filtered ("\n"); + printf_filtered (" Copyright (C) 1989 Free Software Foundation, Inc.\n"); + printf_filtered (" 675 Mass Ave, Cambridge, MA 02139, USA\n"); + printf_filtered (" Everyone is permitted to copy and distribute verbatim copies\n"); + printf_filtered (" of this license document, but changing it is not allowed.\n"); + printf_filtered ("\n"); + printf_filtered (" Preamble\n"); + printf_filtered ("\n"); + printf_filtered (" The license agreements of most software companies try to keep users\n"); + printf_filtered ("at the mercy of those companies. By contrast, our General Public\n"); + printf_filtered ("License is intended to guarantee your freedom to share and change free\n"); + printf_filtered ("software--to make sure the software is free for all its users. The\n"); + printf_filtered ("General Public License applies to the Free Software Foundation's\n"); + printf_filtered ("software and to any other program whose authors commit to using it.\n"); + printf_filtered ("You can use it for your programs, too.\n"); + printf_filtered ("\n"); + printf_filtered (" When we speak of free software, we are referring to freedom, not\n"); + printf_filtered ("price. Specifically, the General Public License is designed to make\n"); + printf_filtered ("sure that you have the freedom to give away or sell copies of free\n"); + printf_filtered ("software, that you receive source code or can get it if you want it,\n"); + printf_filtered ("that you can change the software or use pieces of it in new free\n"); + printf_filtered ("programs; and that you know you can do these things.\n"); + printf_filtered ("\n"); + printf_filtered (" To protect your rights, we need to make restrictions that forbid\n"); + printf_filtered ("anyone to deny you these rights or to ask you to surrender the rights.\n"); + printf_filtered ("These restrictions translate to certain responsibilities for you if you\n"); + printf_filtered ("distribute copies of the software, or if you modify it.\n"); + printf_filtered ("\n"); + printf_filtered (" For example, if you distribute copies of a such a program, whether\n"); + printf_filtered ("gratis or for a fee, you must give the recipients all the rights that\n"); + printf_filtered ("you have. You must make sure that they, too, receive or can get the\n"); + printf_filtered ("source code. And you must tell them their rights.\n"); + printf_filtered ("\n"); + printf_filtered (" We protect your rights with two steps: (1) copyright the software, and\n"); + printf_filtered ("(2) offer you this license which gives you legal permission to copy,\n"); + printf_filtered ("distribute and/or modify the software.\n"); + printf_filtered ("\n"); + printf_filtered (" Also, for each author's protection and ours, we want to make certain\n"); + printf_filtered ("that everyone understands that there is no warranty for this free\n"); + printf_filtered ("software. If the software is modified by someone else and passed on, we\n"); + printf_filtered ("want its recipients to know that what they have is not the original, so\n"); + printf_filtered ("that any problems introduced by others will not reflect on the original\n"); + printf_filtered ("authors' reputations.\n"); + printf_filtered ("\n"); + printf_filtered (" The precise terms and conditions for copying, distribution and\n"); + printf_filtered ("modification follow.\n"); + printf_filtered (" \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 (" \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 (" \n"); + printf_filtered (" 7. The Free Software Foundation may publish revised and/or new versions\n"); + printf_filtered ("of the General Public License from time to time. Such new versions will\n"); + printf_filtered ("be similar in spirit to the present version, but may differ in detail to\n"); + printf_filtered ("address new problems or concerns.\n"); + printf_filtered ("\n"); + printf_filtered ("Each version is given a distinguishing version number. If the Program\n"); + printf_filtered ("specifies a version number of the license which applies to it and \"any\n"); + printf_filtered ("later version\", you have the option of following the terms and conditions\n"); + printf_filtered ("either of that version or of any later version published by the Free\n"); + printf_filtered ("Software Foundation. If the Program does not specify a version number of\n"); + printf_filtered ("the license, you may choose any version ever published by the Free Software\n"); + printf_filtered ("Foundation.\n"); + printf_filtered ("\n"); + printf_filtered (" 8. If you wish to incorporate parts of the Program into other free\n"); + printf_filtered ("programs whose distribution conditions are different, write to the author\n"); + printf_filtered ("to ask for permission. For software which is copyrighted by the Free\n"); + printf_filtered ("Software Foundation, write to the Free Software Foundation; we sometimes\n"); + printf_filtered ("make exceptions for this. Our decision will be guided by the two goals\n"); + printf_filtered ("of preserving the free status of all derivatives of our free software and\n"); + printf_filtered ("of promoting the sharing and reuse of software generally.\n"); + printf_filtered ("\n"); + immediate_quit--; +} + +static void +warranty_info () +{ + immediate_quit++; + printf_filtered (" NO WARRANTY\n"); + printf_filtered ("\n"); + printf_filtered (" 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n"); + printf_filtered ("FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n"); + printf_filtered ("OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n"); + printf_filtered ("PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n"); + printf_filtered ("OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n"); + printf_filtered ("MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n"); + printf_filtered ("TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n"); + printf_filtered ("PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n"); + printf_filtered ("REPAIR OR CORRECTION.\n"); + printf_filtered ("\n"); + printf_filtered (" 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n"); + printf_filtered ("WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n"); + printf_filtered ("REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n"); + printf_filtered ("INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n"); + printf_filtered ("OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n"); + printf_filtered ("TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n"); + printf_filtered ("YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n"); + printf_filtered ("PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n"); + printf_filtered ("POSSIBILITY OF SUCH DAMAGES.\n"); + printf_filtered ("\n"); + immediate_quit--; +} + +void +_initialize_copying () +{ + add_info ("copying", copying_info, + "Conditions for redistributing copies of GDB."); + add_info ("warranty", warranty_info, + "Various kinds of warranty you do not have."); +} diff --git a/gdb/dbxread.c b/gdb/dbxread.c new file mode 100644 index 00000000000..37f456bc74d --- /dev/null +++ b/gdb/dbxread.c @@ -0,0 +1,5348 @@ +/* Read dbx symbol tables and convert to internal format, for GDB. + Copyright (C) 1986-1991 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* 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 +#include +#include "defs.h" +#include "param.h" + +#ifdef USG +#include +#include +#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 + +#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 +#include +#include +#include +#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 + +/* 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}; + +/* 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 + +/* 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; +} + +/* 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; +} + +/* 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; +} + +/* 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; +} + +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); +} + +/* 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; +} + +/* 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 (""); + 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; +} + +/* 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 + ":" ("t" | "T") [ "="] "e" + { ":" ","} ";". */ + + /* 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; +} + +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); +} + +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; +} + + +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); + } +} + +/* 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); + } +} + +/* 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; +} + +/* 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; +} + +/* 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; +} + +#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;lower;upper;". 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 is an unsigned large integral type. */ + if ((n2bits == 0 && n2 == 0) && n3bits != 0) + { + got_unsigned = 1; + nbits = n3bits; + } + /* Range from to -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; +} + +/* 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; + } +} + +/* Register our willingness to decode symbols for SunOS and a.out and + b.out files handled by BFD... */ +static struct sym_fns sunos_sym_fns = {"sunOs", 6, + dbx_new_init, dbx_symfile_init, + dbx_symfile_read, dbx_symfile_discard}; + +static struct sym_fns aout_sym_fns = {"a.out", 5, + dbx_new_init, dbx_symfile_init, + dbx_symfile_read, dbx_symfile_discard}; + +static struct sym_fns bout_sym_fns = {"b.out", 5, + dbx_new_init, dbx_symfile_init, + dbx_symfile_read, dbx_symfile_discard}; + +void +_initialize_dbxread () +{ + add_symtab_fns(&sunos_sym_fns); + add_symtab_fns(&aout_sym_fns); + add_symtab_fns(&bout_sym_fns); + + undef_types_allocated = 20; + undef_types_length = 0; + undef_types = (struct type **) xmalloc (undef_types_allocated * + sizeof (struct type *)); +} diff --git a/gdb/defs.h b/gdb/defs.h new file mode 100644 index 00000000000..51a46b4ccca --- /dev/null +++ b/gdb/defs.h @@ -0,0 +1,173 @@ +/* Basic definitions for GDB, the GNU debugger. + Copyright (C) 1986, 1989, 1991 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* An address in the program being debugged. Host byte order. */ +typedef unsigned int CORE_ADDR; + +#define min(a, b) ((a) < (b) ? (a) : (b)) +#define max(a, b) ((a) > (b) ? (a) : (b)) + +/* The character C++ uses to build identifiers that must be unique from + the program's identifiers (such as $this and $$vptr). */ +#define CPLUS_MARKER '$' /* May be overridden to '.' for SysV */ + +/* + * Allow things in gdb to be declared "const". If compiling ANSI, it + * just works. If compiling with gcc but non-ansi, redefine to __const__. + * If non-ansi, non-gcc, then eliminate "const" entirely, making those + * objects be read-write rather than read-only. + */ +#ifndef __STDC__ +# ifdef __GNUC__ +# define const __const__ +# define volatile __volatile__ +# else +# define const /*nothing*/ +# define volatile /*nothing*/ +# endif /* GNUC */ +#endif /* STDC */ + +extern char *savestring (); +extern char *strsave (); +extern char *concat (); +#ifdef __STDC__ +extern void *xmalloc (), *xrealloc (); +#else +extern char *xmalloc (), *xrealloc (); +#endif +extern void free (); +extern int parse_escape (); +extern char *reg_names[]; +/* Indicate that these routines do not return to the caller. */ +extern volatile void error(), fatal(); + +/* Various possibilities for alloca. */ +#ifdef __GNUC__ +# define alloca __builtin_alloca +#else +# ifdef sparc +# include +# 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 but describes the target machine. */ +#if !defined (TARGET_CHAR_BIT) +#define TARGET_CHAR_BIT 8 +#endif diff --git a/gdb/environ.c b/gdb/environ.c new file mode 100644 index 00000000000..4109472e4ea --- /dev/null +++ b/gdb/environ.c @@ -0,0 +1,187 @@ +/* environ.c -- library for manipulating environments for GNU. + Copyright (C) 1986, 1989 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define min(a, b) ((a) < (b) ? (a) : (b)) +#define max(a, b) ((a) > (b) ? (a) : (b)) + +#include "environ.h" +#include + +extern char *xmalloc (); +extern char *xrealloc (); +extern void free (); + +/* 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; +} + +/* Return the value in environment E of variable VAR. */ + +char * +get_in_environ (e, var) + struct environ *e; + char *var; +{ + register int len = strlen (var); + register char **vector = e->vector; + register char *s; + + for (; s = *vector; vector++) + if (!strncmp (s, var, len) + && s[len] == '=') + return &s[len + 1]; + + return 0; +} + +/* Store the value in E of VAR as VALUE. */ + +void +set_in_environ (e, var, value) + struct environ *e; + char *var; + char *value; +{ + register int i; + register int len = strlen (var); + register char **vector = e->vector; + register char *s; + + for (i = 0; s = vector[i]; i++) + if (!strncmp (s, var, len) + && s[len] == '=') + break; + + if (s == 0) + { + if (i == e->allocated) + { + e->allocated += 10; + vector = (char **) xrealloc ((char *)vector, + (e->allocated + 1) * sizeof (char *)); + e->vector = vector; + } + vector[i + 1] = 0; + } + else + free (s); + + s = (char *) xmalloc (len + strlen (value) + 2); + strcpy (s, var); + strcat (s, "="); + strcat (s, value); + vector[i] = s; + + /* Certain variables get exported back to the parent (e.g. our) + environment, too. */ + if (!strcmp(var, "PATH") /* Object file location */ + || !strcmp (var, "G960BASE") /* Intel 960 downloads */ + || !strcmp (var, "G960BIN") /* Intel 960 downloads */ + ) { + putenv (strsave (s)); + } + return; +} + +/* Remove the setting for variable VAR from environment E. */ + +void +unset_in_environ (e, var) + struct environ *e; + char *var; +{ + register int len = strlen (var); + register char **vector = e->vector; + register char *s; + + for (; s = *vector; vector++) + if (!strncmp (s, var, len) + && s[len] == '=') + { + free (s); + bcopy (vector + 1, vector, + (e->allocated - (vector - e->vector)) * sizeof (char *)); + e->vector[e->allocated - 1] = 0; + return; + } +} diff --git a/gdb/environ.h b/gdb/environ.h new file mode 100644 index 00000000000..13f31f470a5 --- /dev/null +++ b/gdb/environ.h @@ -0,0 +1,39 @@ +/* Header for environment manipulation library. + Copyright (C) 1989, Free Software Foundation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* We manipulate environments represented as these structures. */ + +struct environ +{ + /* Number of usable slots allocated in VECTOR. + VECTOR always has one slot not counted here, + to hold the terminating zero. */ + int allocated; + /* A vector of slots, ALLOCATED + 1 of them. + The first few slots contain strings "VAR=VALUE" + and the next one contains zero. + Then come some unused slots. */ + char **vector; +}; + +struct environ *make_environ (); +void free_environ (); +void init_environ (); +char *get_in_environ (); +void set_in_environ (); +void unset_in_environ (); +char **environ_vector (); diff --git a/gdb/eval.c b/gdb/eval.c new file mode 100644 index 00000000000..0cf5cbf7d60 --- /dev/null +++ b/gdb/eval.c @@ -0,0 +1,1042 @@ +/* Evaluate expressions for GDB. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "defs.h" +#include "param.h" +#include "symtab.h" +#include "value.h" +#include "expression.h" +#include "target.h" + +#define NULL_TYPE ((struct type *)0) + + +/* 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; +} + +/* 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); +} + +/* Evaluate a subexpression of EXP, at index *POS, + and return the address of that subexpression. + Advance *POS over the subexpression. + If the subexpression isn't an lvalue, get an error. + NOSIDE may be EVAL_AVOID_SIDE_EFFECTS; + then only the type of the result need be correct. */ + +static value +evaluate_subexp_for_address (exp, pos, noside) + register struct expression *exp; + register int *pos; + enum noside noside; +{ + enum exp_opcode op; + register int pc; + + pc = (*pos); + op = exp->elts[pc].opcode; + + switch (op) + { + case UNOP_IND: + (*pos)++; + return evaluate_subexp (NULL_TYPE, exp, pos, noside); + + case UNOP_MEMVAL: + (*pos) += 3; + return value_cast (lookup_pointer_type (exp->elts[pc + 1].type), + evaluate_subexp (NULL_TYPE, exp, pos, noside)); + + case OP_VAR_VALUE: + (*pos) += 3; + if (noside == EVAL_AVOID_SIDE_EFFECTS) + { + struct type *type = + lookup_pointer_type (SYMBOL_TYPE (exp->elts[pc + 1].symbol)); + enum address_class sym_class = + SYMBOL_CLASS (exp->elts[pc + 1].symbol); + + if (sym_class == LOC_CONST + || sym_class == LOC_CONST_BYTES + || sym_class == LOC_REGISTER + || sym_class == LOC_REGPARM) + error ("Attempt to take address of register or constant."); + + return + value_zero (type, not_lval); + } + else + return locate_var_value (exp->elts[pc + 1].symbol, (CORE_ADDR) 0); + + default: + if (noside == EVAL_AVOID_SIDE_EFFECTS) + { + value x = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (VALUE_LVAL (x) == lval_memory) + return value_zero (TYPE_POINTER_TYPE (VALUE_TYPE (x)), + not_lval); + else + error ("Attempt to take address of non-lval"); + } + return value_addr (evaluate_subexp (NULL_TYPE, exp, pos, noside)); + } +} + +/* Evaluate like `evaluate_subexp' except coercing arrays to pointers. + When used in contexts where arrays will be coerced anyway, + this is equivalent to `evaluate_subexp' + but much faster because it avoids actually fetching array contents. */ + +static value +evaluate_subexp_with_coercion (exp, pos, noside) + register struct expression *exp; + register int *pos; + enum noside noside; +{ + register enum exp_opcode op; + register int pc; + register value val; + + pc = (*pos); + op = exp->elts[pc].opcode; + + switch (op) + { + case OP_VAR_VALUE: + if (TYPE_CODE (SYMBOL_TYPE (exp->elts[pc + 1].symbol)) == TYPE_CODE_ARRAY) + { + (*pos) += 3; + val = locate_var_value (exp->elts[pc + 1].symbol, (CORE_ADDR) 0); + return value_cast (lookup_pointer_type (TYPE_TARGET_TYPE (SYMBOL_TYPE (exp->elts[pc + 1].symbol))), + val); + } + default: + return evaluate_subexp (NULL_TYPE, exp, pos, noside); + } +} + +/* Evaluate a subexpression of EXP, at index *POS, + and return a value for the size of that subexpression. + Advance *POS over the subexpression. */ + +static value +evaluate_subexp_for_sizeof (exp, pos) + register struct expression *exp; + register int *pos; +{ + enum exp_opcode op; + register int pc; + value val; + + pc = (*pos); + op = exp->elts[pc].opcode; + + switch (op) + { + /* This case is handled specially + so that we avoid creating a value for the result type. + If the result type is very big, it's desirable not to + create a value unnecessarily. */ + case UNOP_IND: + (*pos)++; + val = evaluate_subexp (NULL_TYPE, exp, pos, EVAL_AVOID_SIDE_EFFECTS); + return value_from_long (builtin_type_int, (LONGEST) + TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (val)))); + + case UNOP_MEMVAL: + (*pos) += 3; + return value_from_long (builtin_type_int, + (LONGEST) TYPE_LENGTH (exp->elts[pc + 1].type)); + + case OP_VAR_VALUE: + (*pos) += 3; + return value_from_long (builtin_type_int, + (LONGEST) TYPE_LENGTH (SYMBOL_TYPE (exp->elts[pc + 1].symbol))); + + default: + val = evaluate_subexp (NULL_TYPE, exp, pos, EVAL_AVOID_SIDE_EFFECTS); + return value_from_long (builtin_type_int, + (LONGEST) TYPE_LENGTH (VALUE_TYPE (val))); + } +} diff --git a/gdb/exec.c b/gdb/exec.c new file mode 100644 index 00000000000..eefe77223ac --- /dev/null +++ b/gdb/exec.c @@ -0,0 +1,350 @@ +/* Work with executable files, for GDB. + Copyright (C) 1988, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" +#include "target.h" + +#ifdef USG +#include +#endif + +#include +#include + +#include "gdbcore.h" + +#ifdef STILL_NEEDED_FOR_DECSTATION +#include /* For DECstations */ +#include /* After a.out.h */ +#include +#endif + +#include + +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); +} + + +/* 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; +} + +/* 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 + +static void +exec_files_info () +{ + struct section_table *p; + + printf ("\tExecutable file `%s'.\n", bfd_get_filename(exec_bfd)); + + for (p = exec_sections; p < exec_sections_end; p++) + printf("\texecutable from 0x%08x to 0x%08x is %s\n", + p->addr, p->endaddr, + bfd_section_name (exec_bfd, p->sec_ptr)); +} + +struct target_ops exec_ops = { + "exec", "Local exec file", + exec_file_command, exec_close, /* open, close */ + child_attach, 0, 0, 0, /* attach, detach, resume, wait, */ + 0, 0, /* fetch_registers, store_registers, */ + 0, 0, 0, /* prepare_to_store, conv_to, conv_from, */ + exec_xfer_memory, exec_files_info, + 0, 0, /* insert_breakpoint, remove_breakpoint, */ + 0, 0, 0, 0, 0, /* terminal stuff */ + 0, 0, 0, 0, 0, /* kill, load, add_syms, call fn, lookup sym */ + child_create_inferior, + 0, /* mourn_inferior */ + file_stratum, 0, /* next */ + 0, 1, 0, 0, 0, /* all mem, mem, stack, regs, exec */ + OPS_MAGIC, /* Always the last thing */ +}; + +void +_initialize_exec() +{ + + add_com ("file", class_files, file_command, + "Use FILE as program to be debugged.\n\ +It is read for its symbols, for getting the contents of pure memory,\n\ +and it is the program executed when you use the `run' command.\n\ +If FILE cannot be found as specified, your execution directory path\n\ +($PATH) is searched for a command of that name.\n\ +No arg means to have no executable file and no symbols."); + + add_com ("exec-file", class_files, exec_file_command, + "Use FILE as program for getting contents of pure memory.\n\ +If FILE cannot be found as specified, your execution directory path\n\ +is searched for a command of that name.\n\ +No arg means have no executable file."); + + add_target (&exec_ops); +} diff --git a/gdb/expprint.c b/gdb/expprint.c new file mode 100644 index 00000000000..9e1e9d20294 --- /dev/null +++ b/gdb/expprint.c @@ -0,0 +1,324 @@ +/* Print in infix form a struct expression. + Copyright (C) 1986, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include "defs.h" +#include "symtab.h" +#include "param.h" +#include "expression.h" +#include "value.h" + + +/* 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}, + }; + +static void print_subexp (); + +void +print_expression (exp, stream) + struct expression *exp; + FILE *stream; +{ + int pc = 0; + print_subexp (exp, &pc, stream, PREC_NULL); +} + +/* Print the subexpression of EXP that starts in position POS, on STREAM. + PREC is the precedence of the surrounding operator; + if the precedence of the main operator of this subexpression is less, + parentheses are needed here. */ + +static void +print_subexp (exp, pos, stream, prec) + register struct expression *exp; + register int *pos; + FILE *stream; + enum precedence prec; +{ + register unsigned tem; + register int pc; + unsigned nargs; + register char *op_str; + int assign_modify = 0; + enum exp_opcode opcode; + enum precedence myprec; + /* Set to 1 for a right-associative operator. */ + int assoc; + + pc = (*pos)++; + opcode = exp->elts[pc].opcode; + switch (opcode) + { + case OP_SCOPE: + myprec = PREC_PREFIX; + assoc = 0; + (*pos) += 2; + print_subexp (exp, pos, stream, (int) myprec + assoc); + fprintf (stream, " :: "); + nargs = strlen (&exp->elts[pc + 2].string); + (*pos) += 1 + (nargs + sizeof (union exp_element)) / sizeof (union exp_element); + + fprintf (stream, &exp->elts[pc + 2].string); + return; + + case OP_LONG: + (*pos) += 3; + value_print (value_from_long (exp->elts[pc + 1].type, + exp->elts[pc + 2].longconst), + stream, 0, Val_no_prettyprint); + return; + + case OP_DOUBLE: + (*pos) += 3; + value_print (value_from_double (exp->elts[pc + 1].type, + exp->elts[pc + 2].doubleconst), + stream, 0, Val_no_prettyprint); + return; + + case OP_VAR_VALUE: + (*pos) += 2; + fprintf (stream, "%s", SYMBOL_NAME (exp->elts[pc + 1].symbol)); + return; + + case OP_LAST: + (*pos) += 2; + fprintf (stream, "$%d", (int) exp->elts[pc + 1].longconst); + return; + + case OP_REGISTER: + (*pos) += 2; + fprintf (stream, "$%s", reg_names[exp->elts[pc + 1].longconst]); + return; + + case OP_INTERNALVAR: + (*pos) += 2; + fprintf (stream, "$%s", + internalvar_name (exp->elts[pc + 1].internalvar)); + return; + + case OP_FUNCALL: + (*pos) += 2; + nargs = exp->elts[pc + 1].longconst; + print_subexp (exp, pos, stream, PREC_SUFFIX); + fprintf (stream, " ("); + for (tem = 0; tem < nargs; tem++) + { + if (tem != 0) + fprintf (stream, ", "); + print_subexp (exp, pos, stream, PREC_ABOVE_COMMA); + } + fprintf (stream, ")"); + return; + + case OP_STRING: + nargs = strlen (&exp->elts[pc + 1].string); + (*pos) += 2 + (nargs + sizeof (union exp_element)) / sizeof (union exp_element); + fprintf (stream, "\""); + for (tem = 0; tem < nargs; tem++) + printchar ((&exp->elts[pc + 1].string)[tem], stream, '"'); + fprintf (stream, "\""); + return; + + case TERNOP_COND: + if ((int) prec > (int) PREC_COMMA) + fprintf (stream, "("); + /* Print the subexpressions, forcing parentheses + around any binary operations within them. + This is more parentheses than are strictly necessary, + but it looks clearer. */ + print_subexp (exp, pos, stream, PREC_HYPER); + fprintf (stream, " ? "); + print_subexp (exp, pos, stream, PREC_HYPER); + fprintf (stream, " : "); + print_subexp (exp, pos, stream, PREC_HYPER); + if ((int) prec > (int) PREC_COMMA) + fprintf (stream, ")"); + return; + + case STRUCTOP_STRUCT: + tem = strlen (&exp->elts[pc + 1].string); + (*pos) += 2 + (tem + sizeof (union exp_element)) / sizeof (union exp_element); + print_subexp (exp, pos, stream, PREC_SUFFIX); + fprintf (stream, ".%s", &exp->elts[pc + 1].string); + return; + + case STRUCTOP_PTR: + tem = strlen (&exp->elts[pc + 1].string); + (*pos) += 2 + (tem + sizeof (union exp_element)) / sizeof (union exp_element); + print_subexp (exp, pos, stream, PREC_SUFFIX); + fprintf (stream, "->%s", &exp->elts[pc + 1].string); + return; + + case BINOP_SUBSCRIPT: + print_subexp (exp, pos, stream, PREC_SUFFIX); + fprintf (stream, "["); + print_subexp (exp, pos, stream, PREC_ABOVE_COMMA); + fprintf (stream, "]"); + return; + + case UNOP_POSTINCREMENT: + print_subexp (exp, pos, stream, PREC_SUFFIX); + fprintf (stream, "++"); + return; + + case UNOP_POSTDECREMENT: + print_subexp (exp, pos, stream, PREC_SUFFIX); + fprintf (stream, "--"); + return; + + case UNOP_CAST: + (*pos) += 2; + if ((int) prec > (int) PREC_PREFIX) + fprintf (stream, "("); + fprintf (stream, "("); + type_print (exp->elts[pc + 1].type, "", stream, 0); + fprintf (stream, ") "); + print_subexp (exp, pos, stream, PREC_PREFIX); + if ((int) prec > (int) PREC_PREFIX) + fprintf (stream, ")"); + return; + + case UNOP_MEMVAL: + (*pos) += 2; + if ((int) prec > (int) PREC_PREFIX) + fprintf (stream, "("); + fprintf (stream, "{"); + type_print (exp->elts[pc + 1].type, "", stream, 0); + fprintf (stream, "} "); + print_subexp (exp, pos, stream, PREC_PREFIX); + if ((int) prec > (int) PREC_PREFIX) + fprintf (stream, ")"); + return; + + case BINOP_ASSIGN_MODIFY: + opcode = exp->elts[pc + 1].opcode; + (*pos) += 2; + myprec = PREC_ASSIGN; + assoc = 1; + assign_modify = 1; + for (tem = 0; tem < sizeof op_print_tab / sizeof op_print_tab[0]; tem++) + if (op_print_tab[tem].opcode == opcode) + { + op_str = op_print_tab[tem].string; + break; + } + + case OP_THIS: + ++(*pos); + fprintf (stream, "this"); + return; + + default: + for (tem = 0; tem < sizeof op_print_tab / sizeof op_print_tab[0]; tem++) + if (op_print_tab[tem].opcode == opcode) + { + op_str = op_print_tab[tem].string; + myprec = op_print_tab[tem].precedence; + assoc = op_print_tab[tem].right_assoc; + break; + } + } + + if ((int) myprec < (int) prec) + fprintf (stream, "("); + if ((int) opcode > (int) BINOP_END) + { + /* Unary prefix operator. */ + fprintf (stream, "%s", op_str); + print_subexp (exp, pos, stream, PREC_PREFIX); + } + else + { + /* Binary operator. */ + /* Print left operand. + If operator is right-associative, + increment precedence for this operand. */ + print_subexp (exp, pos, stream, (int) myprec + assoc); + /* Print the operator itself. */ + if (assign_modify) + fprintf (stream, " %s= ", op_str); + else if (op_str[0] == ',') + fprintf (stream, "%s ", op_str); + else + fprintf (stream, " %s ", op_str); + /* Print right operand. + If operator is left-associative, + increment precedence for this operand. */ + print_subexp (exp, pos, stream, (int) myprec + !assoc); + } + if ((int) myprec < (int) prec) + fprintf (stream, ")"); +} diff --git a/gdb/expression.h b/gdb/expression.h new file mode 100644 index 00000000000..b7a6fff4794 --- /dev/null +++ b/gdb/expression.h @@ -0,0 +1,200 @@ +/* Definitions for expressions stored in reversed prefix form, for GDB. + Copyright (C) 1986, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Definitions for saved C expressions. */ + +/* An expression is represented as a vector of union exp_element's. + Each exp_element is an opcode, except that some opcodes cause + the following exp_element to be treated as a long or double constant + or as a variable. The opcodes are obeyed, using a stack for temporaries. + The value is left on the temporary stack at the end. */ + +/* When it is necessary to include a string, + it can occupy as many exp_elements as it needs. + We find the length of the string using strlen, + divide to find out how many exp_elements are used up, + and skip that many. Strings, like numbers, are indicated + by the preceding opcode. */ + +enum exp_opcode +{ +/* BINOP_... operate on two values computed by following subexpressions, + replacing them by one result value. They take no immediate arguments. */ + BINOP_ADD, /* + */ + BINOP_SUB, /* - */ + BINOP_MUL, /* * */ + BINOP_DIV, /* / */ + BINOP_REM, /* % */ + BINOP_LSH, /* << */ + BINOP_RSH, /* >> */ + BINOP_AND, /* && */ + BINOP_OR, /* || */ + BINOP_LOGAND, /* & */ + BINOP_LOGIOR, /* | */ + BINOP_LOGXOR, /* ^ */ + BINOP_EQUAL, /* == */ + BINOP_NOTEQUAL, /* != */ + BINOP_LESS, /* < */ + BINOP_GTR, /* > */ + BINOP_LEQ, /* <= */ + BINOP_GEQ, /* >= */ + BINOP_REPEAT, /* @ */ + BINOP_ASSIGN, /* = */ + BINOP_COMMA, /* , */ + BINOP_SUBSCRIPT, /* x[y] */ + BINOP_EXP, /* Exponentiation */ + +/* C++. */ + BINOP_MIN, /* ? */ + BINOP_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_, then look at it. */ +extern struct block *innermost_block; + +/* From expprint.c. */ +void print_expression (); diff --git a/gdb/findvar.c b/gdb/findvar.c new file mode 100644 index 00000000000..c674a548961 --- /dev/null +++ b/gdb/findvar.c @@ -0,0 +1,684 @@ +/* Find a variable's value in memory, for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#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; +} + +/* 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)); +} + +/* 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; +} + +/* Given a struct symbol for a variable, + and a stack frame id, + return a (pointer to a) struct value containing the variable's address. */ + +value +locate_var_value (var, frame) + register struct symbol *var; + FRAME frame; +{ + CORE_ADDR addr = 0; + struct type *type = SYMBOL_TYPE (var); + struct type *result_type; + value lazy_value; + + /* Evaluate it first; if the result is a memory address, we're fine. + Lazy evaluation pays off here. */ + + lazy_value = read_var_value (var, frame); + if (lazy_value == 0) + error ("Address of \"%s\" is unknown.", SYMBOL_NAME (var)); + + if (VALUE_LAZY (lazy_value)) + { + addr = VALUE_ADDRESS (lazy_value); + + /* C++: The "address" of a reference should yield the address + * of the object pointed to. So force an extra de-reference. */ + + if (TYPE_CODE (type) == TYPE_CODE_REF) + { + char *buf = alloca (TYPE_LENGTH (type)); + read_memory (addr, buf, TYPE_LENGTH (type)); + addr = unpack_long (type, buf); + type = TYPE_TARGET_TYPE (type); + } + + /* Address of an array is of the type of address of it's elements. */ + result_type = + lookup_pointer_type (TYPE_CODE (type) == TYPE_CODE_ARRAY ? + TYPE_TARGET_TYPE (type) : type); + + return value_cast (result_type, + value_from_long (builtin_type_long, (LONGEST) addr)); + } + + /* Not a memory address; check what the problem was. */ + switch (VALUE_LVAL (lazy_value)) + { + case lval_register: + case lval_reg_frame_relative: + error ("Address requested for identifier \"%s\" which is in a register.", + SYMBOL_NAME (var)); + break; + + default: + error ("Can't take address of \"%s\" which isn't an lvalue.", + SYMBOL_NAME (var)); + break; + } + return 0; /* For lint -- never reached */ +} diff --git a/gdb/frame.h b/gdb/frame.h new file mode 100644 index 00000000000..5c98c9c7baf --- /dev/null +++ b/gdb/frame.h @@ -0,0 +1,128 @@ +/* Definitions for dealing with stack frames, for GDB, the GNU debugger. + Copyright (C) 1986, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#if !defined (FRAME_H) +#define FRAME_H 1 +#include "param.h" + +/* + * FRAME is the type of the identifier of a specific stack frame. It + * is a pointer to the frame cache item corresponding to this frame. + * Please note that frame id's are *not* constant over calls to the + * inferior. Use frame addresses, which are. + * + * FRAME_ADDR is the type of the address of a specific frame. I + * cannot imagine a case in which this would not be CORE_ADDR, so + * maybe it's silly to give it it's own type. Life's rough. + * + * FRAME_FP is a macro which converts from a frame identifier into a + * frame_address. + * + * FRAME_INFO_ID is a macro which "converts" from a frame info pointer + * to a frame id. This is here in case I or someone else decides to + * change the FRAME type again. + * + * This file and blockframe.c are the only places which are allowed to + * use the equivalence between FRAME and struct frame_info *. EXCEPTION: + * value.h uses CORE_ADDR instead of FRAME_ADDR because the compiler + * will accept that in the absense of this file. + */ +typedef struct frame_info *FRAME; +typedef CORE_ADDR FRAME_ADDR; +#define FRAME_FP(fr) ((fr)->frame) +#define FRAME_INFO_ID(f) (f) + +/* + * Caching structure for stack frames. This is also the structure + * used for extended info about stack frames. May add more to this + * structure as it becomes necessary. + * + * Note that the first entry in the cache will always refer to the + * innermost executing frame. This value should be set (is it? + * Check) in something like normal_stop. + */ +struct frame_info + { + /* Nominal address of the frame described. */ + FRAME_ADDR frame; + /* Address at which execution is occurring in this frame. + For the innermost frame, it's the current pc. + For other frames, it is a pc saved in the next frame. */ + CORE_ADDR pc; + /* The frame called by the frame we are describing, or 0. + This may be set even if there isn't a frame called by the one + we are describing (.->next == 0); in that case it is simply the + bottom of this frame */ + FRAME_ADDR next_frame; + /* Anything extra for this structure that may have been defined + in the machine depedent files. */ +#ifdef EXTRA_FRAME_INFO + EXTRA_FRAME_INFO +#endif + /* Pointers to the next and previous frame_info's in this stack. */ + FRAME next, prev; + }; + +/* Describe the saved registers of a frame. */ + +struct frame_saved_regs + { + /* For each register, address of where it was saved on entry to the frame, + or zero if it was not saved on entry to this frame. */ + CORE_ADDR regs[NUM_REGS]; + }; + +/* The stack frame that the user has specified for commands to act on. + Note that one cannot assume this is the address of valid data. */ + +extern FRAME selected_frame; + +extern struct frame_info *get_frame_info (); +extern struct frame_info *get_prev_frame_info (); + +extern FRAME create_new_frame (); +extern void flush_cached_frames (); + +extern void get_frame_saved_regs (); + +extern void set_current_frame (); +extern FRAME get_prev_frame (); +extern FRAME get_current_frame (); +extern FRAME get_next_frame (); + +extern struct block *get_frame_block (); +extern struct block *get_current_block (); +extern struct block *get_selected_block (); +extern struct symbol *get_frame_function (); +extern CORE_ADDR get_frame_pc (); +extern CORE_ADDR get_pc_function_start (); +struct block *block_for_pc (); + +int frameless_look_for_prologue (); + +void print_frame_args (); + +/* In stack.c */ +extern FRAME find_relative_frame (); +extern void print_selected_frame (); +extern void print_sel_frame (); +extern void select_frame (); +extern void record_selected_frame (); + +#endif /* frame.h not already included. */ diff --git a/gdb/gdb-int.texinfo b/gdb/gdb-int.texinfo new file mode 100755 index 00000000000..cc1b1880e2b --- /dev/null +++ b/gdb/gdb-int.texinfo @@ -0,0 +1,242 @@ +\input texinfo +@setfilename gdb-internals +@ifinfo +This file documents the internals of the GNU debugger GDB. + +Copyright (C) 1990, 1991 Free Software Foundation, Inc. +Contributed by Cygnus Support. Written by John Gilmore. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +@ignore +Permission is granted to process this file through Tex and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). + +@end ignore +Permission is granted to copy or distribute modified versions of this +manual under the terms of the GPL (for which purpose this text may be +regarded as a program in the language TeX). +@end ifinfo + +@setchapternewpage odd +@settitle GDB Internals +@titlepage +@title{Working in GDB} +@subtitle{A guide to the internals of the GNU debugger} +@author John Gilmore +@author Cygnus Support +@page +@tex +\def\$#1${{#1}} % Kluge: collect RCS revision info without $...$ +\xdef\manvers{\$Revision$} % For use in headers, footers too +{\parskip=0pt +\hfill Cygnus Support\par +\hfill \manvers\par +\hfill \TeX{}info \texinfoversion\par +} +@end tex + +@vskip 0pt plus 1filll +Copyright @copyright{} 1990, 1991 Free Software Foundation, Inc. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +@end titlepage + +@node Top, Cleanups, (dir), (dir) + +@menu +* Cleanups:: Cleanups +* Wrapping:: Wrapping output lines +* Releases:: Configuring GDB for release +* README:: The README file +* New Architectures:: Defining a new host or target architecture +* Host versus Targt:: What features are in which files + +@end menu + +@node Cleanups, Wrapping, Top, Top +@chapter Cleanups + +Cleanups are a structured way to deal with things that need to be done +later. When your code does something (like malloc some memory, or open +a file) that needs to be undone later (e.g. free the memory or close +the file), it can make a cleanup. The cleanup will be done at some +future point: when the command is finished, when an error occurs, or +when your code decides it's time to do cleanups. + +You can also discard cleanups, that is, throw them away without doing +what they say. This is only done if you ask that it be done. + +Syntax: + +@table @code +@item old_chain = make_cleanup (function, arg); +This makes a cleanup which will cause FUNCTION to be called with ARG +(a char *) later. The result, OLD_CHAIN, is a handle that can be +passed to do_cleanups or discard_cleanups later. Unless you are +going to call do_cleanups or discard_cleanups yourself, +you can ignore the result from make_cleanup. + + +@item do_cleanups (old_chain); +Performs all cleanups done since make_cleanup returned OLD_CHAIN. +E.g.: make_cleanup (a, 0); old = make_cleanup (b, 0); do_cleanups (old); +will call b() but will not call a(). The cleanup that calls a() will remain +in the cleanup chain, and will be done later unless otherwise discarded. + +@item discard_cleanups (old_chain); +Same as do_cleanups except that it just removes the cleanups from the +chain and does not call the specified functions. + +@end table + +Some functions, e.g. @code{fputs_filtered()} or @code{error()}, specify that they +``should not be called when cleanups are not in place''. This means +that any actions you need to reverse in the case of an error or +interruption must be on the cleanup chain before you call these functions, +since they might never return to your code (they @samp{longjmp} instead). + + +@node Wrapping, Releases, Cleanups, Top +@chapter Wrapping output lines + +Output that goes through printf_filtered or fputs_filtered or +fputs_demangled needs only to have calls to wrap_here() added +in places that would be good breaking points. The utility routines +will take care of actually wrapping if the line width is exceeded. + +The argument to wrap_here() is an indentation string which is printed +ONLY if the line breaks there. This argument is saved away and used +later. It must remain valid until the next call to wrap_here() or +until a newline has been printed through the *_filtered functions. +Don't pass in a local variable and then return! + +It is usually best to call wrap_here() after printing a comma or space. +If you call it before printing a space, make sure that your indentation +properly accounts for the leading space that will print if the line wraps +there. + +Any function or set of functions that produce filtered output must finish +by printing a newline, to flush the wrap buffer, before switching to +unfiltered ("printf") output. Symbol reading routines that print +warnings are a good example. + + +@node Releases, README, Wrapping, Top +@chapter Configuring GDB for release + + +GDB should be released after doing @samp{config.gdb none} in the top level +directory. This will leave a makefile there, but no tm- or xm- files. +The makefile is needed, for example, for @samp{make gdb.tar.Z}@dots{} If you +have tm- or xm-files in the main source directory, C's include rules +cause them to be used in preference to tm- and xm-files in the +subdirectories where the user will actually configure and build the +binaries. + +@samp{config.gdb none} is also a good way to rebuild the top level Makefile +after changing Makefile.dist, alldeps.mak, etc. + + + +@node README, New Architectures, Releases, Top +@chapter The README file + + +Check the README file, it often has useful information that does not +appear anywhere else in the directory. + + + +@node New Architectures, Host versus Target, README, Top +@chapter Defining a new host or target architecture + + +When building support for a new host and/or target, this will help you +organize where to put the various parts. @var{ARCH} stands for the +architecture involved. + +Object files needed when the host system is an @var{ARCH} are listed in +the file @file{xconfig/@var{ARCH}}, in the Makefile macro @samp{XDEPFILES += }@dots{}. You can also define XXXXXX in there. + +There are some ``generic'' versions of routines that can be used by +various host systems. If these routines work for the @var{ARCH} host, +you can just include the generic file's name (with .o, not .c) in +@code{XDEPFILES}. Otherwise, you will need to write routines that +perform the same functions as the generic file, put them into +@code{@var{ARCH}-xdep.c}, and put @code{@var{ARCH}-xdep.o} into +@code{XDEPFILES}. These generic host support files include: + +@example + coredep.c, coredep.o +@end example + +@table @code +@item fetch_core_registers() +Support for reading registers out of a core file. This routine calls +@code{register_addr(}), see below. + +@item register_addr() +If your @code{xm-@var{ARCH}.h} file defines the macro @code{REGISTER_U_ADDR(reg)} to be the +offset within the @samp{user} struct of a register (represented as a GDB +register number), @file{coredep.c} will define the @code{register_addr()} function +and use the macro in it. If you do not define @code{REGISTER_U_ADDR}, but +you are using the standard @code{fetch_core_registers}, you +will need to define your own version of @code{register_addr}, put it into +your @code{@var{ARCH}-xdep.c} file, and be sure @code{@var{ARCH}-xdep.o} is in the @code{XDEPFILES} list. +If you have your own @code{fetch_core_registers}, you only need to define +@code{register_addr} if your @code{fetch_core_registers} calls it. Many custom +@code{fetch_core_registers} implementations simply locate the registers +themselves. +@end table + +Files needed when the target system is an @var{ARCH} are listed in the file +@file{tconfig/@var{ARCH}}, in the @code{Makefile} macro @samp{TDEPFILES = }@dots{}. You can also +define XXXXXX in there. + +Similar generic support files for target systems are: + +@example + exec.c, exec.o: +@end example + +This file defines functions for accessing files that are executable +on the target system. These functions open and examine an exec file, +extract data from one, write data to one, print information about one, +etc. Now that executable files are handled with BFD, every architecture +should be able to use the generic exec.c rather than its own custom code. + +@node Host versus Target, , README, Top +@chapter What is considered ``host-dependent'' versus ``target-dependent''? + +The xconfig/*, xm-*.h and *-xdep.c files are for host support. The +question is, what features or aspects of a debugging or cross-debugging +environment are considered to be ``host'' support. + +Defines and include files needed to build on the host are host support. +Examples are tty support, system defined types, host byte order, host +float format. + +Unix child process support is considered an aspect of the host. Since +when you fork on the host you are still on the host, the various macros +needed for finding the registers in the upage, running ptrace, and such +are all in the host-dependent files. + +This is still somewhat of a grey area; I (John Gilmore) didn't do the +xm- and tm- split for gdb (it was done by Jim Kingdon) so I have had to +figure out the grounds on which it was split, and make my own choices +as I evolve it. I have moved many things out of the xdep files +actually, partly as a result of BFD and partly by removing duplicated +code. + +@contents +@bye + diff --git a/gdb/gdbcmd.h b/gdb/gdbcmd.h new file mode 100644 index 00000000000..39151f575df --- /dev/null +++ b/gdb/gdbcmd.h @@ -0,0 +1,63 @@ +/* Header file for GDB-specific command-line stuff. + Copyright (C) 1986, 1989, 1990 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "command.h" + +/* Chain containing all defined commands. */ + +extern struct cmd_list_element *cmdlist; + +/* Chain containing all defined info subcommands. */ + +extern struct cmd_list_element *infolist; + +/* Chain containing all defined enable subcommands. */ + +extern struct cmd_list_element *enablelist; + +/* Chain containing all defined disable subcommands. */ + +extern struct cmd_list_element *disablelist; + +/* Chain containing all defined delete subcommands. */ + +extern struct cmd_list_element *deletelist; + +/* Chain containing all defined "enable breakpoint" subcommands. */ + +extern struct cmd_list_element *enablebreaklist; + +/* Chain containing all defined set subcommands */ + +extern struct cmd_list_element *setlist; + +/* Chain containing all defined show subcommands. */ +extern struct cmd_list_element *showlist; + +/* Chain containing all defined \"set history\". */ + +extern struct cmd_list_element *sethistlist; + +/* Chain containing all defined \"show history\". */ +extern struct cmd_list_element *showhistlist; + +/* Chain containing all defined \"unset history\". */ + +extern struct cmd_list_element *unsethistlist; + +void execute_command (); +char **noop_completer (); diff --git a/gdb/gdbcore.h b/gdb/gdbcore.h new file mode 100644 index 00000000000..991ce64ebdb --- /dev/null +++ b/gdb/gdbcore.h @@ -0,0 +1,82 @@ +/* Machine independent variables that describe the core file under GDB. + Copyright (C) 1986, 1987, 1989, 1990 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Interface routines for core, executable, etc. */ + +#include "bfd.h" /* Binary File Description */ + +/* Return the name of the executable file as a string. + ERR nonzero means get error if there is none specified; + otherwise return 0 in that case. */ +char *get_exec_file (); + +/* Nonzero if there is a core file. */ +int have_core_file_p (); + +/* Read "memory data" from whatever target or inferior we have. + Returns zero if successful, errno value if not. EIO is used + for address out of bounds. If breakpoints are inserted, returns + shadow contents, not the breakpoints themselves. From breakpoint.c. */ +int read_memory_nobpt (); + +/* Report a memory error with error(). */ + +void memory_error (); + +/* Like target_read_memory, but report an error if can't read. */ +void read_memory (); + +/* Read an integer from debugged memory, given address and number of bytes. */ +long read_memory_integer (); + +/* Hook for `exec_file_command' command to call. */ + +extern void (*exec_file_display_hook) (); + +/* Binary File Diddlers for the exec and core files */ +extern bfd *core_bfd; +extern bfd *exec_bfd; + +void core_file_command (); +void exec_file_command (); +void validate_files (); +unsigned int register_addr (); +int xfer_core_file (); +void fetch_core_registers (); +void registers_fetched (); + +#if !defined (KERNEL_U_ADDR) +extern CORE_ADDR kernel_u_addr; +#define KERNEL_U_ADDR kernel_u_addr +#endif + +/* Struct section_table maps address ranges to file sections. It is + mostly used with BFD files, but can be used without (e.g. for handling + raw disks, or files not in formats handled by BFD). */ + +struct section_table { + CORE_ADDR addr; /* Lowest address in section */ + CORE_ADDR endaddr; /* 1+highest address in section */ + sec_ptr sec_ptr; /* BFD section pointer */ +}; + +/* Builds a section table, given args BFD, SECTABLE_PTR, SECEND_PTR. + Returns 0 if OK, 1 on error. */ + +int build_section_table (); diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c new file mode 100644 index 00000000000..d621fa3a2e2 --- /dev/null +++ b/gdb/i386-tdep.c @@ -0,0 +1,494 @@ +/* Intel 386 stuff. + Copyright (C) 1988, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" +#include "gdbcore.h" + +#ifdef USG +#include +#endif + +#include +#include +#include +#include +#include +#include + +#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 +#include + +/* 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 +#else +#include +#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 $, %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 $, %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 $, %esp'. 'enter' has + * a 16 bit unsigned argument for space to allocate, and the + * 'addl' instruction could have either a signed byte, or + * 32 bit immediate. + * + * Next, the registers used by this function are pushed. In + * the sys5 compiler they will always be in the order: %edi, %esi, %ebx + * (and sometimes a harmless bug causes it to also save but not restore %eax); + * however, the code below is willing to see the pushes in any order, + * and will handle up to 8 of them. + * + * If the setup sequence is at the end of the function, then the + * next instruction will be a branch back to the start. + */ + +i386_frame_find_saved_regs (fip, fsrp) + struct frame_info *fip; + struct frame_saved_regs *fsrp; +{ + long locals; + unsigned char *p; + unsigned char op; + CORE_ADDR dummy_bottom; + CORE_ADDR adr; + int i; + + bzero (fsrp, sizeof *fsrp); + + /* if frame is the end of a dummy, compute where the + * beginning would be + */ + dummy_bottom = fip->frame - 4 - REGISTER_BYTES - CALL_DUMMY_LENGTH; + + /* check if the PC is in the stack, in a dummy frame */ + if (dummy_bottom <= fip->pc && fip->pc <= fip->frame) + { + /* all regs were saved by push_call_dummy () */ + adr = fip->frame; + for (i = 0; i < NUM_REGS; i++) + { + adr -= REGISTER_RAW_SIZE (i); + fsrp->regs[i] = adr; + } + return; + } + + locals = i386_get_frame_setup (get_pc_function_start (fip->pc)); + + if (locals >= 0) + { + adr = fip->frame - 4 - locals; + for (i = 0; i < 8; i++) + { + op = codestream_get (); + if (op < 0x50 || op > 0x57) + break; + fsrp->regs[op - 0x50] = adr; + adr -= 4; + } + } + + fsrp->regs[PC_REGNUM] = fip->frame + 4; + fsrp->regs[FP_REGNUM] = fip->frame; +} + +/* return pc of first real instruction */ +i386_skip_prologue (pc) +{ + unsigned char op; + int i; + + if (i386_get_frame_setup (pc) < 0) + return (pc); + + /* found valid frame setup - codestream now points to + * start of push instructions for saving registers + */ + + /* skip over register saves */ + for (i = 0; i < 8; i++) + { + op = codestream_peek (); + /* break if not pushl inst */ + if (op < 0x50 || op > 0x57) + break; + codestream_get (); + } + + i386_follow_jump (); + + return (codestream_tell ()); +} + +i386_push_dummy_frame () +{ + CORE_ADDR sp = read_register (SP_REGNUM); + int regnum; + char regbuf[MAX_REGISTER_RAW_SIZE]; + + sp = push_word (sp, read_register (PC_REGNUM)); + sp = push_word (sp, read_register (FP_REGNUM)); + write_register (FP_REGNUM, sp); + for (regnum = 0; regnum < NUM_REGS; regnum++) + { + read_register_gen (regnum, regbuf); + sp = push_bytes (sp, regbuf, REGISTER_RAW_SIZE (regnum)); + } + write_register (SP_REGNUM, sp); +} + +i386_pop_frame () +{ + FRAME frame = get_current_frame (); + CORE_ADDR fp; + int regnum; + struct frame_saved_regs fsr; + struct frame_info *fi; + char regbuf[MAX_REGISTER_RAW_SIZE]; + + fi = get_frame_info (frame); + fp = fi->frame; + get_frame_saved_regs (fi, &fsr); + for (regnum = 0; regnum < NUM_REGS; regnum++) + { + CORE_ADDR adr; + adr = fsr.regs[regnum]; + if (adr) + { + read_memory (adr, regbuf, REGISTER_RAW_SIZE (regnum)); + write_register_bytes (REGISTER_BYTE (regnum), regbuf, + REGISTER_RAW_SIZE (regnum)); + } + } + write_register (FP_REGNUM, read_memory_integer (fp, 4)); + write_register (PC_REGNUM, read_memory_integer (fp + 4, 4)); + write_register (SP_REGNUM, fp + 8); + flush_cached_frames (); + set_current_frame ( create_new_frame (read_register (FP_REGNUM), + read_pc ())); +} diff --git a/gdb/infcmd.c b/gdb/infcmd.c new file mode 100644 index 00000000000..e3f86d47478 --- /dev/null +++ b/gdb/infcmd.c @@ -0,0 +1,1088 @@ +/* Memory-access and commands for inferior process, for GDB. + Copyright (C) 1986, 1987, 1988, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include +#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 (); + + +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)); +} + +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); +} + +/* 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 + } +} + +/* 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); +} + +/* 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); +} + +/* "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'); + } +} + +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"); +} + +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 (); +} + +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); +} + +/* + * 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 +} + +void +_initialize_infcmd () +{ + struct cmd_list_element *c; + + add_com ("tty", class_run, tty_command, + "Set terminal for future runs of program being debugged."); + + add_show_from_set + (add_set_cmd ("args", class_run, var_string_noescape, (char *)&inferior_args, + +"Set arguments to give program being debugged when it is started.\n\ +Follow this command with any number of args, to be passed to the program.", + &setlist), + &showlist); + + c = add_cmd + ("environment", no_class, environment_info, + "The environment to give the program, or one variable's value.\n\ +With an argument VAR, prints the value of environment variable VAR to\n\ +give the program being debugged. With no arguments, prints the entire\n\ +environment to be given to the program.", &showlist); + c->completer = noop_completer; + + c = add_cmd ("environment", class_run, unset_environment_command, + "Cancel environment variable VAR for the program.\n\ +This does not affect the program until the next \"run\" command.", + &deletelist); + c->completer = noop_completer; + + c = add_cmd ("environment", class_run, set_environment_command, + "Set environment variable value to give the program.\n\ +Arguments are VAR VALUE where VAR is variable name and VALUE is value.\n\ +VALUES of environment variables are uninterpreted strings.\n\ +This does not affect the program until the next \"run\" command.", + &setlist); + c->completer = noop_completer; + + add_com ("path", class_files, path_command, + "Add directory DIR(s) to beginning of search path for object files.\n\ +$cwd in the path means the current working directory.\n\ +This path is equivalent to the $PATH shell variable. It is a list of\n\ +directories, separated by colons. These directories are searched to find\n\ +fully linked executable files and separately compiled object files as needed."); + + add_info ("path", path_info, + "Current search path for finding object files.\n\ +$cwd in the path means the current working directory.\n\ +This path is equivalent to the $PATH shell variable. It is a list of\n\ +directories, separated by colons. These directories are searched to find\n\ +fully linked executable files and separately compiled object files as needed."); + + add_com ("attach", class_run, attach_command, + "Attach to a process or file outside of GDB.\n\ +This command attaches to another target, of the same type as your last\n\ +`target' command (`info files' will show your target stack).\n\ +The command may take as argument a process id or a device file.\n\ +For a process id, you must have permission to send the process a signal,\n\ +and it must have the same effective uid as the debugger.\n\ +When using \"attach\", you should use the \"file\" command to specify\n\ +the program running in the process, and to load its symbol table."); + + add_com ("detach", class_run, detach_command, + "Detach a process or file previously attached.\n\ +If a process, it is no longer traced, and it continues its execution. If you\n\ +were debugging a file, the file is closed and gdb no longer accesses it."); + + add_com ("signal", class_run, signal_command, + "Continue program giving it signal number SIGNUMBER."); + + add_com ("stepi", class_run, stepi_command, + "Step one instruction exactly.\n\ +Argument N means do this N times (or till program stops for another reason)."); + add_com_alias ("si", "stepi", class_alias, 0); + + add_com ("nexti", class_run, nexti_command, + "Step one instruction, but proceed through subroutine calls.\n\ +Argument N means do this N times (or till program stops for another reason)."); + add_com_alias ("ni", "nexti", class_alias, 0); + + add_com ("finish", class_run, finish_command, + "Execute until selected stack frame returns.\n\ +Upon return, the value returned is printed and put in the value history."); + + add_com ("next", class_run, next_command, + "Step program, proceeding through subroutine calls.\n\ +Like the \"step\" command as long as subroutine calls do not happen;\n\ +when they do, the call is treated as one instruction.\n\ +Argument N means do this N times (or till program stops for another reason)."); + add_com_alias ("n", "next", class_run, 1); + + add_com ("step", class_run, step_command, + "Step program until it reaches a different source line.\n\ +Argument N means do this N times (or till program stops for another reason)."); + add_com_alias ("s", "step", class_run, 1); + + add_com ("until", class_run, until_command, + "Execute until the program reaches a source line greater than the current\n\ +or a specified line or address or function (same args as break command).\n\ +Execution will also stop upon exit from the current stack frame."); + add_com_alias ("u", "until", class_run, 1); + + add_com ("jump", class_run, jump_command, + "Continue program being debugged at specified line or address.\n\ +Give as argument either LINENUM or *ADDR, where ADDR is an expression\n\ +for an address to start at."); + + add_com ("continue", class_run, continue_command, + "Continue program being debugged, after signal or breakpoint.\n\ +If proceeding from breakpoint, a number N may be used as an argument:\n\ +then the same breakpoint won't break until the Nth time it is reached."); + add_com_alias ("c", "cont", class_run, 1); + add_com_alias ("fg", "cont", class_run, 1); + + add_com ("run", class_run, run_command, + "Start debugged program. You may specify arguments to give it.\n\ +Args may include \"*\", or \"[...]\"; they are expanded using \"sh\".\n\ +Input and output redirection with \">\", \"<\", or \">>\" are also allowed.\n\n\ +With no arguments, uses arguments last specified (with \"run\" or \"set args\".\n\ +To cancel previous arguments and run with no arguments,\n\ +use \"set args\" without arguments."); + add_com_alias ("r", "run", class_run, 1); + + add_info ("registers", registers_info, + "List of registers and their contents, for selected stack frame.\n\ +Register name as argument means describe only that register."); + + add_info ("program", program_info, + "Execution status of the program."); + + add_info ("float", float_info, + "Print the status of the floating point unit\n"); + + inferior_args = savestring ("", 1); /* Initially no args */ + inferior_environ = make_environ (); + init_environ (inferior_environ); +} diff --git a/gdb/inferior.h b/gdb/inferior.h new file mode 100644 index 00000000000..d99c4a62848 --- /dev/null +++ b/gdb/inferior.h @@ -0,0 +1,201 @@ +/* Variables that describe the inferior process running under GDB: + Where it is, why it stopped, and how to step it. + Copyright (C) 1986, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* For bpstat. */ +#include "breakpoint.h" + +/* For FRAME_ADDR. */ +#include "frame.h" + +/* + * Structure in which to save the status of the inferior. Save + * through "save_inferior_status", restore through + * "restore_inferior_status". + * This pair of routines should be called around any transfer of + * control to the inferior which you don't want showing up in your + * control variables. + */ +struct inferior_status { + int pc_changed; + int stop_signal; + int stop_pc; + FRAME_ADDR stop_frame_address; + bpstat stop_bpstat; + int stop_step; + int stop_stack_dummy; + int stopped_by_random_signal; + int trap_expected; + CORE_ADDR step_range_start; + CORE_ADDR step_range_end; + FRAME_ADDR step_frame_address; + int step_over_calls; + CORE_ADDR step_resume_break_address; + int stop_after_trap; + int stop_soon_quietly; + FRAME_ADDR selected_frame_address; + int selected_level; + char stop_registers[REGISTER_BYTES]; + int breakpoint_proceeded; + int restore_stack_info; + int proceed_to_finish; +}; + +void save_inferior_status (), restore_inferior_status (); + +/* File name for default use for standard in/out in the inferior. */ + +extern char *inferior_io_terminal; + +/* Pid of our debugged inferior, or 0 if no inferior now. */ + +extern int inferior_pid; + +/* Character array containing an image of the inferior programs' registers. */ + +extern char registers[]; + +extern void clear_proceed_status (); +extern void start_inferior (); +extern void proceed (); +extern void kill_inferior (); +extern void kill_inferior_fast (); +extern void generic_mourn_inferior (); +extern void terminal_ours (); +extern void detach (); +extern void run_stack_dummy (); +extern CORE_ADDR read_pc (); +extern void write_pc (); +extern void wait_for_inferior (); +extern void init_wait_for_inferior (); +extern void close_exec_file (); +extern void reopen_exec_file (); + +/* Last signal that the inferior received (why it stopped). */ + +extern int stop_signal; + +/* Address at which inferior stopped. */ + +extern CORE_ADDR stop_pc; + +/* Stack frame when program stopped. */ + +extern FRAME_ADDR stop_frame_address; + +/* Chain containing status of breakpoint(s) that we have stopped at. */ + +extern bpstat stop_bpstat; + +/* Flag indicating that a command has proceeded the inferior past the + current breakpoint. */ + +extern int breakpoint_proceeded; + +/* Nonzero if stopped due to a step command. */ + +extern int stop_step; + +/* Nonzero if stopped due to completion of a stack dummy routine. */ + +extern int stop_stack_dummy; + +/* Nonzero if program stopped due to a random (unexpected) signal in + inferior process. */ + +extern int stopped_by_random_signal; + +/* Range to single step within. + If this is nonzero, respond to a single-step signal + by continuing to step if the pc is in this range. */ + +extern CORE_ADDR step_range_start; /* Inclusive */ +extern CORE_ADDR step_range_end; /* Exclusive */ + +/* Stack frame address as of when stepping command was issued. + This is how we know when we step into a subroutine call, + and how to set the frame for the breakpoint used to step out. */ + +extern FRAME_ADDR step_frame_address; + +/* 1 means step over all subroutine calls. + -1 means step over calls to undebuggable functions. */ + +extern int step_over_calls; + +/* If stepping, nonzero means step count is > 1 + so don't print frame next time inferior stops + if it stops due to stepping. */ + +extern int step_multi; + +/* Nonzero if proceed is being used for a "finish" command or a similar + situation when stop_registers should be saved. */ + +extern int proceed_to_finish; + +/* Save register contents here when about to pop a stack dummy frame, + if-and-only-if proceed_to_finish is set. + Thus this contains the return value from the called function (assuming + values are returned in a register). */ + +extern char stop_registers[REGISTER_BYTES]; + +/* Nonzero if pc has been changed by the debugger + since the inferior stopped. */ + +extern int pc_changed; + +/* Nonzero if the child process in inferior_pid was attached rather + than forked. */ + +int attach_flag; + +/* Possible values for CALL_DUMMY_LOCATION. */ +#define ON_STACK 1 +#define BEFORE_TEXT_END 2 +#define AFTER_TEXT_END 3 + +#if !defined (CALL_DUMMY_LOCATION) +#if defined (CANNOT_EXECUTE_STACK) +#define CALL_DUMMY_LOCATION BEFORE_TEXT_END +#else /* Can execute stack. */ +#define CALL_DUMMY_LOCATION ON_STACK +#endif /* Can execute stack. */ +#endif /* No CALL_DUMMY_LOCATION. */ + +/* Are we in a call dummy? The code below which allows DECR_PC_AFTER_BREAK + below is for infrun.c, which may give the macro a pc without that + subtracted out. */ +#if !defined (PC_IN_CALL_DUMMY) +#if CALL_DUMMY_LOCATION == BEFORE_TEXT_END +#define PC_IN_CALL_DUMMY(pc, sp, frame_address) \ + ((pc) >= text_end - CALL_DUMMY_LENGTH \ + && (pc) < text_end + DECR_PC_AFTER_BREAK) +#else /* Not before text_end. */ +#if CALL_DUMMY_LOCATION == AFTER_TEXT_END +#define PC_IN_CALL_DUMMY(pc, sp, frame_address) \ + ((pc) >= text_end \ + && (pc) < text_end + CALL_DUMMY_LENGTH + DECR_PC_AFTER_BREAK) +#else /* On stack. */ +#define PC_IN_CALL_DUMMY(pc, sp, frame_address) \ + ((sp) INNER_THAN (pc) && (pc) INNER_THAN (frame_address)) +#endif /* On stack. */ +#endif /* Not before text_end. */ +#endif /* No PC_IN_CALL_DUMMY. */ diff --git a/gdb/inflow.c b/gdb/inflow.c new file mode 100644 index 00000000000..6e6905fd508 --- /dev/null +++ b/gdb/inflow.c @@ -0,0 +1,478 @@ +/* Low level interface to ptrace, for GDB when running under Unix. + Copyright (C) 1986, 1987, 1989, 1991 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#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 +#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 + +#include +#include +#include + +extern struct target_ops child_ops; + +/* Nonzero if we are debugging an attached outside process + rather than an inferior. */ + +int attach_flag; + + +/* 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 +} + +/* 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); +} + +/* 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 (); +} + +#if 0 +/* This function is just for testing, and on some systems (Sony NewsOS + 3.2) also includes 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 + +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; +} + diff --git a/gdb/infptrace.c b/gdb/infptrace.c new file mode 100644 index 00000000000..03bb271c53f --- /dev/null +++ b/gdb/infptrace.c @@ -0,0 +1,397 @@ +/* Low level Unix child interface to ptrace, for GDB when running under Unix. + Copyright (C) 1988, 1989, 1990, 1991 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" +#include "target.h" + +#ifdef USG +#include +#endif + +#include +#include +#include +#include +#include +#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 /* After a.out.h */ +#include +#include + +/* 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"); +} + +#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 */ + +#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). */ + +/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory + in the NEW_SUN_PTRACE case. + It ought to be straightforward. But it appears that writing did + not write the data that I specified. I cannot understand where + it got the data that it actually did write. */ + +/* Copy LEN bytes to or from inferior's memory starting at MEMADDR + to debugger memory starting at MYADDR. Copy to inferior if + WRITE is nonzero. + + Returns the length copied, which is either the LEN argument or zero. + This xfer function does not do partial moves, since child_ops + doesn't allow memory operations to cross below us in the target stack + anyway. */ + +int +child_xfer_memory (memaddr, myaddr, len, write) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; +{ + register int i; + /* Round starting address down to longword boundary. */ + register CORE_ADDR addr = memaddr & - sizeof (int); + /* Round ending address up; get number of longwords that makes. */ + register int count + = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int); + /* Allocate buffer of that many longwords. */ + register int *buffer = (int *) alloca (count * sizeof (int)); + + if (write) + { + /* Fill start and end extra bytes of buffer with existing memory data. */ + + if (addr != memaddr || len < (int)sizeof (int)) { + /* Need part of initial word -- fetch it. */ + buffer[0] = ptrace (PT_READ_I, inferior_pid, (int *)addr, 0); + } + + if (count > 1) /* FIXME, avoid if even boundary */ + { + buffer[count - 1] + = ptrace (PT_READ_I, inferior_pid, + (int *)(addr + (count - 1) * sizeof (int)), 0); + } + + /* Copy data to be written over corresponding part of buffer */ + + bcopy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len); + + /* Write the entire buffer. */ + + for (i = 0; i < count; i++, addr += sizeof (int)) + { + errno = 0; + ptrace (PT_WRITE_D, inferior_pid, (int *)addr, buffer[i]); + if (errno) + { + /* Using the appropriate one (I or D) is necessary for + Gould NP1, at least. */ + errno = 0; + ptrace (PT_WRITE_I, inferior_pid, (int *)addr, buffer[i]); + } + if (errno) + return 0; + } + } + else + { + /* Read all the longwords */ + for (i = 0; i < count; i++, addr += sizeof (int)) + { + errno = 0; + buffer[i] = ptrace (PT_READ_I, inferior_pid, (int *)addr, 0); + if (errno) + return 0; + QUIT; + } + + /* Copy appropriate bytes out of the buffer. */ + bcopy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len); + } + return len; +} diff --git a/gdb/infrun.c b/gdb/infrun.c new file mode 100644 index 00000000000..1cca59277d3 --- /dev/null +++ b/gdb/infrun.c @@ -0,0 +1,1690 @@ +/* Start (run) and stop the inferior process, for GDB. + Copyright (C) 1986, 1987, 1988, 1989, 1991 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Notes on the algorithm used in wait_for_inferior to determine if we + just did a subroutine call when stepping. We have the following + information at that point: + + Current and previous (just before this step) pc. + Current and previous sp. + Current and previous start of current function. + + If the start's of the functions don't match, then + + a) We did a subroutine call. + + In this case, the pc will be at the beginning of a function. + + b) We did a subroutine return. + + Otherwise. + + c) We did a longjmp. + + If we did a longjump, we were doing "nexti", since a next would + have attempted to skip over the assembly language routine in which + the longjmp is coded and would have simply been the equivalent of a + continue. I consider this ok behaivior. We'd like one of two + things to happen if we are doing a nexti through the longjmp() + routine: 1) It behaves as a stepi, or 2) It acts like a continue as + above. Given that this is a special case, and that anybody who + thinks that the concept of sub calls is meaningful in the context + of a longjmp, I'll take either one. Let's see what happens. + + Acts like a subroutine return. I can handle that with no problem + at all. + + -->So: If the current and previous beginnings of the current + function don't match, *and* the pc is at the start of a function, + we've done a subroutine call. If the pc is not at the start of a + function, we *didn't* do a subroutine call. + + -->If the beginnings of the current and previous function do match, + either: + + a) We just did a recursive call. + + In this case, we would be at the very beginning of a + function and 1) it will have a prologue (don't jump to + before prologue, or 2) (we assume here that it doesn't have + a prologue) there will have been a change in the stack + pointer over the last instruction. (Ie. it's got to put + the saved pc somewhere. The stack is the usual place. In + a recursive call a register is only an option if there's a + prologue to do something with it. This is even true on + register window machines; the prologue sets up the new + window. It might not be true on a register window machine + where the call instruction moved the register window + itself. Hmmm. One would hope that the stack pointer would + also change. If it doesn't, somebody send me a note, and + I'll work out a more general theory. + bug-gdb@prep.ai.mit.edu). This is true (albeit slipperly + so) on all machines I'm aware of: + + m68k: Call changes stack pointer. Regular jumps don't. + + sparc: Recursive calls must have frames and therefor, + prologues. + + vax: All calls have frames and hence change the + stack pointer. + + b) We did a return from a recursive call. I don't see that we + have either the ability or the need to distinguish this + from an ordinary jump. The stack frame will be printed + when and if the frame pointer changes; if we are in a + function without a frame pointer, it's the users own + lookout. + + c) We did a jump within a function. We assume that this is + true if we didn't do a recursive call. + + d) We are in no-man's land ("I see no symbols here"). We + don't worry about this; it will make calls look like simple + jumps (and the stack frames will be printed when the frame + pointer moves), which is a reasonably non-violent response. + +#if 0 + We skip this; it causes more problems than it's worth. +#ifdef SUN4_COMPILER_FEATURE + We do a special ifdef for the sun 4, forcing it to single step + into calls which don't have prologues. This means that we can't + nexti over leaf nodes, we can probably next over them (since they + won't have debugging symbols, usually), and we can next out of + functions returning structures (with a "call .stret4" at the end). +#endif +#endif +*/ + + + + + +#include +#include +#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 + +/* unistd.h is needed to #define X_OK */ +#ifdef USG +#include +#else +#include +#endif + +#ifdef SET_STACK_LIMIT_HUGE +extern int original_stack_limit; +#endif /* SET_STACK_LIMIT_HUGE */ + +/* Required by . */ +#include +/* Required by , at least on system V. */ +#include +/* Needed by IN_SIGTRAMP on some machines (e.g. vax). */ +#include +/* Needed by IN_SIGTRAMP on some machines (e.g. vax). */ +#include + +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 (); + + +/* 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 */ +} + +/* 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; + } +} + +/* 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); + } +} + +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); +} + +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"); +} + +/* 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); + } +} + + +void +_initialize_infrun () +{ + register int i; + + add_info ("signals", signals_info, + "What debugger does when program gets various signals.\n\ +Specify a signal number as argument to print info on that signal only."); + + add_com ("handle", class_run, handle_command, + "Specify how to handle a signal.\n\ +Args are signal number followed by flags.\n\ +Flags allowed are \"stop\", \"print\", \"pass\",\n\ + \"nostop\", \"noprint\" or \"nopass\".\n\ +Print means print a message if this signal happens.\n\ +Stop means reenter debugger if this signal happens (implies print).\n\ +Pass means let program see this signal; otherwise program doesn't know.\n\ +Pass and Stop may be combined."); + + for (i = 0; i < NSIG; i++) + { + signal_stop[i] = 1; + signal_print[i] = 1; + signal_program[i] = 1; + } + + /* Signals caused by debugger's own actions + should not be given to the program afterwards. */ + signal_program[SIGTRAP] = 0; + signal_program[SIGINT] = 0; + + /* Signals that are not errors should not normally enter the debugger. */ +#ifdef SIGALRM + signal_stop[SIGALRM] = 0; + signal_print[SIGALRM] = 0; +#endif /* SIGALRM */ +#ifdef SIGVTALRM + signal_stop[SIGVTALRM] = 0; + signal_print[SIGVTALRM] = 0; +#endif /* SIGVTALRM */ +#ifdef SIGPROF + signal_stop[SIGPROF] = 0; + signal_print[SIGPROF] = 0; +#endif /* SIGPROF */ +#ifdef SIGCHLD + signal_stop[SIGCHLD] = 0; + signal_print[SIGCHLD] = 0; +#endif /* SIGCHLD */ +#ifdef SIGCLD + signal_stop[SIGCLD] = 0; + signal_print[SIGCLD] = 0; +#endif /* SIGCLD */ +#ifdef SIGIO + signal_stop[SIGIO] = 0; + signal_print[SIGIO] = 0; +#endif /* SIGIO */ +#ifdef SIGURG + signal_stop[SIGURG] = 0; + signal_print[SIGURG] = 0; +#endif /* SIGURG */ +} + diff --git a/gdb/inftarg.c b/gdb/inftarg.c new file mode 100644 index 00000000000..ce64437f766 --- /dev/null +++ b/gdb/inftarg.c @@ -0,0 +1,182 @@ +/* Subroutines for handling an "inferior" (child) process as a target + for debugging, in GDB. + Copyright 1990, 1991 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include "defs.h" +#include "param.h" +#include "frame.h" /* required by inferior.h */ +#include "inferior.h" +#include "target.h" +#include "wait.h" +#include "gdbcore.h" +#include "ieee-float.h" /* Required by REGISTER_CONVERT_TO_XXX */ + +extern int fetch_inferior_registers(); +extern int store_inferior_registers(); +extern int child_xfer_memory(); +extern int memory_insert_breakpoint(), memory_remove_breakpoint(); +extern void terminal_init_inferior(), terminal_ours(), terminal_inferior(); +extern void terminal_ours_for_output(), child_terminal_info(); +extern void kill_inferior(), add_syms_addr_command(); +extern struct value *call_function_by_hand(); +extern void child_resume(); +extern void child_create_inferior(); +extern void child_mourn_inferior(); +extern void child_attach (); + +/* Forward declaration */ +extern struct target_ops child_ops; + +/* Wait for child to do something. Return pid of child, or -1 in case + of error; store status through argument pointer STATUS. */ + +int +child_wait (status) + int *status; +{ + int pid; + + do { + pid = wait (status); + if (pid == -1) /* No more children to wait for */ + { + fprintf (stderr, "Child process unexpectedly missing.\n"); + *status = 42; /* Claim it exited with signal 42 */ + return -1; + } + } while (pid != inferior_pid); /* Some other child died or stopped */ + return pid; +} + + +/* + * child_detach() + * takes a program previously attached to and detaches it. + * The program resumes execution and will no longer stop + * on signals, etc. We better not have left any breakpoints + * in the program or it'll die when it hits one. For this + * to work, it may be necessary for the process to have been + * previously attached. It *might* work if the program was + * started via the normal ptrace (PTRACE_TRACEME). + */ + +static void +child_detach (args, from_tty) + char *args; + int from_tty; +{ + int siggnal = 0; + +#ifdef ATTACH_DETACH + if (from_tty) + { + char *exec_file = get_exec_file (0); + if (exec_file == 0) + exec_file = ""; + printf ("Detaching program: %s pid %d\n", + exec_file, inferior_pid); + fflush (stdout); + } + if (args) + siggnal = atoi (args); + + detach (siggnal); + inferior_pid = 0; + unpush_target (&child_ops); /* Pop out of handling an inferior */ +#else + error ("This version of Unix does not support detaching a process."); +#endif +} + +/* Get ready to modify the registers array. On machines which store + individual registers, this doesn't need to do anything. On machines + which store all the registers in one fell swoop, this makes sure + that registers contains all the registers from the program being + debugged. */ + +void +child_prepare_to_store () +{ +#ifdef CHILD_PREPARE_TO_STORE + CHILD_PREPARE_TO_STORE (); +#endif +} + +/* Convert data from raw format for register REGNUM + to virtual format for register REGNUM. */ + +void +host_convert_to_virtual (regnum, from, to) + int regnum; + char *from; + char *to; +{ + REGISTER_CONVERT_TO_VIRTUAL (regnum, from, to); +} + +/* Convert data from virtual format for register REGNUM + to raw format for register REGNUM. */ + +void +host_convert_from_virtual (regnum, from, to) + int regnum; + char *from; + char *to; +{ + REGISTER_CONVERT_TO_RAW (regnum, from, to); +} + +/* Print status information about what we're accessing. */ + +static void +child_files_info () +{ + printf ("\tUsing the running image of %s process %d.\n", + attach_flag? "attached": "child", inferior_pid); +} + +struct target_ops child_ops = { + "child", "Unix child process", + 0, 0, /* open, close */ + child_attach, child_detach, + child_resume, + child_wait, + fetch_inferior_registers, store_inferior_registers, + child_prepare_to_store, + host_convert_to_virtual, host_convert_from_virtual, + child_xfer_memory, child_files_info, + memory_insert_breakpoint, memory_remove_breakpoint, + terminal_init_inferior, terminal_inferior, + terminal_ours_for_output, terminal_ours, child_terminal_info, + kill_inferior, 0, add_syms_addr_command, /* load */ + call_function_by_hand, + 0, /* lookup_symbol */ + child_create_inferior, child_mourn_inferior, + process_stratum, 0, /* next */ + 1, 1, 1, 1, 1, /* all mem, mem, stack, regs, exec */ + OPS_MAGIC, /* Always the last thing */ +}; + +void +_initialize_inftarg () +{ + add_target (&child_ops); +} diff --git a/gdb/m68k-tdep.c b/gdb/m68k-tdep.c new file mode 100644 index 00000000000..edb87dbec87 --- /dev/null +++ b/gdb/m68k-tdep.c @@ -0,0 +1,26 @@ +/* Target dependent code for the Motorola 68000 series. + Copyright (C) 1990 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "defs.h" +#include "ieee-float.h" + +const struct ext_format ext_format_68881 [] = { +/* tot sbyte smask expbyte manbyte */ + { 12, 0, 0x80, 0,1, 4,8 }, /* mc68881 */ +}; diff --git a/gdb/main.c b/gdb/main.c new file mode 100644 index 00000000000..5845079f204 --- /dev/null +++ b/gdb/main.c @@ -0,0 +1,2127 @@ +/* Top level for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1988, 1989, 1990 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +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 +#include +#include + +/* readline defines this. */ +#undef savestring + +#ifdef USG +#include +#include +#endif + +#include +#include +#include +#include +#include + +#ifdef SET_STACK_LIMIT_HUGE +#include +#include +#include + +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 + +/* 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); +} + +/* 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); +} + +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); + } +} + +/* 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; +} + +/* 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); +} + +#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); +} + +/* 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; +} + +/* 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; + } +} + +/* 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, ""); +} + +/* 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); +} + +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); +} + +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--; +} + +/* xgdb calls this to reprint the usual GDB prompt. */ + +void +print_prompt () +{ + printf ("%s", prompt); + fflush (stdout); +} + +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; +} + +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); +} + +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); + } +} + +/* 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 " should print around command number . */ + 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)); +} + + +static void +initialize_cmd_lists () +{ + cmdlist = (struct cmd_list_element *) 0; + infolist = (struct cmd_list_element *) 0; + enablelist = (struct cmd_list_element *) 0; + disablelist = (struct cmd_list_element *) 0; + deletelist = (struct cmd_list_element *) 0; + enablebreaklist = (struct cmd_list_element *) 0; + setlist = (struct cmd_list_element *) 0; + showlist = NULL; + sethistlist = (struct cmd_list_element *) 0; + showhistlist = NULL; + unsethistlist = (struct cmd_list_element *) 0; +} + +static void +initialize_main () +{ + struct cmd_list_element *c; + + char *tmpenv; + +#ifdef DEFAULT_PROMPT + prompt = savestring (DEFAULT_PROMPT, strlen(DEFAULT_PROMPT)); +#else + prompt = savestring ("(gdb) ", 6); +#endif + + /* Set the important stuff up for command editing. */ + command_editing_p = 1; + history_expansion_p = 0; + write_history_p = 0; + + if (tmpenv = getenv ("HISTSIZE")) + history_size = atoi (tmpenv); + else + history_size = 256; + + stifle_history (history_size); + + if (tmpenv = getenv ("GDBHISTFILE")) + history_filename = savestring (tmpenv, strlen(tmpenv)); + else + /* We include the current directory so that if the user changes + directories the file written will be the same as the one + that was read. */ + history_filename = concat (current_directory, "/.gdb_history", ""); + + read_history (history_filename); + + /* Setup important stuff for command line editing. */ + rl_completion_entry_function = (int (*)()) symbol_completion_function; + rl_completer_word_break_characters = gdb_completer_word_break_characters; + rl_readline_name = "gdb"; + + /* Define the classes of commands. + They will appear in the help list in the reverse of this order. */ + + add_cmd ("obscure", class_obscure, NO_FUNCTION, "Obscure features.", &cmdlist); + add_cmd ("aliases", class_alias, NO_FUNCTION, "Aliases of other commands.", &cmdlist); + add_cmd ("user-defined", class_user, NO_FUNCTION, "User-defined commands.\n\ +The commands in this class are those defined by the user.\n\ +Use the \"define\" command to define a command.", &cmdlist); + add_cmd ("support", class_support, NO_FUNCTION, "Support facilities.", &cmdlist); + add_cmd ("status", class_info, NO_FUNCTION, "Status inquiries.", &cmdlist); + add_cmd ("files", class_files, NO_FUNCTION, "Specifying and examining files.", &cmdlist); + add_cmd ("breakpoints", class_breakpoint, NO_FUNCTION, "Making program stop at certain points.", &cmdlist); + add_cmd ("data", class_vars, NO_FUNCTION, "Examining data.", &cmdlist); + add_cmd ("stack", class_stack, NO_FUNCTION, "Examining the stack.\n\ +The stack is made up of stack frames. Gdb assigns numbers to stack frames\n\ +counting from zero for the innermost (currently executing) frame.\n\n\ +At any time gdb identifies one frame as the \"selected\" frame.\n\ +Variable lookups are done with respect to the selected frame.\n\ +When the program being debugged stops, gdb selects the innermost frame.\n\ +The commands below can be used to select other frames by number or address.", + &cmdlist); + add_cmd ("running", class_run, NO_FUNCTION, "Running the program.", &cmdlist); + + add_com ("pwd", class_files, pwd_command, + "Print working directory. This is used for your program as well."); + add_com ("cd", class_files, cd_command, + "Set working directory to DIR for debugger and program being debugged.\n\ +The change does not take effect for the program being debugged\n\ +until the next time it is started."); + + add_show_from_set + (add_set_cmd ("prompt", class_support, var_string, (char *)&prompt, + "Set gdb's prompt", + &setlist), + &showlist); + + add_com ("echo", class_support, echo_command, + "Print a constant string. Give string as argument.\n\ +C escape sequences may be used in the argument.\n\ +No newline is added at the end of the argument;\n\ +use \"\\n\" if you want a newline to be printed.\n\ +Since leading and trailing whitespace are ignored in command arguments,\n\ +if you want to print some you must use \"\\\" before leading whitespace\n\ +to be printed or after trailing whitespace."); + add_com ("document", class_support, document_command, + "Document a user-defined command.\n\ +Give command name as argument. Give documentation on following lines.\n\ +End with a line of just \"end\"."); + add_com ("define", class_support, define_command, + "Define a new command name. Command name is argument.\n\ +Definition appears on following lines, one command per line.\n\ +End with a line of just \"end\".\n\ +Use the \"document\" command to give documentation for the new command.\n\ +Commands defined in this way do not take arguments."); + +#ifdef __STDC__ + add_com ("source", class_support, source_command, + "Read commands from a file named FILE.\n\ +Note that the file \"" GDBINIT_FILENAME "\" is read automatically in this way\n\ +when gdb is started."); +#else + /* Punt file name, we can't help it easily. */ + add_com ("source", class_support, source_command, + "Read commands from a file named FILE.\n\ +Note that the file \".gdbinit\" is read automatically in this way\n\ +when gdb is started."); +#endif + + add_com ("quit", class_support, quit_command, "Exit gdb."); + add_com ("help", class_support, help_command, "Print list of commands."); + add_com_alias ("q", "quit", class_support, 1); + add_com_alias ("h", "help", class_support, 1); + + + c = add_set_cmd ("verbose", class_support, var_boolean, (char *)&info_verbose, + "Set ", + &setlist), + add_show_from_set (c, &showlist); + c->function = set_verbose; + set_verbose (NULL, 0, c); + + add_com ("dump-me", class_obscure, dump_me_command, + "Get fatal error; make debugger dump its core."); + + add_show_from_set + (add_set_cmd ("editing", class_support, var_boolean, (char *)&command_editing_p, + "Set command line editing.\n\ +Use \"on\" to enable to enable the editing, and \"off\" to disable it.\n\ +Without an argument, command line editing is enabled.", &setlist), + &showlist); + + add_prefix_cmd ("history", class_support, set_history, + "Generic command for setting command history parameters.", + &sethistlist, "set history ", 0, &setlist); + add_prefix_cmd ("history", class_support, show_history, + "Generic command for showing command history parameters.", + &showhistlist, "show history ", 0, &showlist); + + add_show_from_set + (add_set_cmd ("expansion", no_class, var_boolean, (char *)&history_expansion_p, + "Set history expansion on command input.\n\ +Without an argument, history expansion is enabled.", &sethistlist), + &showhistlist); + + add_show_from_set + (add_set_cmd ("write", no_class, var_boolean, (char *)&write_history_p, + "Set saving of the history record on exit.\n\ +Use \"on\" to enable to enable the saving, and \"off\" to disable it.\n\ +Without an argument, saving is enabled.", &sethistlist), + &showhistlist); + + c = add_set_cmd ("size", no_class, var_uinteger, (char *)&history_size, + "Set the size of the command history, \n\ +ie. the number of previous commands to keep a record of.", &sethistlist); + add_show_from_set (c, &showhistlist); + c->function = set_history_size_command; + + add_show_from_set + (add_set_cmd ("filename", no_class, var_filename, (char *)&history_filename, + "Set the filename in which to record the command history\n\ + (the list of previous commands of which a record is kept).", &sethistlist), + &showhistlist); + + add_show_from_set + (add_set_cmd ("caution", class_support, var_boolean, + (char *)&caution, + "Set expected caution of user.\n\ +If on (the default), more warnings are printed, and the user is asked whether\n\ +they really want to do various major commands.", &setlist), + &showlist); + + add_prefix_cmd ("info", class_info, info_command, + "Generic command for printing status.", + &infolist, "info ", 0, &cmdlist); + add_com_alias ("i", "info", class_info, 1); + + add_prefix_cmd ("show", class_info, show_command, + "Generic command for showing things set with \"set\".", + &showlist, "show ", 0, &cmdlist); + /* Another way to get at the same thing. */ + add_info ("set", show_command, "Show all GDB settings."); + + add_info ("editing", editing_info, "Status of command editor."); + + add_info ("version", version_info, "Report what version of GDB this is."); +} diff --git a/gdb/mem-break.c b/gdb/mem-break.c new file mode 100644 index 00000000000..eebe7e251f1 --- /dev/null +++ b/gdb/mem-break.c @@ -0,0 +1,178 @@ +/* Simulate breakpoints by patching locations in the target system. + Copyright (C) 1990 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "defs.h" +#include "param.h" + +#ifdef BREAKPOINT +/* This file is only useful if BREAKPOINT is set. If not, we punt. */ + +#include +#include "breakpoint.h" +#include "inferior.h" +#include "target.h" + +/* This is the sequence of bytes we insert for a breakpoint. On some + machines, breakpoints are handled by the target environment and we + don't have to worry about them here. */ + +static char break_insn[] = BREAKPOINT; + +/* This is only to check that BREAKPOINT fits in BREAKPOINT_MAX bytes. */ + +static char check_break_insn_size[BREAKPOINT_MAX] = BREAKPOINT; + +/* Insert a breakpoint on machines that don't have any better breakpoint + support. We read the contents of the target location and stash it, + then overwrite it with a breakpoint instruction. ADDR is the target + location in the target machine. CONTENTS_CACHE is a pointer to + memory allocated for saving the target contents. It is guaranteed + by the caller to be long enough to save sizeof BREAKPOINT bytes. + FIXME: This size is target_arch dependent and should be available in + the target_arch transfer vector, if we ever have one... */ + +int +memory_insert_breakpoint (addr, contents_cache) + CORE_ADDR addr; + char *contents_cache; +{ + int val; + + val = target_read_memory (addr, contents_cache, sizeof break_insn); + + if (val == 0) + val = target_write_memory (addr, break_insn, sizeof break_insn); + + return val; +} + + +int +memory_remove_breakpoint (addr, contents_cache) + CORE_ADDR addr; + char *contents_cache; +{ + return target_write_memory (addr, contents_cache, sizeof break_insn); +} + + +#if 0 +/* This should move back into breakpoint.c, sad to say. Encapsulate + sizeof (BREAKPOINT) by export it as an int from mem-break.c. */ + +/* Like target_read_memory() but if breakpoints are inserted, return + the shadow contents instead of the breakpoints themselves. */ +int +read_memory_nobpt (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + unsigned len; +{ + int status; + struct breakpoint *b; + ALL_BREAKPOINTS (b) + { + if (b->address == NULL || !b->inserted) + continue; + else if (b->address + sizeof (break_insn) <= memaddr) + /* The breakpoint is entirely before the chunk of memory + we are reading. */ + continue; + else if (b->address >= memaddr + len) + /* The breakpoint is entirely after the chunk of memory we + are reading. */ + continue; + else + { + /* Copy the breakpoint from the shadow contents, and recurse + for the things before and after. */ + + /* Addresses and length of the part of the breakpoint that + we need to copy. */ + CORE_ADDR membpt = b->address; + unsigned int bptlen = sizeof (break_insn); + /* Offset within shadow_contents. */ + int bptoffset = 0; + + if (membpt < memaddr) + { + /* Only copy the second part of the breakpoint. */ + bptlen -= memaddr - membpt; + bptoffset = memaddr - membpt; + membpt = memaddr; + } + + if (membpt + bptlen > memaddr + len) + { + /* Only copy the first part of the breakpoint. */ + bptlen -= (membpt + bptlen) - (memaddr + len); + } + + bcopy (b->shadow_contents + bptoffset, + myaddr + membpt - memaddr, bptlen); + + if (membpt > memaddr) + { + /* Copy the section of memory before the breakpoint. */ + status = read_memory_nobpt (memaddr, myaddr, membpt - memaddr); + if (status != 0) + return status; + } + + if (membpt + bptlen < memaddr + len) + { + /* Copy the section of memory after the breakpoint. */ + status = read_memory_nobpt + (membpt + bptlen, + myaddr + membpt + bptlen - memaddr, + memaddr + len - (membpt + bptlen)); + if (status != 0) + return status; + } + return 0; + } + } + /* Nothing overlaps. Just call read_memory_noerr. */ + return target_read_memory (memaddr, myaddr, len); +} +#endif /* 0 */ + +#else /* BREAKPOINT */ + +char nogo[] = "Breakpoints not implemented for this target."; + +int +memory_insert_breakpoint (addr, contents_cache) + CORE_ADDR addr; + char *contents_cache; +{ + error (nogo); + return 0; /* lint */ +} + +int +memory_remove_breakpoint (addr, contents_cache) + CORE_ADDR addr; + char *contents_cache; +{ + error (nogo); + return 0; /* lint */ +} + +#endif /* BREAKPOINT */ diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c new file mode 100644 index 00000000000..abdd2062c06 --- /dev/null +++ b/gdb/mips-tdep.c @@ -0,0 +1,679 @@ +/* Work with core dump and executable files, for GDB on MIPS. + This code would be in core.c if it weren't machine-dependent. */ + +/* Low level interface to ptrace, for GDB when running under Unix. + Copyright (C) 1988, 1989, 1990 Free Software Foundation, Inc. + Contributed by Alessandro Forin(af@cs.cmu.edu) at CMU + and by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* FIXME: Can a MIPS porter/tester determine which of these include + files we still need? -- gnu@cygnus.com */ +#include +#include +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" +#include "symtab.h" +#include "value.h" +#include "gdbcmd.h" + +#ifdef USG +#include +#endif + +#include +#include +#include +#include + +#include "gdbcore.h" + +#ifndef MIPSMAGIC +#ifdef MIPSEL +#define MIPSMAGIC MIPSELMAGIC +#else +#define MIPSMAGIC MIPSEBMAGIC +#endif +#endif + +#define VM_MIN_ADDRESS (unsigned)0x400000 + +#include /* After a.out.h */ +#include +#include + + +#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; + + +#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<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; +} + + +/* Bad floats: Returns 0 if P points to a valid IEEE floating point number, + 1 if P points to a denormalized number or a NaN. LEN says whether this is + a single-precision or double-precision float */ +#define SINGLE_EXP_BITS 8 +#define DOUBLE_EXP_BITS 11 +int +isa_NAN(p, len) + int *p, len; +{ + int exponent; + if (len == 4) + { + exponent = *p; + exponent = exponent << 1 >> (32 - SINGLE_EXP_BITS - 1); + return ((exponent == -1) || (! exponent && *p)); + } + else if (len == 8) + { + exponent = *(p+1); + exponent = exponent << 1 >> (32 - DOUBLE_EXP_BITS - 1); + return ((exponent == -1) || (! exponent && *p * *(p+1))); + } + else return 1; +} + +/* To skip prologues, I use this predicate. Returns either PC + itself if the code at PC does not look like a function prologue, + PC+4 if it does (our caller does not need anything more fancy). */ + +CORE_ADDR mips_skip_prologue(pc) + CORE_ADDR pc; +{ + struct symbol *f; + struct block *b; + unsigned long inst; + + /* For -g modules and most functions anyways the + first instruction adjusts the stack. */ + inst = read_memory_integer(pc, 4); + if ((inst & 0xffff0000) == 0x27bd0000) + return pc + 4; + + /* Well, it looks like a frameless. Let's make sure. + Note that we are not called on the current PC, + but on the function`s start PC, and I have definitely + seen optimized code that adjusts the SP quite later */ + b = block_for_pc(pc); + if (!b) return pc; + + f = lookup_symbol(".gdbinfo.", b, LABEL_NAMESPACE, 0, NULL); + if (!f) return pc; + /* Ideally, I would like to use the adjusted info + from mips_frame_info(), but for all practical + purposes it will not matter (and it would require + a different definition of SKIP_PROLOGUE()) + + Actually, it would not hurt to skip the storing + of arguments on the stack as well. */ + if (((struct mips_extra_func_info *)f->value.value)->framesize) + return pc + 4; + + return pc; +} diff --git a/gdb/mipsread.c b/gdb/mipsread.c new file mode 100644 index 00000000000..2c7112f78cb --- /dev/null +++ b/gdb/mipsread.c @@ -0,0 +1,2879 @@ +/* Read a symbol table in MIPS' format (Third-Eye). + Copyright (C) 1986, 1987, 1989-1991 Free Software Foundation, Inc. + Contributed by Alessandro Forin (af@cs.cmu.edu) at CMU + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include "param.h" +#include "obstack.h" +#include +#include +#include +#include "defs.h" +#include "symtab.h" +#include "gdbcore.h" +#include "symfile.h" +#ifdef CMUCS +#include +#endif CMUCS + +/* Since these things are defined differently on various systems I'll + (re)define here what I really need in this module. I only assume the + three standard COFF structure definitions: filehdr, aouthdr, scnhdr */ +#define MIPS /* Kludge to get MIPS version of coff */ +#include "intel-coff.h" + +struct coff_exec { + struct filehdr f; + struct aouthdr a; +}; +#undef a_magic +#undef a_text +#undef a_data +#undef a_bss +#undef a_syms +#undef a_entry +#define a_magic a.magic /* magic number */ +#define a_text a.tsize /* size of text segment */ +#define a_data a.dsize /* size of initialized data */ +#define a_bss a.bsize /* size of uninitialized data */ +#define a_syms f.f_nsyms /* size of symbol table */ +#define a_entry a.entry /* entry point */ + +#undef N_BADMAG +#define N_BADMAG(x) \ + (((x).a_magic)!=OMAGIC && ((x).a_magic)!=NMAGIC && ((x).a_magic)!=ZMAGIC) + +/* Things we import explicitly from other modules */ + +extern int info_verbose; +extern struct block *block_for_pc(); +extern void sort_symtab_syms(); + +/* Forward declarations */ + +static void psymtab_to_symtab_1(); + +/* Macros and extra defs */ + +struct complaint unknown_ext_complaint = + {"unknown external symbol %s", 0, 0}; + +/* Already parsed symbols are marked specially */ + +#define stParsed stType + +/* Puns: hard to find whether -g was used and how */ + +#define MIN_GLEVEL GLEVEL_0 +#define compare_glevel(a,b) \ + (((a) == GLEVEL_3) ? ((b) < GLEVEL_3) : \ + ((b) == GLEVEL_3) ? -1 : (int)((b) - (a))) + +/* When looking at .o files avoid tripping over bad addresses */ + +#define SAFE_TEXT_ADDR 0x400000 +#define SAFE_DATA_ADDR 0x10000000 + +#define UNSAFE_DATA_ADDR(p) ((unsigned)p < SAFE_DATA_ADDR || (unsigned)p > 2*SAFE_DATA_ADDR) + + +/* Things we export to other modules */ + + +/* Lists of partial symbols */ + +struct psymbol_allocation_list global_psymbols, static_psymbols; + +/* Address bounds for the signal trampoline in inferior, if any */ + +CORE_ADDR sigtramp_address, sigtramp_end; + + +/* Functions that we really export */ + +/* THIS DESCRIPTION IS OBSOLETE POST-BFD; FIXME! */ +/* Basically, this module must provide two functions: symbol_file_command() + which loads the symbol table from a file, and add_file_command() which + adds more symbols to the symbol table (incrementally). + + These two functions only do the minimum work necessary for letting the + user "name" things symbolically, they do not read the entire symtab. + Instead, they read in the external symbols and put them in partial + symbol tables. When more extensive information is requested of a + file the corresponding partial symbol table is mutated into a full + fledged symbol table by going back and reading the relative symbols + for real. mipscoff_psymtab_to_symtab() is the function that does this */ + +/* The entry point (starting address) of the file, if it is an executable. */ + +static CORE_ADDR entry_point; + +extern CORE_ADDR startup_file_start; /* From blockframe.c */ +extern CORE_ADDR startup_file_end; /* From blockframe.c */ + +void +mipscoff_new_init() +{ +} + +void +mipscoff_symfile_init (sf) + struct sym_fns *sf; +{ + bfd *abfd = sf->sym_bfd; + sf->sym_private = NULL; + /* Save startup file's range of PC addresses to help blockframe.c + decide where the bottom of the stack is. */ + if (bfd_get_file_flags (abfd) & EXEC_P) + { + /* Executable file -- record its entry point so we'll recognize + the startup file because it contains the entry point. */ + entry_point = bfd_get_start_address (abfd); + } + else + { + /* Examination of non-executable.o files. Short-circuit this stuff. */ + /* ~0 will not be in any file, we hope. */ + entry_point = ~0; + /* set the startup file to be an empty range. */ + startup_file_start = 0; + startup_file_end = 0; + } +} + +void +mipscoff_symfile_read(sf, addr, mainline) + struct sym_fns *sf; + CORE_ADDR addr; + int mainline; +{ + struct coff_symfile_info *info = (struct coff_symfile_info *)sf->sym_private; + bfd *abfd = sf->sym_bfd; + char *name = bfd_get_filename (abfd); + int desc; + register int val; + int num_symbols; + int symtab_offset; + int stringtab_offset; + +/* WARNING WILL ROBINSON! ACCESSING BFD-PRIVATE DATA HERE! FIXME! */ + desc = fileno ((FILE *)(abfd->iostream)); /* Raw file descriptor */ + num_symbols = bfd_get_symcount (abfd); /* How many syms */ +/* symtab_offset = obj_sym_filepos (abfd); * Symbol table file offset */ +/* stringtab_offset = symtab_offset + num_symbols * SYMESZ; * String tab */ +/* End of warning */ + +#ifdef TDESC + debug_info = text_hdr.s_relptr; + if (tdesc_handle) + { + dc_terminate (tdesc_handle); + tdesc_handle = 0; + } +#endif + +#if 0 + /* Read the line number table, all at once. */ + info->min_lineno_offset = 0; + info->max_lineno_offset = 0; + bfd_map_over_sections (abfd, find_linenos, info); + + val = init_lineno (desc, info->min_lineno_offset, + info->max_lineno_offset - info->min_lineno_offset); + if (val < 0) + error ("\"%s\": error reading line numbers\n", name); + + /* Now read the string table, all at once. */ + + val = init_stringtab (desc, stringtab_offset); + if (val < 0) + { + free_all_symtabs (); /* FIXME blows whole symtab */ + printf ("\"%s\": can't get string table", name); + fflush (stdout); + return; + } + make_cleanup (free_stringtab, 0); +#endif + /* Position to read the symbol table. Do not read it all at once. */ + val = lseek (desc, (long)symtab_offset, 0); + if (val < 0) + perror_with_name (name); + + init_misc_bunches (); + make_cleanup (discard_misc_bunches, 0); + + /* Now that the executable file is positioned at symbol table, + process it and define symbols accordingly. */ + + printf("Reading symbol data from %s...", name); + fflush(stdout); + read_mips_symtab(desc, 0); + +/* patch_opaque_types ();*/ + + /* Sort symbols alphabetically within each block. */ + + sort_all_symtab_syms (); + + /* Go over the misc symbol bunches and install them in vector. */ + + condense_misc_bunches (0); + + /* Make a default for file to list. */ + + select_source_symtab (0); /* FIXME, this might be too slow, see dbxread */ +} + +void +mipscoff_symfile_discard() +{ +} + + +#if 0 +/* Exported procedure: Reads symbols from file NAME. + Invoked at startup time if executable was given. + When invoked cleans up the world */ + +void +symbol_file_command(name, from_tty) + char *name; + int from_tty; +{ + int desc; + struct coff_exec hdr; + register int val; + extern void close(); + struct cleanup *old_chain; + + dont_repeat(); + + /* + * Make sure s/he means it + */ + if (name == 0) { + if ((symtab_list || partial_symtab_list) + && from_tty + && !query("Discard symbol table? ", 0)) + error("Not confirmed."); + destroy_all_symtabs(); + return; + } + + name = tilde_expand(name); + make_cleanup(free, name); + + if (symtab_list && + !query("Load new symbol table from \"%s\"? ", name)) + error("Not confirmed."); + + /* Open the file */ + { + char *absolute_name; + desc = openp (getenv ("PATH"), 1, name, O_RDONLY, 0, &absolute_name); + if (desc < 0) + perror_with_name (name); + else + name = absolute_name; + } + + old_chain = make_cleanup (close, desc); + make_cleanup (free_current_contents, &name); + + /* + * Check file is indeed executable + */ + val = myread(desc, &hdr, sizeof hdr); + if (val < 0) + perror_with_name(name); + + if (N_BADMAG(hdr)) + error("File \"%s\" not in executable format.", name); + + if (hdr.a.entry < SAFE_TEXT_ADDR && access(name, 1)) + printf_filtered("Warning: %s is not executable!\n", name); + + if (hdr.a_syms == 0) { + printf_filtered("%s does not have a symbol-table.\n", name); + fflush(stdout); + return; + } + + /* Get the modification time. */ + { + struct stat symstat; + + if (fstat (desc, &symstat) < 0) + perror_with_name (name); + + symfile_mtime = symstat.st_mtime; + } + + /* + * Throw away the old symbol table. + */ + + destroy_all_symtabs(); + + /* Make a default for file to list. */ + + symfile = savestring (name, strlen (name)); + + /* Prepare to remember misc symbol values */ + + init_misc_bunches (); + make_cleanup (discard_misc_bunches, 0); + + /* + * Now read the new symbol table + */ + + read_mips_symtab(desc, 0); + + /* Go over the misc symbol bunches and install them in vector. */ + + condense_misc_bunches (0); + + /* Don't allow char * to have a typename (else would get caddr_t.) */ + + TYPE_NAME (lookup_pointer_type (builtin_type_char)) = 0; + + /* Force reinit of the sigtramp info */ + sigtramp_address = 0; + + do_cleanups (old_chain); /* Descriptor closed here */ + + if (!partial_symtab_list) + printf ("\n(no debugging symbols found)..."); + + printf ("done.\n"); + fflush(stdout); +} +#endif + +/* C++: + This function allows the addition of incrementally linked object files. + Since this has a fair amount of code in common with symbol_file_command, + it might be worthwhile to consolidate things, as was done with + read_dbx_symtab and condense_misc_bunches. */ + +/* Exported procedure: add more symbols from file NAME. */ + +void +add_file_command(arg_string) + char* arg_string; +{ + int desc; + struct coff_exec hdr; + register int val; + extern void close(); + struct cleanup *old_chain; + char *name; + unsigned text_addr; + + if (arg_string == 0) + error ("add-file takes a file name and an address"); + + if (arg_string == 0) + error ("add-file takes a file name and an address"); + + arg_string = tilde_expand (arg_string); + make_cleanup (free, arg_string); + + for( ; *arg_string == ' '; arg_string++ ); + name = arg_string; + for( ; *arg_string && *arg_string != ' ' ; arg_string++ ); + *arg_string++ = (char) 0; + + if (name[0] == 0) + error ("add-file takes a file name and an address"); + + text_addr = parse_and_eval_address (arg_string); + + dont_repeat(); + + if (!query ("add symbol table from filename \"%s\" at text_addr = 0x%x\n", + name, text_addr)) + error ("Not confirmed."); + + /* + * Open the file + */ + { + char *absolute_name; + + desc = openp(getenv("PATH"), 1, name, O_RDONLY, 0, &absolute_name); + if (desc < 0) + perror_with_name(name); + else + name = absolute_name; + } + old_chain = make_cleanup (close, desc); + + + /* + * Check file is indeed executable + */ + val = myread(desc, &hdr, sizeof hdr); + if (val < 0) + perror_with_name(name); + + if (N_BADMAG(hdr)) + error("File \"%s\" not in executable format.", name); + + if (hdr.a.entry < SAFE_TEXT_ADDR && access(name, 1)) + printf_filtered("Warning: %s is not executable!\n", name); + + if (hdr.a_syms == 0) { + printf_filtered("%s does not have a symbol-table.\n", name); + fflush(stdout); + return; + } + + if (symfile) + free(symfile); + symfile = 0; + + /* + * Now read the new symbol table + */ + + symfile = savestring(name, strlen(name)); + + init_misc_bunches (); + make_cleanup (discard_misc_bunches, 0); + read_mips_symtab(desc, 1); + + /* Go over the misc symbol bunches and install them in vector. */ + + condense_misc_bunches (1); + + /* Don't allow char * to have a typename (else would get caddr_t.) */ + + TYPE_NAME (lookup_pointer_type (builtin_type_char)) = 0; + + do_cleanups (old_chain); + + printf_filtered("done.\n"); + fflush(stdout); +} + +/* Exported procedure: Allocate zeroed memory */ + +char *xzalloc(size) +{ + char *p = xmalloc(size); + + bzero(p, size); + return p; +} + +/* Exported procedure: Builds a symtab from the PST partial one. + Restores the environment in effect when PST was created, delegates + most of the work to an ancillary procedure, and sorts + and reorders the symtab list at the end */ + +/* Forward decls */ +static HDRR *cur_hdr; /* MIPS symtab header for the current file */ + +void +mipscoff_psymtab_to_symtab(pst) + struct partial_symtab *pst; +{ + struct symtab *ret; + int i; + + if (!pst) + return; + + if (info_verbose) { + printf_filtered("Reading in symbols for %s...", pst->filename); + fflush(stdout); + } + /* Restore the header and list of pending typedefs */ + cur_hdr = (HDRR *) pst->ldsymlen; + + psymtab_to_symtab_1(pst); + + reorder_symtabs(); + + /* Finish up the debug error message. */ + if (info_verbose) + printf_filtered("done.\n"); +} + +/* Exported procedure: Is PC in the signal trampoline code */ + +int in_sigtramp(pc,name) + CORE_ADDR pc; +{ + if (sigtramp_address == 0) + fixup_sigtramp(); + return (pc >= sigtramp_address && pc < sigtramp_end); +} + + +/* Things that really are local to this module */ + +/* All allocated symtabs and psymtabs */ + +static int all_symtabs_count; +static int all_psymtabs_count; + +/* GDB symtable for the current compilation unit */ + +static struct symtab *cur_stab; + +/* Header for executable/object file we read symbols from */ + +static struct coff_exec filhdr; +#define END_OF_TEXT_SEGMENT(f) ((f).a.text_start + (f).a.tsize) + +/* Pointer to current file decriptor record, and its index */ + +static FDR *cur_fdr; +static int cur_fd; + +/* Index of current symbol */ + +static int cur_sdx; + +/* Note how much "debuggable" this image is. We would like + to see at least one FDR with full symbols */ + +static max_gdbinfo; +static max_glevel; + +/* When examining .o files, report on undefined symbols */ + +static int n_undef_symbols, n_undef_labels, n_undef_vars, n_undef_procs; + +/* Extra builtin types */ + +struct type *builtin_type_complex; +struct type *builtin_type_double_complex; +struct type *builtin_type_fixed_dec; +struct type *builtin_type_float_dec; +struct type *builtin_type_string; + +/* Template types */ + +static struct type *builtin_type_ptr; +static struct type *builtin_type_struct; +static struct type *builtin_type_union; +static struct type *builtin_type_enum; +static struct type *builtin_type_range; +static struct type *builtin_type_set; + + +/* Forward decls */ + +static struct symbol *new_symbol(); +static struct type *new_type(); +static struct field *new_field(); +static struct block *new_block(); +static struct symtab *new_symtab(); +static struct linetable *new_linetable(); +static struct blockvector *new_bvect(); + +static struct type *parse_type(); +static struct type *make_type(); +static struct symbol *mylookup_symbol(); +static struct block *shrink_block(); + +static int compare_symtabs(); +static int compare_psymtabs(); +static int compare_blocks(); + +static struct partial_symtab *new_psymtab(); +static struct partial_symbol *new_psymbol(); +static struct partial_symtab *parse_fdr(); +static int compare_psymbols(); + +/* File-level interface functions */ + +/* Read the symtab information from file FSYM into memory */ + +static +read_the_mips_symtab(fsym) +{ + int stsize, st_hdrsize; + unsigned st_filptr; + HDRR st_hdr; + + /* Find and read the symbol table header */ + st_hdrsize = filhdr.f.f_nsyms; + st_filptr = filhdr.f.f_symptr; + if (st_filptr == 0) + return 0; + + lseek(fsym, st_filptr, L_SET); + if (read(fsym, &st_hdr, st_hdrsize) != st_hdrsize) + goto readerr; + + /* Find out how large the symbol table is */ + stsize = (st_hdr.cbExtOffset - (st_filptr + st_hdrsize)) + + st_hdr.iextMax * cbEXTR; + + /* Allocate space for the symbol table. Read it in. */ + cur_hdr = (HDRR *) xmalloc(stsize + st_hdrsize); + + bcopy(&st_hdr, cur_hdr, st_hdrsize); + if (read(fsym, (char *) cur_hdr + st_hdrsize, stsize) != stsize) + goto readerr; + + /* Fixup file_pointers in it */ + fixup_symtab(cur_hdr, (char *) cur_hdr + st_hdrsize, + st_filptr + st_hdrsize); + + return; +readerr: + error("Short read on %s", symfile); +} + + +/* Turn all file-relative pointers in the symtab described by HDR + into memory pointers, given that the symtab itself is located + at DATA in memory and F_PTR in the file. */ + +static +fixup_symtab( hdr, data, f_ptr) + HDRR *hdr; + char *data; +{ + int f_idx, s_idx; + FDR *fh; + SYMR *sh; + OPTR *op; + PDR *pr; + EXTR *esh; + + /* + * These fields are useless (and empty) by now: + * hdr->cbDnOffset, hdr->cbOptOffset + * We use them for other internal purposes. + */ + hdr->cbDnOffset = 0; + hdr->cbOptOffset = 0; + +#define FIX(off) \ + if (hdr->off) hdr->off = (unsigned int)data + (hdr->off - f_ptr); + + FIX(cbLineOffset); + FIX(cbPdOffset); + FIX(cbSymOffset); + FIX(cbOptOffset); + FIX(cbAuxOffset); + FIX(cbSsOffset); + FIX(cbSsExtOffset); + FIX(cbFdOffset); + FIX(cbRfdOffset); + FIX(cbExtOffset); +#undef FIX + + + /* + * Fix all string pointers inside the symtab, and + * the FDR records. Also fix other miscellany. + */ + for (f_idx = 0; f_idx < hdr->ifdMax; f_idx++) { + register unsigned code_offset; + + /* Header itself, and strings */ + fh = (FDR *) (hdr->cbFdOffset) + f_idx; + fh->issBase += hdr->cbSsOffset; + if (fh->rss != -1) + fh->rss = (long)fh->rss + fh->issBase; + for (s_idx = 0; s_idx < fh->csym; s_idx++) { + sh = (SYMR*)(hdr->cbSymOffset) + fh->isymBase + s_idx; + sh->iss = (long) sh->iss + fh->issBase; + sh->reserved = 0; + } + + cur_fd = f_idx; + + /* Local symbols */ + fh->isymBase = (int)((SYMR*)(hdr->cbSymOffset)+fh->isymBase); + + /* cannot fix fh->ipdFirst because it is a short */ +#define IPDFIRST(h,fh) \ + ((long)h->cbPdOffset + fh->ipdFirst * sizeof(PDR)) + + /* Optional symbols (actually used for partial_symtabs) */ + fh->ioptBase = 0; + fh->copt = 0; + + /* Aux symbols */ + if (fh->caux) + fh->iauxBase = hdr->cbAuxOffset + fh->iauxBase * sizeof(AUXU); + /* Relative file descriptor table */ + fh->rfdBase = hdr->cbRfdOffset + fh->rfdBase * sizeof(RFDT); + + /* Line numbers */ + if (fh->cbLine) + fh->cbLineOffset += hdr->cbLineOffset; + + /* Procedure symbols. (XXX This should be done later) */ + code_offset = fh->adr; + for (s_idx = 0; s_idx < fh->cpd; s_idx++) { + unsigned name, only_ext; + + pr = (PDR*)(IPDFIRST(hdr,fh)) + s_idx; + + /* Simple rule to find files linked "-x" */ + only_ext = fh->rss == -1; + if (only_ext) { + if (pr->isym == -1) { + /* static function */ + sh = (SYMR*)-1; + } else { + /* external */ + name = hdr->cbExtOffset + pr->isym * sizeof(EXTR); + sh = &((EXTR*)name)->asym; + } + } else { + /* Full symbols */ + sh = (SYMR*)fh->isymBase + pr->isym; + /* Included code ? */ + if (s_idx == 0 && pr->adr != 0) + code_offset -= pr->adr; + } + + /* Turn index into a pointer */ + pr->isym = (long)sh; + + /* Fix line numbers */ + pr->cbLineOffset += fh->cbLineOffset; + + /* Relocate address */ + if (!only_ext) + pr->adr += code_offset; + } + } + + /* External symbols: fix string */ + for (s_idx = 0; s_idx < hdr->iextMax; s_idx++) { + esh = (EXTR*)(hdr->cbExtOffset) + s_idx; + esh->asym.iss = esh->asym.iss + hdr->cbSsExtOffset; + } +} + + +/* Find a file descriptor given its index RF relative to a file CF */ + +static +FDR *get_rfd( cf, rf) +{ + register FDR *f; + + f = (FDR *) (cur_hdr->cbFdOffset) + cf; + /* Object files do not have the RFD table, all refs are absolute */ + if (f->rfdBase == 0) + return (FDR *) (cur_hdr->cbFdOffset) + rf; + cf = *((pRFDT) f->rfdBase + rf); + return (FDR *) (cur_hdr->cbFdOffset) + cf; +} + +/* Return a safer print NAME for a file descriptor */ + +static +char *fdr_name(name) + char *name; +{ + if (name == (char *) -1) + return ""; + if (UNSAFE_DATA_ADDR(name)) + return ""; + return name; +} + + +/* Read in and parse the symtab of the file DESC. INCREMENTAL says + whether we are adding to the general symtab or not */ + +static +read_mips_symtab( desc, incremental) +{ + /* + * We get here with DESC pointing to the symtab header. But we need + * other info from the initial headers + */ + lseek(desc, 0L, 0); + myread(desc, &filhdr, sizeof filhdr); + + read_the_mips_symtab(desc); + + parse_partial_symbols(cur_hdr, incremental); + cur_hdr = 0; + + /* + * Check to make sure file was compiled with -g. + * If not, warn the user of this limitation. + */ + if (compare_glevel(max_glevel, GLEVEL_2) < 0) { + if (max_gdbinfo == 0) + printf("\n%s not compiled with -g, debugging support is limited.", symfile); + printf("\nYou should compile with -g2 or -g3 for best debugging support.\n"); + fflush(stdout); + } + + /* + * Dont allow char * to have a typename (else would get + * caddr_t.) + */ + TYPE_NAME(lookup_pointer_type(builtin_type_char)) = 0; +} + + +/* Local utilities */ + + +/* Map of FDR indexes to partial symtabs */ + +static struct pst_map { + struct partial_symtab *pst; /* the psymtab proper */ + int n_globals; /* globals it exports */ +} * fdr_to_pst; + + +/* Utility stack, used to nest procedures and blocks properly. + It is a doubly linked list, to avoid too many alloc/free. + Since we might need it quite a few times it is NOT deallocated + after use. */ + +static struct parse_stack { + struct parse_stack *next, *prev; + struct symtab *cur_st; /* Current symtab */ + struct block *cur_block; /* Block in it */ + int blocktype; /* What are we parsing */ + int maxsyms; /* Max symbols in this block */ + struct type *cur_type; /* Type we parse fields for */ + int procadr; /* Start addres of this procedure */ + int numargs; /* Its argument count */ +} *top_stack; /* Top stack ptr */ + + +/* Enter a new lexical context */ + +static push_parse_stack() +{ + struct parse_stack *new; + + /* Reuse frames if possible */ + if (top_stack && top_stack->prev) + new = top_stack->prev; + else + new = (struct parse_stack *) xzalloc(sizeof(struct parse_stack)); + /* Initialize new frame with previous content */ + if (top_stack) { + register struct parse_stack *prev = new->prev; + + *new = *top_stack; + top_stack->prev = new; + new->prev = prev; + new->next = top_stack; + } + top_stack = new; +} + +/* Exit a lexical context */ + +static pop_parse_stack() +{ + if (!top_stack) + return; + if (top_stack->next) + top_stack = top_stack->next; +} + + +/* Cross-references might be to things we haven't looked at + yet, e.g. type references. To avoid too many type + duplications we keep a quick fixup table, an array + of lists of references indexed by file descriptor */ + +static struct pending { + struct pending *next; /* link */ + SYMR *s; /* the symbol */ + struct type *t; /* its partial type descriptor */ +} **pending_list; + + +/* Check whether we already saw symbol SH in file FH as undefined */ + +static +struct pending *is_pending_symbol(fh, sh) + FDR *fh; + SYMR *sh; +{ + int f_idx = fh - (FDR *) cur_hdr->cbFdOffset; + register struct pending *p; + + /* Linear search is ok, list is typically no more than 10 deep */ + for (p = pending_list[f_idx]; p; p = p->next) + if (p->s == sh) + break; + return p; +} + +/* Check whether we already saw type T in file FH as undefined */ + +static +struct pending *is_pending_type(fh, t) + FDR *fh; + struct type *t; +{ + int f_idx = fh - (FDR *) cur_hdr->cbFdOffset; + register struct pending *p; + + for (p = pending_list[f_idx]; p; p = p->next) + if (p->t == t) + break; + return p; +} + +/* Add a new undef symbol SH of type T */ + +static +add_pending(fh, sh, t) + FDR *fh; + SYMR *sh; + struct type *t; +{ + int f_idx = fh - (FDR *) cur_hdr->cbFdOffset; + struct pending *p = is_pending_symbol(fh, sh); + + /* Make sure we do not make duplicates */ + if (!p) { + p = (struct pending *) xmalloc(sizeof(*p)); + p->s = sh; + p->t = t; + p->next = pending_list[f_idx]; + pending_list[f_idx] = p; + } + sh->reserved = 1; /* for quick check */ +} + +/* Throw away undef entries when done with file index F_IDX */ + +static +free_pending(f_idx) +{ + register struct pending *p, *q; + + for (p = pending_list[f_idx]; p; p = q) { + q = p->next; + free(p); + } + pending_list[f_idx] = 0; +} + +/* The number of args to a procedure is not explicit in the symtab, + this is the list of all those we know of. + This makes parsing more reasonable and avoids extra passes */ + +static struct numarg { + struct numarg *next; /* link */ + unsigned adr; /* procedure's start address */ + unsigned num; /* arg count */ +} *numargs_list; + +/* Record that the procedure at ADR takes NUM arguments. */ + +static +got_numargs(adr,num) +{ + struct numarg *n = (struct numarg *) xmalloc(sizeof(struct numarg)); + + n->adr = adr; + n->num = num; + n->next = numargs_list; + numargs_list = n; +} + +/* See if we know how many arguments the procedure at ADR takes */ + +static +lookup_numargs(adr) +{ + struct numarg *n = numargs_list; + + while (n && n->adr != adr) + n = n->next; + return (n) ? n->num : -1; +} + +/* Release storage when done with this file */ + +static +free_numargs() +{ + struct numarg *n = numargs_list, *m; + + while (n) { + m = n->next; + free(n); + n = m; + } + numargs_list = 0; +} + + +/* Parsing Routines proper. */ + +/* Parse a single symbol. Mostly just make up a GDB symbol for it. + For blocks, procedures and types we open a new lexical context. + This is basically just a big switch on the symbol's type */ + +static +parse_symbol(sh, ax) + SYMR *sh; + AUXU *ax; +{ + struct symbol *s; + struct block *b; + struct type *t; + struct field *f; + /* When a symbol is cross-referenced from other files/symbols + we mark it explicitly */ + int pend = (sh->reserved == 1); + enum address_class class; + + switch (sh->st) { + + case stNil: + break; + + case stGlobal: /* external symbol, goes into the primary block */ + class = LOC_STATIC; + b = BLOCKVECTOR_BLOCK(BLOCKVECTOR(top_stack->cur_st), 0); + goto data; + + case stStatic: /* static data, goes into the current block. */ + class = LOC_STATIC; + b = top_stack->cur_block; + goto data; + + case stLocal: /* local variable, goes into the current block */ + if (sh->sc == scRegister) { + class = LOC_REGISTER; + if (sh->value > 31) + sh->value += 6; + } else + class = LOC_LOCAL; + b = top_stack->cur_block; + +data: /* Common code for symbols describing data */ + s = new_symbol(sh->iss); + SYMBOL_NAMESPACE(s) = VAR_NAMESPACE; + SYMBOL_CLASS(s) = class; + add_symbol(s, b); + + /* Type could be missing in a number of cases */ + if (sh->sc == scUndefined || sh->sc == scNil || + sh->index == 0xfffff) + SYMBOL_TYPE(s) = builtin_type_int; /* undefined? */ + else + SYMBOL_TYPE(s) = parse_type(ax + sh->index, sh, 0); + /* Value of a data symbol is its memory address */ + SYMBOL_VALUE(s) = sh->value; + break; + + case stParam: /* argument to procedure, goes into current block */ + max_gdbinfo++; + top_stack->numargs++; + s = new_symbol(sh->iss); + SYMBOL_NAMESPACE(s) = VAR_NAMESPACE; + if (sh->sc == scRegister) { + SYMBOL_CLASS(s) = LOC_REGPARM; + if (sh->value > 31) + sh->value += 6; + } else + SYMBOL_CLASS(s) = LOC_ARG; + SYMBOL_VALUE(s) = sh->value; + SYMBOL_TYPE(s) = parse_type(ax + sh->index, sh, 0); + add_symbol(s, top_stack->cur_block); + break; + + case stLabel: /* label, we do make a symbol for it */ + s = new_symbol(sh->iss); + SYMBOL_NAMESPACE(s) = VAR_NAMESPACE; /* so that it can be used */ + SYMBOL_CLASS(s) = LOC_LABEL; /* but not misused */ + SYMBOL_VALUE(s) = sh->value; + SYMBOL_TYPE(s) = builtin_type_int; + add_symbol(s, top_stack->cur_block); + break; + + case stProc: /* Procedure */ + case stStaticProc: /* Static procedure */ + s = new_symbol(sh->iss); + SYMBOL_NAMESPACE(s) = VAR_NAMESPACE; + SYMBOL_CLASS(s) = LOC_BLOCK; + /* Type of the return value */ + if (sh->sc == scUndefined || sh->sc == scNil) + t = builtin_type_int; + else + t = parse_type(ax + sh->index, sh, 0); + add_symbol(s, top_stack->cur_block); + + /* Make a type for the procedure itself */ + SYMBOL_TYPE(s) = lookup_function_type (t); + + /* Create and enter a new lexical context */ + b = new_block(top_stack->maxsyms); + SYMBOL_BLOCK_VALUE(s) = b; + BLOCK_FUNCTION(b) = s; + BLOCK_START(b) = BLOCK_END(b) = sh->value; + BLOCK_SUPERBLOCK(b) = top_stack->cur_block; + add_block(b, top_stack->cur_st); + + /* Not if we only have partial info */ + if (sh->sc == scUndefined || sh->sc == scNil) + break; + + push_parse_stack(); + top_stack->cur_block = b; + top_stack->blocktype = sh->st; + top_stack->cur_type = SYMBOL_TYPE(s); + top_stack->procadr = sh->value; + top_stack->numargs = 0; + + sh->value = (long) SYMBOL_TYPE(s); + break; + + case stBlock: /* Either a lexical block, or some type */ + push_parse_stack(); + top_stack->blocktype = stBlock; + if (sh->sc == scInfo) { /* structure/union/enum def */ + s = new_symbol(sh->iss); + SYMBOL_NAMESPACE(s) = STRUCT_NAMESPACE; + SYMBOL_CLASS(s) = LOC_TYPEDEF; + SYMBOL_VALUE(s) = 0; + add_symbol(s, top_stack->cur_block); + /* If this type was expected, use its partial definition */ + if (pend) { + t = is_pending_symbol(cur_fdr, sh)->t; + } else { + /* Uhmm, can`t decide yet. Smash later */ + t = new_type(sh->iss); + TYPE_CODE(t) = TYPE_CODE_UNDEF; + add_pending(cur_fdr, sh, t); + } + SYMBOL_TYPE(s) = t; + /* make this the current type */ + top_stack->cur_type = t; + TYPE_LENGTH(t) = sh->value; + /* Mark that symbol has a type, and say which one */ + sh->value = (long) t; + } else { + /* beginnning of (code) block. Value of symbol + is the displacement from procedure start */ + b = new_block(top_stack->maxsyms); + BLOCK_START(b) = sh->value + top_stack->procadr; + BLOCK_SUPERBLOCK(b) = top_stack->cur_block; + top_stack->cur_block = b; + add_block(b, top_stack->cur_st); + } + break; + + case stEnd: /* end (of anything) */ + if (sh->sc == scInfo) { + /* Finished with type */ + top_stack->cur_type = 0; + } else if (sh->sc == scText && + (top_stack->blocktype == stProc || + top_stack->blocktype == stStaticProc)) { + /* Finished with procedure */ + struct blockvector *bv = BLOCKVECTOR(top_stack->cur_st); + struct block *b; + int i; + + BLOCK_END(top_stack->cur_block) += sh->value; /* size */ + got_numargs(top_stack->procadr, top_stack->numargs); + /* Reallocate symbols, saving memory */ + b = shrink_block(top_stack->cur_block, top_stack->cur_st); + + /* f77 emits proc-level with address bounds==[0,0], + So look for such child blocks, and patch them. */ + for (i = 0; i < BLOCKVECTOR_NBLOCKS(bv); i++) { + struct block *b_bad = BLOCKVECTOR_BLOCK(bv,i); + if (BLOCK_SUPERBLOCK(b_bad) == b + && BLOCK_START(b_bad) == top_stack->procadr + && BLOCK_END(b_bad) == top_stack->procadr) { + BLOCK_START(b_bad) = BLOCK_START(b); + BLOCK_END(b_bad) = BLOCK_END(b); + } + } + } else if (sh->sc == scText && top_stack->blocktype == stBlock) { + /* End of (code) block. The value of the symbol + is the displacement from the procedure`s start + address of the end of this block. */ + BLOCK_END(top_stack->cur_block) = sh->value + top_stack->procadr; + (void) shrink_block(top_stack->cur_block, top_stack->cur_st); + } + pop_parse_stack(); /* restore previous lexical context */ + break; + + case stMember: /* member of struct/union/enum.. */ + f = new_field(top_stack->cur_type, sh->iss); + f->bitpos = sh->value; + f->type = parse_type(ax + sh->index, sh, &f->bitsize); + break; + + case stTypedef: /* type definition */ + s = new_symbol(sh->iss); + SYMBOL_NAMESPACE(s) = VAR_NAMESPACE; + SYMBOL_CLASS(s) = LOC_TYPEDEF; + SYMBOL_BLOCK_VALUE(s) = top_stack->cur_block; + add_symbol(s, top_stack->cur_block); + SYMBOL_TYPE(s) = parse_type(ax + sh->index, sh, 0); + sh->value = (long) SYMBOL_TYPE(s); + break; + + case stFile: /* file name */ + push_parse_stack(); + top_stack->blocktype = sh->st; + break; + + /* I`ve never seen these for C */ + case stRegReloc: + break; /* register relocation */ + case stForward: + break; /* forwarding address */ + case stConstant: + break; /* constant */ + default: + error("Unknown symbol type %x.", sh->st); + } + sh->st = stParsed; +} + +/* Parse the type information provided in the AX entries for + the symbol SH. Return the bitfield size in BS, in case. */ + +static struct type *parse_type(ax, sh, bs) + AUXU *ax; + SYMR *sh; + int *bs; +{ + /* Null entries in this map are treated specially */ + static struct type **map_bt[] = + { + &builtin_type_void, /* btNil */ + 0, /* btAdr */ + &builtin_type_char, /* btChar */ + &builtin_type_unsigned_char, /* btUChar */ + &builtin_type_short, /* btShort */ + &builtin_type_unsigned_short, /* btUShort */ + &builtin_type_int, /* btInt */ + &builtin_type_unsigned_int, /* btUInt */ + &builtin_type_long, /* btLong */ + &builtin_type_unsigned_long, /* btULong */ + &builtin_type_float, /* btFloat */ + &builtin_type_double, /* btDouble */ + 0, /* btStruct */ + 0, /* btUnion */ + 0, /* btEnum */ + 0, /* btTypedef */ + 0, /* btRange */ + 0, /* btSet */ + &builtin_type_complex, /* btComplex */ + &builtin_type_double_complex, /* btDComplex */ + 0, /* btIndirect */ + &builtin_type_fixed_dec, /* btFixedDec */ + &builtin_type_float_dec, /* btFloatDec */ + &builtin_type_string, /* btString */ + 0, /* btBit */ + 0, /* btPicture */ + &builtin_type_void, /* btVoid */ + }; + + TIR *t; + struct type *tp = 0, *tp1; + char *fmt = "%s"; + + /* Procedures start off by one */ + if (sh->st == stProc || sh->st == stStaticProc) + ax++; + + /* Undefined ? Should not happen */ + if (ax->rndx.rfd == 0xfff) { + return builtin_type_void; + } + + /* Use aux as a type information record, map its basic type */ + t = &ax->ti; + if (t->bt > 26 || t->bt == btPicture) { + printf_filtered("Internal: cannot map MIPS basic type x%x\n", t->bt); + return builtin_type_int; + } + if (map_bt[t->bt]) + tp = *map_bt[t->bt]; + else { + /* Cannot use builtin types, use templates */ + tp = make_type(TYPE_CODE_VOID, 0, 0, 0); + switch (t->bt) { + case btAdr: + *tp = *builtin_type_ptr; + break; + case btStruct: + *tp = *builtin_type_struct; + fmt = "struct %s"; + break; + case btUnion: + *tp = *builtin_type_union; + fmt = "union %s"; + break; + case btEnum: + *tp = *builtin_type_enum; + fmt = "enum %s"; + break; + case btRange: + *tp = *builtin_type_range; + break; + case btSet: + *tp = *builtin_type_set; + fmt = "set %s"; + break; + } + } + + /* Move on to next aux */ + ax++; + if (t->continued) { + /* This is the way it would work if the compiler worked */ + register TIR *t1 = t; + while (t1->continued) + ax++; + } + + /* For bitfields all we need is the width */ + if (t->fBitfield) { + *bs = ax->width; + return tp; + } + + /* All these types really point to some (common) MIPS type + definition, and only the type-qualifiers fully identify + them. We`ll make the same effort at sharing */ + if (t->bt == btIndirect || + t->bt == btStruct || + t->bt == btUnion || + t->bt == btEnum || + t->bt == btTypedef || + t->bt == btRange || + t->bt == btSet) { + char name[256], *pn; + + /* Try to cross reference this type */ + tp1 = tp; + ax += cross_ref(ax, &tp1, &pn); + /* SOMEONE OUGHT TO FIX DBXREAD TO DROP "STRUCT" */ + sprintf(name, fmt, pn); + + /* reading .o file ? */ + if (UNSAFE_DATA_ADDR(tp1)) + tp1 = tp; + if (TYPE_CODE(tp1) == TYPE_CODE_UNDEF) { + /* + * Type was incompletely defined, now we know. + */ + TYPE_CODE(tp1) = TYPE_CODE(tp); + TYPE_NAME(tp1) = obsavestring(name, strlen(name)); + if (TYPE_CODE(tp1) == TYPE_CODE_ENUM) { + int i; + + for (i = 0; i < TYPE_NFIELDS(tp1); i++) + make_enum_constant(&TYPE_FIELD(tp1,i), tp1); + } + } + if (tp1 != tp) { + /* found as cross ref, rid of our template */ + if ((TYPE_FLAGS(tp) & TYPE_FLAG_PERM) == 0) + free(tp); + tp = tp1; + /* stupid idea of prepending "struct" to type names */ + if (t->bt == btStruct && !index(TYPE_NAME(tp), ' ')) { + sprintf(name, fmt, TYPE_NAME(tp)); + TYPE_NAME(tp) = obsavestring(name, strlen(name)); + } + } else + TYPE_NAME(tp) = savestring(name, strlen(name)); + } + + /* Deal with range types */ + if (t->bt == btRange) { + struct field *f; + + f = new_field(tp, "Low"); + f->bitpos = ax->dnLow; + ax++; + f = new_field(tp, "High"); + f->bitpos = ax->dnHigh; + ax++; + } + + /* Parse all the type qualifiers now. If there are more + than 6 the game will continue in the next aux */ + +#define PARSE_TQ(tq) \ + if (t->tq != tqNil) ax += upgrade_type(&tp, t->tq, ax, sh); + +again: PARSE_TQ(tq0); + PARSE_TQ(tq1); + PARSE_TQ(tq2); + PARSE_TQ(tq3); + PARSE_TQ(tq4); + PARSE_TQ(tq5); +#undef PARSE_TQ + + if (t->continued) { + t++; + goto again; + } + return tp; +} + +/* Make up a complex type from a basic one. Type is passed by + reference in TPP and side-effected as necessary. The type + qualifier TQ says how to handle the aux symbols at AX for + the symbol SX we are currently analyzing. + Returns the number of aux symbols we parsed. */ + +static +upgrade_type(tpp, tq, ax, sh) + struct type **tpp; + AUXU *ax; + SYMR *sh; +{ + int off = 0; + int ret = 0; + struct type *t; + + if (tq == tqPtr) { + t = lookup_pointer_type (*tpp); + } else if (tq == tqProc) { + t = lookup_function_type (*tpp); + } else if (tq == tqArray) { + int rf, id; + FDR *fh; + struct field *f; + SYMR ss; + + t = make_type(TYPE_CODE_ARRAY, 0, 0, 0); + TYPE_TARGET_TYPE(t) = *tpp; + + /* Pointer to domain type (type of index) */ + id = ax->rndx.index; + if ((rf = ax->rndx.rfd) == 0xfff) + rf = (++ax)->isym, off++; + + fh = get_rfd(cur_fd, rf); + f = new_field(t, 0); + bzero(&ss, sizeof ss); +/* XXX */ f->type = parse_type(fh->iauxBase + id * sizeof(AUXU), + &ss, &f->bitsize); + + /* + * This seems to be a pointer to the end of the Block defining + * the type. Why it is here is magic for me, and I have no + * good use for it anyways. + */ + if (off == 0) { + off++; + id = (++ax)->rndx.index; + if ((rf = ax->rndx.rfd) == 0xfff) + rf = (++ax)->isym, off++; + } + f->bitpos = (++ax)->dnLow; /* ?? */ + f->bitsize = (++ax)->dnHigh; /* ?? */ + rf = (++ax)->width - 1; /* bit alignment */ + id = TYPE_LENGTH(TYPE_TARGET_TYPE(t)) << 3; /* bitsize */ + + if (id == 0) { + /* Most likely an undefined type */ + id = rf + 1; + TYPE_LENGTH(TYPE_TARGET_TYPE(t)) = id >> 3; + } + TYPE_LENGTH(t) = (f->bitsize < 0) ? 0 : + (f->bitsize - f->bitpos + 1) * (id >> 3); + ret = 4 + off; + } else { + if (tq != tqVol) + printf_filtered("Internal: unknown type qualifier %x\n", tq); + return ret; + } + + *tpp = t; + return ret; +} + + +/* Parse a procedure descriptor record PR. Note that the procedure + is parsed _after_ the local symbols, now we just make up the + extra information we need into a special symbol that we insert + in the procedure's main block. Note also that images that + have been partially stripped (ld -x) have been deprived + of local symbols, and we have to cope with them here. + The procedure's code ends at BOUND */ + +static +parse_procedure(pr, bound) + PDR *pr; +{ + struct symbol *s, *i; + SYMR *sh = (SYMR*)pr->isym; + struct block *b; + struct mips_extra_func_info *e; + char name[100]; + char *sh_name; + + /* Reuse the MIPS record */ + e = (struct mips_extra_func_info *) pr; + e->numargs = lookup_numargs(pr->adr); + + /* Make up our special symbol */ + i = new_symbol(".gdbinfo."); + SYMBOL_VALUE(i) = (int)e; + SYMBOL_NAMESPACE(i) = LABEL_NAMESPACE; + SYMBOL_CLASS(i) = LOC_CONST; + SYMBOL_TYPE(i) = builtin_type_void; + + /* Make up a name for static procedures. Sigh. */ + if (sh == (SYMR*)-1) { + sprintf(name,".static_procedure@%x",pr->adr); + sh_name = savestring(name, strlen(name)); + s = NULL; + } + else { + sh_name = (char*)sh->iss; + s = mylookup_symbol(sh_name, top_stack->cur_block, + VAR_NAMESPACE, LOC_BLOCK); + } + if (s != 0) { + b = SYMBOL_BLOCK_VALUE(s); + } else { + s = new_symbol(sh_name); + SYMBOL_NAMESPACE(s) = VAR_NAMESPACE; + SYMBOL_CLASS(s) = LOC_BLOCK; + /* Donno its type, hope int is ok */ + SYMBOL_TYPE(s) = lookup_function_type (builtin_type_int); + add_symbol(s, top_stack->cur_block); + /* Wont have symbols for this one */ + b = new_block(2); + SYMBOL_BLOCK_VALUE(s) = b; + BLOCK_FUNCTION(b) = s; + BLOCK_START(b) = pr->adr; + BLOCK_END(b) = bound; + BLOCK_SUPERBLOCK(b) = top_stack->cur_block; + add_block(b, top_stack->cur_st); + } + e->isym = (long)s; + add_symbol(i,b); +} + +/* Parse the external symbol ES. Just call parse_symbol() after + making sure we know where the aux are for it. For procedures, + parsing of the PDRs has already provided all the needed + information, we only parse them if SKIP_PROCEDURES is false, + and only if this causes no symbol duplication */ + +static +parse_external(es, skip_procedures) + EXTR *es; +{ + AUXU *ax; + + if (es->ifd != ifdNil) { + cur_fd = es->ifd; + cur_fdr = (FDR*)(cur_hdr->cbFdOffset) + cur_fd; + ax = (AUXU*)cur_fdr->iauxBase; + } else { + cur_fdr = (FDR*)(cur_hdr->cbFdOffset); + ax = 0; + } + top_stack->cur_st = cur_stab; + top_stack->cur_block = BLOCKVECTOR_BLOCK(BLOCKVECTOR(top_stack->cur_st),0); + + /* Reading .o files */ + if (es->asym.sc == scUndefined || es->asym.sc == scNil) { + char *what; + switch (es->asym.st) { + case stStaticProc: + case stProc: what = "Procedure"; n_undef_procs++; break; + case stGlobal: what = "Variable"; n_undef_vars++; break; + case stLabel: what = "Label"; n_undef_labels++; break; + default : what = "Symbol"; break; + } + n_undef_symbols++; + if (info_verbose) + printf_filtered("Warning: %s %s is undefined (in %s)\n", what, + es->asym.iss, fdr_name(cur_fdr->rss)); + return; + } + + switch (es->asym.st) { + case stProc: + /* If we have full symbols we do not need more */ + if (skip_procedures) + return; + if (mylookup_symbol (es->asym.iss, top_stack->cur_block, + VAR_NAMESPACE, LOC_BLOCK)) + break; + /* fall through */ + case stGlobal: + case stLabel: + /* + * Note that the case of a symbol with indexNil + * must be handled anyways by parse_symbol(). + */ + parse_symbol(&es->asym, ax); + break; + default: + break; + } +} + +/* Parse the line number info for file descriptor FH into + GDB's linetable LT. MIPS' encoding requires a little bit + of magic to get things out. Note also that MIPS' line + numbers can go back and forth, apparently we can live + with that and do not need to reorder our linetables */ + +static +parse_lines(fh, lt) + FDR *fh; + struct linetable *lt; +{ + char *base = (char*)fh->cbLineOffset; + int i, j, k; + int delta, count, lineno = 0; + PDR *pr; + + if (base == 0) + return; + + /* Scan by procedure descriptors */ + i = 0; j = 0, k = 0; + for (pr = (PDR*)IPDFIRST(cur_hdr,fh); j < fh->cpd; j++, pr++) { + int l, halt; + + /* No code for this one */ + if (pr->iline == ilineNil || + pr->lnLow == -1 || pr->lnHigh == -1) + continue; + /* + * Aurgh! To know where to stop expanding we + * must look-ahead. + */ + for (l = 1; l < (fh->cpd - j); l++) + if (pr[l].iline != -1) + break; + if (l == (fh->cpd - j)) + halt = fh->cline; + else + halt = pr[l].iline; + /* + * When procedures are moved around the linenumbers + * are attributed to the next procedure up + */ + if (pr->iline >= halt) continue; + + base = (char*)pr->cbLineOffset; + l = pr->adr >> 2; /* in words */ + halt += (pr->adr >> 2) - pr->iline; + for (lineno = pr->lnLow; l < halt;) { + count = *base & 0x0f; + delta = *base++ >> 4; + if (delta == -8) { + delta = (base[0] << 8) | (base[1] & 0xff); + base += 2; + } + lineno += delta;/* first delta is 0 */ + k = add_line(lt, lineno, l, k); + l += count + 1; + } + } +} + + +/* Parse the symbols of the file described by FH, whose index is F_IDX. + BOUND is the highest core address of this file's procedures */ + +static +parse_one_file(fh, f_idx, bound) + FDR *fh; +{ + register int s_idx; + SYMR *sh; + PDR *pr; + + /* Parse local symbols first */ + + for (s_idx = 0; s_idx < fh->csym; s_idx++) { + sh = (SYMR *) (fh->isymBase) + s_idx; + cur_sdx = s_idx; + parse_symbol(sh, fh->iauxBase); + } + + /* Procedures next, note we need to look-ahead to + find out where the procedure's code ends */ + + for (s_idx = 0; s_idx < fh->cpd-1; s_idx++) { + pr = (PDR *) (IPDFIRST(cur_hdr, fh)) + s_idx; + parse_procedure(pr, pr[1].adr); /* next proc up */ + } + if (fh->cpd) { + pr = (PDR *) (IPDFIRST(cur_hdr, fh)) + s_idx; + parse_procedure(pr, bound); /* next file up */ + } + + /* Linenumbers. At the end, check if we can save memory */ + parse_lines(fh, LINETABLE(cur_stab)); + if (LINETABLE(cur_stab)->nitems < fh->cline) + shrink_linetable(cur_stab); +} + + +/* Master parsing procedure. Parses the symtab described by the + symbolic header HDR. If INCREMENTAL is true we are called + by add-file and must preserve the old symtabs */ +static +parse_partial_symbols(hdr, incremental) + HDRR *hdr; +{ + int f_idx, s_idx, h_max; + CORE_ADDR dummy, *prevhigh; + /* Running pointers */ + FDR *fh; + RFDT *rh; + register EXTR *esh; + + /* + * Big plan: + * + * Only parse the External symbols, and the Relative FDR. + * Fixup enough of the loader symtab to be able to use it. + * Allocate space only for the file`s portions we need to + * look at. (XXX) + */ + + cur_hdr = hdr; + max_gdbinfo = 0; + max_glevel = MIN_GLEVEL; + + /* Allocate the map FDR -> PST. + Minor hack: -O3 images might claim some global data belongs + to FDR -1. We`ll go along with that */ + fdr_to_pst = (struct pst_map *)xzalloc((hdr->ifdMax+1) * sizeof *fdr_to_pst); + fdr_to_pst++; + { + struct partial_symtab * pst = new_psymtab(""); + fdr_to_pst[-1].pst = pst; + pst->ldsymoff = -1; + } + + /* Now scan the FDRs, mostly for dependencies */ + for (f_idx = 0; f_idx < hdr->ifdMax; f_idx++) + (void) parse_fdr(f_idx, 1); + + /* Take a good guess at how many symbols we might ever need */ + h_max = hdr->iextMax; + + /* Parse externals: two passes because they can be ordered + in any way */ + + /* Pass 1: Presize and partition the list */ + for (s_idx = 0; s_idx < hdr->iextMax; s_idx++) { + esh = (EXTR *) (hdr->cbExtOffset) + s_idx; + fdr_to_pst[esh->ifd].n_globals++; + } + + if (global_psymbols.list) { + global_psymbols.list = (struct partial_symbol *) + xrealloc( global_psymbols.list, (h_max + + global_psymbols.size) * sizeof(struct partial_symbol)); + global_psymbols.next = global_psymbols.list + global_psymbols.size; + global_psymbols.size += h_max; + } else { + global_psymbols.list = (struct partial_symbol *) + xmalloc( h_max * sizeof(struct partial_symbol)); + global_psymbols.size = h_max; + global_psymbols.next = global_psymbols.list; + } + + s_idx = global_psymbols.next - global_psymbols.list; + for (f_idx = -1; f_idx < hdr->ifdMax; f_idx++) { + fdr_to_pst[f_idx].pst->globals_offset = s_idx; + s_idx += fdr_to_pst[f_idx].n_globals; + } + + /* Pass 2: fill in symbols */ + for (s_idx = 0; s_idx < hdr->iextMax; s_idx++) { + register struct partial_symbol *p; + enum misc_function_type misc_type = mf_text; + esh = (EXTR *) (hdr->cbExtOffset) + s_idx; + + if (esh->asym.sc == scUndefined || esh->asym.sc == scNil) + continue; + p = new_psymbol(&global_psymbols, esh->asym.iss, esh->ifd); + SYMBOL_VALUE(p) = esh->asym.value; + SYMBOL_NAMESPACE(p) = VAR_NAMESPACE; + + switch (esh->asym.st) { + case stProc: + SYMBOL_CLASS(p) = LOC_BLOCK; + break; + case stGlobal: + SYMBOL_CLASS(p) = LOC_STATIC; + misc_type = mf_data; + break; + case stLabel: + SYMBOL_CLASS(p) = LOC_LABEL; + break; + default: + misc_type = mf_unknown; + complain (&unknown_ext_complaint, SYMBOL_NAME(p)); + } + prim_record_misc_function (SYMBOL_NAME(p), + SYMBOL_VALUE(p), + misc_type); + } + + + /* The array (of lists) of globals must be sorted. + Take care, since we are at it, of pst->texthigh. + + NOTE: The way we handle textlow/high is incorrect, but good + enough for a first approximation. The case we fail is on a + file "foo.c" that looks like + proc1() {...} + #include "bar.c" -- this contains proc2() + proc3() {...} + where proc3() is attributed to bar.c. But since this is a + dependent file it will cause loading of foo.c as well, so + everything will be fine at the end. */ + + prevhigh = &dummy; + for (f_idx = 0; f_idx < hdr->ifdMax; f_idx++) { + struct partial_symtab *pst = fdr_to_pst[f_idx].pst; + if (pst->n_global_syms > 1) + qsort (global_psymbols.list + pst->globals_offset, + pst->n_global_syms, sizeof (struct partial_symbol), + compare_psymbols); + if (pst->textlow) { + *prevhigh = pst->textlow; + prevhigh = &pst->texthigh; + } + } + + /* Mark the last code address, and remember it for later */ + *prevhigh = END_OF_TEXT_SEGMENT(filhdr); + hdr->cbDnOffset = END_OF_TEXT_SEGMENT(filhdr); + + reorder_psymtabs(); + free(&fdr_to_pst[-1]); + fdr_to_pst = 0; +} + + +/* Do the initial analisys of the F_IDX-th file descriptor. + Allocates a partial symtab for it, and builds the list + of dependent files by recursion. LEV says at which level + of recursion we are called (to pretty up debug traces) */ + +static struct partial_symtab * +parse_fdr(f_idx, lev) + int f_idx; +{ + register FDR *fh; + register struct partial_symtab *pst; + int s_idx, s_id0; + + fh = (FDR *) (cur_hdr->cbFdOffset) + f_idx; + + /* Use this to indicate into which symtab this file was parsed */ + if (fh->ioptBase) + return (struct partial_symtab *) fh->ioptBase; + + /* Debuggability level */ + if (compare_glevel(max_glevel, fh->glevel) < 0) + max_glevel = fh->glevel; + + /* Make a new partial_symtab */ + pst = new_psymtab(fh->rss); + if (fh->cpd == 0){ + pst->textlow = 0; + pst->texthigh = 0; + } else { + pst->textlow = fh->adr; + pst->texthigh = fh->cpd; /* To be fixed later */ + } + /* Reverse mapping PST -> FDR */ + pst->ldsymoff = f_idx; + + fdr_to_pst[f_idx].pst = pst; + fh->ioptBase = (int)pst; + + /* Analyze its dependencies */ + if (fh->crfd <= 1) + return pst; + + s_id0 = 0; + if (fh->cpd == 0) { /* If there are no functions defined here ... */ + /* ...then presumably a .h file: drop reverse depends .h->.c */ + for (; s_id0 < fh->crfd; s_id0++) { + RFDT *rh = (RFDT *) (fh->rfdBase) + s_id0; + if (*rh == f_idx) { + s_id0++; /* Skip self-dependency */ + break; + } + } + } + pst->number_of_dependencies = fh->crfd - s_id0; + pst->dependencies = (struct partial_symtab **) + obstack_alloc (psymbol_obstack, + pst->number_of_dependencies * sizeof(char*)); + for (s_idx = s_id0; s_idx < fh->crfd; s_idx++) { + RFDT *rh = (RFDT *) (fh->rfdBase) + s_idx; + + pst->dependencies[s_idx-s_id0] = parse_fdr(*rh, lev+1); + + } + + return pst; +} + + +/* Ancillary function to psymtab_to_symtab(). Does all the work + for turning the partial symtab PST into a symtab, recurring + first on all dependent psymtabs */ + +static void psymtab_to_symtab_1(pst) + struct partial_symtab *pst; +{ + int i, f_max; + struct symtab *st; + FDR *fh; + + if (pst->readin) + return; + pst->readin = 1; + + pending_list = (struct pending **) cur_hdr->cbOptOffset; + if (pending_list == 0) { + pending_list = (struct pending **) + xzalloc(cur_hdr->ifdMax * sizeof(struct pending *)); + cur_hdr->cbOptOffset = (int)pending_list; + } + + /* How many symbols will we need */ + f_max = pst->n_global_syms + pst->n_static_syms; + if (pst->ldsymoff == -1) { + fh = 0; + st = new_symtab( "unknown", f_max, 0); + } else { + fh = (FDR *) (cur_hdr->cbFdOffset) + pst->ldsymoff; + f_max += fh->csym + fh->cpd; + st = new_symtab(pst->filename, 2 * f_max, 2 * fh->cline); + } + + /* + * Read in all partial symbtabs on which this one is dependent. + * NOTE that we do have circular dependencies, sigh. + */ + for (i = 0; i < pst->number_of_dependencies; i++) + if (!pst->dependencies[i]->readin) { + /* + * DO NOT inform about additional files that need to + * be read in, it would only annoy the user. + */ + psymtab_to_symtab_1(pst->dependencies[i]); + } + + /* Now read the symbols for this symtab */ + + cur_fd = pst->ldsymoff; + cur_fdr = fh; + cur_stab = st; + + /* Get a new lexical context */ + + push_parse_stack(); + top_stack->cur_st = cur_stab; + top_stack->cur_block = BLOCKVECTOR_BLOCK(BLOCKVECTOR(cur_stab), 0); + BLOCK_START(top_stack->cur_block) = fh ? fh->adr : 0; + BLOCK_END(top_stack->cur_block) = 0; + top_stack->blocktype = stFile; + top_stack->maxsyms = f_max; + top_stack->cur_type = 0; + top_stack->procadr = 0; + top_stack->numargs = 0; + + /* Parse locals and procedures */ + if (fh) + parse_one_file(fh, cur_fd, (cur_fd == (cur_hdr->ifdMax - 1)) ? + cur_hdr->cbDnOffset : fh[1].adr); + + /* .. and our share of externals. + XXX use the global list to speed up things here. how ? */ + top_stack->blocktype = stFile; + top_stack->maxsyms = cur_hdr->isymMax + cur_hdr->ipdMax + cur_hdr->iextMax; + for (i = 0; i < cur_hdr->iextMax; i++) { + register EXTR *esh = (EXTR *) (cur_hdr->cbExtOffset) + i; + if (esh->ifd == cur_fd) + parse_external(esh, 1); + } + + /* If there are undefined, tell the user */ + if (n_undef_symbols) { + printf_filtered("File %s contains %d unresolved references:", + st->filename, n_undef_symbols); + printf_filtered("\n\t%4d variables\n\t%4d procedures\n\t%4d labels\n", + n_undef_vars, n_undef_procs, n_undef_labels); + n_undef_symbols = n_undef_labels = n_undef_vars = n_undef_procs = 0; + } + + pop_parse_stack(); + + /* + * Sort the symbol table now, we are done adding symbols to it. + */ + sort_symtab_syms(st); +} + + + + +/* Ancillary parsing procedures. */ + +/* Lookup the type at relative index RN. Return it in TPP + if found and in any event come up with its name PNAME. + Return value says how many aux symbols we ate */ + +static +cross_ref(rn, tpp, pname) + RNDXR *rn; + struct type **tpp; + char **pname; +{ + unsigned rf; + + /* Escape index means 'the next one' */ + if (rn->rfd == 0xfff) + rf = *(unsigned *) (rn + 1); + else + rf = rn->rfd; + + if (rf == -1) { + /* Ooops */ + *pname = ""; + } 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)) ? "" : + (char *) sh->iss; + + /* Have we parsed it ? */ + if ((!UNSAFE_DATA_ADDR(sh->value)) && (sh->st == stParsed)) { + t = (struct type *) sh->value; + *tpp = t; + } else { + struct pending *p; + + /* Avoid duplicates */ + p = is_pending_symbol(fh, sh); + + if (p) + *tpp = p->t; + else + add_pending(fh, sh, *tpp); + } + } + return (rn->rfd == 0xfff); +} + + +/* Quick&dirty lookup procedure, to avoid the MI ones that require + keeping the symtab sorted */ + +static struct symbol * +mylookup_symbol (name, block, namespace, class) + char *name; + register struct block *block; + enum namespace namespace; + enum address_class class; +{ + register int bot, top, inc; + register struct symbol *sym; + + bot = 0; + top = BLOCK_NSYMS(block); + inc = name[0]; + while (bot < top) { + sym = BLOCK_SYM(block, bot); + if (SYMBOL_NAME(sym)[0] == inc + && SYMBOL_NAMESPACE(sym) == namespace + && SYMBOL_CLASS(sym) == class + && !strcmp(SYMBOL_NAME(sym), name)) + return sym; + bot++; + } + if (block = BLOCK_SUPERBLOCK (block)) + return mylookup_symbol (name, block, namespace, class); + return 0; +} + + +/* Add a new symbol S to a block B */ + +static +add_symbol(s,b) + struct symbol *s; + struct block *b; +{ + BLOCK_SYM(b,BLOCK_NSYMS(b)++) = s; + if (b == top_stack->cur_block && + BLOCK_NSYMS(b) > top_stack->maxsyms) + printf_filtered("Internal: block at @%x overfilled (by %d)\n", + b, BLOCK_NSYMS(b) - top_stack->maxsyms); +} + +/* Add a new block B to a symtab S */ + +static +add_block(b,s) + struct block *b; + struct symtab *s; +{ + struct blockvector *bv = BLOCKVECTOR(s); + + bv = (struct blockvector *)xrealloc(bv, sizeof(struct blockvector) + + BLOCKVECTOR_NBLOCKS(bv) * sizeof(bv->block)); + if (bv != BLOCKVECTOR(s)) + BLOCKVECTOR(s) = bv; + + BLOCKVECTOR_BLOCK(bv, BLOCKVECTOR_NBLOCKS(bv)++) = b; +} + +/* Add a new linenumber entry (LINENO,ADR) to a linevector LT. + MIPS' linenumber encoding might need more than one byte + to describe it, LAST is used to detect these continuation lines */ + +static +add_line(lt, lineno, adr, last) + struct linetable *lt; + CORE_ADDR adr; +{ + if (last == 0) + last = -2; /* make sure we record first line */ + + if (last == lineno) /* skip continuation lines */ + return lineno; + + lt->item[lt->nitems].line = lineno; + lt->item[lt->nitems++].pc = adr << 2; + return lineno; +} + + + +/* Comparison functions, used when sorting things */ + +/* Symtabs must be ordered viz the code segments they cover */ + +static int +compare_symtabs( s1, s2) + struct symtab **s1, **s2; +{ + /* "most specific" first */ + + register struct block *b1, *b2; + b1 = BLOCKVECTOR_BLOCK(BLOCKVECTOR(*s1),0); + b2 = BLOCKVECTOR_BLOCK(BLOCKVECTOR(*s2),0); + if (BLOCK_END(b1) == BLOCK_END(b2)) + return BLOCK_START(b1) - BLOCK_START(b2); + return BLOCK_END(b1) - BLOCK_END(b2); +} + + +/* Partial Symtabs, same */ + +static int +compare_psymtabs( s1, s2) + struct partial_symtab **s1, **s2; +{ + /* Perf twist: put the ones with no code at the end */ + + register int a = (*s1)->textlow; + register int b = (*s2)->textlow; + if (a == 0) + return b; + if (b == 0) + return -a; + return a - b; +} + + +/* Partial symbols are compared lexicog by their print names */ + +static int +compare_psymbols (s1, s2) + register struct partial_symbol *s1, *s2; +{ + register char + *st1 = SYMBOL_NAME(s1), + *st2 = SYMBOL_NAME(s2); + + return (st1[0] - st2[0] ? st1[0] - st2[0] : + strcmp(st1 + 1, st2 + 1)); +} + +/* Blocks with a smaller low bound should come first */ + +static int compare_blocks(b1,b2) + struct block **b1, **b2; +{ + register int addr_diff; + + addr_diff = (BLOCK_START((*b1))) - (BLOCK_START((*b2))); + if (addr_diff == 0) + return (BLOCK_END((*b1))) - (BLOCK_END((*b2))); + return addr_diff; +} + + +/* Sorting and reordering procedures */ + +/* Sort the blocks of a symtab S. + Reorder the blocks in the blockvector by code-address, + as required by some MI search routines */ + +static +sort_blocks(s) + struct symtab *s; +{ + struct blockvector *bv = BLOCKVECTOR(s); + + if (BLOCKVECTOR_NBLOCKS(bv) <= 2) { + /* Cosmetic */ + if (BLOCK_END(BLOCKVECTOR_BLOCK(bv,0)) == 0) + BLOCK_START(BLOCKVECTOR_BLOCK(bv,0)) = 0; + return; + } + /* + * This is very unfortunate: normally all functions are compiled in + * the order they are found, but if the file is compiled -O3 things + * are very different. It would be nice to find a reliable test + * to detect -O3 images in advance. + */ + if (BLOCKVECTOR_NBLOCKS(bv) > 3) + qsort(&BLOCKVECTOR_BLOCK(bv,2), + BLOCKVECTOR_NBLOCKS(bv) - 2, + sizeof(struct block *), + compare_blocks); + + { + register CORE_ADDR high = 0; + register int i, j = BLOCKVECTOR_NBLOCKS(bv); + + for (i = 2; i < j; i++) + if (high < BLOCK_END(BLOCKVECTOR_BLOCK(bv,i))) + high = BLOCK_END(BLOCKVECTOR_BLOCK(bv,i)); + BLOCK_END(BLOCKVECTOR_BLOCK(bv,0)) = high; + } + + BLOCK_START(BLOCKVECTOR_BLOCK(bv,0)) = BLOCK_START(BLOCKVECTOR_BLOCK(bv,2)); + + BLOCK_START(BLOCKVECTOR_BLOCK(bv,1)) = BLOCK_START(BLOCKVECTOR_BLOCK(bv,0)); + BLOCK_END (BLOCKVECTOR_BLOCK(bv,1)) = BLOCK_END (BLOCKVECTOR_BLOCK(bv,0)); +} + +/* Sort the symtab list, as required by some search procedures. + We want files ordered to make them look right to users, and for + searching (see block_for_pc). */ + +static +reorder_symtabs() +{ + register int i; + struct symtab *stab; + struct symtab **all_symtabs = (struct symtab **) + obstack_alloc (psymbol_obstack, + all_symtabs_count * sizeof (struct symtab *)); + + /* Create an array of pointers to all the symtabs. */ + for (i = 0, stab = symtab_list; + i < all_symtabs_count; + i++, stab = stab->next) { + all_symtabs[i] = stab; + /* FIXME: Only do this for new symtabs ??? */ + sort_blocks(all_symtabs[i]); + } + + qsort(all_symtabs, all_symtabs_count, + sizeof(struct symtab *), compare_symtabs); + + /* Re-construct the symtab list, but now it is sorted. */ + for (i = 0; i < all_symtabs_count-1; i++) + all_symtabs[i]->next = all_symtabs[i+1]; + all_symtabs[i]->next = 0; + symtab_list = all_symtabs[0]; + obstack_free (psymbol_obstack, all_symtabs); +} + +/* Sort the partial symtab list, as required by some search procedures */ + +static reorder_psymtabs() +{ + register int i; + struct partial_symtab *pstab; + + /* + * PC lookups stop at the first psymtab such that + * textlow <= PC < texthigh + */ + /* Create an array of pointers to all the partial_symtabs. */ + struct partial_symtab **all_psymtabs = (struct partial_symtab **) + obstack_alloc (psymbol_obstack, + all_psymtabs_count*sizeof(struct partial_symtab*)); + for (i = 0, pstab = partial_symtab_list; + i < all_psymtabs_count; + i++, pstab = pstab->next) + all_psymtabs[i] = pstab; + + qsort(all_psymtabs, all_psymtabs_count, + sizeof(struct partial_symtab *), compare_psymtabs); + + /* Re-construct the partial_symtab_list, but now it is sorted. */ + + for (i = 0; i < all_psymtabs_count-1; i++) + all_psymtabs[i]->next = all_psymtabs[i+1]; + all_psymtabs[i]->next = 0; + partial_symtab_list = all_psymtabs[0]; + + obstack_free (psymbol_obstack, all_psymtabs); +} + + + +/* Constructor/restructor/destructor procedures */ + +/* Allocate a new symtab for NAME. Needs an estimate of how many symbols + MAXSYMS and linenumbers MAXLINES we'll put in it */ + +static +struct symtab * +new_symtab(name, maxsyms, maxlines) + char *name; +{ + struct symtab *s = (struct symtab *) xzalloc(sizeof(struct symtab)); + int i; + + LINETABLE(s) = new_linetable(maxlines); + + s->filename = name; + + /* All symtabs must have at least two blocks */ + BLOCKVECTOR(s) = new_bvect(2); + BLOCKVECTOR_BLOCK(BLOCKVECTOR(s), 0) = new_block(maxsyms); + BLOCKVECTOR_BLOCK(BLOCKVECTOR(s), 1) = new_block(maxsyms); + BLOCK_SUPERBLOCK( BLOCKVECTOR_BLOCK(BLOCKVECTOR(s),1)) = + BLOCKVECTOR_BLOCK(BLOCKVECTOR(s), 0); + + s->free_code = free_linetable; + + /* Link the new symtab into the list of such. */ + s->next = symtab_list; + symtab_list = s; + + all_symtabs_count++; + + return s; +} + +/* Cleanup before loading a fresh image */ + +static destroy_all_symtabs() +{ + if (symfile) + free(symfile); + symfile = 0; + + free_all_symtabs(); + all_symtabs_count = 0; + current_source_symtab = 0; + /* psymtabs! */ +} + +/* Allocate a new partial_symtab NAME */ + +static struct partial_symtab * +new_psymtab(name) + char *name; +{ + struct partial_symtab *pst; + + pst = (struct partial_symtab *) + obstack_alloc (psymbol_obstack, sizeof (*pst)); + bzero (pst, sizeof (*pst)); + + if (name == (char*)-1) /* FIXME -- why not null here? */ + pst->filename = ""; + else + pst->filename = name; + + pst->next = partial_symtab_list; + partial_symtab_list = pst; + all_psymtabs_count++; + + /* Keep a backpointer to the file`s symbols */ + pst->ldsymlen = (int)cur_hdr; + + /* The way to turn this into a symtab is to call... */ + pst->read_symtab = mipscoff_psymtab_to_symtab; + + return pst; +} + + +/* Allocate a new NAME psymbol from LIST, extending it if necessary. + The psymbol belongs to the psymtab at index PST_IDX */ + +static struct partial_symbol * +new_psymbol(list, name, pst_idx) + struct psymbol_allocation_list *list; + char *name; +{ + struct partial_symbol *p; + struct partial_symtab *pst = fdr_to_pst[pst_idx].pst; + + /* Lists are pre-sized, we won`t overflow */ + + p = list->list + pst->globals_offset + pst->n_global_syms++; + SYMBOL_NAME(p) = name; + return p; +} + + +/* Allocate a linetable array of the given SIZE */ + +static +struct linetable *new_linetable(size) +{ + struct linetable *l; + + size = size * sizeof(l->item) + sizeof(struct linetable); + l = (struct linetable *)xmalloc(size); + l->nitems = 0; + return l; +} + +/* Oops, too big. Shrink it. This was important with the 2.4 linetables, + I am not so sure about the 3.4 ones */ + +static shrink_linetable(s) + struct symtab *s; +{ + struct linetable *l = new_linetable(LINETABLE(s)->nitems); + + bcopy(LINETABLE(s), l, + LINETABLE(s)->nitems * sizeof(l->item) + sizeof(struct linetable)); + free (LINETABLE(s)); + LINETABLE(s) = l; +} + +/* Allocate and zero a new blockvector of NBLOCKS blocks. */ + +static +struct blockvector *new_bvect(nblocks) +{ + struct blockvector *bv; + int size; + + size = sizeof(struct blockvector) + nblocks * sizeof(struct block*); + bv = (struct blockvector *) xzalloc(size); + + BLOCKVECTOR_NBLOCKS(bv) = nblocks; + + return bv; +} + +/* Allocate and zero a new block of MAXSYMS symbols */ + +static +struct block *new_block(maxsyms) +{ + int size = sizeof(struct block) + (maxsyms-1) * sizeof(struct symbol *); + struct block *b = (struct block *)xzalloc(size); + + return b; +} + +/* Ooops, too big. Shrink block B in symtab S to its minimal size */ + +static struct block * +shrink_block(b, s) + struct block *b; + struct symtab *s; +{ + struct block *new; + struct blockvector *bv = BLOCKVECTOR(s); + int i; + + /* Just get a new one, copy, and fix references to the old one */ + + new = (struct block *)xmalloc(sizeof(struct block) + + (BLOCK_NSYMS(b)-1) * sizeof(struct symbol *)); + + bcopy(b, new, sizeof(*new) + (BLOCK_NSYMS(b) - 1) * sizeof(struct symbol*)); + + /* Should chase pointers to old one. Fortunately, that`s just + the block`s function and inferior blocks */ + if (BLOCK_FUNCTION(b) && SYMBOL_BLOCK_VALUE(BLOCK_FUNCTION(b)) == b) + SYMBOL_BLOCK_VALUE(BLOCK_FUNCTION(b)) = new; + for (i = 0; i < BLOCKVECTOR_NBLOCKS(bv); i++) + if (BLOCKVECTOR_BLOCK(bv,i) == b) + BLOCKVECTOR_BLOCK(bv,i) = new; + else if (BLOCK_SUPERBLOCK(BLOCKVECTOR_BLOCK(bv,i)) == b) + BLOCK_SUPERBLOCK(BLOCKVECTOR_BLOCK(bv,i)) = new; + free(b); + return new; +} + +/* Create a new symbol with printname NAME */ + +static +struct symbol * +new_symbol(name) + char *name; +{ + struct symbol *s = (struct symbol *) + obstack_alloc (symbol_obstack, sizeof (struct symbol)); + + bzero (s, sizeof (*s)); + SYMBOL_NAME(s) = name; + return s; +} + +/* Create a new type with printname NAME */ + +static +struct type * +new_type(name) + char *name; +{ + struct type *t = (struct type *) + obstack_alloc (symbol_obstack, sizeof (struct type)); + + bzero (t, sizeof (*t)); + TYPE_NAME(t) = name; + return t; +} + +/* Create and initialize a new type with printname NAME. + CODE and LENGTH are the initial info we put in, + UNS says whether the type is unsigned or not. */ + +static +struct type * +make_type(code, length, uns, name) + enum type_code code; + int length, uns; + char *name; +{ + register struct type *type; + + type = (struct type *) xzalloc(sizeof(struct type)); + TYPE_CODE(type) = code; + TYPE_LENGTH(type) = length; + TYPE_FLAGS(type) = uns ? TYPE_FLAG_UNSIGNED : 0; + TYPE_NAME(type) = name; + + return type; +} + +/* Allocate a new field named NAME to the type TYPE */ + +static +struct field *new_field(type,name) + struct type *type; + char *name; +{ + struct field *f; + + /* Fields are kept in an array */ + if (TYPE_NFIELDS(type)) + TYPE_FIELDS(type) = (struct field*)xrealloc(TYPE_FIELDS(type), + (TYPE_NFIELDS(type)+1) * sizeof(struct field)); + else + TYPE_FIELDS(type) = (struct field*)xzalloc(2*sizeof(struct field)); + f = &(TYPE_FIELD(type,TYPE_NFIELDS(type)++)); + bzero(f, sizeof(struct field)); + if (name) + f->name = name; + return f; +} + +/* Make an enum constant for a member F of an enumerated type T */ + +static +make_enum_constant(f,t) + struct field *f; + struct type *t; +{ + struct symbol *s; + /* + * This is awful, but that`s the way it is supposed to be + * (BTW, no need to free the real 'type', it's a builtin) + */ + f->type = (struct type *) f->bitpos; + + s = new_symbol(f->name); + SYMBOL_NAMESPACE(s) = VAR_NAMESPACE; + SYMBOL_CLASS(s) = LOC_CONST; + SYMBOL_TYPE(s) = t; + SYMBOL_VALUE(s) = f->bitpos; + add_symbol(s, top_stack->cur_block); +} + + + +/* Things used for calling functions in the inferior. + These functions are exported to our companion + mips-dep.c file and are here because they play + with the symbol-table explicitly. */ + +#if 0 +/* Need to make a new symbol on the fly for the dummy + frame we put on the stack. Which goes in the.. */ + +static struct symtab *dummy_symtab; + +/* Make up a dummy symbol for the code we put at END_PC, + of size SIZE, invoking a function with NARGS arguments + and using a frame of FRAMESIZE bytes */ + +mips_create_dummy_symbol(end_pc, size, nargs, framesize) +{ + struct block *bl; + struct symbol *g; + struct mips_extra_func_info *gdbinfo; + + /* Allocate symtab if not done already */ + if (dummy_symtab == 0) + dummy_symtab = new_symtab(".dummy_symtab.", 100, 0); + + /* Make a new block. Only needs one symbol */ + bl = new_block(1); + BLOCK_START(bl) = end_pc - size; + BLOCK_END(bl) = end_pc; + + BLOCK_SUPERBLOCK(bl) = BLOCKVECTOR_BLOCK(BLOCKVECTOR(dummy_symtab),0); + add_block(bl, dummy_symtab); + sort_blocks(dummy_symtab); + + BLOCK_FUNCTION(bl) = new_symbol("??"); + SYMBOL_BLOCK_VALUE(BLOCK_FUNCTION(bl)) = bl; + g = new_symbol(".gdbinfo."); + BLOCK_SYM(bl,BLOCK_NSYMS(bl)++) = g; + + SYMBOL_NAMESPACE(g) = LABEL_NAMESPACE; + SYMBOL_CLASS(g) = LOC_CONST; + SYMBOL_TYPE(g) = builtin_type_void; + gdbinfo = (struct mips_extra_func_info *) + xzalloc(sizeof(struct mips_extra_func_info)); + + SYMBOL_VALUE(g) = (long) gdbinfo; + + gdbinfo->numargs = nargs; + gdbinfo->framesize = framesize; + gdbinfo->framereg = 29; + gdbinfo->pcreg = 31; + gdbinfo->regmask = -2; + gdbinfo->regoffset = -4; + gdbinfo->fregmask = 0; /* XXX */ + gdbinfo->fregoffset = 0; /* XXX */ +} + +/* We just returned from the dummy code at END_PC, drop its symbol */ + +mips_destroy_dummy_symbol(end_pc) +{ + struct block *bl; + struct blockvector *bv = BLOCKVECTOR(dummy_symtab); + int i; + + bl = block_for_pc(end_pc); + free(BLOCK_FUNCTION(bl)); + free(SYMBOL_VALUE(BLOCK_SYM(bl,0))); + free(BLOCK_SYM(bl,0)); + + for (i = 2; i < BLOCKVECTOR_NBLOCKS(bv); i++) + if (BLOCKVECTOR_BLOCK(bv,i) == bl) + break; + for (; i < BLOCKVECTOR_NBLOCKS(bv) - 1; i++) + BLOCKVECTOR_BLOCK(bv,i) = BLOCKVECTOR_BLOCK(bv,i+1); + BLOCKVECTOR_NBLOCKS(bv)--; + sort_blocks(dummy_symtab); + free(bl); +} +#endif + +/* Sigtramp: make sure we have all the necessary information + about the signal trampoline code. Since the official code + from MIPS does not do so, we make up that information ourselves. + If they fix the library (unlikely) this code will neutralize itself. */ + +static +fixup_sigtramp() +{ + struct symbol *s; + struct symtab *st; + struct block *b, *b0; + + sigtramp_address = -1; + + /* We know it is sold as sigvec */ + s = lookup_symbol("sigvec", 0, VAR_NAMESPACE, 0, NULL); + + /* Most programs do not play with signals */ + if (s == 0) + return; + + b0 = SYMBOL_BLOCK_VALUE(s); + + /* A label of sigvec, to be more precise */ + s = lookup_symbol("sigtramp", b0, VAR_NAMESPACE, 0, NULL); + + /* But maybe this program uses its own version of sigvec */ + if (s == 0) + return; + + sigtramp_address = SYMBOL_VALUE(s); + sigtramp_end = sigtramp_address + 0x88; /* black magic */ + + /* Did we or MIPSco fix the library ? */ + if (SYMBOL_CLASS(s) == LOC_BLOCK) + return; + + /* But what symtab does it live in ? */ + st = find_pc_symtab(SYMBOL_VALUE(s)); + + /* + * Ok, there goes the fix: turn it into a procedure, with all the + * needed info. Note we make it a nested procedure of sigvec, + * which is the way the (assembly) code is actually written. + */ + SYMBOL_NAMESPACE(s) = VAR_NAMESPACE; + SYMBOL_CLASS(s) = LOC_BLOCK; + SYMBOL_TYPE(s) = make_type(TYPE_CODE_FUNC, 4, 0, 0); + TYPE_TARGET_TYPE(SYMBOL_TYPE(s)) = builtin_type_void; + + /* Need a block to allocate .gdbinfo. in */ + b = new_block(1); + SYMBOL_BLOCK_VALUE(s) = b; + BLOCK_START(b) = sigtramp_address; + BLOCK_END(b) = sigtramp_end; + BLOCK_FUNCTION(b) = s; + BLOCK_SUPERBLOCK(b) = BLOCK_SUPERBLOCK(b0); + add_block(b, st); + sort_blocks(st); + + /* Make a .gdbinfo. for it */ + { + struct mips_extra_func_info *e = + (struct mips_extra_func_info *) + xzalloc(sizeof(struct mips_extra_func_info)); + + e->numargs = 0; /* the kernel thinks otherwise */ + /* align_longword(sigcontext + SIGFRAME) */ + e->framesize = 0x150; + e->framereg = SP_REGNUM; + e->pcreg = 31; + e->regmask = -2; + e->regoffset = -(41 * sizeof(int)); + e->fregmask = -1; + e->fregoffset = -(37 * sizeof(int)); + e->isym = (long)s; + + s = new_symbol(".gdbinfo."); + SYMBOL_VALUE(s) = (int) e; + SYMBOL_NAMESPACE(s) = LABEL_NAMESPACE; + SYMBOL_CLASS(s) = LOC_CONST; + SYMBOL_TYPE(s) = builtin_type_void; + } + + BLOCK_SYM(b,BLOCK_NSYMS(b)++) = s; +} + + +/* Initialization */ + +static struct sym_fns ecoff_sym_fns = {"ecoff", 5, + mipscoff_new_init, mipscoff_symfile_init, + mipscoff_symfile_read, mipscoff_symfile_discard}; + +_initialize_mipsread () +{ + add_symtab_fns (&ecoff_sym_fns); + + bzero (&global_psymbols, sizeof (global_psymbols)); + bzero (&static_psymbols, sizeof (static_psymbols)); + + add_com("add-file", class_files, add_file_command, + "Add a new symbol table (in mips format) from file FILE."); + + /* Missing basic types */ + builtin_type_string = make_type(TYPE_CODE_PASCAL_ARRAY, + 1, 0, "string"); + builtin_type_complex = make_type(TYPE_CODE_FLT, + 2 * sizeof(float), 0, "complex"); + builtin_type_double_complex = make_type(TYPE_CODE_FLT, + 2 * sizeof(double), 0, "double_complex"); + builtin_type_fixed_dec = make_type(TYPE_CODE_INT, sizeof(int), + 0, "fixed_decimal"); + builtin_type_float_dec = make_type(TYPE_CODE_FLT, sizeof(double), + 0, "floating_decimal"); + + /* Templates types */ + builtin_type_ptr = lookup_pointer_type (builtin_type_void); + builtin_type_struct = make_type(TYPE_CODE_STRUCT, 0, 0, 0); + builtin_type_union = make_type(TYPE_CODE_UNION, 0, 0, 0); + builtin_type_enum = make_type(TYPE_CODE_ENUM, 0, 0, 0); + builtin_type_range = make_type(TYPE_CODE_RANGE, 0, 0, 0); + builtin_type_set = make_type(TYPE_CODE_SET, 0, 0, 0); +} diff --git a/gdb/printcmd.c b/gdb/printcmd.c new file mode 100644 index 00000000000..b8bc298ed5d --- /dev/null +++ b/gdb/printcmd.c @@ -0,0 +1,1960 @@ +/* Print values for GNU debugger GDB. + Copyright (C) 1986-1991 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#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 (); + + +/* 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; +} + +/* 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 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 + 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); +} + + + +/* 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); + } +} + +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"); +} + +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); + } +} + +/* 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"); +} + +#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 */ + +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++; + } +} + + +/* 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); + } +} + +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. */ +} + +/* 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); +} + + +void +_initialize_printcmd () +{ + current_display_number = -1; + + add_info ("address", address_info, + "Describe where variable VAR is stored."); + + add_com ("x", class_vars, x_command, + "Examine memory: x/FMT ADDRESS.\n\ +ADDRESS is an expression for the memory address to examine.\n\ +FMT is a repeat count followed by a format letter and a size letter.\n\ +Format letters are o(octal), x(hex), d(decimal), u(unsigned decimal),\n\ + f(float), a(address), i(instruction), c(char) and s(string).\n\ +Size letters are b(byte), h(halfword), w(word), g(giant, 8 bytes).\n\ + g is meaningful only with f, for type double.\n\ +The specified number of objects of the specified size are printed\n\ +according to the format.\n\n\ +Defaults for format and size letters are those previously used.\n\ +Default count is 1. Default address is following last thing printed\n\ +with this command or \"print\"."); + + add_com ("disassemble", class_vars, disassemble_command, + "Disassemble a specified section of memory.\n\ +Default is the function surrounding the pc of the selected frame.\n\ +With a single argument, the function surrounding that address is dumped.\n\ +Two arguments are taken as a range of memory to dump."); + + add_com ("ptype", class_vars, ptype_command, + "Print definition of type TYPE.\n\ +Argument may be a type name defined by typedef, or \"struct STRUCTNAME\"\n\ +or \"union UNIONNAME\" or \"enum ENUMNAME\".\n\ +The selected stack frame's lexical context is used to look up the name."); + + add_com ("whatis", class_vars, whatis_command, + "Print data type of expression EXP."); + +#if 0 + add_com ("whereis", class_vars, whereis_command, + "Print line number and file of definition of variable."); +#endif + + add_info ("display", display_info, + "Expressions to display when program stops, with code numbers."); + + add_cmd ("undisplay", class_vars, undisplay_command, + "Cancel some expressions to be displayed when program stops.\n\ +Arguments are the code numbers of the expressions to stop displaying.\n\ +No argument means cancel all automatic-display expressions.\n\ +\"delete display\" has the same effect as this command.\n\ +Do \"info display\" to see current list of code numbers.", + &cmdlist); + + add_com ("display", class_vars, display_command, + "Print value of expression EXP each time the program stops.\n\ +/FMT may be used before EXP as in the \"print\" command.\n\ +/FMT \"i\" or \"s\" or including a size-letter is allowed,\n\ +as in the \"x\" command, and then EXP is used to get the address to examine\n\ +and examining is done as in the \"x\" command.\n\n\ +With no argument, display all currently requested auto-display expressions.\n\ +Use \"undisplay\" to cancel display requests previously made."); + + add_cmd ("display", class_vars, enable_display, + "Enable some expressions to be displayed when program stops.\n\ +Arguments are the code numbers of the expressions to resume displaying.\n\ +No argument means enable all automatic-display expressions.\n\ +Do \"info display\" to see current list of code numbers.", &enablelist); + + add_cmd ("display", class_vars, disable_display_command, + "Disable some expressions to be displayed when program stops.\n\ +Arguments are the code numbers of the expressions to stop displaying.\n\ +No argument means disable all automatic-display expressions.\n\ +Do \"info display\" to see current list of code numbers.", &disablelist); + + add_cmd ("display", class_vars, undisplay_command, + "Cancel some expressions to be displayed when program stops.\n\ +Arguments are the code numbers of the expressions to stop displaying.\n\ +No argument means cancel all automatic-display expressions.\n\ +Do \"info display\" to see current list of code numbers.", &deletelist); + + add_com ("printf", class_vars, printf_command, + "printf \"printf format string\", arg1, arg2, arg3, ..., argn\n\ +This is useful for formatted output in user-defined commands."); + add_com ("output", class_vars, output_command, + "Like \"print\" but don't put in value history and don't print newline.\n\ +This is useful in user-defined commands."); + + add_prefix_cmd ("set", class_vars, set_command, +"Perform an assignment VAR = EXP.\n\ +You must type the \"=\". VAR may be a debugger \"convenience\" variable\n\ +(names starting with $), a register (a few standard names starting with $),\n\ +or an actual variable in the program being debugged. EXP is any expression.\n\ +Use \"set variable\" for variables with names identical to set subcommands.\n\ +\nWith a subcommand, this command modifies parts of the gdb environment.\n\ +You can see these environment settings with the \"show\" command.", + &setlist, "set ", 1, &cmdlist); + + /* "call" is the same as "set", but handy for dbx users to call fns. */ + add_com ("call", class_vars, call_command, + "Call a function in the inferior process.\n\ +The argument is the function name and arguments, in standard C notation.\n\ +The result is printed and saved in the value history, if it is not void."); + + add_cmd ("variable", class_vars, set_command, + "Perform an assignment VAR = EXP.\n\ +You must type the \"=\". VAR may be a debugger \"convenience\" variable\n\ +(names starting with $), a register (a few standard names starting with $),\n\ +or an actual variable in the program being debugged. EXP is any expression.\n\ +This may usually be abbreviated to simply \"set\".", + &setlist); + + add_com ("print", class_vars, print_command, + concat ("Print value of expression EXP.\n\ +Variables accessible are those of the lexical environment of the selected\n\ +stack frame, plus all those whose scope is global or an entire file.\n\ +\n\ +$NUM gets previous value number NUM. $ and $$ are the last two values.\n\ +$$NUM refers to NUM'th value back from the last one.\n\ +Names starting with $ refer to registers (with the values they would have\n\ +if the program were to return to the stack frame now selected, restoring\n\ +all registers saved by frames farther in) or else to debugger\n\ +\"convenience\" variables (any such name not a known register).\n\ +Use assignment expressions to give values to convenience variables.\n", + "\n\ +{TYPE}ADREXP refers to a datum of data type TYPE, located at address ADREXP.\n\ +@ is a binary operator for treating consecutive data objects\n\ +anywhere in memory as an array. FOO@NUM gives an array whose first\n\ +element is FOO, whose second element is stored in the space following\n\ +where FOO is stored, etc. FOO must be an expression whose value\n\ +resides in memory.\n", + "\n\ +EXP may be preceded with /FMT, where FMT is a format letter\n\ +but no count or size letter (see \"x\" command).")); + add_com_alias ("p", "print", class_vars, 1); + + add_com ("inspect", class_vars, inspect_command, +"Same as \"print\" command, except that if you are running in the epoch\n\ +environment, the value is printed in its own window."); +} diff --git a/gdb/remote-sa.m68k.shar b/gdb/remote-sa.m68k.shar new file mode 100755 index 00000000000..aeb76e5d851 --- /dev/null +++ b/gdb/remote-sa.m68k.shar @@ -0,0 +1,893 @@ +# This is a shell archive. Remove anything before this line, +# then unpack it by saving it in a file and typing "sh file". +# +# Wrapped by Glenn Engel 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 + * + * $#. + * + * where + * :: + * :: < two hex digits computed as modulo 256 sum of > + * + * 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 +#include +#include + +/************************************************************************ + * + * 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 $# */ +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; + + /* $#. */ + 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> 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;iexceptionPC, + frame->exceptionVector); + if (frame->exceptionPC == newPC) break; /* bingo! a match */ + /* + * for a breakpoint instruction, the saved pc may + * be off by two due to re-executing the instruction + * replaced by the trap instruction. Check for this. + */ + if ((frame->exceptionVector == 33) && + (frame->exceptionPC == (newPC+2))) break; + frame = frame->previous; + } + + /* + * If we found a match for the PC AND we are not returning + * as a result of a breakpoint (33), + * trace exception (9), nmi (31), jmp to + * the old exception handler as if this code never ran. + */ + if (frame) + { + if ((frame->exceptionVector != 9) && + (frame->exceptionVector != 31) && + (frame->exceptionVector != 33)) + { + /* + * invoke the previous handler. + */ + if (oldExceptionHook) + (*oldExceptionHook) (frame->exceptionVector); + newPC = registers[ PC ]; /* pc may have changed */ + if (newPC != frame->exceptionPC) + { + if (remote_debug) + printf("frame at 0x%x has pc=0x%x, except#=%d\n", + frame,frame->exceptionPC, + frame->exceptionVector); + /* dispose of this frame, we're skipping it (longjump?)*/ + lastFrame = frame->previous; + frame = (Frame *) 0; + } + } + } + + _returnFromException( frame ); + + break; + + /* kill the program */ + case 'k' : /* do nothing */ + break; + } /* switch */ + + /* reply to the request */ + putpacket(outbuffer); + } +} + + +/* this function is used to set up exception handlers for tracing and + breakpoints */ +void set_debug_traps() +{ +extern void _debug_level7(); +extern void remcomHandler(); +int exception; + + for (exception = 2; exception <= 23; exception++) + exceptionHandler(exception,_catchException); + + /* level 7 interrupt */ + exceptionHandler(31,_debug_level7); + + /* breakpoint exception (trap #1) */ + exceptionHandler(33,_catchException); + + /* floating point error (trap #8) */ + exceptionHandler(40,_catchException); + + /* 48 to 54 are floating point coprocessor errors */ + for (exception = 48; exception <= 54; exception++) + exceptionHandler(exception,_catchException); + + if (oldExceptionHook != remcomHandler) + { + oldExceptionHook = exceptionHook; + exceptionHook = remcomHandler; + } + + initialized = 1; + + lastFrame = (Frame *) &frameStack[FRAMESIZE-1]; + lastFrame->previous = (Frame *) 0; +} + +/* This function will generate a breakpoint exception. It is used at the + beginning of a program to sync up with a debugger and can be used + otherwise as a quick means to stop program execution and "break" into + the debugger. */ + +void breakpoint() +{ + if (initialized) BREAKPOINT(); +} + +@EOF + +chmod 444 remcom.c + +exit 0 + diff --git a/gdb/remote.c b/gdb/remote.c new file mode 100644 index 00000000000..9ff56502b8f --- /dev/null +++ b/gdb/remote.c @@ -0,0 +1,829 @@ +/* Memory-access and commands for inferior process, for GDB. + Copyright (C) 1988-1991 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Remote communication protocol. + All values are encoded in ascii hex digits. + + Request Packet + + read registers g + reply XX....X Each byte of register data + is described by two hex digits. + Registers are in the internal order + for GDB, and the bytes in a register + are in the same order the machine uses. + or ENN for an error. + + write regs GXX..XX Each byte of register data + is described by two hex digits. + reply OK for success + ENN for an error + + read mem mAA..AA,LLLL AA..AA is address, LLLL is length. + reply XX..XX XX..XX is mem contents + or ENN NN is errno + + write mem MAA..AA,LLLL:XX..XX + AA..AA is address, + LLLL is number of bytes, + XX..XX is data + reply OK for success + ENN for an error + + cont cAA..AA AA..AA is address to resume + If AA..AA is omitted, + resume at same address. + + step sAA..AA AA..AA is address to resume + If AA..AA is omitted, + resume at same address. + + last signal ? Reply the current reason for stopping. + This is the same reply as is generated + for step or cont : SAA where AA is the + signal number. + + There is no immediate reply to step or cont. + The reply comes when the machine stops. + It is SAA AA is the "signal number" + + kill req k +*/ + +#include +#include +#include +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" +#include "target.h" +#include "wait.h" +#include "terminal.h" + +#ifdef USG +#include +#endif + +#include + +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 + + +/* 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; +} + +/* 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 */ + +/* 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; + } +} + +/* 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"); +} + +/* + +A debug packet whose contents are +is encapsulated for transmission in the form: + + $ # CSUM1 CSUM2 + + must be ASCII alphanumeric and cannot include characters + '$' or '#' + + CSUM1 and CSUM2 are ascii hex representation of an 8-bit + checksum of , 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); +} + +/* 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 +#include +#include +#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 . +** +** NOTE: This only works under SunOS4.0. +*/ + +struct so_list *find_solib(so_list_ptr) +struct so_list *so_list_ptr; /* so_list_head position ptr */ +{ +struct so_list *so_list_next = 0; +CORE_ADDR inferior_dynamic_ptr = 0; +struct link_map *inferior_lm = 0; +struct link_dynamic inferior_dynamic_cpy; +struct link_dynamic_2 inferior_ld_2_cpy; +struct so_list *new; +int i; + + if (!so_list_ptr) { + if (!(so_list_next = so_list_head)) { + for (i = 0; i < misc_function_count; i++) { + if (!strcmp (misc_function_vector[i].name, "_DYNAMIC")) { + inferior_dynamic_ptr = misc_function_vector[i].address; + break; + } + } + if (inferior_dynamic_ptr) { + read_memory(inferior_dynamic_ptr, &inferior_dynamic_cpy, sizeof(struct link_dynamic)); + if (inferior_dynamic_cpy.ld_version == 3) { + read_memory((CORE_ADDR)inferior_dynamic_cpy.ld_un.ld_2, + &inferior_ld_2_cpy, + sizeof(struct link_dynamic_2)); + inferior_lm = inferior_ld_2_cpy.ld_loaded; + } + } + } + } else { + /* + ** Advance to next local abbreviated load_map structure + */ + if (!(inferior_lm = so_list_ptr->inferior_lm.lm_next)) { + /* + ** See if any were added + */ + read_memory((CORE_ADDR)so_list_ptr->inferior_lm_add, + &so_list_ptr->inferior_lm, + sizeof(struct link_map)); + inferior_lm = so_list_ptr->inferior_lm.lm_next; + } + so_list_next = so_list_ptr->next; + } + if ((!so_list_next) && inferior_lm) { + /* + ** Get Next LM Structure from inferior image and build + ** an local abbreviated load_map structure + */ + new = (struct so_list *) xmalloc(sizeof(struct so_list)); + new->inferior_lm_add = inferior_lm; + read_memory((CORE_ADDR)inferior_lm, + &new->inferior_lm, + sizeof(struct link_map)); + + read_memory((CORE_ADDR)new->inferior_lm.lm_name, + new->inferior_so_name, + MAX_PATH_SIZE - 1); + new->inferior_so_name[MAX_PATH_SIZE - 1] = 0; + /* Zero everything after the first terminating null */ + strncpy(new->inferior_so_name, new->inferior_so_name, MAX_PATH_SIZE); + + read_memory((CORE_ADDR)new->inferior_lm.lm_ld, + &inferior_dynamic_cpy, + sizeof(struct link_dynamic)); + read_memory((CORE_ADDR)inferior_dynamic_cpy.ld_un.ld_2, + &inferior_ld_2_cpy, + sizeof(struct link_dynamic_2)); + new->ld_text = inferior_ld_2_cpy.ld_text; + + new->next = 0; + new->symbols_loaded = 0; + if (so_list_ptr) + so_list_ptr->next = new; + else + so_list_head = new; + so_list_next = new; + } + return(so_list_next); +} +/*=======================================================================*/ + +static void solib_add(arg_string, from_tty) +char *arg_string; +int from_tty; +{ + register struct so_list *so = 0; /* link map state variable */ + char *val; + int sz; + + if (arg_string == 0) + re_comp ("."); + else if (val = (char *) re_comp (arg_string)) { + error ("Invalid regexp: %s", val); + } + + printf_filtered ("All shared libraries"); + if (arg_string) + printf_filtered (" matching regular expresion \"%s\"", arg_string); + printf_filtered (":\n"); + + dont_repeat(); + + while (so = find_solib(so)) { + if (re_exec(so->inferior_so_name)) { + if (so->symbols_loaded) { + printf("Symbols already loaded for %s\n", so->inferior_so_name); + } else { + /* File Name String Freed by processing */ + sz = strlen(so->inferior_so_name) + 1; + val = (char *) xmalloc(sz); + bcopy(so->inferior_so_name, val, sz); + symbol_file_add (val, from_tty, + (unsigned int)so->inferior_lm.lm_addr, 0); + so->symbols_loaded = 1; + } + } + } +} +/*=======================================================================*/ + +static void solib_info() +{ +register struct so_list *so = 0; /* link map state variable */ + + while (so = find_solib(so)) { + if (so == so_list_head) { + printf(" Address Range Symbols Shared Object Library\n"); + } + printf(" 0x%08x - 0x%08x %s %s\n", + so->inferior_lm.lm_addr, + so->inferior_lm.lm_addr + so->ld_text - 1, + (so->symbols_loaded ? "Yes" : "No "), + so->inferior_so_name); + } + if (!so_list_head) { + printf("No shared libraries loaded at this time.\n"); + } +} + +/* +** Called by Insert Breakpoint to see if Address is Shared Library Address +*/ +int +solib_address(address) + CORE_ADDR address; +{ +register struct so_list *so = 0; /* link map state variable */ + + while (so = find_solib(so)) { + if ((address >= (CORE_ADDR) so->inferior_lm.lm_addr) && + (address < (CORE_ADDR) so->inferior_lm.lm_addr + so->ld_text)) + return 1; + } + return 0; +} + +/* +** Called by free_all_symtabs +*/ +void +clear_solib() +{ +struct so_list *next; + + while (so_list_head) { + next = so_list_head->next; + free(so_list_head); + so_list_head = next; + } + +} + +void +_initialize_solib() +{ + + add_com("sharedlibrary", class_files, solib_add, + "Load shared object library symbols for files matching REGEXP."); + add_info("sharedlibrary", solib_info, + "Status of loaded shared object libraries"); + +} diff --git a/gdb/source.c b/gdb/source.c new file mode 100644 index 00000000000..ebc7041bf98 --- /dev/null +++ b/gdb/source.c @@ -0,0 +1,1186 @@ +/* List lines of source files for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1988, 1989, 1991 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include "defs.h" +#include "symtab.h" +#include "param.h" +#include "command.h" +#include "frame.h" + +#ifdef USG +#include +#endif + +#include +#include +#include +#include +#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; + + +/* 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; + } +} + +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; + } +} + + + +/* 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); +} + + +/* 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; +} + +/* 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; +} + +/* 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); +} + + + +/* + 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); +} + +/* 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); + } +} + +/* 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; +} + +void +_initialize_source () +{ + current_source_symtab = 0; + init_source_path (); + + add_com ("directory", class_files, directory_command, + "Add directory DIR to beginning of search path for source files.\n\ +Forget cached info on source file locations and line positions.\n\ +DIR can also be $cwd for the current working directory, or $cdir for the\n\ +directory in which the source file was compiled into object code.\n\ +With no argument, reset the search path to $cdir:$cwd, the default."); + + add_info ("directories", directories_info, + "Current search path for finding source files.\n\ +$cwd in the path means the current working directory.\n\ +$cdir in the path means the compilation directory of the source file."); + + add_info ("source", source_info, + "Information about the current source file."); + + add_info ("line", line_info, + "Core addresses of the code for a source line.\n\ +Line can be specified as\n\ + LINENUM, to list around that line in current file,\n\ + FILE:LINENUM, to list around that line in that file,\n\ + FUNCTION, to list around beginning of that function,\n\ + FILE:FUNCTION, to distinguish among like-named static functions.\n\ +Default is to describe the last source line that was listed.\n\n\ +This sets the default address for \"x\" to the line's first instruction\n\ +so that \"x/i\" suffices to start examining the machine code.\n\ +The address is also stored as the value of \"$_\"."); + + add_com ("forward-search", class_files, forward_search_command, + "Search for regular expression (see regex(3)) from last line listed."); + add_com_alias ("search", "forward-search", class_files, 0); + + add_com ("reverse-search", class_files, reverse_search_command, + "Search backward for regular expression (see regex(3)) from last line listed."); + + add_com ("list", class_files, list_command, + "List specified function or line.\n\ +With no argument, lists ten more lines after or around previous listing.\n\ +\"list -\" lists the ten lines before a previous ten-line listing.\n\ +One argument specifies a line, and ten lines are listed around that line.\n\ +Two arguments with comma between specify starting and ending lines to list.\n\ +Lines can be specified in these ways:\n\ + LINENUM, to list around that line in current file,\n\ + FILE:LINENUM, to list around that line in that file,\n\ + FUNCTION, to list around beginning of that function,\n\ + FILE:FUNCTION, to distinguish among like-named static functions.\n\ + *ADDRESS, to list around the line containing that address.\n\ +With two args if one is empty it stands for ten lines away from the other arg."); + add_com_alias ("l", "list", class_files, 0); +} + diff --git a/gdb/sparc-tdep.c b/gdb/sparc-tdep.c new file mode 100644 index 00000000000..e0fb8ba79d4 --- /dev/null +++ b/gdb/sparc-tdep.c @@ -0,0 +1,586 @@ +/* Machine-dependent code which would otherwise be in inflow.c and core.c, + for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + This code is for the sparc cpu. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#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 +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#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; + } +} + +/* + * Find the pc saved in frame FRAME. + */ +CORE_ADDR +frame_saved_pc (frame) + FRAME frame; +{ + CORE_ADDR prev_pc; + + /* If it's at the bottom, the return value's stored in i7/rp */ + if (get_current_frame () == frame) + prev_pc = GET_RWINDOW_REG (read_register (SP_REGNUM), rw_in[7]); + else + /* Wouldn't this always work? This would allow this routine to + be completely a macro. */ + prev_pc = GET_RWINDOW_REG (frame->bottom, rw_in[7]); + + return PC_ADJUST (prev_pc); +} + +/* + * Since an individual frame in the frame cache is defined by two + * arguments (a frame pointer and a stack pointer), we need two + * arguments to get info for an arbitrary stack frame. This routine + * takes two arguments and makes the cached frames look as if these + * two arguments defined a frame on the cache. This allows the rest + * of info frame to extract the important arguments without + * difficulty. + */ +FRAME +setup_arbitrary_frame (frame, stack) + FRAME_ADDR frame, stack; +{ + FRAME fid = create_new_frame (frame, 0); + + if (!fid) + fatal ("internal: create_new_frame returned invalid frame id"); + + fid->bottom = stack; + + return fid; +} + +/* This code was written by Gary Beihl (beihl@mcc.com). + It was modified by Michael Tiemann (tiemann@corto.inria.fr). */ + +/* + * This routine appears to be passed a size by which to increase the + * stack. It then executes a save instruction in the inferior to + * increase the stack by this amount. Only the register window system + * should be affected by this; the program counter & etc. will not be. + * + * This instructions used for this purpose are: + * + * sethi %hi(0x0),g1 * + * add g1,0x1ee0,g1 * + * save sp,g1,sp + * sethi %hi(0x0),g1 * + * add g1,0x1ee0,g1 * + * t g0,0x1,o0 + * sethi %hi(0x0),g0 (nop) + * + * I presume that these set g1 to be the negative of the size, do a + * save (putting the stack pointer at sp - size) and restore the + * original contents of g1. A * indicates that the actual value of + * the instruction is modified below. + */ +static int save_insn_opcodes[] = { + 0x03000000, 0x82007ee0, 0x9de38001, 0x03000000, + 0x82007ee0, 0x91d02001, 0x01000000 }; + +/* Neither do_save_insn or do_restore_insn save stack configuration + (current_frame, etc), + since the stack is in an indeterminate state through the call to + each of them. That responsibility of the routine which calls them. */ + +static void +do_save_insn (size) + int size; +{ + int g1 = read_register (G1_REGNUM); + CORE_ADDR sp = read_register (SP_REGNUM); + CORE_ADDR pc = read_register (PC_REGNUM); + CORE_ADDR npc = read_register (NPC_REGNUM); + CORE_ADDR fake_pc = sp - sizeof (save_insn_opcodes); + struct inferior_status inf_status; + + save_inferior_status (&inf_status, 0); /* Don't restore stack info */ + /* + * See above. + */ + save_insn_opcodes[0] = 0x03000000 | ((-size >> 10) & 0x3fffff); + save_insn_opcodes[1] = 0x82006000 | (-size & 0x3ff); + save_insn_opcodes[3] = 0x03000000 | ((g1 >> 10) & 0x3fffff); + save_insn_opcodes[4] = 0x82006000 | (g1 & 0x3ff); + write_memory (fake_pc, (char *)save_insn_opcodes, sizeof (save_insn_opcodes)); + + clear_proceed_status (); + stop_after_trap = 1; + proceed (fake_pc, 0, 0); + + write_register (PC_REGNUM, pc); + write_register (NPC_REGNUM, npc); + restore_inferior_status (&inf_status); +} + +/* + * This routine takes a program counter value. It restores the + * register window system to the frame above the current one. + * THIS ROUTINE CLOBBERS PC AND NPC IN THE TARGET! + */ + +/* The following insns translate to: + + restore %g0,%g0,%g0 + t %g0,1 + sethi %hi(0),%g0 */ + +static int restore_insn_opcodes[] = { 0x81e80000, 0x91d02001, 0x01000000 }; + +static void +do_restore_insn () +{ + CORE_ADDR sp = read_register (SP_REGNUM); + CORE_ADDR fake_pc = sp - sizeof (restore_insn_opcodes); + struct inferior_status inf_status; + + save_inferior_status (&inf_status, 0); /* Don't restore stack info */ + + write_memory (fake_pc, (char *)restore_insn_opcodes, + sizeof (restore_insn_opcodes)); + + clear_proceed_status (); + stop_after_trap = 1; + proceed (fake_pc, 0, 0); + + restore_inferior_status (&inf_status); +} + +/* This routine should be more specific in it's actions; making sure + that it uses the same register in the initial prologue section. + Also, FIXME-SOON, it should recognize leaf functions as ones without + a SAVE in the prologue, and pass that info back to the caller so the + PC and arguments can be properly located. */ +CORE_ADDR +skip_prologue (pc) + CORE_ADDR pc; +{ + union + { + unsigned long int code; + struct + { + unsigned int op:2; + unsigned int rd:5; + unsigned int op2:3; + unsigned int imm22:22; + } sethi; + struct + { + unsigned int op:2; + unsigned int rd:5; + unsigned int op3:6; + unsigned int rs1:5; + unsigned int i:1; + unsigned int simm13:13; + } add; + int i; + } x; + int dest = -1; + + x.i = read_memory_integer (pc, 4); + + /* Recognize the `sethi' insn and record its destination. */ + if (x.sethi.op == 0 && x.sethi.op2 == 4) + { + dest = x.sethi.rd; + pc += 4; + x.i = read_memory_integer (pc, 4); + } + + /* Recognize an add immediate value to register to either %g1 or + the destination register recorded above. Actually, this might + well recognize several different arithmetic operations. */ + if (x.add.op == 2 && x.add.i && (x.add.rd == 1 || x.add.rd == dest)) + { + pc += 4; + x.i = read_memory_integer (pc, 4); + } + + /* This recognizes any SAVE insn. But why do the XOR and then + the compare? That's identical to comparing against 60 (as long + as there isn't any sign extension). */ + if (x.add.op == 2 && (x.add.op3 ^ 32) == 28) + { + pc += 4; + x.i = read_memory_integer (pc, 4); + } + + /* Now we need to recognize stores into the frame from the input + registers. This recognizes all non alternate stores of input + register, into a location offset from the frame pointer. */ + while (x.add.op == 3 + && (x.add.op3 & 0x3c) == 4 /* Store, non-alternate. */ + && (x.add.rd & 0x18) == 0x18 /* Input register. */ + && x.add.i /* Immediate mode. */ + && x.add.rs1 == 30 /* Off of frame pointer. */ + /* Into reserved stack space. */ + && x.add.simm13 >= 0x44 + && x.add.simm13 < 0x5b) + { + pc += 4; + x.i = read_memory_integer (pc, 4); + } + return pc; +} + +/* Check instruction at ADDR to see if it is an annulled branch. + All other instructions will go to NPC or will trap. + Set *TARGET if we find a canidate branch; set to zero if not. */ + +branch_type +isannulled (instruction, addr, target) + long instruction; + CORE_ADDR addr, *target; +{ + branch_type val = not_branch; + long int offset; /* Must be signed for sign-extend. */ + union + { + unsigned long int code; + struct + { + unsigned int op:2; + unsigned int a:1; + unsigned int cond:4; + unsigned int op2:3; + unsigned int disp22:22; + } b; + } insn; + + *target = 0; + insn.code = instruction; + + if (insn.b.op == 0 + && (insn.b.op2 == 2 || insn.b.op2 == 6 || insn.b.op2 == 7)) + { + if (insn.b.cond == 8) + val = insn.b.a ? baa : ba; + else + val = insn.b.a ? bicca : bicc; + offset = 4 * ((int) (insn.b.disp22 << 10) >> 10); + *target = addr + offset; + } + + return val; +} + +/* sparc_frame_find_saved_regs () + + Stores, into a struct frame_saved_regs, + the addresses of the saved registers of frame described by FRAME_INFO. + This includes special registers such as pc and fp saved in special + ways in the stack frame. sp is even more special: + the address we return for it IS the sp for the next frame. + + Note that on register window machines, we are currently making the + assumption that window registers are being saved somewhere in the + frame in which they are being used. If they are stored in an + inferior frame, find_saved_register will break. + + On the Sun 4, the only time all registers are saved is when + a dummy frame is involved. Otherwise, the only saved registers + are the LOCAL and IN registers which are saved as a result + of the "save/restore" opcodes. This condition is determined + by address rather than by value. + + The "pc" is not stored in a frame on the SPARC. (What is stored + is a return address minus 8.) sparc_pop_frame knows how to + deal with that. Other routines might or might not. + + See tm-sparc.h (PUSH_FRAME and friends) for CRITICAL information + about how this works. */ + +void +sparc_frame_find_saved_regs (fi, saved_regs_addr) + struct frame_info *fi; + struct frame_saved_regs *saved_regs_addr; +{ + register int regnum; + FRAME_ADDR frame = read_register (FP_REGNUM); + FRAME fid = FRAME_INFO_ID (fi); + + if (!fid) + fatal ("Bad frame info struct in FRAME_FIND_SAVED_REGS"); + + bzero (saved_regs_addr, sizeof (*saved_regs_addr)); + + /* Old test. + if (fi->pc >= frame - CALL_DUMMY_LENGTH - 0x140 + && fi->pc <= frame) */ + + if (fi->pc >= (fi->bottom ? fi->bottom : + read_register (SP_REGNUM)) + && fi->pc <= FRAME_FP(fi)) + { + /* Dummy frame. All but the window regs are in there somewhere. */ + for (regnum = G1_REGNUM; regnum < G1_REGNUM+7; regnum++) + saved_regs_addr->regs[regnum] = + frame + (regnum - G0_REGNUM) * 4 - 0xa0; + for (regnum = I0_REGNUM; regnum < I0_REGNUM+8; regnum++) + saved_regs_addr->regs[regnum] = + frame + (regnum - I0_REGNUM) * 4 - 0xc0; + for (regnum = FP0_REGNUM; regnum < FP0_REGNUM + 32; regnum++) + saved_regs_addr->regs[regnum] = + frame + (regnum - FP0_REGNUM) * 4 - 0x80; + for (regnum = Y_REGNUM; regnum < NUM_REGS; regnum++) + saved_regs_addr->regs[regnum] = + frame + (regnum - Y_REGNUM) * 4 - 0xe0; + frame = fi->bottom ? + fi->bottom : read_register (SP_REGNUM); + } + else + { + /* Normal frame. Just Local and In registers */ + frame = fi->bottom ? + fi->bottom : read_register (SP_REGNUM); + for (regnum = L0_REGNUM; regnum < L0_REGNUM+16; regnum++) + saved_regs_addr->regs[regnum] = frame + (regnum-L0_REGNUM) * 4; + } + if (fi->next) + { + /* Pull off either the next frame pointer or the stack pointer */ + FRAME_ADDR next_next_frame = + (fi->next->bottom ? + fi->next->bottom : + read_register (SP_REGNUM)); + for (regnum = O0_REGNUM; regnum < O0_REGNUM+8; regnum++) + saved_regs_addr->regs[regnum] = next_next_frame + regnum * 4; + } + /* Otherwise, whatever we would get from ptrace(GETREGS) is accurate */ + saved_regs_addr->regs[SP_REGNUM] = FRAME_FP (fi); +} + +/* Push an empty stack frame, and record in it the current PC, regs, etc. + + Note that the write's are of registers in the context of the newly + pushed frame. Thus the the fp*'s, the g*'s, the i*'s, and + the randoms, of the new frame, are being saved. The locals and outs + are new; they don't need to be saved. The i's and l's of + the last frame were saved by the do_save_insn in the register + file (now on the stack, since a context switch happended imm after). + + The return pointer register %i7 does not have + the pc saved into it (return from this frame will be accomplished + by a POP_FRAME). In fact, we must leave it unclobbered, since we + must preserve it in the calling routine except across call instructions. */ + +/* Definitely see tm-sparc.h for more doc of the frame format here. */ + +void +sparc_push_dummy_frame () +{ + CORE_ADDR fp; + char register_temp[REGISTER_BYTES]; + + do_save_insn (0x140); /* FIXME where does this value come from? */ + fp = read_register (FP_REGNUM); + + read_register_bytes (REGISTER_BYTE (FP0_REGNUM), register_temp, 32 * 4); + write_memory (fp - 0x80, register_temp, 32 * 4); + + read_register_bytes (REGISTER_BYTE (G0_REGNUM), register_temp, 8 * 4); + write_memory (fp - 0xa0, register_temp, 8 * 4); + + read_register_bytes (REGISTER_BYTE (I0_REGNUM), register_temp, 8 * 4); + write_memory (fp - 0xc0, register_temp, 8 * 4); + + /* Y, PS, WIM, TBR, PC, NPC, FPS, CPS regs */ + read_register_bytes (REGISTER_BYTE (Y_REGNUM), register_temp, 8 * 4); + write_memory (fp - 0xe0, register_temp, 8 * 4); +} + +/* Discard from the stack the innermost frame, restoring all saved registers. + + Note that the values stored in fsr by get_frame_saved_regs are *in + the context of the called frame*. What this means is that the i + regs of fsr must be restored into the o regs of the (calling) frame that + we pop into. We don't care about the output regs of the calling frame, + since unless it's a dummy frame, it won't have any output regs in it. + + We never have to bother with %l (local) regs, since the called routine's + locals get tossed, and the calling routine's locals are already saved + on its stack. */ + +/* Definitely see tm-sparc.h for more doc of the frame format here. */ + +void +sparc_pop_frame () +{ + register FRAME frame = get_current_frame (); + register CORE_ADDR pc; + struct frame_saved_regs fsr; + struct frame_info *fi; + char raw_buffer[REGISTER_BYTES]; + + fi = get_frame_info (frame); + get_frame_saved_regs (fi, &fsr); + do_restore_insn (); + if (fsr.regs[FP0_REGNUM]) + { + read_memory (fsr.regs[FP0_REGNUM], raw_buffer, 32 * 4); + write_register_bytes (REGISTER_BYTE (FP0_REGNUM), raw_buffer, 32 * 4); + } + if (fsr.regs[G1_REGNUM]) + { + read_memory (fsr.regs[G1_REGNUM], raw_buffer, 7 * 4); + write_register_bytes (REGISTER_BYTE (G1_REGNUM), raw_buffer, 7 * 4); + } + if (fsr.regs[I0_REGNUM]) + { + read_memory (fsr.regs[I0_REGNUM], raw_buffer, 8 * 4); + write_register_bytes (REGISTER_BYTE (O0_REGNUM), raw_buffer, 8 * 4); + } + if (fsr.regs[PS_REGNUM]) + write_register (PS_REGNUM, read_memory_integer (fsr.regs[PS_REGNUM], 4)); + if (fsr.regs[Y_REGNUM]) + write_register (Y_REGNUM, read_memory_integer (fsr.regs[Y_REGNUM], 4)); + if (fsr.regs[PC_REGNUM]) + { + /* Explicitly specified PC (and maybe NPC) -- just restore them. */ + write_register (PC_REGNUM, read_memory_integer (fsr.regs[PC_REGNUM], 4)); + if (fsr.regs[NPC_REGNUM]) + write_register (NPC_REGNUM, + read_memory_integer (fsr.regs[NPC_REGNUM], 4)); + } + else if (fsr.regs[I7_REGNUM]) + { + /* Return address in %i7 -- adjust it, then restore PC and NPC from it */ + pc = PC_ADJUST (read_memory_integer (fsr.regs[I7_REGNUM], 4)); + write_register (PC_REGNUM, pc); + write_register (NPC_REGNUM, pc + 4); + } + flush_cached_frames (); + set_current_frame ( create_new_frame (read_register (FP_REGNUM), + read_pc ())); +} + +/* Structure of SPARC extended floating point numbers. + This information is not currently used by GDB, since no current SPARC + implementations support extended float. */ + +const struct ext_format ext_format_sparc[] = { +/* tot sbyte smask expbyte manbyte */ + { 16, 0, 0x80, 0,1, 4,8 }, /* sparc */ +}; diff --git a/gdb/stack.c b/gdb/stack.c new file mode 100644 index 00000000000..09920130b78 --- /dev/null +++ b/gdb/stack.c @@ -0,0 +1,1139 @@ +/* Print and select stack frames for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include + +#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 (); + +/* 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"); +} + +/* 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); +} + +/* 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); +} + +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); +} + +void +_initialize_stack () +{ +#if 0 + backtrace_limit = 30; +#endif + + add_com ("return", class_stack, return_command, + "Make selected stack frame return to its caller.\n\ +Control remains in the debugger, but when you continue\n\ +execution will resume in the frame above the one now selected.\n\ +If an argument is given, it is an expression for the value to return."); + + add_com ("up", class_stack, up_command, + "Select and print stack frame that called this one.\n\ +An argument says how many frames up to go."); + add_com ("up-silently", class_support, up_silently_command, + "Same as the `up' command, but does not print anything.\n\ +This is useful in command scripts."); + + add_com ("down", class_stack, down_command, + "Select and print stack frame called by this one.\n\ +An argument says how many frames down to go."); + add_com_alias ("do", "down", class_stack, 1); + add_com ("down-silently", class_support, down_silently_command, + "Same as the `down' command, but does not print anything.\n\ +This is useful in command scripts."); + + add_com ("frame", class_stack, frame_command, + "Select and print a stack frame.\n\ +With no argument, print the selected stack frame. (See also \"info frame\").\n\ +An argument specifies the frame to select.\n\ +It can be a stack frame number or the address of the frame.\n\ +With argument, nothing is printed if input is coming from\n\ +a command file or a user-defined command."); + + add_com_alias ("f", "frame", class_stack, 1); + + add_com ("backtrace", class_stack, backtrace_command, + "Print backtrace of all stack frames, or innermost COUNT frames.\n\ +With a negative argument, print outermost -COUNT frames."); + add_com_alias ("bt", "backtrace", class_stack, 0); + add_com_alias ("where", "backtrace", class_alias, 0); + add_info ("stack", backtrace_command, + "Backtrace of the stack, or innermost COUNT frames."); + add_info_alias ("s", "stack", 1); + add_info ("frame", frame_info, + "All about selected stack frame, or frame at ADDR."); + add_info_alias ("f", "frame", 1); + add_info ("locals", locals_info, + "Local variables of current stack frame."); + add_info ("args", args_info, + "Argument variables of current stack frame."); + add_info ("catch", catch_info, + "Exceptions that can be caught in the current stack frame."); + +#if 0 + add_cmd ("backtrace-limit", class_stack, set_backtrace_limit_command, + "Specify maximum number of frames for \"backtrace\" to print by default.", + &setlist); + add_info ("backtrace-limit", backtrace_limit_info, + "The maximum number of frames for \"backtrace\" to print by default."); +#endif +} + diff --git a/gdb/symfile.c b/gdb/symfile.c new file mode 100644 index 00000000000..31aa1e22fc7 --- /dev/null +++ b/gdb/symfile.c @@ -0,0 +1,746 @@ +/* Generic symbol file reading for the GNU debugger, GDB. + Copyright 1990, 1991 Free Software Foundation, Inc. + Contributed by Cygnus Support, using pieces from other GDB modules. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#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 +#include + +#include +#include +#include +#include + +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}, +}; + + +/* 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; +} + +/* 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."); +} + +/* 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); +} + +/* 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); +} + +/* 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; +} + +void +_initialize_symfile () +{ + + add_com ("symbol-file", class_files, symbol_file_command, + "Load symbol table from executable file FILE.\n\ +The `file' command can also load symbol tables, as well as setting the file\n\ +to execute."); + + add_com ("add-syms", class_files, add_syms_command, + "Load the symbols from FILE, assuming FILE has been dynamically loaded.\n\ +The second argument provides the starting address of the file's text."); + + add_com ("load", class_files, load_command, + "Dynamically load FILE into the running program, and record its symbols\n\ +for access from GDB."); + + add_show_from_set + (add_set_cmd ("complaints", class_support, var_uinteger, + (char *)&stop_whining, + "Set max number of complaints about incorrect symbols.", + &setlist), + &showlist); + + obstack_init (symbol_obstack); + obstack_init (psymbol_obstack); +} diff --git a/gdb/symfile.h b/gdb/symfile.h new file mode 100644 index 00000000000..67851170f1f --- /dev/null +++ b/gdb/symfile.h @@ -0,0 +1,170 @@ +/* Definitions for reading symbol files into GDB. + Copyright (C) 1990 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* This file requires that you first include "bfd.h". */ + +/* Data structures and function definitions for dealing with + symbol table reading from files. */ + +/* Structure to keep track of symbol reading functions for various + object file types. */ + +struct sym_fns { + + /* sym_name + is the name, or name prefix, of the BFD "target type" that this + set of functions handles. E.g. "a.out" or "sunOs" or "coff". */ + + char *sym_name; + + /* sym_namelen + counts how many bytes of sym_name should be checked against the + BFD target type of the file being read. If an exact match is + desired, specify the number of characters in sym_name plus 1 for the + NUL. If a prefix match is desired, specify the number of characters in + sym_name. */ + + int sym_namelen; + + /* sym_new_init + initializes anything that is global to the entire + symbol table. It is called e.g. during symbol_file_command, when + we begin debugging an entirely new program. */ + + void (*sym_new_init) (); + + /* sym_init (sf) + reads any initial information from a symbol file, and + initializes the struct sym_fns SF in preparation for sym_read(). + It is called every time we read a symbol file for any reason. */ + + void (*sym_init) (); + + /* sym_read (sf, addr, mainline) + reads a symbol file into a psymtab (or possibly a symtab). + SF is the struct sym_fns that sym_init initialized. ADDR + is the offset between the file's specified start address and + its true address in memory. MAINLINE is 1 if this is the + main symbol table being read, and 0 if a secondary + symbol file (e.g. shared library or dynamically loaded file) + is being read. */ + + void (*sym_read) (); + + /* sym_discard (sf) + discards any cached information from SF or elsewhere, that + was saved as part of reading a single symbol file. */ + + void (*sym_discard) (); + + /* sym_bfd + is the accessor for the symbol file being read. */ + + bfd *sym_bfd; + + /* sym_private + is where information can be shared among sym_init, sym_read and + sym_discard. It is typically a pointer to malloc'd memory. */ + + char *sym_private; /* Should be void * */ + + /* next + finds the next struct sym_fns. They are allocated and initialized + in whatever module implements the functions pointed to; an + initializer calls add_symtab_fns to add them to the global chain. */ + struct sym_fns *next; +}; + + /* Functions */ + +extern void free_named_symtab (); +extern int fill_in_vptr_fieldno (); +extern void add_symtab_fns (); + +/* Functions for dealing with the misc "function" vector, really a misc + address<->symbol mapping vector for things we don't have debug symbols + for. */ + +extern void init_misc_bunches (); +extern void prim_record_misc_function (); +extern void discard_misc_bunches (); +extern void condense_misc_bunches (); + +/* Sorting your symbols for fast lookup or alphabetical printing. */ + +extern void sort_block_syms (); +extern void sort_symtab_syms (); +extern void sort_all_symtab_syms (); +extern void sort_block_syms (); + +/* Make a copy of the string at PTR with SIZE characters in the symbol obstack + (and add a null character at the end in the copy). + Returns the address of the copy. */ + +extern char *obsavestring (); + +/* Concatenate strings S1, S2 and S3; return the new string. + Space is found in the symbol_obstack. */ + +extern char *obconcat (); + + /* Variables */ + +/* File name symbols were loaded from. */ + +extern char *symfile; + +/* The modification date of the file when they were loaded. */ + +extern int symfile_mtime; + +/* The BFD for this file -- only good while we're actively reading + symbols into a psymtab or a symtab. */ + +static bfd *symfile_bfd; + +/* Vectors of all partial symbols read in from file. */ + +extern struct psymbol_allocation_list { + struct partial_symbol *list, *next; + int size; +} global_psymbols, static_psymbols; + +/* Support for complaining about things in the symbol file that aren't + catastrophic. + + Each such thing gets a counter. The first time we have the problem, + during a symbol read, we report it. At the end of symbol reading, + if verbose, we report how many of each problem we had. */ + +struct complaint { + char *message; + unsigned counter; + struct complaint *next; +}; + +/* Root of the chain of complaints that have at some point been issued. + This is used to reset the counters, and/or report the total counts. */ + +extern struct complaint complaint_root[1]; + +/* Functions that handle complaints. (in symfile.c) */ + +int complain(); +void clear_complaints(); diff --git a/gdb/symmisc.c b/gdb/symmisc.c new file mode 100644 index 00000000000..2aead6e20fc --- /dev/null +++ b/gdb/symmisc.c @@ -0,0 +1,442 @@ +/* Do various things to symbol tables (other than lookup)), for GDB. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#include "defs.h" +#include "param.h" +#include "symtab.h" +#include "breakpoint.h" +#include "command.h" + +#include +#include + +static void free_symtab (); + + +/* 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 */ +} + + +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; +} + +/* + * 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; +} + +void +_initialize_symmisc () +{ + symtab_list = (struct symtab *) 0; + partial_symtab_list = (struct partial_symtab *) 0; + + add_com ("printsyms", class_obscure, print_symtabs, + "Print dump of current symbol definitions to file OUTFILE."); +} + diff --git a/gdb/symtab.c b/gdb/symtab.c new file mode 100644 index 00000000000..09f3282f26b --- /dev/null +++ b/gdb/symtab.c @@ -0,0 +1,2622 @@ +/* Symbol table lookup for the GNU debugger, GDB. + Copyright (C) 1986, 1987, 1988, 1989, 1990 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#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 +#include + +#include +#include +#include +#include + +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; +} + +/* 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; +} + +/* 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; +} + + +/* 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); +} + +/* 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; +} + + +/* 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. */ +} + +/* 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; +} + +/* 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; +} + +/* 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 */ +} + +/* 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); +} + +/* 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); +} + + +/* 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); +} + +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, ""); +} + diff --git a/gdb/symtab.h b/gdb/symtab.h new file mode 100644 index 00000000000..e63c8795a98 --- /dev/null +++ b/gdb/symtab.h @@ -0,0 +1,884 @@ +/* Symbol table definitions for GDB. + Copyright (C) 1986, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#if !defined (SYMTAB_H) +#define SYMTAB_H 1 +#include + +/* 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; + +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; +}; + +/* 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]; +}; + +/* 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; +}; + +/* 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 + +/* 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 + +/* Functions that work on the objects described above */ + +extern struct symtab *lookup_symtab (); +extern struct symbol *lookup_symbol (); +extern struct symbol *lookup_block_symbol (); +extern int lookup_misc_func (); +extern void check_stub_type (); +extern void check_stub_method (); +extern struct type *lookup_primitive_typename (); +extern struct type *lookup_typename (); +extern struct type *lookup_unsigned_typename (); +extern struct type *lookup_struct (); +extern struct type *lookup_union (); +extern struct type *lookup_enum (); +extern struct type *lookup_struct_elt_type (); +extern struct type *lookup_pointer_type (); +extern struct type *lookup_function_type (); +extern struct type *lookup_basetype_type (); +extern struct type *create_array_type (); +extern struct symbol *block_function (); +extern struct symbol *find_pc_function (); +extern int find_pc_partial_function (); +extern void clearpc_function_cache (); +extern struct partial_symtab *lookup_partial_symtab (); +extern struct partial_symtab *find_pc_psymtab (); +extern struct symtab *find_pc_symtab (); +extern struct partial_symbol *find_pc_psymbol (); +extern int find_pc_misc_function (); +extern int find_pc_line_pc_range (); +extern char *type_name_no_tag (); +extern int contained_in(); + +/* C++ stuff. */ +extern struct type *lookup_reference_type (); +extern struct type *lookup_member_type (); +extern struct type *lookup_class (); +extern void smash_to_method_type (); +/* end of C++ stuff. */ + +extern void free_all_symtabs (); +extern void free_all_psymtabs (); +extern void free_inclink_symtabs (); +extern void reread_symbols (); + +extern struct type *builtin_type_void; +extern struct type *builtin_type_char; +extern struct type *builtin_type_short; +extern struct type *builtin_type_int; +extern struct type *builtin_type_long; +extern struct type *builtin_type_unsigned_char; +extern struct type *builtin_type_unsigned_short; +extern struct type *builtin_type_unsigned_int; +extern struct type *builtin_type_unsigned_long; +extern struct type *builtin_type_float; +extern struct type *builtin_type_double; +/* This type represents a type that was unrecognized in symbol + read-in. */ +extern struct type *builtin_type_error; + +#ifdef LONG_LONG +extern struct type *builtin_type_long_long; +extern struct type *builtin_type_unsigned_long_long; + +#define BUILTIN_TYPE_LONGEST builtin_type_long_long +#define BUILTIN_TYPE_UNSIGNED_LONGEST builtin_type_unsigned_long_long +/* This should not be a typedef, because "unsigned LONGEST" needs + to work. */ +#define LONGEST long long + +#else /* not LONG_LONG. */ + +#define BUILTIN_TYPE_LONGEST builtin_type_long +#define BUILTIN_TYPE_UNSIGNED_LONGEST builtin_type_unsigned_long +#define LONGEST long + +#endif /* not LONG_LONG. */ + +struct symtab_and_line +{ + struct symtab *symtab; + int line; + CORE_ADDR pc; + CORE_ADDR end; +}; + +struct symtabs_and_lines +{ + struct symtab_and_line *sals; + int nelts; +}; + +/* Given a pc value, return line number it is in. + Second arg nonzero means if pc is on the boundary + use the previous statement's line number. */ + +struct symtab_and_line find_pc_line (); + +/* Given a symtab and line number, return the pc there. */ +extern CORE_ADDR find_line_pc (); +extern int find_line_pc_range (); + +/* Given a string, return the line specified by it. + For commands like "list" and "breakpoint". */ + +struct symtabs_and_lines decode_line_spec (); +struct symtabs_and_lines decode_line_spec_1 (); +struct symtabs_and_lines decode_line_1 (); + +/* Symbol-reading stuff in symfile.c and solib.c. */ +struct symtab *psymtab_to_symtab (); +void clear_solib (); +void symbol_file_add (); + +/* source.c */ +int identify_source_line (); +void print_source_lines (); + +char **make_symbol_completion_list (); + +/* The entry point of a file we are reading. */ +extern CORE_ADDR entry_point; + +#endif /* symtab.h not already included. */ diff --git a/gdb/target.c b/gdb/target.c new file mode 100644 index 00000000000..a58d0cd5c8c --- /dev/null +++ b/gdb/target.c @@ -0,0 +1,563 @@ +/* Select target systems and architectures at runtime for GDB. + Copyright (C) 1990 Free Software Foundation, Inc. + Contributed by Cygnus Support. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include "defs.h" +#include "target.h" +#include "gdbcmd.h" +#include "symtab.h" +#include "inferior.h" +#include "bfd.h" +#include "symfile.h" + +extern int memory_insert_breakpoint(), memory_remove_breakpoint(); +extern void host_convert_to_virtual(), host_convert_from_virtual(); + +static void cleanup_target (); + +/* Pointer to array of target architecture structures; the size of the + array; the current index into the array; the allocated size of the + array. */ +struct target_ops **target_structs; +unsigned target_struct_size; +unsigned target_struct_index; +unsigned target_struct_allocsize; +#define DEFAULT_ALLOCSIZE 10 + +/* The initial current target, so that there is always a semi-valid + current target. */ + +struct target_ops dummy_target = {"None", "None", + 0, 0, 0, 0, /* open, close, attach, detach */ + 0, 0, /* resume, wait */ + 0, 0, 0, 0, 0, /* registers */ + 0, 0, /* memory */ + 0, 0, /* bkpts */ + 0, 0, 0, 0, 0, /* terminal */ + 0, 0, 0, /* kill, load, add_syms */ + 0, 0, /* call_function, lookup_symbol */ + 0, 0, /* create_inferior, mourn_inferior */ + dummy_stratum, 0, /* stratum, next */ + 0, 0, 0, 0, 0, /* all mem, mem, stack, regs, exec */ + OPS_MAGIC, +}; + +/* The target structure we are currently using to talk to a process + or file or whatever "inferior" we have. */ + +struct target_ops *current_target; + +/* The stack of target structures that have been pushed. */ + +struct target_ops **current_target_stack; + + +/* Add a possible target architecture to the list. */ + +void +add_target (t) + struct target_ops *t; +{ + if (t->to_magic != OPS_MAGIC) + { + fprintf(stderr, "Magic number of %s target struct wrong\n", + t->to_shortname); + abort(); + } + + if (!target_structs) + { + target_struct_allocsize = DEFAULT_ALLOCSIZE; + target_structs = (struct target_ops **) xmalloc + (target_struct_allocsize * sizeof (*target_structs)); + } + if (target_struct_size >= target_struct_allocsize) + { + target_struct_allocsize *= 2; + target_structs = (struct target_ops **) xrealloc (target_structs, + target_struct_allocsize * sizeof (*target_structs)); + } + target_structs[target_struct_size++] = t; + cleanup_target (t); +} + +/* Stub functions */ + +static void +ignore () +{ +} + +/* ARGSUSED */ +static int +nomemory (memaddr, myaddr, len, write) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; +{ + return 0; /* No bytes handled */ +} + +static void +tcomplain () +{ + error ("You can't do that when your target is `%s'", + current_target->to_shortname); +} + +static int +noprocess () +{ + error ("You can't do that without a process to debug"); +} + +static int +nosymbol (name, addrp) + char *name; + CORE_ADDR *addrp; +{ + return 1; /* Symbol does not exist in target env */ +} + +static void +default_terminal_info (args, from_tty) + char *args; + int from_tty; +{ + printf("No saved terminal information.\n"); +} + +#if 0 +/* With strata, this function is no longer needed. FIXME. */ +/* This is the default target_create_inferior function. It looks up + the stack for some target that cares to create inferiors, then + calls it -- or complains if not found. */ + +static void +upstack_create_inferior (exec, args, env) + char *exec; + char *args; + char **env; +{ + struct target_ops *t; + + for (t = current_target; + t; + t = t->to_next) + { + if (t->to_create_inferior != upstack_create_inferior) + { + t->to_create_inferior (exec, args, env); + return; + } + + } + tcomplain(); +} +#endif + +/* This is the default target_create_inferior and target_attach function. + If the current target is executing, it asks whether to kill it off. + If this function returns without calling error(), it has killed off + the target, and the operation should be attempted. */ + +static void +kill_or_be_killed (from_tty) + int from_tty; +{ + struct target_ops *savecur; + + if (target_has_execution) + { + printf ("You are already running a program:\n"); + target_files_info (); + if (query ("Kill it? ")) { + savecur = current_target; + target_kill (0, from_tty); + if (target_has_execution) + error ("Killing the program did not help."); + return; + } else { + error ("Program not killed."); + } + } + tcomplain(); +} + +static void +maybe_kill_then_attach (args, from_tty) + char *args; + int from_tty; +{ + kill_or_be_killed (from_tty); + target_attach (args, from_tty); +} + +static void +maybe_kill_then_create_inferior (exec, args, env) + char *exec; + char *args; + char **env; +{ + kill_or_be_killed (0); + target_create_inferior (exec, args, env); +} + +/* Clean up a target struct so it no longer has any zero pointers in it. + We default entries, at least to stubs that print error messages. */ + +static void +cleanup_target (t) + struct target_ops *t; +{ + + /* Check magic number. If wrong, it probably means someone changed + the struct definition, but not all the places that initialize one. */ + if (t->to_magic != OPS_MAGIC) + { + fprintf(stderr, "Magic number of %s target struct wrong\n", + t->to_shortname); + abort(); + } + +#define de_fault(field, value) \ + if (!t->field) t->field = value + + /* FIELD DEFAULT VALUE */ + + de_fault (to_open, tcomplain); + de_fault (to_close, (void (*)())ignore); + de_fault (to_attach, maybe_kill_then_attach); + de_fault (to_detach, (void (*)())ignore); + de_fault (to_resume, (void (*)())noprocess); + de_fault (to_wait, noprocess); + de_fault (to_fetch_registers, noprocess); + de_fault (to_store_registers, noprocess); + de_fault (to_prepare_to_store, (void (*)())noprocess); + de_fault (to_convert_to_virtual, host_convert_to_virtual); + de_fault (to_convert_from_virtual, host_convert_from_virtual); + de_fault (to_xfer_memory, nomemory); + de_fault (to_files_info, ignore); + de_fault (to_insert_breakpoint, memory_insert_breakpoint); + de_fault (to_remove_breakpoint, memory_remove_breakpoint); + de_fault (to_terminal_init, ignore); + de_fault (to_terminal_inferior, ignore); + de_fault (to_terminal_ours_for_output,ignore); + de_fault (to_terminal_ours, ignore); + de_fault (to_terminal_info, default_terminal_info); + de_fault (to_kill, (void (*)())noprocess); + de_fault (to_load, tcomplain); + de_fault (to_add_syms, tcomplain); + de_fault (to_call_function, (struct value *(*)())noprocess); + de_fault (to_lookup_symbol, nosymbol); + de_fault (to_create_inferior, maybe_kill_then_create_inferior); + de_fault (to_mourn_inferior, (void (*)())noprocess); + de_fault (to_next, 0); + de_fault (to_has_all_memory, 0); + de_fault (to_has_memory, 0); + de_fault (to_has_stack, 0); + de_fault (to_has_registers, 0); + de_fault (to_has_execution, 0); + +#undef de_fault +} + +/* Push a new target type into the stack of the existing target accessors, + possibly superseding some of the existing accessors. + + Result is zero if the pushed target ended up on top of the stack, + nonzero if at least one target is on top of it. + + Rather than allow an empty stack, we always have the dummy target at + the bottom stratum, so we can call the function vectors without + checking them. */ + +int +push_target (t) + struct target_ops *t; +{ + struct target_ops *st, *prev; + + for (prev = 0, st = current_target; + st; + prev = st, st = st->to_next) { + if ((int)(t->to_stratum) >= (int)(st->to_stratum)) + break; + } + + while (t->to_stratum == st->to_stratum) { + /* There's already something on this stratum. Close it off. */ + (st->to_close) (0); + if (prev) + prev->to_next = st->to_next; /* Unchain old target_ops */ + else + current_target = st->to_next; /* Unchain first on list */ + st = st->to_next; + } + + /* We have removed all targets in our stratum, now add ourself. */ + t->to_next = st; + if (prev) + prev->to_next = t; + else + current_target = t; + + cleanup_target (current_target); + return prev != 0; +} + +/* Remove a target_ops vector from the stack, wherever it may be. + Return how many times it was removed (0 or 1 unless bug). */ + +int +unpush_target (t) + struct target_ops *t; +{ + struct target_ops *u, *v; + int result = 0; + + for (u = current_target, v = 0; + u; + v = u, u = u->to_next) + if (u == t) + { + if (v == 0) + pop_target(); /* unchain top copy */ + else { + (t->to_close)(0); /* Let it clean up */ + v->to_next = t->to_next; /* unchain middle copy */ + } + result++; + } + return result; +} + +void +pop_target () +{ + (current_target->to_close)(0); /* Let it clean up */ + current_target = current_target->to_next; + if (!current_target) /* At bottom, push dummy. */ + push_target (&dummy_target); +} + +/* Print things about the whole set of targets and about the + current target stack. */ +static void +targets_info () +{ + int i; + + printf("Possible targets:\n\n"); + for (i = 0; i < target_struct_size; i++) + printf ("%-15s %s\n", + target_structs[i]->to_shortname, + target_structs[i]->to_longname); +} + +/* Move memory to or from the targets. Iterate until all of it has + been moved, if necessary. The top target gets priority; anything + it doesn't want, is offered to the next one down, etc. Note the + business with curlen: if an early target says "no, but I have a + boundary overlapping this xfer" then we shorten what we offer to + the subsequent targets so the early guy will get a chance at the + tail before the subsequent ones do. + + Result is 0 or errno value. */ + +int +target_read_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + return target_xfer_memory (memaddr, myaddr, len, 0); +} + +int +target_write_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + return target_xfer_memory (memaddr, myaddr, len, 1); +} + +int +target_xfer_memory (memaddr, myaddr, len, write) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; +{ + int curlen; + int res; + struct target_ops *t; + + /* The quick case is that the top target does it all. */ + res = current_target->to_xfer_memory(memaddr, myaddr, len, write); + if (res == len) + return 0; + + if (res > 0) + goto bump; + /* If res <= 0 then we call it again in the loop. Ah well. */ + + for (; len > 0;) + { + curlen = len; /* Want to do it all */ + for (t = current_target; + t; + t = t->to_has_all_memory? 0: t->to_next) + { + res = t->to_xfer_memory(memaddr, myaddr, curlen, write); + if (res > 0) break; /* Handled all or part of xfer */ + if (res == 0) continue; /* Handled none */ + curlen = -res; /* Could handle once we get past res bytes */ + } + if (res <= 0) + { + /* If this address is for nonexistent memory, + read zeros if reading, or do nothing if writing. Return error. */ + if (!write) + bzero (myaddr, len); + return EIO; + } +bump: + memaddr += res; + myaddr += res; + len -= res; + } + return 0; /* We managed to cover it all somehow. */ +} + + +static void +target_info (args, from_tty) + char *args; + int from_tty; +{ + struct target_ops *t; + int has_all_mem = 0; + + if (symfile != 0) + printf ("Symbols from \"%s\".\n", symfile); + +#ifdef FILES_INFO_HOOK + if (FILES_INFO_HOOK ()) + return; +#endif + + for (t = current_target; + t; + t = t->to_next) + { + if ((int)(t->to_stratum) <= (int)dummy_stratum) + continue; + if (has_all_mem) + printf("\tWhile running this, gdb does not access memory from...\n"); + printf("%s:\n", t->to_longname); + (t->to_files_info)(); + has_all_mem = t->to_has_all_memory; + } +} + +/* The target command selects a target and calls its open routine. + The open routine takes the rest of the parameters from the command, + and (if successful) pushes a new target onto the stack. */ + +static void +target_command (args, from_tty) + char *args; + int from_tty; +{ + int i; + char *rest; + + dont_repeat(); + + if (!args) + error ( + "Argument required (target name). `info targets' lists possible targets"); + + if (target_has_execution) + { + if (query ("A program is being debugged already. Kill it? ")) + target_kill ((char *)0, from_tty); + else + error ("Program not killed."); + } + + /* Skip to first space, or end of args */ + for (rest = args; *rest && !isspace(*rest); rest++) ; + if (*rest == '\0') + rest = 0; /* Only one word in args */ + else + { + *rest = '\0'; /* Terminate first word, scan for next */ + for (rest++; isspace (*rest); rest++) ; + if (*rest == '\0') /* Only one word w/trailing blanks */ + rest = 0; + } + + /* Search target list for a match */ + + for (i = 0; i < target_struct_size; i++) + { + if (!strcmp (args, target_structs[i]->to_shortname)) + goto gotit; + } + error ("No such target. `info targets' will list all targets"); + +gotit: + (*target_structs[i]->to_open) (rest, from_tty); +} + +static char targ_desc[] = + "Names of targets and files being debugged.\n\ +Shows the entire stack of targets currently in use (including the exec-file,\n\ +core-file, and process, if any), as well as the symbol file name."; + +void +_initialize_targets () +{ + current_target = &dummy_target; + cleanup_target (current_target); + + add_info ("targets", targets_info, + "Names of all possible targets.\n\ +A target is typically a protocol for talking to debugging facilities;\n\ +for example, `child' for Unix child processes, or `vxworks' for a\n\ +TCP/IP link to a VxWorks system."); + + add_info ("target", target_info, targ_desc); + add_info ("files", target_info, targ_desc); + + add_com ("target", class_run, target_command, +"Connect to a target machine or process.\n\ +The first argument is the type or protocol of the target machine. Remaining\n\ +arguments are interpreted by the target protocol, but typically include\n\ +things like device names or host names to connect with, process numbers,\n\ +baud rates, etc. You can list all possible targets with the `info targets'\n\ +command."); +} diff --git a/gdb/target.h b/gdb/target.h new file mode 100644 index 00000000000..924f4aaf86a --- /dev/null +++ b/gdb/target.h @@ -0,0 +1,406 @@ +/* Interface between GDB and target environments, including files and processes + Copyright 1990, 1991 Free Software Foundation, Inc. + Contributed by Cygnus Support. Written by John Gilmore. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* This include file defines the interface between the main part + of the debugger, and the part which is target-specific, or + specific to the communications interface between us and the + target. + + A TARGET is an interface between the debugger and a particular + kind of file or process. Targets can be STACKED in STRATA, + so that more than one target can potentially respond to a request. + In particular, memory accesses will walk down the stack of targets + until they find a target that is interested in handling that particular + address. STRATA are artificial boundaries on the stack, within + which particular kinds of targets live. Strata exist so that + people don't get confused by pushing e.g. a process target and then + a file target, and wondering why they can't see the current values + of variables any more (the file target is handling them and they + never get to the process target). So when you push a file target, + it goes into the file stratum, which is always below the process + stratum. */ + +enum strata { + dummy_stratum, /* The lowest of the low */ + file_stratum, /* Executable files, etc */ + core_stratum, /* Core dump files */ + process_stratum, /* Executing processes */ +}; + +struct target_ops { + char *to_shortname; /* Name this target type */ + char *to_longname; /* Name for printing */ +#ifdef __STDC__ + void (*to_open) (char *name, int from_tty); + void (*to_close) (int quitting); + void (*to_attach) (char *name, int from_tty); + void (*to_detach) (char *args, int from_tty); + void (*to_resume) (int step, int siggnal); + int (*to_wait) (int *status); + int (*to_fetch_registers) (int regno); + int (*to_store_registers) (int regno); + void (*to_prepare_to_store) (); + void (*to_convert_to_virtual) (int regnum, char *from, char *to); + void (*to_convert_from_virtual) (int regnum, char *from, char *to); + int (*to_xfer_memory) (CORE_ADDR memaddr, char *myaddr, int len, int w); + void (*to_files_info) (); + int (*to_insert_breakpoint) (CORE_ADDR addr, char *save); + int (*to_remove_breakpoint) (CORE_ADDR addr, char *save); + void (*to_terminal_init) (); + void (*to_terminal_inferior) (); + void (*to_terminal_ours_for_output) (); + void (*to_terminal_ours) (); + void (*to_terminal_info) (char *arg, int from_tty); + void (*to_kill) (char *arg, int from_tty); + void (*to_load) (char *arg, int from_tty); + void (*to_add_syms) (char *arg, int from_tty); +struct value *(*to_call_function) (struct value *function, + int nargs, struct value **args); + int (*to_lookup_symbol) (char *name, CORE_ADDR *addrp); + void (*to_create_inferior) (char *exec, char *args, char **env); + void (*to_mourn_inferior) (); + enum strata to_stratum; +struct target_ops *to_next; + int to_has_all_memory; + int to_has_memory; + int to_has_stack; + int to_has_registers; + int to_has_execution; + int to_magic; +/* Need sub-structure for target machine related rather than comm related? */ +#else /* STDC */ + void (*to_open) (); + void (*to_close) (); + void (*to_attach) (); + void (*to_detach) (); + void (*to_resume) (); + int (*to_wait) (); + int (*to_fetch_registers) (); + int (*to_store_registers) (); + void (*to_prepare_to_store) (); + void (*to_convert_to_virtual) (); + void (*to_convert_from_virtual) (); + int (*to_xfer_memory) (); + void (*to_files_info) (); + int (*to_insert_breakpoint) (); + int (*to_remove_breakpoint) (); + void (*to_terminal_init) (); + void (*to_terminal_inferior) (); + void (*to_terminal_ours_for_output) (); + void (*to_terminal_ours) (); + void (*to_terminal_info) (); + void (*to_kill) (); + void (*to_load) (); + void (*to_add_syms) (); +struct value *(*to_call_function) (); + int (*to_lookup_symbol) (); + void (*to_create_inferior) (); + void (*to_mourn_inferior) (); + enum strata to_stratum; +struct target_ops *to_next; + int to_has_all_memory; + int to_has_memory; + int to_has_stack; + int to_has_registers; + int to_has_execution; + int to_magic; +/* Need sub-structure for target machine related rather than comm related? */ +#endif +}; + +/* Magic number for checking ops size. If a struct doesn't end with this + number, somebody changed the declaration but didn't change all the + places that initialize one. */ + +#define OPS_MAGIC 3840 + +/* The ops structure for our "current" target process. */ + +extern struct target_ops *current_target; + +/* Define easy words for doing these operations on our current target. */ + +#define target_shortname (current_target->to_shortname) +#define target_longname (current_target->to_longname) + +#define target_open(name, from_tty) \ + (*current_target->to_open) (name, from_tty) + +/* Does whatever cleanup is required for a target that we are no longer + going to be calling. Argument says whether we are quitting gdb and + should not get hung in case of errors, or whether we want a clean + termination even if it takes a while. This routine is automatically + always called just before a routine is popped off the target stack. + Closing file descriptors and freeing memory are typical things it should + do. */ + +#define target_close(quitting) \ + (*current_target->to_close) (quitting) + +/* Attaches to a process on the target side. */ + +#define target_attach(args, from_tty) \ + (*current_target->to_attach) (args, from_tty) + +/* Takes a program previously attached to and detaches it. + The program may resume execution (some targets do, some don't) and will + no longer stop on signals, etc. We better not have left any breakpoints + in the program or it'll die when it hits one. ARGS is arguments + typed by the user (e.g. a signal to send the process). FROM_TTY + says whether to be verbose or not. */ + +#define target_detach(args, from_tty) \ + (*current_target->to_detach) (args, from_tty) + +/* Resume execution of the target process. STEP says whether to single-step + or to run free; SIGGNAL is the signal value (e.g. SIGINT) to be given + to the target, or zero for no signal. */ + +#define target_resume(step, siggnal) \ + (*current_target->to_resume) (step, siggnal) + +/* Wait for inferior process to do something. Return pid of child, + or -1 in case of error; store status through argument pointer STATUS. */ + +#define target_wait(status) \ + (*current_target->to_wait) (status) + +/* Fetch register REGNO, or all regs if regno == -1. Result is 0 + for success, -1 for problems. */ + +#define target_fetch_registers(regno) \ + (*current_target->to_fetch_registers) (regno) + +/* Store at least register REGNO, or all regs if REGNO == -1. + It can store as many registers as it wants to, so the entire registers + array must be valid. Result is 0 for success, -1 for problems. */ + +#define target_store_registers(regs) \ + (*current_target->to_store_registers) (regs) + +/* Get ready to modify the registers array. On machines which store + individual registers, this doesn't need to do anything. On machines + which store all the registers in one fell swoop, this makes sure + that REGISTERS contains all the registers from the program being + debugged. */ + +#define target_prepare_to_store() \ + (*current_target->to_prepare_to_store) () + +/* Convert data from raw format for register REGNUM + to virtual format for register REGNUM. */ + +#define target_convert_to_virtual(regnum, from, to) \ + (*current_target->to_convert_to_virtual) (regnum, from, to) + +/* Convert data from virtual format for register REGNUM + to raw format for register REGNUM. */ + +#define target_convert_from_virtual(regnum, from, to) \ + (*current_target->to_convert_from_virtual) (regnum, from, to) + +/* Reading and writing memory actually happens through a glue + function which iterates across the various targets. Result is + 0 for success, or an errno value. */ + +#ifdef __STDC__ +/* Needs defs.h for CORE_ADDR */ +extern int target_read_memory(CORE_ADDR memaddr, char *myaddr, int len); +extern int target_write_memory(CORE_ADDR memaddr, char *myaddr, int len); +extern int target_xfer_memory(CORE_ADDR memaddr, char *myaddr, int len, + int write); +#else +extern int target_read_memory(); +extern int target_write_memory(); +extern int target_xfer_memory(); +#endif + +/* Print a line about the current target. */ + +#define target_files_info() \ + (*current_target->to_files_info) () + +/* Insert a breakpoint at address ADDR in the target machine. + SAVE is a pointer to memory allocated for saving the + target contents. It is guaranteed by the caller to be long enough + to save "sizeof BREAKPOINT" bytes. Result is 0 for success, or + an errno value. */ + +#define target_insert_breakpoint(addr, save) \ + (*current_target->to_insert_breakpoint) (addr, save) + +/* Remove a breakpoint at address ADDR in the target machine. + SAVE is a pointer to the same save area + that was previously passed to target_insert_breakpoint. + Result is 0 for success, or an errno value. */ + +#define target_remove_breakpoint(addr, save) \ + (*current_target->to_remove_breakpoint) (addr, save) + +/* Initialize the terminal settings we record for the inferior, + before we actually run the inferior. */ + +#define target_terminal_init() \ + (*current_target->to_terminal_init) () + +/* Put the inferior's terminal settings into effect. + This is preparation for starting or resuming the inferior. */ + +#define target_terminal_inferior() \ + (*current_target->to_terminal_inferior) () + +/* Put some of our terminal settings into effect, + enough to get proper results from our output, + but do not change into or out of RAW mode + so that no input is discarded. + + After doing this, either terminal_ours or terminal_inferior + should be called to get back to a normal state of affairs. */ + +#define target_terminal_ours_for_output() \ + (*current_target->to_terminal_ours_for_output) () + +/* Put our terminal settings into effect. + First record the inferior's terminal settings + so they can be restored properly later. */ + +#define target_terminal_ours() \ + (*current_target->to_terminal_ours) () + +/* Print useful information about our terminal status, if such a thing + exists. */ + +#define target_terminal_info(arg, from_tty) \ + (*current_target->to_terminal_info) (arg, from_tty) + +/* Kill the inferior process. Make it go away. */ + +#define target_kill(arg, from_tty) \ + (*current_target->to_kill) (arg, from_tty) + +/* Load an executable file into the target process. This is expected to + not only bring new code into the target process, but also to update + GDB's symbol tables to match. */ + +#define target_load(arg, from_tty) \ + (*current_target->to_load) (arg, from_tty) + +/* Add the symbols from an executable file into GDB's symbol table, as if + the file had been loaded at a particular address (or set of addresses). + This does not change any state in the target system, only in GDB. */ + +#define target_add_syms(arg, from_tty) \ + (*current_target->to_add_syms) (arg, from_tty) + +/* Perform a function call in the inferior. + ARGS is a vector of values of arguments (NARGS of them). + FUNCTION is a value, the function to be called. + Returns a value representing what the function returned. + May fail to return, if a breakpoint or signal is hit + during the execution of the function. */ + +#define target_call_function(function, nargs, args) \ + (*current_target->to_call_function) (function, nargs, args) + +/* Look up a symbol in the target's symbol table. NAME is the symbol + name. ADDRP is a CORE_ADDR * pointing to where the value of the symbol + should be returned. The result is 0 if successful, nonzero if the + symbol does not exist in the target environment. This function should + not call error() if communication with the target is interrupted, since + it is called from symbol reading, but should return nonzero, possibly + doing a complain(). */ + +#define target_lookup_symbol(name, addrp) \ + (*current_target->to_lookup_symbol) (name, addrp) + +/* Start an inferior process and set inferior_pid to its pid. + EXEC_FILE is the file to run. + ALLARGS is a string containing the arguments to the program. + ENV is the environment vector to pass. Errors reported with error(). + On VxWorks and various standalone systems, we ignore exec_file. */ + +#define target_create_inferior(exec_file, args, env) \ + (*current_target->to_create_inferior) (exec_file, args, env) + +/* The inferior process has died. Do what is right. */ + +#define target_mourn_inferior() \ + (*current_target->to_mourn_inferior) () + +/* Pointer to next target in the chain, e.g. a core file and an exec file. */ + +#define target_next \ + (current_target->to_next) + +/* Does the target include all of memory, or only part of it? This + determines whether we look up the target chain for other parts of + memory if this target can't satisfy a request. */ + +#define target_has_all_memory \ + (current_target->to_has_all_memory) + +/* Does the target include memory? (Dummy targets don't.) */ + +#define target_has_memory \ + (current_target->to_has_memory) + +/* Does the target have a stack? (Exec files don't, VxWorks doesn't, until + we start a process.) */ + +#define target_has_stack \ + (current_target->to_has_stack) + +/* Does the target have registers? (Exec files don't.) */ + +#define target_has_registers \ + (current_target->to_has_registers) + +/* Does the target have execution? Can we make it jump (through hoops), + or pop its stack a few times, or set breakpoints? */ + +#define target_has_execution \ + (current_target->to_has_execution) + +/* Routines for maintenance of the target structures... + + add_target: Add a target to the list of all possible targets. + + push_target: Make this target the top of the stack of currently used + targets, within its particular stratum of the stack. Result + is 0 if now atop the stack, nonzero if not on top (maybe + should warn user). + + unpush_target: Remove this from the stack of currently used targets, + no matter where it is on the list. Returns 0 if no + change, 1 if removed from stack. + + pop_target: Remove the top thing on the stack of current targets. */ + +#ifdef __STDC__ +void add_target (struct target_ops *); +int push_target (struct target_ops *); +int unpush_target (struct target_ops *); +void pop_target (); +#else +void add_target (); +int push_target (); +int unpush_target (); +void pop_target (); +#endif diff --git a/gdb/terminal.h b/gdb/terminal.h new file mode 100644 index 00000000000..4658c7ab4a3 --- /dev/null +++ b/gdb/terminal.h @@ -0,0 +1,50 @@ +/* Terminal interface definitions for GDB, the GNU Debugger. + Copyright (C) 1986, 1989, 1991 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* Define a common set of macros -- BSD based -- and redefine whatever + the system offers to make it look like that. */ + +#ifdef HAVE_TERMIO + +#include + +#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 +#include +#include +#define TERMINAL struct sgttyb + +#endif /* no termio */ + +extern void new_tty (); diff --git a/gdb/utils.c b/gdb/utils.c new file mode 100644 index 00000000000..1441db12e5d --- /dev/null +++ b/gdb/utils.c @@ -0,0 +1,1294 @@ +/* General utility routines for GDB, the GNU debugger. + Copyright (C) 1986, 1989, 1990, 1991 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include +#include "defs.h" +#include "param.h" +#include "signals.h" +#include "gdbcmd.h" +#include "terminal.h" +#include +#include +#include +#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; + +/* 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); +} + +/* 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); +} + +/* 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 (); +} + +/* 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; +} + +/* 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"); + } +} + +/* 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; + } +} + +/* 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); + } +} + +/* 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 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); +} + +/* 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); + } +} + +#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 */ + +/* 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; +} + +void +_initialize_utils () +{ + struct cmd_list_element *c; + + c = add_set_cmd ("width", class_support, var_uinteger, + (char *)&chars_per_line, + "Set number of characters gdb thinks are in a line.", + &setlist); + add_show_from_set (c, &showlist); + c->function = set_width_command; + + add_show_from_set + (add_set_cmd ("height", class_support, + var_uinteger, (char *)&lines_per_page, + "Set number of lines gdb thinks are in a page.", &setlist), + &showlist); + + /* These defaults will be used if we are unable to get the correct + values from termcap. */ + lines_per_page = 24; + chars_per_line = 80; + /* Initialize the screen height and width from termcap. */ + { + char *termtype = getenv ("TERM"); + + /* Positive means success, nonpositive means failure. */ + int status; + + /* 2048 is large enough for all known terminals, according to the + GNU termcap manual. */ + char term_buffer[2048]; + + if (termtype) + { + status = tgetent (term_buffer, termtype); + if (status > 0) + { + int val; + + val = tgetnum ("li"); + if (val >= 0) + lines_per_page = val; + else + /* The number of lines per page is not mentioned + in the terminal description. This probably means + that paging is not useful (e.g. emacs shell window), + so disable paging. */ + lines_per_page = UINT_MAX; + + val = tgetnum ("co"); + if (val >= 0) + chars_per_line = val; + } + } + } + + set_width_command ((char *)NULL, 0, c); + + add_show_from_set + (add_set_cmd ("demangle", class_support, var_boolean, + (char *)&demangle, + "Set demangling of encoded C++ names when displaying symbols.", + &setlist), + &showlist); + + add_show_from_set + (add_set_cmd ("sevenbit-strings", class_support, var_boolean, + (char *)&sevenbit_strings, + "Set printing of 8-bit characters in strings as \\nnn.", + &setlist), + &showlist); + + add_show_from_set + (add_set_cmd ("asm-demangle", class_support, var_boolean, + (char *)&asm_demangle, + "Set demangling of C++ names in disassembly listings.", + &setlist), + &showlist); +} diff --git a/gdb/valarith.c b/gdb/valarith.c new file mode 100644 index 00000000000..6269defec53 --- /dev/null +++ b/gdb/valarith.c @@ -0,0 +1,694 @@ +/* Perform arithmetic and other operations on values, for GDB. + Copyright (C) 1986, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "defs.h" +#include "param.h" +#include "value.h" +#include "expression.h" +#include "target.h" +#include + + +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 - pointer to . */ + 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; +} + +/* 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_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 */ +} + +/* 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; +} + +/* 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; + } +} + +/* 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)); +} + diff --git a/gdb/valops.c b/gdb/valops.c new file mode 100644 index 00000000000..8031471b360 --- /dev/null +++ b/gdb/valops.c @@ -0,0 +1,1478 @@ +/* Perform non-arithmetic operations on values, for GDB. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#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 + +/* Local functions. */ +static value search_struct_field (); + +/* 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 */ +} + +/* 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. */ + +/* 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; +} + +/* Helper function used by value_struct_elt to recurse through baseclasses. + Look for a field NAME in ARG1. Adjust the address of ARG1 by OFFSET bytes, + and treat the result as having type TYPE. + If found, return value, else return NULL. */ + +static value +search_struct_field (name, arg1, offset, type) + char *name; + register value arg1; + int offset; + register struct type *type; +{ + int i; + + check_stub_type (type); + + for (i = TYPE_NFIELDS (type) - 1; i >= TYPE_N_BASECLASSES (type); i--) + { + char *t_field_name = TYPE_FIELD_NAME (type, i); + if (t_field_name && !strcmp (t_field_name, name)) + return TYPE_FIELD_STATIC (type, i) + ? value_static_field (type, name, i) + : value_primitive_field (arg1, offset, i, type); + } + + for (i = TYPE_N_BASECLASSES (type) - 1; i >= 0; i--) + { + value v; + /* If we are looking for baseclasses, this is what we get when we + hit them. */ + int found_baseclass = !strcmp (name, TYPE_BASECLASS_NAME (type, i)); + + if (BASETYPE_VIA_VIRTUAL (type, i)) + { + value v2; + baseclass_addr (type, i, VALUE_CONTENTS (arg1) + offset, &v2); + if (v2 == 0) + error ("virtual baseclass botch"); + if (found_baseclass) + return v2; + v = search_struct_field (name, v2, 0, TYPE_BASECLASS (type, i)); + if (v) return v; + else continue; + } + if (found_baseclass) + v = value_primitive_field (arg1, offset, i, type); + else + v = search_struct_field (name, arg1, + offset + TYPE_BASECLASS_BITPOS (type, i) / 8, + TYPE_BASECLASS (type, i)); + if (v) return v; + } + return NULL; +} + +/* Helper function used by value_struct_elt to recurse through baseclasses. + Look for a field NAME in ARG1. Adjust the address of ARG1 by OFFSET bytes, + and treat the result as having type TYPE. + If found, return value, else return NULL. */ + +static value +search_struct_method (name, arg1, args, offset, static_memfuncp, type) + char *name; + register value arg1, *args; + int offset, *static_memfuncp; + register struct type *type; +{ + int i; + + check_stub_type (type); + for (i = TYPE_NFN_FIELDS (type) - 1; i >= 0; i--) + { + char *t_field_name = TYPE_FN_FIELDLIST_NAME (type, i); + if (t_field_name && !strcmp (t_field_name, name)) + { + int j; + struct fn_field *f = TYPE_FN_FIELDLIST1 (type, i); + + for (j = TYPE_FN_FIELDLIST_LENGTH (type, i) - 1; j >= 0; --j) + { + if (TYPE_FLAGS (TYPE_FN_FIELD_TYPE (f, j)) & TYPE_FLAG_STUB) + check_stub_method (type, i, j); + if (!typecmp (TYPE_FN_FIELD_STATIC_P (f, j), + TYPE_FN_FIELD_ARGS (f, j), args)) + { + if (TYPE_FN_FIELD_VIRTUAL_P (f, j)) + return (value)value_virtual_fn_field (arg1, f, j); + if (TYPE_FN_FIELD_STATIC_P (f, j) && static_memfuncp) + *static_memfuncp = 1; + return (value)value_fn_field (arg1, i, j); + } + } + } + } + + for (i = TYPE_N_BASECLASSES (type) - 1; i >= 0; i--) + { + value v; + + if (BASETYPE_VIA_VIRTUAL (type, i)) + { + value v2; + baseclass_addr (type, i, VALUE_CONTENTS (arg1) + offset, &v2); + if (v2 == 0) + error ("virtual baseclass botch"); + v = search_struct_method (name, v2, args, 0, + static_memfuncp, TYPE_BASECLASS (type, i)); + if (v) return v; + else continue; + } + + v = search_struct_method (name, arg1, args, + TYPE_BASECLASS_BITPOS (type, i) / 8, + static_memfuncp, TYPE_BASECLASS (type, i)); + if (v) return v; + } + return NULL; +} + +/* Given *ARGP, a value of type (pointer to a)* structure/union, + extract the component named NAME from the ultimate target structure/union + and return it as a value with its appropriate type. + ERR is used in the error message if *ARGP's type is wrong. + + C++: ARGS is a list of argument types to aid in the selection of + an appropriate method. Also, handle derived types. + + STATIC_MEMFUNCP, if non-NULL, points to a caller-supplied location + where the truthvalue of whether the function that was resolved was + a static member function or not is stored. + + ERR is an error message to be printed in case the field is not found. */ + +value +value_struct_elt (argp, args, name, static_memfuncp, err) + register value *argp, *args; + char *name; + int *static_memfuncp; + char *err; +{ + register struct type *t; + int found = 0; /* FIXME, half the time this doesn't get set */ + value arg1_as_ptr = *argp; /* FIXME, set but not used! */ + value v; + + COERCE_ARRAY (*argp); + + t = VALUE_TYPE (*argp); + + /* Follow pointers until we get to a non-pointer. */ + + while (TYPE_CODE (t) == TYPE_CODE_PTR || TYPE_CODE (t) == TYPE_CODE_REF) + { + arg1_as_ptr = *argp; + *argp = value_ind (*argp); + COERCE_ARRAY (*argp); + t = VALUE_TYPE (*argp); + } + + if (TYPE_CODE (t) == TYPE_CODE_MEMBER) + error ("not implemented: member type in value_struct_elt"); + + if (TYPE_CODE (t) != TYPE_CODE_STRUCT + && TYPE_CODE (t) != TYPE_CODE_UNION) + error ("Attempt to extract a component of a value that is not a %s.", err); + + /* Assume it's not, unless we see that it is. */ + if (static_memfuncp) + *static_memfuncp =0; + + if (!args) + { + /* if there are no arguments ...do this... */ + + /* Try as a variable first, because if we succeed, there + is less work to be done. */ + v = search_struct_field (name, *argp, 0, t); + if (v) + return v; + + /* C++: If it was not found as a data field, then try to + return it as a pointer to a method. */ + + if (destructor_name_p (name, t)) + error ("Cannot get value of destructor"); + + v = search_struct_method (name, *argp, args, 0, static_memfuncp, t); + + if (v == 0) + { + if (TYPE_NFN_FIELDS (t)) + error ("There is no member or method named %s.", name); + else + error ("There is no member named %s.", name); + } + return v; + } + + if (destructor_name_p (name, t)) + { + if (!args[1]) + { + /* destructors are a special case. */ + return (value)value_fn_field (*argp, 0, + TYPE_FN_FIELDLIST_LENGTH (t, 0)); + } + else + { + error ("destructor should not have any argument"); + } + } + else + v = search_struct_method (name, *argp, args, 0, static_memfuncp, t); + + if (v == 0) + { + /* See if user tried to invoke data as function. If so, + hand it back. If it's not callable (i.e., a pointer to function), + gdb should give an error. */ + v = search_struct_field (name, *argp, 0, t); + } + + if (!v) + error ("Structure has no component named %s.", name); + return v; +} + +/* C++: return 1 is NAME is a legitimate name for the destructor + of type TYPE. If TYPE does not have a destructor, or + if NAME is inappropriate for TYPE, an error is signaled. */ +int +destructor_name_p (name, type) + char *name; + struct type *type; +{ + /* destructors are a special case. */ + + if (name[0] == '~') + { + char *dname = type_name_no_tag (type); + + if (! TYPE_HAS_DESTRUCTOR (type)) + error ("type `%s' does not have destructor defined", dname); + if (strcmp (dname, name+1)) + error ("name of destructor must equal name of class"); + else + return 1; + } + return 0; +} + +/* Helper function for check_field: Given TYPE, a structure/union, + return 1 if the component named NAME from the ultimate + target structure/union is defined, otherwise, return 0. */ + +static int +check_field_in (type, name) + register struct type *type; + char *name; +{ + register int i; + + for (i = TYPE_NFIELDS (type) - 1; i >= TYPE_N_BASECLASSES (type); i--) + { + char *t_field_name = TYPE_FIELD_NAME (type, i); + if (t_field_name && !strcmp (t_field_name, name)) + return 1; + } + + /* C++: If it was not found as a data field, then try to + return it as a pointer to a method. */ + + /* Destructors are a special case. */ + if (destructor_name_p (name, type)) + return 1; + + for (i = TYPE_NFN_FIELDS (type) - 1; i >= 0; --i) + { + if (!strcmp (TYPE_FN_FIELDLIST_NAME (type, i), name)) + return 1; + } + + for (i = TYPE_N_BASECLASSES (type) - 1; i >= 0; i--) + if (check_field_in (TYPE_BASECLASS (type, i), name)) + return 1; + + return 0; +} + + +/* C++: Given ARG1, a value of type (pointer to a)* structure/union, + return 1 if the component named NAME from the ultimate + target structure/union is defined, otherwise, return 0. */ + +int +check_field (arg1, name) + register value arg1; + char *name; +{ + register struct type *t; + + COERCE_ARRAY (arg1); + + t = VALUE_TYPE (arg1); + + /* Follow pointers until we get to a non-pointer. */ + + while (TYPE_CODE (t) == TYPE_CODE_PTR || TYPE_CODE (t) == TYPE_CODE_REF) + t = TYPE_TARGET_TYPE (t); + + if (TYPE_CODE (t) == TYPE_CODE_MEMBER) + error ("not implemented: member type in check_field"); + + if (TYPE_CODE (t) != TYPE_CODE_STRUCT + && TYPE_CODE (t) != TYPE_CODE_UNION) + error ("Internal error: `this' is not an aggregate"); + + return check_field_in (t, name); +} + +/* C++: Given an aggregate type DOMAIN, and a member name NAME, + return the address of this member as a pointer to member + type. If INTYPE is non-null, then it will be the type + of the member we are looking for. This will help us resolve + pointers to member functions. */ + +value +value_struct_elt_for_address (domain, intype, name) + struct type *domain, *intype; + char *name; +{ + register struct type *t = domain; + register int i; + value v; + + struct type *baseclass; + + if (TYPE_CODE (t) != TYPE_CODE_STRUCT + && TYPE_CODE (t) != TYPE_CODE_UNION) + error ("Internal error: non-aggregate type to value_struct_elt_for_address"); + + baseclass = t; + + while (t) + { + for (i = TYPE_NFIELDS (t) - 1; i >= TYPE_N_BASECLASSES (t); i--) + { + char *t_field_name = TYPE_FIELD_NAME (t, i); + if (t_field_name && !strcmp (t_field_name, name)) + { + if (TYPE_FIELD_STATIC (t, i)) + { + char *phys_name = TYPE_FIELD_STATIC_PHYSNAME (t, i); + struct symbol *sym = + lookup_symbol (phys_name, 0, VAR_NAMESPACE, 0, NULL); + if (! sym) error ("Internal error: could not find physical static variable named %s", phys_name); + v = value_from_long(builtin_type_long, + (CORE_ADDR)SYMBOL_BLOCK_VALUE (sym)); + VALUE_TYPE(v) = lookup_pointer_type (TYPE_FIELD_TYPE (t, i)); + return v; + } + if (TYPE_FIELD_PACKED (t, i)) + error ("pointers to bitfield members not allowed"); + + v = value_from_long (builtin_type_int, + (LONGEST) (TYPE_FIELD_BITPOS (t, i) >> 3)); + VALUE_TYPE (v) + = lookup_pointer_type (lookup_member_type (TYPE_FIELD_TYPE (t, i), baseclass)); + return v; + } + } + + if (TYPE_N_BASECLASSES (t) == 0) + break; + + t = TYPE_BASECLASS (t, 0); + } + + /* C++: If it was not found as a data field, then try to + return it as a pointer to a method. */ + t = baseclass; + + /* Destructors are a special case. */ + if (destructor_name_p (name, t)) + { + error ("pointers to destructors not implemented yet"); + } + + /* Perform all necessary dereferencing. */ + while (intype && TYPE_CODE (intype) == TYPE_CODE_PTR) + intype = TYPE_TARGET_TYPE (intype); + + while (t) + { + for (i = TYPE_NFN_FIELDS (t) - 1; i >= 0; --i) + { + if (!strcmp (TYPE_FN_FIELDLIST_NAME (t, i), name)) + { + int j = TYPE_FN_FIELDLIST_LENGTH (t, i); + struct fn_field *f = TYPE_FN_FIELDLIST1 (t, i); + + if (intype == 0 && j > 1) + error ("non-unique member `%s' requires type instantiation", name); + if (intype) + { + while (j--) + if (TYPE_FN_FIELD_TYPE (f, j) == intype) + break; + if (j < 0) + error ("no member function matches that type instantiation"); + } + else + j = 0; + + if (TYPE_FN_FIELD_VIRTUAL_P (f, j)) + { + v = value_from_long (builtin_type_long, + (LONGEST) TYPE_FN_FIELD_VOFFSET (f, j)); + } + else + { + struct symbol *s = lookup_symbol (TYPE_FN_FIELD_PHYSNAME (f, j), + 0, VAR_NAMESPACE, 0, NULL); + v = locate_var_value (s, 0); + } + VALUE_TYPE (v) = lookup_pointer_type (lookup_member_type (TYPE_FN_FIELD_TYPE (f, j), baseclass)); + return v; + } + } + + if (TYPE_N_BASECLASSES (t) == 0) + break; + + t = TYPE_BASECLASS (t, 0); + } + return 0; +} + +/* Compare two argument lists and return the position in which they differ, + or zero if equal. + + STATICP is nonzero if the T1 argument list came from a + static member function. + + For non-static member functions, we ignore the first argument, + which is the type of the instance variable. This is because we want + to handle calls with objects from derived classes. This is not + entirely correct: we should actually check to make sure that a + requested operation is type secure, shouldn't we? FIXME. */ + +int +typecmp (staticp, t1, t2) + int staticp; + struct type *t1[]; + value t2[]; +{ + int i; + + if (staticp && t1 == 0) + return t2[1] != 0; + if (t1 == 0) + return 1; + if (t1[0]->code == TYPE_CODE_VOID) return 0; + if (t1[!staticp] == 0) return 0; + for (i = !staticp; t1[i] && t1[i]->code != TYPE_CODE_VOID; i++) + { + if (! t2[i] + || t1[i]->code != t2[i]->type->code +/* Too pessimistic: || t1[i]->target_type != t2[i]->type->target_type */ + ) + return i+1; + } + if (!t1[i]) return 0; + return t2[i] ? i+1 : 0; +} + +/* C++: return the value of the class instance variable, if one exists. + Flag COMPLAIN signals an error if the request is made in an + inappropriate context. */ +value +value_of_this (complain) + int complain; +{ + extern FRAME selected_frame; + struct symbol *func, *sym; + struct block *b; + int i; + static const char funny_this[] = "this"; + value this; + + + if (selected_frame == 0) + if (complain) + error ("no frame selected"); + else return 0; + + func = get_frame_function (selected_frame); + if (!func) + { + if (complain) + error ("no `this' in nameless context"); + else return 0; + } + + b = SYMBOL_BLOCK_VALUE (func); + i = BLOCK_NSYMS (b); + if (i <= 0) + if (complain) + error ("no args, no `this'"); + else return 0; + + /* Calling lookup_block_symbol is necessary to get the LOC_REGISTER + symbol instead of the LOC_ARG one (if both exist). */ + sym = lookup_block_symbol (b, funny_this, VAR_NAMESPACE); + if (sym == NULL) + { + if (complain) + error ("current stack frame not in method"); + else + return NULL; + } + + this = read_var_value (sym, selected_frame); + if (this == 0 && complain) + error ("`this' argument at unknown address"); + return this; +} diff --git a/gdb/valprint.c b/gdb/valprint.c new file mode 100644 index 00000000000..9a3ab9055fd --- /dev/null +++ b/gdb/valprint.c @@ -0,0 +1,1915 @@ +/* Print values for GNU debugger gdb. + Copyright (C) 1986, 1988, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#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 +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 + +/* 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, "' ", 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, ""); + 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); + } +} + +/* 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 ("
"); + return 0; + } + if (VALUE_OPTIMIZED_OUT (val)) + { + printf_filtered (""); + 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, " ", 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; +} + +/* 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, ""); + 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, ""); + 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, " ", 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, + ("
" + + 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, ""); + break; + + case TYPE_CODE_ERROR: + fprintf_filtered (stream, "?"); + break; + + default: + error ("Invalid type code in symbol table."); + } + fflush (stream); + return 0; +} + +/* 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, "\n"); + else + fprintf_filtered (stream, "\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, " ", + 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, ""); + break; + + default: + error ("Invalid type code in symbol table."); + } +} + +/* 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); +} + +void +_initialize_valprint () +{ + struct cmd_list_element *c; + + add_show_from_set + (add_set_cmd ("array-max", class_vars, var_uinteger, (char *)&print_max, + "Set limit on string chars or array elements to print.\n\ +\"set array-max 0\" causes there to be no limit.", + &setlist), + &showlist); + + add_show_from_set + (add_set_cmd ("prettyprint", class_support, var_boolean, (char *)&prettyprint, + "Set prettyprinting of structures.", + &setlist), + &showlist); + + add_alias_cmd ("pp", "prettyprint", class_support, 1, &setlist); + + add_show_from_set + (add_set_cmd ("unionprint", class_support, var_boolean, (char *)&unionprint, + "Set printing of unions interior to structures.", + &setlist), + &showlist); + + add_show_from_set + (add_set_cmd ("vtblprint", class_support, var_boolean, (char *)&vtblprint, + "Set printing of C++ virtual function tables.", + &setlist), + &showlist); + + add_show_from_set + (add_set_cmd ("arrayprint", class_support, var_boolean, (char *)&arrayprint, + "Set prettyprinting of arrays.", + &setlist), + &showlist); + + add_show_from_set + (add_set_cmd ("addressprint", class_support, var_boolean, (char *)&addressprint, + "Set printing of addresses.", + &setlist), + &showlist); + +#if 0 + /* The "show radix" cmd isn't good enough to show two separate values. + The rest of the code works, but the show part is confusing, so don't + let them be set separately 'til we work out "show". */ + c = add_set_cmd ("input-radix", class_support, var_uinteger, + (char *)&input_radix, + "Set default input radix for entering numbers.", + &setlist); + add_show_from_set (c, &showlist); + c->function = set_input_radix; + + c = add_set_cmd ("output-radix", class_support, var_uinteger, + (char *)&output_radix, + "Set default output radix for printing of values.", + &setlist); + add_show_from_set (c, &showlist); + c->function = set_output_radix; +#endif + + c = add_set_cmd ("radix", class_support, var_uinteger, + (char *)&output_radix, + "Set default input and output number radix.", + &setlist); + add_show_from_set (c, &showlist); + c->function = set_radix; + + /* Give people the defaults which they are used to. */ + prettyprint = 0; + unionprint = 1; + vtblprint = 0; + arrayprint = 0; + addressprint = 1; + + print_max = 200; + + unsigned_type_table + = (char **) xmalloc ((1 + sizeof (unsigned LONGEST)) * sizeof (char *)); + bzero (unsigned_type_table, (1 + sizeof (unsigned LONGEST))); + unsigned_type_table[sizeof (unsigned char)] = "unsigned char"; + unsigned_type_table[sizeof (unsigned short)] = "unsigned short"; + unsigned_type_table[sizeof (unsigned long)] = "unsigned long"; + unsigned_type_table[sizeof (unsigned int)] = "unsigned int"; +#ifdef LONG_LONG + unsigned_type_table[sizeof (unsigned long long)] = "unsigned long long"; +#endif + + signed_type_table + = (char **) xmalloc ((1 + sizeof (LONGEST)) * sizeof (char *)); + bzero (signed_type_table, (1 + sizeof (LONGEST))); + signed_type_table[sizeof (char)] = "char"; + signed_type_table[sizeof (short)] = "short"; + signed_type_table[sizeof (long)] = "long"; + signed_type_table[sizeof (int)] = "int"; +#ifdef LONG_LONG + signed_type_table[sizeof (long long)] = "long long"; +#endif + + float_type_table + = (char **) xmalloc ((1 + sizeof (double)) * sizeof (char *)); + bzero (float_type_table, (1 + sizeof (double))); + float_type_table[sizeof (float)] = "float"; + float_type_table[sizeof (double)] = "double"; + obstack_begin (&dont_print_obstack, 32 * sizeof (struct type *)); +} diff --git a/gdb/value.h b/gdb/value.h new file mode 100644 index 00000000000..e4ac10120d5 --- /dev/null +++ b/gdb/value.h @@ -0,0 +1,289 @@ +/* Definitions for values of C expressions, for GDB. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#if !defined (VALUE_H) +#define VALUE_H 1 +/* + * The structure which defines the type of a value. It should never + * be possible for a program lval value to survive over a call to the inferior + * (ie to be put into the history list or an internal variable). + */ +enum lval_type { + /* Not an lval. */ + not_lval, + /* In memory. Could be a saved register. */ + lval_memory, + /* In a register. */ + lval_register, + /* In a gdb internal variable. */ + lval_internalvar, + /* Part of a gdb internal variable (structure field). */ + lval_internalvar_component, + /* In a register series in a frame not the current one, which may have been + partially saved or saved in different places (otherwise would be + lval_register or lval_memory). */ + lval_reg_frame_relative, +}; + +struct value + { + /* Type of value; either not an lval, or one of the various + different possible kinds of lval. */ + enum lval_type lval; + /* Location of value (if lval). */ + union + { + /* Address in inferior or byte of registers structure. */ + CORE_ADDR address; + /* Pointer to interrnal variable. */ + struct internalvar *internalvar; + /* Number of register. Only used with + lval_reg_frame_relative. */ + int regnum; + } location; + /* Describes offset of a value within lval a structure in bytes. */ + int offset; + /* Only used for bitfields; number of bits contained in them. */ + int bitsize; + /* Only used for bitfields; position of start of field. */ + int bitpos; + /* Frame value is relative to. In practice, this address is only + used if the value is stored in several registers in other than + the current frame, and these registers have not all been saved + at the same place in memory. This will be described in the + lval enum above as "lval_reg_frame_relative". */ + CORE_ADDR frame_addr; + /* Type of the value. */ + struct type *type; + /* Values are stored in a chain, so that they can be deleted + easily over calls to the inferior. Values assigned to internal + variables or put into the value history are taken off this + list. */ + struct value *next; + /* If an lval is forced to repeat, a new value is created with + these fields set. The new value is not an lval. */ + short repeated; + short repetitions; + /* Register number if the value is from a register. Is not kept + if you take a field of a structure that is stored in a + register. Shouldn't it be? */ + short regno; + /* If zero, contents of this value are in the contents field. + If nonzero, contents are in inferior memory at address + in the location.address field plus the offset field + (and the lval field should be lval_memory). */ + char lazy; + /* If nonzero, this is the value of a variable which does not + actually exist in the program. */ + char optimized_out; + /* Actual contents of the value. For use of this value; setting + it uses the stuff above. Not valid if lazy is nonzero. + Target byte-order. We force it to be aligned properly for any + possible value. */ + union { + long contents[1]; + double force_double_align; +#ifdef LONG_LONG + long long force_longlong_align; +#endif + } aligner; + + }; + +typedef struct value *value; + +#define VALUE_TYPE(val) (val)->type +#define VALUE_LAZY(val) (val)->lazy +/* VALUE_CONTENTS and VALUE_CONTENTS_RAW both return the address of + the gdb buffer used to hold a copy of the contents of the lval. + VALUE_CONTENTS is used when the contents of the buffer are needed -- + it uses value_fetch_lazy() to load the buffer from the process being + debugged if it hasn't already been loaded. VALUE_CONTENTS_RAW is + used when data is being stored into the buffer, or when it is + certain that the contents of the buffer are valid. */ +#define VALUE_CONTENTS_RAW(val) ((char *) (val)->aligner.contents) +#define VALUE_CONTENTS(val) ((void)(VALUE_LAZY(val) && value_fetch_lazy(val)),\ + VALUE_CONTENTS_RAW(val)) +extern int value_fetch_lazy (); +#define VALUE_LVAL(val) (val)->lval +#define VALUE_ADDRESS(val) (val)->location.address +#define VALUE_INTERNALVAR(val) (val)->location.internalvar +#define VALUE_FRAME_REGNUM(val) ((val)->location.regnum) +#define VALUE_FRAME(val) ((val)->frame_addr) +#define VALUE_OFFSET(val) (val)->offset +#define VALUE_BITSIZE(val) (val)->bitsize +#define VALUE_BITPOS(val) (val)->bitpos +#define VALUE_NEXT(val) (val)->next +#define VALUE_REPEATED(val) (val)->repeated +#define VALUE_REPETITIONS(val) (val)->repetitions +#define VALUE_REGNO(val) (val)->regno +#define VALUE_OPTIMIZED_OUT(val) ((val)->optimized_out) + +/* Convert a REF to the object referenced. */ + +#define COERCE_REF(arg) \ +{ if (TYPE_CODE ( VALUE_TYPE (arg)) == TYPE_CODE_REF) \ + arg = value_at_lazy (TYPE_TARGET_TYPE (VALUE_TYPE (arg)), \ + unpack_long (VALUE_TYPE (arg), \ + VALUE_CONTENTS (arg)));} + +/* If ARG is an array, convert it to a pointer. + If ARG is an enum, convert it to an integer. + If ARG is a function, convert it to a function pointer. + + References are dereferenced. */ + +#define COERCE_ARRAY(arg) \ +{ COERCE_REF(arg); \ + if (VALUE_REPEATED (arg) \ + || TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_ARRAY) \ + arg = value_coerce_array (arg); \ + if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_FUNC) \ + arg = value_coerce_function (arg); \ + if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_ENUM) \ + arg = value_cast (builtin_type_unsigned_int, arg); \ +} + +/* If ARG is an enum, convert it to an integer. */ + +#define COERCE_ENUM(arg) \ +{ if (TYPE_CODE ( VALUE_TYPE (arg)) == TYPE_CODE_REF) \ + arg = value_ind (arg); \ + if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_ENUM) \ + arg = value_cast (builtin_type_unsigned_int, arg); \ +} + +/* Internal variables (variables for convenience of use of debugger) + are recorded as a chain of these structures. */ + +struct internalvar +{ + struct internalvar *next; + char *name; + value value; +}; + +#include "symtab.h" +LONGEST value_as_long (); +double value_as_double (); +LONGEST unpack_long (); +double unpack_double (); +long unpack_field_as_long (); +value value_from_long (); +value value_from_double (); +value value_at (); +value value_at_lazy (); +value value_from_register (); +value value_of_variable (); +value value_of_register (); +value read_var_value (); +value locate_var_value (); +value allocate_value (); +value allocate_repeat_value (); +value value_string (); + +value value_binop (); +value value_add (); +value value_sub (); +value value_coerce_array (); +value value_coerce_function (); +value value_ind (); +value value_addr (); +value value_assign (); +value value_neg (); +value value_lognot (); +value value_struct_elt (), value_struct_elt_for_address (); +value value_field (), value_primitive_field (); +value value_cast (); +value value_zero (); +value value_repeat (); +value value_subscript (); + +value value_being_returned (); +int using_struct_return (); +void set_return_value (); + +value evaluate_expression (); +value evaluate_type (); +value parse_and_eval (); +value parse_to_comma_and_eval (); +extern CORE_ADDR parse_and_eval_address (); +extern CORE_ADDR parse_and_eval_address_1 (); + +value access_value_history (); +value value_of_internalvar (); +void set_internalvar (); +void set_internalvar_component (); +struct internalvar *lookup_internalvar (); + +int value_equal (); +int value_less (); +int value_zerop (); + +/* C++ */ +value value_of_this (); +value value_static_field (); +value value_x_binop (); +value value_x_unop (); +value value_fn_field (); +value value_virtual_fn_field (); +value value_static_field (); +int binop_user_defined_p (); +int unop_user_defined_p (); +int typecmp (); +int fill_in_vptr_fieldno (); +int destructor_name_p (); + +#define value_free(val) free (val) +void free_all_values (); +void release_value (); +int record_latest_value (); + +void registers_changed (); +void read_register_bytes (); +void write_register_bytes (); +void read_register_gen (); +CORE_ADDR read_register (); +void write_register (); +void supply_register (); +void get_saved_register (); + +void modify_field (); +void type_print (); +void type_print_1 (); + +/* Possibilities for prettyprint parameters to routines which print + things. */ +enum val_prettyprint { + Val_no_prettyprint = 0, + Val_prettyprint, + /* Use the default setting which the user has specified. */ + Val_pretty_default + }; + +char *baseclass_addr (); +void print_floating (); +int value_print (); +int val_print (); +void print_variable_value (); +char *internalvar_name (); +void clear_value_history (); +void clear_internalvars (); + +#endif /* value.h not already included. */ diff --git a/readline/COPYING b/readline/COPYING new file mode 100644 index 00000000000..9a170375811 --- /dev/null +++ b/readline/COPYING @@ -0,0 +1,249 @@ + + GNU GENERAL PUBLIC LICENSE + Version 1, February 1989 + + Copyright (C) 1989 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The license agreements of most software companies try to keep users +at the mercy of those companies. By contrast, our General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. The +General Public License applies to the Free Software Foundation's +software and to any other program whose authors commit to using it. +You can use it for your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Specifically, the General Public License is designed to make +sure that you have the freedom to give away or sell copies of free +software, that you receive source code or can get it if you want it, +that you can change the software or use pieces of it in new free +programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of a such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must tell them their rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + The precise terms and conditions for copying, distribution and +modification follow. + + 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. + + 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. + + 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 + + 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. + + + Copyright (C) 19yy + + 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. + + , 1 April 1989 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/readline/Makefile.in b/readline/Makefile.in new file mode 100644 index 00000000000..4fb6ceb1fbf --- /dev/null +++ b/readline/Makefile.in @@ -0,0 +1,103 @@ +## -*- text -*- #################################################### +# # +# Makefile for readline and history libraries. # +# # +#################################################################### + +# Here is a rule for making .o files from .c files that doesn't force +# the type of the machine (like -sun3) into the flags. +.c.o: + $(CC) -c $(CFLAGS) $(LOCAL_INCLUDES) $(CPPFLAGS) $(READLINE_DEFINES) $< + +# Destination installation directory. The libraries are copied to DESTDIR +# when you do a `make install', and the header files to INCDIR/readline/*.h. +DESTDIR = /usr/local/lib +INCDIR = /usr/local/include + +# Define TYPES as -DVOID_SIGHANDLER if your operating system uses +# a return type of "void" for signal handlers. +TYPES = -DVOID_SIGHANDLER + +# Define SYSV as -DSYSV if you are using a System V operating system. +#SYSV = -DSYSV + +# HP-UX compilation requires the BSD library. +#LOCAL_LIBS = -lBSD + +# Xenix compilation requires -ldir -lx +#LOCAL_LIBS = -ldir -lx + +# Comment out "-DVI_MODE" if you don't think that anyone will ever desire +# the vi line editing mode and features. +READLINE_DEFINES = $(TYPES) -DVI_MODE + +DEBUG_FLAGS = -g +LDFLAGS = $(DEBUG_FLAGS) +CFLAGS = $(DEBUG_FLAGS) $(SYSV) -I. + +# A good alternative is gcc -traditional. +#CC = gcc -traditional +CC = cc +RANLIB = /usr/bin/ranlib +AR = ar +RM = rm +CP = cp + +LOCAL_INCLUDES = -I../ + +CSOURCES = readline.c history.c funmap.c keymaps.c vi_mode.c \ + emacs_keymap.c vi_keymap.c + +HSOURCES = readline.h chardefs.h history.h keymaps.h +SOURCES = $(CSOURCES) $(HSOURCES) + +DOCUMENTATION = readline.texinfo inc-readline.texinfo \ + history.texinfo inc-history.texinfo + +SUPPORT = COPYING Makefile $(DOCUMENTATION) ChangeLog + +THINGS_TO_TAR = $(SOURCES) $(SUPPORT) + +########################################################################## + +all: libreadline.a + +libreadline.a: readline.o history.o funmap.o keymaps.o + $(RM) -f libreadline.a + $(AR) clq libreadline.a readline.o history.o funmap.o keymaps.o + -if [ -f $(RANLIB) ]; then $(RANLIB) libreadline.a; fi + +readline.o: readline.h chardefs.h keymaps.h history.h readline.c vi_mode.c +history.o: history.c history.h +funmap.o: readline.h +keymaps.o: emacs_keymap.c vi_keymap.c keymaps.h chardefs.h keymaps.c + +libtest: libreadline.a libtest.c + $(CC) -o libtest $(CFLAGS) $(CPPFLAGS) -L. libtest.c -lreadline -ltermcap + +readline: readline.c history.o keymaps.o funmap.o readline.h chardefs.h + $(CC) $(CFLAGS) $(CPPFLAGS) $(READLINE_DEFINES) \ + $(LOCAL_INCLUDES) -DTEST -o readline readline.c funmap.o \ + keymaps.o history.o -L. -ltermcap + +readline.tar: $(THINGS_TO_TAR) + tar -cf readline.tar $(THINGS_TO_TAR) + +readline.tar.Z: readline.tar + compress -f readline.tar + +install: $(DESTDIR)/libreadline.a includes + +includes: + if [ ! -r $(INCDIR)/readline ]; then\ + mkdir $(INCDIR)/readline;\ + chmod a+r $(INCDIR)/readline;\ + fi + $(CP) readline.h keymaps.h chardefs.h $(INCDIR)/readline/ +clean: + rm -f *.o *.a *.log *.cp *.tp *.vr *.fn *.aux *.pg *.toc + +$(DESTDIR)/libreadline.a: libreadline.a + -mv $(DESTDIR)/libreadline.a $(DESTDIR)/libreadline.old + cp libreadline.a $(DESTDIR)/libreadline.a + $(RANLIB) -t $(DESTDIR)/libreadline.a diff --git a/readline/chardefs.h b/readline/chardefs.h new file mode 100644 index 00000000000..9749ae489f4 --- /dev/null +++ b/readline/chardefs.h @@ -0,0 +1,50 @@ +/* chardefs.h -- Character definitions for readline. */ +#ifndef _CHARDEFS_ + +#ifndef savestring +#define savestring(x) (char *)strcpy (xmalloc (1 + strlen (x)), (x)) +#endif + +#ifndef whitespace +#define whitespace(c) (((c) == ' ') || ((c) == '\t')) +#endif + +#ifdef CTRL +#undef CTRL +#endif + +/* Some character stuff. */ +#define control_character_threshold 0x020 /* smaller than this is control */ +#define meta_character_threshold 0x07f /* larger than this is Meta. */ +#define control_character_bit 0x40 /* 0x000000, must be off. */ +#define meta_character_bit 0x080 /* x0000000, must be on. */ + +#define CTRL(c) ((c) & (~control_character_bit)) +#define META(c) ((c) | meta_character_bit) + +#define UNMETA(c) ((c) & (~meta_character_bit)) +#define UNCTRL(c) to_upper(((c)|control_character_bit)) + +#define lowercase_p(c) (((c) > ('a' - 1) && (c) < ('z' + 1))) +#define uppercase_p(c) (((c) > ('A' - 1) && (c) < ('Z' + 1))) + +#define pure_alphabetic(c) (lowercase_p(c) || uppercase_p(c)) + +#ifndef to_upper +#define to_upper(c) (lowercase_p(c) ? ((c) - 32) : (c)) +#define to_lower(c) (uppercase_p(c) ? ((c) + 32) : (c)) +#endif + +#define CTRL_P(c) ((c) < control_character_threshold) +#define META_P(c) ((c) > meta_character_threshold) + +#define NEWLINE '\n' +#define RETURN CTRL('M') +#define RUBOUT 0x07f +#define TAB '\t' +#define ABORT_CHAR CTRL('G') +#define PAGE CTRL('L') +#define SPACE 0x020 +#define ESC CTRL('[') + +#endif /* _CHARDEFS_ */ diff --git a/readline/emacs_keymap.c b/readline/emacs_keymap.c new file mode 100644 index 00000000000..24961de0773 --- /dev/null +++ b/readline/emacs_keymap.c @@ -0,0 +1,472 @@ +/* emacs_keymap.c -- the keymap for emacs_mode in readline (). */ + +/* Copyright (C) 1988,1989 Free Software Foundation, Inc. + + This file is part of GNU Readline, a library for reading lines + of text with interactive input and history editing. + + Readline is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 1, or (at your option) any + later version. + + Readline is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Readline; see the file COPYING. If not, write to the Free + Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef BUFSIZ +#include +#endif /* BUFSIZ */ + +#include "readline.h" + +/* An array of function pointers, one for each possible key. + If the type byte is ISKMAP, then the pointer is the address of + a keymap. */ + +KEYMAP_ENTRY_ARRAY emacs_standard_keymap = { + + /* Control keys. */ + { ISFUNC, (Function *)0x0 }, /* Control-@ */ + { ISFUNC, rl_beg_of_line }, /* Control-a */ + { ISFUNC, rl_backward }, /* Control-b */ + { ISFUNC, (Function *)0x0 }, /* Control-c */ + { ISFUNC, rl_delete }, /* Control-d */ + { ISFUNC, rl_end_of_line }, /* Control-e */ + { ISFUNC, rl_forward }, /* Control-f */ + { ISFUNC, rl_abort }, /* Control-g */ + { ISFUNC, rl_backward }, /* Control-h */ + { ISFUNC, rl_complete }, /* Control-i */ + { ISFUNC, rl_newline }, /* Control-j */ + { ISFUNC, rl_kill_line }, /* Control-k */ + { ISFUNC, rl_clear_screen }, /* Control-l */ + { ISFUNC, rl_newline }, /* Control-m */ + { ISFUNC, rl_get_next_history }, /* Control-n */ + { ISFUNC, (Function *)0x0 }, /* Control-o */ + { ISFUNC, rl_get_previous_history }, /* Control-p */ + { ISFUNC, rl_quoted_insert }, /* Control-q */ + { ISFUNC, rl_reverse_search_history }, /* Control-r */ + { ISFUNC, rl_forward_search_history }, /* Control-s */ + { ISFUNC, rl_transpose_chars }, /* Control-t */ + { ISFUNC, rl_unix_line_discard }, /* Control-u */ + { ISFUNC, rl_quoted_insert }, /* Control-v */ + { ISFUNC, rl_unix_word_rubout }, /* Control-w */ + { ISKMAP, (Function *)emacs_ctlx_keymap }, /* Control-x */ + { ISFUNC, rl_yank }, /* Control-y */ + { ISFUNC, (Function *)0x0 }, /* Control-z */ + { ISKMAP, (Function *)emacs_meta_keymap }, /* Control-[ */ + { ISFUNC, (Function *)0x0 }, /* Control-\ */ + { ISFUNC, (Function *)0x0 }, /* Control-] */ + { ISFUNC, (Function *)0x0 }, /* Control-^ */ + { ISFUNC, rl_undo_command }, /* Control-_ */ + + /* The start of printing characters. */ + { ISFUNC, rl_insert }, /* SPACE */ + { ISFUNC, rl_insert }, /* ! */ + { ISFUNC, rl_insert }, /* " */ + { ISFUNC, rl_insert }, /* # */ + { ISFUNC, rl_insert }, /* $ */ + { ISFUNC, rl_insert }, /* % */ + { ISFUNC, rl_insert }, /* & */ + { ISFUNC, rl_insert }, /* ' */ + { ISFUNC, rl_insert }, /* ( */ + { ISFUNC, rl_insert }, /* ) */ + { ISFUNC, rl_insert }, /* * */ + { ISFUNC, rl_insert }, /* + */ + { ISFUNC, rl_insert }, /* , */ + { ISFUNC, rl_insert }, /* - */ + { ISFUNC, rl_insert }, /* . */ + { ISFUNC, rl_insert }, /* / */ + + /* Regular digits. */ + { ISFUNC, rl_insert }, /* 0 */ + { ISFUNC, rl_insert }, /* 1 */ + { ISFUNC, rl_insert }, /* 2 */ + { ISFUNC, rl_insert }, /* 3 */ + { ISFUNC, rl_insert }, /* 4 */ + { ISFUNC, rl_insert }, /* 5 */ + { ISFUNC, rl_insert }, /* 6 */ + { ISFUNC, rl_insert }, /* 7 */ + { ISFUNC, rl_insert }, /* 8 */ + { ISFUNC, rl_insert }, /* 9 */ + + /* A little more punctuation. */ + { ISFUNC, rl_insert }, /* : */ + { ISFUNC, rl_insert }, /* ; */ + { ISFUNC, rl_insert }, /* < */ + { ISFUNC, rl_insert }, /* = */ + { ISFUNC, rl_insert }, /* > */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* @ */ + + /* Uppercase alphabet. */ + { ISFUNC, rl_insert }, /* A */ + { ISFUNC, rl_insert }, /* B */ + { ISFUNC, rl_insert }, /* C */ + { ISFUNC, rl_insert }, /* D */ + { ISFUNC, rl_insert }, /* E */ + { ISFUNC, rl_insert }, /* F */ + { ISFUNC, rl_insert }, /* G */ + { ISFUNC, rl_insert }, /* H */ + { ISFUNC, rl_insert }, /* I */ + { ISFUNC, rl_insert }, /* J */ + { ISFUNC, rl_insert }, /* K */ + { ISFUNC, rl_insert }, /* L */ + { ISFUNC, rl_insert }, /* M */ + { ISFUNC, rl_insert }, /* N */ + { ISFUNC, rl_insert }, /* O */ + { ISFUNC, rl_insert }, /* P */ + { ISFUNC, rl_insert }, /* Q */ + { ISFUNC, rl_insert }, /* R */ + { ISFUNC, rl_insert }, /* S */ + { ISFUNC, rl_insert }, /* T */ + { ISFUNC, rl_insert }, /* U */ + { ISFUNC, rl_insert }, /* V */ + { ISFUNC, rl_insert }, /* W */ + { ISFUNC, rl_insert }, /* X */ + { ISFUNC, rl_insert }, /* Y */ + { ISFUNC, rl_insert }, /* Z */ + + /* Some more punctuation. */ + { ISFUNC, rl_insert }, /* [ */ + { ISFUNC, rl_insert }, /* \ */ + { ISFUNC, rl_insert }, /* ] */ + { ISFUNC, rl_insert }, /* ^ */ + { ISFUNC, rl_insert }, /* _ */ + { ISFUNC, rl_insert }, /* ` */ + + /* Lowercase alphabet. */ + { ISFUNC, rl_insert }, /* a */ + { ISFUNC, rl_insert }, /* b */ + { ISFUNC, rl_insert }, /* c */ + { ISFUNC, rl_insert }, /* d */ + { ISFUNC, rl_insert }, /* e */ + { ISFUNC, rl_insert }, /* f */ + { ISFUNC, rl_insert }, /* g */ + { ISFUNC, rl_insert }, /* h */ + { ISFUNC, rl_insert }, /* i */ + { ISFUNC, rl_insert }, /* j */ + { ISFUNC, rl_insert }, /* k */ + { ISFUNC, rl_insert }, /* l */ + { ISFUNC, rl_insert }, /* m */ + { ISFUNC, rl_insert }, /* n */ + { ISFUNC, rl_insert }, /* o */ + { ISFUNC, rl_insert }, /* p */ + { ISFUNC, rl_insert }, /* q */ + { ISFUNC, rl_insert }, /* r */ + { ISFUNC, rl_insert }, /* s */ + { ISFUNC, rl_insert }, /* t */ + { ISFUNC, rl_insert }, /* u */ + { ISFUNC, rl_insert }, /* v */ + { ISFUNC, rl_insert }, /* w */ + { ISFUNC, rl_insert }, /* x */ + { ISFUNC, rl_insert }, /* y */ + { ISFUNC, rl_insert }, /* z */ + + /* Final punctuation. */ + { ISFUNC, rl_insert }, /* { */ + { ISFUNC, rl_insert }, /* | */ + { ISFUNC, rl_insert }, /* } */ + { ISFUNC, rl_insert }, /* ~ */ + { ISFUNC, rl_rubout } /* RUBOUT */ +}; + +KEYMAP_ENTRY_ARRAY emacs_meta_keymap = { + + /* Meta keys. Just like above, but the high bit is set. */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-@ */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-a */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-b */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-c */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-d */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-e */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-f */ + { ISFUNC, rl_abort }, /* Meta-Control-g */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-h */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-i */ + { ISFUNC, rl_vi_editing_mode }, /* Meta-Control-j */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-k */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-l */ + { ISFUNC, rl_vi_editing_mode }, /* Meta-Control-m */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-n */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-o */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-p */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-q */ + { ISFUNC, rl_revert_line }, /* Meta-Control-r */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-s */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-t */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-u */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-v */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-w */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-x */ + { ISFUNC, rl_yank_nth_arg }, /* Meta-Control-y */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-z */ + + { ISFUNC, (Function *)0x0 }, /* Meta-Control-[ */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-\ */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-] */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-^ */ + { ISFUNC, (Function *)0x0 }, /* Meta-Control-_ */ + + /* The start of printing characters. */ + { ISFUNC, (Function *)0x0 }, /* Meta-SPACE */ + { ISFUNC, (Function *)0x0 }, /* Meta-! */ + { ISFUNC, (Function *)0x0 }, /* Meta-" */ + { ISFUNC, (Function *)0x0 }, /* Meta-# */ + { ISFUNC, (Function *)0x0 }, /* Meta-$ */ + { ISFUNC, (Function *)0x0 }, /* Meta-% */ + { ISFUNC, (Function *)0x0 }, /* Meta-& */ + { ISFUNC, (Function *)0x0 }, /* Meta-' */ + { ISFUNC, (Function *)0x0 }, /* Meta-( */ + { ISFUNC, (Function *)0x0 }, /* Meta-) */ + { ISFUNC, (Function *)0x0 }, /* Meta-* */ + { ISFUNC, (Function *)0x0 }, /* Meta-+ */ + { ISFUNC, (Function *)0x0 }, /* Meta-, */ + { ISFUNC, rl_digit_argument }, /* Meta-- */ + { ISFUNC, (Function *)0x0 }, /* Meta-. */ + { ISFUNC, (Function *)0x0 }, /* Meta-/ */ + + /* Regular digits. */ + { ISFUNC, rl_digit_argument }, /* Meta-0 */ + { ISFUNC, rl_digit_argument }, /* Meta-1 */ + { ISFUNC, rl_digit_argument }, /* Meta-2 */ + { ISFUNC, rl_digit_argument }, /* Meta-3 */ + { ISFUNC, rl_digit_argument }, /* Meta-4 */ + { ISFUNC, rl_digit_argument }, /* Meta-5 */ + { ISFUNC, rl_digit_argument }, /* Meta-6 */ + { ISFUNC, rl_digit_argument }, /* Meta-7 */ + { ISFUNC, rl_digit_argument }, /* Meta-8 */ + { ISFUNC, rl_digit_argument }, /* Meta-9 */ + + /* A little more punctuation. */ + { ISFUNC, (Function *)0x0 }, /* Meta-: */ + { ISFUNC, (Function *)0x0 }, /* Meta-; */ + { ISFUNC, rl_beginning_of_history }, /* Meta-< */ + { ISFUNC, (Function *)0x0 }, /* Meta-= */ + { ISFUNC, rl_end_of_history }, /* Meta-> */ + { ISFUNC, rl_possible_completions }, /* Meta-? */ + { ISFUNC, (Function *)0x0 }, /* Meta-@ */ + + /* Uppercase alphabet. */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-A */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-B */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-C */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-D */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-E */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-F */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-G */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-H */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-I */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-J */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-K */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-L */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-M */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-N */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-O */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-P */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-Q */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-R */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-S */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-T */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-U */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-V */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-W */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-X */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-Y */ + { ISFUNC, rl_do_lowercase_version }, /* Meta-Z */ + + /* Some more punctuation. */ + { ISFUNC, (Function *)0x0 }, /* Meta-[ */ + { ISFUNC, (Function *)0x0 }, /* Meta-\ */ + { ISFUNC, (Function *)0x0 }, /* Meta-] */ + { ISFUNC, (Function *)0x0 }, /* Meta-^ */ + { ISFUNC, (Function *)0x0 }, /* Meta-_ */ + { ISFUNC, (Function *)0x0 }, /* Meta-` */ + + /* Lowercase alphabet. */ + { ISFUNC, (Function *)0x0 }, /* Meta-a */ + { ISFUNC, rl_backward_word }, /* Meta-b */ + { ISFUNC, rl_capitalize_word }, /* Meta-c */ + { ISFUNC, rl_kill_word }, /* Meta-d */ + { ISFUNC, (Function *)0x0 }, /* Meta-e */ + { ISFUNC, rl_forward_word }, /* Meta-f */ + { ISFUNC, (Function *)0x0 }, /* Meta-g */ + { ISFUNC, (Function *)0x0 }, /* Meta-h */ + { ISFUNC, (Function *)0x0 }, /* Meta-i */ + { ISFUNC, (Function *)0x0 }, /* Meta-j */ + { ISFUNC, (Function *)0x0 }, /* Meta-k */ + { ISFUNC, rl_downcase_word }, /* Meta-l */ + { ISFUNC, (Function *)0x0 }, /* Meta-m */ + { ISFUNC, (Function *)0x0 }, /* Meta-n */ + { ISFUNC, (Function *)0x0 }, /* Meta-o */ + { ISFUNC, (Function *)0x0 }, /* Meta-p */ + { ISFUNC, (Function *)0x0 }, /* Meta-q */ + { ISFUNC, rl_revert_line }, /* Meta-r */ + { ISFUNC, (Function *)0x0 }, /* Meta-s */ + { ISFUNC, rl_transpose_words }, /* Meta-t */ + { ISFUNC, rl_upcase_word }, /* Meta-u */ + { ISFUNC, (Function *)0x0 }, /* Meta-v */ + { ISFUNC, (Function *)0x0 }, /* Meta-w */ + { ISFUNC, (Function *)0x0 }, /* Meta-x */ + { ISFUNC, rl_yank_pop }, /* Meta-y */ + { ISFUNC, (Function *)0x0 }, /* Meta-z */ + + /* Final punctuation. */ + { ISFUNC, (Function *)0x0 }, /* Meta-{ */ + { ISFUNC, (Function *)0x0 }, /* Meta-| */ + { ISFUNC, (Function *)0x0 }, /* Meta-} */ + { ISFUNC, (Function *)0x0 }, /* Meta-~ */ + { ISFUNC, rl_backward_kill_word } /* Meta-rubout */ +}; + +KEYMAP_ENTRY_ARRAY emacs_ctlx_keymap = { + + /* Control keys. */ + { ISFUNC, (Function *)0x0 }, /* Control-@ */ + { ISFUNC, (Function *)0x0 }, /* Control-a */ + { ISFUNC, (Function *)0x0 }, /* Control-b */ + { ISFUNC, (Function *)0x0 }, /* Control-c */ + { ISFUNC, (Function *)0x0 }, /* Control-d */ + { ISFUNC, (Function *)0x0 }, /* Control-e */ + { ISFUNC, (Function *)0x0 }, /* Control-f */ + { ISFUNC, rl_abort }, /* Control-g */ + { ISFUNC, (Function *)0x0 }, /* Control-h */ + { ISFUNC, (Function *)0x0 }, /* Control-i */ + { ISFUNC, (Function *)0x0 }, /* Control-j */ + { ISFUNC, (Function *)0x0 }, /* Control-k */ + { ISFUNC, (Function *)0x0 }, /* Control-l */ + { ISFUNC, (Function *)0x0 }, /* Control-m */ + { ISFUNC, (Function *)0x0 }, /* Control-n */ + { ISFUNC, (Function *)0x0 }, /* Control-o */ + { ISFUNC, (Function *)0x0 }, /* Control-p */ + { ISFUNC, (Function *)0x0 }, /* Control-q */ + { ISFUNC, rl_re_read_init_file }, /* Control-r */ + { ISFUNC, (Function *)0x0 }, /* Control-s */ + { ISFUNC, (Function *)0x0 }, /* Control-t */ + { ISFUNC, rl_undo_command }, /* Control-u */ + { ISFUNC, (Function *)0x0 }, /* Control-v */ + { ISFUNC, (Function *)0x0 }, /* Control-w */ + { ISFUNC, (Function *)0x0 }, /* Control-x */ + { ISFUNC, (Function *)0x0 }, /* Control-y */ + { ISFUNC, (Function *)0x0 }, /* Control-z */ + { ISFUNC, (Function *)0x0 }, /* Control-[ */ + { ISFUNC, (Function *)0x0 }, /* Control-\ */ + { ISFUNC, (Function *)0x0 }, /* Control-] */ + { ISFUNC, (Function *)0x0 }, /* Control-^ */ + { ISFUNC, (Function *)0x0 }, /* Control-_ */ + + /* The start of printing characters. */ + { ISFUNC, (Function *)0x0 }, /* SPACE */ + { ISFUNC, (Function *)0x0 }, /* ! */ + { ISFUNC, (Function *)0x0 }, /* " */ + { ISFUNC, (Function *)0x0 }, /* # */ + { ISFUNC, (Function *)0x0 }, /* $ */ + { ISFUNC, (Function *)0x0 }, /* % */ + { ISFUNC, (Function *)0x0 }, /* & */ + { ISFUNC, (Function *)0x0 }, /* ' */ + { ISFUNC, rl_start_kbd_macro }, /* ( */ + { ISFUNC, rl_end_kbd_macro }, /* ) */ + { ISFUNC, (Function *)0x0 }, /* * */ + { ISFUNC, (Function *)0x0 }, /* + */ + { ISFUNC, (Function *)0x0 }, /* , */ + { ISFUNC, (Function *)0x0 }, /* - */ + { ISFUNC, (Function *)0x0 }, /* . */ + { ISFUNC, (Function *)0x0 }, /* / */ + + /* Regular digits. */ + { ISFUNC, (Function *)0x0 }, /* 0 */ + { ISFUNC, (Function *)0x0 }, /* 1 */ + { ISFUNC, (Function *)0x0 }, /* 2 */ + { ISFUNC, (Function *)0x0 }, /* 3 */ + { ISFUNC, (Function *)0x0 }, /* 4 */ + { ISFUNC, (Function *)0x0 }, /* 5 */ + { ISFUNC, (Function *)0x0 }, /* 6 */ + { ISFUNC, (Function *)0x0 }, /* 7 */ + { ISFUNC, (Function *)0x0 }, /* 8 */ + { ISFUNC, (Function *)0x0 }, /* 9 */ + + /* A little more punctuation. */ + { ISFUNC, (Function *)0x0 }, /* : */ + { ISFUNC, (Function *)0x0 }, /* ; */ + { ISFUNC, (Function *)0x0 }, /* < */ + { ISFUNC, (Function *)0x0 }, /* = */ + { ISFUNC, (Function *)0x0 }, /* > */ + { ISFUNC, (Function *)0x0 }, /* ? */ + { ISFUNC, (Function *)0x0 }, /* @ */ + + /* Uppercase alphabet. */ + { ISFUNC, rl_do_lowercase_version }, /* A */ + { ISFUNC, rl_do_lowercase_version }, /* B */ + { ISFUNC, rl_do_lowercase_version }, /* C */ + { ISFUNC, rl_do_lowercase_version }, /* D */ + { ISFUNC, rl_do_lowercase_version }, /* E */ + { ISFUNC, rl_do_lowercase_version }, /* F */ + { ISFUNC, rl_do_lowercase_version }, /* G */ + { ISFUNC, rl_do_lowercase_version }, /* H */ + { ISFUNC, rl_do_lowercase_version }, /* I */ + { ISFUNC, rl_do_lowercase_version }, /* J */ + { ISFUNC, rl_do_lowercase_version }, /* K */ + { ISFUNC, rl_do_lowercase_version }, /* L */ + { ISFUNC, rl_do_lowercase_version }, /* M */ + { ISFUNC, rl_do_lowercase_version }, /* N */ + { ISFUNC, rl_do_lowercase_version }, /* O */ + { ISFUNC, rl_do_lowercase_version }, /* P */ + { ISFUNC, rl_do_lowercase_version }, /* Q */ + { ISFUNC, rl_do_lowercase_version }, /* R */ + { ISFUNC, rl_do_lowercase_version }, /* S */ + { ISFUNC, rl_do_lowercase_version }, /* T */ + { ISFUNC, rl_do_lowercase_version }, /* U */ + { ISFUNC, rl_do_lowercase_version }, /* V */ + { ISFUNC, rl_do_lowercase_version }, /* W */ + { ISFUNC, rl_do_lowercase_version }, /* X */ + { ISFUNC, rl_do_lowercase_version }, /* Y */ + { ISFUNC, rl_do_lowercase_version }, /* Z */ + + /* Some more punctuation. */ + { ISFUNC, (Function *)0x0 }, /* [ */ + { ISFUNC, (Function *)0x0 }, /* \ */ + { ISFUNC, (Function *)0x0 }, /* ] */ + { ISFUNC, (Function *)0x0 }, /* ^ */ + { ISFUNC, (Function *)0x0 }, /* _ */ + { ISFUNC, (Function *)0x0 }, /* ` */ + + /* Lowercase alphabet. */ + { ISFUNC, (Function *)0x0 }, /* a */ + { ISFUNC, (Function *)0x0 }, /* b */ + { ISFUNC, (Function *)0x0 }, /* c */ + { ISFUNC, (Function *)0x0 }, /* d */ + { ISFUNC, rl_call_last_kbd_macro }, /* e */ + { ISFUNC, (Function *)0x0 }, /* f */ + { ISFUNC, (Function *)0x0 }, /* g */ + { ISFUNC, (Function *)0x0 }, /* h */ + { ISFUNC, (Function *)0x0 }, /* i */ + { ISFUNC, (Function *)0x0 }, /* j */ + { ISFUNC, (Function *)0x0 }, /* k */ + { ISFUNC, (Function *)0x0 }, /* l */ + { ISFUNC, (Function *)0x0 }, /* m */ + { ISFUNC, (Function *)0x0 }, /* n */ + { ISFUNC, (Function *)0x0 }, /* o */ + { ISFUNC, (Function *)0x0 }, /* p */ + { ISFUNC, (Function *)0x0 }, /* q */ + { ISFUNC, (Function *)0x0 }, /* r */ + { ISFUNC, (Function *)0x0 }, /* s */ + { ISFUNC, (Function *)0x0 }, /* t */ + { ISFUNC, (Function *)0x0 }, /* u */ + { ISFUNC, (Function *)0x0 }, /* v */ + { ISFUNC, (Function *)0x0 }, /* w */ + { ISFUNC, (Function *)0x0 }, /* x */ + { ISFUNC, (Function *)0x0 }, /* y */ + { ISFUNC, (Function *)0x0 }, /* z */ + + /* Final punctuation. */ + { ISFUNC, (Function *)0x0 }, /* { */ + { ISFUNC, (Function *)0x0 }, /* | */ + { ISFUNC, (Function *)0x0 }, /* } */ + { ISFUNC, (Function *)0x0 }, /* ~ */ + { ISFUNC, rl_backward_kill_line } /* RUBOUT */ +}; diff --git a/readline/funmap.c b/readline/funmap.c new file mode 100644 index 00000000000..54af607121e --- /dev/null +++ b/readline/funmap.c @@ -0,0 +1,212 @@ +/* funmap.c -- attach names to functions. */ + +/* Copyright (C) 1988,1989 Free Software Foundation, Inc. + + This file is part of GNU Readline, a library for reading lines + of text with interactive input and history editing. + + Readline is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 1, or (at your option) any + later version. + + Readline is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Readline; see the file COPYING. If not, write to the Free + Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define STATIC_MALLOC +#ifndef STATIC_MALLOC +extern char *xmalloc (), *xrealloc (); +#else +static char *xmalloc (), *xrealloc (); +#endif + +#ifndef FILE +#include +#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 + +/* **************************************************************** */ +/* */ +/* xmalloc and xrealloc () */ +/* */ +/* **************************************************************** */ + +static void memory_error_and_abort (); + +static char * +xmalloc (bytes) + int bytes; +{ + char *temp = (char *)malloc (bytes); + + if (!temp) + memory_error_and_abort (); + return (temp); +} + +static char * +xrealloc (pointer, bytes) + char *pointer; + int bytes; +{ + char *temp = (char *)realloc (pointer, bytes); + + if (!temp) + memory_error_and_abort (); + return (temp); +} + +static void +memory_error_and_abort () +{ + fprintf (stderr, "history: Out of virtual memory!\n"); + abort (); +} +#endif /* STATIC_MALLOC */ diff --git a/readline/history.c b/readline/history.c new file mode 100644 index 00000000000..3c07d11833d --- /dev/null +++ b/readline/history.c @@ -0,0 +1,1478 @@ +/* History.c -- standalone history library */ + +/* Copyright (C) 1989 Free Software Foundation, Inc. + + This file contains the GNU History Library (the Library), a set of + routines for managing the text of previously typed lines. + + The Library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + The Library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* The goal is to make the implementation transparent, so that you + don't have to know what data types are used, just what functions + you can call. I think I have done that. */ + +/* Remove these declarations when we have a complete libgnu.a. */ +#define STATIC_MALLOC +#ifndef STATIC_MALLOC +extern char *xmalloc (), *xrealloc (); +#else +static char *xmalloc (), *xrealloc (); +#endif + +#include + +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else +#if defined (sparc) && defined (sun) +#include +#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); +} + + +/* **************************************************************** */ +/* */ +/* 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 + +/* **************************************************************** */ +/* */ +/* 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 */ + + +/* **************************************************************** */ +/* */ +/* 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 */ + +/* +* Local variables: +* compile-command: "gcc -g -DTEST -o history history.c" +* end: +*/ diff --git a/readline/history.h b/readline/history.h new file mode 100644 index 00000000000..0bac2092079 --- /dev/null +++ b/readline/history.h @@ -0,0 +1,108 @@ +/* History.h -- the names of functions that you can call in history. */ + +typedef struct _hist_entry { + char *line; + char *data; +} HIST_ENTRY; + +/* For convenience only. You set this when interpreting history commands. + It is the logical offset of the first history element. */ +extern int history_base; + +/* Begin a session in which the history functions might be used. This + just initializes the interactive variables. */ +extern void using_history (); + +/* Place STRING at the end of the history list. + The associated data field (if any) is set to NULL. */ +extern void add_history (); + +/* Returns the number which says what history element we are now + looking at. */ +extern int where_history (); + +/* Set the position in the history list to POS. */ +int history_set_pos (); + +/* Search for STRING in the history list, starting at POS, an + absolute index into the list. DIR, if negative, says to search + backwards from POS, else forwards. + Returns the absolute index of the history element where STRING + was found, or -1 otherwise. */ +extern int history_search_pos (); + +/* A reasonably useless function, only here for completeness. WHICH + is the magic number that tells us which element to delete. The + elements are numbered from 0. */ +extern HIST_ENTRY *remove_history (); + +/* Stifle the history list, remembering only MAX number of entries. */ +extern void stifle_history (); + +/* Stop stifling the history. This returns the previous amount the + history was stifled by. The value is positive if the history was + stifled, negative if it wasn't. */ +extern int unstifle_history (); + +/* Add the contents of FILENAME to the history list, a line at a time. + If FILENAME is NULL, then read from ~/.history. Returns 0 if + successful, or errno if not. */ +extern int read_history (); + +/* Append the current history to FILENAME. If FILENAME is NULL, + then append the history list to ~/.history. Values returned + are as in read_history (). */ +extern int write_history (); + + +/* Make the history entry at WHICH have LINE and DATA. This returns + the old entry so you can dispose of the data. In the case of an + invalid WHICH, a NULL pointer is returned. */ +extern HIST_ENTRY *replace_history_entry (); + +/* Return the history entry at the current position, as determined by + history_offset. If there is no entry there, return a NULL pointer. */ +HIST_ENTRY *current_history (); + +/* Back up history_offset to the previous history entry, and return + a pointer to that entry. If there is no previous entry, return + a NULL pointer. */ +extern HIST_ENTRY *previous_history (); + +/* Move history_offset forward to the next item in the input_history, + and return the a pointer to that entry. If there is no next entry, + return a NULL pointer. */ +extern HIST_ENTRY *next_history (); + +/* Return a NULL terminated array of HIST_ENTRY which is the current input + history. Element 0 of this list is the beginning of time. If there + is no history, return NULL. */ +extern HIST_ENTRY **history_list (); + +/* Search the history for STRING, starting at history_offset. + If DIRECTION < 0, then the search is through previous entries, + else through subsequent. If the string is found, then + current_history () is the history entry, and the value of this function + is the offset in the line of that history entry that the string was + found in. Otherwise, nothing is changed, and a -1 is returned. */ +extern int history_search (); + +/* Expand the string STRING, placing the result into OUTPUT, a pointer + to a string. Returns: + + 0) If no expansions took place (or, if the only change in + the text was the de-slashifying of the history expansion + character) + 1) If expansions did take place + -1) If there was an error in expansion. + + If an error ocurred in expansion, then OUTPUT contains a descriptive + error message. */ +extern int history_expand (); + +/* Extract a string segment consisting of the FIRST through LAST + arguments present in STRING. Arguments are broken up as in + the shell. */ +extern char *history_arg_extract (); + + diff --git a/readline/keymaps.c b/readline/keymaps.c new file mode 100644 index 00000000000..b7c79cec622 --- /dev/null +++ b/readline/keymaps.c @@ -0,0 +1,172 @@ +/* keymaps.c -- Functions and keymaps for the GNU Readline library. */ + +/* Copyright (C) 1988,1989 Free Software Foundation, Inc. + + This file is part of GNU Readline, a library for reading lines + of text with interactive input and history editing. + + Readline is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 1, or (at your option) any + later version. + + Readline is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Readline; see the file COPYING. If not, write to the Free + Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "keymaps.h" +#include "emacs_keymap.c" + +#ifdef VI_MODE +#include "vi_keymap.c" +#endif + +/* Remove these declarations when we have a complete libgnu.a. */ +#define STATIC_MALLOC +#ifndef STATIC_MALLOC +extern char *xmalloc (), *xrealloc (); +#else +static char *xmalloc (), *xrealloc (); +#endif + +/* **************************************************************** */ +/* */ +/* Functions for manipulating Keymaps. */ +/* */ +/* **************************************************************** */ + + +/* Return a new, empty keymap. + Free it with free() when you are done. */ +Keymap +rl_make_bare_keymap () +{ + register int i; + Keymap keymap = (Keymap)xmalloc (128 * sizeof (KEYMAP_ENTRY)); + + for (i = 0; i < 128; i++) + { + keymap[i].type = ISFUNC; + keymap[i].function = (Function *)NULL; + } + + for (i = 'A'; i < ('Z' + 1); i++) + { + keymap[i].type = ISFUNC; + keymap[i].function = rl_do_lowercase_version; + } + + return (keymap); +} + +/* Return a new keymap which is a copy of MAP. */ +Keymap +rl_copy_keymap (map) + Keymap map; +{ + register int i; + Keymap temp = rl_make_bare_keymap (); + + for (i = 0; i < 128; i++) + { + temp[i].type = map[i].type; + temp[i].function = map[i].function; + } + return (temp); +} + +/* Return a new keymap with the printing characters bound to rl_insert, + the uppercase Meta characters bound to run their lowercase equivalents, + and the Meta digits bound to produce numeric arguments. */ +Keymap +rl_make_keymap () +{ + extern rl_insert (), rl_rubout (), rl_do_lowercase_version (); + extern rl_digit_argument (); + register int i; + Keymap newmap; + + newmap = rl_make_bare_keymap (); + + /* All printing characters are self-inserting. */ + for (i = ' '; i < 126; i++) + newmap[i].function = rl_insert; + + newmap[TAB].function = rl_insert; + newmap[RUBOUT].function = rl_rubout; + + return (newmap); +} + +/* Free the storage associated with MAP. */ +rl_discard_keymap (map) + Keymap (map); +{ + int i; + + if (!map) + return; + + for (i = 0; i < 128; i++) + { + switch (map[i].type) + { + case ISFUNC: + break; + + case ISKMAP: + rl_discard_keymap ((Keymap)map[i].function); + break; + + case ISMACR: + free ((char *)map[i].function); + break; + } + } +} + +#ifdef STATIC_MALLOC + +/* **************************************************************** */ +/* */ +/* xmalloc and xrealloc () */ +/* */ +/* **************************************************************** */ + +static void memory_error_and_abort (); + +static char * +xmalloc (bytes) + int bytes; +{ + char *temp = (char *)malloc (bytes); + + if (!temp) + memory_error_and_abort (); + return (temp); +} + +static char * +xrealloc (pointer, bytes) + char *pointer; + int bytes; +{ + char *temp = (char *)realloc (pointer, bytes); + + if (!temp) + memory_error_and_abort (); + return (temp); +} + +static void +memory_error_and_abort () +{ + fprintf (stderr, "readline: Out of virtual memory!\n"); + abort (); +} +#endif /* STATIC_MALLOC */ diff --git a/readline/keymaps.h b/readline/keymaps.h new file mode 100644 index 00000000000..3c577b398f5 --- /dev/null +++ b/readline/keymaps.h @@ -0,0 +1,53 @@ +/* keymaps.h -- Manipulation of readline keymaps. */ + +#ifndef _KEYMAPS_H_ +#define _KEYMAPS_H_ + +#include + +#ifndef __FUNCTION_DEF +typedef int Function (); +#define __FUNCTION_DEF +#endif + +/* A keymap contains one entry for each key in the ASCII set. + Each entry consists of a type and a pointer. + POINTER is the address of a function to run, or the + address of a keymap to indirect through. + TYPE says which kind of thing POINTER is. */ +typedef struct _keymap_entry { + char type; + Function *function; +} KEYMAP_ENTRY; + +/* I wanted to make the above structure contain a union of: + union { Function *function; struct _keymap_entry *keymap; } value; + but this made it impossible for me to create a static array. + Maybe I need C lessons. */ + +typedef KEYMAP_ENTRY KEYMAP_ENTRY_ARRAY[128]; +typedef KEYMAP_ENTRY *Keymap; + +/* The values that TYPE can have in a keymap entry. */ +#define ISFUNC 0 +#define ISKMAP 1 +#define ISMACR 2 + +extern KEYMAP_ENTRY_ARRAY emacs_standard_keymap, emacs_meta_keymap, emacs_ctlx_keymap; +extern KEYMAP_ENTRY_ARRAY vi_insertion_keymap, vi_movement_keymap; + +/* Return a new, empty keymap. + Free it with free() when you are done. */ +Keymap rl_make_bare_keymap (); + +/* Return a new keymap which is a copy of MAP. */ +Keymap rl_copy_keymap (); + +/* Return a new keymap with the printing characters bound to rl_insert, + the lowercase Meta characters bound to run their equivalents, and + the Meta digits bound to produce numeric arguments. */ +Keymap rl_make_keymap (); + +#endif /* _KEYMAPS_H_ */ + + diff --git a/readline/readline.c b/readline/readline.c new file mode 100644 index 00000000000..b05a7c97e5b --- /dev/null +++ b/readline/readline.c @@ -0,0 +1,5641 @@ +/* readline.c -- a general facility for reading lines of input + with emacs style editing and completion. */ + +/* Copyright (C) 1987,1989 Free Software Foundation, Inc. + + This file contains the Readline Library (the Library), a set of + routines for providing Emacs style line input to programs that ask + for it. + + The Library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + The Library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Remove these declarations when we have a complete libgnu.a. */ +#define STATIC_MALLOC +#ifndef STATIC_MALLOC +extern char *xmalloc (), *xrealloc (); +#else +static char *xmalloc (), *xrealloc (); +#endif + +#include +#include +#include +#include +#include + +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else +#if defined (sparc) && defined (sun) +#include +#endif +#endif + +#define NEW_TTY_DRIVER +#if defined (SYSV) || defined (hpux) || defined (Xenix) +#undef NEW_TTY_DRIVER +#include +#else +#include +#endif + +#include +extern int errno; + +#include + +/* These next are for filename completion. Perhaps this belongs + in a different place. */ +#include + +#include +#ifdef SYSV +struct passwd *getpwuid (), *getpwent (); +#endif + +#define HACK_TERMCAP_MOTION + +#ifndef SYSV +#include +#else /* SYSV */ +#if defined (Xenix) +#include +#else +#ifdef hpux +#include +#else +#include +#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 + + +/* **************************************************************** */ +/* */ +/* 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 + + +/* **************************************************************** */ +/* */ +/* `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; + + +/* **************************************************************** */ +/* */ +/* 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 . */ + 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)); +} + + +/* **************************************************************** */ +/* */ +/* 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 */ + + +/* **************************************************************** */ +/* */ +/* 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; +} + + +/* **************************************************************** */ +/* */ +/* 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)); +} + + +/* **************************************************************** */ +/* */ +/* 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 */ +} + + +/* **************************************************************** */ +/* */ +/* 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; + } + } + } +} + + +/* **************************************************************** */ +/* */ +/* 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 (); +} + +/* **************************************************************** */ +/* */ +/* 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); + } +} + + +/* **************************************************************** */ +/* */ +/* 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 */ + + +/* **************************************************************** */ +/* */ +/* 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); +} + + +/* **************************************************************** */ +/* */ +/* 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'; +} + + +/* **************************************************************** */ +/* */ +/* 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. +*/ + + +/* **************************************************************** */ +/* */ +/* 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; +} + + +/* **************************************************************** */ +/* */ +/* 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); +} + + +/* **************************************************************** */ +/* */ +/* 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; + } +} + + + +/* **************************************************************** */ +/* */ +/* 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--; + } +} + + +/* **************************************************************** */ +/* */ +/* 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); +} + + +/* **************************************************************** */ +/* */ +/* 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; + } + } +} + +/* **************************************************************** */ +/* */ +/* 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; + } +} + + + +/* **************************************************************** */ +/* */ +/* 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; +{ +} + + + +/* **************************************************************** */ +/* */ +/* 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; +} + +/* **************************************************************** */ +/* */ +/* 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; +} + + +/* **************************************************************** */ +/* */ +/* 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. 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); + } +} + + +/* **************************************************************** */ +/* */ +/* 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); +} + + +/* **************************************************************** */ +/* */ +/* 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); +} + + +/* **************************************************************** */ +/* */ +/* 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 + +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 + +/* **************************************************************** */ +/* */ +/* 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 */ + + +/* **************************************************************** */ +/* */ +/* 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 */ + + +/* + * Local variables: + * compile-command: "gcc -g -traditional -I. -I.. -DTEST -o readline readline.c keymaps.o funmap.o history.o -ltermcap" + * end: + */ diff --git a/readline/readline.h b/readline/readline.h new file mode 100644 index 00000000000..3e62976c505 --- /dev/null +++ b/readline/readline.h @@ -0,0 +1,170 @@ +/* Readline.h -- the names of functions callable from within readline. */ + +#ifndef _READLINE_H_ +#define _READLINE_H_ + +#include + +#ifndef __FUNCTION_DEF +typedef int Function (); +#define __FUNCTION_DEF +#endif + +/* The functions for manipulating the text of the line within readline. +Most of these functions are bound to keys by default. */ +extern int +rl_beg_of_line (), rl_backward (), rl_delete (), rl_end_of_line (), +rl_forward (), ding (), rl_backward (), rl_newline (), rl_kill_line (), +rl_clear_screen (), rl_get_next_history (), rl_get_previous_history (), +rl_quoted_insert (), rl_reverse_search_history (), rl_transpose_chars +(), rl_unix_line_discard (), rl_quoted_insert (), rl_unix_word_rubout +(), rl_yank (), rl_rubout (), rl_backward_word (), rl_kill_word (), +rl_forward_word (), rl_tab_insert (), rl_yank_pop (), rl_yank_nth_arg (), +rl_backward_kill_word (), rl_backward_kill_line (), rl_transpose_words +(), rl_complete (), rl_possible_completions (), rl_do_lowercase_version +(), rl_digit_argument (), rl_universal_argument (), rl_abort (), +rl_undo_command (), rl_revert_line (), rl_beginning_of_history (), +rl_end_of_history (), rl_forward_search_history (), rl_insert (), +rl_upcase_word (), rl_downcase_word (), rl_capitalize_word (), +rl_restart_output (), rl_re_read_init_file (); + +/* These are *both* defined even when VI_MODE is not. */ +extern int rl_vi_editing_mode (), rl_emacs_editing_mode (); + +#ifdef VI_MODE +/* Things for vi mode. */ +extern int rl_vi_movement_mode (), rl_vi_insertion_mode (), rl_vi_arg_digit (), +rl_vi_prev_word (), rl_vi_next_word (), rl_vi_char_search (), +rl_vi_eof_maybe (), rl_vi_append_mode (), rl_vi_put (), +rl_vi_append_eol (), rl_vi_insert_beg (), rl_vi_delete (), rl_vi_comment (), +rl_vi_first_print (), rl_vi_fword (), rl_vi_fWord (), rl_vi_bword (), +rl_vi_bWord (), rl_vi_eword (), rl_vi_eWord (), rl_vi_end_word (), +rl_vi_change_case (), rl_vi_match (), rl_vi_bracktype (), rl_vi_change_char (), +rl_vi_yank_arg (), rl_vi_search (), rl_vi_search_again (), +rl_vi_dosearch (), rl_vi_subst (), rl_vi_overstrike (), +rl_vi_overstrike_delete (), rl_vi_replace(), rl_vi_column (), +rl_vi_delete_to (), rl_vi_change_to (), rl_vi_yank_to (), rl_vi_complete (); +#endif /* VI_MODE */ + +/* Keyboard macro commands. */ +extern int +rl_start_kbd_macro (), rl_end_kbd_macro (), rl_call_last_kbd_macro (); + +/* Maintaining the state of undo. We remember individual deletes and inserts + on a chain of things to do. */ + +/* The actions that undo knows how to undo. Notice that UNDO_DELETE means + to insert some text, and UNDO_INSERT means to delete some text. I.e., + the code tells undo what to undo, not how to undo it. */ +enum undo_code { UNDO_DELETE, UNDO_INSERT, UNDO_BEGIN, UNDO_END }; + +/* What an element of THE_UNDO_LIST looks like. */ +typedef struct undo_list { + struct undo_list *next; + int start, end; /* Where the change took place. */ + char *text; /* The text to insert, if undoing a delete. */ + enum undo_code what; /* Delete, Insert, Begin, End. */ +} UNDO_LIST; + +/* The current undo list for RL_LINE_BUFFER. */ +extern UNDO_LIST *rl_undo_list; + +/* The data structure for mapping textual names to code addresses. */ +typedef struct { + char *name; + Function *function; +} FUNMAP; + +extern FUNMAP **funmap; + +/* **************************************************************** */ +/* */ +/* Well Published Variables */ +/* */ +/* **************************************************************** */ + +/* The name of the calling program. You should initialize this to + whatever was in argv[0]. It is used when parsing conditionals. */ +extern char *rl_readline_name; + +/* The line buffer that is in use. */ +extern char *rl_line_buffer; + +/* The location of point, and end. */ +extern int rl_point, rl_end; + +/* The name of the terminal to use. */ +extern char *rl_terminal_name; + +/* The input and output streams. */ +extern FILE *rl_instream, *rl_outstream; + +/* The basic list of characters that signal a break between words for the + completer routine. The contents of this variable is what breaks words + in the shell, i.e. "n\"\\'`@$>". */ +extern char *rl_basic_word_break_characters; + +/* The list of characters that signal a break between words for + rl_complete_internal. The default list is the contents of + rl_basic_word_break_characters. */ +extern char *rl_completer_word_break_characters; + +/* List of characters that are word break characters, but should be left + in TEXT when it is passed to the completion function. The shell uses + this to help determine what kind of completing to do. */ +extern char *rl_special_prefixes; + +/* Pointer to the generator function for completion_matches (). + NULL means to use filename_entry_function (), the default filename + completer. */ +extern Function *rl_completion_entry_function; + +/* Pointer to alternative function to create matches. + Function is called with TEXT, START, and END. + START and END are indices in RL_LINE_BUFFER saying what the boundaries + of TEXT are. + If this function exists and returns NULL then call the value of + rl_completion_entry_function to try to match, otherwise use the + array of strings returned. */ +extern Function *rl_attempted_completion_function; + +/* If non-null, this contains the address of a function to call if the + standard meaning for expanding a tilde fails. The function is called + with the text (sans tilde, as in "foo"), and returns a malloc()'ed string + which is the expansion, or a NULL pointer if there is no expansion. */ +extern Function *rl_tilde_expander; + +/* If non-zero, then this is the address of a function to call just + before readline_internal () prints the first prompt. */ +extern Function *rl_startup_hook; + +/* If non-zero, then this is the address of a function to call when + completing on a directory name. The function is called with + the address of a string (the current directory name) as an arg. */ +extern Function *rl_symbolic_link_hook; + +/* Non-zero means that modified history lines are preceded + with an asterisk. */ +extern int rl_show_star; + +/* **************************************************************** */ +/* */ +/* Well Published Functions */ +/* */ +/* **************************************************************** */ + +/* Read a line of input. Prompt with PROMPT. A NULL PROMPT means none. */ +extern char *readline (); + +/* Return an array of strings which are the result of repeatadly calling + FUNC with TEXT. */ +extern char **completion_matches (); + +/* rl_add_defun (char *name, Function *function, int key) + Add NAME to the list of named functions. Make FUNCTION + be the function that gets called. + If KEY is not -1, then bind it. */ +extern int rl_add_defun (); + +#endif /* _READLINE_H_ */ + diff --git a/readline/vi_keymap.c b/readline/vi_keymap.c new file mode 100644 index 00000000000..81fbb9b8cd3 --- /dev/null +++ b/readline/vi_keymap.c @@ -0,0 +1,474 @@ +/* vi_keymap.c -- the keymap for vi_mode in readline (). */ + +/* Copyright (C) 1988,1989 Free Software Foundation, Inc. + + This file is part of GNU Readline, a library for reading lines + of text with interactive input and history editing. + + Readline is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 1, or (at your option) any + later version. + + Readline is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Readline; see the file COPYING. If not, write to the Free + Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef FILE +#include +#endif /* FILE */ + +#include "readline.h" + +extern KEYMAP_ENTRY_ARRAY vi_escape_keymap; + +/* The keymap arrays for handling vi mode. */ +KEYMAP_ENTRY_ARRAY vi_movement_keymap = { + + /* The regular control keys come first. */ + { ISFUNC, (Function *)0x0 }, /* Control-@ */ + { ISFUNC, (Function *)0x0 }, /* Control-a */ + { ISFUNC, (Function *)0x0 }, /* Control-b */ + { ISFUNC, (Function *)0x0 }, /* Control-c */ + { ISFUNC, rl_vi_eof_maybe }, /* Control-d */ + { ISFUNC, rl_emacs_editing_mode }, /* Control-e */ + { ISFUNC, (Function *)0x0 }, /* Control-f */ + { ISFUNC, rl_abort }, /* Control-g */ + { ISFUNC, rl_backward }, /* Control-h */ + { ISFUNC, (Function *)0x0 }, /* Control-i */ + { ISFUNC, rl_newline }, /* Control-j */ + { ISFUNC, rl_kill_line }, /* Control-k */ + { ISFUNC, rl_clear_screen }, /* Control-l */ + { ISFUNC, rl_newline }, /* Control-m */ + { ISFUNC, rl_get_next_history }, /* Control-n */ + { ISFUNC, (Function *)0x0 }, /* Control-o */ + { ISFUNC, rl_get_previous_history }, /* Control-p */ + { ISFUNC, rl_quoted_insert }, /* Control-q */ + { ISFUNC, rl_reverse_search_history }, /* Control-r */ + { ISFUNC, rl_forward_search_history }, /* Control-s */ + { ISFUNC, rl_transpose_chars }, /* Control-t */ + { ISFUNC, rl_unix_line_discard }, /* Control-u */ + { ISFUNC, rl_quoted_insert }, /* Control-v */ + { ISFUNC, rl_unix_word_rubout }, /* Control-w */ + { ISFUNC, (Function *)0x0 }, /* Control-x */ + { ISFUNC, rl_yank }, /* Control-y */ + { ISFUNC, (Function *)0x0 }, /* Control-z */ + + { ISKMAP, (Function *)vi_escape_keymap }, /* Control-[ */ + { ISFUNC, (Function *)0x0 }, /* Control-\ */ + { ISFUNC, (Function *)0x0 }, /* Control-] */ + { ISFUNC, (Function *)0x0 }, /* Control-^ */ + { ISFUNC, rl_undo_command }, /* Control-_ */ + + /* The start of printing characters. */ + { ISFUNC, rl_forward }, /* SPACE */ + { ISFUNC, (Function *)0x0 }, /* ! */ + { ISFUNC, (Function *)0x0 }, /* " */ + { ISFUNC, rl_vi_comment }, /* # */ + { ISFUNC, rl_end_of_line }, /* $ */ + { ISFUNC, rl_vi_match }, /* % */ + { ISFUNC, (Function *)0x0 }, /* & */ + { ISFUNC, (Function *)0x0 }, /* ' */ + { ISFUNC, (Function *)0x0 }, /* ( */ + { ISFUNC, (Function *)0x0 }, /* ) */ + { ISFUNC, rl_vi_complete }, /* * */ + { ISFUNC, rl_get_next_history}, /* + */ + { ISFUNC, rl_vi_char_search }, /* , */ + { ISFUNC, rl_get_previous_history }, /* - */ + { ISFUNC, (Function *)0x0 }, /* . */ + { ISFUNC, rl_vi_search }, /* / */ + + /* Regular digits. */ + { ISFUNC, rl_vi_arg_digit }, /* 0 */ + { ISFUNC, rl_vi_arg_digit }, /* 1 */ + { ISFUNC, rl_vi_arg_digit }, /* 2 */ + { ISFUNC, rl_vi_arg_digit }, /* 3 */ + { ISFUNC, rl_vi_arg_digit }, /* 4 */ + { ISFUNC, rl_vi_arg_digit }, /* 5 */ + { ISFUNC, rl_vi_arg_digit }, /* 6 */ + { ISFUNC, rl_vi_arg_digit }, /* 7 */ + { ISFUNC, rl_vi_arg_digit }, /* 8 */ + { ISFUNC, rl_vi_arg_digit }, /* 9 */ + + /* A little more punctuation. */ + { ISFUNC, (Function *)0x0 }, /* : */ + { ISFUNC, rl_vi_char_search }, /* ; */ + { ISFUNC, (Function *)0x0 }, /* < */ + { ISFUNC, (Function *)0x0 }, /* = */ + { ISFUNC, (Function *)0x0 }, /* > */ + { ISFUNC, rl_vi_search }, /* ? */ + { ISFUNC, (Function *)0x0 }, /* @ */ + + /* Uppercase alphabet. */ + { ISFUNC, rl_vi_append_eol }, /* A */ + { ISFUNC, rl_vi_prev_word}, /* B */ + { ISFUNC, rl_vi_change_to }, /* C */ + { ISFUNC, rl_vi_delete_to }, /* D */ + { ISFUNC, rl_vi_end_word }, /* E */ + { ISFUNC, rl_vi_char_search }, /* F */ + { ISFUNC, (Function *)0x0 }, /* G */ + { ISFUNC, (Function *)0x0 }, /* H */ + { ISFUNC, rl_vi_insert_beg }, /* I */ + { ISFUNC, (Function *)0x0 }, /* J */ + { ISFUNC, (Function *)0x0 }, /* K */ + { ISFUNC, (Function *)0x0 }, /* L */ + { ISFUNC, (Function *)0x0 }, /* M */ + { ISFUNC, rl_vi_search_again }, /* N */ + { ISFUNC, (Function *)0x0 }, /* O */ + { ISFUNC, rl_vi_put }, /* P */ + { ISFUNC, (Function *)0x0 }, /* Q */ + { ISFUNC, rl_vi_replace }, /* R */ + { ISFUNC, rl_vi_subst }, /* S */ + { ISFUNC, rl_vi_char_search }, /* T */ + { ISFUNC, rl_revert_line }, /* U */ + { ISFUNC, (Function *)0x0 }, /* V */ + { ISFUNC, rl_vi_next_word }, /* W */ + { ISFUNC, rl_rubout }, /* X */ + { ISFUNC, rl_vi_yank_to }, /* Y */ + { ISFUNC, (Function *)0x0 }, /* Z */ + + /* Some more punctuation. */ + { ISFUNC, (Function *)0x0 }, /* [ */ + { ISFUNC, (Function *)0x0 }, /* \ */ + { ISFUNC, (Function *)0x0 }, /* ] */ + { ISFUNC, rl_vi_first_print }, /* ^ */ + { ISFUNC, rl_vi_yank_arg }, /* _ */ + { ISFUNC, (Function *)0x0 }, /* ` */ + + /* Lowercase alphabet. */ + { ISFUNC, rl_vi_append_mode }, /* a */ + { ISFUNC, rl_vi_prev_word }, /* b */ + { ISFUNC, rl_vi_change_to }, /* c */ + { ISFUNC, rl_vi_delete_to }, /* d */ + { ISFUNC, rl_vi_end_word }, /* e */ + { ISFUNC, rl_vi_char_search }, /* f */ + { ISFUNC, (Function *)0x0 }, /* g */ + { ISFUNC, rl_backward }, /* h */ + { ISFUNC, rl_vi_insertion_mode }, /* i */ + { ISFUNC, rl_get_next_history }, /* j */ + { ISFUNC, rl_get_previous_history }, /* k */ + { ISFUNC, rl_forward }, /* l */ + { ISFUNC, (Function *)0x0 }, /* m */ + { ISFUNC, rl_vi_search_again }, /* n */ + { ISFUNC, (Function *)0x0 }, /* o */ + { ISFUNC, rl_vi_put }, /* p */ + { ISFUNC, (Function *)0x0 }, /* q */ + { ISFUNC, rl_vi_change_char }, /* r */ + { ISFUNC, rl_vi_subst }, /* s */ + { ISFUNC, rl_vi_char_search }, /* t */ + { ISFUNC, rl_undo_command }, /* u */ + { ISFUNC, (Function *)0x0 }, /* v */ + { ISFUNC, rl_vi_next_word }, /* w */ + { ISFUNC, rl_vi_delete }, /* x */ + { ISFUNC, rl_vi_yank_to }, /* y */ + { ISFUNC, (Function *)0x0 }, /* z */ + + /* Final punctuation. */ + { ISFUNC, (Function *)0x0 }, /* { */ + { ISFUNC, rl_vi_column }, /* | */ + { ISFUNC, (Function *)0x0 }, /* } */ + { ISFUNC, rl_vi_change_case }, /* ~ */ + { ISFUNC, rl_backward } /* RUBOUT */ +}; + + +KEYMAP_ENTRY_ARRAY vi_insertion_keymap = { + + /* The regular control keys come first. */ + { ISFUNC, (Function *)0x0 }, /* Control-@ */ + { ISFUNC, rl_insert }, /* Control-a */ + { ISFUNC, rl_insert }, /* Control-b */ + { ISFUNC, rl_insert }, /* Control-c */ + { ISFUNC, rl_vi_eof_maybe }, /* Control-d */ + { ISFUNC, rl_insert }, /* Control-e */ + { ISFUNC, rl_insert }, /* Control-f */ + { ISFUNC, rl_insert }, /* Control-g */ + { ISFUNC, rl_rubout }, /* Control-h */ + { ISFUNC, rl_complete }, /* Control-i */ + { ISFUNC, rl_newline }, /* Control-j */ + { ISFUNC, rl_insert }, /* Control-k */ + { ISFUNC, rl_insert }, /* Control-l */ + { ISFUNC, rl_newline }, /* Control-m */ + { ISFUNC, rl_insert }, /* Control-n */ + { ISFUNC, rl_insert }, /* Control-o */ + { ISFUNC, rl_insert }, /* Control-p */ + { ISFUNC, rl_insert }, /* Control-q */ + { ISFUNC, rl_reverse_search_history }, /* Control-r */ + { ISFUNC, rl_forward_search_history }, /* Control-s */ + { ISFUNC, rl_transpose_chars }, /* Control-t */ + { ISFUNC, rl_unix_line_discard }, /* Control-u */ + { ISFUNC, rl_quoted_insert }, /* Control-v */ + { ISFUNC, rl_unix_word_rubout }, /* Control-w */ + { ISFUNC, rl_insert }, /* Control-x */ + { ISFUNC, rl_yank }, /* Control-y */ + { ISFUNC, rl_insert }, /* Control-z */ + + { ISFUNC, rl_vi_movement_mode }, /* Control-[ */ + { ISFUNC, rl_insert }, /* Control-\ */ + { ISFUNC, rl_insert }, /* Control-] */ + { ISFUNC, rl_insert }, /* Control-^ */ + { ISFUNC, rl_undo_command }, /* Control-_ */ + + /* The start of printing characters. */ + { ISFUNC, rl_insert }, /* SPACE */ + { ISFUNC, rl_insert }, /* ! */ + { ISFUNC, rl_insert }, /* " */ + { ISFUNC, rl_insert }, /* # */ + { ISFUNC, rl_insert }, /* $ */ + { ISFUNC, rl_insert }, /* % */ + { ISFUNC, rl_insert }, /* & */ + { ISFUNC, rl_insert }, /* ' */ + { ISFUNC, rl_insert }, /* ( */ + { ISFUNC, rl_insert }, /* ) */ + { ISFUNC, rl_insert }, /* * */ + { ISFUNC, rl_insert }, /* + */ + { ISFUNC, rl_insert }, /* , */ + { ISFUNC, rl_insert }, /* - */ + { ISFUNC, rl_insert }, /* . */ + { ISFUNC, rl_insert }, /* / */ + + /* Regular digits. */ + { ISFUNC, rl_insert }, /* 0 */ + { ISFUNC, rl_insert }, /* 1 */ + { ISFUNC, rl_insert }, /* 2 */ + { ISFUNC, rl_insert }, /* 3 */ + { ISFUNC, rl_insert }, /* 4 */ + { ISFUNC, rl_insert }, /* 5 */ + { ISFUNC, rl_insert }, /* 6 */ + { ISFUNC, rl_insert }, /* 7 */ + { ISFUNC, rl_insert }, /* 8 */ + { ISFUNC, rl_insert }, /* 9 */ + + /* A little more punctuation. */ + { ISFUNC, rl_insert }, /* : */ + { ISFUNC, rl_insert }, /* ; */ + { ISFUNC, rl_insert }, /* < */ + { ISFUNC, rl_insert }, /* = */ + { ISFUNC, rl_insert }, /* > */ + { ISFUNC, rl_insert }, /* ? */ + { ISFUNC, rl_insert }, /* @ */ + + /* Uppercase alphabet. */ + { ISFUNC, rl_insert }, /* A */ + { ISFUNC, rl_insert }, /* B */ + { ISFUNC, rl_insert }, /* C */ + { ISFUNC, rl_insert }, /* D */ + { ISFUNC, rl_insert }, /* E */ + { ISFUNC, rl_insert }, /* F */ + { ISFUNC, rl_insert }, /* G */ + { ISFUNC, rl_insert }, /* H */ + { ISFUNC, rl_insert }, /* I */ + { ISFUNC, rl_insert }, /* J */ + { ISFUNC, rl_insert }, /* K */ + { ISFUNC, rl_insert }, /* L */ + { ISFUNC, rl_insert }, /* M */ + { ISFUNC, rl_insert }, /* N */ + { ISFUNC, rl_insert }, /* O */ + { ISFUNC, rl_insert }, /* P */ + { ISFUNC, rl_insert }, /* Q */ + { ISFUNC, rl_insert }, /* R */ + { ISFUNC, rl_insert }, /* S */ + { ISFUNC, rl_insert }, /* T */ + { ISFUNC, rl_insert }, /* U */ + { ISFUNC, rl_insert }, /* V */ + { ISFUNC, rl_insert }, /* W */ + { ISFUNC, rl_insert }, /* X */ + { ISFUNC, rl_insert }, /* Y */ + { ISFUNC, rl_insert }, /* Z */ + + /* Some more punctuation. */ + { ISFUNC, rl_insert }, /* [ */ + { ISFUNC, rl_insert }, /* \ */ + { ISFUNC, rl_insert }, /* ] */ + { ISFUNC, rl_insert }, /* ^ */ + { ISFUNC, rl_insert }, /* _ */ + { ISFUNC, rl_insert }, /* ` */ + + /* Lowercase alphabet. */ + { ISFUNC, rl_insert }, /* a */ + { ISFUNC, rl_insert }, /* b */ + { ISFUNC, rl_insert }, /* c */ + { ISFUNC, rl_insert }, /* d */ + { ISFUNC, rl_insert }, /* e */ + { ISFUNC, rl_insert }, /* f */ + { ISFUNC, rl_insert }, /* g */ + { ISFUNC, rl_insert }, /* h */ + { ISFUNC, rl_insert }, /* i */ + { ISFUNC, rl_insert }, /* j */ + { ISFUNC, rl_insert }, /* k */ + { ISFUNC, rl_insert }, /* l */ + { ISFUNC, rl_insert }, /* m */ + { ISFUNC, rl_insert }, /* n */ + { ISFUNC, rl_insert }, /* o */ + { ISFUNC, rl_insert }, /* p */ + { ISFUNC, rl_insert }, /* q */ + { ISFUNC, rl_insert }, /* r */ + { ISFUNC, rl_insert }, /* s */ + { ISFUNC, rl_insert }, /* t */ + { ISFUNC, rl_insert }, /* u */ + { ISFUNC, rl_insert }, /* v */ + { ISFUNC, rl_insert }, /* w */ + { ISFUNC, rl_insert }, /* x */ + { ISFUNC, rl_insert }, /* y */ + { ISFUNC, rl_insert }, /* z */ + + /* Final punctuation. */ + { ISFUNC, rl_insert }, /* { */ + { ISFUNC, rl_insert }, /* | */ + { ISFUNC, rl_insert }, /* } */ + { ISFUNC, rl_insert }, /* ~ */ + { ISFUNC, rl_rubout } /* RUBOUT */ +}; + +KEYMAP_ENTRY_ARRAY vi_escape_keymap = { + + /* The regular control keys come first. */ + { ISFUNC, (Function *)0x0 }, /* Control-@ */ + { ISFUNC, (Function *)0x0 }, /* Control-a */ + { ISFUNC, (Function *)0x0 }, /* Control-b */ + { ISFUNC, (Function *)0x0 }, /* Control-c */ + { ISFUNC, (Function *)0x0 }, /* Control-d */ + { ISFUNC, (Function *)0x0 }, /* Control-e */ + { ISFUNC, (Function *)0x0 }, /* Control-f */ + { ISFUNC, (Function *)0x0 }, /* Control-g */ + { ISFUNC, (Function *)0x0 }, /* Control-h */ + { ISFUNC, rl_tab_insert}, /* Control-i */ + { ISFUNC, rl_emacs_editing_mode}, /* Control-j */ + { ISFUNC, rl_kill_line }, /* Control-k */ + { ISFUNC, (Function *)0x0 }, /* Control-l */ + { ISFUNC, rl_emacs_editing_mode}, /* Control-m */ + { ISFUNC, (Function *)0x0 }, /* Control-n */ + { ISFUNC, (Function *)0x0 }, /* Control-o */ + { ISFUNC, (Function *)0x0 }, /* Control-p */ + { ISFUNC, (Function *)0x0 }, /* Control-q */ + { ISFUNC, (Function *)0x0 }, /* Control-r */ + { ISFUNC, (Function *)0x0 }, /* Control-s */ + { ISFUNC, (Function *)0x0 }, /* Control-t */ + { ISFUNC, (Function *)0x0 }, /* Control-u */ + { ISFUNC, (Function *)0x0 }, /* Control-v */ + { ISFUNC, (Function *)0x0 }, /* Control-w */ + { ISFUNC, (Function *)0x0 }, /* Control-x */ + { ISFUNC, (Function *)0x0 }, /* Control-y */ + { ISFUNC, (Function *)0x0 }, /* Control-z */ + + { ISFUNC, rl_vi_movement_mode }, /* Control-[ */ + { ISFUNC, (Function *)0x0 }, /* Control-\ */ + { ISFUNC, (Function *)0x0 }, /* Control-] */ + { ISFUNC, (Function *)0x0 }, /* Control-^ */ + { ISFUNC, rl_undo_command }, /* Control-_ */ + + /* The start of printing characters. */ + { ISFUNC, (Function *)0x0 }, /* SPACE */ + { ISFUNC, (Function *)0x0 }, /* ! */ + { ISFUNC, (Function *)0x0 }, /* " */ + { ISFUNC, (Function *)0x0 }, /* # */ + { ISFUNC, (Function *)0x0 }, /* $ */ + { ISFUNC, (Function *)0x0 }, /* % */ + { ISFUNC, (Function *)0x0 }, /* & */ + { ISFUNC, (Function *)0x0 }, /* ' */ + { ISFUNC, (Function *)0x0 }, /* ( */ + { ISFUNC, (Function *)0x0 }, /* ) */ + { ISFUNC, (Function *)0x0 }, /* * */ + { ISFUNC, (Function *)0x0 }, /* + */ + { ISFUNC, (Function *)0x0 }, /* , */ + { ISFUNC, (Function *)0x0 }, /* - */ + { ISFUNC, (Function *)0x0 }, /* . */ + { ISFUNC, (Function *)0x0 }, /* / */ + + /* Regular digits. */ + { ISFUNC, rl_vi_arg_digit }, /* 0 */ + { ISFUNC, rl_vi_arg_digit }, /* 1 */ + { ISFUNC, rl_vi_arg_digit }, /* 2 */ + { ISFUNC, rl_vi_arg_digit }, /* 3 */ + { ISFUNC, rl_vi_arg_digit }, /* 4 */ + { ISFUNC, rl_vi_arg_digit }, /* 5 */ + { ISFUNC, rl_vi_arg_digit }, /* 6 */ + { ISFUNC, rl_vi_arg_digit }, /* 7 */ + { ISFUNC, rl_vi_arg_digit }, /* 8 */ + { ISFUNC, rl_vi_arg_digit }, /* 9 */ + + /* A little more punctuation. */ + { ISFUNC, (Function *)0x0 }, /* : */ + { ISFUNC, (Function *)0x0 }, /* ; */ + { ISFUNC, (Function *)0x0 }, /* < */ + { ISFUNC, (Function *)0x0 }, /* = */ + { ISFUNC, (Function *)0x0 }, /* > */ + { ISFUNC, (Function *)0x0 }, /* ? */ + { ISFUNC, (Function *)0x0 }, /* @ */ + + /* Uppercase alphabet. */ + { ISFUNC, rl_do_lowercase_version }, /* A */ + { ISFUNC, rl_do_lowercase_version }, /* B */ + { ISFUNC, rl_do_lowercase_version }, /* C */ + { ISFUNC, rl_do_lowercase_version }, /* D */ + { ISFUNC, rl_do_lowercase_version }, /* E */ + { ISFUNC, rl_do_lowercase_version }, /* F */ + { ISFUNC, rl_do_lowercase_version }, /* G */ + { ISFUNC, rl_do_lowercase_version }, /* H */ + { ISFUNC, rl_do_lowercase_version }, /* I */ + { ISFUNC, rl_do_lowercase_version }, /* J */ + { ISFUNC, rl_do_lowercase_version }, /* K */ + { ISFUNC, rl_do_lowercase_version }, /* L */ + { ISFUNC, rl_do_lowercase_version }, /* M */ + { ISFUNC, rl_do_lowercase_version }, /* N */ + { ISFUNC, rl_do_lowercase_version }, /* O */ + { ISFUNC, rl_do_lowercase_version }, /* P */ + { ISFUNC, rl_do_lowercase_version }, /* Q */ + { ISFUNC, rl_do_lowercase_version }, /* R */ + { ISFUNC, rl_do_lowercase_version }, /* S */ + { ISFUNC, rl_do_lowercase_version }, /* T */ + { ISFUNC, rl_do_lowercase_version }, /* U */ + { ISFUNC, rl_do_lowercase_version }, /* V */ + { ISFUNC, rl_do_lowercase_version }, /* W */ + { ISFUNC, rl_do_lowercase_version }, /* X */ + { ISFUNC, rl_do_lowercase_version }, /* Y */ + { ISFUNC, rl_do_lowercase_version }, /* Z */ + + /* Some more punctuation. */ + { ISFUNC, (Function *)0x0 }, /* [ */ + { ISFUNC, (Function *)0x0 }, /* \ */ + { ISFUNC, (Function *)0x0 }, /* ] */ + { ISFUNC, (Function *)0x0 }, /* ^ */ + { ISFUNC, (Function *)0x0 }, /* _ */ + { ISFUNC, (Function *)0x0 }, /* ` */ + + /* Lowercase alphabet. */ + { ISFUNC, (Function *)0x0 }, /* a */ + { ISFUNC, (Function *)0x0 }, /* b */ + { ISFUNC, (Function *)0x0 }, /* c */ + { ISFUNC, (Function *)0x0 }, /* d */ + { ISFUNC, (Function *)0x0 }, /* e */ + { ISFUNC, (Function *)0x0 }, /* f */ + { ISFUNC, (Function *)0x0 }, /* g */ + { ISFUNC, (Function *)0x0 }, /* h */ + { ISFUNC, (Function *)0x0 }, /* i */ + { ISFUNC, (Function *)0x0 }, /* j */ + { ISFUNC, (Function *)0x0 }, /* k */ + { ISFUNC, (Function *)0x0 }, /* l */ + { ISFUNC, (Function *)0x0 }, /* m */ + { ISFUNC, (Function *)0x0 }, /* n */ + { ISFUNC, (Function *)0x0 }, /* o */ + { ISFUNC, (Function *)0x0 }, /* p */ + { ISFUNC, (Function *)0x0 }, /* q */ + { ISFUNC, (Function *)0x0 }, /* r */ + { ISFUNC, (Function *)0x0 }, /* s */ + { ISFUNC, (Function *)0x0 }, /* t */ + { ISFUNC, (Function *)0x0 }, /* u */ + { ISFUNC, (Function *)0x0 }, /* v */ + { ISFUNC, (Function *)0x0 }, /* w */ + { ISFUNC, (Function *)0x0 }, /* x */ + { ISFUNC, (Function *)0x0 }, /* y */ + { ISFUNC, (Function *)0x0 }, /* z */ + + /* Final punctuation. */ + { ISFUNC, (Function *)0x0 }, /* { */ + { ISFUNC, (Function *)0x0 }, /* | */ + { ISFUNC, (Function *)0x0 }, /* } */ + { ISFUNC, (Function *)0x0 }, /* ~ */ + { ISFUNC, rl_backward_kill_word } /* RUBOUT */ +}; diff --git a/readline/vi_mode.c b/readline/vi_mode.c new file mode 100644 index 00000000000..478af9194a0 --- /dev/null +++ b/readline/vi_mode.c @@ -0,0 +1,925 @@ +/* vi_mode.c -- A vi emulation mode for Bash. + + Derived from code written by Jeff Sparkes (jeff1@????). + */ + + +/* **************************************************************** */ +/* */ +/* 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); +} -- 2.30.2