diff options
author | nate <nate@FreeBSD.org> | 1993-06-29 09:48:26 +0000 |
---|---|---|
committer | nate <nate@FreeBSD.org> | 1993-06-29 09:48:26 +0000 |
commit | 3d05155a65112f93d518e0894e88e5bbe3b8c29b (patch) | |
tree | cdd68fbd62669dc58e35c33f53db5141dfd8776e /gnu/usr.bin/gdb | |
parent | 76b8039b4b77138d9129d34ff5b328c7bd187af1 (diff) | |
download | FreeBSD-src-3d05155a65112f93d518e0894e88e5bbe3b8c29b.zip FreeBSD-src-3d05155a65112f93d518e0894e88e5bbe3b8c29b.tar.gz |
Added GNU gdb to src/gnu
Diffstat (limited to 'gnu/usr.bin/gdb')
82 files changed, 60574 insertions, 0 deletions
diff --git a/gnu/usr.bin/gdb/COPYING b/gnu/usr.bin/gdb/COPYING new file mode 100644 index 0000000..9a17037 --- /dev/null +++ b/gnu/usr.bin/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. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19xx name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the +appropriate parts of the General Public License. Of course, the +commands you use may be called something other than `show w' and `show +c'; they could even be mouse-clicks or menu items--whatever suits your +program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + program `Gnomovision' (a program to direct compilers to make passes + at assemblers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/gnu/usr.bin/gdb/ChangeLog b/gnu/usr.bin/gdb/ChangeLog new file mode 100644 index 0000000..1f2342b --- /dev/null +++ b/gnu/usr.bin/gdb/ChangeLog @@ -0,0 +1,4887 @@ +Thu Feb 8 01:11:55 1990 Jim Kingdon (kingdon at pogo.ai.mit.edu) + + * GDB 3.5 released. + + * version.c: Change version number to 3.5 + +Tue Feb 6 15:58:06 1990 Jim Kingdon (kingdon at pogo.ai.mit.edu) + + * m-hp9k320.h: define ATTACH_DETACH. + hp9k320-dep.c [ATTACH_DETACH]: New code. + +Thu Feb 1 17:43:00 1990 Jim Kingdon (kingdon at pogo.ai.mit.edu) + + * valprint.c (is_nan, val_print): Use char * not void *. + + * symmisc.c (print_symbol): Print newline after label. + +Tue Jan 30 15:35:52 1990 Jim Kingdon (kingdon at albert.ai.mit.edu) + + * Makefile.dist (READLINE): Add {readline,history}.texinfo. + + * m-merlin.h: Put in clarifying comments about SHELL_FILE. + config.gdb (merlin): Explain about /usr/local/lib/gdb-sh. + +Sat Jan 27 02:30:27 1990 Jim Kingdon (kingdon at pogo.ai.mit.edu) + + * version.c: Change version number to 3.5alpha.1. + + * dbxread.c (process_one_symbol): Compare context_stack_depth + with !VARIABLES_INSIDE_BLOCK, not VARIABLES_INSIDE_BLOCK. + +Fri Jan 26 01:21:51 1990 Jim Kingdon (kingdon at mole.ai.mit.edu) + + * main.c [ALIGN_STACK_ON_STARTUP]: New code. + m-i386.h: Define ALIGN_STACK_ON_STARTUP. + + * m-merlin.h (NO_SIGINTERRUPT, SHELL_FILE): Define. + + * umax-dep.c (exec_file_command): Add commas to call to + read_section_hdr. + +Tue Jan 23 15:49:47 1990 Jim Kingdon (kingdon at pogo.ai.mit.edu) + + * dbxread.c (define_symbol): Deal with deftype 'X'. + + * convex-dep.c (wait): Make it pid_t. + + * convex-dep.c (comm_registers_info): accept decimal comm register + specification, as "i comm 32768". + + * dbxread.c (process_one_symbol): Make VARIABLES_INSIDE_BLOCK + macro say by itself where variables are. Pass it desc. + m-convex.h (VARIABLES_INSIDE_BLOCK): Nonzero for native compiler. + + * m-convex.h (SET_STACK_LIMIT_HUGE): Define. + (IGNORE_SYMBOL): Take out #ifdef N_MONPT and put in 0xc4. + +Fri Jan 19 20:04:15 1990 Jim Kingdon (kingdon at albert.ai.mit.edu) + + * printcmd.c (print_frame_args): Always set highest_offset to + current_offset when former is -1. + + * dbxread.c (read_struct_type): Print nice error message + when encountering multiple inheritance. + +Thu Jan 18 13:43:30 1990 Jim Kingdon (kingdon at mole.ai.mit.edu) + + * dbxread.c (read_dbx_symtab): Always treat N_FN as a potential + source for a x.o or -lx symbol, ignoring OFILE_FN_FLAGGED. + + * printcmd.c (print_frame_args): Cast -1 to (CORE_ADDR). + + * hp300bsd-dep.c (_initialize_hp300_dep): Get kernel_u_addr. + m-hp300bsd.h (KERNEL_U_ADDR): Use kernel_u_addr. + + * infcmd.c (run_command): #if 0 out call to + breakpoint_clear_ignore_counts. + +Thu Jan 11 12:58:12 1990 Jim Kingdon (kingdon at mole) + + * printcmd.c (print_frame_args) [STRUCT_ARG_SYM_GARBAGE]: + Try looking up name of var before giving up & printing '?'. + +Wed Jan 10 14:00:14 1990 Jim Kingdon (kingdon at pogo) + + * many files: Move stdio.h before param.h. + + * sun3-dep.c (store_inferior_registers): Only try to write FP + regs #ifdef FP0_REGNUM. + +Mon Jan 8 17:56:15 1990 Jim Kingdon (kingdon at pogo) + + * symtab.c: #if 0 out "info methods" code. + +Sat Jan 6 12:33:04 1990 Jim Kingdon (kingdon at pogo) + + * dbxread.c (read_struct_type): Set TYPE_NFN_FIELDS_TOTAL + from all baseclasses; remove vestigial variable baseclass. + + * findvar.c (read_var_value): Check REG_STRUCT_HAS_ADDR. + printcmd.c (print_frame_args): Check STRUCT_ARG_SYM_GARBAGE. + m-sparc.h: Define REG_STRUCT_HAS_ADDR and STRUCT_ARG_SYM_GARBAGE. + + * blockframe.c (get_frame_block): Subtract one from pc if not + innermost frame. + +Fri Dec 29 15:26:33 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * printcmd.c (print_frame_args): check highest_offset != -1, not i. + +Thu Dec 28 16:21:02 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * valops.c (value_struct_elt): Clean up error msg. + + * breakpoint.c (describe_other_breakpoints): + Delete extra space before "also set at" and add period at end. + +Tue Dec 19 10:28:42 1989 Jim Kingdon (kingdon at pogo) + + * source.c (print_source_lines): Tell user which line number + was out of range when printing error message. + +Sun Dec 17 14:14:09 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * blockframe.c (find_pc_partial_function): Use + BLOCK_START (SYMBOL_BLOCK_VALUE (f)) instead of + SYMBOL_VALUE (f) to get start of function. + + * dbxread.c: Make xxmalloc just a #define for xmalloc. + +Thu Dec 14 16:13:16 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * m68k-opcode.h (fseq & following fp instructions): + Change @ to $. + +Fri Dec 8 19:06:44 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * breakpoint.c (breakpoint_clear_ignore_counts): New function. + infcmd.c (run_command): Call it. + +Wed Dec 6 15:03:38 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * valprint.c: Change it so "array-max 0" means there is + no limit. + + * expread.y (yylex): Change error message "invalid token in + expression" to "invalid character '%c' in expression". + +Mon Dec 4 16:12:54 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * blockframe.c (find_pc_partial_function): Always return 1 + for success, 0 for failure, and set *NAME and *ADDRESS to + match the return value. + + * dbxread.c (symbol_file_command): Use perror_with_name on + error from stat. + (psymtab_to_symtab, add_file_command), + core.c (validate_files), source.c (find_source_lines), + default-dep.c (exec_file_command): Check for errors from stat, + fstat, and myread. + +Fri Dec 1 05:16:42 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * valops.c (check_field): When following pointers, just get + their types; don't call value_ind. + +Thu Nov 30 14:45:29 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * config.gdb (pyr): New machine. + core.c [REG_STACK_SEGMENT]: New code. + dbxread.c (process_one_symbol): Cast return from copy_pending + to long before casting to enum namespace. + infrun.c: Split registers_info into DO_REGISTERS_INFO + and registers_info. + m-pyr.h, pyr-{dep.c,opcode.h,pinsn.c}: New files. + + * hp300bsd-dep.c: Stay in sync with default-dep.c. + + * m-hp300bsd.h (IN_SIGTRAMP): Define. + +Mon Nov 27 23:48:21 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu) + + * m-sparc.h (EXTRACT_RETURN_VALUE, STORE_RETURN_VALUE): + Return floating point values in %f0. + +Tue Nov 21 00:34:46 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * dbxread.c (read_type): #if 0 out code which skips to + comma following x-ref. + +Sat Nov 18 20:10:54 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * valprint.c (val_print): Undo changes of Nov 11 & 16. + (print_string): Add parameter force_ellipses. + (val_print): Pass force_ellipses true when we stop fetching string + before we get to the end, else pass false. + +Thu Nov 16 11:59:50 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * infrun.c (restore_inferior_status): Don't try to restore + selected frame if the inferior no longer exists. + + * valprint.c (val_print): Rewrite string printing code not to + call print_string. + + * Makefile.dist (clean): Remove xgdb and xgdb.o. + +Tue Nov 14 12:41:47 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * Makefile.dist (XGDB, bindir, xbindir, install, all): New stuff. + +Sat Nov 11 15:29:38 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * valprint.c (val_print): chars_to_get: New variable. + +Thu Nov 9 12:31:47 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * main.c (main): Process "-help" as a switch that doesn't + take an argument. + +Wed Nov 8 13:07:02 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * Makefile.dist (gdb.tar.Z): Add "else true". + +Tue Nov 7 12:25:14 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * infrun.c (restore_inferior_status): Don't dereference fid if NULL. + + * config.gdb (sun3, sun4): Accept "sun3" and "sun4". + +Mon Nov 6 09:49:23 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * Makefile.dist (Makefile): Move comments after commands. + + * *-dep.c [READ_COFF_SYMTAB]: Pass optional header size to + read_section_hdr(). + + * inflow.c: Include <fcntl.h> regardless of USG. + + * coffread.c (read_section_hdr): Add optional_header_size. + (symbol_file_command): Pass optional header size to + read_section_hdr(). + (read_coff_symtab): Initialize filestring. + + * version.c: Change version to 3.4.xxx. + + * GDB 3.4 released. + +Sun Nov 5 11:39:01 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * version.c: Change version to 3.4. + + * symtab.c (decode_line_1): Only skip past "struct" if it + is there. + + * valops.c (value_ind), eval.c (evaluate_subexp, case UNOP_IND): + Have "*" <int-valued-exp> return an int, not a LONGEST. + + * utils.c (fprintf_filtered): Pass arg{4,5,6} to sprintf. + + * printcmd.c (x_command): Use variable itself rather + than treating it as a pointer only if it is a function. + (See comment "this makes x/i main work"). + + * coffread.c (symbol_file_command): Use error for + "%s does not have a symbol-table.\n". + +Wed Nov 1 19:56:18 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * dbxread.c [BELIEVE_PCC_PROMOTION_TYPE]: New code. + m-sparc.h: Define BELIEVE_PCC_PROMOTION_TYPE. + +Thu Oct 26 12:45:00 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * infrun.c: Include <sys/dir.h>. + + * dbxread.c (read_dbx_symtab, case N_LSYM, case 'T'): + Check for enum types and put constants in psymtab. + +Mon Oct 23 15:02:25 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * dbxread.c (define_symbol, read_dbx_symtab): Handle enum + constants (e.g. "b:c=e6,0"). + +Thu Oct 19 14:57:26 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * stack.c (frame_info): Use FRAME_ARGS_ADDRESS_CORRECT + m-vax.h (FRAME_ARGS_ADDRESS_CORRECT): New macro. + (FRAME_ARGS_ADDRESS): Restore old meaning. + + * frame.h (Frame_unknown): New macro. + stack.c (frame_info): Check for Frame_unknown return from + FRAME_ARGS_ADDRESS. + m-vax.h (FRAME_ARGS_ADDRESS): Sometimes return Frame_unknown. + + * utils.c (fatal_dump_core): Add "internal error" to message. + + * infrun.c (IN_SIGTRAMP): New macro. + (wait_for_inferior): Use IN_SIGTRAMP. + m-vax.h (IN_SIGTRAMP): New macro. + +Wed Oct 18 15:09:22 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * config.gdb, Makefile.dist: Shorten m-i386-sv32.h. + + * coffread.c (symbol_file_command): Pass 0 to select_source_symtab. + +Tue Oct 17 12:24:41 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * i386-dep.c (i386_frame_num_args): Take function from m-i386.h + file. Check for pfi null. + m-i386.h (FRAME_NUM_ARGS): Use i386_frame_num_args. + + * infrun.c (wait_for_inferior): set stop_func_name to 0 + before calling find_pc_partial_function. + +Thu Oct 12 01:08:50 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * breakpoint.c (_initialize_breakpoint): Add "disa". + + * Makefile.dist: Add GLOBAL_CFLAGS and pass to readline. + + * config.gdb (various): "$machine =" -> "machine =". + +Wed Oct 11 11:54:31 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * inflow.c (try_writing_regs): #if 0 out this function. + + * main.c (main): Add "-help" option. + + * dbxread.c (read_dbx_symtab): Merge code for N_FUN with + N_STSYM, etc. + +Mon Oct 9 14:21:55 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * inflow.c (try_writing_regs_command): Don't write past end + of struct user. + + * dbxread.c (read_struct_type): #if 0 out code which checks for + bitpos and bitsize 0. + + * config.gdb: Accept sequent-i386 (not seq386). + (symmetry): Set depfile and paramfile. + + * m-convex.h (IGNORE_SYMBOL): Check for N_MONPT if defined. + +Thu Oct 5 10:14:26 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * default-dep.c (read_inferior_memory): Put #if 0'd out comment + within /* */. + +Wed Oct 4 18:44:41 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu) + + * config.gdb: Change /dev/null to m-i386.h for various + 386 machine "opcodefile" entries. + + * config.gdb: Accept seq386 for sequent symmetry. + +Mon Oct 2 09:59:50 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * hp300bsd-dep.c: Fix copyright notice. + +Sun Oct 1 16:25:30 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * Makefile.dist (DEPFILES): Add isi-dep.c. + + * default-dep.c (read_inferior_memory): Move #endif after else. + +Sat Sep 30 12:50:16 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * version.c: Change version number to 3.3.xxx. + + * GDB 3.3 released. + + * version.c: Change version number to 3.3. + + * Makefile.dist (READLINE): Add vi_mode.c + + * config.gdb (i386): Change /dev/null to m-i386.h + + * config.gdb: Add ';;' before 'esac'. + + * Makefile.dist (gdb.tar.Z): Move comment above dependency. + + * dbxread.c (read_ofile_symtab): Check symbol before start + of source file for GCC_COMPILED_FLAG_SYMBOL. + (start_symtab): Don't clear processing_gcc_compilation. + +Thu Sep 28 22:30:23 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * valprint.c (print_string): If LENGTH is zero, print "". + +Wed Sep 27 10:15:10 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu) + + * config.gdb: "rm tmp.c" -> "rm -f tmp.c". + +Tue Sep 26 13:02:10 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * utils.c (_initialize_utils): Use termcap to set lines_per_page + and chars_per_line. + +Mon Sep 25 10:06:43 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * dbxread.c (read_dbx_symtab, N_SOL): Do not add the same file + more than once. + +Thu Sep 21 12:43:18 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * infcmd.c (unset_environment_command): Delete all variables + if called with no arg. + + * remote.c, inferior.h (remote_{read,write}_inferior_memory): + New functions. + core.c ({read,write}_memory): Use remote_{read,write}_inferior_memory. + + * valops.c (call_function): When reserving stack space for + arguments, call value_arg_coerce. + + * m-hp9k320.h: define BROKEN_LARGE_ALLOCA. + + * breakpoint.c (delete_command): Ask for confirmation only + when there are breakpoints. + + * dbxread.c (read_struct_type): If lookup_basetype_type has + copied a stub type, call add_undefined_type. + + * sparc_pinsn.c (compare_opcodes): Check for "1+i" anywhere + in args. + + * val_print.c (type_print_base): Print stub types as + "<incomplete type>". + +Wed Sep 20 07:32:00 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * sparc-opcode.h (swapa): Remove i bit from match. + (all alternate space instructions): Delete surplus "foo rs1+0" + patterns. + + * Makefile.dist (LDFLAGS): Set to $(CFLAGS). + + * remote-multi.shar (remote_utils.c, putpkt): Change csum to unsigned. + +Tue Sep 19 14:15:16 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu) + + * sparc-opcode.h: Set i bit in lose for many instructions which + aren't immediate. + + * stack.c (print_frame_info): add "func = 0". + +Mon Sep 18 16:19:48 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * sparc-opcode.h (mov): Add mov to/from %tbr, %psr, %wim. + + * sparc-opcode.h (rett): Fix notation to use suggested assembler + syntax from architecture manual. + + * symmetry-dep.c (I386_REGNO_TO_SYMMETRY): New macro. + (i386_frame_find_saved_regs): Use I386_REGNO_TO_SYMMETRY. + +Sat Sep 16 22:21:17 1989 Jim Kingdon (kingdon at spiff) + + * remote.c (remote_close): Set remote_desc to -1. + + * gdb.texinfo (Output): Fix description of echo to match + reality and ANSI C. + +Fri Sep 15 14:28:59 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu) + + * symtab.c (lookup_symbol): Add comment about "asm". + + * sparc-pinsn.c: Use NUMOPCODES. + + * sparc-opcode.h (NUMOPCODES): Use sparc_opcodes[0] not *sparc_opcodes. + +Thu Sep 14 15:25:20 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu) + + * dbxread.c (xxmalloc): Print error message before calling abort(). + + * infrun.c (wait_for_inferior): Check for {stop,prev}_func_name + null before passing to strcmp. + +Wed Sep 13 12:34:15 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * sparc-opcode.h: New field delayed. + sparc-pinsn.c (is_delayed_branch): New function. + (print_insn): Check for delayed branches. + + * stack.c (print_frame_info): Use misc_function_vector in + case where ar truncates file names. + +Tue Sep 12 00:16:14 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * convex-dep.c (psw_info): Move "struct pswbit *p" with declarations. + +Mon Sep 11 14:59:57 1989 Jim Kingdon (kingdon at spiff) + + * convex-dep.c (core_file_command): Delete redundant printing + of "Program %s". + + * m-convex.h (ENTRY_POINT): New macro. + + * m-convex.h (FRAME_CHAIN_VALID): Change outside_first_object_file + to outside_startup_file + + * main.c: #if 0 out catch_termination and related code. + + * command.c (lookup_cmd_1): Consider underscores part of + command names. + +Sun Sep 10 09:20:12 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * printcmd.c: Change asdump_command to disassemble_command + (_initialize_printcmd): Change asdump to diassemble. + + * main.c (main): Exit with code 0 if we hit the end of a batch + file. + + * Makefile.dist (libreadline.a): Fix syntax of "CC=${CC}". + +Sat Sep 9 01:07:18 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu) + + * values.c (history_info): Renamed to value_history_info. + Command renamed to "info value" (with "info history" still + accepted). + + * sparc-pinsn.c (print_insn): Extend symbolic address printing + to cover "sethi" following by an insn which uses 1+i. + +Fri Sep 8 14:24:01 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * m-hp9k320.h, m-hp300bsd.h, m-altos.h, m-sparc.h, m-sun3.h + (READ_GDB_SYMSEGS): Remove. + dbxread.c [READ_GDB_SYMSEGS]: Remove code to read symsegs. + + * sparc-pinsn.c (print_insn): Detect "sethi-or" pairs and + print symbolic address. + + * sparc-opcode.h (sethi, set): Change lose from 0xc0000000 to + 0xc0c00000000. + + * remote.c (remote_desc): Initialize to -1. + + * Makefile.dist (libreadline.a): Pass CC='${CC}' to readline makefile. + +Thu Sep 7 00:07:17 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu) + + * dbxread.c (read_struct_type): Check for static member functions. + values.c, eval.c, valarith.c, valprint.c, valops.c: Merge changes + from Tiemann for static member functions. + + * sparc-opcode.h (tst): Fix all 3 patterns. + + * Makefile.dist (gdb1): New rule. + + * sparc-opcode.h: Change comment about what the disassembler + does with the order of the opcodes. + + * sparc-pinsn.c (compare_opcodes): Put 1+i before i+1. + Also fix mistaken comment about preserving order of original table. + + * sparc-opcode.h (clr, mov): Fix incorrect lose entries. + + * m-symmetry.h (FRAME_NUM_ARGS): Add check to deal with code that + GCC sometimes generates. + + * config.gdb: Change all occurances of "skip" to "/dev/null". + + * README (about languages other than C): Update comments about + Pascal and FORTRAN. + + * sparc-opcode.h (nop): Change lose from 0xae3fffff to 0xfe3fffff. + + * values.c (value_virtual_fn_field): #if 0-out assignment to + VALUE_TYPE(vtbl). + +Wed Sep 6 12:19:22 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * utils.c (fatal_dump_core): New function. + Makefile.dist (MALLOC_FLAGS): use -Dbotch=fatal_dump_core + +Tue Sep 5 15:47:18 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * breakpoint.c (enable_command): With no arg, enable all bkpts. + + * Makefile.dist (Makefile): Remove \"'s around $(MD). + + * Makefile.dist: In "cd readline; make . . ." change first + SYSV_DEFINE to SYSV. + + * m68k-pinsn.c (_initialize_pinsn): Use alternate assembler + syntax #ifdef HPUX_ASM + +Sat Sep 2 23:24:43 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu) + + * values.c (history_info): Don't check num_exp[0] if num_exp + is nil (just like recent editing_info change). + +Fri Sep 1 19:19:01 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu) + + * gdb.texinfo (inc-history, inc-readline): Copy in the inc-* files + because people might not have makeinfo. + + * README (xgdb): Strengthen nasty comments. + + * gdb.texinfo: Change @setfilename to "gdb.info". + +Thu Aug 31 17:23:50 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu) + + * main.c (editing_info): Don't check arg[0] if arg is null. + + * m-vax.h: Add comment about known sigtramp bug. + + * sun3-dep.c, sparc-dep.c (IS_OBJECT_FILE, exec_file_command): + Get right text & data addresses for .o files. + +Wed Aug 30 13:54:19 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * utils.c (tilde_expand): Remove function (it's in readline). + + * sparc-opcode.h (call): Change "8" to "9" in first two + patterns (%g7->%o7). + +Tue Aug 29 16:44:41 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * printcmd.c (whatis_command): Change 4th arg to type_print + from 1 to -1. + +Mon Aug 28 12:22:41 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * dbxread.c (psymtab_to_symtab_1): In "and %s ..." change + pst->filename to pst->dependencies[i]->filename. + + * blockframe.c (FRAMELESS_LOOK_FOR_PROLOGUE): New macro + made from FRAMELESS_FUNCTION_INVOCATION from m-sun3.h except + that it checks for zero return from get_pc_function_start. + m-hp9k320.h, m-hp300bsd.h, m-i386.h, m-isi.h, m-altos.h, + m-news.h, m-sparc.h, m-sun2.h, m-sun3.h, m-symmetry.h + (FRAMELESS_FUNCTION_INVOCATION): Use FRAMELESS_LOOK_FOR_PROLOGUE. + + * dbxread.c (read_struct_type): Give warning and ignore field + if bitpos and bitsize are zero. + +Sun Aug 27 04:55:20 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu) + + * dbxread.c (psymtab_to_symtab{,_1}): Print message about + reading in symbols before reading stringtab, not after. + +Sat Aug 26 02:01:53 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * dbxread.c (IS_OBJECT_FILE, ADDR_OF_TEXT_SEGMENT): New macros. + (read_dbx_symtab): Use text_addr & text_size to set end_of_text_addr. + (symbol_file_command): pass text_addr & text_size to read_dbx_symtab. + +Fri Aug 25 23:08:13 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * valprint.c (value_print): Try to give the name of function + pointed to when printing a function pointer. + +Thu Aug 24 23:18:40 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * core.c (xfer_core_file): In cases where MEMADDR is above the + largest address that makes sense, set i to len. + +Thu Aug 24 16:04:17 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * valprint.c (print_string): New function to print a character + string, doing array-max limiting and repeat count processing. + (val_print, value_print): Use print_string. + (REPEAT_COUNT_THRESHOLD): New #define, the max number of elts to print + without using a repeat count. Set to ten. + (value_print, val_print): Use REPEAT_COUNT_THRESHOLD. + + * utils.c (printchar): Use {fputs,fprintf}_filtered. + + * valprint.c (val_print): Pass the repeat count arg to the + fprintf_filtered call for "<repeats N times>" messages. + +Wed Aug 23 22:53:47 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * utils.c: Include <pwd.h>. + + * main.c: Declare free. + +Wed Aug 23 05:05:59 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu) + + * utils.c, defs.h: Add tilde_expand. + source.c (directory_command), + main.c (cd_command), + main.c (set_history_filename), + dbxread.c (symbol_file_command), + coffread.c (symbol_file_command), + dbxread.c (add_file_command), + symmisc.c (print_symtabs), + *-dep.c (exec_file_command, core_file_command), + main.c (source_command): Use tilde_expand. + + * dbxread.c (read_type): When we get a cross-reference, resolve + it immediately if possible, only calling add_undefined_type if + necessary. + + * gdb.texinfo: Uncomment @includes and put comment at start + of file telling people to use makeinfo. + + * valprint.c (type_print_base): Print the right thing for + bitfields. + + * config.gdb (sun3os3): Set paramfile and depfile. + +Tue Aug 22 05:38:36 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * dbxread.c (symbol_file_command): Pass string table size to + read_dbx_symtab(). + (read_dbx_symtab): Before indexing into string table, check + string table index for reasonableness. + (psymtab_to_symtab{,_1}, read_ofile_symtab): Same. + +Tue Aug 22 04:04:39 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * m68k-pinsn.c: Replaced many calls to fprintf and fputs with + calls to fprintf_filtered and fputs_filtered. + (print_insn_arg): Use normal MIT 68k syntax for postincrement, + predecrement, and register indirect addressing modes. + +Mon Aug 21 10:08:02 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * main.c (initialize_signals): Set signal handler for SIGQUIT + and SIGHUP to do_nothing. + + * ns32k-opcode.h (ord): Change 1D1D to 1D2D. + + * ns32k-pinsn.c (print_insn_arg, print_insn): Handle index + bytes correctly. + + * ns32k-opcode.h: Add comments. + + * dbxread.c (read_type): Put enum fields in type.fields in order + that they were found in the debugging symbols (not reverse order). + +Sun Aug 20 21:17:13 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * main.c (source_command): Read .gdbinit if run without argument. + + * source.c (directory_command): Only print "foo already in path" + if from_tty. + + * version.c: Change version number to 3.2.xxx + +Sat Aug 19 00:24:08 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu) + + * m-news.h: Define HAVE_WAIT_STRUCT. + + * m-isi.h, isi-dep.c: Replace with new version from Adam de Boor. + config.gdb: Remove isibsd43. + + * main.c (catch_termination): Don't say we have written + .gdb_history until after we really have. + + * convex-dep.c (attach): Add "sleep (1)". + (write_vector_register): Use "LL" with long long constant. + (wait): Close comment. + (wait): Change "unix 7.1 bug" to "unix 7.1 feature" & related + changes in comment. + (scan_stack): And fp with 0x80000000 in while loop test. + (core_file_command): Move code to set COREFILE. + (many places): Change printf to printf_filtered. + (psw_info): Allow argument giving value to print as a psw. + (_initialize_convex_dep): Update docstrings. + + * m-convex.h (WORDS_BIG_ENDIAN): Correct typo ("WRODS") + define NO_SIGINTERRUPT. + define SET_STACK_LIMIT_HUGE. + add "undef BUILTIN_TYPE_LONGEST" before defining it. + Use "LL" after constants in CALL_DUMMY. + + * dbxread.c: In the 3 places it says error "ridiculous string + table size"... delete extra parameter to error. + + * dbxread.c (scan_file_globals): Check for FORTRAN common block. + Allow multiple references for the sake of common blocks. + + * main.c (initialize_main): Set history_filename to include + current directory. + + * valprint.c (decode_format): Don't return a defaulted size + field if osize is zero. + + * gdb.texinfo (Compilation): Update information on -gg symbols. + Document problem with ar. + +Fri Aug 18 19:45:20 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu) + + * valprint.c (val_print, value_print): Add "<repeats %d times>" code. + Also put "..." outside quotes for strings. + + * main.c (initialize_main): Add comment about history output file + being different from history input file. + + * m-newsos3.h: Undefine NO_SIGINTERRUPT. Rearrange a few comments. + + * m-newsos3.h (REGISTER_U_ADDR): Use new version from Hikichi. + + * sparc-opcode.h: Add comment clarifying meaning of the order of + the entries in sparc_opcodes. + + * eval.c (evaluate_subexp, case UNOP_IND): Deal with deferencing + things that are not pointers. + + * valops.c (value_ind): Make dereferencing an int give a LONGEST. + + * expprint.c (print_subexp): Add (int) cast in OP_LAST case. + + * dbxread.c (read_array_type): Set lower and upper if adjustable. + + * symtab.c (lookup_symbol): Don't abort if symbol found in psymtab + but not in symtab. + +Thu Aug 17 15:51:20 1989 Randy Smith (randy at hobbes.ai.mit.edu) + + * config.gdb: Changed "Makefile.c" to "Makefile.dist". + +Thu Aug 17 01:58:04 1989 Roland McGrath (roland at apple-gunkies.ai.mit.edu) + + * sparc-opcode.h (or): Removed incorrect lose bit 0x08000000. + [many]: Changed many `lose' entries to have the 0x10 bit set, so + they don't think %l0 is %g0. + +Wed Aug 16 00:30:44 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * m-symmetry.h (STORE_STRUCT_RETURN): Also write reg 0. + (EXTRACT_RETURN_VALUE): Call symmetry_extract_return_value. + symmetry-dep.c (symmetry_extract_return_value): New fn. + + * main.c (symbol_completion_function): Deal with changed + result_list from lookup_cmd_1 for ambiguous return. + command.c (lookup_cmd): Same. + + * inflow.c [TIOCGETC]: Move #include "param.h" back before + system #includes. Change all #ifdef TIOCGETC to + #if defined(TIOCGETC) && !defined(TIOCGETC_BROKEN) + m-i386-sysv3.2.h, m-i386gas-sysv3.2.h: Remove "#undef TIOCGETC" + and add "#define TIOCGETC_BROKEN". + + * command.c (lookup_cmd_1): Give the correct result_list in the + case of an ambiguous return where there is a partial match + (e.g. "info a"). Add comment clarifying what is the correct + result_list. + + * gdb.texinfo (GDB History): Document the two changes below. + + * main.c (command_line_input): Make history expansion not + just occur at the beginning of a line. + + * main.c (initialize_main): Make history expansion off by default. + + * inflow.c: Move #include "param.h" after system #includes. + + * i386-dep.c (i386_float_info): Use U_FPSTATE macro. + + * m-i386-sysv3.2.h, m-i386gas-sysv3.2.h: New files. + Makefile.dist, config.gdb: Know about these new files. + +Tue Aug 15 21:36:11 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * symtab.c (lookup_struct_elt_type): Use type_print rather + than assuming type has a name. + +Tue Aug 15 02:25:43 1989 Roland McGrath (roland at apple-gunkies.ai.mit.edu) + + * sparc-opcode.h (mov): Removed bogus "or i,0,d" pattern. + + * sparc-opcode.h (mov, or): Fixed incorrect `lose' members. + + * sparc-dep.c: Don't include "sparc-opcode.h". + (skip_prologue, isanulled): Declare special types to recognize + instructions, and use them. + + * sparc-pinsn.c (print_insn): Sign-extend 13-bit immediate args. + If they are less than +9, print them in signed decimal instead + of unsigned hex. + + * sparc-opcode.h, sparc-pinsn.c: Completely rewritten to share an + opcode table with gas, and thus produce disassembly that looks + like what the assembler accepts. + +Tue Aug 15 16:20:52 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu) + + * symtab.c (find_pc_psymbol): Move best_pc=psymtab->textlow-1 + after test for psymtab null. + + * main.c (editing_info): Remove variable retval. + + * config.gdb (sun3, isi): Comment out obsolete message about telling + it whether you have an FPU (now that it detects it). + + * config.gdb (sun3): Accept sun3os3. + + * m68k-insn.h: Include <signal.h>. + + * m68k-pinsn.h (convert_{to,from}_68881): Add have_fpu code + + * m-newsos3.h: Undefine USE_PCB. That code didn't seem to work. + + * sparc-dep.c: Put in insn_fmt and other stuff from the old + sparc-opcode.h. + + * sparc-opcode.h, sparc-pinsn.c: Correct copyright notice. + + * sparc-opcode.h, sparc-pinsn.c: Replace the old ones with the new + ones by roland. + +Tue Aug 15 02:25:43 1989 Roland McGrath (roland at apple-gunkies.ai.mit.edu) + + * Makefile.dist: Don't define CC at all. + + * Makefile.dist (Makefile): Remove tmp.c after preprocessing. + Use $(MD) instead of M_MAKEDEFINE in the cc command. + + * Makefile.dist: Don't define RL_LIB as + "${READLINE}/libreadline.a", since READLINE is a list of files. + +Mon Aug 14 23:49:29 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * main.c (print_version): Change 1988 to 1989. + + * main.c (copying_info, initialize_main): Remove #if 0'd code. + +Tue Aug 1 14:44:56 1989 Hikichi (hikichi at sran203) + + * m-newsos3.h + (NO_SIGINTERRUPT): have SIGINTERRUPT on NEWS os 3. + + * m-news.h(FRAME_FIND_SAVED_REGS): use the sun3's instead of old + one. + +Mon Aug 14 15:27:01 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * m-news.h, m-newsos3.h, news-dep.c: Merge additional changes + by Hikichi (ChangeLog entries above). + + * Makefile.dist (READLINE): List readline files individually + so we don't accidently get random files from the readline + directory. + + * m-news.h (STORE_RETURN_VALUE, EXTRACT_RETURN_VALUE): + Expect floating point returns to be in fp0. + + * gdb.texinfo (Format options): New node. + + * gdb.texinfo: Comment out "@include"s until bfox fixes the + readline & history docs. + + * dbxread.c (read_addl_syms): Set startup_file_* if necessary at + the end (as well as when we hit ".o"). + + * printcmd.c (decode_format): Set val.format & val.size to '?' at + start and set defaults at end. + + * symtab.c (decode_line_1): Check for class_name null. + + * valops.c: Each place where it compares against field names, + check for null field names. (new t_field_name variables). + + * utils.c (fputs_filtered): Check for linebuffer null before + checking whether to call fputs. Remove later check for linebuffer + null. + +Sun Aug 13 15:56:50 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * m-isi.h, m-sun3.h ({PUSH,POP}_FP_REGS): New macros. + m-sun3.h (NUM_REGS): Conditionalize on FPU. + config.gdb (sun3, isi): Add message about support for machines + without FPU. + + * main.c (catch_termination, initialize_signals): new functions. + + * main.c (editing_info): Add "info editing n" and "info editing +". + Rewrite much of this function. + gdb.texinfo (GDB Readline): Document it. + + * values.c (history_info): Add "info history +". Also add code to + do "info history +" when command is repeated. + gdb.texinfo (Value History): Document "info history +". + + * expprint.c (print_subexp): Add OP_THIS to case stmt. + + * config.gdb (sun4os4): Put quotes around make define. + + * config.gdb: Canonicalize machine name at beginning. + +Sat Aug 12 00:50:59 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * config.gdb: define M_MAKEDEFINE + Makefile (Makefile, MD): Be able to re-make Makefile. + + * main.c (command_line_input): Add comments to + the command history. + + * Makefile.dist (Makefile): Add /bin/false. + +Fri Aug 11 14:35:33 1989 Jim Kingdon (kingdon at spiff) + + * Makefile.dist: Comment out .c.o rule and add TARGET_ARCH. + + * m-altos.h: Include sys/page.h & sys/net.h + + * m-altos.h (FRAME_CHAIN{,_VALID}): Use outside_startup_file. + + * config.gdb (altos, altosgas): Add M_SYSV & M_BSD_NM and remove + M_ALLOCA=alloca.o from makedefine. + + * coffread.c (complete_symtab): Change a_entry to entry. + + * m-altosgas.h: New file. + + * m-symmetry (REGISTER_BYTE): Fix dumb mistake. + +Fri Aug 11 06:39:49 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * utils.c (set_screensize_command): Check for ARG being nil, since + that's what execute_command will pass if there's no argument. + + * expread.y (yylex): Recognize "0x" or "0X" as the beginning of a + number. + +Thu Aug 10 15:43:12 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * config.gdb, Makefile.dist: Rename Makefile.c to Makefile.dist. + + * m-altos.h: Add comment about porting to USGR2. + + * config.gdb (sparc): Add -Usparc. + +Wed Aug 9 14:20:39 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * m-sun3os4.h: Define BROKEN_LARGE_ALLOCA. + + * values.c (modify_field): Check for value too large to fit in + bitfield. + + * utils.c (fputs_filtered): Allow LINEBUFFER to be NULL. + + * breakpoint.c (condition_command): Check for attempt to specify + non-numeric breakpoint number. + + * config.gdb, Makefile, m-altos.h, altos-dep.c: Merge Altos + port. + + * README: Change message about editing Makefile. + + * config.gdb: Edit Makefile. + Copied Makefile to Makefile.c and changed to let config.gdb + run us through the C preprocessor. + + * expread.y (yylex): Test correctly for definition of number. + +Wed Aug 9 11:56:05 1989 Randy Smith (randy at hobbes.ai.mit.edu) + + * dbxread.c (read_dbx_symtab): Put bracketing of entry point in + test case for .o symbols so that it will be correct even without + debugging symbols. + (end_psymtab): Took bracketing out. + + * blockframe.c (outside_startup_file): Reverse the sense of the + return value to make the functionality implied by the name + correct. + +Tue Aug 8 11:48:38 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * coffread.c (symbol_file_command): Do not assume presence of a.out + header. + + * blockframe.c: Replace first_object_file_end with + startup_file_{start,end} + (outside_startup_file): New function. + dbxread.c (read_addl_syms, read_dbx_symtab, end_psymbol): set + startup_file_*. Delete first_object_file_end code. + Add entry_point and ENTRY_POINT + coffread.c (complete_symtab): Set startup_file_*. + (first_object_file_end): Add as static. + m-*.h (FRAME_CHAIN, FRAME_CHAIN_VALID): Call outside_startup_file + instead of comparing with first_object_file_end. + + * breakpoint.c (breakpoint_1): Change -1 to (CORE_ADDR)-1. + + * config.gdb (i386, i386gas): Add missing quotes at end of "echo" + + * source.c (directory_command): Add dont_repeat (); + +Mon Aug 7 18:03:51 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * dbxread.c (read_addl_syms): Change strcmp to strncmp and put 3rd + arg back. + + * command.h (struct cmd_list_element): Add comment clarifying + purpose of abbrev_flag. + +Mon Aug 7 12:51:03 1989 Randy Smith (randy at hobbes.ai.mit.edu) + + * printcmd.c (_initialize_printcmd): Changed "undisplay" not to + have abbrev flag set; it isn't an abbreviation of "delete + display", it's an alias. + +Mon Aug 7 00:25:15 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * symtab.c (lookup_symtab_1): Remove filematch (never used). + + * expread.y [type]: Add second argument to 2 calls to + lookup_member_type which were missing them. + + * dbxread.c (symbol_file_command): Add from_tty arg. + Check it before calling query. + + * infcmd.c (tty_command): Add from_tty arg. + + * eval.c (evaluate_subexp): Remove 3rd argument from + calls to value_x_unop. + + * dbxread.c (read_addl_syms): Remove 3rd argument from + call to strcmp. + + * gdb.texinfo (Command editing): @include inc-readline.texinfo + and inc-history.texinfo and reorganize GDB-specific stuff. + + * Makefile: Add line MAKE=make. + + * README (second paragraph): Fix trivial errors. + + * dbxread.c (read_struct_type): Make sure p is initialized. + + * main.c (symbol_completion_function): Complete correctly + on the empty string. + +Sun Aug 6 21:01:59 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * symmetry-dep.c: Remove "long" from definition of i386_follow_jump. + + * gdb.texinfo (Backtrace): Document "where" and "info stack". + + * dbxread.c (cleanup_undefined_types): Strip off "struct " + or "union " from type names before doing comparison + +Sat Aug 5 02:05:36 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * config.gdb (i386, i386gas): Improve makefile editing instructions. + + * Makefile: Fix typo in CLIBS for SYSV. + + * dbxread.c (read_dbx_symtab): Deal with N_GSYM typedefs. + + * dbxread.c (add_file_command): Do not free name. We didn't + allocate it; it just points into arg_string. + + * Makefile, m-*.h: Change LACK_VPRINTF to HAVE_VPRINTF. + +Fri Jul 28 00:07:48 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * valprint.c (val_print): Made sure that all returns returned a + value (usually 0, indicating no memory printed). + + * core.c (read_memory): Changed "return" to "return 0". + + * expread.y (parse_number): Handle scientific notation when the + string does not contain a '.'. + +Thu Jul 27 15:14:03 1989 Randy Smith (randy at hobbes.ai.mit.edu) + + * infrun.c (signals_info): Error if signal number passed is out of + bounds. + + * defs.h: Define alloca to be __builtin_alloca if compiling with + gcc and localized inclusion of alloca.h on the sparc with the + other alloca stuff. + * command.c: Doesn't need to include alloca.h on the sparc; defs.h + does it for you. + + * printcmd.c (print_frame_args): Changed test for call to + print_frame_nameless_args to check i to tell if any args had been + printed. + +Thu Jul 27 04:40:56 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * blockframe.c (find_pc_partial_function): Always check that NAME + and/or ADDRESS are not nil before storing into them. + +Wed Jul 26 23:41:21 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * m-newsos3.h: Define BROKEN_LARGE_ALLOCA. + * dbxread.c (symbol_file_command, psymtab_to_symtab): + Use xmalloc #ifdef BROKEN_LARGE_ALLOCA. + +Tue Jul 25 16:28:18 1989 Jay Fenlason (hack at apple-gunkies.ai.mit.edu) + + * m68k-opcode.h: moved some of the fmovem entries so they're + all consecutive. This way the assembler doesn't bomb. + +Mon Jul 24 22:45:54 1989 Randy Smith (randy at hobbes.ai.mit.edu) + + * symtab.c (lookup_symbol): Changed error to an informational (if + not very comforting) message about internal problems. This will + get a null symbol returned to decode_line_1, which should force + things to be looked up in the misc function vector. + +Wed Jul 19 13:47:34 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * symtab.c (lookup_symbol): Changed "fatal" to "error" in + external symbol not found in symtab in which it was supposed to be + found. This can be reached because of a bug in ar. + +Tue Jul 18 22:57:43 1989 Randy Smith (roland at hobbes.ai.mit.edu) + + * m-news.h [REGISTER_U_ADDR]: Decreased the assumed offset of fp0 + by 4 to bring it into (apparently) appropriate alignment with + reality. + +Tue Jul 18 18:14:42 1989 Randy Smith (randy at hobbes.ai.mit.edu) + + * Makefile: pinsn.o should depend on opcode.h + + * m68k-opcode.h: Moved fmovemx with register lists to before other + fmovemx. + +Tue Jul 18 11:21:42 1989 Jim Kingdon (kingdon at susie) + + * Makefile, m*.h: Only #define vprintf (to _doprnt or printf, + depends on the system) if the library lacks it (controlled by + LACK_VPRINTF_DEFINE in makefile). Unpleasant, but necessary to + make this work with the GNU C library. + +Mon Jul 17 15:17:48 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * breakpoint.c (breakpoint_1): Change addr-b->address to + b->address-addr. + +Sun Jul 16 16:23:39 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * eval.c (evaluate_subexp): Change error message printed when + right operand of '@' is not an integer to English. + + * infcmd.c (registers_info): Fix call to print_spaces_filtered + to specify right # of arguments. + + * gdb.texinfo (Command Editing): Document info editing command. + + * coffread.c (read_file_hdr): Add MC68MAGIC. + + * source.c (select_source_symtab): Change MAX to max. + +Fri Jul 14 21:19:11 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu) + + * infcmd.c (registers_info): Clean up display to look good with long + register names, to say "register" instead of "reg", and to put the + "relative to selected stack frame" bit at the top. + +Fri Jul 14 18:23:09 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * dbxread.c (record_misc_function): Put parens around | to force + correct evaluation. + +Wed Jul 12 12:25:53 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * m-newsos3, m-news, infrun.c, Makefile, config.gdb, news-dep.c: + Merge in Hikichi's changes for Sony/News-OS 3 support. + +Tue Jul 11 21:41:32 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu) + + * utils.c (fputs_filtered): Don't do any filtering if output is + not to stdout, or if stdout is not a tty. + (fprintf_filtered): Rely on fputs_filtered's check for whether to + do filtering. + +Tue Jul 11 00:33:58 1989 Randy Smith (randy at hobbes.ai.mit.edu) + + * GDB 3.2 Released. + + * valprint.h: Deleted. + + * utils.c (fputs_filtered): Don't do any filtering if filtering is + disabled (lines_per_page == 0). + +Mon Jul 10 22:27:53 1989 Randy Smith (roland at hobbes.ai.mit.edu) + + * expread.y [typebase]: Added "unsigned long int" and "unsigned + short int" to specs. + +Mon Jul 10 21:44:55 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * main.c (main): Make -cd use cd_command to avoid + current_directory with non-absolute pathname. + +Mon Jul 10 00:34:29 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * dbxread.c (symbol_file_command): Catch errors from stat (even + though they should never happen). + + * source.c (openp): If the path is null, use the current + directory. + + * dbxread.c (read_dbx_symtab): Put N_SETV symbols into the misc + function vector ... + (record_misc_function): ... as data symbols. + + * utils.c (fprintf_filtered): Return after printing if we aren't + going to do filtering. + + * Makefile: Added several things for make clean to take care of. + + * expread.y: Lowered "@" in precedence below +,-,*,/,%. + + * eval.c (evaluate_subexp): Return an error if the rhs of "@" + isn't integral. + + * Makefile: Added removal of core and gdb[0-9] files to clean + target. + + * Makefile: Made a new target "distclean", which cleans things up + correctly for making a distribution. + +Sun Jul 9 23:21:27 1989 Randy Smith (randy at hobbes.ai.mit.edu) + + * dbxread.c: Surrounded define of gnu symbols with an #ifndef + NO_GNU_STABS in case you don't want them on some machines. + * m-npl.h, m-pn.h: Defined NO_GNU_STABS. + +Sun Jul 9 19:25:22 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu) + + * utils.c (fputs_filtered): New function. + (fprintf_filtered): Use fputs_filtered. + utils.c (print_spaces_filtered), + command.c (help_cmd,help_cmd_list), + printcmd.c (print_frame_args), + stack.c (print_block_frame_locals, print_frame_arg_vars), + valprint.c (many functions): Use fputs_filtered instead of + fprintf_filtered to avoid arbitrary limit. + + * utils.c (fprintf_filtered): Fix incorrect comment. + +Sat Jul 8 18:12:01 1989 Randy Smith (randy at hobbes.ai.mit.edu) + + * valprint.c (val_print): Changed assignment of pretty to use + prettyprint as a conditional rather than rely on values of the + enum. + + * Projects: Cleaned up a little for release. + + * main.c (initialize_main): Initialize + rl_completion_entry_function instead of completion_entry_function. + + * Makefile: Modified to use the new readline library setup. + + * breakpoint.c (break_command_1, delete_breakpoint, + enable_breakpoint, disable_breakpoint): Put in new printouts for + xgdb usage triggered off of xgdb_verbose. + * main.c (main): Added check for flag to set xgdb_verbose. + * stack.c (frame_command): Set frame_changed when frame command + used. + +Fri Jul 7 16:20:58 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * Remove valprint.h and move contents to value.h (more logical). + +Fri Jul 7 02:28:06 1989 Randall Smith (randy at rice-chex) + + * m68k-pinsn.c (print_insn): Included a check for register list; + if there is one, make sure to start p after it. + + * breakpoint.c (break_command_1, delete_breakpoint, + enable_breakpoint, disable_breakpoint): #ifdef'd out changes + below; they produce unwanted output in gdb mode in gnu-emacs. + + * gdb.texinfo: Spelled. Also removed index references from + command editing section; the relevance/volume ratio was too low. + Removed all references to the function index. + + * ns32k-opcode.h, ns32k-pinsn.c: Backed out changes of June 24th; + haven't yet received legal papers. + + * .gdbinit: Included message telling the user what it is doing. + + * symmetry-dep.c: Added static decls for i386_get_frame_setup, + i386_follow_jump. + * values.c (unpack_double): Added a return (double)0 at the end to + silence a compiler warning. + + * printcmd.c (containing_function_bounds, asdump_command): Created + to dump the assembly code of a function (support for xgdb and a + useful hack). + (_initialize_printcmd): Added this to command list. + * gdb.texinfo [Memory]: Added documentation for the asdump + command. + * breakpoint.c (break_command_1, delete_breakpoint, + enable_breakpoint, disable_breakpoint): Added extra verbosity for + xgdb conditionalized on the new external frame_full_file_name. + * source.c (identify_source_line): Increase verbosity of fullname + prointout to include pc value. + * stack.c: Added a new variable; "frame_changed" to indicate when + a frame has been changed so that gdb can print out a frame change + message when the frame only changes implicitly. + (print_frame_info): Check the new variable in determining when to + print out a new message and set it to zero when done. + (up_command): Increment it. + (down_command): Decrement it. + + * m68k-pinsn.c (print_insn_arg [lL]): Modified cases for register + lists to reset the point to point to after the word from which the + list is grabbed *if* that would cause point to point farther than + it currently is. + +Thu Jul 6 14:28:11 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu) + + * valprint.c (val_print, value_print): Add parameter to control + prettyprinting. + valprint.h: New file containing constants used for passing + prettyprinting parameter to val{,ue}_print. + expprint.c, infcmd.c, printcmd.c, valprint.c, values.c: + Change all calls to val{,ue}_print to use new parameter. + +Mon Jul 3 22:38:11 1989 Randy Smith (randy at apple-gunkies.ai.mit.edu) + + * dbxread.c (,process_one_symbol): Moved extern declaration for + index out of function to beginning of file. + +Mon Jul 3 18:40:14 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * gdb.texinfo (Registers): Add "ps" to list of standard registers. + +Sun Jul 2 23:13:03 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu) + + * printcmd.c (enable_display): Change d->next to d = d->next so + that "enable display" without args works. + +Fri Jun 30 23:42:04 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu) + + * source.c (list_command): Made error message given when no + symtab is loaded clearer. + + * valops.c (value_assign): Make it so that when assigning to an + internal variable, the type of the assignment exp is the type of + the value being assigned. + +Fri Jun 30 12:12:43 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * main.c (verbose_info): Created. + (initialize_main): Put "info verbose" into command list. + + * utils.c (screensize_info): Created. + (_initialize_utils): Defined "info screensize" as a normal command. + + * valprint.c (format_info): Added information about maximum number + of array elements to function. + + * blockframe.c (find_pc_partial_function): Again. + + * blockframe.c (find_pc_partial_function): Replaced a "shouldn't + happen" (which does) with a zero return. + + * main.c (dont_repeat): Moved ahead of first use. + +Thu Jun 29 19:15:08 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * vax-opcode.h: Made minor modifications (moved an instruction and + removed a typo) to bring this into accord with gas' table; also + changed copyright to reflect it being part of both gdb and gas. + + * m68k-opcode.h: Added whole scads and bunches of new stuff for + the m68851 and changed the coptyrightto recognize that the file + was shared between gdb and gas. + + * main.c (stop_sig): Use "dont_repeat ()" instead of *line = 0; + + * core.c (read_memory): Don't do anything if length is 0. + + * Makefile: Added readline.c to the list of files screwed by + having the ansi ioctl.h compilation with gcc. + + * config.gdb: Added sun4os3 & sun4-os3 as availible options. + +Wed Jun 28 02:01:26 1989 Jim Kingdon (kingdon at apple-gunkies.ai.mit.edu) + + * command.c (lookup_cmd): Add ignore_help_classes argument. + (lookup_cmd_1): Add ignore_help_classes argument. + command.c, main.c: Change callers of lookup_cmd{,_1} to supply + value for ignore_help_classes. + +Tue Jun 27 18:01:31 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * utils.c (print_spaces_filtered): Made more efficient. + * defs.h: Declaration. + * valprint.c (val_print): Used in a couple of new places. + +Mon Jun 26 18:27:28 1989 Randall Smith (randy at gluteus.ai.mit.edu) + + * m68k-pinsn.c (print_insn_arg ['#', '^']): Combined them into one + case which always gets the argument from the word immediately + following the instruction. + (print_insn_arg ["[lL]w"]): Make sure to always get the register + mask from the word immediately following the instruction. + +Sun Jun 25 19:14:56 1989 Randall Smith (randy at galapas.ai.mit.edu) + + * Makefile: Added hp-include back in as something to distribute. + + * stack.c (print_block_frame_locals): Return value changed from + void to int; return 1 if values printed. Use _filtered. + (print_frame_local_vars): Use return value from + print_block_frame_locals to mention if nothing printed; mention + lack of symbol table, use _filtered. + (print_frame_arg_vars): Tell the user if no symbol table + or no values printed. Use fprintf_filtered instead of fprintf. + * blockframe.c (get_prev_frame_info): Check for no inferior or + core file before crashing. + + * inflow.c (inferior_died): Set current frame to zero to keep from + looking like we're in start. + +Sat Jun 24 15:50:53 1989 Randall Smith (randy at gluteus.ai.mit.edu) + + * stack.c (frame_command): Added a check to make sure that there + was an inferior or a core file. + + * expread.y (yylex): Allow floating point numbers of the form ".5" + to be parsed. + + Changes by David Taylor at TMC: + * ns32k-pinsn.c: Added define for ?floating point coprocessor? and + tables for register names to be used for each of the possibilities. + (list_search): Created; searches a list of options for a specific + value. + (print_insn_arg): Added 'Q', 'b', 'M', 'P', 'g', and 'G' options + to the value location switch. + * ns32k-opcode.h: Added several new location flags. + [addr, enter, exit, ext[bwd], exts[bwd], lmr, lpr[bwd], restore, + rett, spr[bwd], smr]: Improved insn format output. + + * symtab.c (list_symbols): Rearrange printing to produce readable + output for "info types". + + * eval.c (evaluate_subexp_for_address): Fixed typo. + + * dbxread.c (read_type): Don't output an error message when + there isn't a ',' after a cross-reference. + + * dbxread.c (read_dbx_symtab): #if'd out N_FN case in + read_dbx_symtab if it has the EXT bit set (otherwise multiple + cases with the same value). + +Fri Jun 23 13:12:08 1989 Randall Smith (randy at plantaris.ai.mit.edu) + + * symmisc.c: Changed decl of print_spaces from static to extern + (since it's defined in utils.c). + + * remote.c (remote_open): Close remote_desc if it's already been + opened. + + * Remote_Makefile, remote_gutils.c, remote_inflow.c, + remote_server.c, remote_utils.c: Combined into remote-multi.shar. + * remote-multi.shar: Created (Vikram Koka's remote stub). + * remote-sa.m68k.shar: Created (Glenn Engel's remcom.c). + * README: Updated to reflect new organization of remote stubs. + + * dbxread.c (read_dbx_symtab): Put an N_FN in with N_FN | N_EXT to + account for those machines which don't use the external bit here. + Sigh. + + * m-symmetry.h: Defined NO_SIGINTERRUPT. + +Thu Jun 22 12:51:37 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * printcmd.c (decode_format): Make sure characters are printed + using a byte size. + + * utils.c (error): Added a terminal_ours here. + + * stack.c (locals_info): Added check for selected frame. + + * dbxread.c (read_type): Checked to make sure that a "," was + actually found in the symbol to end a cross reference. + +Wed Jun 21 10:30:01 1989 Randy Smith (randy at tartarus.uchicago.edu) + + * expread.y (parse_number, [exp]): Allowed for the return of a + number marked as unsigned; this will allow inclusion of unsigned + constants. + + * symtab.h: Put in default definitions for BUILTIN_TYPE_LONGEST + and BUILTIN_TYPE_UNSIGNED_LONGEST. + + * expread.y (parse_number): Will now accept integers suffixed with + a 'u' (though does nothing special with it). + + * valarith.c (value_binop): Added cases to deal with unsigned + arithmetic correctly. + +Tue Jun 20 14:25:54 1989 Randy Smith (randy at tartarus.uchicago.edu) + + * dbxread.c (psymtab_to_symtab_1): Changed reading in info message + to go through printf_filtered. + + * symtab.c (list_symbols): Placed header message after all calls + to psymtab_to_symtab. + + * symtab.c (smash_to_{function, reference, pointer}_type): Carried + attribute of permanence for the type being smashed over the bzero + and allowed any type to point at this one if it is permanent. + + * symtab.c (smash_to_{function, reference, pointer}_type): Fix + typo: check flags of to_type instead of type. + + * m-hp9k320.h: Changed check on __GNU__ predefine to __GNUC__. + + * Makefile: Made MUNCH_DEFINE seperate and based on SYSV_DEFINE; + they aren't the same on hp's. + +Mon Jun 19 17:10:16 1989 Randy Smith (randy at tartarus.uchicago.edu) + + * Makefile: Fixed typo. + + * valops.c (call_function): Error if the inferior has not been + started. + + * ns32k-opcode.h [check[wc], cmpm[bwd], movm[bwd], skpsb]: Fixed + typos. + +Fri Jun 9 16:23:04 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * m-news.h [NO_SIGINTERRUPT]: Defined. + + * dbxread.c (read_type): Start copy of undefined structure name + past [sue] defining type of cross ref. + + * dbxread.c (process_one_symbol): Changed strchr to index. + + * ns32k-opcode.h, ns32k-pinsn.c: More changes to number of + operands, addition of all of the set condition opcodes, addition + of several flag letters, all patterned after the gas code. + + * ns32k-opcode.h [mov{su,us}[bwd], or[bwd]]: Changed number of + operands from 1 to 2. + +Wed Jun 7 15:04:24 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * symseg.h [TYPE_FLAG_STUB]: Created. + * dbxread.c (read_type): Set flag bit if type is stub. + (cleanup_undefined_types): Don't mark it as a stub if it's been + defined since we first learned about it. + * valprint.c (val_print): Print out a message to that effect if + this type is encountered. + + * symseg.h, symtab.h: Moved the definition of TYPE_FLAG_PERM over + to symseg.h so that all such definitions would be in the same place. + + * valprint.c (val_print): Print out <No data fields> for a + structure if there aren't any. + + * dbxread.c (read_type): Set type name of a cross reference type + to "struct whatever" or something. + +Tue Jun 6 19:40:52 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * breakpoint.c (breakpoint_1): Print out symbolic location of + breakpoints for which there are no debugging symbols. + +Mon Jun 5 15:14:51 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * command.c (help_cmd_list): Made line_size static. + +Sat Jun 3 17:33:45 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * Makefile: Don't include the binutils hp-include directory in the + distribution anymore; refer the users to the binutils distribution. + +Thu Jun 1 16:33:07 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * printcmd.c (disable_display_command): Fixed loop iteration for + no arg case. + + * printcmd.c (disable_display_command): Added from_tty parameter + to function. + + * valops.c (value_of_variable): Call read_var_value with 0 cast to + FRAME instead of CORE_ADDR. + + * eval.c (evaluate_subexp): Corrected number of args passed to + value_subscript (to 2). + + * infrun.c (wait_for_inferior), symtab.c (decode_line_1), + m-convex.h: Changed name of FIRSTLINE_DEBUG_BROKEN to + PROLOGUE_FIRSTLINE_OVERLAP. + + * m-merlin.h: Fixed typo. + * ns32k-opcode.h: Added ns32381 opcodes and "cinv" insn, and fixed + errors in movm[wd], rett, and sfsr. + + * eval.c (evaluate_subexp, evaluate_subexp_for_address), valops.c + (value_zero): Change value_zero over to taking two arguments + instead of three. + + * eval.c (evaluate_subexp) + [OP_VAR_VALUE]: Get correct lval type for AVOID_SIDE_EFFECTS for + all types of symbols. + [BINOP_DIV]: Don't divide if avoiding side effects; just return + an object of the correct type. + [BINOP_REPEAT]: Don't call value_repeat, just allocate a + repeated value. + (evaluete_subexp_for_address) [OP_VAR_VALUE]: Just return a thing + of the right type (after checking to make sure that we are allowed + to take the address of whatever variable has been passed). + +Mon May 29 11:01:02 1989 Randall Smith (randy at galapas.ai.mit.edu) + + * breakpoint.c (until_break_command): Set the breakpoint with a + frame specification so that it won't trip in inferior calls to the + function. Also set things up so that it works based on selected + frame, not current one. + +Sun May 28 15:05:33 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * eval.c (evalue_subexp): Change subscript case to use value_zero + in EVAL_AVOID_SIDE_EFFECTS case. + +Fri May 26 12:03:56 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * dbxread.c (read_addl_syms, psymtab_to_symtab): Removed + cleanup_undefined_types; this needs to be done on a symtab basis. + (end_symtab): Called cleanup_undefined_types from here. + (cleanup_undefined_types): No longer uses lookup_symbol (brain + dead idea; oh, well), now it searches through file_symbols. + +Wed May 24 15:52:43 1989 Randall Smith (randy at galapas) + + * source.c (select_source_symtab): Only run through + partial_symtab_list if it exists. + + * coffread.c (read_coff_symtab): Don't unrecord a misc function + when a function symbol is seen for it. + + * expread.y [variable]: Make sure to write a type for memvals if + you don't get a mft you recognize. + +Tue May 23 12:15:57 1989 Randall Smith (randy at plantaris.ai.mit.edu) + + * dbxread.c (read_ofile_symtab, psymtab_to_symtab): Moved cleanup + of undefined types to psymtab_to_symtab. That way it will be + called once for all readins (which will, among other things, + help reduce infinite loops). + + * symtab.h [misc_function_type]: Forced mf_unknown to 0. + * dbxread.c (record_misc_function): Cast enum to unsigned char (to + fit). + * expread.y [variable]: Cast unsigned char back to enum to test. + +Mon May 22 13:08:25 1989 Randall Smith (randy at gluteus.ai.mit.edu) + + Patches by John Gilmore for dealing well with floating point: + * findvar.c (value_from_register, locate_var_value): Used + BYTES_BIG_ENDIAN instead of an inline test. + * m-sparc.h [IEEE_FLOAT]: Created to indicate that the sparc is + IEEE compatible. + * printcmd.c (print_scalar_formatted): Use BYTES_BIG_ENDIAN and + the stream argument for printing; also modify default type for + 'f'. Change handling of invalid floats; changed call syntax for + is_nan. + (print_command): Don't print out anything indicating that + something was recorded on the history list if it wasn't. + * valprint.c (val_print): Fixed to deal properley with new format + of is_nan and unpacking doubles without errors occuring. + (is_nan): Changed argument list and how it figures big endianness + (uses macros). + * values.c (record_latest_value): Return -1 and don't record if + it's an invalid float. + (value_as_double): Changed to use new unpack_double calling + convention. + (unpack_double): Changed not to call error if the float was + invalid; simply to set invp and return. Changed calling syntax. + (unpack_field_as_long, modify_field): Changed to use + BITS_BIG_ENDIAN to determine correct action. + + * m-hp9k320.h [HP_OS_BUG]: Created; deals with problem where a + trap happens after a continue. + * infrun.c (wait_for_inferior): Used. + + * m-convex.h [FIRSTLINE_DEBUG_BROKEN]: Defined a flag to indicate + that the debugging symbols output by the compiler for the first + line of a function were broken. + * infrun.c (wait_for_inferior), symtab.c (decode_line_1): Used. + + * gdb.texinfo [Data, Memory]: Minor cleanups of phrasing. + +Fri May 19 00:16:59 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * dbxread.c (add_undefined_type, cleanup_undefined_types): Created + to keep a list of cross references to as yet undefined types. + (read_type): Call add_undefined_type when we run into such a case. + (read_addl_syms, read_ofile_symtab): Call cleanup_undefined_types + when we're done. + + * dbxread.c (psymtab_to_symtab, psymtab_to_symtab_1): Broke + psymtab_to_symtab out into two routines; made sure the string + table was only readin once and the globals were only scanned once, + for any number of dependencies. + +Thu May 18 19:59:18 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * m-*.h: Defined (or not, as appropriate per machine) + BITS_BIG_ENDIAN, BYTES_BIG_ENDIAN, and WORDS_BIG_ENDIAN. + +Wed May 17 13:37:45 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * main.c (symbol_completion_function): Always complete on result + command list, even if exact match found. If it's really an exact + match, it'll find it again; if there's something longer than it, + it'll get the right result. + + * symtab.c (make_symbol_completion_function): Fixed typo; strcmp + ==> strncmp. + + * dbxread.c (read_dbx_symtab): Change 'G' case to mark symbols as + LOC_EXTERNAL. + + * expread.y [variables]: Changed default type of text symbols to + function returning int so that one can use, eg. strcmp. + + * infrun.c (wait_for_inferior): Include a special flag indicating + that one shouldn't insert the breakpoints on the next step for + returning from a sigtramp and forcing at least one move forward. + + * infrun.c (wait_for_inferior): Change test for nexting into a + function to check for current stack pointer inner than previous + stack pointer. + + * infrun.c (wait_for_inferior): Check for step resume break + address before dealing with normal breakpoints. + + * infrun.c (wait_for_inferior): Added a case to deal with taking + and passing along a signal when single stepping past breakpoints + before inserting breakpoints. + + * infrun.c (wait_for_inferior): Inserted special case to keep + going after taking a signal we are supposed to be taking. + +Tue May 16 12:49:55 1989 Randall Smith (randy at gluteus.ai.mit.edu) + + * inflow.c (terminal_ours_1): Cast result of signal to (int + (*)()). + + * gdb.texinfo: Made sure that references to the program were in + upper case. Modify description of the "set prompt" command. + [Running]: Cleaned up introduction. + [Attach]: Cleaned up. + [Stepping]: Change "Proceed" to "Continue running" or "Execute". + Minor cleanup. + [Source Path]: Cleaned up intro. Cleared up distinction between + the executable search path and the source path. Restated effect + of the "directory" command with no arguments. + [Data]: Fixed typos and trivial details. + [Stepping]: Fixed up explanation of "until". + + * source.c (print_source_lines): Print through filter. + + * printcmd.c (x_command): If the format with which to print is + "i", use the address of anything that isn't a pointer instead of + the value. This is for, eg. "x/10i main". + + * gdb.texinfo: Updated last modification date on manual. + +Mon May 15 12:11:33 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * symtab.c (lookup_symtab): Fixed typo (name ==> copy) in call to + lookup_symtab_1. + + * gdb.texinfo: Added documentation for "break [+-]n" and for new + actions of "directory" command (taking multiple directory names at + the same time). + + * m68k-opcode.h: Replaced the version in gdb with an up-to-date + version from the assembler directory. + * m68k-pinsn.c (print_insn_arg): Added cases 'l' & 'L' to switch + to print register lists for movem instructions. + + * dbxread.c, m-convex.h: Moved convex dependent include files over + from dbxread.c to m-convex.h. + + * printcmd.c (disable_display, disable_display_command): Changed + name of first to second, and created first which takes an int as + arg rather than a char pointer. Changed second to use first. + (_initialize_printcmd): Changed to use second as command to call. + (delete_current_display, disable_current_display): Changed name of + first to second, and changed functionality to match. + * infrun.c (normal_stop), main.c (return_to_top_level): Changed to + call disable_current_display. + + * dbxread.c (process_one_symbol, read_dbx_symtab): Changed N_FN to + be N_FN | N_EXT to deal with new Berkeley define; this works with + either the old or the new. + + * Remote_Makefile, remote_gutils.c, remote_inflow.c, + remote_server.c, remote_utils.c: Created. + * Makefile: Included in tag and tar files. + * README: Included a note about them. + + * printcmd.c (print_address): Use find_pc_partial_function to + remove need to readin symtabs for symbolic addresses. + + * source.c (directory_command): Replaced function with new one + that can accept lists of directories seperated by spaces or :'s. + + * inflow.c (new_tty): Replaced calls to dup2 with calls to dup. + +Sun May 14 12:33:16 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * stack.c (args_info): Make sure that you have an inferior or core + file before taking action. + + * ns32k-opcode.h [deiw, deid]: Fixed machine code values for these + opcodes. + + * dbxread.c (scan_file_globals): Modified to use misc function + vector instead of file itself. Killed all arguments to the + funciton; no longer needed. + (psymtab_to_symtab): Changed call for above to reflect new (void) + argument list. + + * dbxread.c (read_dbx_symtab, ): Moved HASH_OFFSET define out of + read_dbx_symtab. + + * expread.y [variable]: Changed default type of misc function in + text space to be (void ()). + + * Makefile: Modified for proper number of s/r conflicts (order is + confusing; the mod that necessitated this change was on May 12th, + not today). + + * expread.y (yylex): Added SIGNED, LONG, SHORT, and INT keywords. + [typename]: Created. + [typebase]: Added rules for LONG, LONG INT, SHORT, SHORT INT, + SIGNED name, and UNSIGNED name (a good approximation of ansi + standard). + + * Makefile: Included .c.o rule to avoid sun's make from throwing + any curves at us. + + * blockframe.c: Included <obstack.h> + + * command.c (lookup_cmd): Clear out trailing whitespace. + + * command.c (lookup_cmd_1): Changed malloc to alloca. + +Fri May 12 12:13:12 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * printcmd.c (print_frame_args): Only print nameless args when you + know how many args there are supposed to be and when you've + printed fewer than them. Don't print nameless args between + printed args. + + * symtab.c (make_symbol_completion_function): Fixed typo (= ==> + ==). + + * remote.c (remote_open): ifdef'd out siginterrupt call by #ifndef + NO_SIGINTERRUPT. + * m-umax.h: Defined NO_SIGINTERRUPT. + + * expread.y [ptype, array_mod, func_mod, direct_abs_decl, + abs_decl]: Added rules for parsing and creating arbitrarily + strange types for casts and sizeofs. + + * symtab.c, symtab.h (create_array_type): Created. Some minor + misfeatures; see comments for details (main one being that you + might end up creating two arrays when you only needed one). + +Thu May 11 13:11:49 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * valops.c (value_zero): Add an argument for type of lval. + * eval.c (evaluate_subexp_for_address): Take address properly in + the avoid side affects case (ie. keep track of whether we have an + lval in memory and we can take the address). + (evaluate_subexp): Set the lval type of expressions created with + value_zero properley. + + * valops.c, value.h (value_zero): Created--will return a value of + any type with contents filled with zero. + * symtab.c, symtab.h (lookup_struct_elt_type): Created. + * eval.c (evaluate_subexp): Modified to not read memory when + called with EVAL_AVOID_SIDE_EFFECTS. + + * Makefile: Moved dbxread.c ahead of coffread.c in the list of + source files. + +Wed May 10 11:29:19 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * munch: Make sure that sysv version substitutes for the whole + line. + + * symtab.h: Created an enum misc_function_type to hold the type of + the misc function being recorded. + * dbxread.c (record_misc_function): Branched on dbx symbols to + decide which type to assign to a misc function. + * coffread.c (record_misc_function): Always assign type unknown. + * expread.y [variable]: Now tests based on new values. + +Tue May 9 13:03:54 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * symtab.c: Changed inclusion of <strings.h> (doesn't work on + SYSV) to declaration of index. + + * Makefile: Changed last couple of READLINE_FLAGS SYSV_DEFINE + + * source.c ({forward, reverse}_search_command): Made a default + search file similar to for the list command. + +Mon May 8 18:07:51 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * printcmd.c (print_frame_args): If we don't know how many + arguments there are to this function, don't print the nameless + arguments. We don't know enough to find them. + + * printcmd.c (print_frame_args): Call print_frame_nameless_args + with proper arguments (start & end as offsets from addr). + + * dbxread.c (read_addl_syms): Removed cases to deal with global + symbols; this should all be done in scan_global_symbols. + +Sun May 7 11:36:23 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * Makefile: Added copying.awk to ${OTHERS}. + +Fri May 5 16:49:01 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * valprint.c (type_print_varspec_prefix): Don't pass + passed_a_pointer onto children. + + * valprint.c (type_print_varspec_suffix): Print "array of" with + whatever the "of" is after tha array brackets. + + * valprint.c (type_print_varspec_{prefix,suffix}): Arrange to + parenthesisze pointers to arrays as well as pointers to other + objects. + + * valprint.c (type_print_varspec_suffix): Make sure to print + subscripts of multi-dimensional arrays in the right order. + + * infcmd.c (run_command): Fixed improper usages of variables + within remote debugging branch. + + * Makefile: Added Convex.notes to the list of extra files to carry + around. + + * dbxread.c (symbol_file_command): Made use of alloca or malloc + dependent on macro define. + +Thu May 4 15:47:04 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * Makefile: Changed READLINE_FLAGS to SYSV_DEFINE and called munch + with it also. + * munch: Check first argument for -DSYSV and be looser about + picking up init routines if you find it. + + * coffread.c: Made fclose be of type int. + + * breakpoint.c (_initialize_breakpoint): Put "unset" into class + alias. + +Wed May 3 14:09:12 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * m-sparc.h [STACK_END_ADDR]: Parameterized off of + machine/vmparam.h (as per John Gilmore's suggestion). + + * blockframe.c (get_prev_frame_info): Changed this function back + to checking frameless invocation first before checking frame + chain. This means that a backtrace up from start will produce the + wrong value, but that a backtrace from a frameless function called + in main will show up correctly. + + * breakpoint.c (_initialize_breakpoint): Added entry in help for + delete that indicates that unset is an alias for it. + + * main.c (symbol_completion_function): Modified recognition of + being within a single command. + +Tue May 2 15:13:45 1989 Randy Smith (randy at gnu) + + * expread.y [variable]: Add some parens to get checking of the + misc function vector right. + +Mon May 1 13:07:03 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * default-dep.c (core_file_command): Made reg_offset unsigned. + + * default-dep.c (core_file_command): Improved error messages for + reading in registers. + + * expread.y: Allowed a BLOCKNAME to be ok for a variable name (as + per C syntax). + + * dbxread.c (psymtab_to_symtab): Flushed stdout after printing + starting message about reading in symbols. + + * printcmd.c (print_frame_args): Switched starting place for + printing of frameless args to be sizeof int above last real arg + printed. + + * printcmd.c (print_frame_args): Modified final call to + print_nameless_args to not use frame slots used array if none had + been used. + + * infrun.c (wait_for_inferior): Take FUNCTION_START_OFFSET into + account when dealing with comparison of pc values to function + addresses. + + * Makefile: Added note about compiling gdb on a Vax running 4.3. + +Sun Apr 30 12:59:46 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * command.c (lookup_cmd): Got correct error message on bad + command. + + * m-sun3.h [ABOUT_TO_RETURN]: Modified to allow any of the return + instructions, including trapv and return from interupt. + + * command.c (lookup_cmd): If a command is found, use it's values + for error reporting and determination of needed subcommands. + + * command.c (lookup_cmd): Use null string for error if cmdtype is + null; pass *line to error instead of **. + + * command.c (lookup_cmd_1): End of command marked by anything but + alpha numeric or '-'. Included ctype.h. + +Fri Apr 28 18:30:49 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * source.c (select_source_symtab): Kept line number from ever + being less than 1 in main decode. + +Wed Apr 26 13:03:20 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * default-dep.c (core_file_command): Fixed typo. + + * utils.c (fprintf_filtered): Don't use return value from + numchars. + + * main.c, command.c (complete_on_cmdlist): Moved function to + command.c. + + * command.c (lookup_cmd): Modified to use my new routine. Old + version is still there, ifdef'd out. + + * command.c, command.h (lookup_cmd_1): Added a routine to do all + of the work of lookup_cmd with no error reporting and full return + of information garnered in search. + +Tue Apr 25 12:37:54 1989 Randall Smith (randy at gluteus.ai.mit.edu) + + * breakpoint.c (_initialize_breakpoint): Change "delete + breakpionts" to be in class alias and not have the abbrev flag + set. + + * main.c (symbol_completion_function): Fix to correctly complete + things that correspond to multiword aliases. + + * main.c (complete_on_cmdlist): Don't complete on something if it + isn't a command or prefix (ie. if it's just a help topic). + + * main.c (symbol_completion_function): Set list index to be 0 if + creating a list with just one element. + + * main.c (complete_on_cmdlist): Don't allow things with + abbrev_flag set to be completion values. + (symbol_completion_function): Don't accept an exact match if the + abbrev flag is set. + + * dbxread.c (read_type): Fixed typo in comparision to check if + type number existed. + + * dbxread.c (read_type): Made sure to only call dbx_lookup_type on + typenums if typenums were not -1. + +Mon Apr 24 17:52:12 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * symtab.c: Added strings.h as an include file. + +Fri Apr 21 15:28:38 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * symtab.c (lookup_partial_symtab): Changed to only return a match + if the name match is exact (which is what I want in all cases in + which this is currently used. + +Thu Apr 20 11:12:34 1989 Randall Smith (randy at gluteus.ai.mit.edu) + + * m-isi.h [REGISTER_U_ADDR]: Installed new version from net. + * default-dep.c: Deleted inclusion of fcntl.h; apparently not + necessary. + * Makefile: Added comment about compiling on isi under 4.3. + + * breakpoint.c (break_command_1): Only give decode_line_1 the + default_breakpoint_defaults if there's nothing better (ie. make + the default be off of the current_source notes if at all + possible). + + * blockframe.c (get_prev_frame_info): Clean up comments and + delete code ifdefed out around FRAMELESS_FUNCTION_INVOCATION test. + + * remote.c: Added a "?" message to protocol. + (remote_open): Used at startup. + (putpkt): Read whatever garbage comes over the line until we see a + '+' (ie. don't treat garbage as a timeout). + + * valops.c (call_function): Eliminated no longer appropriate + comment. + + * infrun.c (wait_for_inferior): Changed several convex conditional + compilations to be conditional on CANNOT_EXECUTE_STACK. + +Wed Apr 19 10:18:17 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * printcmd.c (print_frame_args): Added code to attempt to deal + with arguments that are bigger than an int. + + Continuation of Convex/Fortran changes: + * printcmd.c (print_scalar_formatted): Added leading zeros to + printing of large integers. + (address_info, print_frame_args): Added code to deal with + LOC_REF_ARG. + (print_nameless_args): Allow param file to specify a routine with + which to print typeless integers. + (printf_command): Deal with long long values well. + * stack.c (print_frame_arg_vars): Change to deal with LOC_REF_ARG. + * symmisc.c (print_symbol): Change to deal with LOC_REF_ARG. + * symseg.h: Added LOC_REF_ARG to enum address_class. + * symtab.c (lookup_block_symbol): Changed to deal with + LOC_REF_ARG. + * valarith.c (value_subscripted_rvalue): Created. + (value_subscript): Used above when app. + (value_less, value_equal): Change to cast to (char *) before doing + comparison, for machines where that casting does something. + * valops.c (call_function): Setup to deal with machines where you + cannot execute code on the stack segment. + * valprint.c (val_print): Make sure that array element size isn't + zero before printing. Set address of default array to address of + first element. Put in a couple of int cast. Removed some convex + specific code. Added check for endianness of machine in case of a + packed structure. Added code for printing typeless integers and + for LONG LONG's. + (set_maximum_command): Change to use parse_and_eval_address to get + argument (so can use expressions there). + * values.c (value_of_internalvar, set_internalvar_component, + set_internalvar, convenience_info): Add in hooks for trapped + internal vars. + (unpack_long): Deal with LONG_LONG. + (value_field): Remove LONGEST cast. + (using_struct_return): Fixed typo ENUM ==> UNION. + * xgdb.c (_initialize_xgdb): Make sure that specify_exec_file_hook + is not called unless we are setting up a windowing environ. + +Tue Apr 18 13:43:37 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + Various changes involved in 1) getting gdb to work on the convex, + and 2) Getting gdb to work with fortran (due to convex!csmith): + * convex-dep.c, convex-opcode.h, m-convex.h, convex-pinsn.c: + Created (or replaced with new files). + * Makefile: Add convex dependent files. Changed default flags to + gnu malloc to be CFLAGS. + * config.gdb: Added convex to list of machines. + * core.c (files_info): Added a FILES_INFO_HOOK to be used if + defined. + (xfer_core_file): Conditionalized compilation of xfer_core_file on + the macro XFER_CORE_FILE. + * coffread.c (record_misc_function): Made sure it zerod type field + (which is now being used; see next). + * dbxread.c: Included some convex dependent include files. + (copy_pending, fix_common_blocks): Created. + [STAB_REG_REGNUM, BELIEVE_PCC_PROMOTION]: Created default values; + may be overridden in m-*.h. + Included data structures for keeping track of common blocks. + (dbx_alloc_type): Modified; if called with negative 1's will + create a type without putting it into the type vector. + (read_dbx_symtab, read_addl_syms): Modified calls to + record_misc_function to include the new information. + (symbol_file_command, psymtab_to_symtab, add_file_command): + Modified reading in of string table to adapt to machines which + *don't* store the size of the string table in the first four bytes + of the string table. + (read_dbx_symtab, scan_file_globals, read_ofile_symtab, + read_addl_syms): Modified assignment of namestring to accept null + index into symtab as ok. + (read_addl_syms): Modified readin of a new object file to fiddle + with common blocks correctly. + (process_one_symbol): Fixed incorrect comment about convex. Get + symbols local to a lexical context from correct spot on a per + machine basis. Catch a bug in pcc which occaisionally puts an SO + where there should be an SOL. Seperate sections for N_BCOMM & + N_ECOMM. + (define_symbol): Ignore symbols with no ":". Use + STAB_REG_TO_REGNUM. Added support for function args calling by + reference. + (read_type): Only read type number if one is there. Remove old + (#if 0'd out) array code. + (read_array_type): Added code for dealing with adjustable (by + parameter) arrays half-heartedly. + (read_enum_type): Allow a ',' to end a list of values. + (read_range_type): Added code to check for long long. + * expread.y: Modified to use LONGEST instead of long where + necessary. Modified to use a default type of int for objects that + weren't in text space. + * findvar.c (locate_var_value, read_var_value): Modified to deal + with args passed by reference. + * inflow.c (create_inferior): Used CREATE_INFERIOR_HOOK if it + exists. + * infrun.c (attach_program): Run terminal inferior when attaching. + (wait_for_inferior): Removed several convex dependencies. + * main.c (float_handler): Created. + Made whatever signal indicates a stop configurable (via macro + STOP_SIGNAL). + (main): Setup use of above as a signal handler. Added check for + "-nw" in args already processed. + (command_line_input): SIGTSTP ==>STOP_SIGNAL. + + * expread.y: Added token BLOCKNAME to remove reduce/reduce + conflict. + * Makefile: Change message to reflect new grammar. + +Mon Apr 17 13:24:59 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * printcmd.c (compare_ints): Created. + (print_frame_args): Modified to always print arguments in the + order in which they were found in the symbol table. Figure out + what apots are missing on the fly. + + * stack.c (up_command): Error if no inferior or core file. + + * m-i386.h, m-symmetry.h [FRAMELESS_FUNCTION_INVOCATION]: Created; + same as m68k. + + * dbxread.c (define_symbol): Changed "desc==0" test to + "processing_gcc_compilation", which is the correct way to do it. + +Sat Apr 15 17:18:38 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * expread.y: Added precedence rules for arglists, ?:, and sizeof + to eliminate some shift-reduce conflicts. + * Makefile: Modified "Expect" message to conform to new results. + +Thu Apr 13 12:29:26 1989 Randall Smith (randy at plantaris.ai.mit.edu) + + * inflow.c (terminal_init_inferior): Fixed typo in recent diff + installation; TIOGETC ==> TIOCGETC. + + * m-vax.h, m-sun2.h, m-sun3.h, m-sparc.h, m-hp*.h, m-isi.h, + m-news.h [FRAMELESS_FUNCTION_INVOCATION]: Created macro with + appropriate definition. + +Wed Apr 12 15:30:29 1989 Randall Smith (randy at plantaris.ai.mit.edu) + + * blockframe.c (get_prev_frame_info): Added in a macro to specify + when a "frame" is called without a frame pointer being setup. + + * Makefile [clean]: Made sure to delete gnu malloc if it was being + used. + +Mon Apr 10 12:43:49 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * dbxread.c (process_one_symbol): Reset within_function to 0 after + last RBRAC of a function. + + * dbxread.c (read_struct_type): Changed check for filling in of + TYPE_MAIN_VARIANT of type. + + * inflow.c (create_inferior): Conditionalized fork so that it + would be used if USG was defined and HAVE_VFORK was not defined. + + * defs.h: Added comment about enum command_class element + class_alias. + + * dbxread.c (process_one_symbol): Fixed a typo with interesting + implications for associative processing in the brain (':' ==> 'c'). + + * sparc-dep.c (isabranch): Changed name to isannulled, modified to + deal with coprocessor branches, and improved comment. + (single_step): Changed to trap at npc + 4 instead of pc +8 on + annulled branches. Changed name in call to isabranch as above. + + * m-sun4os4.h (STACK_END_ADDRESS): Changed it to 0xf8000000 under + os 4.0. + +Sat Apr 8 17:04:07 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * dbxread.c (process_one_symbol): In the case N_FUN or N_FNAME the + value being refered to is sometimes just a text segment variable. + Catch this case. + + * infrun.c (wait_for_inferior), breakpoint.c + (breakpoint_stop_status): Move the selection of the frame to + inside breakpoint_stop_status so that the frame only gets selected + (and the symbols potentially read in) if the symbols are needed. + + * symtab.c (find_pc_psymbol): Fixed minor misthough (pc >= + fucntion start, not >). + + * breakpoint.c (_initialize_breakpoint): Change "delete" internal + help entry to simply refer to it being a prefix command (since the + list of subcommands is right there on a "help delete"). + +Fri Apr 7 15:22:18 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * blockframe.c (find_pc_partial_function): Created; figures out + what function pc is in (name and address) without reading in any + new symbols. + * symtab.h: Added decl for above. + * infrun.c (wait_for_inferior): Used instead of + find_pc_function_start. + * stack.c (print_frame_info): Used instead of hand coding for same + thing. + + * dbxread.c (psymtab_to_symtab): No longer patch readin pst's out + of the partial_symtab_list; need them there for some checks. + * blockframe.c (block_for_pc), source.c (select_source_symtab), + symtab.c (lookup_symbol, find_pc_symtab, list_symbols): Made extra + sure not to call psymtab_to_symtab with ->readin == 1, since these + psymtab now stay on the list. + * symtab.c (sources_info): Now distinguishes between psymtabs with + readin set and those with it not set. + + * symtab.c (lookup_symtab): Added check through partial symtabs + for name with .c appended. + + * source.c (select_source_symtab): Changed semantics a little so + that the argument means something. + * source.c (list_command), symtab.c (decode_line_1): Changed call + to select_source_symtab to match new conventions. + + * dbxread.c (add_file_command): This command no longer selects a + symbol table to list from. + + * infrun.c (wait_for_inferior): Only call find_pc_function (to + find out if we have debugging symbols for a function and hence if + we should step over or into it) if we are doing a "step". + +Thu Apr 6 12:42:28 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * main.c (command_line_input): Added a local buffer and only + copied information into the global main.c buffer when it is + appropriate for it to be saved (and repeated). + (dont_repeat): Only nail line when we are reading from stdin + (otherwise null lines won't repeat and what's in line needs to be + saved). + (read_command_lines): Fixed typo; you don't what to repeat when + reading command lines from the input stream unless it's standard + input. + + John Gilmore's (gnu@toad.com) mods for USG gdb: + * inflow.c: Removed inclusion of sys/user.h; no longer necessary. + (, terminal_init_inferior, terminal_inferior, terminal_ours_1, + term_status_command, _initialize_inflow) Seperated out declaration + and usage of terminal mode structures based on the existence of + the individual ioctls. + * utils.c (request_quit): Restore signal handler under USG. If + running under USG initialize sys_siglist at run time (too much + variation between systems). + +Wed Apr 5 13:47:24 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + John Gilmore's (gnu@toad.com) mods for USG gdb: + * default-dep.c: Moved include of sys/user.h to after include of + a.out.h. + (store_inferior_registers): Fixed error message. + (core_file_command): Improved error messages from reading in of + u area in core file. Changed calculation of offset of registers + to account for some machines putting it in as an offset rather + than an absolute address. Changed error messages for reading of + registers from core file. + + * coffread.c (read_file_hdr): Added final check for BADMAG macro + to use if couldn't recognize magic number. + * Makefile: Added explicit directions for alloca addition. + Included alloca.c in list of possible library files. Cleaned up + possible library usage. Included additional information on gcc + and include files. + + * source.c, remote.c, inflow.c, dbxread.c, core.c, coffread.c: + Changed include of sys/fcntl.h to an include of fcntl.h (as per + posix; presumably this will break fewer machines. I hopw). + * README: Added a pointer to comments at top of Makefile. + * Makefile: Added a comment about machines which need fcntl.h in + sys. + +Tue Apr 4 11:29:04 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * valprint.c (set_prettyprint_command, set_unionprint_command, + format_info): Created. + (_initialize_valprint): Added to lists of commands. + + * gdb.texinfo [Backtrace]: Added a section describing the format + if symbols have not yet been read in. + + * valprint.c (val_print): Added code to prettyprint structures if + "prettyprint" is set and only to print unions below the top level + if "unionprint" is set. + + * infcmd.c (registers_info), valprint.c (value_print, val_print): + Added argument to call to val_print indicating deptch of recursion. + + * symtab.[ch] (find_pc_psymbol): Created; finds static function + psymbol with value nearest to but under value passed. + * stack.c (print_frame_info): Used above to make sure I have best + fit to pc value. + + * symseg.h (struct partial_symbol): Added value field. + * dbxread.c (read_dbx_symtab): Set value field for partial symbols + saved (so that we can lookup static symbols). + + * symtab.[ch] (find_pc_symtab): Changed to external. + * stack.c (select_frame): Call above to make sure that symbols for + a selected frame is readin. + +Mon Apr 3 12:48:16 1989 Randall Smith (randy at plantaris.ai.mit.edu) + + * stack.c (print_frame_info): Modified to only print out full + stack frame info on symbols whose tables have been read in. + * symtab.c, symtab.h (find_pc_psymtab): Made function external; + above needed it. + + * main.c (,set_verbose_command, initialize_main): Created a + variable "info_verbose" which says to talk it up in various and + sundry places. Added command to set this variable. + * gdb.texinfo (GDB Output): Added documentation on "set verbose" + and changed the name of the "Screen Output" section to "GDB + Output". + * dbxread.c (psymtab_to_symtab): Added information message about + symbol readin. Conditionalized on above. + + * dbxread.c (define_symbol): Made an "i" constant be of class + LOC_CONST and an "r" constant be of class LOC_CONST_BYTES. + + * README: Made a note about modifications which may be necessary + to the manual for this version of gdb. + + * blockframe.c (get_prev_frame_info): Now we get saved address and + check for validity before we check for leafism. This means that + we will catch the fact that we are in start, but we will miss any + fns that start calls without an fp. This should be fine. + + * m-*.h (FRAME_CHAIN): Modified to return 0 if we are in start. + This is usually a test for within the first object file. + * m-sparc.h (FRAME_CHAIN): The test here is simply if the fp saved + off the the start sp is 0. + + * blockframe.c (get_prev_frame_info): Removed check to see if we + were in start. Screws up sparc. + + * m-sparc.h (FRAME_FIND_SAVED_REGISTERS): Changed test for dummy + frame to not need frame to be innermost. + + * gdb.texinfo: Added section on frameless invocations of functions + and when gdb can and can't deal with this. + + * stack.c (frame_info): Disallowed call if no inferior or core + file; fails gracefully if truely bad stack specfication has been + given (ie. parse_frame_specification returns 0). + +Fri Mar 31 13:59:33 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * infrun.c (normal_stop): Changed references to "unset-env" to + "delete env". + + * infcmd.c (_initialize_infcmd): Change reference to set-args in + help run to "set args". + + * remote.c (getpkt): Allow immediate quit when reading from + device; it could be hung. + + * coffread.c (process_coff_symbol): Modify handling of REG + parameter symbols. + +Thu Mar 30 15:27:23 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * dbxread.c (symbol_file_command): Use malloc to allocate the + space for the string table in symbol_file_command (and setup a + cleanup for this). This allows a more graceful error failure if + there isn't any memory availible (and probably allows more memory + to be avail, depending on the machine). + + Additional mods for handling GNU C++ (from Tiemann): + * dbxread.c (read_type): Added case for '#' type (method type, I + believe). + (read_struct_type): If type code is undefined, make the main + variant for the type be itself. Allow recognition of bad format + in reading of structure fields. + * eval.c (evaluate_subexp): Modify evaluation of a member of a + structure and pointer to same to make sure that the syntax is + being used correctly and that the member is being accessed correctly. + * symseg.h: Added TYPE_CODE_METHOD to enum type_code. Add a + pointer to an array of argument types to the type structure. + * symtab.c (lookout_method_type, smash_to_method_type): Created. + * symtab.h (TYPE_ARG_TYPES): Created. + * valops.c (call_function): Modified handling of methods to be the + same as handling of functions; no longer check for members. + * valprint.c (val_print, type_print_varspec_{prefix,suffix}, + type_print_base): Added code to print method args correctly. + * values.c (value_virtual_fn_field): Modify access to virtual + function table. + +Wed Mar 29 13:19:34 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * findvar.c: Special cases for REGISTER_WINDOWS: 1) Return 0 if we + are the innermost frame, and 2) return the next frame in's value + if the SP is being looked for. + + * blockframe.c (get_next_frame): Created; returns the next (inner) + frame of the called frame. + * frame.h: Extern delcaration for above. + + * main.c (command_line_input): Stick null at end before doing + history expansion. + +Tue Mar 28 17:35:50 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * dbxread.c (read_dbx_symtab): Added namestring assignment to + N_DATA/BSS/ABS case. Sigh. + +Sat Mar 25 17:49:07 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * expread.y: Defined YYDEBUG. + +Fri Mar 24 20:46:55 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * symtab.c (make_symbol_completion_list): Completely rewrote to + never call psymtab_to_symtab, to do a correct search (no + duplicates) through the visible symbols, and to include structure + and union fields in the things that it can match. + +Thu Mar 23 15:27:44 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * dbxread.c (dbx_create_type): Created; allocates and inits space + for a type without putting it on the type vector lists. + (dbx_alloc_type): Uses above. + + * Makefile: xgdb.o now produced by default rules for .o.c. + +Fri Mar 17 14:27:50 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * infrun.c: Fixed up inclusion of aouthdr.h on UMAX_PTRACE. + + * Makefile, config.gdb: Added hp300bsd to potential + configurations. + * hp300bsd-dep.c, m-hp300bsd.h: Created. + + * infrun.c (wait_for_inferior): Rewrote to do no access to + inferior until we make sure it's still there. + + * inflow.c (inferior_died): Added a select to force the selected + frame to null when inferior dies. + + * dbxread.c (symbol_file_command): free and zero symfile when + discarding symbols. + + * core.c (xfer_core_file): Extended and cleaned up logic in + interpeting memory address. + + * core.c (xfer_core_file): Extended opening comment. + +Thu Mar 16 15:39:42 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * coffread.c (symbol_file_command): Free symfile name when freeing + contents. + + * blockframe.c (get_prev_frame_info): Added to fatal error message + to indicate that it should never happen. + + * stack.c (frame_info): Printed out value of "saved" sp seperately + to call attention to the fact that it isn't stored in memory + anywhere; the actual previous frames address is printed. + + * m-sparc.h (FRAME_FIND_SAVED_REGS): Set address of sp saved in + frame to value of fp (rather than value of sp in current frame). + + * expread.y: Allow "unsigned" as a type itself, as well as a type + modifier. + + * coffread.c: Added declaration for fclose + +Fri Mar 10 17:22:31 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * main.c (command_line_input): Checked for -1 return from + readline; indicates EOF. + +Fri Mar 3 00:31:27 1989 Randall Smith (randy at gluteus.ai.mit.edu) + + * remote.c (remote_open): Cast return from signal to (void (*)) to + avoid problems on machines where the return type of signal is (int + (*)). + + * Makefile: Removed deletion of version control from it (users + will need it for their changes). + +Thu Mar 2 15:32:21 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * symmetry-dep.c (print_1167_regs): Print out effective doubles on + even number regs. + (fetch_inferior_registers): Get the floating point regs also. + + * xgdb.c (do_command): Copied command before calling execute + command (so that execute_command wouldn't write into text space). + + * copying.awk: Created (will produce copying.c as output when + given COPYING as input). + * Makefile: Used above to create copying.c. + * main.c: Took out info_warranty and info_copying. + + * *.*: Changed copyright notice to use new GNU General Public + License (includes necessary changes to manual). + + * xgdb.c (create_text_widget): Created text_widget before I create + the source and sink. + (print_prompt): Added fflush (stdout). + + * Makefile: Added -lXmu to the compilation line for xgdb. Left + the old one there incase people still had R2. + + * README: Added note about -gg format. + + * remote.c (getpkt): Fixed typo; && ==> &. + + * Makefile: Added new variable READLINE_FLAGS so that I could + force compilation of readline.c and history.c with -DSYSV on + system V machines. Mentioned in Makefile comments at top. + +Wed Mar 1 17:01:01 1989 Randall Smith (randy at gluteus.ai.mit.edu) + + * hp9k320-dep.c (store_inferior_registers): Fixed typo. + +Fri Feb 24 14:58:45 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * hp9k320-dep.c (store_inferior_registers, + fetch_inferior_registers): Added support for remote debugging. + + * remote.c (remote_timer): Created. + (remote_open, readchar): Setup to timeout reads if they take + longer than "timeout". This allows one to debug how long such + things take. + (putpkt): Modified to print a debugging message (if such things + are enabled) each time it resends a packet. + (getpkt): Modified to make the variable CSUM unsigned and read it + CSUM with an & 0xff (presumably to deal with poor sign extension + on some machines). Also made c1 and c2 unsigned. + (remote_wait): Changed buffer to unsigned status. + (remote_store_registers, remote_write_bytes): Puts a null byte at + the end of the control string. + + * infcmd.c (attach_command, detach_command, _initialize_infcmd): + Made attach_command and detach_command always availible, but + modified them to only allow device file attaches if ATTACH_DETACH + is not defined. + + * gdb.texinfo: Added cross reference from attach command to remote + debugging. + +Thu Feb 23 12:37:59 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * remote.c (remote_close): Created to close the remote connection + and set the remote_debugging flag to 0. + * infcmd.c (detach_command): Now calls the above when appropriate. + + * gdb.texinfo: Removed references to the ``Distribution'' section + in the copyright. + + * main.c, utils.c (ISATTY): Created default defintions of this + macro which use isatty and fileno. + * utils.c (fprintf_filtered, print_spaces_filtered), main.c + (command_loop, command_line_input): Used this macro. + * m-news.h: Created a definition to override this one. + + * utils.c (fprintf_filtered): Made line_size static (clueless). + + * utils.c (fprintf_filtered): Changed max length of line printed + to be 255 chars or twice the format length. + + * symmetry-dep.c, m-symmetry: Fixed typo (^L ==> ). + + * printcmd.c (do_examine): Fixed typo (\n ==> \t). + +Wed Feb 22 16:00:33 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + Contributed by Jay Vosburgh (jay@mentor.cc.purdue.edu) + * m-symmetry.h, symmetry-dep.c: Created. + * Makefile: Added above in appropriate lists. + * config.gdb: Added "symmetry" target. + + * utils.c (prompt_for_continue): Zero'd chars_printed also. + + * utils.c (fprintf_filtered): Call prompt for continue instead of + doing it yourself. + + * dbxread.c (read_dbx_symtab): Added code to conditionalize what + symbol type holds to "x.o" or "-lx" symbol that indicates the + beginning of a new file. + +Tue Feb 21 16:22:13 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * gdb.texinfo: Deleted @ignore block at end of file. + + * findvar.c, stack.c: Changed comments that refered to "frame + address" to "frame id". + + * findvar.c (locate_var_value): Modified so that taking the + address of an array generates an object whose type is a pointer to + the elements of the array. + +Sat Feb 18 16:35:14 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * gdb.texinfo: Removed reference to "!" as a shell escape + character. Added a section on controling screen output + (pagination); changing "Input" section to "User Interface" + section. Changed many inappropriate subsubsection nodes into + subsections nodes (in the readline and history expansion + sections). + +Fri Feb 17 11:10:54 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * utils.c (set_screensize_command): Created. + (_initialize_utils): Added above to setlist. + + * main.c (main): Added check to see if ~/.gdbinit and .gdbinit + were the same file; only one gets read if so. Had to include + sys/stat.h for this. + + * valprint.c (type_print_base): Changed calls to print_spaces to + print_spaces_filtered. + + * main.c (command_line_input): Chaned test for command line + editing to check for stdin and isatty. + + * main.c (command_loop): Call reinitialize_more_filter before each + command (if reading from stdin and it's a tty). + utils.c (initialize_more_filter): Changed name to + reinitialize_more_filter; killed arguments. + utils.c (_initialize_utils): Created; initialized lines_per_page + and chars_per_line here. + + * utils.c (fprintf_filtered): Removed printing of "\\\n" after + printing linesize - 1 chars; assume that the screen display will + take care of that. Still watching that overflow. + + * main.c: Created the global variables linesize and pagesize to + describe the number of chars per line and lines per page. + +Thu Feb 16 17:27:43 1989 Randall Smith (randy at gluteus.ai.mit.edu) + + * printcmd.c (do_examine, print_scalar_formatted, print_address, + whatis_command, do_one_display, ptype_command), valprint.c + (value_print, val_print, type_print_method_args, type_print_1, + type_print_derivation_info, type_print_varspec_suffix, + type_print_base), breakpoint.c (breakpoints_info, breakpoint_1), + values.c (history_info), main.c (editing_info, warranty_info, + copying_info), infcmd.c (registers_info), inflow.c + (term_status_command), infrun.c (signals_info), stack.c + (backtrace_command, print_frame_info), symtab.c (list_symbols, + output_source_filename), command.c (help_cmd, help_list, + help_command_list): Replaced calls to printf, fprintf, and putc + with calls to [f]printf_filtered to handle more processing. + Killed local more emulations where I noticed them. + +Wed Feb 15 15:27:36 1989 Randall Smith (randy at gluteus.ai.mit.edu) + + * defs.h, utils.c (initialize_more_filter, fprintf_filtered, + printf_filtered): Created a printf that will also act as a more + filter, prompting the user for a <return> whenever the page length + is overflowed. + + * symtab.c (list_symbols): Elminated some code inside of an #if 0. + +Tue Feb 14 11:11:24 1989 Randall Smith (randy at gluteus.ai.mit.edu) + + * Makefile: Turned off backup versions for this file; it changes + too often. + + * command.c (lookup_cmd, _initialize_command): Changed '!' so that + it was no longer a shell escape. "sh" must be used. + + * main.c (command_line_input, set_history_expansion, + initialize_main): Turned history expansion on, made it the + default, and only execute it if the first character in the line is + a '!'. + + * version.c, gdb.texinfo: Moved version to 3.2 (as usual, jumping + the gun some time before release). + + * gdb.texinfo: Added sections (adapted from Brian's notes) on + command line editing and history expansion. + + * main.c (set_command_editing, initialize_main): Modified name to + set_editing and modified command to "set editing". + + * Makefile: Put in dependencies for READLINEOBJS. + + * main.c (history_info, command_info): Combined into new command + info; deleted history_info. + (initialize_main): Deleted "info history" command; it was + interfering with the value history. + + * coffread.c (enter_linenos): Modified to do bit copy instead of + pointer dereference, since the clipper machine can't handle having + longs on short boundaries. + (read_file_hdr): Added code to get number of syms for clipper. + + * stack.c (return_command): Fixed method for checking when all of + the necessary frames had been popped. + + * dbxread.c (read_dbx_symtab (ADD_PSYMBOL_TO_LIST)): Fixed typo in + allocation length. + +Mon Feb 13 10:03:27 1989 Randall Smith (randy at gluteus.ai.mit.edu) + + * dbxread.c (read_dbx_symtab): Split assignment to namestring into + several different assignments (so that it wouldn't be done except + when it had to be). Shortened switches and duplicated code to + produce the lowest possible execution time. Commented (at top of + switch) which code I duplicated. + + * dbxread.c (read_dbx_symtab): Modified which variables were + register and deleted several variables which weren't used. Also + eliminated 'F' choice from subswitch, broke out strcmp's, reversed + compare on line 1986, and elminated test for !namestring[0]; it is + caught by following test for null index of ':'. + +Sun Feb 12 12:57:56 1989 Randall Smith (randy at plantaris.ai.mit.edu) + + * main.c (gdb_completer_word_break_characters): Turned \~ into ~. + +Sat Feb 11 15:39:06 1989 Randall Smith (randy at plantaris.ai.mit.edu) + + * symtab.c (find_pc_psymtab): Created; checks all psymtab's till + it finds pc. + (find_pc_symtab): Used; fatal error if psymtab found is readin + (should have been caught in symtab loop). + (lookup_symbol): Added check before scan through partial symtab + list for symbol name to be on the misc function vector (only if in + VAR_NAMESPACE). Also made sure that psymtab's weren't fooled with + if they had already been read in. + (list_symbols): Checked through misc_function_vector for matching + names if we were looking for functions. + (make_symbol_completion_list): Checked through + misc_function_vector for matching names. + * dbxread.c (read_dbx_symtab): Don't bother to do processing on + global function types; this will be taken care of by the + misc_function hack. + + * symtab.h: Modified comment on misc_function structure. + +Fri Feb 10 18:09:33 1989 Randall Smith (randy at plantaris.ai.mit.edu) + + * symseg.h, dbxread.c (read_dbx_symtab, init_psymbol_list, + start_psymtab, end_psymtab), coffread.c (_initialize_coff), + symtab.c (lookup_partial_symbol, list_symbols, + make_symbol_completion_list): Changed separate variables for + description of partial symbol allocation into a specific kind of + structure. + + (read_dbx_symtab, process_symbol_for_psymtab): Moved most of + process_symbol_for_psymtab up into read_dbx_symtab, moved a couple + of symbol types down to the ingore section, streamlined (I hope) + code some, modularized access to psymbol lists. + +Thu Feb 9 13:21:19 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * main.c (command_line_input): Made sure that it could recognize + newlines as indications to repeat the last line. + + * symtab.c (_initialize_symtab): Changed size of builtin_type_void + to be 1 for compatibility with gcc. + + * main.c (initialize_main): Made history_expansion the default + when gdb is compiled with HISTORY_EXPANSION. + + * readline.c, readline.h, history.c, history.h, general.h, + emacs_keymap.c, vi_keymap.c, keymaps.c, funmap.c: Made all of + these links to /gp/gnu/bash/* to keep them updated. + * main.c (initialize_main): Made default be command editing on. + +Wed Feb 8 13:32:04 1989 & Smith (randy at hobbes) + + * dbxread.c (read_dbx_symtab): Ignore N_BSLINE on first + readthrough. + + * Makefile: Removed convex-dep.c from list of distribution files. + +Tue Feb 7 14:06:25 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * main.c: Added command lists sethistlist and unsethistlist to + accesible command lists. + (parse_binary_operation): Created to parse a on/1/yes vs. off/0/no + spec. + (set_command_edit, set_history, set_history_expansion, + set_history_write, set_history_size, set_history_filename, + command_info, history_info): Created to allow users to control + various aspects of command line editing. + + * main.c (symbol_creation_function): Created. + (command_line_input, initialize_main): Added rest of stuff + necessary for calling bfox' command editing routines under + run-time control. + * Makefile: Included readline and history source files for command + editing; also made arrangements to make sure that the termcap + library was available. + * symtab.c (make_symbol_completion_list): Created. + +Mon Feb 6 16:25:25 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * main.c: Invented variables to control command editing. + command_editing_p, history_expansion_p, history_size, + write_history_p, history_filename. Initialized them to default + values in initialize_main. + + * infcmd.c (registers_info), infrun.c (signals_info), + * main.c (gdb_read_line): Changed name to command_line_input. + (readline): Changed name to gdb_readline; added second argument + indicating that the read value shouldn't be saved (via malloc). + * infcmd.c (registers_info), infrun.c (signals_info), main.c + (copying_info), symtab.c (output_source_filename, MORE, + list_symbols): Converted to use gdb_readline in place of + gdb_read_line. + + +Sun Feb 5 17:34:38 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * blockframe.c (get_frame_saved_regs): Removed macro expansion + that had accidentally been left in the code. + +Sat Feb 4 17:54:14 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * main.c (gdb_read_line, readline): Added function readline and + converted gdb_read_line to use it. This was a conversion to the + line at a time style of input, in preparation for full command + editing. + +Fri Feb 3 12:39:03 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * dbxread.c (read_dbx_symtab): Call end_psymtab at the end of + read_dbx_symtab if any psymtab still needs to be completed. + + * config.gdb, sun3-dep.c: Brought these into accord with the + actual sun2 status (no floating point period; sun3-dep.c unless + has os > 3.0). + * m-sun2os2.h: Deleted; not needed. + + * config.gdb: Added a couple of aliases for machines in the + script. + + * infrun.c: Added inclusion of aouthdr.h inside of #ifdef UMAX + because ptrace needs to know about the a.out header. + + * Makefile: Made dep.o depend on dep.c and config.status only. + + * expread.y: Added declarations of all of the new write_exp_elt + functions at the include section in the top. + + * Makefile: Added a YACC definition so that people can use bison + if they wish. + + * Makefile: Added rms' XGDB-README to the distribution. + + * Makefile: Added removal of init.o on a "make clean". + +Thu Feb 2 16:27:06 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * *-dep.c: Deleted definition of COFF_FORMAT if AOUTHDR was + defined since 1) We *may* (recent mail message) want to define + AOUTHDR under a basically BSD system, and 2) AOUTHDR is sometimes + a typedef in coff encapsulation setups. Also removed #define's of + AOUTHDR if AOUTHDR is already defined (inside of coff format). + * core.c, dbxread.c: Removed #define's of AOUTHDR if AOUTHDR is + already defined (inside of coff format). + +Tue Jan 31 12:56:01 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * GDB 3.1 released. + + * values.c (modify_field): Changed test for endianness to assign + to integer and reference character (so that all bits would be + defined). + +Mon Jan 30 11:41:21 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * news-dep.c: Deleted inclusion of fcntl.h; just duplicates stuff + found in sys/file.h. + + * i386-dep.c: Included default definition of N_SET_MAGIC for + COFF_FORMAT. + + * config.gdb: Added checks for several different operating + systems. + + * coffread.c (read_struct_type): Put in a flag variable so that + one could tell when you got to the end of a structure. + + * sun3-dep.c (core_file_command): Changed #ifdef based on SUNOS4 + to ifdef based on FPU. + + * infrun.c (restore_inferior_status): Changed error message to + "unable to restore previously selected frame". + + * dbxread.c (read_dbx_symtab): Used intermediate variable in error + message reporting a bad symbol type. (scan_file_globals, + read_ofile_symtab, read_addl_syms): Data type of "type" changed to + unsigned char (which is what it is). + * i386-dep.c: Removed define of COFF_FORMAT if AOUTHDR is defined. + Removed define of a_magic to magic (taken care of by N_MAGIC). + (core_file_command): Zero'd core_aouthdr instead of setting magic + to zero. + * i386-pinsn.c: Changed jcxz == jCcxz in jump table. + (putop): Added a case for 'C'. + (OP_J): Added code to handle possible masking of PC value on + certain kinds of data. + m-i386gas.h: Moved COFF_ENCAPSULATE to before inclusion of + m-i386.h and defined NAMES_HAVE_UNDERSCORE. + + * coffread.c (unrecrod_misc_function, read_coff_symtab): Added + symbol number on which error occured to error output. + +Fri Jan 27 11:55:04 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * Makefile: Removed init.c in make clean. Removed it without -f + and with leading - in make ?gdb. + +Thu Jan 26 15:08:03 1989 Randall Smith (randy at gluteus.ai.mit.edu) + + Changes to get it to work on gould NP1. + * dbxread.c (read_dbx_symtab): Included cases for N_NBDATA and + N_NBBSS. + (psymtab_to_symtab): Changed declaration of hdr to + DECLARE_FILE_HEADERS. Changed access to use STRING_TABLE_SIZE and + SYMBOL_TABLE_SIZE. + * gld-pinsn.c (findframe): Added declaration of framechain() as + FRAME_ADDR. + + * coffread.c (read_coff_symtab): Avoided treating typedefs as + external symbol definitions. + +Wed Jan 25 14:45:43 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * Makefile: Removed reference to alloca.c. If they need it, they + can pull alloca.o from the gnu-emacs directory. + + * version.c, gdb.texinfo: Updated version to 3.1 (jumping the gun + a bit so that I won't forget when I release). + + * m-sun2.h, m-sun2os2.h, m-sun3os4.h, config.gdb: Modified code so + that default includes new sun core, ptrace, and attach-detach. + Added defaults for sun 2 os 2. + + Modifications to reset stack limit back to what it used to be just + before exec. All mods inside of #ifdef SET_STACK_LIMIT_HUGE. + * main.c: Added global variable original_stack_limit. + (main): Set original_stack_limit to original stack limit. + * inflow.c: Added inclusion of necessary files and external + reference to original_stack_limit. + (create_inferior): Reset stack limit to original_stack_limit. + + * dbxread.c (read_dbx_symtab): Killed PROFILE_SYMBOLS ifdef. + + * sparc-dep.c (isabranch): Multiplied offset by 4 before adding it + to addr to get target. + + * Makefile: Added definition of SHELL to Makefile. + + * m-sun2os4.h: Added code to define NEW_SUN_PTRACE, NEW_SUN_CORE, + and ATTACH_DETACH. + * sun3-dep.c: Added code to avoid fp regs if we are on a sun2. + +Tue Jan 24 17:59:14 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * dbxread.c (read_array_type): Added function. + (read_type): Added call to above instead of inline code. + + * Makefile: Added ${GNU_MALLOC} to the list of dependencies for + the executables. + +Mon Jan 23 15:08:51 1989 Randall Smith (randy at plantaris.ai.mit.edu) + + * gdb.texinfo: Added paragraph to summary describing languages + with which gdb can be run. Also added descriptions of the + "info-methods" and "add-file" commands. + + * symseg.h: Commented a range type as having TYPE_TARGET_TYPE + pointing at the containing type for the range (often int). + * dbxread.c (read_range_type): Added code to do actual range types + if they are defined. Assumed that the length of a range type is + the length of the target type; this is a lie, but will do until + somebody gets back to me as to what these silly dbx symbols mean. + + * dbxread.c (read_range_type): Added code to be more picky about + recognizing builtins as range types, to treat types defined as + subranges of themselves to be subranges of int, and to recognize + the char type idiom from dbx as a special case. + +Sun Jan 22 01:00:13 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * m-vax.h: Removed definition of FUNCTION_HAS_FRAME_POINTER. + * blockframe.c (get_prev_frame_info): Removed default definition + and use of above. Instead conditionalized checking for leaf nodes + on FUNCTION_START_OFFSET (see comment in code). + +Sat Jan 21 16:59:19 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * dbxread.c (read_range_type): Fixed assumption that integer was + always type 1. + + * gdb.texinfo: Fixed spelling mistake and added a note in the + running section making it clear that users may invoke subroutines + directly from gdb. + + * blockframe.c: Setup a default definition for the macro + FUNCTION_HAS_FRAME_POINTER. + (get_prev_frame_info): Used this macro instead of checking + SKIP_PROLOGUE directly. + * m-vax.h: Overroad definition; all functions on the vax have + frame pointers. + +Fri Jan 20 12:25:35 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * core.c: Added default definition of N_MAGIC for COFF_FORMAT. + + * xgdb.c: Installed a fix to keep the thing from dying when there + isn't any frame selected. + + * core.c: Made a change for the UMAX system; needs a different + file included if using that core format. + + * Makefile: Deleted duplicate obstack.h in dbxread.c dependency. + + * munch: Modified (much simpler) to cover (I hope) all cases. + + * utils.c (save_cleanups, restore_cleanups): Added functions to + allow you to push and pop the chain of cleanups to be done. + * defs.h: Declared the new functions. + * main.c (catch_errors): Made sure that the only cleanups which + would be done were the ones put on the chain *after* the current + location. + + * m-*.h (FRAME_CHAIN_VALID): Removed check on pc in the current + frame being valid. + * blockframe.c (get_prev_frame_info): Made the assumption that if + a frame's pc value was within the first object file (presumed to + be /lib/crt0.o), that we shouldn't go any higher. + + * infrun.c (wait_for_inferior): Do *not* execute check for stop pc + at step_resume_break if we are proceeding over a breakpoint (ie. + if trap_expected != 0). + + * Makefile: Added -g to LDFLAGS. + + * m-news.h (POP_FRAME) Fixed typo. + + * printcmd.c (print_frame_args): Modified to print out register + params in order by .stabs entry, not by register number. + + * sparc-opcode.h: Changed declaration of (struct + arith_imm_fmt).simm to be signed (as per architecture manual). + * sparc-pinsn.c (fprint_addr1, print_insn): Forced a cast to an + int, so that we really would get signed behaivior (default for sun + cc is unsigned). + + * i386-dep.c (i386_get_frame_setup): Replace function with new + function provided by pace to fix bug in recognizing prologue. + +Thu Jan 19 11:01:22 1989 Randall Smith (randy at plantaris.ai.mit.edu) + + * infcmd.c (run_command): Changed error message to "Program not + restarted." + + * value.h: Changed "frame" field in value structure to be a + FRAME_ADDR (actually CORE_ADDR) so that it could survive across + calls. + + * m-sun.h (FRAME_FIND_SAVED_REGS): Fixed a typo. + + * value.h: Added lval: "lval_reg_frame_relative" to indicate a + register that must be interpeted relative to a frame. Added + single entry to value structure: "frame", used to indicate which + frame a relative regnum is relative to. + * findvar.c (value_from_register): Modified to correctly setup + these fields when needed. Deleted section to fiddle with last + register copied on little endian machine; multi register + structures will always occupy an integral number of registers. + (find_saved_register): Made extern. + * values.c (allocate_value, allocate_repeat_value): Zero frame + field on creation. + * valops.c (value_assign): Added case for lval_reg_frame_relative; + copy value out, modify it, and copy it back. Desclared + find_saved_register as being external. + * value.h: Removed addition of kludgy structure; thoroughly + commented file. + * values.c (free_value, free_all_values, clear_value_history, + set_internalvar, clear_internavars): Killed free_value. + +Wed Jan 18 20:09:39 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * value.h: Deleted struct partial_storage; left over from + yesterday. + + * findvar.c (value_from_register): Added code to create a value of + type lval_reg_partsaved if a value is in seperate registers and + saved in different places. + +Tue Jan 17 13:50:18 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * value.h: Added lval_reg_partsaved to enum lval_type and + commented enum lval_type. Commented value structure. + Added "struct partial_register_saved" to value struct; added + macros to deal with structure to value.h. + * values.c (free_value): Created; special cases lval_reg_partsaved + (which has a pointer to an array which also needs to be free). + (free_all_values, clear_value_history, set_internalvar, + clear_internalvars): Modified to use free_values. + + * m-sunos4.h: Changed name to sun3os4.h. + * m-sun2os4.h, m-sun4os4.h: Created. + * config.gdb: Added configuration entries for each of the above. + * Makefile: Added into correct lists. + + * Makefile: Added dependencies on a.out.encap.h. Made + a.out.encap.h dependent on a.out.gnu.h and dbxread.c dependent on + stab.gnu.h. + + * infrun.c, remote.c: Removed inclusion of any a.out.h files in + these files; they aren't needed. + + * README: Added comment about bug reporting and comment about + xgdb. + + * Makefile: Added note to HPUX dependent section warning about + problems if compiled with gcc and mentioning the need to add + -Ihp-include to CFLAGS if you compile on those systems. Added a + note about needing the GNU nm with compilers *of gdb* that use the + coff encapsulate feature also. * hp-include: Made symbolic link + over to /gp/gnu/binutils. + + * Makefile: Added TSOBS NTSOBS OBSTACK and REGEX to list of things + to delete in "make clean". Also changed "squeakyclean" target as + "realclean". + + * findvar.c (value_from_register): Added assignment of VALUE_LVAL + to be lval_memory when that is appropriate (original code didn't + bother because it assumed that it was working with a pre lval + memoried value). + + * expread.y (yylex): Changed to only return type THIS if the + symbol "$this" is defined in some block superior or equal to the + current expression context block. + +Mon Jan 16 13:56:44 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * m-*.h (FRAME_CHAIN_VALID): On machines which check the relation + of FRAME_SAVED_PC (thisframe) to first_object_file_end (all except + gould), make sure that the pc of the current frame also passes (in + case someone stops in _start). + + * findvar.c (value_of_register): Changed error message in case of + no inferior or core file. + + * infcmd.c (registers_info): Added a check for inferior or core + file; error message if not. + + * main.c (gdb_read_line): Modified to take prompt as argument and + output it to stdout. + * infcmd.c (registers_info, signals_info), main.c (command_loop, + read_command_lines, copying_info), symtab.c (decode_line_2, + output_source_filename, MORE, list_symbols): Changed calling + convention used to call gdb_read_line. + + * infcmd.c, infrun.c, main.c, symtab.c: Changed the name of the + function "read_line" to "gdb_read_line". + * breakpoint.c: Deleted external referenced to function + "read_line" (not needed by code). + +Fri Jan 13 12:22:05 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * i386-dep.c: Include a.out.encap.h if COFF_ENCAPSULATE. + (N_SET_MAGIC): Defined if not defined by include file. + (core_file_command): Used N_SET_MAGIC instead of assignment to + a_magic. + (exec_file_command): Stuck in a HEADER_SEEK_FD. + + * config.gdb: Added i386-dep.c as depfile for i386gas choice. + + * munch: Added -I. to cc to pick up things included by the param + file. + + * stab.gnu.def: Changed name to stab.def (stab.gnu.h needs this name). + * Makefile: Changed name here also. + * dbxread.c: Changed name of gnu-stab.h to stab.gnu.h. + + * gnu-stab.h: Changed name to stab.gnu.h. + * stab.gnu.def: Added as link to binutils. + * Makefile: Put both in in the distribution. + +Thu Jan 12 11:33:49 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * dbxread.c: Made which stab.h is included dependent on + COFF_ENCAPSULATE; either <stab.h> or "gnu-stab.h". + * Makefile: Included gnu-stab.h in the list of files to include in + the distribution. + * gnu-stab.h: Made a link to /gp/gnu/binutils/stab.h + + * Makefile: Included a.out.gnu.h and m-i386gas.h in list of + distribution files. + * m-i386gas.h: Changed to include m-i386.h and fiddle with it + instead of being a whole new file. + * a.out.gnu.h: Made a link to /gp/gnu/binutils/a.out.gnu.h. + + Chris Hanson's changes to gdb for hp Unix. + * Makefile: Modified comments on hpux. + * hp9k320-dep.c: #define'd WOPR & moved inclusion of signal.h + * inflow.c: Moved around declaratiosn of <sys/fcntl.h> and + <sys/ioctl.h> inside of USG depends and deleted all SYSV ifdef's + (use USG instead). + * munch: Modified to accept any number of spaces between the T and + the symbol name. + + Pace's changes to gdb to work with COFF_ENCAPSULATE (robotussin): + * config.gdb: Added i386gas to targets. + * default-dep.c: Include a.out.encap.h if COFF_ENCAPSULATE. + (N_SET_MAGIC): Defined if not defined by include file. + (core_file_command): Used N_SET_MAGIC instead of assignment to a_magic. + (exec_file_command): Stuck in a HEADER_SEEK_FD. + * infrun.c, remote.c: Added an include of a.out.encap.h if + COFF_ENCAPSULATE defined. This is commented out in these two + files, I presume because the definitions aren't used. + * m-i386gas.h: Created. + * dbxread.c: Included defintions for USG. + (READ_FILE_HEADERS): Now uses HEADER_SEEK_FD if it exists. + (symbol_file_command): Deleted use of HEADER_SEEK_FD. + * core.c: Deleted extra definition of COFF_FORMAT. + (N_MAGIC): Defined to be a_magic if not already defined. + (validate_files): USed N_MAGIC instead of reading a_magic. + +Wed Jan 11 12:51:00 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * remote.c: Upped PBUFSIZ. + (getpkt): Added zeroing of c inside loop in case of error retry. + + * dbxread.c (read_dbx_symtab, process_symbol_for_psymtab): Removed + code to not put stuff with debugging symbols in the misc function + list. Had been ifdef'd out. + + * gdb.texinfo: Added the fact that the return value for a function + is printed if you use return. + + * infrun.c (wait_for_inferior): Removed test in "Have we hit + step_resume_breakpoint" for sp values in proper orientation. Was + in there for recursive calls in functions without frame pointers + and it was screwing up calls to alloca. + + * dbxread.c: Added #ifdef COFF_ENCAPSULATE to include + a.out.encap.h. + (symbol_file_command): Do HEADER_SEEK_FD when defined. + * dbxread.c, core.c: Deleted #ifdef ROBOTUSSIN stuff. + * robotussin.h: Deleted local copy (was symlink). + * a.out.encap.h: Created symlink to + /gp/gnu/binutils/a.out.encap.h. + * Makefile: Removed robotussin.h and included a.out.encap.h in + list of files. + + * valprint.c (val_print, print_scalar_formatted): Changed default + precision of printing float value; now 6 for a float and 16 for a + double. + + * findvar.c (value_from_register): Added code to deal with the + case where a value is spread over several registers. Still don't + deal with the case when some registers are saved in memory and + some aren't. + +Tue Jan 10 17:04:04 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * xgdb.c (xgdb_create_window): Removed third arg (XtDepth) to + frameArgs. + + * infrun.c (handle_command): Error if signal number is less or + equal to 0 or greater or equal to NSIG or a signal number is not + provided. + + * command.c (lookup_cmd): Modified to not convert command section + of command line to lower case in place (in case it isn't a + subcommand, but an argument to a command). + +Fri Jan 6 17:57:34 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * dbxread.c: Changed "text area" to "data area" in comments on + N_SETV. + +Wed Jan 4 12:29:54 1989 Randall Smith (randy at gluteus.ai.mit.edu) + + * dbxread.c: Added definitions of gnu symbol types after inclusion + of a.out.h and stab.h. + +Mon Jan 2 20:38:31 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * eval.c (evaluate_subexp): Binary logical operations needed to + know type to determine whether second value should be evaluated. + Modified to discover type before binup_user_defined_p branch. + Also commented "enum noside". + + * Makefile: Changed invocations of munch to be "./munch". + + * gdb.texinfo: Updated to refer to current version of gdb with + January 1989 last update. + + * coffread.c (end_symtab): Zero context stack when finishing + lexical contexts. + (read_coff_symtab): error if context stack 0 in ".ef" else case. + + * m-*.h (FRAME_SAVED_PC): Changed name of argument from "frame" to + "FRAME" to avoid problems with replacement of "->frame" part of + macro. + + * i386-dep.c (i386_get_frame_setup): Added codestream_get() to + move codestream pointer up to the correct location in "subl $X, + %esp" case. + +Sun Jan 1 14:24:35 1989 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * valprint.c (val_print): Rewrote routine to print string pointed + to by char pointer; was producing incorrect results when print_max + was 0. + +Fri Dec 30 12:13:35 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * dbxread.c (read_dbx_symtab, process_symbol_for_psymtab): Put + everything on the misc function list. + + * Checkpointed distribution. + + * Makefile: Added expread.tab.c to the list of things slated for + distribution. + +Thu Dec 29 10:06:41 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * stack.c (set_backtrace_limit_command, backtrace_limit_info, + bactrace_command, _initialize_stack): Removed modifications for + limit on backtrace. Piping the backtrace through an interuptable + "more" emulation is a better way to do it. + +Wed Dec 28 11:43:09 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * stack.c + (set_backtrace_limit_command): Added command to set a limit to the + number of frames for a backtrace to print by default. + (backtrace_limit_info): To print the current limit. + (backtrace_command): To use the limit. + (_initialize_stack): To initialize the limit to its default value + (30), and add the set and info commands onto the appropriate + command lists. + + * gdb.texinfo: Documented changes to "backtrace" and "commands" + commands. + + * stack.c (backtrace_command): Altered so that a negative argument + would show the last few frames on the stack instead of the first + few. + (_initialize_stack): Modified help documentation. + + * breakpoint.c (commands_command): Altered so that "commands" with + no argument would refer to the last breakpoint set. + (_initialize_breakpoint): Modified help documentation. + + * infrun.c (wait_for_inferior): Removed ifdef on Sun4; now you can + single step through compiler generated sub calls and will die if + you next off of the end of a function. + + * sparc-dep.c (single_step): Fixed typo; "break_insn" ==> "sizeof + break_insn". + + * m-sparc.h (INIT_EXTRA_FRAME_INFO): Set the bottom of a stack + frame to be the bottom of the stack frame inner from this, if that + inner one is a leaf node. + + * dbxread.c (read_dbx_symtab): Check to make sure we don't add a + psymtab to it's own dependency list. + + * dbxread.c (read_dbx_symtab): Modified check for duplicate + dependencies to catch them correctly. + +Tue Dec 27 17:02:09 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * m-*.h (FRAME_SAVED_PC): Modified macro to take frame info + pointer as argument. + * stack.c (frame_info), blockframe.c (get_prev_frame_info), + gld-pinsn.c (findframe), m-*.h (SAVED_PC_AFTER_CALL, + FRAME_CHAIN_VALID, FRAME_NUM_ARGS): Changed usage of macros to + conform to above. + * m-sparc.h (FRAME_SAVED_PC), sparc-dep.c (frame_saved_pc): + Changed frame_saved_pc to have a frame info pointer as an + argument. + + * m-vax.h, m-umax.h, m-npl.h, infrun.c (wait_for_inferior), + blockframe.c (get_prev_frame_info): Modified SAVED_PC_AFTER_CALL + to take a frame info pointer as an argument. + + * blockframe.c (get_prev_frame_info): Altered the use of the + macros FRAME_CHAIN, FRAME_CHAIN_VALID, and FRAME_CHAIN_COMBINE to + use frame info pointers as arguments instead of frame addresses. + * m-vax.h, m-umax.h, m-sun3.h, m-sun3.h, m-sparc.h, m-pn.h, + m-npl.h, m-news.h, m-merlin.h, m-isi.h, m-hp9k320.h, m-i386.h: + Modified definitions of the above macros to suit. + * m-pn.h, m-npl.h, gould-dep.c (findframe): Modified findframe to + use a frame info argument; also fixed internals (wouldn't work + before). + + * m-sparc.h: Cosmetic changes; reordered some macros and made sure + that nothing went over 80 lines. + +Thu Dec 22 11:49:15 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * Version 3.0 released. + + * README: Deleted note about changing -lobstack to obstack.o. + +Wed Dec 21 11:12:47 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * m-vax.h (SKIP_PROLOGUE): Now recognizes gcc prologue also. + + * blockframe.c (get_prev_frame_info): Added FUNCTION_START_OFFSET + to result of get_pc_function_start. + * infrun.c (wait_for_inferior): Same. + + * gdb.texinfo: Documented new "step" and "next" behavior in + functions without line number information. + +Tue Dec 20 18:00:45 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * infcmd.c (step_1): Changed behavior of "step" or "next" in a + function witout line number information. It now sets the step + range around the function (to single step out of it) using the + misc function vector, warns the user, and continues. + + * symtab.c (find_pc_line): Zero "end" subsection of returned + symtab_and_line if no symtab found. + +Mon Dec 19 17:44:35 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * i386-pinsn.c (OP_REG): Added code from pace to streamline + disassembly and corrected types. + * i386-dep.c + (i386_follow_jump): Code added to follow byte and word offset + branches. + (i386_get_frame_setup): Expanded to deal with more wide ranging + function prologue. + (i386_frame_find_saved_regs, i386_skip_prologue): Changed to use + i386_get_frame_setup. + + +Sun Dec 18 11:15:03 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * m-sparc.h: Deleted definition of SUN4_COMPILER_BUG; was designed + to avoid something that I consider a bug in our code, not theirs, + and which I fixed earlier. Also deleted definition of + CANNOT_USE_ARBITRARY_FRAME; no longer used anywhere. + FRAME_SPECIFICATION_DYADIC used instead. + + * infrun.c (wait_for_inferior): On the sun 4, if a function + doesn't have a prologue, a next over it single steps into it. + This gets around the problem of a "call .stret4" at the end of + functions returning structures. + * m-sparc.h: Defined SUN4_COMPILER_FEATURE. + + * main.c (copying_info): Seperated the last printf into two + printfs. The 386 compiler will now handle it. + + * i386-pinsn.c, i386-dep.c: Moved print_387_control_word, + print_387_status_word, print_387_status, and i386_float_info to + dep.c Also included reg.h in dep.c. + +Sat Dec 17 15:31:38 1988 Randall Smith (randy at gluteus.ai.mit.edu) + + * main.c (source_command): Don't close instream if it's null + (indicating execution of a user-defined command). + (execute_command): Set instream to null before executing + commands and setup clean stuff to put it back on error. + + * inflow.c (terminal_inferior): Went back to not checking the + ioctl returns; there are some systems when this will simply fail. + It seems that, on most of these systems, nothing bad will happen + by that failure. + + * values.c (value_static_field): Fixed dereferencing of null + pointer. + + * i386-dep.c (i386_follow_jump): Modified to deal with + unconditional byte offsets also. + + * dbxread.c (read_type): Fixed typo in function type case of switch. + + * infcmd.c (run_command): Does not prompt to restart if command is + not from a tty. + +Fri Dec 16 15:21:58 1988 Randy Smith (randy at calvin) + + * gdb.texinfo: Added a third option under the "Cannot Insert + Breakpoints" workarounds. + + * printcmd.c (display_command): Don't do the display unless there + is an active inferior; only set it. + + * findvar.c (value_of_register): Added an error check for calling + this when the inferior isn't active and a core file isn't being + read. + + * config.gdb: Added reminder about modifying REGEX in the + makefile for the 386. + + * i386-pinsn.c, i386-dep.c: Moved m-i386.h helper functions over + to i386-dep.c.b + +Thu Dec 15 14:04:25 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * README: Added a couple of notes about compiling gdb with itself. + + * breakpoint.c (set_momentary_breakpoint): Only takes FRAME_FP of + frame if frame is non-zero. + + * printcmd.c (print_scalar_formatted): Implemented /g size for + hexadecimal format on machines without an 8 byte integer type. It + seems to be non-trivial to implement /g for other formats. + (decode_format): Allowed hexadecimal format to make it through /g + fileter. + +Wed Dec 14 13:27:04 1988 Randall Smith (randy at gluteus.ai.mit.edu) + + * expread.y: Converted all calls to write_exp_elt from the parser + to calls to one of write_exp_elt_{opcode, sym, longcst, dblcst, + char, type, intern}. Created all of these routines. This gets + around possible problems in passing one of these things in one ear + and getting something different out the other. Eliminated + SUN4_COMPILER_BUG ifdef's; they are now superfluous. + + * symmisc.c (free_all_psymtabs): Reinited partial_symtab_list to 0. + (_initialize_symmisc): Initialized both symtab_list and + partial_symtab_list. + + * dbxread.c (start_psymtab): Didn't allocate anything on + dependency list. + (end_psymtab): Allocate dependency list on psymbol obstack from + local list. + (add_psymtab_dependency): Deleted. + (read_dbx_symtab): Put dependency on local list if it isn't on it + already. + + * symtab.c: Added definition of psymbol_obstack. + * symtab.h: Added declaration of psymbol_obstack. + * symmisc.c (free_all_psymtabs): Added freeing and + reinitionaliztion of psymbol_obstack. + * dbxread.c (free_all_psymbols): Deleted. + (start_psymtab, end_psymtab, + process_symbol_for_psymtab): Changed most allocation + of partial symbol stuff to be off of psymbol_obstack. + + * symmisc.c (free_psymtab, free_all_psymtabs): Deleted + free_psymtab subroutine. + + * symtab.h: Removed num_includes and includes from partial_symtab + structure; no longer needed now that all include files have their + own psymtab. + * dbxread.c (start_psymtab): Eliminated initialization of above. + (end_psymtab): Eliminated finalization of above; get + includes from seperate list. + (read_dbx_symtab): Moved includes from psymtab list to + their own list; included in call to end_psymtab. + * symmisc.c (free_psymtab): Don't free includes. + +Tue Dec 13 14:48:14 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * i386-pinsn.c: Reformatted entire file to correspond to gnu + software indentation conventions. + + * sparc-dep.c (skip_prologue): Added capability of recognizign + stores of input register parameters into stack slots. + + * sparc-dep.c: Added an include of sparc-opcode.h. + * sparc-pinsn.c, sparc-opcode.h: Moved insn_fmt structures and + unions from pinsn.c to opcode.h. + * sparc-pinsn.c, sparc-dep.c (isabranch, skip_prologue): Moved + this function from pinsn.c to dep.c. + + * Makefile: Put in warnings about compiling with gcc (non-ansi + include files) and compiling with shared libs on Sunos 4.0 (can't + debug something that's been compiled that way). + + * sparc-pinsn.c: Put in a completely new file (provided by + Tiemann) to handle floating point disassembly, load and store + instructions, and etc. better. Made the modifications this file + (ChangeLog) list for sparc-pinsn.c again. + + * symtab.c (output_source_filename): Included "more" emulation hack. + + * symtab.c (output_source_filename): Initialized COLUMN to 0. + (sources_info): Modified to not print out a line for + all of the include files within a partial symtab (since + they have pst's of their own now). Also modified to + make a distinction between those pst's read in and + those not. + + * infrun.c: Included void declaration of single_step() if it's + going to be used. + * sparc-dep.c (single_step): Moved function previous to use of it. + + * Makefile: Took removal of expread.tab.c out of make clean entry + and put it into a new "squeakyclean" entry. + +Mon Dec 12 13:21:02 1988 Randall Smith (randy at gluteus.ai.mit.edu) + + * sparc-pinsn.c (skip_prologue): Changed a struct insn_fmt to a + union insn_fmt. + + * inflow.c (terminal_inferior): Checked *all* return codes from + ioctl's and fcntl's in routine. + + * inflow.c (terminal_inferior): Added check for sucess of + TIOCSPGRP ioctl call. Just notifies if bad. + + * dbxread.c (symbol_file_command): Close was getting called twice; + once directly and once through cleanup. Killed the direct call. + +Sun Dec 11 19:40:40 1988 & Smith (randy at hobbes.ai.mit.edu) + + * valprint.c (val_print): Deleted spurious printing of "=" from + TYPE_CODE_REF case. + +Sat Dec 10 16:41:07 1988 Randall Smith (randy at gluteus.ai.mit.edu) + + * dbxread.c: Changed allocation of psymbols from using malloc and + realloc to using obstacks. This means they aren't realloc'd out + from under the pointers to them. + +Fri Dec 9 10:33:24 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * sparc-dep.c inflow.c core.c expread.y command.c infrun.c + infcmd.c dbxread.c symmisc.c symtab.c printcmd.c valprint.c + values.c source.c stack.c findvar.c breakpoint.c blockframe.c + main.c: Various cleanups inspired by "gcc -Wall" (without checking + for implicit declarations). + + * Makefile: Cleaned up some more. + + * valops.c, m-*.h (FIX_CALL_DUMMY): Modified to take 5 arguments + as per what sparc needs (programming for a superset of needed + args). + + * dbxread.c (process_symbol_for_psymtab): Modified to be slightly + more picky about what it puts on the list of things *not* to be + put on the misc function list. When/if I shift everything over to + being placed on the misc_function_list, this will go away. + + * inferior.h, infrun.c: Added fields to save in inferior_status + structure. + + * maketarfile: Deleted; functionality is in Makefile now. + + * infrun.c (wait_for_inferior): Modified algorithm for determining + whether or not a single-step was through a subroutine call. See + comments at top of file. + + * dbxread.c (read_dbx_symtab): Made sure that the IGNORE_SYMBOL + macro would be checked during initial readin. + + * dbxread.c (read_ofile_symtab): Added macro GCC_COMPILED_FLAG_SYMBOL + into dbxread.c to indicate what string in a local text symbol will + indicate a file compiled with gcc. Defaults to "gcc_compiled.". + +Thu Dec 8 11:46:22 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * m-sparc.h (FRAME_FIND_SAVED_REGS): Cleaned up a little to take + advantage of the new frame cache system. + + * inferior.h, infrun.c, valops.c, valops.c, infcmd.c: Changed + mechanism to save inferior status over calls to inferior (eg. + call_function); implemented save_inferior_info and + restore_inferior_info. + + * blockframe.c (get_prev_frame): Simplified this by a direct call + to get_prev_frame_info. + + * frame.h, stack.c, printcmd.c, m-sparc.h, sparc-dep.c: Removed + all uses of frame_id_from_addr. There are short routines like it + still in frame_saved_pc (m-sparc.h) and parse_frame_spec + (stack.c). Eventually the one in frame_saved_pc will go away. + + * infcmd.c, sparc-dep.c: Implemented a new mechanism for + re-selecting the selected frame on return from a call. + + * blockframe.c, stack.c, findvar.c, printcmd.c, m-*.h: Changed + all routines and macros that took a "struct frame_info" as an + argument to take a "struct frame_info *". Routines: findarg, + framechain, print_frame_args, FRAME_ARGS_ADDRESS, + FRAME_STRUCT_ARGS_ADDRESS, FRAME_LOCALS_ADDRESS, FRAME_NUM_ARGS, + FRAME_FIND_SAVED_REGS. + + * frame.h, stack.c, printcmd.c, infcmd.c, findvar.c, breakpoint.c, + blockframe.c, xgdb.c, i386-pinsn.c, gld-pinsn.c, m-umax.h, + m-sun2.h, m-sun3.h, m-sparc.h, m-pn.h, m-npl.h, m-news.h, + m-merlin.h, m-isi.h, m-i386.h, m-hp9k320.h: Changed routines to + use "struct frame_info *" internally. + +Wed Dec 7 12:07:54 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * frame.h, blockframe.c, m-sparc.h, sparc-dep.c: Changed all calls + to get_[prev_]frame_cache_item to get_[prev_]frame_info. + + * blockframe.c: Elminated get_frame_cache_item and + get_prev_frame_cache_item; functionality now taken care of by + get_frame_info and get_prev_frame_info. + + * blockframe.c: Put allocation on an obstack and eliminated fancy + reallocation routines, several variables, and various nasty + things. + + * frame.h, stack.c, infrun.c, blockframe.c, sparc-dep.c: Changed + type FRAME to be a typedef to "struct frame_info *". Had to also + change routines that returned frame id's to return the pointer + instead of the cache index. + + * infcmd.c (finish_command): Used proper method of getting from + function symbol to start of function. Was treating a symbol as a + value. + + * blockframe.c, breakpoint.c, findvar.c, infcmd.c, stack.c, + xgdb.c, i386-pinsn.c, frame.h, m-hp9k320.h, m-i386.h, m-isi.h, + m-merlin.h, m-news.h, m-npl.h, m-pn.h, m-sparc.h, m-sun2.h, + m-sun3.h, m-umax.h: Changed get_frame_info and get_prev_frame_info + to return pointers instead of structures. + + * blockframe.c (get_pc_function_start): Modified to go to misc + function table instead of bombing if pc was in a block without a + containing function. + + * coffread.c: Dup'd descriptor passed to read_coff_symtab and + fdopen'd it so that there wouldn't be multiple closes on the same + fd. Also put (fclose, stream) on the cleanup list. + + * printcmd.c, stack.c: Changed print_frame_args to take a + frame_info struct as argument instead of the address of the args + to the frame. + + * m-i386.h (STORE_STRUCT_RETURN): Decremented sp by sizeof object + to store (an address) rather than 1. + + * dbxread.c (read_dbx_symtab): Set first_object_file_end in + read_dbx_symtab (oops). + + * coffread.c (fill_in_vptr_fieldno): Rewrote TYPE_BASECLASS as + necessary. + +Tue Dec 6 13:03:43 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * coffread.c: Added fake support for partial_symtabs to allow + compilation and execution without there use. + * inflow.c: Added a couple of minor USG mods. + * munch: Put in appropriate conditionals so that it would work on + USG systems. + * Makefile: Made regex.* handled same as obstack.*; made sure tar + file included everything I wanted it to include (including + malloc.c). + + * dbxread.c (end_psymtab): Create an entry in the + partial_symtab_list for each subfile of the .o file just read in. + This allows a "list expread.y:10" to work when we haven't read in + expread.o's symbol stuff yet. + + * symtab.h, dbxread.c (psymtab_to_symtab): Recognize pst->ldsymlen + == 0 as indicating a dummy psymtab, only in existence to cause the + dependency list to be read in. + + * dbxread.c (sort_symtab_syms): Elminated reversal of symbols to + make sure that register debug symbol decls always come before + parameter symbols. After mod below, this is not needed. + + * symtab.c (lookup_block_symbol): Take parameter type symbols + (LOC_ARG or LOC_REGPARM) after any other symbols which match. + + * dbxread.c (read_type): When defining a type in terms of some + other type and the other type is supposed to have a pointer back + to this specific kind of type (pointer, reference, or function), + check to see if *that* type has been created yet. If it has, use + it and fill in the appropriate slot with a pointer to it. + +Mon Dec 5 11:25:04 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * symmisc.c: Eliminated existence of free_inclink_symtabs and + init_free_inclink_symtabs; they aren't called from anywhere, and + if they were they could disrupt gdb's data structure badly + (elimination of struct type's which values that stick around past + elimination of inclink symtabs). + + * dbxread.c (symbol_file_command): Fixed a return pathway out of + the routine to do_cleanups before it left. + + * infcmd.c (set_environment_command), gdb.texinfo: Added + capability to set environmental variable values to null. + + * gdb.texinfo: Modified doc on "break" without args slightly. + +Sun Dec 4 17:03:16 1988 Randall Smith (randy at gluteus.ai.mit.edu) + + * dbxread.c (symbol_file_command): Added check; if there weren't + any debugging symbols in the file just read, the user is warned. + + * infcmd.c: Commented set_environment_command (a little). + + * createtags: Cleaned up and commented. + + * Makefile: Updated depen_memory and write_inferior_memory in that errno is + checked after each ptrace and returned to the caller. Used in + value_at to detect references to addresses which are out of + bounds. Also core.c (xfer_core_file): return 1 if invalid + address, 0 otherwise. + + * inflow.c, <machine>-infdep.c: removed all calls to ptrace from + inflo, m-sun3.h: Cleaned up dealings with + functions returning structu0 19:19:36 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu) + + * symmisc.c: (read_symsegs) Accept only format number 2. Since + the size of the type structure changed when C++ support was added, + format 1 can no longer be used. + + * core.c, m-sunos4.h: (core_file_command) support for SunOS 4.0. + Slight change in the core structure. #ifdef SUNOS4. New file + m-sunos4.h. May want to change config.gdb also. + +Fri Jul 8 19:59:49 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu) + + * breakpoint.c: (break_command_1) Allow `break if condition' + rather than parsing `if' as a function name and returning an + error. + +Thu Jul 7 22:22:47 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu) + + * C++: valops.c, valprint.c, value.h, values.c: merged code to deal + with C++ expressions. + +Wed Jul 6 03:28:18 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu) + + * C++: dbxread.c: (read_dbx_symtab, condense_misc_bunches, + add_file_command) Merged code to read symbol information from + an incrementally linked file. symmisc.c: + (init_free_inclink_symtabs, free_inclink_symtabs) Cleanup + routines. + +Tue Jul 5 02:50:41 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu) + + * C++: symtab.c, breakpoint.c, source.c: Merged code to deal with + ambiguous line specifications. In C++ one can have overloaded + function names, so that `list classname::overloadedfuncname' + refers to several different lines, possibly sure currently configured machine + dependent files come first in e at corn-chex.ai.mit.edu) + + * C++: symtab.c: replaced lookup_symtab_1 and lookup_symtab_2 with + a modified lookup_symbol which checks for fields of the current + implied argument `this'. printcmd.c, source.c, symtab.c, + valops.c: Need to change callers once callers are + installed. + +Wed Jun 29 01:26:56 1988 Peter TerMaat (pete at frosted-flakes.ai.mit.edu) + + * C++: eval.c, expprint.c, expread.y, expression.h, valarith.c, + Merged code to deal with evaluation of user-defined operators, + member functions, and virtual functions. + binop_must_be_user_defined tests for user-defined binops, + value_x_binop calls the appropriate operator function. + +Tue Jun 28 02:56:42 1988 Peter TerMaat (pete at frosted-flakes.ai.mit.edu) + + * C++: Makefile: changed the echo: expect 101 shift/reduce conflicts + and 1 reduce/reduce conflict. + + +Local Variables: +mode: indented-text +eval: (auto-fill-mode 1) +left-margin: 8 +fill-column: 74 +version-control: never +End: + + constructors, and flags being defined via public and via + virtual paths. Added fields NEXT_VARIANT, N_BASECLASSES, + and BASECLASSES to this type (tr: Changed types from + having to be derived from a single baseclass to a multiple + base class). + * symtab.h: Added macros to access new fields defined in symseg.h. + Added decl for lookup_basetype_type. + * dbxread.c + (condense_addl_misc_bunches): Function added to condense the misc + function bunches added by reading in a new .o file. + (read_addl_syms): Function added to read in symbols + from a new .o file (incremental linking). + (add_file_command): Command interface function to indicate + incrmental linking of a new .o file; this now calls + read_addl_syms and condense_addl_misc_bunches. + (define_symbol): Modified code to handle types defined from base + types which were not known when the derived class was + output. + (read_struct_type): Modified to better handle description of + struct types as derived types. Possibly derived from + several different base classes. Also added new code to + mark definitions via virtual paths or via public paths. + Killed seperate code to handle classes with destructors + but without constructors and improved marking of classes + as having destructors and constructors. + * infcmd.c: Modified call to val_print (one more argument). + * symtab.c (lookup_member_type): Modified to deal with new + structure in symseg.h. + (lookup_basetype_type): Function added to find or construct a type + ?derived? from the given type. + (decode_line_1): Modified to deal with new type data structures. + Modified to deal with new number of args for + decode_line_2. + (decode_line_2): Changed number of args (?why?). + (init_type): Added inits for new C++ fields from + symseg.h. + *valarith.c + (value_x_binop, value_binop): Added cases for BINOP_MIN & + BINOP_MAX. + * valops.c + (value_struct_elt, check_field, value_struct_elt_for_address): + Changed to deal with multiple possible baseclasses. + (value_of_this): Made SELECTED_FRAME an extern variable. + * valprint.c + (val_print): Added an argument DEREF_REF to dereference references + automatically, instead of printing them like pointers. + Changed number of arguments in recursive calls to itself. + Changed to deal with varibale numbers of base classes. + (value_print): Changed number of arguments to val_print. Print + type of value also if value is a reference. + (type_print_derivation_info): Added function to print out + derivation info a a type. + (type_print_base): Modified to use type_print_derivation_info and + to handle multiple baseclasses. + +Mon Nov 21 10:32:07 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * inflow.c (term_status_command): Add trailing newline to output. + + * sparc-dep.c (do_save_insn, do_restore_insn): Saved + "stop_registers" over the call for the sake of normal_stop and + run_stack_dummy. + + * m-sparc.h (EXTRACT_RETURN_VALUE): Put in parenthesis to force + addition of 8 to the int pointer, not the char pointer. + + * sparc-pinsn.c (print_addr1): Believe that I have gotten the + syntax right for loads and stores as adb does it. + + * symtab.c (list_symbols): Turned search for match on rexegp into + a single loop. + + * dbxread.c (psymtab_to_symtab): Don't read it in if it's already + been read in. + + * dbxread.c (psymtab_to_symtab): Changed error to fatal in + psymtab_to_symtab. + + * expread.y (parse_number): Fixed bug which treated 'l' at end of + number as '0'. + +Fri Nov 18 13:57:33 1988 Randall Smith (randy at gluteus.ai.mit.edu) + + * dbxread.c (read_dbx_symtab, process_symbol_for_psymtab): Was + being foolish and using pointers into an array I could realloc. + Converted these pointers into integers. + +Wed Nov 16 11:43:10 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * m-sparc.h (POP_FRAME): Made the new frame be PC_ADJUST of the + old frame. + + * i386-pinsn.c, m-hp9k320.h, m-isi.h, m-merlin.h, m-news.h, + m-npl.h, m-pn.h, m-sparc.h, m-sun2.h, m-sun3.h, m-umax.h, m-vax.h: + Modified POP_FRAME to use the current frame instead of + read_register (FP_REGNUM) and to flush_cached_frames before + setting the current frame. Also added a call to set the current + frame in those POP_FRAMEs that didn't have it. + + * infrun.c (wait_for_inferior): Moved call to set_current_frame up + to guarrantee that the current frame will always be set when a + POP_FRAME is done. + + * infrun.c (normal_stop): Added something to reset the pc of the + current frame (was incorrect because of DECR_PC_AFTER_BREAK). + + * valprint.c (val_print): Changed to check to see if a string was + out of bounds when being printed and to indicate this if so. + + * convex-dep.c (read_inferior_memory): Changed to return the value + of errno if the call failed (which will be 0 if the call + suceeded). + +Tue Nov 15 10:17:15 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * infrun.c (wait_for_inferior): Two changes: 1) Added code to + not trigger the step breakpoint on recursive calls to functions + without frame info, and 2) Added calls to distinguish recursive + calls within a function without a frame (which next/nexti might + wish to step over) from jumps to the beginning of a function + (which it generally doesn't). + + * m-sparc.h (INIT_EXTRA_FRAME_INFO): Bottom set correctly for leaf + parents. + + * blockframe.c (get_prev_frame_cache_item): Put in mod to check + for a leaf node (by presence or lack of function prologue). If + there is a leaf node, it is assumed that SAVED_PC_AFTER_CALL is + valid. Otherwise, FRAME_SAVED_PC or read_pc is used. + + * blockframe.c, frame.h: Did final deletion of unused routines and + commented problems with getting a pointer into the frame cache in + the frame_info structure comment. + + * blockframe.c, frame.h, stack.c: Killed use of + frame_id_from_frame_info; used frame_id_from_addr instead. + + * blockframe.c, frame.h, stack.c, others (oops): Combined stack + cache and frame info structures. + + * blockframe.c, sparc-dep.c, stack.c: Created the function + create_new_frame and used it in place of bad calls to + frame_id_from_addr. + + * blockframe.c, inflow.c, infrun.c, i386-pinsn.c, m-hp9k320.h, + m-npl.h, m-pn.h, m-sparc.h, m-sun3.h, m-vax.h, default-dep.c, + convex-dep.c, gould-dep.c, hp9k320-dep.c, news-dep.c, sparc-dep.c, + sun3-dep.c, umax-dep.c: Killed use of + set_current_Frame_by_address. Used set_current_frame + (create_new_frame...) instead. + + * frame.h: Killed use of FRAME_FP_ID. + + * infrun.c, blockframe.c: Killed select_frame_by_address. Used + select_frame (get_current_frame (), 0) (which was correct in all + cases that we need to worry about. + +Mon Nov 14 14:19:32 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * frame.h, blockframe.c, stack.c, m-sparc.h, sparc-dep.c: Added + mechanisms to deal with possible specification of frames + dyadically. + +Sun Nov 13 16:03:32 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * ns32k-opcode.h: Add insns acbw, acbd. + +Sun Nov 13 15:09:58 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * breakpoint.c: Changed breakpoint structure to use the address of + a given frame (constant across inferior runs) as the criteria for + stopping instead of the frame ident (which varies across inferior + calls). + +Fri Nov 11 13:00:22 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * gld-pinsn.c (findframe): Modified to work with the new frame + id's. Actually, it looks as if this routine should be called with + an address anyway. + + * findvar.c (find_saved_register): Altered bactrace loop to work + off of frames and not frame infos. + + * frame.h, blockframe.c, stack.c, sparc-dep.c, m-sparc.h: Changed + FRAME from being the address of the frame to being a simple ident + which is an index into the frame_cache_item list. + * convex-dep.c, default-dep.c, gould-dep.c, hp9k320-dep.c, + i386-pinsn.c, inflow.c, infrun.c, news-dep.c, sparc-dep.c, + sun3-dep.c, umax-dep.c, m-hp9k320.h, m-npl.h, m-pn.h, m-sparc.h, + m-sun3.h, m-vax.h: Changed calls of the form set_current_frame + (read_register (FP_REGNUM)) to set_current_frame_by_address (...). + +Thu Nov 10 16:57:57 1988 Randall Smith (randy at gluteus.ai.mit.edu) + + * frame.h, blockframe.c, gld-pinsn.c, sparc-dep.c, stack.c, + infrun.c, findvar.c, m-sparc.h: Changed the FRAME type to be + purely an identifier, using FRAME_FP and FRAME_FP_ID to convert + back and forth between the two. The identifier is *currently* + still the frame pointer value for that frame. + +Wed Nov 9 17:28:14 1988 Chris Hanson (cph at kleph) + + * m-hp9k320.h (FP_REGISTER_ADDR): Redefine this to return + difference between address of given FP register, and beginning of + `struct user' that it occurs in. + + * hp9k320-dep.c (core_file_command): Fix sign error in size + argument to myread. Change buffer argument to pointer; was + copying entire structure. + (fetch_inferior_registers, store_inferior_registers): Replace + occurrences of `FP_REGISTER_ADDR_DIFF' with `FP_REGISTER_ADDR'. + Flush former definition. + +Wed Nov 9 12:11:37 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * xgdb.c: Killed include of initialize.h. + + * Pulled in xgdb.c from the net. + + * Checkpointed distribution (to provide to 3b2 guy). + + * coffread.c, dbxread.c, symmisc.c, symtab.c, symseg.h: Changed + format of table of line number--pc mapping information. Can + handle negative pc's now. + + * command.c: Deleted local copy of savestring; code in utils.c is + identical. + +Tue Nov 8 11:12:16 1988 Randall Smith (randy at plantaris.ai.mit.edu) + + * gdb.texinfo: Added documentation for shell escape. + +Mon Nov 7 12:27:16 1988 Randall Smith (randy at sugar-bombs.ai.mit.edu) + + * command.c: Added commands for shell escape. + + * core.c, dbxread.c: Added ROBOTUSSIN mods. + + * Checkpointed distribution. + + * printcmd.c (x_command): Yanked error if there is no memory to + examine (could be looking at executable straight). + + * sparc-pinsn.c (print_insn): Amount to leftshift sethi imm by is + now 10 (matches adb in output). + + * printcmd.c (x_command): Don't attempt to set $_ & $__ if there + is no last_examine_value (can happen if you did an x/0). + +Fri Nov 4 13:44:49 1988 Randall Smith (randy at gluteus.ai.mit.edu) + + * printcmd.c (x_command): Error if there is no memory to examine. + + * gdb.texinfo: Added "cont" to the command index. + + * sparc-dep.c (do_save_insn): Fixed typo in shift amount. + + * m68k-opcode.h: Fixed opcodes for 68881. + + * breakpoint.c, infcmd.c, source.c: Changed defaults in several + places for decode_line_1 to work off of the default_breakpoint_* + values instead of current_source_* values (the current_source_* + values are off by 5 or so because of listing defaults). + + * stack.c (frame_info): ifdef'd out FRAME_SPECIFCATION_DYADIC in + the stack.c module. If I can't do this right, I don't want to do + it at all. Read the comment there for more info. + +Mon Oct 31 16:23:06 1988 Randall Smith (randy at gluteus.ai.mit.edu) + + * gdb.texinfo: Added documentation on the "until" command. + +Sat Oct 29 17:47:10 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * breakpoint.c, infcmd.c: Added UNTIL_COMMAND and subroutines of + it. + + * breakpoint.c, infcmd.c, infrun.c: Added new field to breakpoint + structure (silent, indicating a silent breakpoint), and modified + breakpoint_stop_status and things that read it's return value to + understand it. + +Fri Oct 28 17:45:33 1988 Randall Smith (randy at gluteus.ai.mit.edu) + + * dbxread.c, symmisc.c: Assorted speedups for readin, including + special casing most common symbols, and doing buffering instead of + calling malloc. + +Thu Oct 27 11:11:15 1988 Randall Smith (randy at gluteus.ai.mit.edu) + + * stack.c, sparc-dep.c, m-sparc.h: Modified to allow "info frame" + to take two arguments on the sparc and do the right thing with + them. + + * dbxread.c (read_dbx_symtab, process_symbol_for_psymtab): Put + stuff to put only symbols that didn't have debugging info on the + misc functions list back in. + +Wed Oct 26 10:10:32 1988 Randall Smith (randy at gluteus.ai.mit.edu) + + * valprint.c (type_print_varspec_suffix): Added check for + TYPE_LENGTH(TYPE_TARGET_TYPE(type)) > 0 to prevent divide by 0. + + * printcmd.c (print_formatted): Added check for VALUE_REPEATED; + value_print needs to be called for that. + + * infrun.c (wait_for_inferior): Added break when you decide to + stop on a null function prologue rather than continue stepping. + + * m-sun3.h: Added explanatory comment to REGISTER_RAW_SIZE. + + * expread.y (parse_c_1): Initialized paren_depth for each parse. + +Tue Oct 25 14:19:38 1988 Randall Smith (randy at gluteus.ai.mit.edu) + + * valprint.c, coffread.c, dbxread.c: Enum constant values in enum + type now accessed through TYPE_FIELD_BITPOS. + + * dbxread.c (process_symbol_for_psymtab): Added code to deal with + possible lack of a ":" in a debugging symbol (do nothing). + + * symtab.c (decode_line_1): Added check in case of all numbers for + complete lack of symbols. + + * source.c (select_source_symtab): Made sure that this wouldn't + bomb on complete lack of symbols. + +Mon Oct 24 12:28:29 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * m-sparc.h, findvar.c: Ditched REGISTER_SAVED_UNIQUELY and based + code on REGISTER_IN_WINDOW_P and HAVE_REGISTER_WINDOWS. This will + break when we find a register window machine which saves the + window registers within the context of an inferior frame. + + * sparc-dep.c (frame_saved_pc): Put PC_ADJUST return back in for + frame_saved_pc. Seems correct. + + * findvar.c, m-sparc.h: Created the macro REGISTER_SAVED_UNIQUELY + to handle register window issues (ie. that find_saved_register + wasn't checking the selected frame itself for shit). + + * sparc-dep.c (core_file_command): Offset target of o & g register + bcopy by 1 to hit correct registers. + + * m-sparc.h: Changed STACK_END_ADDR. + +Sun Oct 23 19:41:51 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * sparc-dep.c (core_file_command): Added in code to get the i & l + registers from the stack in the corefile, and blew away some wrong + code to get i & l from inferior. + +Fri Oct 21 15:09:19 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu) + + * m-sparc.h (PUSH_DUMMY_FRAME): Saved the value of the RP register + in the location reserved for i7 (in the created frame); this way + the rp value won't get lost. The pc (what we put into the rp in + this routine) gets saved seperately, so we loose no information. + + * sparc-dep.c (do_save_insn & do_restore_insn): Added a wrapper to + preserve the proceed status state variables around each call to + proceed (the current frame was getting munged because this wasn't + being done). + + * m-sparc.h (FRAME_FIND_SAVED_REGS): Fix bug: saved registers + addresses were being computed using absolute registers number, + rather than numbers relative to each group of regs. + + * m-sparc.h (POP_FRAME): Fixed a bug (I hope) in the context + within which saved reg numbers were being interpetted. The + values to be restored were being gotten in the inferior frame, and + the restoring was done in the superior frame. This means that i + registers must be restored into o registers. + + * sparc-dep.c (do_restore_insn): Modified to take a pc as an + argument, instead of a raw_buffer. This matches (at least it + appears to match) usage from POP_FRAME, which is the only place + from which do_restore_insn is called. + + * sparc-dep.c (do_save_insn and do_restore_insn): Added comments. + + * m-sparc.h (FRAME_FIND_SAVED_REGS): Modified my code to find the + save addresses of out registers to use the in regs off the stack + pointer when the current frame is 1 from the innermost. + +Thu Oct 20 13:56:15 1988 & Smith (randy at hobbes.ai.mit.edu) + + * blockframe.c, m-sparc.h: Removed code associated with + GET_PREV_FRAME_FROM_CACHE_ITEM. This code was not needed for the + sparc; you can always find the previous frames fp from the fp of + the current frame (which is the sp of the previous). It's getting + the information associated with a given frame (ie. saved + registers) that's a bitch, because that stuff is saved relative to + the stack pointer rather than the frame pointer. + + * m-sparc.h (GET_PREV_FRAME_FROM_CACHE_ITEM): Modified to return + the frame pointer of the previous frame instead of the stack + pointer of same. + + * blockframe.c (flush_cached_frames): Modified call to + obstack_free to free back to frame_cache instead of back to zero. + This leaves the obstack control structure in finite state (and + still frees the entry allocated at frame_cache). + +Sat Oct 15 16:30:47 1988 & Smith (randy at tartarus.uchicago.edu) + + * valops.c (call_function): Suicide material here. Fixed a typo; + CALL_DUMMY_STACK_ADJUST was spelled CAll_DUMMY_STACK_ADJUST on + line 530 of the file. This cost me three days. I'm giving up + typing for lent. + +Fri Oct 14 15:10:43 1988 & Smith (randy at tartarus.uchicago.edu) + + * m-sparc.h: Corrected a minor mistake in the dummy frame code + that was getting the 5th argument and the first argument from the + same place. + +Tue Oct 11 11:49:33 1988 & Smith (randy at tartarus.uchicago.edu) + + * infrun.c: Made stop_after_trap and stop_after_attach extern + instead of static so that code which used proceed from machine + dependent files could fiddle with them. + + * blockframe.c, frame.h, sparc-dep.c, m-sparc.h: Changed sense of + ->prev and ->next in struct frame_cache_item to fit usage in rest + of gdb (oops). + +Mon Oct 10 15:32:42 1988 Randy Smith (randy at gargoyle.uchicago.edu) + + * m-sparc.h, sparc-dep.c, blockframe.c, frame.h: Wrote + get_frame_cache_item. Modified FRAME_SAVED_PC and frame_saved_pc + to take only one argument and do the correct thing with it. Added + the two macros I recently defined in blockframe.c to m-sparc.h. + Have yet to compile this thing on a sparc, but I've now merged in + everything that I received from tiemann, either exactly, or simply + effectively. + + * source.c: Added code to allocated space to sals.sals in the case + where no line was specified. + + * blockframe.c, infrun.c: Modified to cache stack frames requested + to minimize accesses to subprocess. + +Tue Oct 4 15:10:39 1988 Randall Smith (randy at cream-of-wheat.ai.mit.edu) + + * config.gdb: Added sparc. + +Mon Oct 3 23:01:22 1988 Randall Smith (randy at cream-of-wheat.ai.mit.edu) + + * Makefile, blockframe.c, command.c, core.c, dbxread.c, defs.h, + expread.y, findvar.c, infcmd.c, inflow.c, infrun.c, sparc-pinsn.c, + m-sparc.h, sparc-def.c, printcmd.c, stack.c, symmisc.c, symseg.h, + valops.c, values.c: Did initial merge of sparc port. This will + not compile; have to do stack frame caching and finish port. + + * inflow.c, gdb.texinfo: `tty' now resets the controling terminal. + +Fri Sep 30 11:31:16 1988 Randall Smith (randy at gluteus.ai.mit.edu) + + * inferior.h, infcmd.c, infrun.c: Changed the variable + stop_random_signal to stopped_by_random signal to fit in better + with name conventions (variable is not a direction to the + proceed/resume set; it is information from it). + +Thu Sep 29 13:30:46 1988 Randall Smith (randy at cream-of-wheat.ai.mit.edu) + + * infcmd.c (finish_command): Value type of return value is now + whatever the function returns, not the type of the function (fixed + a bug in printing said value). + + * dbxread.c (read_dbx_symtab, process_symbol_for_psymtab): + Put *all* global symbols into misc_functions. This is what was + happening anyway, and we need it for find_pc_misc_function. + + ** This was eventually taken out, but I didn't mark it in the + ChangeLog. Oops. + + * dbxread.c (process_symbol_for_psymtab): Put every debugger + symbol which survives the top case except for constants on the + symchain. This means that all of these *won't* show up in misc + functions (this will be fixed once I make sure it's broken the way + it's supposed to be). + + * dbxread.c: Modified placement of debugger globals onto the hash + list; now we exclude the stuff after the colon and don't skip the + first character (debugger symbols don't have underscores). + + * dbxread.c: Killed debuginfo stuff with ifdef's. + +Wed Sep 28 14:31:51 1988 Randall Smith (randy at cream-of-wheat.ai.mit.edu) + + * symtab.h, dbxread.c: Modified to deal with BINCL, EINCL, and + EXCL symbols produced by the sun loader by adding a list of + pre-requisite partial_symtabs that each partial symtab needs. + + * symtab.h, dbxread.c, symtab.c, symmisc.c: Modified to avoid + doing a qsort on the local (static) psymbols for each file to + speed startup. This feature is not completely debugged, but it's + inclusion has forced the inclusion of another feature (dealing + with EINCL's, BINCL's and EXCL's) and so I'm going to go in and + deal with them. + + * dbxread.c (process_symbol_for_psymtab): Made sure that the class + of the symbol made it into the partial_symbol entry. + +Tue Sep 27 15:10:26 1988 Randall Smith (randy at gluteus.ai.mit.edu) + + * dbxread.c: Fixed bug; init_psymbol_list was not being called + with the right number of arguments (1). + + * dbxread.c: Put ifdef's around N_MAIN, N_M2C, and N_SCOPE to + allow compilation on a microvax. + + * config.gdb: Modified so that "config.gdb vax" would work. + + * dbxread.c, symtab.h, symmisc.h, symtab.c, source.c: Put in many + and varied hacks to speed up gdb startup including: A complete + rewrite of read_dbx_symtab, a modification of the partial_symtab + data type, deletion of select_source_symtab from + symbol_file_command, and optimiztion of the call to strcmp in + compare_psymbols. + +Thu Sep 22 11:08:54 1988 Randall Smith (randy at gluteus.ai.mit.edu) + + * dbxread.c (psymtab_to_symtab): Removed call to + init_misc_functions. + + * dbxread.c: Fixed enumeration type clash (used enum instead of + integer constant). + + * breakpoint.c: Fixed typo; lack of \ at end of line in middle of + string constant. + + * symseg.h: Fixed typo; lack of semicolon after structure + definition. + + * command.c, breakpoint.c, printcmd.c: Added cmdlist editing + functions to add commands with the abbrev flag set. Changed + help_cmd_list to recognize this flag and modified unset, + undisplay, and enable, disable, and delete breakpoints to have + this flag set. + +Wed Sep 21 13:34:19 1988 Randall Smith (randy at plantaris.ai.mit.edu) + + * breakpoint.c, infcmd.c, gdb.texinfo: Created "unset" as an alias + for delete, and changed "unset-environment" to be the + "environment" subcommand of "delete". + + * gdb.texinfo, valprint.c: Added documentation in the manual for + breaking the set-* commands into subcommands of set. Changed "set + maximum" to "set array-max". + + * main.c, printcmd.c, breakpoint.c: Moved the declaration of + command lists into main and setup a function in main initializing + them to guarrantee that they would be initialized before calling + any of the individual files initialize routines. + + * command.c (lookup_cmd): A null string subcommand is treated as + an unknown subcommand rather than an ambiguous one (eg. "set $x = + 1" will now work). + + * infrun.c (wait_for_inferior): Put in ifdef for Sony News in + check for trap by INNER_THAN macro. + + * eval.c (evaluate_subexp): Put in catch to keep the user from + attempting to call a non function as a function. + +Tue Sep 20 10:35:53 1988 Randall Smith (randy at oatmeal.ai.mit.edu) + + * dbxread.c (read_dbx_symtab): Installed code to keep track of + which global symbols did not have debugger symbols refering to + them, and recording these via record_misc_function. + + * dbxread.c: Killed code to check for extra global symbols in the + debugger symbol table. + + * printcmd.c, breakpoint.c: Modified help entries for several + commands to make sure that abbreviations were clearly marked and + that the right commands showed up in the help listings. + + * main.c, command.c, breakpoint.c, infcmd.c, printcmd.c, + valprint.c, defs.h: Modified help system to allow help on a class + name to show subcommands as well as commands and help on a command + to show *all* subcommands of that command. + +Fri Sep 16 16:51:19 1988 Randall Smith (randy at gluteus.ai.mit.edu) + + * breakpoint.c (_initialize_breakpoint): Made "breakpoints" + subcommands of enable, disable, and delete use class 0 (ie. they + show up when you do a help xxx now). + + * infcmd.c,printcmd,c,main.c,valprint.c: Changed the set-* + commands into subcommands of set. Created "set variable" for use + with variables whose names might conflict with other subcommands. + + * blockframe.c, dbxread.c, coffread.c, expread.y, source.c: + Fixed mostly minor (and one major one in block_for_pc) bugs + involving checking the partial_symtab_list when a scan through the + symtab_list fails. + +Wed Sep 14 12:02:05 1988 Randall Smith (randy at sugar-smacks.ai.mit.edu) + + * breakpoint.c, gdb.texinfo: Added enable breakpoints, disable + breakpoints and delete breakpoints as synonyms for enable, + disable, and delete. This seemed reasonable because of the + immeninent arrival of watchpoints & etc. + + * gdb.texinfo: Added enable display, disable display, and delete + display to manual. + +Tue Sep 13 16:53:56 1988 Randall Smith (randy at sugar-smacks.ai.mit.edu) + + * inferior.h, infrun.c, infcmd.c: Added variable + stop_random_signal to indicate when a proceed had been stopped by + an unexpected signal. Used this to determine (in normal_stop) + whether the current display point should be deleted. + + * valops.c: Fix to value_ind to check for reference before doing a + COERCE_ARRAY. + +Sun Jul 31 11:42:36 1988 Richard Stallman (rms at frosted-flakes.ai.mit.edu) + + * breakpoint.c (_initialize_breakpoint): Clean up doc for commands + that can now apply also to auto-displays. + + * coffread.c (record_line): Corrected a spazz in editing. + Also removed the two lines that assume line-numbers appear + only in increasing order. + +Tue Jul 26 22:19:06 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu) + + * expression.h, eval.c, expprint.c, printcmd.c, valarith.c, + valops.c, valprint.c, values.c, m-*.h: Changes for evaluating and + displaying 64-bit `long long' integers. Each machine must define + a LONGEST type, and a BUILTIN_TYPE_LONGEST. + + * symmisc.c: (print_symtab) check the status of the fopen and call + perror_with_name if needed. + +Thu Jul 21 00:56:11 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu) + + * Convex: core.c: changes required by Convex's SOFF format were + isolated in convex-dep.c. + +Wed Jul 20 21:26:10 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu) + + * coffread.c, core.c, expread.y, i386-pinsn.c, infcmd.c, inflow.c, + infrun.c, m-i386.h, main.c, remote.c, source.c, valops.c: + Improvements for the handling of the i386 and other machines + running USG. (Several of these files just needed extra header files + such as types.h.) utils.c: added bcopy, bcmp, bzero, getwd, list + of signals, and queue routines for USG systems. Added vfork macro + to i386 + + * printcmd.c, breakpoint.c: New commands to enable/disable + auto-displays. Also `delete display displaynumber' works like + `undisplay displaynumber'. + +Tue Jul 19 02:17:18 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu) + + * coffread.c: (coff_lookup_type) Wrong portion of type_vector was + being bzero'd after type_vector was reallocated. + + * printcmd.c: (delete_display) Check for a display chain before + attempting to delete a display. + + * core.c, *-dep.c (*-infdep moved to *-dep): machine-dependent + parts of core.c (core_file_command, exec_file_command) moved to + *-dep.c. + +Mon Jul 18 19:45:51 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu) + + * dbxread.c: typo in read_struct_type (missing '=') was causing a + C struct to be parsed as a C++ struct, resulting in a `invalid + character' message. + +Sun Jul 17 22:27:32 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu) + + * printcmd.c, symtab.c, valops.c, expread.y: When an expression is + read, the innermost block required to evaluate the expression is + saved in the global variable `innermost_block'. This information + is saved in the `block' field of an auto-display so that + expressions with inactive variables can be skipped. `info display' + tells the user which displays are active and which are not. New + fn `contained_in' returns nonzero if one block is contained within + another. + +Fri Jul 15 01:53:14 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu) + + * infrun.c, m-i386.h: Use macro TRAPS_EXPECTED to set number of + traps to skip when sh execs the program. Default is 2, m-i386.h + overrides this and sets to 4. + + * coffread.c, infrun.c: minor changes for the i386. May be able + to eliminate them with more general code. + + * default-infdep.c: #ifdef SYSTEMV, include header file types.h. + Also switched the order of signal.h and user.h, since System 5 + requires signal.h to come first. + + * core.c main.c, remote,c, source.c, inflow.c: #ifdef SYSTEMV, + include various header files. Usually types.h and fcntl.h. + + * utils.c: added queue routines needed by the i386 (and other sys + 5 machines). + + * sys5.c, regex.c, regex.h: new files for sys 5 systems. (The + regex files are simply links to /gp/gnu/lib.) + +Thu Jul 14 01:47:14 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu) + + * config.gdb, README: Provide a list of known machines when user + enters an invalid machine. New second arg is operating system, + currently only used with `sunos4' or `os4'. Entry for i386 added. + + * news-infdep.c: new file. + + * m-news.h: new version which deals with new bugs in news800's OS. + +Tue Jul 12 19:52:16 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu) + + * Makefile, *.c, munch, config.gdb, README: New initialization + scheme uses nm to find functions whose names begin with + `_initialize_'. Files `initialize.h', `firstfile.c', + `lastfile.c', `m-*init.h' no longer needed. + + * eval.c, symtab.c, valarith.c, valops.c, value.h, values.c: Bug + fixes from gdb+ 2.5.4. evaluate_subexp takes a new arg, type + expected. New fn value_virtual_fn_field. + +Mon Jul 11 00:48:49 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu) + + * core.c (read_memory): xfer_core_file was being called with an + extra argument (0) by read_memory. + + * core.c (read_memory), *-infdep.c (read_inferior_memory), + valops.c (value_at): read_memory and read_inferior_memory now work + like write_memory and write_inferior_memory in that errno is + checked after each ptrace and returned to the caller. Used in + value_at to detect references to addresses which are out of + bounds. Also core.c (xfer_core_file): return 1 if invalid + address, 0 otherwise. + + * inflow.c, <machine>-infdep.c: removed all calls to ptrace from + inflow.c and put them in machine-dependent files *-infdep.c. + +Sun Jul 10 19:19:36 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu) + + * symmisc.c: (read_symsegs) Accept only format number 2. Since + the size of the type structure changed when C++ support was added, + format 1 can no longer be used. + + * core.c, m-sunos4.h: (core_file_command) support for SunOS 4.0. + Slight change in the core structure. #ifdef SUNOS4. New file + m-sunos4.h. May want to change config.gdb also. + +Fri Jul 8 19:59:49 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu) + + * breakpoint.c: (break_command_1) Allow `break if condition' + rather than parsing `if' as a function name and returning an + error. + +Thu Jul 7 22:22:47 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu) + + * C++: valops.c, valprint.c, value.h, values.c: merged code to deal + with C++ expressions. + +Wed Jul 6 03:28:18 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu) + + * C++: dbxread.c: (read_dbx_symtab, condense_misc_bunches, + add_file_command) Merged code to read symbol information from + an incrementally linked file. symmisc.c: + (init_free_inclink_symtabs, free_inclink_symtabs) Cleanup + routines. + +Tue Jul 5 02:50:41 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu) + + * C++: symtab.c, breakpoint.c, source.c: Merged code to deal with + ambiguous line specifications. In C++ one can have overloaded + function names, so that `list classname::overloadedfuncname' + refers to several different lines, possibly in different files. + +Fri Jul 1 02:44:20 1988 Peter TerMaat (pete at corn-chex.ai.mit.edu) + + * C++: symtab.c: replaced lookup_symtab_1 and lookup_symtab_2 with + a modified lookup_symbol which checks for fields of the current + implied argument `this'. printcmd.c, source.c, symtab.c, + valops.c: Need to change callers once callers are + installed. + +Wed Jun 29 01:26:56 1988 Peter TerMaat (pete at frosted-flakes.ai.mit.edu) + + * C++: eval.c, expprint.c, expread.y, expression.h, valarith.c, + Merged code to deal with evaluation of user-defined operators, + member functions, and virtual functions. + binop_must_be_user_defined tests for user-defined binops, + value_x_binop calls the appropriate operator function. + +Tue Jun 28 02:56:42 1988 Peter TerMaat (pete at frosted-flakes.ai.mit.edu) + + * C++: Makefile: changed the echo: expect 101 shift/reduce conflicts + and 1 reduce/reduce conflict. + +Local Variables: +mode: indented-text +left-margin: 8 +fill-column: 74 +version-control: never +End: diff --git a/gnu/usr.bin/gdb/Gdbinit b/gnu/usr.bin/gdb/Gdbinit new file mode 100644 index 0000000..bcacd5d --- /dev/null +++ b/gnu/usr.bin/gdb/Gdbinit @@ -0,0 +1,15 @@ +echo Setting up the environment for debugging gdb.\n + +b fatal + +b info_command +commands + silent + return +end + +define rr + run +end + +set prompt (top-gdb) diff --git a/gnu/usr.bin/gdb/Makefile b/gnu/usr.bin/gdb/Makefile new file mode 100644 index 0000000..550ed07 --- /dev/null +++ b/gnu/usr.bin/gdb/Makefile @@ -0,0 +1,38 @@ +# @(#)Makefile 6.4 (Berkley) 5/6/91 + +PROG= gdb +GDBSRCS= blockframe.c breakpoint.c command.c copying.c core.c \ + cplus-dem.c dbxread.c environ.c eval.c expprint.c \ + expread.y findvar.c infcmd.c inflow.c infrun.c \ + main.c obstack.c printcmd.c regex.c remote.c \ + remote-sl.c source.c stack.c symmisc.c symtab.c \ + utils.c valarith.c valops.c valprint.c values.c \ + version.c +READLINESRCS= funmap.c history.c keymaps.c readline.c +SRCS= $(CONFIGSRCS) $(GDBSRCS) $(READLINESRCS) init.c +CFLAGS+= -I. -I$(.CURDIR) -I$(.CURDIR)/config -I$(.CURDIR)/readline \ + -DHAVE_VPRINTF -DVI_MODE -DKERNELDEBUG -DNEWVM +LDADD= -ltermcap +YFLAGS= +.PATH: $(.CURDIR)/config $(.CURDIR)/readline + +depend: + +.include "config/Makefile.$(MACHINE)" +.include <bsd.prog.mk> + +$(OBJS): param.h + +# +# Generate the constructor +# +init.c: $(CONFIGSRCS) $(GDBSRCS) $(READLINESRCS) + -((cd $(.CURDIR)/config; \ + egrep -h '^_initialize_[^ ]* *\(\)' $(CONFIGSRCS)); \ + (cd $(.CURDIR); egrep -h '^_initialize_[^ ]* *\(\)' $(GDBSRCS)); \ + (cd $(.CURDIR)/readline; \ + egrep -h '^_initialize_[^ ]* *\(\)' $(READLINESRCS))) | \ + (echo 'void initialize_all_files () {'; sed -e 's/$$/;/'; echo '}') \ + > init.c + +CLEANFILES+= init.c param.h diff --git a/gnu/usr.bin/gdb/Makefile.dist b/gnu/usr.bin/gdb/Makefile.dist new file mode 100644 index 0000000..3cbc91f --- /dev/null +++ b/gnu/usr.bin/gdb/Makefile.dist @@ -0,0 +1,371 @@ +/* This file should be run through the C preprocessor by config.gdb + to produce the Makefile. */ + +/* Define this to xgdb if you want to compile xgdb as well as gdb. */ +XGDB= +/* Place to install binaries. */ +bindir=/usr/local/bin +/* Place to install X binaries. */ +xbindir=$(bindir) + +/* 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=gcc -traditional */ +CC=cc + +/* 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 -v +/* 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} + +/* If you are using the GNU C library, uncomment the following line. */ +/* HAVE_VPRINTF_DEFINE = -DHAVE_VPRINTF */ + +/* -I. for "#include <obstack.h>". Possibly regex.h also. */ + +/* M_CFLAGS, if defined, has system-dependent CFLAGS. */ +#if !defined(M_CFLAGS) +#define M_CFLAGS +#endif + +/* CFLAGS for both GDB and readline. */ +GLOBAL_CFLAGS = -g M_CFLAGS +CFLAGS = -I. ${HAVE_VPRINTF_DEFINE} ${GLOBAL_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 + you must at the same time define OBSTACK1 as "obstack.o" + so that the dependencies work right. Similarly with REGEX and "regex.o". + 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 */ +OBSTACK = obstack.o +OBSTACK1 = obstack.o + +#ifdef M_REGEX +REGEX = M_REGEX +REGEX1 = M_REGEX +#else +REGEX = +REGEX1 = +#endif + +#ifdef M_ALLOCA +ALLOCA = M_ALLOCA +ALLOCA1 = M_ALLOCA +#else +ALLOCA = +ALLOCA1 = +#endif + +/* + define this to be "malloc.o" if you want to use the gnu malloc routine + (useful for debugging memory allocation problems in gdb). Otherwise, leave + it blank. */ +/* GNU_MALLOC = */ +GNU_MALLOC = malloc.o + +/* Flags to be used in compiling malloc.o + Specify range checking for storage allocation. */ +/* MALLOC_FLAGS = ${CFLAGS} */ +MALLOC_FLAGS = ${CFLAGS} -Drcheck -Dbotch=fatal_dump_core -DMSTATS + +/* Define SYSV if compiling on a system V or HP machine. */ +#ifdef M_SYSV +SYSV_DEFINE = -DSYSV +#else +SYSV_DEFINE = +#endif + +/* MUNCH_DEFINE should be -DSYSV if have System V-style nm, + or null if have BSD-style nm. */ +#ifdef M_BSD_NM +MUNCH_DEFINE = +#else +MUNCH_DEFINE = ${SYSV_DEFINE} +#endif + +/* Flags that describe where you can find the termcap library. + You may need to make other arrangements for USG. */ +TERMCAP = -ltermcap + +/* M_CLIBS, if defined, has system-dependent libs + For example, -lPW for System V to get alloca(). */ +#ifndef M_CLIBS +#define M_CLIBS +#endif +CLIBS = ${ADD_FILES} ${TERMCAP} M_CLIBS + +ADD_FILES = ${OBSTACK} ${REGEX} ${ALLOCA} ${GNU_MALLOC} +ADD_DEPS = ${OBSTACK1} ${REGEX1} ${ALLOCA1} ${GNU_MALLOC} + +SFILES = blockframe.c breakpoint.c dbxread.c coffread.c command.c core.c \ + environ.c eval.c expprint.c findvar.c infcmd.c inflow.c infrun.c \ + kdb-start.c main.c printcmd.c \ + remote.c source.c stack.c standalone.c stuff.c symmisc.c symtab.c \ + utils.c valarith.c valops.c valprint.c values.c version.c expread.y \ + xgdb.c + +DEPFILES = umax-dep.c gould-dep.c default-dep.c sun3-dep.c \ + sparc-dep.c hp9k320-dep.c hp300bsd-dep.c news-dep.c i386-dep.c \ + symmetry-dep.c convex-dep.c altos-dep.c isi-dep.c pyr-dep.c + +PINSNS = gld-pinsn.c i386-pinsn.c sparc-pinsn.c vax-pinsn.c m68k-pinsn.c \ + ns32k-pinsn.c convex-pinsn.c pyr-pinsn.c + +HFILES = command.h defs.h environ.h expression.h frame.h getpagesize.h \ + inferior.h symseg.h symtab.h value.h wait.h \ + a.out.encap.h a.out.gnu.h stab.gnu.h + +OPCODES = m68k-opcode.h pn-opcode.h sparc-opcode.h npl-opcode.h vax-opcode.h \ + ns32k-opcode.h convex-opcode.h pyr-opcode.h + +MFILES = m-hp9k320.h m-hp300bsd.h m-i386.h m-i386gas.h \ + m-i386-sv32.h m-i386g-sv32.h m-isi.h m-merlin.h \ + m-altos.h m-news.h m-newsos3.h m-npl.h m-pn.h \ + m-sparc.h m-sun2.h m-sun3.h m-sun2os4.h \ + m-sun3os4.h m-sun4os4.h m-umax.h m-vax.h m-symmetry.h m-convex.h \ + m-pyr.h + +/* This list of files really shouldn't be in this makefile, but I can't think + of any good way to get the readline makefile to tell us what files + to put in our tarfile. */ +READLINE = readline.c history.c funmap.c \ + emacs_keymap.c vi_keymap.c vi_mode.c keymaps.c \ + readline.h history.h keymaps.h chardefs.h \ + inc-readline.texinfo inc-history.texinfo \ + readline.texinfo history.texinfo \ + Makefile ChangeLog + +REMOTE_EXAMPLES = remote-sa.m68k.shar remote-multi.shar + +POSSLIBS = obstack.h obstack.c regex.c regex.h malloc.c alloca.c + +TESTS = testbpt.c testfun.c testrec.c testreg.c testregs.c + +OTHERS = Makefile.dist createtags munch config.gdb ChangeLog README TAGS \ + gdb.texinfo .gdbinit COPYING expread.tab.c stab.def \ + XGDB-README copying.c Projects Convex.notes copying.awk hp-include + +TAGFILES = ${SFILES} ${DEPFILES} ${PINSNS} ${HFILES} ${OPCODES} ${MFILES} \ + ${POSSLIBS} +TARFILES = ${TAGFILES} ${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 symmisc.o coffread.o dbxread.o infcmd.o infrun.o remote.o \ + command.o utils.o expread.o expprint.o pinsn.o environ.o version.o \ + copying.o ${READLINEOBS} + +TSOBS = core.o inflow.o dep.o + +NTSOBS = standalone.o + +TSSTART = /lib/crt0.o + +NTSSTART = kdb-start.o + +RL_LIB = readline/libreadline.a + +/* Do some fancy trickery to produce a line like + -DM_MAKEDEFINE="-DM_SYSV -DM_BSD_NM". +*/ +MD=M_MAKEDEFINE + +/* Avoid funny things that Sun's make throws in for us. */ +/* TARGET_ARCH is supposed to get around it putting in the machine type. + If the "things" up there really is plural, we'll need to do something + else as well. */ +/*.c.o: + ${CC} -c ${CFLAGS} $< */ +TARGET_ARCH= + +all: gdb $(XGDB) + +install: gdb $(XGDB) + cp gdb $(bindir)/gdb.new + mv $(bindir)/gdb.new $(bindir)/gdb + -if [ "$(XGDB)" = xgdb ]; then \ + cp xgdb $(xbindir)/xgdb.new; \ + mv $(xbindir)/xgdb.new $(xbindir)xgdb; \ + fi + +gdb : $(OBS) $(TSOBS) ${ADD_DEPS} ${RL_LIB} + rm -f init.c + ./munch ${MUNCH_DEFINE} $(OBS) $(TSOBS) > init.c + ${CC-LD} $(LDFLAGS) -o gdb init.c $(OBS) $(TSOBS) ${RL_LIB} $(CLIBS) + +/* This is useful when debugging GDB, because Unix doesn'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". */ +gdb1 : gdb + cp gdb gdb1 + +Makefile : Makefile.dist + cp Makefile.dist tmp.c + $(CC) -E >Makefile tmp.c $(MD) "-DM_MAKEDEFINE=$(MD)" + -rm tmp.c +/* This did not work-- -Usparc became "-Usparc" became "-Usparc. + Or something like that. */ +/* $(CC) -E >Makefile tmp.c $(MD) "-DM_MAKEDEFINE=\"$(MD)\"" */ + +xgdb : $(OBS) $(TSOBS) xgdb.o ${ADD_DEPS} ${RL_LIB} + rm -f init.c + ./munch ${MUNCH_DEFINE} $(OBS) $(TSOBS) xgdb.o > init.c + $(CC-LD) $(LDFLAGS) -o xgdb init.c $(OBS) $(TSOBS) xgdb.o \ + -lXaw -lXmu -lXt -lX11 ${RL_LIB} $(CLIBS) + +/* Old (pre R3) xgdb comp. + $(CC-LD) $(LDFLAGS) -o xgdb init.c $(OBS) $(TSOBS) xgdb.o \ + -lXaw -lXt -lX11 $(CLIBS) */ + +kdb : $(NTSSTART) $(OBS) $(NTSOBS) ${ADD_DEPS} ${RL_LIB} + rm -f init.c + ./munch ${MUNCH_DEFINE} $(OBS) $(NTSOBS) > init.c + $(CC) $(LDFLAGS) -c init.c $(CLIBS) + ld -o kdb $(NTSSTART) $(OBS) $(NTSOBS) init.o ${RL_LIB} -lc $(CLIBS) + +/* If it can figure out the appropriate order, createtags will make sure + that the proper m-*, *-dep, *-pinsn, and *-opcode files come first + in the tags list. It will attempt to do the same for dbxread.c and + coffread.c. This makes using M-. on machine dependent routines much + easier. */ + +TAGS: ${TAGFILES} + createtags ${TAGFILES} +tags: TAGS + +gdb.tar: ${TARFILES} + rm -f gdb.tar + mkdir dist-gdb + cd dist-gdb ; for i in ${TARFILES} ; do ln -s ../$$i . ; done + mkdir dist-gdb/readline + cd dist-gdb/readline ; for i in ${READLINE} ; do ln -s ../../readline/$$i . ; done + tar chf gdb.tar dist-gdb + rm -rf dist-gdb + +/* Remove gdb.tar.Z so stupid compress doesn't ask whether we want to + overwrite it. compress -f is not what we want, because we do want + to know if compress would not make it smaller. */ +gdb.tar.Z: gdb.tar + if [ -f gdb.tar.Z ]; then rm -f gdb.tar.Z; else true; fi + compress gdb.tar + +clean: + rm -f ${OBS} ${TSOBS} ${NTSOBS} ${OBSTACK} ${REGEX} ${GNU_MALLOC} + rm -f init.c init.o + rm -f xgdb.o xgdb + 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 dep.c opcode.h param.h pinsn.c config.status + rm -f y.output yacc.acts yacc.tmp + rm -f ${TESTS} Makefile + +realclean: clean + rm -f expread.tab.c TAGS + rm -f dep.c opcode.h param.h pinsn.c config.status + rm -f Makefile + +xgdb.o : defs.h param.h symtab.h frame.h + +/* Make copying.c from COPYING */ +copying.c : COPYING copying.awk + awk -f copying.awk < COPYING > copying.c + +expread.tab.c : expread.y + @echo 'Expect 4 shift/reduce conflict.' + ${YACC} expread.y + mv y.tab.c expread.tab.c + +expread.o : expread.tab.c defs.h param.h symtab.h frame.h expression.h + $(CC) -c ${CFLAGS} expread.tab.c + mv expread.tab.o expread.o + +readline/libreadline.a : force_update + cd readline ; ${MAKE} "SYSV=${SYSV_DEFINE}" \ + "DEBUG_FLAGS=${GLOBAL_CFLAGS}" "CC=${CC}" libreadline.a + +force_update : + +/* Only useful if you are using the gnu malloc routines. */ +malloc.o : malloc.c + ${CC} -c ${MALLOC_FLAGS} malloc.c + +/* dep.o depends on config.status in case someone reconfigures gdb out + from under an already compiled gdb. */ +dep.o : dep.c config.status defs.h param.h frame.h inferior.h obstack.h \ + a.out.encap.h + +/* pinsn.o depends on config.status in case someone reconfigures gdb out + from under an already compiled gdb. */ +pinsn.o : pinsn.c config.status defs.h param.h symtab.h obstack.h symseg.h \ + frame.h opcode.h + +/* The rest of this is a standard dependencies list (hand edited output of + cpp -M). It does not include dependencies of .o files on .c files. */ +/* All files which depend on config.status also depend on param.h in case + someone reconfigures gdb out from under an already compiled gdb. */ +blockframe.o : defs.h param.h config.status symtab.h obstack.h symseg.h frame.h +breakpoint.o : defs.h param.h config.status symtab.h obstack.h symseg.h frame.h +coffread.o : defs.h param.h config.status +command.o : command.h defs.h +core.o : defs.h param.h config.status a.out.encap.h +dbxread.o : param.h config.status defs.h symtab.h obstack.h symseg.h a.out.encap.h \ + stab.gnu.h +environ.o : environ.h +eval.o : defs.h param.h config.status symtab.h obstack.h symseg.h value.h expression.h +expprint.o : defs.h symtab.h obstack.h symseg.h param.h config.status expression.h +findvar.o : defs.h param.h config.status symtab.h obstack.h symseg.h frame.h value.h +infcmd.o : defs.h param.h config.status symtab.h obstack.h symseg.h frame.h inferior.h \ + environ.h value.h +inflow.o : defs.h param.h config.status frame.h inferior.h +infrun.o : defs.h param.h config.status symtab.h obstack.h symseg.h frame.h inferior.h \ + wait.h +kdb-start.o : defs.h param.h config.status +main.o : defs.h command.h param.h config.status +malloc.o : getpagesize.h +obstack.o : obstack.h +printcmd.o : defs.h param.h config.status frame.h symtab.h obstack.h symseg.h value.h \ + expression.h +regex.o : regex.h +remote.o : defs.h param.h config.status frame.h inferior.h wait.h +source.o : defs.h symtab.h obstack.h symseg.h param.h config.status +stack.o : defs.h param.h config.status symtab.h obstack.h symseg.h frame.h +standalone.o : defs.h param.h config.status symtab.h obstack.h symseg.h frame.h \ + inferior.h wait.h +symmisc.o : defs.h symtab.h obstack.h symseg.h obstack.h +symtab.o : defs.h symtab.h obstack.h symseg.h param.h config.status obstack.h +utils.o : defs.h param.h config.status +valarith.o : defs.h param.h config.status symtab.h obstack.h symseg.h value.h expression.h +valops.o : defs.h param.h config.status symtab.h obstack.h symseg.h value.h frame.h \ + inferior.h +valprint.o : defs.h param.h config.status symtab.h obstack.h symseg.h value.h +values.o : defs.h param.h config.status symtab.h obstack.h symseg.h value.h + +robotussin.h : getpagesize.h +symtab.h : obstack.h symseg.h +a.out.encap.h : a.out.gnu.h + diff --git a/gnu/usr.bin/gdb/Projects b/gnu/usr.bin/gdb/Projects new file mode 100644 index 0000000..f38f6c7 --- /dev/null +++ b/gnu/usr.bin/gdb/Projects @@ -0,0 +1,114 @@ + + Suggested projects for aspiring or current GDB hackers + ====================================================== + + (You should probably chat with kingdon@ai.mit.edu to make sure that + no one else is doing the project you chose). + +Add watchpoints (break if a memory location changes). This would +usually have to involve constant single stepping, but occasionally +there is operating system support which gdb should be able to cleanly +use (e.g. on the 80386, there are 4 debug registers. By ptracing an +address into them, you can get a trap on writes or on reads and +writes). + +Rewrite proceed, wait_for_inferior, and normal_stop to clean them up. +Suggestions: + + 1) Make each test in wait_for_inferior a seperate subroutine + call. + 2) Combine wait_for_inferior and normal_stop to clean up + communication via global variables. + 3) See if you can find some way to clean up the global + variables that are used; possibly group them by data flow + and information content? + +Work out some kind of way to allow running the inferior to be done as +a sub-execution of, eg. breakpoint command lists. Currently running +the inferior interupts any command list execution. This would require +some rewriting of wait_for_inferior & friends, and hence should +probably be done in concert with the above. + +Add function arguments to gdb user defined functions. + +Add convenience variables that refer to exec file, symbol file, +selected frame source file, selected frame function, selected frame +line number, etc. + +Add a "suspend" subcommand of the "continue" command to suspend gdb +while continuing execution of the subprocess. Useful when you are +debugging servers and you want to dodge out and initiate a connection +to a server running under gdb. + +Make "handle" understand symbolic signal names. + +Work out and implement a reasonably general mechanism for multi-threaded +processies. There are parts of one implemented in convex-dep.c, if +you want an example. + +A standalone version of gdb on the i386 exists. Anyone who wants to +do some serious working cleaning it up and making it a general +standalone gdb should contact pace@wheaties.ai.mit.edu. + +Add stab information to allow reasonable debugging of inline functions +(possibly they should show up on a stack backtrace? With a note +indicating that they weren't "real"?). + +Implement support for specifying arbitrary locations of stack frames +(in practice, this usually requires specification of both the top and +bottom of the stack frame (fp and sp), since you *must* retrieve the +pc that was saved in the innermost frame). + +Modify the naked "until" command to step until past the current source +line, rather than past the current pc value. This is tricky simply +because the low level routines have no way of specifying a multi-line +step range, and there is no way of saying "don't print stuff when we +stop" from above (otherwise could just call step many times). + +Modify the handling of symbols grouped through BINCL/EINCL stabs to +allocate a partial symtab for each BINCL/EINCL grouping. This will +seriously decrease the size of inter-psymtab dependencies and hence +lessen the amount that needs to be read in when a new source file is +accessed. + +Work out some method of saving breakpoints across the reloading of an +executable. Probably this should be by saving the commands by which +the breakpoints were set and re-executing them (as text locations may +change). + +Do an "x/i $pc" after each stepi or nexti. + +Modify all of the disassemblers to use printf_filtered to get correct +more filtering. + +Modify gdb to work correctly with Pascal. + +Rewrite macros that handle frame chaining and frameless functions. +They should be able to tell the difference between start, main, and a +frameless function called from main. + +Work out what information would need to be included in an executable +by the compiler to allow gdb to debug functions which do not have a +frame pointer. Modify gdb and gcc to do this. + +When `attached' to a program (via either OS support or remote +debugging), gdb should arrange to catch signals which the terminal +might send, as it is unlikely that the program will be able to notice +them. SIGINT and SIGTSTP are obvious examples. + +Enhance the gdb manual with extra examples where needed. + +Arrange for list_command not to use decode_line_1 and thus not require +symbols to be read in simply to read a source file. + +Problem in xgdb; the readline library needs the terminal in CBREAK +mode for command line editing, but this makes it difficult to dispatch +on button presses. Possible solution: use a define to replace getc in +readline.c with a routine that does button dispatches. You should +probably see XGDB-README before you fiddle with XGDB. Also, someone +is implementing a new xgdb; it may not be worth while fiddling with +the old one. + +# Local Variables: +# mode: text +# End: diff --git a/gnu/usr.bin/gdb/README.gnu b/gnu/usr.bin/gdb/README.gnu new file mode 100644 index 0000000..fa54dec --- /dev/null +++ b/gnu/usr.bin/gdb/README.gnu @@ -0,0 +1,142 @@ +This is GDB, the GNU source-level debugger, presently running under un*x. + +Before compiling GDB, you must tell GDB what kind of machine you are +running on. To do this, type `config.gdb machine', where machine is +something like `vax' or `sun2'. For a list of valid machine types, +type `config.gdb'. + +Normally config.gdb edits the makefile as necessary. If you have to +edit the makefile on a standard machine listed in config.gdb this +should be considered a bug and reported as such. + +Once these files are set up, just `make' will do everything, +producing an executable `gdb' in this directory. + +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. +The gdb.texinfo file requires the texinfo-format-buffer command from +emacs 18.55 or later. + +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), 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 -gg format... + +Currently GDB version 3.x does *not* support GCC's -gg format. This +is because it (in theory) has fast enough startup on dbx debugging +format object files that -gg format is unnecessary (and hence +undesirable, since it wastes space and processing power in gcc). I +would like to hear people's opinions on the amount of time currently +spent in startup; is it fast enough? + +About remote debugging... + +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. + +About reporting bugs... + +The correct address for reporting bugs found with gdb is +"bug-gdb@prep.ai.mit.edu". Please send all bugs to that address. + +About xgdb... + +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. 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. +Comments on this mode are welcome. + +About the machine-dependent files... + +m-<machine>.h (param.h is a link to this file). +This file contains macro definitions that express information +about the machine's registers, stack frame format and instructions. + +<machine>-opcode.h (opcode.h is a link to this file). +<machine>-pinsn.c (pinsn.c is a link to this file). +These files contain the information necessary to print instructions +for your cpu type. + +<machine>-dep.c (dep.c is a link to this file). +Those routines which provide a low level interface to ptrace and which +tend to be machine-dependent. (The machine-independent routines are in +`infrun.c' and `inflow.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. + +Please try to avoid making machine-specific changes to +machine-independent files (i.e. all files except "param.h" and +"dep.c". "pinsn.c" and "opcode.h" are processor-specific but not +operating system-dependent). 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 +param.h) rather than something like #if defined(vax) or #if +defined(SYSV). + +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, if something needs to be +changed in read_inferior_memory, it is very painful because there is a +copy in every dep.c file. The correct way to do this is to put (in +this case) the standard ptrace interfaces in a separate file ptrace.c, +which is used by all systems which have ptrace. ptrace.c would deal +with variations between systems the same way any system-independent +file would (hooks, #if defined, etc.). + +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. + +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 more details. + diff --git a/gnu/usr.bin/gdb/XGdbinit.samp b/gnu/usr.bin/gdb/XGdbinit.samp new file mode 100644 index 0000000..a99f106 --- /dev/null +++ b/gnu/usr.bin/gdb/XGdbinit.samp @@ -0,0 +1,15 @@ +button "show" push-to-file %S +button "back" pop-file +button "break in" break %S +button "break at" break %l +button delete delete %b%e +button backtrace +button up +button down +button print print %E +button print* print *(%E) +button next +button step +button "do upto" until %l%e +button finish +button continue cont%e diff --git a/gnu/usr.bin/gdb/Xgdb.ad b/gnu/usr.bin/gdb/Xgdb.ad new file mode 100644 index 0000000..5f9fe99 --- /dev/null +++ b/gnu/usr.bin/gdb/Xgdb.ad @@ -0,0 +1,8 @@ +Xgdb*geometry: 580x874-0+28 +Xgdb*src*scrollVertical: whenneeded +Xgdb*src*scrollHorizontal: whenneeded +Xgdb*src*wrap: never +Xgdb*src*editType: read +Xgdb*frame.buttons.allowResize: true +Xgdb*frame.buttons.skipAdjust: true +Xgdb*frame*showGrip: false diff --git a/gnu/usr.bin/gdb/blockframe.c b/gnu/usr.bin/gdb/blockframe.c new file mode 100644 index 0000000..236d1cd --- /dev/null +++ b/gnu/usr.bin/gdb/blockframe.c @@ -0,0 +1,622 @@ +/*- + * This code is derived from software copyrighted by the Free Software + * Foundation. + * + * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. + * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory. + */ + +#ifndef lint +static char sccsid[] = "@(#)blockframe.c 6.4 (Berkeley) 5/11/91"; +#endif /* not lint */ + +/* 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 <obstack.h> + +#if defined(NEWVM) && defined(KERNELDEBUG) +#include <sys/param.h> /* XXX for FRAME_CHAIN_VALID */ +#endif + +/* 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? */ +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; + +struct block *block_for_pc (); +CORE_ADDR get_pc_function_start (); + +/* + * 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. */ + +/* Many machines which allow frameless functions can detect them using + this macro. Such machines should define FRAMELESS_FUNCTION_INVOCATION + to just call this macro. */ +#define FRAMELESS_LOOK_FOR_PROLOGUE(FI, FRAMELESS) \ +{ \ + CORE_ADDR func_start, after_prologue; \ + func_start = (get_pc_function_start ((FI)->pc) + \ + FUNCTION_START_OFFSET); \ + if (func_start) \ + { \ + after_prologue = func_start; \ + SKIP_PROLOGUE (after_prologue); \ + (FRAMELESS) = (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. */ \ + (FRAMELESS) = 0; \ +} + +/* 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) + { + if (!have_inferior_p () && !have_core_file_p ()) + fatal ("get_prev_frame_info: Called before cache primed. \"Shouldn't happen.\""); + else + error ("No inferior or core file."); + } + + 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 param.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; + /* If this frame is a leaf, this will be superceeded by the + code below. */ + address = FRAME_CHAIN_COMBINE (address, next_frame); + } + if (address == 0) + return 0; + + 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. */ + prev->pc = (fromleaf ? SAVED_PC_AFTER_CALL (next_frame) : + next_frame ? FRAME_SAVED_PC (next_frame) : read_pc ()); + + return prev; +} + +CORE_ADDR +get_frame_pc (frame) + FRAME frame; +{ + struct frame_info *fi; + fi = get_frame_info (frame); + return fi->pc; +} + +/* 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); +} + +/* 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 innermost lexical block containing the specified pc value, + or 0 if there is none. */ + +extern struct symtab *psymtab_to_symtab (); + +struct block * +block_for_pc (pc) + register CORE_ADDR pc; +{ + register struct block *b; + register int bot, top, half; + register struct symtab *s; + register struct partial_symtab *ps; + struct blockvector *bl; + + /* First search all symtabs for one whose file contains our pc */ + + for (s = symtab_list; s; s = s->next) + { + bl = BLOCKVECTOR (s); + b = BLOCKVECTOR_BLOCK (bl, 0); + if (BLOCK_START (b) <= pc + && BLOCK_END (b) > pc) + break; + } + + if (s == 0) + for (ps = partial_symtab_list; ps; ps = ps->next) + { + if (ps->textlow <= pc + && ps->texthigh > pc) + { + if (ps->readin) + fatal ("Internal error: pc found in readin psymtab and not in any symtab."); + s = psymtab_to_symtab (ps); + bl = BLOCKVECTOR (s); + b = BLOCKVECTOR_BLOCK (bl, 0); + break; + } + } + + if (s == 0) + return 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) + return b; + bot--; + } + + 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); +} + +/* 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 = find_pc_psymtab (pc); + struct symbol *f; + int miscfunc; + struct partial_symbol *psb; + + 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 availible symbol. */ + if (name != 0) + *name = 0; + if (address != 0) + *address = 0; + return 0; + } + + if (name) + *name = SYMBOL_NAME (f); + if (address) + *address = BLOCK_START (SYMBOL_BLOCK_VALUE (f)); + 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(psb) + < misc_function_vector[miscfunc].address))) + { + if (address) + *address = misc_function_vector[miscfunc].address; + if (name) + *name = misc_function_vector[miscfunc].name; + return 1; + } + else + { + if (address) + *address = SYMBOL_VALUE (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 (address) + *address = misc_function_vector[miscfunc].address; + if (name) + *name = misc_function_vector[miscfunc].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; + register int distance; + + /* 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; + distance = misc_function_vector[new].address - pc; + if (distance == 0) + return new; /* an exact match */ + else if (distance > 0) + 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/gnu/usr.bin/gdb/breakpoint.c b/gnu/usr.bin/gdb/breakpoint.c new file mode 100644 index 0000000..b515ed3 --- /dev/null +++ b/gnu/usr.bin/gdb/breakpoint.c @@ -0,0 +1,1383 @@ +/*- + * This code is derived from software copyrighted by the Free Software + * Foundation. + * + * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. + * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory. + */ + +#ifndef lint +static char sccsid[] = "@(#)breakpoint.c 6.3 (Berkeley) 5/8/91"; +#endif /* not lint */ + +/* Everything about breakpoints, for GDB. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <stdio.h> +#include "defs.h" +#include "param.h" +#include "symtab.h" +#include "frame.h" + +/* This is the sequence of bytes we insert for a breakpoint. */ + +static char break_insn[] = BREAKPOINT; + +/* 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 */ + +struct breakpoint +{ + struct breakpoint *next; + /* Number assigned to distinguish breakpoints. */ + int number; + /* Address to break at. */ + CORE_ADDR address; + /* Line number of this address. Redundant. */ + int line_number; + /* Symtab of file of this address. Redundant. */ + 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. */ + char shadow_contents[sizeof break_insn]; + /* Nonzero if this breakpoint is now inserted. */ + char inserted; + /* Nonzero if this is not the first breakpoint in the list + for the given address. */ + 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; +}; + +#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; + +/* 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; + +/* Remaining commands (not yet executed) + of last breakpoint hit. */ + +struct command_line *breakpoint_commands; + +static void delete_breakpoint (); +void clear_momentary_breakpoints (); +void breakpoint_auto_delete (); + +/* Flag indicating extra verbosity for xgdb. */ +extern int xgdb_verbose; + +/* 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; + register char *p; + register int bnum; + register struct expression *expr; + + if (arg == 0) + error_no_arg ("breakpoint number"); + + p = arg; + while (*p >= '0' && *p <= '9') p++; + if (p == arg) + /* There is no number here. (e.g. "cond a == b"). */ + error_no_arg ("breakpoint number"); + bnum = atoi (arg); + + ALL_BREAKPOINTS (b) + if (b->number == bnum) + { + if (b->cond) + { + free (b->cond); + b->cond = 0; /* parse_c_1 can leave this unchanged. */ + } + if (*p == 0) + { + b->cond = 0; + if (from_tty) + printf ("Breakpoint %d now unconditional.\n", bnum); + } + else + { + if (*p != ' ' && *p != '\t') + error ("Arguments must be an integer (breakpoint number) and an expression."); + + /* Find start of expression */ + while (*p == ' ' || *p == '\t') p++; + + arg = p; + b->cond = (struct expression *) 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; + register char *p, *p1; + 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 (breakpoint_commands) + error ("Can't use the \"commands\" command among a breakpoint's commands."); + + /* Allow commands by itself to refer to the last breakpoint. */ + if (arg == 0) + bnum = breakpoint_count; + else + { + p = arg; + if (! (*p >= '0' && *p <= '9')) + error ("Argument must be integer (a breakpoint number)."); + + while (*p >= '0' && *p <= '9') p++; + if (*p) + error ("Unexpected extra arguments following breakpoint number."); + + bnum = atoi (arg); + } + + ALL_BREAKPOINTS (b) + if (b->number == bnum) + { + if (from_tty && 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 (from_tty); + free_command_lines (b->commands); + b->commands = l; + return; + } + error ("No breakpoint number %d.", bnum); +} + +/* Called from command loop to execute the commands + associated with the breakpoint we just stopped at. */ + +void +do_breakpoint_commands () +{ + struct command_line *cmd; + + while (cmd = breakpoint_commands) + { + breakpoint_commands = 0; + execute_command_lines(cmd); + /* If command was "cont", breakpoint_commands is now 0, + of if we stopped at yet another breakpoint which has commands, + it is now the commands for the new breakpoint. */ + } + clear_momentary_breakpoints (); +} + +/* Used when the program is proceeded, to eliminate any remaining + commands attached to the previous breakpoint we stopped at. */ + +void +clear_breakpoint_commands () +{ + breakpoint_commands = 0; + breakpoint_auto_delete (0); +} + +/* Functions to get and set the current list of pending + breakpoint commands. These are used by run_stack_dummy + to preserve the commands around a function call. */ + +struct command_line * +get_breakpoint_commands () +{ + return breakpoint_commands; +} + +void +set_breakpoint_commands (cmds) + struct command_line *cmds; +{ + breakpoint_commands = cmds; +} + +/* 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; + +#ifdef BREAKPOINT_DEBUG + printf ("Inserting breakpoints.\n"); +#endif /* BREAKPOINT_DEBUG */ + + ALL_BREAKPOINTS (b) + if (b->enable != disabled && ! b->inserted && ! b->duplicate) + { + read_memory (b->address, b->shadow_contents, sizeof break_insn); + val = write_memory (b->address, break_insn, sizeof break_insn); + if (val) + return val; +#ifdef BREAKPOINT_DEBUG + printf ("Inserted breakpoint at 0x%x, shadow 0x%x, 0x%x.\n", + b->address, b->shadow_contents[0], b->shadow_contents[1]); +#endif /* BREAKPOINT_DEBUG */ + b->inserted = 1; + } + return 0; +} + +int +remove_breakpoints () +{ + register struct breakpoint *b; + int val; + +#ifdef BREAKPOINT_DEBUG + printf ("Removing breakpoints.\n"); +#endif /* BREAKPOINT_DEBUG */ + + ALL_BREAKPOINTS (b) + if (b->inserted) + { + val = write_memory (b->address, b->shadow_contents, sizeof break_insn); + 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; +} + +/* Evaluate the expression EXP and return 1 if value is zero. + This is used inside a catch_errors to evaluate the breakpoint condition. */ + +int +breakpoint_cond_eval (exp) + struct expression *exp; +{ + return value_zerop (evaluate_expression (exp)); +} + +/* Return 0 if PC is not the address just after a breakpoint, + or -1 if breakpoint says do not stop now, + or -2 if breakpoint says it has deleted itself and don't stop, + or -3 if hit a breakpoint number -3 (delete when program stops), + or else the number of the breakpoint, + with 0x1000000 added (or subtracted, for a negative return value) for + a silent breakpoint. */ + +int +breakpoint_stop_status (pc, frame_address) + CORE_ADDR pc; + FRAME_ADDR frame_address; +{ + register struct breakpoint *b; + register int cont = 0; + + /* Get the address where the breakpoint would have been. */ + pc -= DECR_PC_AFTER_BREAK; + + ALL_BREAKPOINTS (b) + if (b->enable != disabled && b->address == pc) + { + if (b->frame && b->frame != frame_address) + cont = -1; + 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, b->cond, + "Error occurred in testing breakpoint condition."); + free_all_values (); + } + if (b->cond && value_zero) + { + cont = -1; + } + else if (b->ignore_count > 0) + { + b->ignore_count--; + cont = -1; + } + else + { + if (b->enable == temporary) + b->enable = disabled; + breakpoint_commands = b->commands; + if (b->silent + || (breakpoint_commands + && !strcmp ("silent", breakpoint_commands->line))) + { + if (breakpoint_commands) + breakpoint_commands = breakpoint_commands->next; + return (b->number > 0 ? + 0x1000000 + b->number : + b->number - 0x1000000); + } + return b->number; + } + } + } + + return cont; +} + +static void +breakpoint_1 (bnum) + int bnum; +{ + register struct breakpoint *b; + register struct command_line *l; + register struct symbol *sym; + CORE_ADDR last_addr = (CORE_ADDR)-1; + + ALL_BREAKPOINTS (b) + if (bnum == -1 || bnum == b->number) + { + printf_filtered ("#%-3d %c 0x%08x", b->number, + "nyod"[(int) b->enable], + 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 (" (", stdout); + } + fputs_filtered (b->symtab->filename, stdout); + printf_filtered (" line %d", b->line_number); + if (sym) fputs_filtered(")", stdout); + } + else + print_address_symbolic (b->address, stdout); + + printf_filtered ("\n"); + + if (b->ignore_count) + printf_filtered ("\tignore next %d hits\n", b->ignore_count); + if (b->frame) + printf_filtered ("\tstop only in stack frame at 0x%x\n", b->frame); + if (b->cond) + { + printf_filtered ("\tbreak only if "); + print_expression (b->cond, stdout); + printf_filtered ("\n"); + } + if (l = b->commands) + while (l) + { + printf_filtered ("\t%s\n", l->line); + l = l->next; + } + } + + /* Compare against (CORE_ADDR)-1 in case some compiler decides + 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) + char *bnum_exp; +{ + int bnum = -1; + + if (bnum_exp) + bnum = parse_and_eval_address (bnum_exp); + else if (breakpoint_chain == 0) + printf_filtered ("No breakpoints.\n"); + else + printf_filtered ("Breakpoints:\n\ +Num Enb Address Where\n"); + + breakpoint_1 (bnum); +} + +/* 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; + + /* 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; + } +} + +/* Set a breakpoint from a symtab and line. + If TEMPFLAG is nonzero, it is a temporary breakpoint. + Print the same confirmation messages that the breakpoint command prints. */ + +void +set_breakpoint (s, line, tempflag) + struct symtab *s; + int line; + int tempflag; +{ + 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); + b->number = ++breakpoint_count; + b->cond = 0; + 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"); + } +} + +/* 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; + char *save_arg; + 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 *) + malloc (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 + /* 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, 0, 0); + + 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); +} + +static 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); +} + +/* + * 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, 0, 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); +} + +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 *) malloc (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 + && (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) + error ("No breakpoint at %s.", arg); + + 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 number BNUM if it is a `delete' breakpoint. + This is called after breakpoint BNUM has been hit. + Also delete any breakpoint numbered -3 unless there are breakpoint + commands to be executed. */ + +void +breakpoint_auto_delete (bnum) + int bnum; +{ + register struct breakpoint *b; + if (bnum != 0) + ALL_BREAKPOINTS (b) + if (b->number == bnum) + { + if (b->enable == delete) + delete_breakpoint (b); + break; + } + if (breakpoint_commands == 0) + clear_momentary_breakpoints (); +} + +static void +delete_breakpoint (bpt) + struct breakpoint *bpt; +{ + register struct breakpoint *b; + + if (bpt->inserted) + write_memory (bpt->address, bpt->shadow_contents, sizeof break_insn); + + 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 (xgdb_verbose && bpt->number >=0) + printf ("breakpoint #%d deleted\n", bpt->number); + + free (bpt); +} + +static void map_breakpoint_numbers (); + +static void +delete_command (arg, from_tty) + char *arg; + int from_tty; +{ + register struct breakpoint *b, *b1; + + if (arg == 0) + { + /* Ask user only if there are some breakpoints to delete. */ + if (!from_tty + || breakpoint_chain && query ("Delete all breakpoints? ")) + { + /* No arg; clear all breakpoints. */ + while (breakpoint_chain) + delete_breakpoint (breakpoint_chain); + } + } + else + map_breakpoint_numbers (arg, delete_breakpoint); +} + +/* Delete all breakpoints. + Done when new symtabs are loaded, since the break condition expressions + may become invalid, and the breakpoints are probably wrong anyway. */ + +void +clear_breakpoints () +{ + delete_command (0, 0); +} + +/* 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; +{ + register char *p = args; + register int num; + + if (p == 0) + error_no_arg ("a breakpoint number"); + + while (*p >= '0' && *p <= '9') p++; + if (*p && *p != ' ' && *p != '\t') + error ("First argument must be a breakpoint number."); + + num = atoi (args); + + 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; + register char *p1; + register int num; + register struct breakpoint *b; + + if (p == 0) + error_no_arg ("one or more breakpoint numbers"); + + while (*p) + { + p1 = p; + while (*p1 >= '0' && *p1 <= '9') p1++; + if (*p1 && *p1 != ' ' && *p1 != '\t') + error ("Arguments must be breakpoint numbers."); + + num = atoi (p); + + ALL_BREAKPOINTS (b) + if (b->number == num) + { + function (b); + goto win; + } + printf ("No breakpoint number %d.\n", num); + win: + p = p1; + while (*p == ' ' || *p == '\t') p++; + } +} + +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); +} + +static void +enable_command (args) + char *args; +{ + 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) + char *args; +{ + 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) + char *args; +{ + 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) + char *args; +{ + 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, 0, 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; + 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 or auto-display expressions.\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.\n\ +\n\ +The \"display\" subcommand applies to auto-displays instead of breakpoints.", + &enablelist, "enable ", 1, &cmdlist); + + add_abbrev_prefix_cmd ("breakpoints", class_breakpoint, enable_command, + "Enable some breakpoints or auto-display expressions.\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\ +May be abbreviates to simply \"enable\".\n\ +With a subcommand you can enable temporarily.", + &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 or auto-display expressions.\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\ +\n\ +The \"display\" subcommand applies to auto-displays instead of breakpoints.", + &disablelist, "disable ", 1, &cmdlist); + add_com_alias ("dis", "disable", class_breakpoint, 1); + add_com_alias ("disa", "disable", class_breakpoint, 1); + + add_abbrev_cmd ("breakpoints", class_breakpoint, disable_command, + "Disable some breakpoints or auto-display expressions.\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."); +} + diff --git a/gnu/usr.bin/gdb/command.c b/gnu/usr.bin/gdb/command.c new file mode 100644 index 0000000..79daea4 --- /dev/null +++ b/gnu/usr.bin/gdb/command.c @@ -0,0 +1,856 @@ +/* Library for reading command lines and decoding commands. + 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. */ + +#include "command.h" +#include "defs.h" +#include <stdio.h> +#include <ctype.h> + +extern char *xmalloc (); + +/* Add element named NAME to command list *LIST. + FUN should be the function to execute the command; + it will get a character string as argument, with leading + and trailing blanks already eliminated. + + DOC is a documentation string for the command. + Its first line should be a complete sentence. + It should start with ? for a command that is an abbreviation + or with * for a command that most users don't need to know about. */ + +struct cmd_list_element * +add_cmd (name, class, fun, doc, list) + char *name; + int class; + void (*fun) (); + char *doc; + struct cmd_list_element **list; +{ + register struct cmd_list_element *c + = (struct cmd_list_element *) xmalloc (sizeof (struct cmd_list_element)); + + delete_cmd (name, list); + c->next = *list; + c->name = savestring (name, strlen (name)); + c->class = class; + c->function = fun; + c->doc = doc; + c->prefixlist = 0; + c->allow_unknown = 0; + c->abbrev_flag = 0; + c->aux = 0; + *list = c; + return c; +} + +/* Same as above, except that the abbrev_flag is set. */ + +struct cmd_list_element * +add_abbrev_cmd (name, class, fun, doc, list) + char *name; + int class; + void (*fun) (); + char *doc; + struct cmd_list_element **list; +{ + register struct cmd_list_element *c + = (struct cmd_list_element *) xmalloc (sizeof (struct cmd_list_element)); + + delete_cmd (name, list); + c->next = *list; + c->name = savestring (name, strlen (name)); + c->class = class; + c->function = fun; + c->doc = doc; + c->prefixlist = 0; + c->allow_unknown = 0; + c->abbrev_flag = 1; + c->aux = 0; + *list = c; + return c; +} + +struct cmd_list_element * +add_alias_cmd (name, oldname, class, abbrev_flag, list) + char *name; + char *oldname; + int class; + int abbrev_flag; + struct cmd_list_element **list; +{ + /* Must do this since lookup_cmd tries to side-effect its first arg */ + char *copied_name; + register struct cmd_list_element *old; + register struct cmd_list_element *c; + copied_name = (char *) alloca (strlen (oldname) + 1); + strcpy (copied_name, oldname); + old = lookup_cmd (&copied_name, *list, 0, 1, 1); + + if (old == 0) + { + delete_cmd (name, list); + return 0; + } + + c = add_cmd (name, class, old->function, old->doc, list); + c->prefixlist = old->prefixlist; + c->prefixname = old->prefixname; + c->allow_unknown = old->allow_unknown; + c->abbrev_flag = abbrev_flag; + c->aux = old->aux; + return c; +} + +/* Like add_cmd but adds an element for a command prefix: + a name that should be followed by a subcommand to be looked up + in another command list. PREFIXLIST should be the address + of the variable containing that list. */ + +struct cmd_list_element * +add_prefix_cmd (name, class, fun, doc, prefixlist, prefixname, + allow_unknown, list) + char *name; + int class; + void (*fun) (); + char *doc; + struct cmd_list_element **prefixlist; + char *prefixname; + int allow_unknown; + struct cmd_list_element **list; +{ + register struct cmd_list_element *c = add_cmd (name, class, fun, doc, list); + c->prefixlist = prefixlist; + c->prefixname = prefixname; + c->allow_unknown = allow_unknown; + return c; +} + +/* Like add_prefix_cmd butsets the abbrev_flag on the new command. */ + +struct cmd_list_element * +add_abbrev_prefix_cmd (name, class, fun, doc, prefixlist, prefixname, + allow_unknown, list) + char *name; + int class; + void (*fun) (); + char *doc; + struct cmd_list_element **prefixlist; + char *prefixname; + int allow_unknown; + struct cmd_list_element **list; +{ + register struct cmd_list_element *c = add_cmd (name, class, fun, doc, list); + c->prefixlist = prefixlist; + c->prefixname = prefixname; + c->allow_unknown = allow_unknown; + c->abbrev_flag = 1; + return c; +} + +/* Remove the command named NAME from the command list. */ + +void +delete_cmd (name, list) + char *name; + struct cmd_list_element **list; +{ + register struct cmd_list_element *c; + + while (*list && !strcmp ((*list)->name, name)) + { + *list = (*list)->next; + } + + if (*list) + for (c = *list; c->next;) + { + if (!strcmp (c->next->name, name)) + c->next = c->next->next; + else + c = c->next; + } +} + +void help_cmd (), help_list (), help_cmd_list (); + +/* This command really has to deal with two things: + * 1) I want documentation on *this string* (usually called by + * "help commandname"). + * 2) I want documentation on *this list* (usually called by + * giving a command that requires subcommands. Also called by saying + * just "help".) + * + * I am going to split this into two seperate comamnds, help_cmd and + * help_list. + */ + +void +help_cmd (command, stream) + char *command; + FILE *stream; +{ + struct cmd_list_element *c; + extern struct cmd_list_element *cmdlist; + + if (!command) + { + help_list (cmdlist, "", -2, stream); + return; + } + + c = lookup_cmd (&command, cmdlist, "", 0, 0); + + if (c == 0) + return; + + /* There are three cases here. + If c->prefixlist is nonzer, we have a prefix command. + Print its documentation, then list its subcommands. + + If c->function is nonzero, we really have a command. + Print its documentation and return. + + If c->function is zero, we have a class name. + Print its documentation (as if it were a command) + and then set class to he number of this class + so that the commands in the class will be listed. */ + + fputs_filtered (c->doc, stream); + fputs_filtered ("\n", stream); + + if (c->prefixlist == 0 && c->function != 0) + return; + fprintf_filtered (stream, "\n"); + + /* If this is a prefix command, print it's subcommands */ + if (c->prefixlist) + help_list (*c->prefixlist, c->prefixname, -1, stream); + + /* If this is a class name, print all of the commands in the class */ + if (c->function == 0) + help_list (cmdlist, "", c->class, stream); +} + +/* + * Get a specific kind of help on a command list. + * + * LIST is the list. + * CMDTYPE is the prefix to use in the title string. + * CLASS is the class with which to list the nodes of this list (see + * documentation for help_cmd_list below), As usual, -1 for + * everything, -2 for just classes, and non-negative for only things + * in a specific class. + * and STREAM is the output stream on which to print things. + * If you call this routine with a class >= 0, it recurses. + */ +void +help_list (list, cmdtype, class, stream) + struct cmd_list_element *list; + char *cmdtype; + int class; + FILE *stream; +{ + int len; + char *cmdtype1, *cmdtype2; + + /* If CMDTYPE is "foo ", CMDTYPE1 gets " foo" and CMDTYPE2 gets "foo sub" */ + len = strlen (cmdtype); + cmdtype1 = (char *) alloca (len + 1); + cmdtype1[0] = 0; + cmdtype2 = (char *) alloca (len + 4); + cmdtype2[0] = 0; + if (len) + { + cmdtype1[0] = ' '; + strncpy (cmdtype1 + 1, cmdtype, len - 1); + cmdtype1[len] = 0; + strncpy (cmdtype2, cmdtype, len - 1); + strcpy (cmdtype2 + len - 1, " sub"); + } + + if (class == -2) + fprintf_filtered (stream, "List of classes of %scommands:\n\n", cmdtype2); + else + fprintf_filtered (stream, "List of %scommands:\n\n", cmdtype2); + + help_cmd_list (list, class, cmdtype, (class >= 0), stream); + + if (class == -2) + fprintf_filtered (stream, "\n\ +Type \"help%s\" followed by a class name for a list of commands in that class.", + cmdtype1); + + fprintf_filtered (stream, "\n\ +Type \"help%s\" followed by %scommand name for full documentation.\n\ +Command name abbreviations are allowed if unambiguous.\n", + cmdtype1, cmdtype2); +} + + +/* + * Implement a help command on command list LIST. + * RECURSE should be non-zero if this should be done recursively on + * all sublists of LIST. + * PREFIX is the prefix to print before each command name. + * STREAM is the stream upon which the output should be written. + * CLASS should be: + * A non-negative class number to list only commands in that + * class. + * -1 to list all commands in list. + * -2 to list all classes in list. + * + * Note that RECURSE will be active on *all* sublists, not just the + * ones seclected by the criteria above (ie. the selection mechanism + * is at the low level, not the high-level). + */ +void +help_cmd_list (list, class, prefix, recurse, stream) + struct cmd_list_element *list; + int class; + char *prefix; + int recurse; + FILE *stream; +{ + register struct cmd_list_element *c; + register char *p; + static char *line_buffer = 0; + static int line_size; + + if (!line_buffer) + { + line_size = 80; + line_buffer = (char *) xmalloc (line_size); + } + + for (c = list; c; c = c->next) + { + if (c->abbrev_flag == 0 && + (class == -1 + || (class == -2 && c->function == 0) + || (class == c->class && c->function != 0))) + { + fprintf_filtered (stream, "%s%s -- ", prefix, c->name); + /* Print just the first line */ + p = c->doc; + while (*p && *p != '\n') p++; + if (p - c->doc > line_size - 1) + { + line_size = p - c->doc + 1; + free (line_buffer); + line_buffer = (char *) xmalloc (line_size); + } + strncpy (line_buffer, c->doc, p - c->doc); + line_buffer[p - c->doc] = '\0'; + fputs_filtered (line_buffer, stream); + fputs_filtered ("\n", stream); + } + if (recurse + && c->prefixlist != 0 + && c->abbrev_flag == 0) + help_cmd_list (*c->prefixlist, class, c->prefixname, 1, stream); + } +} + +/* This routine takes a line of TEXT and a CLIST in which to + start the lookup. When it returns it will have incremented the text + pointer past the section of text it matched, set *RESULT_LIST to + the list in which the last word was matched, and will return the + cmd list element which the text matches. It will return 0 if no + match at all was possible. It will return -1 if ambigous matches are + possible; in this case *RESULT_LIST will be set to the list in which + there are ambiguous choices (and text will be set to the ambiguous + text string). + + It does no error reporting whatsoever; control will always return + to the superior routine. + + In the case of an ambiguous return (-1), *RESULT_LIST will be set to + point at the prefix_command (ie. the best match) *or* (special + case) will be 0 if no prefix command was ever found. For example, + in the case of "info a", "info" matches without ambiguity, but "a" + could be "args" or "address", so *RESULT_LIST is set to + the cmd_list_element for "info". So in this case + result list should not be interpeted as a pointer to the beginning + of a list; it simply points to a specific command. + + This routine does *not* modify the text pointed to by TEXT. + + If INGNORE_HELP_CLASSES is nonzero, ignore any command list + elements which are actually help classes rather than commands (i.e. + the function field of the struct cmd_list_element is 0). */ + +struct cmd_list_element * +lookup_cmd_1 (text, clist, result_list, ignore_help_classes) + char **text; + struct cmd_list_element *clist, **result_list; + int ignore_help_classes; +{ + char *p, *command; + int len, tmp, nfound; + struct cmd_list_element *found, *c; + + while (**text == ' ' || **text == '\t') + (*text)++; + + /* Treating underscores as part of command words is important + so that "set args_foo()" doesn't get interpreted as + "set args _foo()". */ + for (p = *text; + *p && (isalnum(*p) || *p == '-' || *p == '_'); + p++) + ; + + /* If nothing but whitespace, return 0. */ + if (p == *text) + return 0; + + len = p - *text; + + /* *text and p now bracket the first command word to lookup (and + it's length is len). We copy this into a local temporary, + converting to lower case as we go. */ + + command = (char *) alloca (len + 1); + for (tmp = 0; tmp < len; tmp++) + { + char x = (*text)[tmp]; + command[tmp] = (x >= 'A' && x <= 'Z') ? x - 'A' + 'a' : x; + } + command[len] = '\0'; + + /* Look it up. */ + found = 0; + nfound = 0; + for (c = clist; c; c = c->next) + if (!strncmp (command, c->name, len) + && (!ignore_help_classes || c->function)) + { + found = c; + nfound++; + if (c->name[len] == '\0') + { + nfound = 1; + break; + } + } + + /* If nothing matches, we have a simple failure. */ + if (nfound == 0) + return 0; + + if (nfound > 1) + { + *result_list = 0; /* Will be modified in calling routine + if we know what the prefix command is. + */ + return (struct cmd_list_element *) -1; /* Ambiguous. */ + } + + /* We've matched something on this list. Move text pointer forward. */ + + *text = p; + if (found->prefixlist) + { + c = lookup_cmd_1 (text, *found->prefixlist, result_list, + ignore_help_classes); + if (!c) + { + /* Didn't find anything; this is as far as we got. */ + *result_list = clist; + return found; + } + else if (c == (struct cmd_list_element *) -1) + { + /* We've gotten this far properley, but the next step + is ambiguous. We need to set the result list to the best + we've found (if an inferior hasn't already set it). */ + if (!*result_list) + /* This used to say *result_list = *found->prefixlist + If that was correct, need to modify the documentation + at the top of this function to clarify what is supposed + to be going on. */ + *result_list = found; + return c; + } + else + { + /* We matched! */ + return c; + } + } + else + { + *result_list = clist; + return found; + } +} + +/* Look up the contents of *LINE as a command in the command list LIST. + LIST is a chain of struct cmd_list_element's. + If it is found, return the struct cmd_list_element for that command + and update *LINE to point after the command name, at the first argument. + If not found, call error if ALLOW_UNKNOWN is zero + otherwise (or if error returns) return zero. + Call error if specified command is ambiguous, + unless ALLOW_UNKNOWN is negative. + CMDTYPE precedes the word "command" in the error message. + + If INGNORE_HELP_CLASSES is nonzero, ignore any command list + elements which are actually help classes rather than commands (i.e. + the function field of the struct cmd_list_element is 0). */ + +struct cmd_list_element * +lookup_cmd (line, list, cmdtype, allow_unknown, ignore_help_classes) + char **line; + struct cmd_list_element *list; + char *cmdtype; + int allow_unknown; + int ignore_help_classes; +{ + struct cmd_list_element *last_list = 0; + struct cmd_list_element *c = + lookup_cmd_1 (line, list, &last_list, ignore_help_classes); + char *ptr = (*line) + strlen (*line) - 1; + + /* Clear off trailing whitespace. */ + while (ptr >= *line && (*ptr == ' ' || *ptr == '\t')) + ptr--; + *(ptr + 1) = '\0'; + + if (!c) + { + if (!allow_unknown) + { + if (!*line) + error ("Lack of needed %scommand", cmdtype); + else + { + char *p = *line, *q; + + while (isalnum(*p) || *p == '-') + p++; + + q = (char *) alloca (p - *line + 1); + strncpy (q, *line, p - *line); + q[p-*line] = '\0'; + + error ("Undefined %scommand: \"%s\".", cmdtype, q); + } + } + else + return 0; + } + else if (c == (struct cmd_list_element *) -1) + { + /* Ambigous. Local values should be off prefixlist or called + values. */ + int local_allow_unknown = (last_list ? last_list->allow_unknown : + allow_unknown); + char *local_cmdtype = last_list ? last_list->prefixname : cmdtype; + struct cmd_list_element *local_list = + (last_list ? *(last_list->prefixlist) : list); + + if (local_allow_unknown < 0) + { + if (last_list) + return last_list; /* Found something. */ + else + return 0; /* Found nothing. */ + } + else + { + /* Report as error. */ + int amb_len; + char ambbuf[100]; + + for (amb_len = 0; + ((*line)[amb_len] && (*line)[amb_len] != ' ' + && (*line)[amb_len] != '\t'); + amb_len++) + ; + + ambbuf[0] = 0; + for (c = local_list; c; c = c->next) + if (!strncmp (*line, c->name, amb_len)) + { + if (strlen (ambbuf) + strlen (c->name) + 6 < sizeof ambbuf) + { + if (strlen (ambbuf)) + strcat (ambbuf, ", "); + strcat (ambbuf, c->name); + } + else + { + strcat (ambbuf, ".."); + break; + } + } + error ("Ambiguous %scommand \"%s\": %s.", local_cmdtype, + *line, ambbuf); + } + } + else + { + /* We've got something. It may still not be what the caller + wants (if this command *needs* a subcommand). */ + while (**line == ' ' || **line == '\t') + (*line)++; + + if (c->prefixlist && **line && !c->allow_unknown) + error ("Undefined %scommand: \"%s\".", c->prefixname, *line); + + /* Seems to be what he wants. Return it. */ + return c; + } +} + +#if 0 +/* Look up the contents of *LINE as a command in the command list LIST. + LIST is a chain of struct cmd_list_element's. + If it is found, return the struct cmd_list_element for that command + and update *LINE to point after the command name, at the first argument. + If not found, call error if ALLOW_UNKNOWN is zero + otherwise (or if error returns) return zero. + Call error if specified command is ambiguous, + unless ALLOW_UNKNOWN is negative. + CMDTYPE precedes the word "command" in the error message. */ + +struct cmd_list_element * +lookup_cmd (line, list, cmdtype, allow_unknown) + char **line; + struct cmd_list_element *list; + char *cmdtype; + int allow_unknown; +{ + register char *p; + register struct cmd_list_element *c, *found; + int nfound; + char ambbuf[100]; + char *processed_cmd; + int i, cmd_len; + + /* Skip leading whitespace. */ + + while (**line == ' ' || **line == '\t') + (*line)++; + + /* Clear out trailing whitespace. */ + + p = *line + strlen (*line); + while (p != *line && (p[-1] == ' ' || p[-1] == '\t')) + p--; + *p = 0; + + /* Find end of command name. */ + + p = *line; + while (*p == '-' + || (*p >= 'a' && *p <= 'z') + || (*p >= 'A' && *p <= 'Z') + || (*p >= '0' && *p <= '9')) + p++; + + /* Look up the command name. + If exact match, keep that. + Otherwise, take command abbreviated, if unique. Note that (in my + opinion) a null string does *not* indicate ambiguity; simply the + end of the argument. */ + + if (p == *line) + { + if (!allow_unknown) + error ("Lack of needed %scommand", cmdtype); + return 0; + } + + /* Copy over to a local buffer, converting to lowercase on the way. + This is in case the command being parsed is a subcommand which + doesn't match anything, and that's ok. We want the original + untouched for the routine of the original command. */ + + processed_cmd = (char *) alloca (p - *line + 1); + for (cmd_len = 0; cmd_len < p - *line; cmd_len++) + { + char x = (*line)[cmd_len]; + if (x >= 'A' && x <= 'Z') + processed_cmd[cmd_len] = x - 'A' + 'a'; + else + processed_cmd[cmd_len] = x; + } + processed_cmd[cmd_len] = '\0'; + + /* Check all possibilities in the current command list. */ + found = 0; + nfound = 0; + for (c = list; c; c = c->next) + { + if (!strncmp (processed_cmd, c->name, cmd_len)) + { + found = c; + nfound++; + if (c->name[cmd_len] == 0) + { + nfound = 1; + break; + } + } + } + + /* Report error for undefined command name. */ + + if (nfound != 1) + { + if (nfound > 1 && allow_unknown >= 0) + { + ambbuf[0] = 0; + for (c = list; c; c = c->next) + if (!strncmp (processed_cmd, c->name, cmd_len)) + { + if (strlen (ambbuf) + strlen (c->name) + 6 < sizeof ambbuf) + { + if (strlen (ambbuf)) + strcat (ambbuf, ", "); + strcat (ambbuf, c->name); + } + else + { + strcat (ambbuf, ".."); + break; + } + } + error ("Ambiguous %scommand \"%s\": %s.", cmdtype, + processed_cmd, ambbuf); + } + else if (!allow_unknown) + error ("Undefined %scommand: \"%s\".", cmdtype, processed_cmd); + return 0; + } + + /* Skip whitespace before the argument. */ + + while (*p == ' ' || *p == '\t') p++; + *line = p; + + if (found->prefixlist && *p) + { + c = lookup_cmd (line, *found->prefixlist, found->prefixname, + found->allow_unknown); + if (c) + return c; + } + + return found; +} +#endif + +/* Helper function for SYMBOL_COMPLETION_FUNCTION. */ + +/* Return a vector of char pointers which point to the different + possible completions in LIST of TEXT. */ + +char ** +complete_on_cmdlist (list, text) + struct cmd_list_element *list; + char *text; +{ + struct cmd_list_element *ptr; + char **matchlist; + int sizeof_matchlist; + int matches; + int textlen = strlen (text); + + sizeof_matchlist = 10; + matchlist = (char **) xmalloc (sizeof_matchlist * sizeof (char *)); + matches = 0; + + for (ptr = list; ptr; ptr = ptr->next) + if (!strncmp (ptr->name, text, textlen) + && !ptr->abbrev_flag + && (ptr->function + || ptr->prefixlist)) + { + if (matches == sizeof_matchlist) + { + sizeof_matchlist *= 2; + matchlist = (char **) xrealloc (matchlist, + (sizeof_matchlist + * sizeof (char *))); + } + + matchlist[matches] = (char *) + xmalloc (strlen (ptr->name) + 1); + strcpy (matchlist[matches++], ptr->name); + } + + if (matches == 0) + { + free (matchlist); + matchlist = 0; + } + else + { + matchlist = (char **) xrealloc (matchlist, ((matches + 1) + * sizeof (char *))); + matchlist[matches] = (char *) 0; + } + + return matchlist; +} + +static void +shell_escape (arg, from_tty) + char *arg; + int from_tty; +{ + int rc, status, pid; + char *p, *user_shell; + extern char *rindex (); + + if ((user_shell = (char *) getenv ("SHELL")) == NULL) + user_shell = "/bin/sh"; + + /* Get the name of the shell for arg0 */ + if ((p = rindex (user_shell, '/')) == NULL) + p = user_shell; + else + p++; /* Get past '/' */ + + if ((pid = fork()) == 0) + { + if (!arg) + execl (user_shell, p, 0); + else + execl (user_shell, p, "-c", arg, 0); + + fprintf (stderr, "Exec of shell failed\n"); + exit (0); + } + + if (pid != -1) + while ((rc = wait (&status)) != pid && rc != -1) + ; + else + error ("Fork failed"); +} + +void +_initialize_command () +{ + add_com ("shell", class_support, shell_escape, + "Execute the rest of the line as a shell command. \n\ +With no arguments, run an inferior shell."); +} diff --git a/gnu/usr.bin/gdb/command.h b/gnu/usr.bin/gdb/command.h new file mode 100644 index 0000000..fe28aef --- /dev/null +++ b/gnu/usr.bin/gdb/command.h @@ -0,0 +1,77 @@ +/* Header file for command-reading library command.c. + 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. */ + +/* 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. */ + int class; + + /* Function definition of this command. + Zero for command class names and for help topics that + are not really commands. */ + void (*function) (); + + /* Documentation of this command (or help topic). + First line is brief documentation; remaining lines form, with it, + the full documentation. First line should end with a period. + Entire string should also end with a period, not a newline. */ + char *doc; + + /* Auxiliary information. + It is up to the calling program to decide what this means. */ + char *aux; + + /* Nonzero identifies a prefix command. For them, the address + of the variable containing the list of subcommands. */ + struct cmd_list_element **prefixlist; + + /* For prefix commands only: + String containing prefix commands to get here: this one + plus any others needed to get to it. Should end in a space. + It is used before the word "command" in describing the + commands reached through this prefix. */ + char *prefixname; + + /* For prefix commands only: + nonzero means do not get an error if subcommand is not + recognized; call the prefix's own function in that case. */ + char allow_unknown; + + /* Nonzero says this is an abbreviation, and should not + be mentioned in lists of commands. + This allows "br<tab>" to complete to "break", which it + otherwise wouldn't. */ + char abbrev_flag; + }; + +/* 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 *lookup_cmd (), *lookup_cmd_1 (); +extern char **complete_on_cmdlist (); +extern void delete_cmd (); +extern void help_cmd (); diff --git a/gnu/usr.bin/gdb/config/Makefile.i386 b/gnu/usr.bin/gdb/config/Makefile.i386 new file mode 100644 index 0000000..cc52aa3 --- /dev/null +++ b/gnu/usr.bin/gdb/config/Makefile.i386 @@ -0,0 +1,6 @@ +# @(#)Makefile.i386 6.2 (Berkeley) 3/21/91 + +CONFIGSRCS= i386bsd-dep.c i386-pinsn.c + +param.h: + ln -s $(.CURDIR)/config/m-i386bsd.h param.h diff --git a/gnu/usr.bin/gdb/config/default-dep.c b/gnu/usr.bin/gdb/config/default-dep.c new file mode 100644 index 0000000..13fe7b9 --- /dev/null +++ b/gnu/usr.bin/gdb/config/default-dep.c @@ -0,0 +1,585 @@ +/*- + * This code is derived from software copyrighted by the Free Software + * Foundation. + * + * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. + */ + +#ifndef lint +static char sccsid[] = "@(#)default-dep.c 6.3 (Berkeley) 5/8/91"; +#endif /* not lint */ + +/* Low level interface to ptrace, for GDB when running under Unix. + Copyright (C) 1988, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <stdio.h> +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" + +#ifdef USG +#include <sys/types.h> +#endif + +#include <sys/param.h> +#include <sys/dir.h> +#include <signal.h> +#include <sys/ioctl.h> +/* #include <fcntl.h> Can we live without this? */ + +#ifdef COFF_ENCAPSULATE +#include "a.out.encap.h" +#else +#include <a.out.h> +#endif +#ifndef N_SET_MAGIC +#define N_SET_MAGIC(exec, val) ((exec).a_magic = (val)) +#endif + +#include <sys/user.h> /* After a.out.h */ +#include <sys/file.h> +#include <sys/stat.h> + +extern int errno; + +/* This function simply calls ptrace with the given arguments. + It exists so that all calls to ptrace are isolated in this + machine-dependent file. */ +int +call_ptrace (request, pid, arg3, arg4) + int request, pid, arg3, arg4; +{ + return ptrace (request, pid, arg3, arg4); +} + +kill_inferior () +{ + if (remote_debugging) + return; + if (inferior_pid == 0) + return; + ptrace (8, inferior_pid, 0, 0); + wait (0); + inferior_died (); +} + +/* This is used when GDB is exiting. It gives less chance of error.*/ + +kill_inferior_fast () +{ + if (remote_debugging) + return; + if (inferior_pid == 0) + return; + ptrace (8, inferior_pid, 0, 0); + wait (0); +} + +/* Resume execution of the inferior process. + If STEP is nonzero, single-step it. + If SIGNAL is nonzero, give it that signal. */ + +void +resume (step, signal) + int step; + int signal; +{ + errno = 0; + if (remote_debugging) + remote_resume (step, signal); + else + { + ptrace (step ? 9 : 7, inferior_pid, 1, signal); + if (errno) + perror_with_name ("ptrace"); + } +} + +void +fetch_inferior_registers () +{ + register int regno; + register unsigned int regaddr; + char buf[MAX_REGISTER_RAW_SIZE]; + register int i; + + struct user u; + unsigned int offset = (char *) &u.u_ar0 - (char *) &u; + offset = ptrace (3, inferior_pid, offset, 0) - KERNEL_U_ADDR; + + for (regno = 0; regno < NUM_REGS; regno++) + { + regaddr = register_addr (regno, offset); + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int)) + { + *(int *) &buf[i] = ptrace (3, inferior_pid, regaddr, 0); + regaddr += sizeof (int); + } + supply_register (regno, buf); + } +} + +/* Store our register values back into the inferior. + If REGNO is -1, do this for all registers. + Otherwise, REGNO specifies which register (so we can save time). */ + +store_inferior_registers (regno) + int regno; +{ + register unsigned int regaddr; + char buf[80]; + + struct user u; + unsigned int offset = (char *) &u.u_ar0 - (char *) &u; + offset = ptrace (3, inferior_pid, offset, 0) - KERNEL_U_ADDR; + + if (regno >= 0) + { + regaddr = register_addr (regno, offset); + errno = 0; + ptrace (6, inferior_pid, regaddr, read_register (regno)); + if (errno != 0) + { + sprintf (buf, "writing register number %d", regno); + perror_with_name (buf); + } + } + else for (regno = 0; regno < NUM_REGS; regno++) + { + regaddr = register_addr (regno, offset); + errno = 0; + ptrace (6, inferior_pid, regaddr, read_register (regno)); + if (errno != 0) + { + sprintf (buf, "writing all regs, number %d", regno); + perror_with_name (buf); + } + } +} + +/* Copy LEN bytes from inferior's memory starting at MEMADDR + to debugger memory starting at MYADDR. + On failure (cannot read from inferior, usually because address is out + of bounds) returns the value of errno. */ + +int +read_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + register int i; + /* Round starting address down to longword boundary. */ + register CORE_ADDR addr = memaddr & - sizeof (int); + /* Round ending address up; get number of longwords that makes. */ + register int count + = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int); + /* Allocate buffer of that many longwords. */ + register int *buffer = (int *) alloca (count * sizeof (int)); + extern int errno; + + /* Read all the longwords */ + for (i = 0; i < count; i++, addr += sizeof (int)) + { + errno = 0; +#if 0 + /* This is now done by read_memory, because when this function did it, + reading a byte or short int hardware port read whole longs, causing + serious side effects + such as bus errors and unexpected hardware operation. This would + also be a problem with ptrace if the inferior process could read + or write hardware registers, but that's not usually the case. */ + if (remote_debugging) + buffer[i] = remote_fetch_word (addr); + else +#endif + buffer[i] = ptrace (1, inferior_pid, addr, 0); + if (errno) + return errno; + } + + /* Copy appropriate bytes out of the buffer. */ + bcopy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len); + return 0; +} + +/* Copy LEN bytes of data from debugger memory at MYADDR + to inferior's memory at MEMADDR. + On failure (cannot write the inferior) + returns the value of errno. */ + +int +write_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + register int i; + /* Round starting address down to longword boundary. */ + register CORE_ADDR addr = memaddr & - sizeof (int); + /* Round ending address up; get number of longwords that makes. */ + register int count + = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int); + /* Allocate buffer of that many longwords. */ + register int *buffer = (int *) alloca (count * sizeof (int)); + extern int errno; + + /* Fill start and end extra bytes of buffer with existing memory data. */ + + if (remote_debugging) + return (remote_write_inferior_memory(memaddr, myaddr, len)); + + buffer[0] = ptrace (1, inferior_pid, addr, 0); + + if (count > 1) + buffer[count - 1] = ptrace (1, inferior_pid, + addr + (count - 1) * sizeof (int), 0); + + /* Copy data to be written over corresponding part of buffer */ + + bcopy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len); + + /* Write the entire buffer. */ + + for (i = 0; i < count; i++, addr += sizeof (int)) + { + errno = 0; + ptrace (4, inferior_pid, addr, buffer[i]); + if (errno) + return errno; + } + + return 0; +} + +/* Work with core dump and executable files, for GDB. + This code would be in core.c if it weren't machine-dependent. */ + +#ifndef N_TXTADDR +#define N_TXTADDR(hdr) 0 +#endif /* no N_TXTADDR */ + +#ifndef N_DATADDR +#define N_DATADDR(hdr) hdr.a_text +#endif /* no N_DATADDR */ + +/* Make COFF and non-COFF names for things a little more compatible + to reduce conditionals later. */ + +#ifdef COFF_FORMAT +#define a_magic magic +#endif + +#ifndef COFF_FORMAT +#ifndef AOUTHDR +#define AOUTHDR struct exec +#endif +#endif + +extern char *sys_siglist[]; + + +/* Hook for `exec_file_command' command to call. */ + +extern void (*exec_file_display_hook) (); + +/* File names of core file and executable file. */ + +extern char *corefile; +extern char *execfile; + +/* Descriptors on which core file and executable file are open. + Note that the execchan is closed when an inferior is created + and reopened if the inferior dies or is killed. */ + +extern int corechan; +extern int execchan; + +/* Last modification time of executable file. + Also used in source.c to compare against mtime of a source file. */ + +extern int exec_mtime; + +/* Virtual addresses of bounds of the two areas of memory in the core file. */ + +extern CORE_ADDR data_start; +extern CORE_ADDR data_end; +extern CORE_ADDR stack_start; +extern CORE_ADDR stack_end; + +/* Virtual addresses of bounds of two areas of memory in the exec file. + Note that the data area in the exec file is used only when there is no core file. */ + +extern CORE_ADDR text_start; +extern CORE_ADDR text_end; + +extern CORE_ADDR exec_data_start; +extern CORE_ADDR exec_data_end; + +/* Address in executable file of start of text area data. */ + +extern int text_offset; + +/* Address in executable file of start of data area data. */ + +extern int exec_data_offset; + +/* Address in core file of start of data area data. */ + +extern int data_offset; + +/* Address in core file of start of stack area data. */ + +extern int stack_offset; + +#ifdef COFF_FORMAT +/* various coff data structures */ + +extern FILHDR file_hdr; +extern SCNHDR text_hdr; +extern SCNHDR data_hdr; + +#endif /* not COFF_FORMAT */ + +/* a.out header saved in core file. */ + +extern AOUTHDR core_aouthdr; + +/* a.out header of exec file. */ + +extern AOUTHDR exec_aouthdr; + +extern void validate_files (); + +core_file_command (filename, from_tty) + char *filename; + int from_tty; +{ + int val; + extern char registers[]; + + /* Discard all vestiges of any previous core file + and mark data and stack spaces as empty. */ + + if (corefile) + free (corefile); + corefile = 0; + + if (corechan >= 0) + close (corechan); + corechan = -1; + + data_start = 0; + data_end = 0; + stack_start = STACK_END_ADDR; + stack_end = STACK_END_ADDR; + + /* Now, if a new core file was specified, open it and digest it. */ + + if (filename) + { + filename = tilde_expand (filename); + make_cleanup (free, filename); + + if (have_inferior_p ()) + error ("To look at a core file, you must kill the inferior with \"kill\"."); + corechan = open (filename, O_RDONLY, 0); + if (corechan < 0) + perror_with_name (filename); + /* 4.2-style (and perhaps also sysV-style) core dump file. */ + { + struct user u; + + unsigned int reg_offset; + + val = myread (corechan, &u, sizeof u); + if (val < 0) + perror_with_name ("Not a core file: reading upage"); + if (val != sizeof u) + error ("Not a core file: could only read %d bytes", val); + + /* We are depending on exec_file_command having been called + previously to set exec_data_start. Since the executable + and the core file share the same text segment, the address + of the data segment will be the same in both. */ + data_start = exec_data_start; + + data_end = data_start + NBPG * u.u_dsize; + stack_start = stack_end - NBPG * u.u_ssize; + data_offset = NBPG * UPAGES; + stack_offset = NBPG * (UPAGES + u.u_dsize); + + /* Some machines put an absolute address in here and some put + the offset in the upage of the regs. */ + reg_offset = (int) u.u_ar0; + if (reg_offset > NBPG * UPAGES) + reg_offset -= KERNEL_U_ADDR; + + /* I don't know where to find this info. + So, for now, mark it as not available. */ + N_SET_MAGIC (core_aouthdr, 0); + + /* Read the register values out of the core file and store + them where `read_register' will find them. */ + + { + register int regno; + + for (regno = 0; regno < NUM_REGS; regno++) + { + char buf[MAX_REGISTER_RAW_SIZE]; + + val = lseek (corechan, register_addr (regno, reg_offset), 0); + if (val < 0 + || (val = myread (corechan, buf, sizeof buf)) < 0) + { + char * buffer = (char *) alloca (strlen (reg_names[regno]) + + 30); + strcpy (buffer, "Reading register "); + strcat (buffer, reg_names[regno]); + + perror_with_name (buffer); + } + + supply_register (regno, buf); + } + } + } + if (filename[0] == '/') + corefile = savestring (filename, strlen (filename)); + else + { + corefile = concat (current_directory, "/", filename); + } + + set_current_frame ( create_new_frame (read_register (FP_REGNUM), + read_pc ())); + select_frame (get_current_frame (), 0); + validate_files (); + } + else if (from_tty) + printf ("No core file now.\n"); +} + +exec_file_command (filename, from_tty) + char *filename; + int from_tty; +{ + int val; + + /* Eliminate all traces of old exec file. + Mark text segment as empty. */ + + if (execfile) + free (execfile); + execfile = 0; + data_start = 0; + data_end -= exec_data_start; + text_start = 0; + text_end = 0; + exec_data_start = 0; + exec_data_end = 0; + if (execchan >= 0) + close (execchan); + execchan = -1; + + /* Now open and digest the file the user requested, if any. */ + + if (filename) + { + filename = tilde_expand (filename); + make_cleanup (free, filename); + + execchan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0, + &execfile); + if (execchan < 0) + perror_with_name (filename); + +#ifdef COFF_FORMAT + { + int aout_hdrsize; + int num_sections; + + if (read_file_hdr (execchan, &file_hdr) < 0) + error ("\"%s\": not in executable format.", execfile); + + aout_hdrsize = file_hdr.f_opthdr; + num_sections = file_hdr.f_nscns; + + if (read_aout_hdr (execchan, &exec_aouthdr, aout_hdrsize) < 0) + error ("\"%s\": can't read optional aouthdr", execfile); + + if (read_section_hdr (execchan, _TEXT, &text_hdr, num_sections, + aout_hdrsize) < 0) + error ("\"%s\": can't read text section header", execfile); + + if (read_section_hdr (execchan, _DATA, &data_hdr, num_sections, + aout_hdrsize) < 0) + error ("\"%s\": can't read data section header", execfile); + + text_start = exec_aouthdr.text_start; + text_end = text_start + exec_aouthdr.tsize; + text_offset = text_hdr.s_scnptr; + exec_data_start = exec_aouthdr.data_start; + exec_data_end = exec_data_start + exec_aouthdr.dsize; + exec_data_offset = data_hdr.s_scnptr; + data_start = exec_data_start; + data_end += exec_data_start; + exec_mtime = file_hdr.f_timdat; + } +#else /* not COFF_FORMAT */ + { + struct stat st_exec; + +#ifdef HEADER_SEEK_FD + HEADER_SEEK_FD (execchan); +#endif + + val = myread (execchan, &exec_aouthdr, sizeof (AOUTHDR)); + + if (val < 0) + perror_with_name (filename); + + text_start = N_TXTADDR (exec_aouthdr); + exec_data_start = N_DATADDR (exec_aouthdr); + + text_offset = N_TXTOFF (exec_aouthdr); + exec_data_offset = N_TXTOFF (exec_aouthdr) + exec_aouthdr.a_text; + + text_end = 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; + + if (fstat (execchan, &st_exec) < 0) + perror_with_name (filename); + exec_mtime = st_exec.st_mtime; + } +#endif /* not COFF_FORMAT */ + + 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); +} diff --git a/gnu/usr.bin/gdb/config/i386-dep.c b/gnu/usr.bin/gdb/config/i386-dep.c new file mode 100644 index 0000000..c4630d0 --- /dev/null +++ b/gnu/usr.bin/gdb/config/i386-dep.c @@ -0,0 +1,1275 @@ +/* Low level interface to ptrace, for GDB when running on the Intel 386. + Copyright (C) 1988, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <stdio.h> +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" + +#ifdef USG +#include <sys/types.h> +#endif + +#include <sys/param.h> +#include <sys/dir.h> +#include <signal.h> +#include <sys/user.h> +#include <sys/ioctl.h> +#include <fcntl.h> + +#ifdef COFF_ENCAPSULATE +#include "a.out.encap.h" +#else +#include <a.out.h> +#endif + +#ifndef N_SET_MAGIC +#ifdef COFF_FORMAT +#define N_SET_MAGIC(exec, val) ((exec).magic = (val)) +#else +#define N_SET_MAGIC(exec, val) ((exec).a_magic = (val)) +#endif +#endif + +#include <sys/file.h> +#include <sys/stat.h> + +#include <sys/reg.h> + +extern int errno; + +/* This function simply calls ptrace with the given arguments. + It exists so that all calls to ptrace are isolated in this + machine-dependent file. */ +int +call_ptrace (request, pid, arg3, arg4) + int request, pid, arg3, arg4; +{ + return ptrace (request, pid, arg3, arg4); +} + +kill_inferior () +{ + if (remote_debugging) + return; + if (inferior_pid == 0) + return; + ptrace (8, inferior_pid, 0, 0); + wait (0); + inferior_died (); +} + +/* This is used when GDB is exiting. It gives less chance of error.*/ + +kill_inferior_fast () +{ + if (remote_debugging) + return; + if (inferior_pid == 0) + return; + ptrace (8, inferior_pid, 0, 0); + wait (0); +} + +/* Resume execution of the inferior process. + If STEP is nonzero, single-step it. + If SIGNAL is nonzero, give it that signal. */ + +void +resume (step, signal) + int step; + int signal; +{ + errno = 0; + if (remote_debugging) + remote_resume (step, signal); + else + { + ptrace (step ? 9 : 7, inferior_pid, 1, signal); + if (errno) + perror_with_name ("ptrace"); + } +} + +void +fetch_inferior_registers () +{ + register int regno; + register unsigned int regaddr; + char buf[MAX_REGISTER_RAW_SIZE]; + register int i; + + struct user u; + unsigned int offset = (char *) &u.u_ar0 - (char *) &u; + offset = ptrace (3, inferior_pid, offset, 0) - KERNEL_U_ADDR; + + for (regno = 0; regno < NUM_REGS; regno++) + { + regaddr = register_addr (regno, offset); + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int)) + { + *(int *) &buf[i] = ptrace (3, inferior_pid, regaddr, 0); + regaddr += sizeof (int); + } + supply_register (regno, buf); + } +} + +/* Store our register values back into the inferior. + If REGNO is -1, do this for all registers. + Otherwise, REGNO specifies which register (so we can save time). */ + +store_inferior_registers (regno) + int regno; +{ + register unsigned int regaddr; + char buf[80]; + + struct user u; + unsigned int offset = (char *) &u.u_ar0 - (char *) &u; + offset = ptrace (3, inferior_pid, offset, 0) - KERNEL_U_ADDR; + + if (regno >= 0) + { + regaddr = register_addr (regno, offset); + errno = 0; + ptrace (6, inferior_pid, regaddr, read_register (regno)); + if (errno != 0) + { + sprintf (buf, "writing register number %d", regno); + perror_with_name (buf); + } + } + else for (regno = 0; regno < NUM_REGS; regno++) + { + regaddr = register_addr (regno, offset); + errno = 0; + ptrace (6, inferior_pid, regaddr, read_register (regno)); + if (errno != 0) + { + sprintf (buf, "writing register number %d", regno); + perror_with_name (buf); + } + } +} + +/* Copy LEN bytes from inferior's memory starting at MEMADDR + to debugger memory starting at MYADDR. + On failure (cannot read from inferior, usually because address is out + of bounds) returns the value of errno. */ + +int +read_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + register int i; + /* Round starting address down to longword boundary. */ + register CORE_ADDR addr = memaddr & - sizeof (int); + /* Round ending address up; get number of longwords that makes. */ + register int count + = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int); + /* Allocate buffer of that many longwords. */ + register int *buffer = (int *) alloca (count * sizeof (int)); + extern int errno; + + /* Read all the longwords */ + for (i = 0; i < count; i++, addr += sizeof (int)) + { + errno = 0; + if (remote_debugging) + buffer[i] = remote_fetch_word (addr); + else + buffer[i] = ptrace (1, inferior_pid, addr, 0); + if (errno) + return errno; + } + + /* Copy appropriate bytes out of the buffer. */ + bcopy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len); + return 0; +} + +/* Copy LEN bytes of data from debugger memory at MYADDR + to inferior's memory at MEMADDR. + On failure (cannot write the inferior) + returns the value of errno. */ + +int +write_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + register int i; + /* Round starting address down to longword boundary. */ + register CORE_ADDR addr = memaddr & - sizeof (int); + /* Round ending address up; get number of longwords that makes. */ + register int count + = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int); + /* Allocate buffer of that many longwords. */ + register int *buffer = (int *) alloca (count * sizeof (int)); + extern int errno; + + /* Fill start and end extra bytes of buffer with existing memory data. */ + + if (remote_debugging) + buffer[0] = remote_fetch_word (addr); + else + buffer[0] = ptrace (1, inferior_pid, addr, 0); + + if (count > 1) + { + if (remote_debugging) + buffer[count - 1] + = remote_fetch_word (addr + (count - 1) * sizeof (int)); + else + buffer[count - 1] + = ptrace (1, inferior_pid, + addr + (count - 1) * sizeof (int), 0); + } + + /* Copy data to be written over corresponding part of buffer */ + + bcopy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len); + + /* Write the entire buffer. */ + + for (i = 0; i < count; i++, addr += sizeof (int)) + { + errno = 0; + if (remote_debugging) + remote_store_word (addr, buffer[i]); + else + ptrace (4, inferior_pid, addr, buffer[i]); + if (errno) + return errno; + } + + return 0; +} + +/* Work with core dump and executable files, for GDB. + This code would be in core.c if it weren't machine-dependent. */ + +#ifndef N_TXTADDR +#define N_TXTADDR(hdr) 0 +#endif /* no N_TXTADDR */ + +#ifndef N_DATADDR +#define N_DATADDR(hdr) hdr.a_text +#endif /* no N_DATADDR */ + +/* Make COFF and non-COFF names for things a little more compatible + to reduce conditionals later. */ + +#ifndef COFF_FORMAT +#ifndef AOUTHDR +#define AOUTHDR struct exec +#endif +#endif + +extern char *sys_siglist[]; + + +/* Hook for `exec_file_command' command to call. */ + +extern void (*exec_file_display_hook) (); + +/* File names of core file and executable file. */ + +extern char *corefile; +extern char *execfile; + +/* Descriptors on which core file and executable file are open. + Note that the execchan is closed when an inferior is created + and reopened if the inferior dies or is killed. */ + +extern int corechan; +extern int execchan; + +/* Last modification time of executable file. + Also used in source.c to compare against mtime of a source file. */ + +extern int exec_mtime; + +/* Virtual addresses of bounds of the two areas of memory in the core file. */ + +extern CORE_ADDR data_start; +extern CORE_ADDR data_end; +extern CORE_ADDR stack_start; +extern CORE_ADDR stack_end; + +/* Virtual addresses of bounds of two areas of memory in the exec file. + Note that the data area in the exec file is used only when there is no core file. */ + +extern CORE_ADDR text_start; +extern CORE_ADDR text_end; + +extern CORE_ADDR exec_data_start; +extern CORE_ADDR exec_data_end; + +/* Address in executable file of start of text area data. */ + +extern int text_offset; + +/* Address in executable file of start of data area data. */ + +extern int exec_data_offset; + +/* Address in core file of start of data area data. */ + +extern int data_offset; + +/* Address in core file of start of stack area data. */ + +extern int stack_offset; + +#ifdef COFF_FORMAT +/* various coff data structures */ + +extern FILHDR file_hdr; +extern SCNHDR text_hdr; +extern SCNHDR data_hdr; + +#endif /* not COFF_FORMAT */ + +/* a.out header saved in core file. */ + +extern AOUTHDR core_aouthdr; + +/* a.out header of exec file. */ + +extern AOUTHDR exec_aouthdr; + +extern void validate_files (); + +core_file_command (filename, from_tty) + char *filename; + int from_tty; +{ + int val; + extern char registers[]; + + /* Discard all vestiges of any previous core file + and mark data and stack spaces as empty. */ + + if (corefile) + free (corefile); + corefile = 0; + + if (corechan >= 0) + close (corechan); + corechan = -1; + + data_start = 0; + data_end = 0; + stack_start = STACK_END_ADDR; + stack_end = STACK_END_ADDR; + + /* Now, if a new core file was specified, open it and digest it. */ + + if (filename) + { + filename = tilde_expand (filename); + make_cleanup (free, filename); + + if (have_inferior_p ()) + error ("To look at a core file, you must kill the inferior with \"kill\"."); + corechan = open (filename, O_RDONLY, 0); + if (corechan < 0) + perror_with_name (filename); + /* 4.2-style (and perhaps also sysV-style) core dump file. */ + { + struct user u; + + int reg_offset; + + val = myread (corechan, &u, sizeof u); + if (val < 0) + perror_with_name (filename); + data_start = exec_data_start; + + data_end = data_start + NBPG * u.u_dsize; + stack_start = stack_end - NBPG * u.u_ssize; + data_offset = NBPG * UPAGES; + stack_offset = NBPG * (UPAGES + u.u_dsize); + reg_offset = (int) u.u_ar0 - KERNEL_U_ADDR; + + /* I don't know where to find this info. + So, for now, mark it as not available. */ +/* N_SET_MAGIC (core_aouthdr, 0); */ + bzero ((char *) &core_aouthdr, sizeof core_aouthdr); + + /* Read the register values out of the core file and store + them where `read_register' will find them. */ + + { + register int regno; + + for (regno = 0; regno < NUM_REGS; regno++) + { + char buf[MAX_REGISTER_RAW_SIZE]; + + val = lseek (corechan, register_addr (regno, reg_offset), 0); + if (val < 0) + perror_with_name (filename); + + val = myread (corechan, buf, sizeof buf); + if (val < 0) + perror_with_name (filename); + supply_register (regno, buf); + } + } + } + if (filename[0] == '/') + corefile = savestring (filename, strlen (filename)); + else + { + corefile = concat (current_directory, "/", filename); + } + + set_current_frame ( create_new_frame (read_register (FP_REGNUM), + read_pc ())); + select_frame (get_current_frame (), 0); + validate_files (); + } + else if (from_tty) + printf ("No core file now.\n"); +} + +exec_file_command (filename, from_tty) + char *filename; + int from_tty; +{ + int val; + + /* Eliminate all traces of old exec file. + Mark text segment as empty. */ + + if (execfile) + free (execfile); + execfile = 0; + data_start = 0; + data_end -= exec_data_start; + text_start = 0; + text_end = 0; + exec_data_start = 0; + exec_data_end = 0; + if (execchan >= 0) + close (execchan); + execchan = -1; + + /* Now open and digest the file the user requested, if any. */ + + if (filename) + { + filename = tilde_expand (filename); + make_cleanup (free, filename); + + execchan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0, + &execfile); + if (execchan < 0) + perror_with_name (filename); + +#ifdef COFF_FORMAT + { + int aout_hdrsize; + int num_sections; + + if (read_file_hdr (execchan, &file_hdr) < 0) + error ("\"%s\": not in executable format.", execfile); + + aout_hdrsize = file_hdr.f_opthdr; + num_sections = file_hdr.f_nscns; + + if (read_aout_hdr (execchan, &exec_aouthdr, aout_hdrsize) < 0) + error ("\"%s\": can't read optional aouthdr", execfile); + + if (read_section_hdr (execchan, _TEXT, &text_hdr, num_sections, + aout_hdrsize) < 0) + error ("\"%s\": can't read text section header", execfile); + + if (read_section_hdr (execchan, _DATA, &data_hdr, num_sections, + aout_hdrsize) < 0) + error ("\"%s\": can't read data section header", execfile); + + text_start = exec_aouthdr.text_start; + text_end = text_start + exec_aouthdr.tsize; + text_offset = text_hdr.s_scnptr; + exec_data_start = exec_aouthdr.data_start; + exec_data_end = exec_data_start + exec_aouthdr.dsize; + exec_data_offset = data_hdr.s_scnptr; + data_start = exec_data_start; + data_end += exec_data_start; + exec_mtime = file_hdr.f_timdat; + } +#else /* not COFF_FORMAT */ + { + struct stat st_exec; + +#ifdef HEADER_SEEK_FD + HEADER_SEEK_FD (execchan); +#endif + + val = myread (execchan, &exec_aouthdr, sizeof (AOUTHDR)); + + if (val < 0) + perror_with_name (filename); + + text_start = N_TXTADDR (exec_aouthdr); + exec_data_start = N_DATADDR (exec_aouthdr); + + text_offset = N_TXTOFF (exec_aouthdr); + exec_data_offset = N_TXTOFF (exec_aouthdr) + exec_aouthdr.a_text; + + text_end = 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; + } +#endif /* not COFF_FORMAT */ + + 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); +} + +/* 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 %esp */ + { + /* 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) + return (-1); + /* 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) + return (-1); + /* 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; + + pfi = get_prev_frame_info ((fi)); + if (pfi == 0) + { + /* Note: this can happen if we are looking at the frame for + main, because FRAME_CHAIN_VALID won't let us go into + start. If we have debugging symbols, that's not really + a big deal; it just means it will only show as many arguments + to main as are declared. */ + return -1; + } + else + { + retpc = pfi->pc; + op = read_memory_integer (retpc, 1); + if (op == 0x59) + /* pop %ecx */ + return 1; + else if (op == 0x83) + { + op = read_memory_integer (retpc+1, 1); + if (op == 0xc4) + /* addl $<signed imm 8 bits>, %esp */ + return (read_memory_integer (retpc+2,1)&0xff)/4; + else + return 0; + } + else if (op == 0x81) + { /* add with 32 bit immediate */ + op = read_memory_integer (retpc+1, 1); + if (op == 0xc4) + /* addl $<imm 32>, %esp */ + return read_memory_integer (retpc+2, 4) / 4; + else + return 0; + } + else + { + return 0; + } + } +} + +/* + * parse the first few instructions of the function to see + * what registers were stored. + * + * We handle these cases: + * + * The startup sequence can be at the start of the function, + * or the function can start with a branch to startup code at the end. + * + * %ebp can be set up with either the 'enter' instruction, or + * 'pushl %ebp, movl %esp, %ebp' (enter is too slow to be useful, + * but was once used in the sys5 compiler) + * + * Local space is allocated just below the saved %ebp by either the + * 'enter' instruction, or by 'subl $<size>, %esp'. 'enter' has + * a 16 bit unsigned argument for space to allocate, and the + * 'addl' instruction could have either a signed byte, or + * 32 bit immediate. + * + * Next, the registers used by this function are pushed. In + * the sys5 compiler they will always be in the order: %edi, %esi, %ebx + * (and sometimes a harmless bug causes it to also save but not restore %eax); + * however, the code below is willing to see the pushes in any order, + * and will handle up to 8 of them. + * + * If the setup sequence is at the end of the function, then the + * next instruction will be a branch back to the start. + */ + +i386_frame_find_saved_regs (fip, fsrp) + struct frame_info *fip; + struct frame_saved_regs *fsrp; +{ + unsigned 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 - NUM_REGS*4 - 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 - 4; + for (i = 0; i < NUM_REGS; i++) + { + fsrp->regs[i] = adr; + adr -= 4; + } + 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; + + 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++) + sp = push_word (sp, read_register (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; + + 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) + write_register (regnum, read_memory_integer (adr, 4)); + } + 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 ())); +} + +/* this table must line up with REGISTER_NAMES in m-i386.h */ +/* symbols like 'EAX' come from <sys/reg.h> */ +static int regmap[] = +{ + EAX, ECX, EDX, EBX, + UESP, EBP, ESI, EDI, + EIP, EFL, CS, SS, + DS, ES, FS, GS, +}; + +/* blockend is the value of u.u_ar0, and points to the + * place where GS is stored + */ +i386_register_u_addr (blockend, regnum) +{ +#if 0 + /* this will be needed if fp registers are reinstated */ + /* for now, you can look at them with 'info float' + * sys5 wont let you change them with ptrace anyway + */ + if (regnum >= FP0_REGNUM && regnum <= FP7_REGNUM) + { + int ubase, fpstate; + struct user u; + ubase = blockend + 4 * (SS + 1) - KSTKSZ; + fpstate = ubase + ((char *)&u.u_fpstate - (char *)&u); + return (fpstate + 0x1c + 10 * (regnum - FP0_REGNUM)); + } + else +#endif + return (blockend + 4 * regmap[regnum]); + +} + +i387_to_double (from, to) + char *from; + char *to; +{ + long *lp; + /* push extended mode on 387 stack, then pop in double mode + * + * first, set exception masks so no error is generated - + * number will be rounded to inf or 0, if necessary + */ + asm ("pushl %eax"); /* grab a stack slot */ + asm ("fstcw (%esp)"); /* get 387 control word */ + asm ("movl (%esp),%eax"); /* save old value */ + asm ("orl $0x3f,%eax"); /* mask all exceptions */ + asm ("pushl %eax"); + asm ("fldcw (%esp)"); /* load new value into 387 */ + + asm ("movl 8(%ebp),%eax"); + asm ("fldt (%eax)"); /* push extended number on 387 stack */ + asm ("fwait"); + asm ("movl 12(%ebp),%eax"); + asm ("fstpl (%eax)"); /* pop double */ + asm ("fwait"); + + asm ("popl %eax"); /* flush modified control word */ + asm ("fnclex"); /* clear exceptions */ + asm ("fldcw (%esp)"); /* restore original control word */ + asm ("popl %eax"); /* flush saved copy */ +} + +double_to_i387 (from, to) + char *from; + char *to; +{ + /* push double mode on 387 stack, then pop in extended mode + * no errors are possible because every 64-bit pattern + * can be converted to an extended + */ + asm ("movl 8(%ebp),%eax"); + asm ("fldl (%eax)"); + asm ("fwait"); + asm ("movl 12(%ebp),%eax"); + asm ("fstpt (%eax)"); + asm ("fwait"); +} + +struct env387 +{ + unsigned short control; + unsigned short r0; + unsigned short status; + unsigned short r1; + unsigned short tag; + unsigned short r2; + unsigned long eip; + unsigned short code_seg; + unsigned short opcode; + unsigned long operand; + unsigned short operand_seg; + unsigned short r3; + unsigned char regs[8][10]; +}; + +static +print_387_control_word (control) +unsigned short control; +{ + printf ("control 0x%04x: ", control); + printf ("compute to "); + switch ((control >> 8) & 3) + { + case 0: printf ("24 bits; "); break; + case 1: printf ("(bad); "); break; + case 2: printf ("53 bits; "); break; + case 3: printf ("64 bits; "); break; + } + printf ("round "); + switch ((control >> 10) & 3) + { + case 0: printf ("NEAREST; "); break; + case 1: printf ("DOWN; "); break; + case 2: printf ("UP; "); break; + case 3: printf ("CHOP; "); break; + } + if (control & 0x3f) + { + printf ("mask:"); + if (control & 0x0001) printf (" INVALID"); + if (control & 0x0002) printf (" DENORM"); + if (control & 0x0004) printf (" DIVZ"); + if (control & 0x0008) printf (" OVERF"); + if (control & 0x0010) printf (" UNDERF"); + if (control & 0x0020) printf (" LOS"); + printf (";"); + } + printf ("\n"); + if (control & 0xe080) printf ("warning: reserved bits on 0x%x\n", + control & 0xe080); +} + +static +print_387_status_word (status) + unsigned short status; +{ + printf ("status 0x%04x: ", status); + if (status & 0xff) + { + printf ("exceptions:"); + if (status & 0x0001) printf (" INVALID"); + if (status & 0x0002) printf (" DENORM"); + if (status & 0x0004) printf (" DIVZ"); + if (status & 0x0008) printf (" OVERF"); + if (status & 0x0010) printf (" UNDERF"); + if (status & 0x0020) printf (" LOS"); + if (status & 0x0040) printf (" FPSTACK"); + printf ("; "); + } + printf ("flags: %d%d%d%d; ", + (status & 0x4000) != 0, + (status & 0x0400) != 0, + (status & 0x0200) != 0, + (status & 0x0100) != 0); + + printf ("top %d\n", (status >> 11) & 7); +} + +static +print_387_status (status, ep) + unsigned short status; + struct env387 *ep; +{ + int i; + int bothstatus; + int top; + int fpreg; + unsigned char *p; + + bothstatus = ((status != 0) && (ep->status != 0)); + if (status != 0) + { + if (bothstatus) + printf ("u: "); + print_387_status_word (status); + } + + if (ep->status != 0) + { + if (bothstatus) + printf ("e: "); + print_387_status_word (ep->status); + } + + print_387_control_word (ep->control); + printf ("last exception: "); + printf ("opcode 0x%x; ", ep->opcode); + printf ("pc 0x%x:0x%x; ", ep->code_seg, ep->eip); + printf ("operand 0x%x:0x%x\n", ep->operand_seg, ep->operand); + + top = (ep->status >> 11) & 7; + + printf ("regno tag msb lsb value\n"); + for (fpreg = 7; fpreg >= 0; fpreg--) + { + double val; + + printf ("%s %d: ", fpreg == top ? "=>" : " ", fpreg); + + switch ((ep->tag >> (fpreg * 2)) & 3) + { + case 0: printf ("valid "); break; + case 1: printf ("zero "); break; + case 2: printf ("trap "); break; + case 3: printf ("empty "); break; + } + for (i = 9; i >= 0; i--) + printf ("%02x", ep->regs[fpreg][i]); + + i387_to_double (ep->regs[fpreg], (char *)&val); + printf (" %g\n", val); + } + if (ep->r0) + printf ("warning: reserved0 is 0x%x\n", ep->r0); + if (ep->r1) + printf ("warning: reserved1 is 0x%x\n", ep->r1); + if (ep->r2) + printf ("warning: reserved2 is 0x%x\n", ep->r2); + if (ep->r3) + printf ("warning: reserved3 is 0x%x\n", ep->r3); +} + +#ifndef U_FPSTATE +#define U_FPSTATE(u) u.u_fpstate +#endif + +i386_float_info () +{ + struct user u; /* just for address computations */ + int i; + /* fpstate defined in <sys/user.h> */ + struct fpstate *fpstatep; + char buf[sizeof (struct fpstate) + 2 * sizeof (int)]; + unsigned int uaddr; + char fpvalid; + unsigned int rounded_addr; + unsigned int rounded_size; + extern int corechan; + int skip; + + uaddr = (char *)&u.u_fpvalid - (char *)&u; + if (have_inferior_p()) + { + unsigned int data; + unsigned int mask; + + rounded_addr = uaddr & -sizeof (int); + data = ptrace (3, inferior_pid, rounded_addr, 0); + mask = 0xff << ((uaddr - rounded_addr) * 8); + + fpvalid = ((data & mask) != 0); + } + else + { + if (lseek (corechan, uaddr, 0) < 0) + perror ("seek on core file"); + if (myread (corechan, &fpvalid, 1) < 0) + perror ("read on core file"); + + } + + if (fpvalid == 0) + { + printf ("no floating point status saved\n"); + return; + } + + uaddr = (char *)&U_FPSTATE(u) - (char *)&u; + if (have_inferior_p ()) + { + int *ip; + + rounded_addr = uaddr & -sizeof (int); + rounded_size = (((uaddr + sizeof (struct fpstate)) - uaddr) + + sizeof (int) - 1) / sizeof (int); + skip = uaddr - rounded_addr; + + ip = (int *)buf; + for (i = 0; i < rounded_size; i++) + { + *ip++ = ptrace (3, inferior_pid, rounded_addr, 0); + rounded_addr += sizeof (int); + } + } + else + { + if (lseek (corechan, uaddr, 0) < 0) + perror_with_name ("seek on core file"); + if (myread (corechan, buf, sizeof (struct fpstate)) < 0) + perror_with_name ("read from core file"); + skip = 0; + } + + fpstatep = (struct fpstate *)(buf + skip); + print_387_status (fpstatep->status, (struct env387 *)fpstatep->state); +} + diff --git a/gnu/usr.bin/gdb/config/i386-pinsn.c b/gnu/usr.bin/gdb/config/i386-pinsn.c new file mode 100644 index 0000000..649baaf --- /dev/null +++ b/gnu/usr.bin/gdb/config/i386-pinsn.c @@ -0,0 +1,1812 @@ +/* Print i386 instructions for GDB, the GNU debugger. + 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. */ + +/* + * 80386 instruction printer by Pace Willisson (pace@prep.ai.mit.edu) + * July 1988 + */ + +/* + * The main tables describing the instructions is essentially a copy + * of the "Opcode Map" chapter (Appendix A) of the Intel 80386 + * Programmers Manual. Usually, there is a capital letter, followed + * by a small letter. The capital letter tell the addressing mode, + * and the small letter tells about the operand size. Refer to + * the Intel manual for details. + */ + +#include <stdio.h> +#include <ctype.h> + +#define Eb OP_E, b_mode +#define indirEb OP_indirE, b_mode +#define Gb OP_G, b_mode +#define Ev OP_E, v_mode +#define indirEv OP_indirE, v_mode +#define Ew OP_E, w_mode +#define Ma OP_E, v_mode +#define M OP_E, 0 +#define Mp OP_E, 0 /* ? */ +#define Gv OP_G, v_mode +#define Gw OP_G, w_mode +#define Rw OP_rm, w_mode +#define Rd OP_rm, d_mode +#define Ib OP_I, b_mode +#define sIb OP_sI, b_mode /* sign extened byte */ +#define Iv OP_I, v_mode +#define Iw OP_I, w_mode +#define Jb OP_J, b_mode +#define Jv OP_J, v_mode +#define ONE OP_ONE, 0 +#define Cd OP_C, d_mode +#define Dd OP_D, d_mode +#define Td OP_T, d_mode + +#define eAX OP_REG, eAX_reg +#define eBX OP_REG, eBX_reg +#define eCX OP_REG, eCX_reg +#define eDX OP_REG, eDX_reg +#define eSP OP_REG, eSP_reg +#define eBP OP_REG, eBP_reg +#define eSI OP_REG, eSI_reg +#define eDI OP_REG, eDI_reg +#define AL OP_REG, al_reg +#define CL OP_REG, cl_reg +#define DL OP_REG, dl_reg +#define BL OP_REG, bl_reg +#define AH OP_REG, ah_reg +#define CH OP_REG, ch_reg +#define DH OP_REG, dh_reg +#define BH OP_REG, bh_reg +#define AX OP_REG, ax_reg +#define DX OP_REG, dx_reg +#define indirDX OP_REG, indir_dx_reg + +#define Sw OP_SEG, w_mode +#define Ap OP_DIR, lptr +#define Av OP_DIR, v_mode +#define Ob OP_OFF, b_mode +#define Ov OP_OFF, v_mode +#define Xb OP_DSSI, b_mode +#define Xv OP_DSSI, v_mode +#define Yb OP_ESDI, b_mode +#define Yv OP_ESDI, v_mode + +#define es OP_REG, es_reg +#define ss OP_REG, ss_reg +#define cs OP_REG, cs_reg +#define ds OP_REG, ds_reg +#define fs OP_REG, fs_reg +#define gs OP_REG, gs_reg + +int OP_E(), OP_indirE(), OP_G(), OP_I(), OP_sI(), OP_REG(); +int OP_J(), OP_SEG(); +int OP_DIR(), OP_OFF(), OP_DSSI(), OP_ESDI(), OP_ONE(), OP_C(); +int OP_D(), OP_T(), OP_rm(); + + +#define b_mode 1 +#define v_mode 2 +#define w_mode 3 +#define d_mode 4 + +#define es_reg 100 +#define cs_reg 101 +#define ss_reg 102 +#define ds_reg 103 +#define fs_reg 104 +#define gs_reg 105 +#define eAX_reg 107 +#define eCX_reg 108 +#define eDX_reg 109 +#define eBX_reg 110 +#define eSP_reg 111 +#define eBP_reg 112 +#define eSI_reg 113 +#define eDI_reg 114 + +#define lptr 115 + +#define al_reg 116 +#define cl_reg 117 +#define dl_reg 118 +#define bl_reg 119 +#define ah_reg 120 +#define ch_reg 121 +#define dh_reg 122 +#define bh_reg 123 + +#define ax_reg 124 +#define cx_reg 125 +#define dx_reg 126 +#define bx_reg 127 +#define sp_reg 128 +#define bp_reg 129 +#define si_reg 130 +#define di_reg 131 + +#define indir_dx_reg 150 + +#define GRP1b NULL, NULL, 0 +#define GRP1S NULL, NULL, 1 +#define GRP1Ss NULL, NULL, 2 +#define GRP2b NULL, NULL, 3 +#define GRP2S NULL, NULL, 4 +#define GRP2b_one NULL, NULL, 5 +#define GRP2S_one NULL, NULL, 6 +#define GRP2b_cl NULL, NULL, 7 +#define GRP2S_cl NULL, NULL, 8 +#define GRP3b NULL, NULL, 9 +#define GRP3S NULL, NULL, 10 +#define GRP4 NULL, NULL, 11 +#define GRP5 NULL, NULL, 12 +#define GRP6 NULL, NULL, 13 +#define GRP7 NULL, NULL, 14 +#define GRP8 NULL, NULL, 15 + +#define FLOATCODE 50 +#define FLOAT NULL, NULL, FLOATCODE + +struct dis386 { + char *name; + int (*op1)(); + int bytemode1; + int (*op2)(); + int bytemode2; + int (*op3)(); + int bytemode3; +}; + +struct dis386 dis386[] = { + /* 00 */ + { "addb", Eb, Gb }, + { "addS", Ev, Gv }, + { "addb", Gb, Eb }, + { "addS", Gv, Ev }, + { "addb", AL, Ib }, + { "addS", eAX, Iv }, + { "pushl", es }, + { "popl", es }, + /* 08 */ + { "orb", Eb, Gb }, + { "orS", Ev, Gv }, + { "orb", Gb, Eb }, + { "orS", Gv, Ev }, + { "orb", AL, Ib }, + { "orS", eAX, Iv }, + { "pushl", cs }, + { "(bad)" }, /* 0x0f extended opcode escape */ + /* 10 */ + { "adcb", Eb, Gb }, + { "adcS", Ev, Gv }, + { "adcb", Gb, Eb }, + { "adcS", Gv, Ev }, + { "adcb", AL, Ib }, + { "adcS", eAX, Iv }, + { "pushl", ss }, + { "popl", ss }, + /* 18 */ + { "sbbb", Eb, Gb }, + { "sbbS", Ev, Gv }, + { "sbbb", Gb, Eb }, + { "sbbS", Gv, Ev }, + { "sbbb", AL, Ib }, + { "sbbS", eAX, Iv }, + { "pushl", ds }, + { "popl", ds }, + /* 20 */ + { "andb", Eb, Gb }, + { "andS", Ev, Gv }, + { "andb", Gb, Eb }, + { "andS", Gv, Ev }, + { "andb", AL, Ib }, + { "andS", eAX, Iv }, + { "(bad)" }, /* SEG ES prefix */ + { "daa" }, + /* 28 */ + { "subb", Eb, Gb }, + { "subS", Ev, Gv }, + { "subb", Gb, Eb }, + { "subS", Gv, Ev }, + { "subb", AL, Ib }, + { "subS", eAX, Iv }, + { "(bad)" }, /* SEG CS prefix */ + { "das" }, + /* 30 */ + { "xorb", Eb, Gb }, + { "xorS", Ev, Gv }, + { "xorb", Gb, Eb }, + { "xorS", Gv, Ev }, + { "xorb", AL, Ib }, + { "xorS", eAX, Iv }, + { "(bad)" }, /* SEG SS prefix */ + { "aaa" }, + /* 38 */ + { "cmpb", Eb, Gb }, + { "cmpS", Ev, Gv }, + { "cmpb", Gb, Eb }, + { "cmpS", Gv, Ev }, + { "cmpb", AL, Ib }, + { "cmpS", eAX, Iv }, + { "(bad)" }, /* SEG DS prefix */ + { "aas" }, + /* 40 */ + { "incS", eAX }, + { "incS", eCX }, + { "incS", eDX }, + { "incS", eBX }, + { "incS", eSP }, + { "incS", eBP }, + { "incS", eSI }, + { "incS", eDI }, + /* 48 */ + { "decS", eAX }, + { "decS", eCX }, + { "decS", eDX }, + { "decS", eBX }, + { "decS", eSP }, + { "decS", eBP }, + { "decS", eSI }, + { "decS", eDI }, + /* 50 */ + { "pushS", eAX }, + { "pushS", eCX }, + { "pushS", eDX }, + { "pushS", eBX }, + { "pushS", eSP }, + { "pushS", eBP }, + { "pushS", eSI }, + { "pushS", eDI }, + /* 58 */ + { "popS", eAX }, + { "popS", eCX }, + { "popS", eDX }, + { "popS", eBX }, + { "popS", eSP }, + { "popS", eBP }, + { "popS", eSI }, + { "popS", eDI }, + /* 60 */ + { "pusha" }, + { "popa" }, + { "boundS", Gv, Ma }, + { "arpl", Ew, Gw }, + { "(bad)" }, /* seg fs */ + { "(bad)" }, /* seg gs */ + { "(bad)" }, /* op size prefix */ + { "(bad)" }, /* adr size prefix */ + /* 68 */ + { "pushS", Iv }, /* 386 book wrong */ + { "imulS", Gv, Ev, Iv }, + { "pushl", sIb }, /* push of byte really pushes 4 bytes */ + { "imulS", Gv, Ev, Ib }, + { "insb", Yb, indirDX }, + { "insS", Yv, indirDX }, + { "outsb", indirDX, Xb }, + { "outsS", indirDX, Xv }, + /* 70 */ + { "jo", Jb }, + { "jno", Jb }, + { "jb", Jb }, + { "jae", Jb }, + { "je", Jb }, + { "jne", Jb }, + { "jbe", Jb }, + { "ja", Jb }, + /* 78 */ + { "js", Jb }, + { "jns", Jb }, + { "jp", Jb }, + { "jnp", Jb }, + { "jl", Jb }, + { "jnl", Jb }, + { "jle", Jb }, + { "jg", Jb }, + /* 80 */ + { GRP1b }, + { GRP1S }, + { "(bad)" }, + { GRP1Ss }, + { "testb", Eb, Gb }, + { "testS", Ev, Gv }, + { "xchgb", Eb, Gb }, + { "xchgS", Ev, Gv }, + /* 88 */ + { "movb", Eb, Gb }, + { "movS", Ev, Gv }, + { "movb", Gb, Eb }, + { "movS", Gv, Ev }, + { "movw", Ew, Sw }, + { "leaS", Gv, M }, + { "movw", Sw, Ew }, + { "popS", Ev }, + /* 90 */ + { "nop" }, + { "xchgS", eCX, eAX }, + { "xchgS", eDX, eAX }, + { "xchgS", eBX, eAX }, + { "xchgS", eSP, eAX }, + { "xchgS", eBP, eAX }, + { "xchgS", eSI, eAX }, + { "xchgS", eDI, eAX }, + /* 98 */ + { "cwtl" }, + { "cltd" }, + { "lcall", Ap }, + { "(bad)" }, /* fwait */ + { "pushf" }, + { "popf" }, + { "sahf" }, + { "lahf" }, + /* a0 */ + { "movb", AL, Ob }, + { "movS", eAX, Ov }, + { "movb", Ob, AL }, + { "movS", Ov, eAX }, + { "movsb", Yb, Xb }, + { "movsS", Yv, Xv }, + { "cmpsb", Yb, Xb }, + { "cmpsS", Yv, Xv }, + /* a8 */ + { "testb", AL, Ib }, + { "testS", eAX, Iv }, + { "stosb", Yb, AL }, + { "stosS", Yv, eAX }, + { "lodsb", AL, Xb }, + { "lodsS", eAX, Xv }, + { "scasb", AL, Xb }, + { "scasS", eAX, Xv }, + /* b0 */ + { "movb", AL, Ib }, + { "movb", CL, Ib }, + { "movb", DL, Ib }, + { "movb", BL, Ib }, + { "movb", AH, Ib }, + { "movb", CH, Ib }, + { "movb", DH, Ib }, + { "movb", BH, Ib }, + /* b8 */ + { "movS", eAX, Iv }, + { "movS", eCX, Iv }, + { "movS", eDX, Iv }, + { "movS", eBX, Iv }, + { "movS", eSP, Iv }, + { "movS", eBP, Iv }, + { "movS", eSI, Iv }, + { "movS", eDI, Iv }, + /* c0 */ + { GRP2b }, + { GRP2S }, + { "ret", Iw }, + { "ret" }, + { "lesS", Gv, Mp }, + { "ldsS", Gv, Mp }, + { "movb", Eb, Ib }, + { "movS", Ev, Iv }, + /* c8 */ + { "enter", Iw, Ib }, + { "leave" }, + { "lret", Iw }, + { "lret" }, + { "int3" }, + { "int", Ib }, + { "into" }, + { "iret" }, + /* d0 */ + { GRP2b_one }, + { GRP2S_one }, + { GRP2b_cl }, + { GRP2S_cl }, + { "aam", Ib }, + { "aad", Ib }, + { "(bad)" }, + { "xlat" }, + /* d8 */ + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + /* e0 */ + { "loopne", Jb }, + { "loope", Jb }, + { "loop", Jb }, + { "jCcxz", Jb }, + { "inb", AL, Ib }, + { "inS", eAX, Ib }, + { "outb", Ib, AL }, + { "outS", Ib, eAX }, + /* e8 */ + { "call", Av }, + { "jmp", Jv }, + { "ljmp", Ap }, + { "jmp", Jb }, + { "inb", AL, indirDX }, + { "inS", eAX, indirDX }, + { "outb", indirDX, AL }, + { "outS", indirDX, eAX }, + /* f0 */ + { "(bad)" }, /* lock prefix */ + { "(bad)" }, + { "(bad)" }, /* repne */ + { "(bad)" }, /* repz */ + { "hlt" }, + { "cmc" }, + { GRP3b }, + { GRP3S }, + /* f8 */ + { "clc" }, + { "stc" }, + { "cli" }, + { "sti" }, + { "cld" }, + { "std" }, + { GRP4 }, + { GRP5 }, +}; + +struct dis386 dis386_twobyte[] = { + /* 00 */ + { GRP6 }, + { GRP7 }, + { "larS", Gv, Ew }, + { "lslS", Gv, Ew }, + { "(bad)" }, + { "(bad)" }, + { "clts" }, + { "(bad)" }, + /* 08 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 10 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 18 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 20 */ + /* these are all backward in appendix A of the intel book */ + { "movl", Rd, Cd }, + { "movl", Rd, Dd }, + { "movl", Cd, Rd }, + { "movl", Dd, Rd }, + { "movl", Rd, Td }, + { "(bad)" }, + { "movl", Td, Rd }, + { "(bad)" }, + /* 28 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 30 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 38 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 40 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 48 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 50 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 58 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 60 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 68 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 70 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 78 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 80 */ + { "jo", Jv }, + { "jno", Jv }, + { "jb", Jv }, + { "jae", Jv }, + { "je", Jv }, + { "jne", Jv }, + { "jbe", Jv }, + { "ja", Jv }, + /* 88 */ + { "js", Jv }, + { "jns", Jv }, + { "jp", Jv }, + { "jnp", Jv }, + { "jl", Jv }, + { "jge", Jv }, + { "jle", Jv }, + { "jg", Jv }, + /* 90 */ + { "seto", Eb }, + { "setno", Eb }, + { "setb", Eb }, + { "setae", Eb }, + { "sete", Eb }, + { "setne", Eb }, + { "setbe", Eb }, + { "seta", Eb }, + /* 98 */ + { "sets", Eb }, + { "setns", Eb }, + { "setp", Eb }, + { "setnp", Eb }, + { "setl", Eb }, + { "setge", Eb }, + { "setle", Eb }, + { "setg", Eb }, + /* a0 */ + { "pushl", fs }, + { "popl", fs }, + { "(bad)" }, + { "btS", Ev, Gv }, + { "shldS", Ev, Gv, Ib }, + { "shldS", Ev, Gv, CL }, + { "(bad)" }, + { "(bad)" }, + /* a8 */ + { "pushl", gs }, + { "popl", gs }, + { "(bad)" }, + { "btsS", Ev, Gv }, + { "shrdS", Ev, Gv, Ib }, + { "shrdS", Ev, Gv, CL }, + { "(bad)" }, + { "imulS", Gv, Ev }, + /* b0 */ + { "(bad)" }, + { "(bad)" }, + { "lssS", Gv, Mp }, /* 386 lists only Mp */ + { "btrS", Ev, Gv }, + { "lfsS", Gv, Mp }, /* 386 lists only Mp */ + { "lgsS", Gv, Mp }, /* 386 lists only Mp */ + { "movzbS", Gv, Eb }, + { "movzwS", Gv, Ew }, + /* b8 */ + { "(bad)" }, + { "(bad)" }, + { GRP8 }, + { "btcS", Ev, Gv }, + { "bsfS", Gv, Ev }, + { "bsrS", Gv, Ev }, + { "movsbS", Gv, Eb }, + { "movswS", Gv, Ew }, + /* c0 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* c8 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* d0 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* d8 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* e0 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* e8 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* f0 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* f8 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, +}; + +static char obuf[100]; +static char *obufp; +static char scratchbuf[100]; +static unsigned char *start_codep; +static unsigned char *codep; +static int mod; +static int rm; +static int reg; + +static char *names32[]={ + "%eax","%ecx","%edx","%ebx", "%esp","%ebp","%esi","%edi", +}; +static char *names16[] = { + "%ax","%cx","%dx","%bx","%sp","%bp","%si","%di", +}; +static char *names8[] = { + "%al","%cl","%dl","%bl","%ah","%ch","%dh","%bh", +}; +static char *names_seg[] = { + "%es","%cs","%ss","%ds","%fs","%gs","%?","%?", +}; + +struct dis386 grps[][8] = { + /* GRP1b */ + { + { "addb", Eb, Ib }, + { "orb", Eb, Ib }, + { "adcb", Eb, Ib }, + { "sbbb", Eb, Ib }, + { "andb", Eb, Ib }, + { "subb", Eb, Ib }, + { "xorb", Eb, Ib }, + { "cmpb", Eb, Ib } + }, + /* GRP1S */ + { + { "addS", Ev, Iv }, + { "orS", Ev, Iv }, + { "adcS", Ev, Iv }, + { "sbbS", Ev, Iv }, + { "andS", Ev, Iv }, + { "subS", Ev, Iv }, + { "xorS", Ev, Iv }, + { "cmpS", Ev, Iv } + }, + /* GRP1Ss */ + { + { "addS", Ev, sIb }, + { "orS", Ev, sIb }, + { "adcS", Ev, sIb }, + { "sbbS", Ev, sIb }, + { "andS", Ev, sIb }, + { "subS", Ev, sIb }, + { "xorS", Ev, sIb }, + { "cmpS", Ev, sIb } + }, + /* GRP2b */ + { + { "rolb", Eb, Ib }, + { "rorb", Eb, Ib }, + { "rclb", Eb, Ib }, + { "rcrb", Eb, Ib }, + { "shlb", Eb, Ib }, + { "shrb", Eb, Ib }, + { "(bad)" }, + { "sarb", Eb, Ib }, + }, + /* GRP2S */ + { + { "rolS", Ev, Ib }, + { "rorS", Ev, Ib }, + { "rclS", Ev, Ib }, + { "rcrS", Ev, Ib }, + { "shlS", Ev, Ib }, + { "shrS", Ev, Ib }, + { "(bad)" }, + { "sarS", Ev, Ib }, + }, + /* GRP2b_one */ + { + { "rolb", Eb }, + { "rorb", Eb }, + { "rclb", Eb }, + { "rcrb", Eb }, + { "shlb", Eb }, + { "shrb", Eb }, + { "(bad)" }, + { "sarb", Eb }, + }, + /* GRP2S_one */ + { + { "rolS", Ev }, + { "rorS", Ev }, + { "rclS", Ev }, + { "rcrS", Ev }, + { "shlS", Ev }, + { "shrS", Ev }, + { "(bad)" }, + { "sarS", Ev }, + }, + /* GRP2b_cl */ + { + { "rolb", Eb, CL }, + { "rorb", Eb, CL }, + { "rclb", Eb, CL }, + { "rcrb", Eb, CL }, + { "shlb", Eb, CL }, + { "shrb", Eb, CL }, + { "(bad)" }, + { "sarb", Eb, CL }, + }, + /* GRP2S_cl */ + { + { "rolS", Ev, CL }, + { "rorS", Ev, CL }, + { "rclS", Ev, CL }, + { "rcrS", Ev, CL }, + { "shlS", Ev, CL }, + { "shrS", Ev, CL }, + { "(bad)" }, + { "sarS", Ev, CL } + }, + /* GRP3b */ + { + { "testb", Eb, Ib }, + { "(bad)", Eb }, + { "notb", Eb }, + { "negb", Eb }, + { "mulb", AL, Eb }, + { "imulb", AL, Eb }, + { "divb", AL, Eb }, + { "idivb", AL, Eb } + }, + /* GRP3S */ + { + { "testS", Ev, Iv }, + { "(bad)" }, + { "notS", Ev }, + { "negS", Ev }, + { "mulS", eAX, Ev }, + { "imulS", eAX, Ev }, + { "divS", eAX, Ev }, + { "idivS", eAX, Ev }, + }, + /* GRP4 */ + { + { "incb", Eb }, + { "decb", Eb }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + }, + /* GRP5 */ + { + { "incS", Ev }, + { "decS", Ev }, + { "call", indirEv }, + { "lcall", indirEv }, + { "jmp", indirEv }, + { "ljmp", indirEv }, + { "pushS", Ev }, + { "(bad)" }, + }, + /* GRP6 */ + { + { "sldt", Ew }, + { "str", Ew }, + { "lldt", Ew }, + { "ltr", Ew }, + { "verr", Ew }, + { "verw", Ew }, + { "(bad)" }, + { "(bad)" } + }, + /* GRP7 */ + { + { "sgdt", Ew }, + { "sidt", Ew }, + { "lgdt", Ew }, + { "lidt", Ew }, + { "smsw", Ew }, + { "(bad)" }, + { "lmsw", Ew }, + { "(bad)" }, + }, + /* GRP8 */ + { + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "btS", Ev, Ib }, + { "btsS", Ev, Ib }, + { "btrS", Ev, Ib }, + { "btcS", Ev, Ib }, + } +}; + +#define PREFIX_REPZ 1 +#define PREFIX_REPNZ 2 +#define PREFIX_LOCK 4 +#define PREFIX_CS 8 +#define PREFIX_SS 0x10 +#define PREFIX_DS 0x20 +#define PREFIX_ES 0x40 +#define PREFIX_FS 0x80 +#define PREFIX_GS 0x100 +#define PREFIX_DATA 0x200 +#define PREFIX_ADR 0x400 +#define PREFIX_FWAIT 0x800 + +static int prefixes; + +ckprefix () +{ + prefixes = 0; + while (1) + { + switch (*codep) + { + case 0xf3: + prefixes |= PREFIX_REPZ; + break; + case 0xf2: + prefixes |= PREFIX_REPNZ; + break; + case 0xf0: + prefixes |= PREFIX_LOCK; + break; + case 0x2e: + prefixes |= PREFIX_CS; + break; + case 0x36: + prefixes |= PREFIX_SS; + break; + case 0x3e: + prefixes |= PREFIX_DS; + break; + case 0x26: + prefixes |= PREFIX_ES; + break; + case 0x64: + prefixes |= PREFIX_FS; + break; + case 0x65: + prefixes |= PREFIX_GS; + break; + case 0x66: + prefixes |= PREFIX_DATA; + break; + case 0x67: + prefixes |= PREFIX_ADR; + break; + case 0x9b: + prefixes |= PREFIX_FWAIT; + break; + default: + return; + } + codep++; + } +} + +static int dflag; +static int aflag; + +static char op1out[100], op2out[100], op3out[100]; +static int start_pc; + +/* + * disassemble the first instruction in 'inbuf'. You have to make + * sure all of the bytes of the instruction are filled in. + * On the 386's of 1988, the maximum length of an instruction is 15 bytes. + * (see topic "Redundant prefixes" in the "Differences from 8086" + * section of the "Virtual 8086 Mode" chapter.) + * 'pc' should be the address of this instruction, it will + * be used to print the target address if this is a relative jump or call + * 'outbuf' gets filled in with the disassembled instruction. it should + * be long enough to hold the longest disassembled instruction. + * 100 bytes is certainly enough, unless symbol printing is added later + * The function returns the length of this instruction in bytes. + */ +i386dis (pc, inbuf, outbuf) + int pc; + unsigned char *inbuf; + char *outbuf; +{ + struct dis386 *dp; + char *p; + int i; + int enter_instruction; + char *first, *second, *third; + int needcomma; + + obuf[0] = 0; + op1out[0] = 0; + op2out[0] = 0; + op3out[0] = 0; + + start_pc = pc; + start_codep = inbuf; + codep = inbuf; + + ckprefix (); + + if (*codep == 0xc8) + enter_instruction = 1; + else + enter_instruction = 0; + + obufp = obuf; + + if (prefixes & PREFIX_REPZ) + oappend ("repz "); + if (prefixes & PREFIX_REPNZ) + oappend ("repnz "); + if (prefixes & PREFIX_LOCK) + oappend ("lock "); + + if ((prefixes & PREFIX_FWAIT) + && ((*codep < 0xd8) || (*codep > 0xdf))) + { + /* fwait not followed by floating point instruction */ + oappend ("fwait"); + strcpy (outbuf, obuf); + return (1); + } + + /* these would be initialized to 0 if disassembling for 8086 or 286 */ + dflag = 1; + aflag = 1; + + if (prefixes & PREFIX_DATA) + dflag ^= 1; + + if (prefixes & PREFIX_ADR) + { + aflag ^= 1; + oappend ("addr16 "); + } + + if (*codep == 0x0f) + dp = &dis386_twobyte[*++codep]; + else + dp = &dis386[*codep]; + codep++; + mod = (*codep >> 6) & 3; + reg = (*codep >> 3) & 7; + rm = *codep & 7; + + if (dp->name == NULL && dp->bytemode1 == FLOATCODE) + { + dofloat (); + } + else + { + if (dp->name == NULL) + dp = &grps[dp->bytemode1][reg]; + + putop (dp->name); + + obufp = op1out; + if (dp->op1) + (*dp->op1)(dp->bytemode1); + + obufp = op2out; + if (dp->op2) + (*dp->op2)(dp->bytemode2); + + obufp = op3out; + if (dp->op3) + (*dp->op3)(dp->bytemode3); + } + + obufp = obuf + strlen (obuf); + for (i = strlen (obuf); i < 6; i++) + oappend (" "); + oappend (" "); + + /* enter instruction is printed with operands in the + * same order as the intel book; everything else + * is printed in reverse order + */ + if (enter_instruction) + { + first = op1out; + second = op2out; + third = op3out; + } + else + { + first = op3out; + second = op2out; + third = op1out; + } + needcomma = 0; + if (*first) + { + oappend (first); + needcomma = 1; + } + if (*second) + { + if (needcomma) + oappend (","); + oappend (second); + needcomma = 1; + } + if (*third) + { + if (needcomma) + oappend (","); + oappend (third); + } + strcpy (outbuf, obuf); + return (codep - inbuf); +} + +char *float_mem[] = { + /* d8 */ + "fadds", + "fmuls", + "fcoms", + "fcomps", + "fsubs", + "fsubrs", + "fdivs", + "fdivrs", + /* d9 */ + "flds", + "(bad)", + "fsts", + "fstps", + "fldenv", + "fldcw", + "fNstenv", + "fNstcw", + /* da */ + "fiaddl", + "fimull", + "ficoml", + "ficompl", + "fisubl", + "fisubrl", + "fidivl", + "fidivrl", + /* db */ + "fildl", + "(bad)", + "fistl", + "fistpl", + "(bad)", + "fldt", + "(bad)", + "fstpt", + /* dc */ + "faddl", + "fmull", + "fcoml", + "fcompl", + "fsubl", + "fsubrl", + "fdivl", + "fdivrl", + /* dd */ + "fldl", + "(bad)", + "fstl", + "fstpl", + "frstor", + "(bad)", + "fNsave", + "fNstsw", + /* de */ + "fiadd", + "fimul", + "ficom", + "ficomp", + "fisub", + "fisubr", + "fidiv", + "fidivr", + /* df */ + "fild", + "(bad)", + "fist", + "fistp", + "fbld", + "fildll", + "fbstp", + "fistpll", +}; + +#define ST OP_ST, 0 +#define STi OP_STi, 0 +int OP_ST(), OP_STi(); + +#define FGRPd9_2 NULL, NULL, 0 +#define FGRPd9_4 NULL, NULL, 1 +#define FGRPd9_5 NULL, NULL, 2 +#define FGRPd9_6 NULL, NULL, 3 +#define FGRPd9_7 NULL, NULL, 4 +#define FGRPda_5 NULL, NULL, 5 +#define FGRPdb_4 NULL, NULL, 6 +#define FGRPde_3 NULL, NULL, 7 +#define FGRPdf_4 NULL, NULL, 8 + +struct dis386 float_reg[][8] = { + /* d8 */ + { + { "fadd", ST, STi }, + { "fmul", ST, STi }, + { "fcom", STi }, + { "fcomp", STi }, + { "fsub", ST, STi }, + { "fsubr", ST, STi }, + { "fdiv", ST, STi }, + { "fdivr", ST, STi }, + }, + /* d9 */ + { + { "fld", STi }, + { "fxch", STi }, + { FGRPd9_2 }, + { "(bad)" }, + { FGRPd9_4 }, + { FGRPd9_5 }, + { FGRPd9_6 }, + { FGRPd9_7 }, + }, + /* da */ + { + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { FGRPda_5 }, + { "(bad)" }, + { "(bad)" }, + }, + /* db */ + { + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { FGRPdb_4 }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + }, + /* dc */ + { + { "fadd", STi, ST }, + { "fmul", STi, ST }, + { "(bad)" }, + { "(bad)" }, + { "fsub", STi, ST }, + { "fsubr", STi, ST }, + { "fdiv", STi, ST }, + { "fdivr", STi, ST }, + }, + /* dd */ + { + { "ffree", STi }, + { "(bad)" }, + { "fst", STi }, + { "fstp", STi }, + { "fucom", STi }, + { "fucomp", STi }, + { "(bad)" }, + { "(bad)" }, + }, + /* de */ + { + { "faddp", STi, ST }, + { "fmulp", STi, ST }, + { "(bad)" }, + { FGRPde_3 }, + { "fsubp", STi, ST }, + { "fsubrp", STi, ST }, + { "fdivp", STi, ST }, + { "fdivrp", STi, ST }, + }, + /* df */ + { + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { FGRPdf_4 }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + }, +}; + + +char *fgrps[][8] = { + /* d9_2 0 */ + { + "fnop","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, + + /* d9_4 1 */ + { + "fchs","fabs","(bad)","(bad)","ftst","fxam","(bad)","(bad)", + }, + + /* d9_5 2 */ + { + "fld1","fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz","(bad)", + }, + + /* d9_6 3 */ + { + "f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp","fincstp", + }, + + /* d9_7 4 */ + { + "fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos", + }, + + /* da_5 5 */ + { + "(bad)","fucompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, + + /* db_4 6 */ + { + "feni(287 only)","fdisi(287 only)","fNclex","fNinit", + "fNsetpm(287 only)","(bad)","(bad)","(bad)", + }, + + /* de_3 7 */ + { + "(bad)","fcompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, + + /* df_4 8 */ + { + "fNstsw","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, +}; + + +dofloat () +{ + struct dis386 *dp; + unsigned char floatop; + + floatop = codep[-1]; + + if (mod != 3) + { + putop (float_mem[(floatop - 0xd8) * 8 + reg]); + obufp = op1out; + OP_E (v_mode); + return; + } + codep++; + + dp = &float_reg[floatop - 0xd8][reg]; + if (dp->name == NULL) + { + putop (fgrps[dp->bytemode1][rm]); + /* instruction fnstsw is only one with strange arg */ + if (floatop == 0xdf && *codep == 0xe0) + strcpy (op1out, "%eax"); + } + else + { + putop (dp->name); + obufp = op1out; + if (dp->op1) + (*dp->op1)(dp->bytemode1); + obufp = op2out; + if (dp->op2) + (*dp->op2)(dp->bytemode2); + } +} + +/* ARGSUSED */ +OP_ST (ignore) +{ + oappend ("%st"); +} + +/* ARGSUSED */ +OP_STi (ignore) +{ + sprintf (scratchbuf, "%%st(%d)", rm); + oappend (scratchbuf); +} + + +/* capital letters in template are macros */ +putop (template) + char *template; +{ + char *p; + + for (p = template; *p; p++) + { + switch (*p) + { + default: + *obufp++ = *p; + break; + case 'C': /* For jcxz/jecxz */ + if (aflag == 0) + *obufp++ = 'e'; + break; + case 'N': + if ((prefixes & PREFIX_FWAIT) == 0) + *obufp++ = 'n'; + break; + case 'S': + /* operand size flag */ + if (dflag) + *obufp++ = 'l'; + else + *obufp++ = 'w'; + break; + } + } + *obufp = 0; +} + +oappend (s) +char *s; +{ + strcpy (obufp, s); + obufp += strlen (s); + *obufp = 0; +} + +append_prefix () +{ + if (prefixes & PREFIX_CS) + oappend ("%cs:"); + if (prefixes & PREFIX_DS) + oappend ("%ds:"); + if (prefixes & PREFIX_SS) + oappend ("%ss:"); + if (prefixes & PREFIX_ES) + oappend ("%es:"); + if (prefixes & PREFIX_FS) + oappend ("%fs:"); + if (prefixes & PREFIX_GS) + oappend ("%gs:"); +} + +OP_indirE (bytemode) +{ + oappend ("*"); + OP_E (bytemode); +} + +OP_E (bytemode) +{ + int disp; + int havesib; + int didoutput = 0; + int base; + int index; + int scale; + int havebase; + + /* skip mod/rm byte */ + codep++; + + havesib = 0; + havebase = 0; + disp = 0; + + if (mod == 3) + { + switch (bytemode) + { + case b_mode: + oappend (names8[rm]); + break; + case w_mode: + oappend (names16[rm]); + break; + case v_mode: + if (dflag) + oappend (names32[rm]); + else + oappend (names16[rm]); + break; + default: + oappend ("<bad dis table>"); + break; + } + return; + } + + append_prefix (); + if (rm == 4) + { + havesib = 1; + havebase = 1; + scale = (*codep >> 6) & 3; + index = (*codep >> 3) & 7; + base = *codep & 7; + codep++; + } + + switch (mod) + { + case 0: + switch (rm) + { + case 4: + /* implies havesib and havebase */ + if (base == 5) { + havebase = 0; + disp = get32 (); + } + break; + case 5: + disp = get32 (); + break; + default: + havebase = 1; + base = rm; + break; + } + break; + case 1: + disp = *(char *)codep++; + if (rm != 4) + { + havebase = 1; + base = rm; + } + break; + case 2: + disp = get32 (); + if (rm != 4) + { + havebase = 1; + base = rm; + } + break; + } + + if (mod != 0 || rm == 5 || (havesib && base == 5)) + { + sprintf (scratchbuf, "%d", disp); + oappend (scratchbuf); + } + + if (havebase || havesib) + { + oappend ("("); + if (havebase) + oappend (names32[base]); + if (havesib) + { + if (index != 4) + { + sprintf (scratchbuf, ",%s", names32[index]); + oappend (scratchbuf); + } + sprintf (scratchbuf, ",%d", 1 << scale); + oappend (scratchbuf); + } + oappend (")"); + } +} + +OP_G (bytemode) +{ + switch (bytemode) + { + case b_mode: + oappend (names8[reg]); + break; + case w_mode: + oappend (names16[reg]); + break; + case d_mode: + oappend (names32[reg]); + break; + case v_mode: + if (dflag) + oappend (names32[reg]); + else + oappend (names16[reg]); + break; + default: + oappend ("<internal disassembler error>"); + break; + } +} + +get32 () +{ + int x = 0; + + x = *codep++ & 0xff; + x |= (*codep++ & 0xff) << 8; + x |= (*codep++ & 0xff) << 16; + x |= (*codep++ & 0xff) << 24; + return (x); +} + +get16 () +{ + int x = 0; + + x = *codep++ & 0xff; + x |= (*codep++ & 0xff) << 8; + return (x); +} + +OP_REG (code) +{ + char *s; + + switch (code) + { + case indir_dx_reg: s = "(%dx)"; break; + case ax_reg: case cx_reg: case dx_reg: case bx_reg: + case sp_reg: case bp_reg: case si_reg: case di_reg: + s = names16[code - ax_reg]; + break; + case es_reg: case ss_reg: case cs_reg: + case ds_reg: case fs_reg: case gs_reg: + s = names_seg[code - es_reg]; + break; + case al_reg: case ah_reg: case cl_reg: case ch_reg: + case dl_reg: case dh_reg: case bl_reg: case bh_reg: + s = names8[code - al_reg]; + break; + case eAX_reg: case eCX_reg: case eDX_reg: case eBX_reg: + case eSP_reg: case eBP_reg: case eSI_reg: case eDI_reg: + if (dflag) + s = names32[code - eAX_reg]; + else + s = names16[code - eAX_reg]; + break; + default: + s = "<internal disassembler error>"; + break; + } + oappend (s); +} + +OP_I (bytemode) +{ + int op; + + switch (bytemode) + { + case b_mode: + op = *codep++ & 0xff; + break; + case v_mode: + if (dflag) + op = get32 (); + else + op = get16 (); + break; + case w_mode: + op = get16 (); + break; + default: + oappend ("<internal disassembler error>"); + return; + } + sprintf (scratchbuf, "$0x%x", op); + oappend (scratchbuf); +} + +OP_sI (bytemode) +{ + int op; + + switch (bytemode) + { + case b_mode: + op = *(char *)codep++; + break; + case v_mode: + if (dflag) + op = get32 (); + else + op = (short)get16(); + break; + case w_mode: + op = (short)get16 (); + break; + default: + oappend ("<internal disassembler error>"); + return; + } + sprintf (scratchbuf, "$0x%x", op); + oappend (scratchbuf); +} + +OP_J (bytemode) +{ + int disp; + int mask = -1; + + switch (bytemode) + { + case b_mode: + disp = *(char *)codep++; + break; + case v_mode: + if (dflag) + disp = get32 (); + else + { + disp = (short)get16 (); + /* for some reason, a data16 prefix on a jump instruction + means that the pc is masked to 16 bits after the + displacement is added! */ + mask = 0xffff; + } + break; + default: + oappend ("<internal disassembelr error>"); + return; + } + + sprintf (scratchbuf, "0x%x", + (start_pc + codep - start_codep + disp) & mask); + oappend (scratchbuf); +} + +/* ARGSUSED */ +OP_SEG (dummy) +{ + static char *sreg[] = { + "%es","%cs","%ss","%ds","%fs","%gs","%?","%?", + }; + + oappend (sreg[reg]); +} + +OP_DIR (size) +{ + int seg, offset; + + switch (size) + { + case lptr: + if (aflag) + { + offset = get32 (); + seg = get16 (); + } + else + { + offset = get16 (); + seg = get16 (); + } + sprintf (scratchbuf, "0x%x,0x%x", seg, offset); + oappend (scratchbuf); + break; + case v_mode: + if (aflag) + offset = get32 (); + else + offset = (short)get16 (); + + sprintf (scratchbuf, "0x%x", + start_pc + codep - start_codep + offset); + oappend (scratchbuf); + break; + default: + oappend ("<internal disassembler error>"); + break; + } +} + +/* ARGSUSED */ +OP_OFF (bytemode) +{ + int off; + + if (aflag) + off = get32 (); + else + off = get16 (); + + sprintf (scratchbuf, "0x%x", off); + oappend (scratchbuf); +} + +/* ARGSUSED */ +OP_ESDI (dummy) +{ + oappend ("%es:("); + oappend (aflag ? "%edi" : "%di"); + oappend (")"); +} + +/* ARGSUSED */ +OP_DSSI (dummy) +{ + oappend ("%ds:("); + oappend (aflag ? "%esi" : "%si"); + oappend (")"); +} + +/* ARGSUSED */ +OP_ONE (dummy) +{ + oappend ("1"); +} + +/* ARGSUSED */ +OP_C (dummy) +{ + codep++; /* skip mod/rm */ + sprintf (scratchbuf, "%%cr%d", reg); + oappend (scratchbuf); +} + +/* ARGSUSED */ +OP_D (dummy) +{ + codep++; /* skip mod/rm */ + sprintf (scratchbuf, "%%db%d", reg); + oappend (scratchbuf); +} + +/* ARGSUSED */ +OP_T (dummy) +{ + codep++; /* skip mod/rm */ + sprintf (scratchbuf, "%%tr%d", reg); + oappend (scratchbuf); +} + +OP_rm (bytemode) +{ + switch (bytemode) + { + case d_mode: + oappend (names32[rm]); + break; + case w_mode: + oappend (names16[rm]); + break; + } +} + +/* GDB interface */ +#include "defs.h" +#include "param.h" +#include "symtab.h" +#include "frame.h" +#include "inferior.h" + +#define MAXLEN 20 +print_insn (memaddr, stream) + CORE_ADDR memaddr; + FILE *stream; +{ + unsigned char buffer[MAXLEN]; + /* should be expanded if disassembler prints symbol names */ + char outbuf[100]; + int n; + + read_memory (memaddr, buffer, MAXLEN); + + n = i386dis ((int)memaddr, buffer, outbuf); + + fputs (outbuf, stream); + + return (n); +} + diff --git a/gnu/usr.bin/gdb/config/i386bsd-dep.c b/gnu/usr.bin/gdb/config/i386bsd-dep.c new file mode 100644 index 0000000..6172cf7 --- /dev/null +++ b/gnu/usr.bin/gdb/config/i386bsd-dep.c @@ -0,0 +1,1867 @@ +/*- + * This code is derived from software copyrighted by the Free Software + * Foundation. + * + * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. + * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory. + */ + +#ifndef lint +static char sccsid[] = "@(#)i386bsd-dep.c 6.10 (Berkeley) 6/26/91"; +#endif /* not lint */ + +/* Low level interface to ptrace, for GDB when running on the Intel 386. + Copyright (C) 1988, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <stdio.h> +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" +#include "value.h" + +#include <sys/param.h> +#include <sys/dir.h> +#include <signal.h> +#include <sys/ioctl.h> +#include <fcntl.h> + +#include <a.out.h> + +#ifndef N_SET_MAGIC +#define N_SET_MAGIC(exec, val) ((exec).a_magic = (val)) +#endif + +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/uio.h> +#define curpcb Xcurpcb /* XXX avoid leaking declaration from pcb.h */ +#include <sys/user.h> +#undef curpcb +#include <sys/file.h> +#include <sys/stat.h> +#include <sys/ptrace.h> + +#include <machine/reg.h> + +#ifdef KERNELDEBUG +#ifndef NEWVM +#include <sys/vmmac.h> +#include <machine/pte.h> +#else +#include <sys/proc.h> /* for curproc */ +#endif +#include <machine/vmparam.h> +#include <machine/cpu.h> +#include <ctype.h> +#include "symtab.h" /* XXX */ + +#undef vtophys /* XXX */ + +extern int kernel_debugging; + +#define KERNOFF ((unsigned)KERNBASE) +#ifndef NEWVM +#define INKERNEL(x) ((x) >= KERNOFF && (x) < KERNOFF + ctob(slr)) +#define INUPAGE(x) \ + ((x) >= KERNEL_U_ADDR && (x) < KERNEL_U_ADDR + NBPG) +#else +#define INKERNEL(x) ((x) >= KERNOFF) +#endif + +#define PT_ADDR_ANY ((caddr_t) 1) + +/* + * Convert from sysmap pte index to system virtual address & vice-versa. + * (why aren't these in one of the system vm macro files???) + */ +#define smxtob(a) (sbr + (a) * sizeof(pte)) +#define btosmx(b) (((b) - sbr) / sizeof(pte)) + +static int ok_to_cache(); +static int found_pcb; +#ifdef NEWVM +static CORE_ADDR curpcb; +static CORE_ADDR kstack; +#endif + +static void setregmap(); + +extern int errno; + +/* + * This function simply calls ptrace with the given arguments. It exists so + * that all calls to ptrace are isolated in this machine-dependent file. + */ +int +call_ptrace(request, pid, arg3, arg4) + int request; + pid_t pid; + caddr_t arg3; + int arg4; +{ + return(ptrace(request, pid, arg3, arg4)); +} + +kill_inferior() +{ + if (remote_debugging) { +#ifdef KERNELDEBUG + if (kernel_debugging) + /* + * It's a very, very bad idea to go away leaving + * breakpoints in a remote kernel or to leave it + * stopped at a breakpoint. + */ + clear_breakpoints(); +#endif + remote_close(0); + inferior_died(); + } else if (inferior_pid != 0) { + ptrace(PT_KILL, inferior_pid, 0, 0); + wait(0); + inferior_died(); + } +} + +/* + * This is used when GDB is exiting. It gives less chance of error. + */ +kill_inferior_fast() +{ + if (remote_debugging) { +#ifdef KERNELDEBUG + if (kernel_debugging) + clear_breakpoints(); +#endif + remote_close(0); + return; + } + if (inferior_pid == 0) + return; + + ptrace(PT_KILL, inferior_pid, 0, 0); + wait(0); +} + +/* + * Resume execution of the inferior process. If STEP is nonzero, single-step + * it. If SIGNAL is nonzero, give it that signal. + */ +void +resume(step, signal) + int step; + int signal; +{ + errno = 0; + if (remote_debugging) + remote_resume(step, signal); + else { + ptrace(step ? PT_STEP : PT_CONTINUE, inferior_pid, + PT_ADDR_ANY, signal); + if (errno) + perror_with_name("ptrace"); + } +} + +#ifdef ATTACH_DETACH +extern int attach_flag; + +/* + * Start debugging the process whose number is PID. + */ +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, PT_ADDR_ANY, signal); + if (errno) + perror_with_name("ptrace"); + attach_flag = 0; +} +#endif /* ATTACH_DETACH */ + +static unsigned int +get_register_offset() +{ + unsigned int offset; + struct user u; /* XXX */ + unsigned int flags = (char *) &u.u_pcb.pcb_flags - (char *) &u; + + setregmap(ptrace(PT_READ_U, inferior_pid, (caddr_t)flags, 0)); + +#ifdef NEWVM + offset = (char *) &u.u_kproc.kp_proc.p_regs - (char *) &u; + offset = ptrace(PT_READ_U, inferior_pid, (caddr_t)offset, 0) - + USRSTACK; +#else + offset = (char *) &u.u_ar0 - (char *) &u; + offset = ptrace(PT_READ_U, inferior_pid, (caddr_t)offset, 0) - + KERNEL_U_ADDR; +#endif + + return offset; +} + +void +fetch_inferior_registers() +{ + register int regno; + register unsigned int regaddr; + char buf[MAX_REGISTER_RAW_SIZE]; + register int i; + unsigned int offset; + + if (remote_debugging) { + extern char registers[]; + + remote_fetch_registers(registers); + return; + } + + offset = get_register_offset(); + + for (regno = 0; regno < NUM_REGS; regno++) { + 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, + (caddr_t)regaddr, 0); + regaddr += sizeof(int); + } + supply_register(regno, buf); + } +} + +/* + * Store our register values back into the inferior. If REGNO is -1, do this + * for all registers. Otherwise, REGNO specifies which register (so we can + * save time). + */ +store_inferior_registers(regno) + int regno; +{ + register unsigned int regaddr; + char buf[80]; + extern char registers[]; + register int i; + unsigned int offset; + + if (remote_debugging) { + extern char registers[]; + + remote_store_registers(registers); + return; + } + + offset = get_register_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, (caddr_t)regaddr, + *(int *) ®isters[REGISTER_BYTE(regno) + i]); + if (errno != 0) { + sprintf(buf, "writing register number %d(%d)", + regno, i); + perror_with_name(buf); + } + regaddr += sizeof(int); + } + } else + for (regno = 0; regno < NUM_REGS; regno++) { + regaddr = register_addr(regno, offset); + for (i = 0; i < REGISTER_RAW_SIZE(regno); + i += sizeof(int)) { + errno = 0; + ptrace(PT_WRITE_U, inferior_pid, + (caddr_t)regaddr, + *(int *) ®isters[REGISTER_BYTE(regno) + i]); + if (errno != 0) { + sprintf(buf, + "writing register number %d(%d)", + regno, i); + perror_with_name(buf); + } + regaddr += sizeof(int); + } + } +} + +/* + * Copy LEN bytes from inferior's memory starting at MEMADDR to debugger + * memory starting at MYADDR. On failure (cannot read from inferior, usually + * because address is out of bounds) returns the value of errno. + */ +int +read_inferior_memory(memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + register int i; + /* Round starting address down to longword boundary. */ + register CORE_ADDR addr = memaddr & -sizeof(int); + /* Round ending address up; get number of longwords that makes. */ + register int count = (((memaddr + len) - addr) + sizeof(int) - 1) / + sizeof(int); + /* Allocate buffer of that many longwords. */ + register int *buffer = (int *) alloca(count * sizeof(int)); + extern int errno; + + if (remote_debugging) + return (remote_read_inferior_memory(memaddr, myaddr, len)); + + /* Read all the longwords */ + errno = 0; + for (i = 0; i < count && errno == 0; i++, addr += sizeof(int)) + buffer[i] = ptrace(PT_READ_I, inferior_pid, (caddr_t)addr, 0); + + /* Copy appropriate bytes out of the buffer. */ + bcopy((char *) buffer + (memaddr & (sizeof(int) - 1)), myaddr, len); + return(errno); +} + +/* + * Copy LEN bytes of data from debugger memory at MYADDR to inferior's memory + * at MEMADDR. On failure (cannot write the inferior) returns the value of + * errno. + */ + +int +write_inferior_memory(memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + register int i; + /* Round starting address down to longword boundary. */ + register CORE_ADDR addr = memaddr & -sizeof(int); + /* Round ending address up; get number of longwords that makes. */ + register int count = (((memaddr + len) - addr) + sizeof(int) - 1) / + sizeof(int); + /* Allocate buffer of that many longwords. */ + register int *buffer = (int *) alloca(count * sizeof(int)); + extern int errno; + + /* + * Fill start and end extra bytes of buffer with existing memory + * data. + */ + if (remote_debugging) + return (remote_write_inferior_memory(memaddr, myaddr, len)); + + /* + * Fill start and end extra bytes of buffer with existing memory + * data. + */ + buffer[0] = ptrace(PT_READ_I, inferior_pid, (caddr_t)addr, 0); + + if (count > 1) + buffer[count - 1] = ptrace(PT_READ_I, inferior_pid, + (caddr_t)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. */ + + errno = 0; + for (i = 0; i < count && errno == 0; i++, addr += sizeof(int)) + ptrace(PT_WRITE_I, inferior_pid, (caddr_t)addr, buffer[i]); + + return(errno); +} + + +/* + * Work with core dump and executable files, for GDB. + * This code would be in core.c if it weren't machine-dependent. + */ + +#ifndef N_TXTADDR +#define N_TXTADDR(hdr) 0 +#endif /* no N_TXTADDR */ + +#ifndef N_DATADDR +#define N_DATADDR(hdr) hdr.a_text +#endif /* no N_DATADDR */ + +/* + * Make COFF and non-COFF names for things a little more compatible to reduce + * conditionals later. + */ + +#ifndef AOUTHDR +#define AOUTHDR struct exec +#endif + +extern char *sys_siglist[]; + + +/* Hook for `exec_file_command' command to call. */ + +extern void (*exec_file_display_hook) (); + +/* File names of core file and executable file. */ + +extern char *corefile; +extern char *execfile; + +/* Descriptors on which core file and executable file are open. + Note that the execchan is closed when an inferior is created + and reopened if the inferior dies or is killed. */ + +extern int corechan; +extern int execchan; + +/* Last modification time of executable file. + Also used in source.c to compare against mtime of a source file. */ + +extern int exec_mtime; + +/* Virtual addresses of bounds of the two areas of memory in the core file. */ + +extern CORE_ADDR data_start; +extern CORE_ADDR data_end; +extern CORE_ADDR stack_start; +extern CORE_ADDR stack_end; + +/* Virtual addresses of bounds of two areas of memory in the exec file. + Note that the data area in the exec file is used only when there is no core file. */ + +extern CORE_ADDR text_start; +extern CORE_ADDR text_end; + +extern CORE_ADDR exec_data_start; +extern CORE_ADDR exec_data_end; + +/* Address in executable file of start of text area data. */ + +extern int text_offset; + +/* Address in executable file of start of data area data. */ + +extern int exec_data_offset; + +/* Address in core file of start of data area data. */ + +extern int data_offset; + +/* Address in core file of start of stack area data. */ + +extern int stack_offset; + +/* a.out header saved in core file. */ + +extern AOUTHDR core_aouthdr; + +/* a.out header of exec file. */ + +extern AOUTHDR exec_aouthdr; + +extern void validate_files (); + +extern int (*core_file_hook)(); + +#ifdef KERNELDEBUG +/* + * Kernel debugging routines. + */ + +#define IOTOP 0x100000 /* XXX should get this from include file */ +#define IOBASE 0xa0000 /* XXX should get this from include file */ + +static CORE_ADDR file_offset; +static CORE_ADDR lowram; +static CORE_ADDR sbr; +static CORE_ADDR slr; +static struct pcb pcb; + +static CORE_ADDR +ksym_lookup(name) + char *name; +{ + struct symbol *sym; + int i; + + if ((i = lookup_misc_func(name)) < 0) + error("kernel symbol `%s' not found.", name); + + return (misc_function_vector[i].address); +} + +/* + * return true if 'len' bytes starting at 'addr' can be read out as + * longwords and/or locally cached (this is mostly for memory mapped + * i/o register access when debugging remote kernels). + * + * XXX the HP code does this differently with NEWVM + */ +static int +ok_to_cache(addr, len) +{ + static CORE_ADDR atdevbase; + + if (! atdevbase) + atdevbase = ksym_lookup("atdevbase"); + + if (addr >= atdevbase && addr < atdevbase + (IOTOP - IOBASE)) + return (0); + + return (1); +} + +static +physrd(addr, dat, len) + u_int addr; + char *dat; +{ + if (lseek(corechan, addr - file_offset, L_SET) == -1) + return (-1); + if (read(corechan, dat, len) != len) + return (-1); + + return (0); +} + +/* + * When looking at kernel data space through /dev/mem or with a core file, do + * virtual memory mapping. + */ +#ifdef NEWVM +static CORE_ADDR +vtophys(addr) + CORE_ADDR addr; +{ + CORE_ADDR v; + struct pte pte; + static CORE_ADDR PTD = -1; + CORE_ADDR current_ptd; + + /* + * If we're looking at the kernel stack, + * munge the address to refer to the user space mapping instead; + * that way we get the requested process's kstack, not the running one. + */ + if (addr >= kstack && addr < kstack + ctob(UPAGES)) + addr = (addr - kstack) + curpcb; + + /* + * We may no longer have a linear system page table... + * + * Here's the scoop. IdlePTD contains the physical address + * of a page table directory that always maps the kernel. + * IdlePTD is in memory that is mapped 1-to-1, so we can + * find it easily given its 'virtual' address from ksym_lookup(). + * For hysterical reasons, the value of IdlePTD is stored in sbr. + * + * To look up a kernel address, we first convert it to a 1st-level + * address and look it up in IdlePTD. This gives us the physical + * address of a page table page; we extract the 2nd-level part of + * VA and read the 2nd-level pte. Finally, we add the offset part + * of the VA into the physical address from the pte and return it. + * + * User addresses are a little more complicated. If we don't have + * a current PCB from read_pcb(), we use PTD, which is the (fixed) + * virtual address of the current ptd. Since it's NOT in 1-to-1 + * kernel space, we must look it up using IdlePTD. If we do have + * a pcb, we get the ptd from pcb_ptd. + */ + + if (INKERNEL(addr)) + current_ptd = sbr; + else if (found_pcb == 0) { + if (PTD == -1) + PTD = vtophys(ksym_lookup("PTD")); + current_ptd = PTD; + } else + current_ptd = pcb.pcb_ptd; + + /* + * Read the first-level page table (ptd). + */ + v = current_ptd + ((unsigned)addr >> PD_SHIFT) * sizeof pte; + if (physrd(v, (char *)&pte, sizeof pte) || pte.pg_v == 0) + return (~0); + + /* + * Read the second-level page table. + */ + v = i386_ptob(pte.pg_pfnum) + ((addr&PT_MASK) >> PG_SHIFT) * sizeof pte; + if (physrd(v, (char *) &pte, sizeof(pte)) || pte.pg_v == 0) + return (~0); + + addr = i386_ptob(pte.pg_pfnum) + (addr & PGOFSET); +#if 0 + printf("vtophys(%x) -> %x\n", oldaddr, addr); +#endif + return (addr); +} +#else +static CORE_ADDR +vtophys(addr) + CORE_ADDR addr; +{ + CORE_ADDR v; + struct pte pte; + CORE_ADDR oldaddr = addr; + + if (found_pcb == 0 && INUPAGE(addr)) { + static CORE_ADDR pSwtchmap; + + if (pSwtchmap == 0) + pSwtchmap = vtophys(ksym_lookup("Swtchmap")); + addr = pSwtchmap; + } else if (INKERNEL(addr)) { + /* + * In system space get system pte. If valid or reclaimable + * then physical address is combination of its page number + * and the page offset of the original address. + */ + addr = smxtob(btop(addr - KERNOFF)) - KERNOFF; + } else { + v = btop(addr); + if (v < pcb.pcb_p0lr) + addr = (CORE_ADDR) pcb.pcb_p0br + + v * sizeof (struct pte); + else if (v >= pcb.pcb_p1lr && v < P1PAGES) + addr = (CORE_ADDR) pcb.pcb_p0br + + ((pcb.pcb_szpt * NPTEPG - HIGHPAGES) - + (BTOPUSRSTACK - v)) * sizeof (struct pte); + else + return (~0); + + /* + * For p0/p1 address, user-level page table should be in + * kernel vm. Do second-level indirect by recursing. + */ + if (!INKERNEL(addr)) + return (~0); + + addr = vtophys(addr); + } + /* + * Addr is now address of the pte of the page we are interested in; + * get the pte and paste up the physical address. + */ + if (physrd(addr, (char *) &pte, sizeof(pte))) + return (~0); + + if (pte.pg_v == 0 && (pte.pg_fod || pte.pg_pfnum == 0)) + return (~0); + + addr = (CORE_ADDR)ptob(pte.pg_pfnum) + (oldaddr & PGOFSET); +#if 0 + printf("vtophys(%x) -> %x\n", oldaddr, addr); +#endif + return (addr); +} + +#endif + +static +kvread(addr) + CORE_ADDR addr; +{ + CORE_ADDR paddr = vtophys(addr); + + if (paddr != ~0) + if (physrd(paddr, (char *)&addr, sizeof(addr)) == 0); + return (addr); + + return (~0); +} + +static void +read_pcb(uaddr) + u_int uaddr; +{ + int i; + int *pcb_regs = (int *)&pcb; + +#ifdef NEWVM + if (physrd(uaddr, (char *)&pcb, sizeof pcb)) + error("cannot read pcb at %x\n", uaddr); + printf("current pcb at %x\n", uaddr); +#else + if (physrd(uaddr, (char *)&pcb, sizeof pcb)) + error("cannot read pcb at %x\n", uaddr); + printf("p0br %x p0lr %x p1br %x p1lr %x\n", + pcb.pcb_p0br, pcb.pcb_p0lr, pcb.pcb_p1br, pcb.pcb_p1lr); +#endif + + /* + * get the register values out of the sys pcb and + * store them where `read_register' will find them. + */ + for (i = 0; i < 8; ++i) + supply_register(i, &pcb_regs[i+10]); + supply_register(8, &pcb_regs[8]); /* eip */ + supply_register(9, &pcb_regs[9]); /* eflags */ + for (i = 10; i < 13; ++i) /* cs, ss, ds */ + supply_register(i, &pcb_regs[i+9]); + supply_register(13, &pcb_regs[18]); /* es */ + for (i = 14; i < 16; ++i) /* fs, gs */ + supply_register(i, &pcb_regs[i+8]); + + /* XXX 80387 registers? */ +} + +static void +setup_kernel_debugging() +{ + struct stat stb; + int devmem = 0; + CORE_ADDR addr; + + fstat(corechan, &stb); + if ((stb.st_mode & S_IFMT) == S_IFCHR && stb.st_rdev == makedev(2, 0)) + devmem = 1; + +#ifdef NEWVM + physrd(ksym_lookup("IdlePTD") - KERNOFF, &sbr, sizeof sbr); + slr = 2 * NPTEPG; /* XXX temporary */ + printf("IdlePTD %x\n", sbr); + curpcb = ksym_lookup("curpcb") - KERNOFF; + physrd(curpcb, &curpcb, sizeof curpcb); + kstack = ksym_lookup("kstack"); +#else + sbr = ksym_lookup("Sysmap"); + slr = ksym_lookup("Syssize"); + printf("sbr %x slr %x\n", sbr, slr); +#endif + + /* + * pcb where "panic" saved registers in first thing in current + * u area. + */ +#ifndef NEWVM + read_pcb(vtophys(ksym_lookup("u"))); +#endif + found_pcb = 1; + if (!devmem) { + /* find stack frame */ + CORE_ADDR panicstr; + char buf[256]; + register char *cp; + + panicstr = kvread(ksym_lookup("panicstr")); + if (panicstr == ~0) + return; + (void) kernel_core_file_hook(panicstr, buf, sizeof(buf)); + for (cp = buf; cp < &buf[sizeof(buf)] && *cp; cp++) + if (!isascii(*cp) || (!isprint(*cp) && !isspace(*cp))) + *cp = '?'; + if (*cp) + *cp = '\0'; + printf("panic: %s\n", buf); + read_pcb(ksym_lookup("dumppcb") - KERNOFF); + } +#ifdef NEWVM + else + read_pcb(vtophys(kstack)); +#endif + + stack_start = USRSTACK; + stack_end = USRSTACK + ctob(UPAGES); +} + +set_paddr_command(arg) + char *arg; +{ + u_int uaddr; + + if (!arg) + error_no_arg("ps-style address for new current process"); + if (!kernel_debugging) + error("not debugging kernel"); + uaddr = (u_int) parse_and_eval_address(arg); +#ifndef NEWVM + read_pcb(ctob(uaddr)); +#else + /* p_addr is now a pcb virtual address */ + read_pcb(vtophys(uaddr)); + curpcb = uaddr; +#endif + + flush_cached_frames(); + set_current_frame(create_new_frame(read_register(FP_REGNUM), read_pc())); + select_frame(get_current_frame(), 0); +} + +/* + * read len bytes from kernel virtual address 'addr' into local + * buffer 'buf'. Return 0 if read ok, 1 otherwise. On read + * errors, portion of buffer not read is zeroed. + */ +kernel_core_file_hook(addr, buf, len) + CORE_ADDR addr; + char *buf; + int len; +{ + int i; + CORE_ADDR paddr; + + while (len > 0) { + paddr = vtophys(addr); + if (paddr == ~0) { + bzero(buf, len); + return (1); + } + /* we can't read across a page boundary */ + i = min(len, NBPG - (addr & PGOFSET)); + if (physrd(paddr, buf, i)) { + bzero(buf, len); + return (1); + } + buf += i; + addr += i; + len -= i; + } + return (0); +} +#endif + +core_file_command(filename, from_tty) + char *filename; + int from_tty; +{ + int val; + extern char registers[]; +#ifdef KERNELDEBUG + struct stat stb; +#endif + + /* + * Discard all vestiges of any previous core file and mark data and + * stack spaces as empty. + */ + if (corefile) + free(corefile); + corefile = 0; + core_file_hook = 0; + + if (corechan >= 0) + close(corechan); + corechan = -1; + + /* Now, if a new core file was specified, open it and digest it. */ + + if (filename == 0) { + if (from_tty) + printf("No core file now.\n"); + return; + } + filename = tilde_expand(filename); + make_cleanup(free, filename); + if (have_inferior_p()) + error("To look at a core file, you must kill the inferior with \"kill\"."); + corechan = open(filename, O_RDONLY, 0); + if (corechan < 0) + perror_with_name(filename); + +#ifdef KERNELDEBUG + fstat(corechan, &stb); + + if (kernel_debugging) { + setup_kernel_debugging(); + core_file_hook = kernel_core_file_hook; + } else if ((stb.st_mode & S_IFMT) == S_IFCHR && + stb.st_rdev == makedev(2, 1)) { + /* looking at /dev/kmem */ + data_offset = data_start = KERNOFF; + data_end = ~0; /* XXX */ + stack_end = stack_start = data_end; + } else +#endif + { + /* + * 4.2-style core dump file. + */ + struct user u; + unsigned int reg_offset; + + val = myread(corechan, &u, sizeof u); + if (val < 0) + perror_with_name("Not a core file: reading upage"); + if (val != sizeof u) + error("Not a core file: could only read %d bytes", val); + + /* + * We are depending on exec_file_command having been + * called previously to set exec_data_start. Since + * the executable and the core file share the same + * text segment, the address of the data segment will + * be the same in both. + */ + data_start = exec_data_start; + +#ifndef NEWVM + data_end = data_start + NBPG * u.u_dsize; + stack_start = stack_end - NBPG * u.u_ssize; + data_offset = NBPG * UPAGES; + stack_offset = NBPG * (UPAGES + u.u_dsize); + + /* + * Some machines put an absolute address in here and + * some put the offset in the upage of the regs. + */ + reg_offset = (int) u.u_ar0 - KERNEL_U_ADDR; +#else + data_end = data_start + + NBPG * u.u_kproc.kp_eproc.e_vm.vm_dsize; + stack_start = stack_end - + NBPG * u.u_kproc.kp_eproc.e_vm.vm_ssize; + data_offset = NBPG * UPAGES; + stack_offset = NBPG * + (UPAGES + u.u_kproc.kp_eproc.e_vm.vm_dsize); + + reg_offset = (int) u.u_kproc.kp_proc.p_regs - USRSTACK; +#endif + + setregmap(u.u_pcb.pcb_flags); + + /* + * I don't know where to find this info. So, for now, + * mark it as not available. + */ + /* N_SET_MAGIC (core_aouthdr, 0); */ + bzero ((char *) &core_aouthdr, sizeof core_aouthdr); + + /* + * Read the register values out of the core file and + * store them where `read_register' will find them. + */ + { + register int regno; + + for (regno = 0; regno < NUM_REGS; regno++) { + char buf[MAX_REGISTER_RAW_SIZE]; + + val = lseek(corechan, register_addr(regno, reg_offset), 0); + if (val < 0 + || (val = myread(corechan, buf, sizeof buf)) < 0) { + char *buffer = (char *) alloca(strlen(reg_names[regno]) + 30); + strcpy(buffer, "Reading register "); + strcat(buffer, reg_names[regno]); + perror_with_name(buffer); + } + supply_register(regno, buf); + } + } + } +#endif + if (filename[0] == '/') + corefile = savestring(filename, strlen(filename)); + else + corefile = concat(current_directory, "/", filename); + + set_current_frame(create_new_frame(read_register(FP_REGNUM), + read_pc())); + select_frame(get_current_frame(), 0); + validate_files(); +} + +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 = 0; + stack_start = 0; + stack_end = 0; + text_start = 0; + text_end = 0; + exec_data_start = 0; + exec_data_end = 0; + if (execchan >= 0) + close(execchan); + execchan = -1; + + /* Now open and digest the file the user requested, if any. */ + + if (filename) { + filename = tilde_expand(filename); + make_cleanup(free, filename); + + execchan = openp(getenv("PATH"), 1, filename, O_RDONLY, 0, + &execfile); + if (execchan < 0) + perror_with_name(filename); + + { + struct stat st_exec; + +#ifdef HEADER_SEEK_FD + HEADER_SEEK_FD(execchan); +#endif + + val = myread(execchan, &exec_aouthdr, sizeof(AOUTHDR)); + + if (val < 0) + perror_with_name(filename); + +#ifdef KERNELDEBUG + if (kernel_debugging) { + /* Gross and disgusting XXX */ + text_start = KERNTEXT_BASE; + exec_data_start = KERNTEXT_BASE + + (exec_aouthdr.a_text + 4095) & ~ 4095; + } else { +#endif + text_start = N_TXTADDR(exec_aouthdr); + exec_data_start = N_DATADDR(exec_aouthdr); +#ifdef KERNELDEBUG + } +#endif + + text_offset = N_TXTOFF(exec_aouthdr); + exec_data_offset = N_TXTOFF(exec_aouthdr) + exec_aouthdr.a_text; + + text_end = text_start + exec_aouthdr.a_text; + exec_data_end = exec_data_start + exec_aouthdr.a_data; + + 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); +} + +int dummy_code[] = { + 0xb8909090, /* nop; nop; nop; movl $0x32323232,%eax */ + 0x32323232, +#define DUMMY_CALL_INDEX 1 + 0x90ccd0ff, /* call %eax; int3; nop */ +}; + +/* + * Build `dummy' call instructions on inferior's stack to cause + * it to call a subroutine. + * + * N.B. - code in wait_for_inferior requires that sp < pc < fp when + * we take the trap 2 above so it will recognize that we stopped + * at a `dummy' call. So, after the call sp is *not* decremented + * to clean the arguments, code & other stuff we lay on the stack. + * Since the regs are restored to saved values at the breakpoint, + * sp will get reset correctly. Also, this restore means we don't + * have to construct frame linkage info to save pc & fp. The lack + * of frame linkage means we can't do a backtrace, etc., if the + * called function gets a fault or hits a breakpoint but code in + * run_stack_dummy makes this impossible anyway. + */ +CORE_ADDR +setup_dummy(sp, funaddr, nargs, args, struct_return_bytes, pushfn) + CORE_ADDR sp; + CORE_ADDR funaddr; + int nargs; + value *args; + int struct_return_bytes; + CORE_ADDR (*pushfn)(); +{ + int padding, i; + CORE_ADDR top = sp, struct_addr, pc; + + i = arg_stacklen(nargs, args) + struct_return_bytes + + sizeof(dummy_code); + if (i & 3) + padding = 4 - (i & 3); + else + padding = 0; + pc = sp - sizeof(dummy_code); + sp = pc - padding - struct_return_bytes; + struct_addr = sp; + while (--nargs >= 0) + sp = (*pushfn)(sp, *args++); + if (struct_return_bytes) + STORE_STRUCT_RETURN(struct_addr, sp); + write_register(SP_REGNUM, sp); + + dummy_code[DUMMY_CALL_INDEX] = (int)funaddr; + write_memory(pc, (char *)dummy_code, sizeof(dummy_code)); + + return pc; +} + +/* 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 %esp */ + { + /* 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) + return (-1); + /* 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) + return (-1); + /* 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; + + pfi = get_prev_frame_info ((fi)); + if (pfi == 0) + { + /* Note: this can happen if we are looking at the frame for + main, because FRAME_CHAIN_VALID won't let us go into + start. If we have debugging symbols, that's not really + a big deal; it just means it will only show as many arguments + to main as are declared. */ + return -1; + } + else + { + retpc = pfi->pc; + op = read_memory_integer (retpc, 1); + if (op == 0x59) + /* pop %ecx */ + return 1; + else if (op == 0x83) + { + op = read_memory_integer (retpc+1, 1); + if (op == 0xc4) + /* addl $<signed imm 8 bits>, %esp */ + return (read_memory_integer (retpc+2,1)&0xff)/4; + else + return 0; + } + else if (op == 0x81) + { /* add with 32 bit immediate */ + op = read_memory_integer (retpc+1, 1); + if (op == 0xc4) + /* addl $<imm 32>, %esp */ + return read_memory_integer (retpc+2, 4) / 4; + else + return 0; + } + else + { + return 0; + } + } +} + +/* + * parse the first few instructions of the function to see + * what registers were stored. + * + * We handle these cases: + * + * The startup sequence can be at the start of the function, + * or the function can start with a branch to startup code at the end. + * + * %ebp can be set up with either the 'enter' instruction, or + * 'pushl %ebp, movl %esp, %ebp' (enter is too slow to be useful, + * but was once used in the sys5 compiler) + * + * Local space is allocated just below the saved %ebp by either the + * 'enter' instruction, or by 'subl $<size>, %esp'. 'enter' has + * a 16 bit unsigned argument for space to allocate, and the + * 'addl' instruction could have either a signed byte, or + * 32 bit immediate. + * + * Next, the registers used by this function are pushed. In + * the sys5 compiler they will always be in the order: %edi, %esi, %ebx + * (and sometimes a harmless bug causes it to also save but not restore %eax); + * however, the code below is willing to see the pushes in any order, + * and will handle up to 8 of them. + * + * If the setup sequence is at the end of the function, then the + * next instruction will be a branch back to the start. + */ + +i386_frame_find_saved_regs (fip, fsrp) + struct frame_info *fip; + struct frame_saved_regs *fsrp; +{ + unsigned long locals; + unsigned char *p; + unsigned char op; + CORE_ADDR dummy_bottom; + CORE_ADDR adr; + int i; + + bzero (fsrp, sizeof *fsrp); + +#if 0 + /* if frame is the end of a dummy, compute where the + * beginning would be + */ + dummy_bottom = fip->frame - 4 - NUM_REGS*4 - 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 - 4; + for (i = 0; i < NUM_REGS; i++) + { + fsrp->regs[i] = adr; + adr -= 4; + } + return; + } +#endif + + 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_pop_frame () +{ + FRAME frame = get_current_frame (); + CORE_ADDR fp; + int regnum; + struct frame_saved_regs fsr; + struct frame_info *fi; + + 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) + write_register (regnum, read_memory_integer (adr, 4)); + } + 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 ())); +} + +/* this table must line up with REGISTER_NAMES in m-i386.h */ +/* symbols like 'EAX' come from <sys/reg.h> */ +static int trapmap[] = +{ + tEAX, tECX, tEDX, tEBX, + tESP, tEBP, tESI, tEDI, + tEIP, tEFLAGS, tCS, tSS, + tDS, tES, tES, tES /* lies: no fs or gs */ +}; +static int syscallmap[] = +{ + sEAX, sECX, sEDX, sEBX, + sESP, sEBP, sESI, sEDI, + sEIP, sEFLAGS, sCS, sSS, + sCS, sCS, sCS, sCS /* lies: no ds, es, fs or gs */ +}; +static int *regmap; + +static void +setregmap(flags) + int flags; +{ +#ifdef FM_TRAP + regmap = flags & FM_TRAP ? trapmap: syscallmap; +#elif EX_TRAPSTK + regmap = flags & EX_TRAPSTK ? trapmap : syscallmap; +#else + regmap = trapmap; /* the lesser evil */ +#endif +} + +/* blockend is the value of u.u_ar0, and points to the + * place where GS is stored + */ +i386_register_u_addr (blockend, regnum) +{ +#if 0 + /* this will be needed if fp registers are reinstated */ + /* for now, you can look at them with 'info float' + * sys5 wont let you change them with ptrace anyway + */ + if (regnum >= FP0_REGNUM && regnum <= FP7_REGNUM) + { + int ubase, fpstate; + struct user u; + ubase = blockend + 4 * (SS + 1) - KSTKSZ; + fpstate = ubase + ((char *)&u.u_fpstate - (char *)&u); + return (fpstate + 0x1c + 10 * (regnum - FP0_REGNUM)); + } + else +#endif + return (blockend + 4 * regmap[regnum]); +} + +i387_to_double (from, to) + char *from; + char *to; +{ + long *lp; + /* push extended mode on 387 stack, then pop in double mode + * + * first, set exception masks so no error is generated - + * number will be rounded to inf or 0, if necessary + */ + asm ("pushl %eax"); /* grab a stack slot */ + asm ("fstcw (%esp)"); /* get 387 control word */ + asm ("movl (%esp),%eax"); /* save old value */ + asm ("orl $0x3f,%eax"); /* mask all exceptions */ + asm ("pushl %eax"); + asm ("fldcw (%esp)"); /* load new value into 387 */ + + asm ("movl 8(%ebp),%eax"); + asm ("fldt (%eax)"); /* push extended number on 387 stack */ + asm ("fwait"); + asm ("movl 12(%ebp),%eax"); + asm ("fstpl (%eax)"); /* pop double */ + asm ("fwait"); + + asm ("popl %eax"); /* flush modified control word */ + asm ("fnclex"); /* clear exceptions */ + asm ("fldcw (%esp)"); /* restore original control word */ + asm ("popl %eax"); /* flush saved copy */ +} + +double_to_i387 (from, to) + char *from; + char *to; +{ + /* push double mode on 387 stack, then pop in extended mode + * no errors are possible because every 64-bit pattern + * can be converted to an extended + */ + asm ("movl 8(%ebp),%eax"); + asm ("fldl (%eax)"); + asm ("fwait"); + asm ("movl 12(%ebp),%eax"); + asm ("fstpt (%eax)"); + asm ("fwait"); +} + +struct env387 +{ + unsigned short control; + unsigned short r0; + unsigned short status; + unsigned short r1; + unsigned short tag; + unsigned short r2; + unsigned long eip; + unsigned short code_seg; + unsigned short opcode; + unsigned long operand; + unsigned short operand_seg; + unsigned short r3; + unsigned char regs[8][10]; +}; + +static +print_387_control_word (control) +unsigned short control; +{ + printf ("control 0x%04x: ", control); + printf ("compute to "); + switch ((control >> 8) & 3) + { + case 0: printf ("24 bits; "); break; + case 1: printf ("(bad); "); break; + case 2: printf ("53 bits; "); break; + case 3: printf ("64 bits; "); break; + } + printf ("round "); + switch ((control >> 10) & 3) + { + case 0: printf ("NEAREST; "); break; + case 1: printf ("DOWN; "); break; + case 2: printf ("UP; "); break; + case 3: printf ("CHOP; "); break; + } + if (control & 0x3f) + { + printf ("mask:"); + if (control & 0x0001) printf (" INVALID"); + if (control & 0x0002) printf (" DENORM"); + if (control & 0x0004) printf (" DIVZ"); + if (control & 0x0008) printf (" OVERF"); + if (control & 0x0010) printf (" UNDERF"); + if (control & 0x0020) printf (" LOS"); + printf (";"); + } + printf ("\n"); + if (control & 0xe080) printf ("warning: reserved bits on 0x%x\n", + control & 0xe080); +} + +static +print_387_status_word (status) + unsigned short status; +{ + printf ("status 0x%04x: ", status); + if (status & 0xff) + { + printf ("exceptions:"); + if (status & 0x0001) printf (" INVALID"); + if (status & 0x0002) printf (" DENORM"); + if (status & 0x0004) printf (" DIVZ"); + if (status & 0x0008) printf (" OVERF"); + if (status & 0x0010) printf (" UNDERF"); + if (status & 0x0020) printf (" LOS"); + if (status & 0x0040) printf (" FPSTACK"); + printf ("; "); + } + printf ("flags: %d%d%d%d; ", + (status & 0x4000) != 0, + (status & 0x0400) != 0, + (status & 0x0200) != 0, + (status & 0x0100) != 0); + + printf ("top %d\n", (status >> 11) & 7); +} + +static +print_387_status (status, ep) + unsigned short status; + struct env387 *ep; +{ + int i; + int bothstatus; + int top; + int fpreg; + unsigned char *p; + + bothstatus = ((status != 0) && (ep->status != 0)); + if (status != 0) + { + if (bothstatus) + printf ("u: "); + print_387_status_word (status); + } + + if (ep->status != 0) + { + if (bothstatus) + printf ("e: "); + print_387_status_word (ep->status); + } + + print_387_control_word (ep->control); + printf ("last exception: "); + printf ("opcode 0x%x; ", ep->opcode); + printf ("pc 0x%x:0x%x; ", ep->code_seg, ep->eip); + printf ("operand 0x%x:0x%x\n", ep->operand_seg, ep->operand); + + top = (ep->status >> 11) & 7; + + printf ("regno tag msb lsb value\n"); + for (fpreg = 7; fpreg >= 0; fpreg--) + { + double val; + + printf ("%s %d: ", fpreg == top ? "=>" : " ", fpreg); + + switch ((ep->tag >> (fpreg * 2)) & 3) + { + case 0: printf ("valid "); break; + case 1: printf ("zero "); break; + case 2: printf ("trap "); break; + case 3: printf ("empty "); break; + } + for (i = 9; i >= 0; i--) + printf ("%02x", ep->regs[fpreg][i]); + + i387_to_double (ep->regs[fpreg], (char *)&val); + printf (" %g\n", val); + } + if (ep->r0) + printf ("warning: reserved0 is 0x%x\n", ep->r0); + if (ep->r1) + printf ("warning: reserved1 is 0x%x\n", ep->r1); + if (ep->r2) + printf ("warning: reserved2 is 0x%x\n", ep->r2); + if (ep->r3) + printf ("warning: reserved3 is 0x%x\n", ep->r3); +} + +#ifndef U_FPSTATE +#define U_FPSTATE(u) u.u_fpstate +#endif + +i386_float_info () +{ + struct user u; /* just for address computations */ + int i; +#ifndef __386BSD__ + /* fpstate defined in <sys/user.h> */ + struct fpstate *fpstatep; + char buf[sizeof (struct fpstate) + 2 * sizeof (int)]; + unsigned int uaddr; + char fpvalid; + unsigned int rounded_addr; + unsigned int rounded_size; + extern int corechan; + int skip; + + uaddr = (char *)&u.u_fpvalid - (char *)&u; + if (have_inferior_p()) + { + unsigned int data; + unsigned int mask; + + rounded_addr = uaddr & -sizeof (int); + data = ptrace (3, inferior_pid, rounded_addr, 0); + mask = 0xff << ((uaddr - rounded_addr) * 8); + + fpvalid = ((data & mask) != 0); + } + else + { + if (lseek (corechan, uaddr, 0) < 0) + perror ("seek on core file"); + if (myread (corechan, &fpvalid, 1) < 0) + perror ("read on core file"); + + } + + if (fpvalid == 0) + { + printf ("no floating point status saved\n"); + return; + } + + uaddr = (char *)&U_FPSTATE(u) - (char *)&u; + if (have_inferior_p ()) + { + int *ip; + + rounded_addr = uaddr & -sizeof (int); + rounded_size = (((uaddr + sizeof (struct fpstate)) - uaddr) + + sizeof (int) - 1) / sizeof (int); + skip = uaddr - rounded_addr; + + ip = (int *)buf; + for (i = 0; i < rounded_size; i++) + { + *ip++ = ptrace (3, inferior_pid, rounded_addr, 0); + rounded_addr += sizeof (int); + } + } + else + { + if (lseek (corechan, uaddr, 0) < 0) + perror_with_name ("seek on core file"); + if (myread (corechan, buf, sizeof (struct fpstate)) < 0) + perror_with_name ("read from core file"); + skip = 0; + } + + fpstatep = (struct fpstate *)(buf + skip); + print_387_status (fpstatep->status, (struct env387 *)fpstatep->state); +#endif +} + +void +_initialize_i386bsd_dep() +{ +#ifdef KERNELDEBUG + add_com ("process-address", class_obscure, set_paddr_command, + "The process identified by (ps-style) ADDR becomes the\n\ +\"current\" process context for kernel debugging."); + add_com_alias ("paddr", "process-address", class_obscure, 0); +#endif +} diff --git a/gnu/usr.bin/gdb/config/m-i386-sv32.h b/gnu/usr.bin/gdb/config/m-i386-sv32.h new file mode 100644 index 0000000..38fb4eb --- /dev/null +++ b/gnu/usr.bin/gdb/config/m-i386-sv32.h @@ -0,0 +1,28 @@ +/* Macro defintions for i386, running System V 3.2. + Copyright (C) 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 "m-i386.h" + +/* Apparently there is inconsistency among various System V's about what + the name of this field is. */ +#define U_FPSTATE(u) u.u_fps.u_fpstate + +/* TIOCGETC is defined in System V 3.2 termio.h, but struct tchars + is not. This makes problems for inflow.c. */ +#define TIOCGETC_BROKEN diff --git a/gnu/usr.bin/gdb/config/m-i386.h b/gnu/usr.bin/gdb/config/m-i386.h new file mode 100644 index 0000000..5449ec4 --- /dev/null +++ b/gnu/usr.bin/gdb/config/m-i386.h @@ -0,0 +1,394 @@ +/* Macro defintions for i386. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Define the bit, byte, and word ordering of the machine. */ +/* #define BITS_BIG_ENDIAN */ +/* #define BYTES_BIG_ENDIAN */ +/* #define WORDS_BIG_ENDIAN */ + +/* + * Changes for 80386 by Pace Willisson (pace@prep.ai.mit.edu) + * July 1988 + */ + + +#ifndef i386 +#define i386 +#endif + +/* I'm running gdb 3.4 under 386/ix 2.0.2, which is a derivative of AT&T's +Sys V/386 3.2. + +On some machines, gdb crashes when it's starting up while calling the +vendor's termio tgetent() routine. It always works when run under +itself (actually, under 3.2, it's not an infinitely recursive bug.) +After some poking around, it appears that depending on the environment +size, or whether you're running YP, or the phase of the moon or something, +the stack is not always long-aligned when main() is called, and tgetent() +takes strong offense at that. On some machines this bug never appears, but +on those where it does, it occurs quite reliably. */ +#define ALIGN_STACK_ON_STARTUP + +/* define USG if you are using sys5 /usr/include's */ +#define USG + +/* USG systems need these */ +#define vfork() fork() +#define MAXPATHLEN 500 + +/* define this if you don't have the extension to coff that allows + * file names to appear in the string table + * (aux.x_file.x_foff) + */ +#define COFF_NO_LONG_FILE_NAMES + +/* turn this on when rest of gdb is ready */ +/* #define IEEE_FLOAT */ + +#define NBPG NBPC +#define UPAGES USIZE + +#define HAVE_TERMIO + +/* Get rid of any system-imposed stack limit if possible. */ + +/* #define SET_STACK_LIMIT_HUGE not in sys5 */ + +/* Define this if the C compiler puts an underscore at the front + of external names before giving them to the linker. */ + +/* #define NAMES_HAVE_UNDERSCORE */ + +/* Specify debugger information format. */ + +/* #define READ_DBX_FORMAT */ +#define COFF_FORMAT + +/* number of traps that happen between exec'ing the shell + * to run an inferior, and when we finally get to + * the inferior code. This is 2 on most implementations. + */ +#define START_INFERIOR_TRAPS_EXPECTED 4 + +/* Offset from address of function to start of its code. + Zero on most machines. */ + +#define FUNCTION_START_OFFSET 0 + +/* Advance PC across any function entry prologue instructions + to reach some "real" code. */ + +#define SKIP_PROLOGUE(frompc) {(frompc) = i386_skip_prologue((frompc));} + +/* Immediately after a function call, return the saved pc. + Can't always go through the frames for this because on some machines + the new frame is not set up until the new function executes + some instructions. */ + +#define SAVED_PC_AFTER_CALL(frame) \ + (read_memory_integer (read_register (SP_REGNUM), 4)) + +/* This is the amount to subtract from u.u_ar0 + to get the offset in the core file of the register values. */ + +#define KERNEL_U_ADDR 0xe0000000 + +/* Address of end of stack space. */ + +#define STACK_END_ADDR 0x80000000 + +/* Stack grows downward. */ + +#define INNER_THAN < + +/* Sequence of bytes for breakpoint instruction. */ + +#define BREAKPOINT {0xcc} + +/* Amount PC must be decremented by after a breakpoint. + This is often the number of bytes in BREAKPOINT + but not always. */ + +#define DECR_PC_AFTER_BREAK 1 + +/* Nonzero if instruction at PC is a return instruction. */ + +#define ABOUT_TO_RETURN(pc) (read_memory_integer (pc, 1) == 0xc3) + +/* Return 1 if P points to an invalid floating point value. + LEN is the length in bytes -- not relevant on the 386. */ + +#define INVALID_FLOAT(p, len) (0) + +/* code to execute to print interesting information about the + * floating point processor (if any) + * No need to define if there is nothing to do. + */ +#define FLOAT_INFO { i386_float_info (); } + + +/* Largest integer type */ +#define LONGEST long + +/* Name of the builtin type for the LONGEST type above. */ +#define BUILTIN_TYPE_LONGEST builtin_type_long + +/* Say how long (ordinary) registers are. */ + +#define REGISTER_TYPE long + +/* Number of machine registers */ + +#define NUM_REGS 16 + +/* Initializer for an array of names of registers. + There should be NUM_REGS strings in this initializer. */ + +/* the order of the first 8 registers must match the compiler's + * numbering scheme (which is the same as the 386 scheme) + * also, this table must match regmap in i386-pinsn.c. + */ +#define REGISTER_NAMES { "eax", "ecx", "edx", "ebx", \ + "esp", "ebp", "esi", "edi", \ + "eip", "ps", "cs", "ss", \ + "ds", "es", "fs", "gs", \ + } + +/* Register numbers of various important registers. + Note that some of these values are "real" register numbers, + and correspond to the general registers of the machine, + and some are "phony" register numbers which are too large + to be actual register numbers as far as the user is concerned + but do serve to get the desired values when passed to read_register. */ + +#define FP_REGNUM 5 /* Contains address of executing stack frame */ +#define SP_REGNUM 4 /* Contains address of top of stack */ + +#define PC_REGNUM 8 +#define PS_REGNUM 9 + +#define REGISTER_U_ADDR(addr, blockend, regno) \ + (addr) = i386_register_u_addr ((blockend),(regno)); + +/* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. */ +#define REGISTER_BYTES (NUM_REGS * 4) + +/* Index within `registers' of the first byte of the space for + register N. */ + +#define REGISTER_BYTE(N) ((N)*4) + +/* Number of bytes of storage in the actual machine representation + for register N. */ + +#define REGISTER_RAW_SIZE(N) (4) + +/* Number of bytes of storage in the program's representation + for register N. */ + +#define REGISTER_VIRTUAL_SIZE(N) (4) + +/* Largest value REGISTER_RAW_SIZE can have. */ + +#define MAX_REGISTER_RAW_SIZE 4 + +/* Largest value REGISTER_VIRTUAL_SIZE can have. */ + +#define MAX_REGISTER_VIRTUAL_SIZE 4 + +/* Nonzero if register N requires conversion + from raw format to virtual format. */ + +#define REGISTER_CONVERTIBLE(N) (0) + +/* Convert data from raw format for register REGNUM + to virtual format for register REGNUM. */ + +#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,FROM,TO) {bcopy ((FROM), (TO), 4);} + +/* Convert data from virtual format for register REGNUM + to raw format for register REGNUM. */ + +#define REGISTER_CONVERT_TO_RAW(REGNUM,FROM,TO) {bcopy ((FROM), (TO), 4);} + +/* Return the GDB type object for the "standard" data type + of data in register N. */ + +#define REGISTER_VIRTUAL_TYPE(N) (builtin_type_int) + +/* Store the address of the place in which to copy the structure the + subroutine will return. This is called from call_function. */ + +#define STORE_STRUCT_RETURN(ADDR, SP) \ + { (SP) -= sizeof (ADDR); \ + write_memory ((SP), &(ADDR), sizeof (ADDR)); } + +/* Extract from an array REGBUF containing the (raw) register state + a function return value of type TYPE, and copy that, in virtual format, + into VALBUF. */ + +#define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \ + bcopy (REGBUF, VALBUF, TYPE_LENGTH (TYPE)) + +/* Write into appropriate registers a function return value + of type TYPE, given in virtual format. */ + +#define STORE_RETURN_VALUE(TYPE,VALBUF) \ + write_register_bytes (0, VALBUF, TYPE_LENGTH (TYPE)) + +/* Extract from an array REGBUF containing the (raw) register state + the address in which a function should return its structure value, + as a CORE_ADDR (or an expression that can be used as one). */ + +#define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) (*(int *)(REGBUF)) + + +/* Describe the pointer in each stack frame to the previous stack frame + (its caller). */ + +/* FRAME_CHAIN takes a frame's nominal address + and produces the frame's chain-pointer. + + FRAME_CHAIN_COMBINE takes the chain pointer and the frame's nominal address + and produces the nominal address of the caller frame. + + However, if FRAME_CHAIN_VALID returns zero, + it means the given frame is the outermost one and has no caller. + In that case, FRAME_CHAIN_COMBINE is not used. */ + +#define FRAME_CHAIN(thisframe) \ + (outside_startup_file ((thisframe)->pc) ? \ + read_memory_integer ((thisframe)->frame, 4) :\ + 0) + +#define FRAME_CHAIN_VALID(chain, thisframe) \ + (chain != 0 && (outside_startup_file (FRAME_SAVED_PC (thisframe)))) + +#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) + +/* Define other aspects of the stack frame. */ + +/* A macro that tells us whether the function invocation represented + by FI does not have a frame on the stack associated with it. If it + does not, FRAMELESS is set to 1, else 0. */ +#define FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS) \ + FRAMELESS_LOOK_FOR_PROLOGUE(FI, FRAMELESS) + +#define FRAME_SAVED_PC(FRAME) (read_memory_integer ((FRAME)->frame + 4, 4)) + +#define FRAME_ARGS_ADDRESS(fi) ((fi)->frame) + +#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame) + +/* Return number of args passed to a frame. + Can return -1, meaning no way to tell. */ + +#define FRAME_NUM_ARGS(numargs, fi) (numargs) = i386_frame_num_args(fi) + +/* Return number of bytes at start of arglist that are not really args. */ + +#define FRAME_ARGS_SKIP 8 + +/* Put here the code to store, into a struct frame_saved_regs, + the addresses of the saved registers of frame described by FRAME_INFO. + This includes special registers such as pc and fp saved in special + ways in the stack frame. sp is even more special: + the address we return for it IS the sp for the next frame. */ + +#define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) \ +{ i386_frame_find_saved_regs ((frame_info), &(frame_saved_regs)); } + + +/* Things needed for making the inferior call functions. */ + +/* Push an empty stack frame, to record the current PC, etc. */ + +#define PUSH_DUMMY_FRAME { i386_push_dummy_frame (); } + +/* Discard from the stack the innermost frame, restoring all registers. */ + +#define POP_FRAME { i386_pop_frame (); } + +/* this is + * call 11223344 (32 bit relative) + * int3 + */ + +#define CALL_DUMMY { 0x223344e8, 0xcc11 } + +#define CALL_DUMMY_LENGTH 8 + +#define CALL_DUMMY_START_OFFSET 0 /* Start execution at beginning of dummy */ + +/* Insert the specified number of args and function address + into a call sequence of the above form stored at DUMMYNAME. */ + +#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, type) \ +{ \ + int from, to, delta, loc; \ + loc = (int)(read_register (SP_REGNUM) - CALL_DUMMY_LENGTH); \ + from = loc + 5; \ + to = (int)(fun); \ + delta = to - from; \ + *(int *)((char *)(dummyname) + 1) = delta; \ +} + + +#if 0 +/* Interface definitions for kernel debugger KDB. */ + +/* Map machine fault codes into signal numbers. + First subtract 0, divide by 4, then index in a table. + Faults for which the entry in this table is 0 + are not handled by KDB; the program's own trap handler + gets to handle then. */ + +#define FAULT_CODE_ORIGIN 0 +#define FAULT_CODE_UNITS 4 +#define FAULT_TABLE \ +{ 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0} + +/* Start running with a stack stretching from BEG to END. + BEG and END should be symbols meaningful to the assembler. + This is used only for kdb. */ + +#define INIT_STACK(beg, end) {} + +/* Push the frame pointer register on the stack. */ +#define PUSH_FRAME_PTR {} + +/* Copy the top-of-stack to the frame pointer register. */ +#define POP_FRAME_PTR {} + +/* After KDB is entered by a fault, push all registers + that GDB thinks about (all NUM_REGS of them), + so that they appear in order of ascending GDB register number. + The fault code will be on the stack beyond the last register. */ + +#define PUSH_REGISTERS {} + +/* Assuming the registers (including processor status) have been + pushed on the stack in order of ascending GDB register number, + restore them and return to the address in the saved PC register. */ + +#define POP_REGISTERS {} +#endif diff --git a/gnu/usr.bin/gdb/config/m-i386bsd.h b/gnu/usr.bin/gdb/config/m-i386bsd.h new file mode 100644 index 0000000..15c3608 --- /dev/null +++ b/gnu/usr.bin/gdb/config/m-i386bsd.h @@ -0,0 +1,374 @@ +/*- + * This code is derived from software copyrighted by the Free Software + * Foundation. + * + * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. + * Modified 1991 by William Jolitz at UUNET Technologies, Inc. + * + * @(#)m-i386bsd.h 6.7 (Berkeley) 5/8/91 + */ + +/* Macro definitions for i386. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Define the bit, byte, and word ordering of the machine. */ +/* #define BITS_BIG_ENDIAN */ +/* #define BYTES_BIG_ENDIAN */ +/* #define WORDS_BIG_ENDIAN */ + +/* + * Changes for 80386 by Pace Willisson (pace@prep.ai.mit.edu) + * July 1988 + * [ MODIFIED FOR 386BSD W. Jolitz ] + */ + +#ifndef i386 +#define i386 1 +#define i386b 1 +#endif + +#define IEEE_FLOAT + +/* Library stuff: POSIX tty (not supported yet), V7 tty (sigh), vprintf. */ + +#define HAVE_TERMIOS 1 +#define USE_OLD_TTY 1 +#define HAVE_VPRINTF 1 + +/* We support local and remote kernel debugging. */ + +#define KERNELDEBUG 1 + +/* Get rid of any system-imposed stack limit if possible. */ + +#define SET_STACK_LIMIT_HUGE + +/* Define this if the C compiler puts an underscore at the front + of external names before giving them to the linker. */ + +#define NAMES_HAVE_UNDERSCORE + +/* Specify debugger information format. */ + +#define READ_DBX_FORMAT + +/* number of traps that happen between exec'ing the shell + * to run an inferior, and when we finally get to + * the inferior code. This is 2 on most implementations. + */ +#define START_INFERIOR_TRAPS_EXPECTED 2 + +/* Offset from address of function to start of its code. + Zero on most machines. */ + +#define FUNCTION_START_OFFSET 0 + +/* Advance PC across any function entry prologue instructions + to reach some "real" code. */ + +#define SKIP_PROLOGUE(frompc) {(frompc) = i386_skip_prologue((frompc));} + +/* Immediately after a function call, return the saved pc. + Can't always go through the frames for this because on some machines + the new frame is not set up until the new function executes + some instructions. */ + +#define SAVED_PC_AFTER_CALL(frame) \ + (read_memory_integer (read_register (SP_REGNUM), 4)) + +/* This is the amount to subtract from u.u_ar0 + to get the offset in the core file of the register values. */ + +#ifdef NEWVM +#include <machine/vmparam.h> +#define KERNEL_U_ADDR USRSTACK +#else +#define KERNEL_U_ADDR 0xfdffd000 +#endif + +/* Address of end of stack space. */ + +#define STACK_END_ADDR KERNEL_U_ADDR + +/* Stack grows downward. */ + +#define INNER_THAN < + +/* Sequence of bytes for breakpoint instruction. */ + +#define BREAKPOINT {0xcc} + +/* Amount PC must be decremented by after a breakpoint. + This is often the number of bytes in BREAKPOINT + but not always. */ + +#define DECR_PC_AFTER_BREAK 1 + +/* Nonzero if instruction at PC is a return instruction. */ + +#define ABOUT_TO_RETURN(pc) \ + strchr("\302\303\312\313\317", read_memory_integer(pc, 1)) + +/* Return 1 if P points to an invalid floating point value. + LEN is the length in bytes -- not relevant on the 386. */ + +#define INVALID_FLOAT(p, len) (0) + +/* code to execute to print interesting information about the + * floating point processor (if any) + * No need to define if there is nothing to do. + */ +#define FLOAT_INFO { i386_float_info (); } + + +/* Largest integer type */ +#define LONGEST long + +/* Name of the builtin type for the LONGEST type above. */ +#define BUILTIN_TYPE_LONGEST builtin_type_long + +/* Say how long (ordinary) registers are. */ + +#define REGISTER_TYPE long + +/* Number of machine registers */ + +#define NUM_REGS 16 + +/* Initializer for an array of names of registers. + There should be NUM_REGS strings in this initializer. */ + +/* the order of the first 8 registers must match the compiler's + * numbering scheme (which is the same as the 386 scheme) + * also, this table must match regmap in i386-pinsn.c. + */ +#define REGISTER_NAMES { "eax", "ecx", "edx", "ebx", \ + "esp", "ebp", "esi", "edi", \ + "eip", "ps", "cs", "ss", \ + "ds", "es", "fs", "gs", \ + } + +/* Register numbers of various important registers. + Note that some of these values are "real" register numbers, + and correspond to the general registers of the machine, + and some are "phony" register numbers which are too large + to be actual register numbers as far as the user is concerned + but do serve to get the desired values when passed to read_register. */ + +#define FP_REGNUM 5 /* Contains address of executing stack frame */ +#define SP_REGNUM 4 /* Contains address of top of stack */ + +#define PC_REGNUM 8 +#define PS_REGNUM 9 + +#define REGISTER_U_ADDR(addr, blockend, regno) \ + (addr) = i386_register_u_addr ((blockend),(regno)); + +/* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. */ +#define REGISTER_BYTES (NUM_REGS * 4) + +/* Index within `registers' of the first byte of the space for + register N. */ + +#define REGISTER_BYTE(N) ((N)*4) + +/* Number of bytes of storage in the actual machine representation + for register N. */ + +#define REGISTER_RAW_SIZE(N) (4) + +/* Number of bytes of storage in the program's representation + for register N. */ + +#define REGISTER_VIRTUAL_SIZE(N) (4) + +/* Largest value REGISTER_RAW_SIZE can have. */ + +#define MAX_REGISTER_RAW_SIZE 4 + +/* Largest value REGISTER_VIRTUAL_SIZE can have. */ + +#define MAX_REGISTER_VIRTUAL_SIZE 4 + +/* Nonzero if register N requires conversion + from raw format to virtual format. */ + +#define REGISTER_CONVERTIBLE(N) (0) + +/* Convert data from raw format for register REGNUM + to virtual format for register REGNUM. */ + +#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,FROM,TO) {bcopy ((FROM), (TO), 4);} + +/* Convert data from virtual format for register REGNUM + to raw format for register REGNUM. */ + +#define REGISTER_CONVERT_TO_RAW(REGNUM,FROM,TO) {bcopy ((FROM), (TO), 4);} + +/* Return the GDB type object for the "standard" data type + of data in register N. */ + +#define REGISTER_VIRTUAL_TYPE(N) (builtin_type_int) + +/* Store the address of the place in which to copy the structure the + subroutine will return. This is called from call_function. */ + +#define STORE_STRUCT_RETURN(ADDR, SP) \ + { (SP) -= sizeof (ADDR); \ + write_memory ((SP), &(ADDR), sizeof (ADDR)); } + +/* Extract from an array REGBUF containing the (raw) register state + a function return value of type TYPE, and copy that, in virtual format, + into VALBUF. */ + +#define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \ + bcopy (REGBUF, VALBUF, TYPE_LENGTH (TYPE)) + +/* Write into appropriate registers a function return value + of type TYPE, given in virtual format. */ + +#define STORE_RETURN_VALUE(TYPE,VALBUF) \ + write_register_bytes (0, VALBUF, TYPE_LENGTH (TYPE)) + +/* Extract from an array REGBUF containing the (raw) register state + the address in which a function should return its structure value, + as a CORE_ADDR (or an expression that can be used as one). */ + +#define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) (*(int *)(REGBUF)) + + +/* Describe the pointer in each stack frame to the previous stack frame + (its caller). */ + +/* FRAME_CHAIN takes a frame's nominal address + and produces the frame's chain-pointer. + + FRAME_CHAIN_COMBINE takes the chain pointer and the frame's nominal address + and produces the nominal address of the caller frame. + + However, if FRAME_CHAIN_VALID returns zero, + it means the given frame is the outermost one and has no caller. + In that case, FRAME_CHAIN_COMBINE is not used. */ + +#define FRAME_CHAIN(thisframe) \ + (outside_startup_file ((thisframe)->pc) ? \ + read_memory_integer ((thisframe)->frame, 4) :\ + 0) + +#ifdef KERNELDEBUG +#define KERNTEXT_BASE 0xfe000000 +#ifdef NEWVM +#define KERNSTACK_TOP (read_register(SP_REGNUM) + 0x2000) /* approximate */ +#else +/* #define KERNSTACK_TOP (P1PAGES << PGSHIFT) */ +#define KERNSTACK_TOP 0xfe000000 +#endif +extern int kernel_debugging; +#define FRAME_CHAIN_VALID(chain, thisframe) \ + (chain != 0 && \ + !kernel_debugging ? outside_startup_file(FRAME_SAVED_PC(thisframe)) :\ + (chain >= read_register(SP_REGNUM) && chain < KERNSTACK_TOP)) +#else +#define FRAME_CHAIN_VALID(chain, thisframe) \ + (chain != 0 && (outside_startup_file (FRAME_SAVED_PC (thisframe)))) +#endif + +#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) + +/* Define other aspects of the stack frame. */ + +/* A macro that tells us whether the function invocation represented + by FI does not have a frame on the stack associated with it. If it + does not, FRAMELESS is set to 1, else 0. */ +#define FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS) \ + FRAMELESS_LOOK_FOR_PROLOGUE(FI, FRAMELESS) + +#define FRAME_SAVED_PC(FRAME) (read_memory_integer ((FRAME)->frame + 4, 4)) + +#define FRAME_ARGS_ADDRESS(fi) ((fi)->frame) + +#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame) + +/* Return number of args passed to a frame. + Can return -1, meaning no way to tell. */ + +#define FRAME_NUM_ARGS(numargs, fi) (numargs) = i386_frame_num_args(fi) + +/* Return number of bytes at start of arglist that are not really args. */ + +#define FRAME_ARGS_SKIP 8 + +/* Put here the code to store, into a struct frame_saved_regs, + the addresses of the saved registers of frame described by FRAME_INFO. + This includes special registers such as pc and fp saved in special + ways in the stack frame. sp is even more special: + the address we return for it IS the sp for the next frame. */ + +#define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) \ +{ i386_frame_find_saved_regs ((frame_info), &(frame_saved_regs)); } + + +/* Discard from the stack the innermost frame, restoring all registers. */ + +#define POP_FRAME { i386_pop_frame (); } + +#define NEW_CALL_FUNCTION + +#if 0 +/* Interface definitions for kernel debugger KDB. */ + +/* Map machine fault codes into signal numbers. + First subtract 0, divide by 4, then index in a table. + Faults for which the entry in this table is 0 + are not handled by KDB; the program's own trap handler + gets to handle then. */ + +#define FAULT_CODE_ORIGIN 0 +#define FAULT_CODE_UNITS 4 +#define FAULT_TABLE \ +{ 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0} + +/* Start running with a stack stretching from BEG to END. + BEG and END should be symbols meaningful to the assembler. + This is used only for kdb. */ + +#define INIT_STACK(beg, end) {} + +/* Push the frame pointer register on the stack. */ +#define PUSH_FRAME_PTR {} + +/* Copy the top-of-stack to the frame pointer register. */ +#define POP_FRAME_PTR {} + +/* After KDB is entered by a fault, push all registers + that GDB thinks about (all NUM_REGS of them), + so that they appear in order of ascending GDB register number. + The fault code will be on the stack beyond the last register. */ + +#define PUSH_REGISTERS {} + +/* Assuming the registers (including processor status) have been + pushed on the stack in order of ascending GDB register number, + restore them and return to the address in the saved PC register. */ + +#define POP_REGISTERS {} +#endif diff --git a/gnu/usr.bin/gdb/config/m-i386g-sv32.h b/gnu/usr.bin/gdb/config/m-i386g-sv32.h new file mode 100644 index 0000000..3d69eea --- /dev/null +++ b/gnu/usr.bin/gdb/config/m-i386g-sv32.h @@ -0,0 +1,28 @@ +/* Macro defintions for i386, running System V 3.2. + Copyright (C) 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 "m-i386gas.h" + +/* Apparently there is inconsistency among various System V's about what + the name of this field is. */ +#define U_FPSTATE(u) u.u_fps.u_fpstate + +/* TIOCGETC is defined in System V 3.2 termio.h, but struct tchars + is not. This makes problems for inflow.c. */ +#define TIOCGETC_BROKEN diff --git a/gnu/usr.bin/gdb/config/m-i386gas.h b/gnu/usr.bin/gdb/config/m-i386gas.h new file mode 100644 index 0000000..fbd2138 --- /dev/null +++ b/gnu/usr.bin/gdb/config/m-i386gas.h @@ -0,0 +1,37 @@ +/* Macro definitions for i386 using the GNU object file format. + 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. */ + +/* + * Changes for 80386 by Pace Willisson (pace@prep.ai.mit.edu) + * July 1988 + * + * i386gnu: COFF_ENCAPSULATE + */ + + +#define COFF_ENCAPSULATE + +#include "m-i386.h" + + +#define NAMES_HAVE_UNDERSCORE + +#undef COFF_FORMAT +#define READ_DBX_FORMAT + diff --git a/gnu/usr.bin/gdb/copying.c b/gnu/usr.bin/gdb/copying.c new file mode 100644 index 0000000..b3d7519 --- /dev/null +++ b/gnu/usr.bin/gdb/copying.c @@ -0,0 +1,215 @@ +/* Do not modify this file; it is created automatically + by copying.awk. */ +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/gnu/usr.bin/gdb/core.c b/gnu/usr.bin/gdb/core.c new file mode 100644 index 0000000..307addb --- /dev/null +++ b/gnu/usr.bin/gdb/core.c @@ -0,0 +1,581 @@ +/*- + * This code is derived from software copyrighted by the Free Software + * Foundation. + * + * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. + * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory. + */ + +#ifndef lint +static char sccsid[] = "@(#)core.c 6.3 (Berkeley) 5/8/91"; +#endif /* not lint */ + +/* Work with core dump and executable files, for GDB. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <stdio.h> +#include "defs.h" +#include "param.h" +#include "frame.h" /* required by inferior.h */ +#include "inferior.h" + +#ifdef USG +#include <sys/types.h> +#include <fcntl.h> +#endif + +#ifdef COFF_ENCAPSULATE +#include "a.out.encap.h" +#else +#include <a.out.h> +#endif +#ifndef N_MAGIC +#ifdef COFF_FORMAT +#define N_MAGIC(exec) ((exec).magic) +#else +#define N_MAGIC(exec) ((exec).a_magic) +#endif +#endif +#include <signal.h> +#include <sys/param.h> +#include <sys/dir.h> +#include <sys/file.h> +#include <sys/stat.h> + +#ifdef UMAX_CORE +#include <sys/ptrace.h> +#else +#include <sys/user.h> +#endif + +#ifndef N_TXTADDR +#define N_TXTADDR(hdr) 0 +#endif /* no N_TXTADDR */ + +#ifndef N_DATADDR +#define N_DATADDR(hdr) hdr.a_text +#endif /* no N_DATADDR */ + +#ifndef COFF_FORMAT +#ifndef AOUTHDR +#define AOUTHDR struct exec +#endif +#endif + +extern char *sys_siglist[]; + +extern core_file_command (), exec_file_command (); + +/* Hook for `exec_file_command' command to call. */ + +void (*exec_file_display_hook) (); + +/* File names of core file and executable file. */ + +char *corefile; +char *execfile; + +/* Descriptors on which core file and executable file are open. + Note that the execchan is closed when an inferior is created + and reopened if the inferior dies or is killed. */ + +int corechan; +int execchan; + +/* Last modification time of executable file. + Also used in source.c to compare against mtime of a source file. */ + +int exec_mtime; + +/* Virtual addresses of bounds of the two areas of memory in the core file. */ + +CORE_ADDR data_start; +CORE_ADDR data_end; +CORE_ADDR stack_start; +CORE_ADDR stack_end; + +#if defined (REG_STACK_SEGMENT) +/* Start and end of the register stack segment. */ +CORE_ADDR reg_stack_start; +CORE_ADDR reg_stack_end; +#endif /* REG_STACK_SEGMENT */ + +/* Virtual addresses of bounds of two areas of memory in the exec file. + Note that the data area in the exec file is used only when there is no core file. */ + +CORE_ADDR text_start; +CORE_ADDR text_end; + +CORE_ADDR exec_data_start; +CORE_ADDR exec_data_end; + +/* Offset within executable file of start of text area data. */ + +int text_offset; + +/* Offset within executable file of start of data area data. */ + +int exec_data_offset; + +/* Offset within core file of start of data area data. */ + +int data_offset; + +/* Offset within core file of start of stack area data. */ + +int stack_offset; + +#ifdef COFF_FORMAT +/* various coff data structures */ + +FILHDR file_hdr; +SCNHDR text_hdr; +SCNHDR data_hdr; + +#endif /* not COFF_FORMAT */ + +/* a.out header saved in core file. */ + +AOUTHDR core_aouthdr; + +/* a.out header of exec file. */ + +AOUTHDR exec_aouthdr; + +void validate_files (); +unsigned int register_addr (); + +/* Call this to specify the hook for exec_file_command to call back. + This is called from the x-window display code. */ + +void +specify_exec_file_hook (hook) + void (*hook) (); +{ + exec_file_display_hook = hook; +} + +/* The exec file must be closed before running an inferior. + If it is needed again after the inferior dies, it must + be reopened. */ + +void +close_exec_file () +{ + if (execchan >= 0) + close (execchan); + execchan = -1; +} + +void +reopen_exec_file () +{ + if (execchan < 0 && execfile != 0) + { + char *filename = concat (execfile, "", ""); + exec_file_command (filename, 0); + free (filename); + } +} + +/* If we have both a core file and an exec file, + print a warning if they don't go together. + This should really check that the core file came + from that exec file, but I don't know how to do it. */ + +void +validate_files () +{ + if (execfile != 0 && corefile != 0) + { + struct stat st_core; + + if (fstat (corechan, &st_core) < 0) + /* It might be a good idea to print an error message. + On the other hand, if the user tries to *do* anything with + the core file, (s)he'll find out soon enough. */ + return; + + if (N_MAGIC (core_aouthdr) != 0 + && bcmp (&core_aouthdr, &exec_aouthdr, sizeof core_aouthdr)) + printf ("Warning: core file does not match specified executable file.\n"); + else if (exec_mtime > st_core.st_mtime) { +#ifdef KERNELDEBUG + extern int kernel_debugging; + if (!kernel_debugging) +#endif + printf ("Warning: exec file is newer than core file.\n"); + } + } +} + +/* 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 (err) + int err; +{ + if (err && execfile == 0) + error ("No executable file specified.\n\ +Use the \"exec-file\" and \"symbol-file\" commands."); + return execfile; +} + +int +have_core_file_p () +{ + return corefile != 0; +} + +static void +files_info () +{ + char *symfile; + extern char *get_sym_file (); + + if (execfile) + printf ("Executable file \"%s\".\n", execfile); + else + printf ("No executable file\n"); + if (corefile == 0) + printf ("No core dump file\n"); + else + printf ("Core dump file \"%s\".\n", corefile); + + if (have_inferior_p ()) + printf ("Using the running image of the program, rather than these files.\n"); + + symfile = get_sym_file (); + if (symfile != 0) + printf ("Symbols from \"%s\".\n", symfile); + +#ifdef FILES_INFO_HOOK + if (FILES_INFO_HOOK ()) + return; +#endif + + if (! have_inferior_p ()) + { + if (execfile) + { + printf ("Text segment in executable from 0x%x to 0x%x.\n", + text_start, text_end); + printf ("Data segment in executable from 0x%x to 0x%x.\n", + exec_data_start, exec_data_end); + if (corefile) + printf ("(But since we have a core file, we're using...)\n"); + } + if (corefile) + { + printf ("Data segment in core file from 0x%x to 0x%x.\n", + data_start, data_end); + printf ("Stack segment in core file from 0x%x to 0x%x.\n", + stack_start, stack_end); + } + } +} + +/* Read "memory data" from core file and/or executable file. + Returns zero if successful, 1 if xfer_core_file failed, errno value if + ptrace failed. */ + +int +read_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + if (len == 0) + return 0; + + if (have_inferior_p ()) + { + if (remote_debugging) + return remote_read_inferior_memory (memaddr, myaddr, len); + else + return read_inferior_memory (memaddr, myaddr, len); + } + else + return xfer_core_file (memaddr, myaddr, len); +} + +/* Write LEN bytes of data starting at address MYADDR + into debugged program memory at address MEMADDR. + Returns zero if successful, or an errno value if ptrace failed. */ + +int +write_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + if (have_inferior_p ()) + { + if (remote_debugging) + return remote_write_inferior_memory (memaddr, myaddr, len); + else + return write_inferior_memory (memaddr, myaddr, len); + } + else + error ("Can write memory only when program being debugged is running."); +} + +#ifndef XFER_CORE_FILE +int (*core_file_hook)(); /* hook to handle special core files like + like /dev/mem and crash dumps */ + +/* 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, 1 if not. */ + +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; + + if (core_file_hook) + return ((*core_file_hook)(memaddr, myaddr, len)); + + 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 are equal. */ + else if (memaddr >= stack_start && memaddr < stack_end) + { + i = min (len, stack_end - memaddr); + fileptr = memaddr - stack_start + stack_offset; + xferfile = &corefile; + xferchan = corechan; + } +#ifdef REG_STACK_SEGMENT + /* Pyramids have an extra segment in the virtual address space + for the (control) stack of register-window frames */ + 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; + xferfile = &corefile; + xferchan = corechan; + } +#endif /* REG_STACK_SEGMENT */ + + 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) + { + i = min (len, text_end - memaddr); + fileptr = memaddr - 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) + { + /* Since there is nothing at higher addresses than data + (without a core file or an inferior, there is no + stack, set i to do the rest of the operation now. */ + i = len; + } +#ifdef REG_STACK_SEGMENT + else if (memaddr >= reg_stack_end && reg_stack_end != 0) + { + i = min (len, reg_stack_start - memaddr); + } + else if (memaddr >= stack_end && memaddr < reg_stack_start) +#else /* no REG_STACK_SEGMENT. */ + else if (memaddr >= stack_end && stack_end != 0) +#endif /* no REG_STACK_SEGMENT. */ + { + /* Since there is nothing at higher addresses than + the stack, set i to do the rest of the operation now. */ + i = len; + } + 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 == -1) + 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 = 1; + } + + memaddr += i; + myaddr += i; + len -= i; + } + return returnval; +} +#endif /* XFER_CORE_FILE */ + +/* 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; +} + +#ifdef REGISTER_U_ADDR + +/* Return the address in the core dump or inferior of register REGNO. + BLOCKEND is the address of the end of the user structure. */ + +unsigned int +register_addr (regno, blockend) + int regno; + int blockend; +{ + int addr; + + if (regno < 0 || regno >= NUM_REGS) + error ("Invalid register number %d.", regno); + + REGISTER_U_ADDR (addr, blockend, regno); + + return addr; +} + +#endif /* REGISTER_U_ADDR */ + +void +_initialize_core() +{ + corechan = -1; + execchan = -1; + corefile = 0; + execfile = 0; + exec_file_display_hook = 0; + + text_start = 0; + text_end = 0; + data_start = 0; + data_end = 0; + exec_data_start = 0; + exec_data_end = 0; + stack_start = STACK_END_ADDR; + stack_end = STACK_END_ADDR; + + add_com ("core-file", class_files, core_file_command, + "Use FILE as core dump for examining memory and registers.\n\ +No arg means have no core file."); + 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_info ("files", files_info, "Names of files being debugged."); +} + diff --git a/gnu/usr.bin/gdb/cplus-dem.c b/gnu/usr.bin/gdb/cplus-dem.c new file mode 100644 index 0000000..8ea9c8b --- /dev/null +++ b/gnu/usr.bin/gdb/cplus-dem.c @@ -0,0 +1,996 @@ +/* Demangler for GNU C++ + Copyright (C) 1989 Free Software Foundation, Inc. + written by James Clark (jjc@jclark.uucp) + + 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. */ + +/* This is for g++ 1.36.1 (November 6 version). It will probably + require changes for any other version. + + Modified for g++ 1.36.2 (November 18 version). */ + +/* This file exports one function + + char *cplus_demangle (const char *name, int mode) + + If NAME is a mangled function name produced by GNU C++, then + a pointer to a malloced string giving a C++ representation + of the name will be returned; otherwise NULL will be returned. + It is the caller's responsibility to free the string which + is returned. + + If MODE > 0, then ANSI qualifiers such as `const' and `void' are output. + Otherwise they are not. + If MODE >= 0, parameters are emitted; otherwise not. + + For example, + + cplus_demangle ("foo__1Ai", 0) => "A::foo(int)" + cplus_demangle ("foo__1Ai", 1) => "A::foo(int)" + cplus_demangle ("foo__1Ai", -1) => "A::foo" + + cplus_demangle ("foo__1Afe", 0) => "A::foo(float,...)" + cplus_demangle ("foo__1Afe", 1) => "A::foo(float,...)" + cplus_demangle ("foo__1Afe", -1) => "A::foo" + + This file imports xmalloc and xrealloc, which are like malloc and + realloc except that they generate a fatal error if there is no + available memory. */ + +/* #define nounderscore 1 /* define this is names don't start with _ */ + +#include <stdio.h> +#include <ctype.h> + +#ifdef USG +#include <memory.h> +#include <string.h> +#else +#include <strings.h> +#define memcpy(s1, s2, n) bcopy ((s2), (s1), (n)) +#define memcmp(s1, s2, n) bcmp ((s2), (s1), (n)) +#define strchr index +#define strrchr rindex +#endif + +#ifndef __STDC__ +#define const +#endif + +#ifdef __STDC__ +extern char *cplus_demangle (const char *type, int mode); +#else +extern char *cplus_demangle (); +#endif + +#ifdef __STDC__ +extern char *xmalloc (int); +extern char *xrealloc (char *, int); +#else +extern char *xmalloc (); +extern char *xrealloc (); +#endif + +static char **typevec = 0; +static int ntypes = 0; +static int typevec_size = 0; + +static struct { + const char *in; + const char *out; +} optable[] = { + "new", " new", + "delete", " delete", + "ne", "!=", + "eq", "==", + "ge", ">=", + "gt", ">", + "le", "<=", + "lt", "<", + "plus", "+", + "minus", "-", + "mult", "*", + "convert", "+", /* unary + */ + "negate", "-", /* unary - */ + "trunc_mod", "%", + "trunc_div", "/", + "truth_andif", "&&", + "truth_orif", "||", + "truth_not", "!", + "postincrement", "++", + "postdecrement", "--", + "bit_ior", "|", + "bit_xor", "^", + "bit_and", "&", + "bit_not", "~", + "call", "()", + "cond", "?:", + "alshift", "<<", + "arshift", ">>", + "component", "->", + "indirect", "*", + "method_call", "->()", + "addr", "&", /* unary & */ + "array", "[]", + "nop", "", /* for operator= */ +}; + +/* Beware: these aren't '\0' terminated. */ + +typedef struct { + char *b; /* pointer to start of string */ + char *p; /* pointer after last character */ + char *e; /* pointer after end of allocated space */ +} string; + +#ifdef __STDC__ +static void string_need (string *s, int n); +static void string_delete (string *s); +static void string_init (string *s); +static void string_clear (string *s); +static int string_empty (string *s); +static void string_append (string *p, const char *s); +static void string_appends (string *p, string *s); +static void string_appendn (string *p, const char *s, int n); +static void string_prepend (string *p, const char *s); +#if 0 +static void string_prepends (string *p, string *s); +#endif +static void string_prependn (string *p, const char *s, int n); +static int get_count (const char **type, int *count); +static int do_args (const char **type, string *decl, int arg_mode); +static int do_type (const char **type, string *result, int arg_mode); +static int do_arg (const char **type, string *result, int arg_mode); +static void munge_function_name (string *name, int arg_mode); +static void remember_type (const char *type, int len); +#else +static void string_need (); +static void string_delete (); +static void string_init (); +static void string_clear (); +static int string_empty (); +static void string_append (); +static void string_appends (); +static void string_appendn (); +static void string_prepend (); +static void string_prepends (); +static void string_prependn (); +static int get_count (); +static int do_args (); +static int do_type (); +static int do_arg (); +static int do_args (); +static void munge_function_name (); +static void remember_type (); +#endif + +char * +cplus_demangle (type, arg_mode) + const char *type; + int arg_mode; +{ + string decl; + int n; + int success = 0; + int constructor = 0; + int const_flag = 0; + int i; + const char *p; +#ifndef LONGERNAMES + const char *premangle; +#endif + +# define print_ansi_qualifiers (arg_mode > 0) +# define print_arg_types (arg_mode >= 0) + + if (type == NULL || *type == '\0') + return NULL; +#ifndef nounderscore + if (*type++ != '_') + return NULL; +#endif + p = type; + while (*p != '\0' && !(*p == '_' && p[1] == '_')) + p++; + if (*p == '\0') + { + /* destructor */ + if (type[0] == '_' && type[1] == '$' && type[2] == '_') + { + int n = (strlen (type) - 3)*2 + 3 + 2 + 1; + char *tem = (char *) xmalloc (n); + strcpy (tem, type + 3); + strcat (tem, "::~"); + strcat (tem, type + 3); + strcat (tem, "()"); + return tem; + } + /* static data member */ + if (*type != '_' && (p = strchr (type, '$')) != NULL) + { + int n = strlen (type) + 2; + char *tem = (char *) xmalloc (n); + memcpy (tem, type, p - type); + strcpy (tem + (p - type), "::"); + strcpy (tem + (p - type) + 2, p + 1); + return tem; + } + /* virtual table "_vt$" */ + if (type[0] == '_' && type[1] == 'v' && type[2] == 't' && type[3] == '$') + { + int n = strlen (type + 4) + 14 + 1; + char *tem = (char *) xmalloc (n); + strcpy (tem, type + 4); + strcat (tem, " virtual table"); + return tem; + } + return NULL; + } + + string_init (&decl); + + if (p == type) + { + if (!isdigit (p[2])) + { + string_delete (&decl); + return NULL; + } + constructor = 1; + } + else + { + string_appendn (&decl, type, p - type); + munge_function_name (&decl, arg_mode); + } + p += 2; + +#ifndef LONGERNAMES + premangle = p; +#endif + switch (*p) + { + case 'C': + /* a const member function */ + if (!isdigit (p[1])) + { + string_delete (&decl); + return NULL; + } + p += 1; + const_flag = 1; + /* fall through */ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + n = 0; + do + { + n *= 10; + n += *p - '0'; + p += 1; + } + while (isdigit (*p)); + if (strlen (p) < n) + { + string_delete (&decl); + return NULL; + } + if (constructor) + { + string_appendn (&decl, p, n); + string_append (&decl, "::"); + string_appendn (&decl, p, n); + } + else + { + string_prepend (&decl, "::"); + string_prependn (&decl, p, n); + } + p += n; +#ifndef LONGERNAMES + remember_type (premangle, p - premangle); +#endif + success = do_args (&p, &decl, arg_mode); + if (const_flag && print_arg_types) + string_append (&decl, " const"); + break; + case 'F': + p += 1; + success = do_args (&p, &decl, arg_mode); + break; + } + + for (i = 0; i < ntypes; i++) + if (typevec[i] != NULL) + free (typevec[i]); + ntypes = 0; + if (typevec != NULL) + { + free ((char *)typevec); + typevec = NULL; + typevec_size = 0; + } + + if (success) + { + string_appendn (&decl, "", 1); + return decl.b; + } + else + { + string_delete (&decl); + return NULL; + } +} + +static int +get_count (type, count) + const char **type; + int *count; +{ + if (!isdigit (**type)) + return 0; + *count = **type - '0'; + *type += 1; + /* see flush_repeats in cplus-method.c */ + if (isdigit (**type)) + { + const char *p = *type; + int n = *count; + do + { + n *= 10; + n += *p - '0'; + p += 1; + } + while (isdigit (*p)); + if (*p == '_') + { + *type = p + 1; + *count = n; + } + } + return 1; +} + +/* result will be initialised here; it will be freed on failure */ + +static int +do_type (type, result, arg_mode) + const char **type; + string *result; + int arg_mode; +{ + int n; + int done; + int non_empty = 0; + int success; + string decl; + const char *remembered_type; + + string_init (&decl); + string_init (result); + + done = 0; + success = 1; + while (success && !done) + { + int member; + switch (**type) + { + case 'P': + *type += 1; + string_prepend (&decl, "*"); + break; + + case 'R': + *type += 1; + string_prepend (&decl, "&"); + break; + + case 'T': + *type += 1; + if (!get_count (type, &n) || n >= ntypes) + success = 0; + else + { + remembered_type = typevec[n]; + type = &remembered_type; + } + break; + + case 'F': + *type += 1; + if (!string_empty (&decl) && decl.b[0] == '*') + { + string_prepend (&decl, "("); + string_append (&decl, ")"); + } + if (!do_args (type, &decl, arg_mode) || **type != '_') + success = 0; + else + *type += 1; + break; + + case 'M': + case 'O': + { + int constp = 0; + int volatilep = 0; + + member = **type == 'M'; + *type += 1; + if (!isdigit (**type)) + { + success = 0; + break; + } + n = 0; + do + { + n *= 10; + n += **type - '0'; + *type += 1; + } + while (isdigit (**type)); + if (strlen (*type) < n) + { + success = 0; + break; + } + string_append (&decl, ")"); + string_prepend (&decl, "::"); + string_prependn (&decl, *type, n); + string_prepend (&decl, "("); + *type += n; + if (member) + { + if (**type == 'C') + { + *type += 1; + constp = 1; + } + if (**type == 'V') + { + *type += 1; + volatilep = 1; + } + if (*(*type)++ != 'F') + { + success = 0; + break; + } + } + if ((member && !do_args (type, &decl, arg_mode)) || **type != '_') + { + success = 0; + break; + } + *type += 1; + if (! print_ansi_qualifiers) + break; + if (constp) + { + if (non_empty) + string_append (&decl, " "); + else + non_empty = 1; + string_append (&decl, "const"); + } + if (volatilep) + { + if (non_empty) + string_append (&decl, " "); + else + non_empty = 1; + string_append (&decl, "volatile"); + } + break; + } + + case 'C': + if ((*type)[1] == 'P') + { + *type += 1; + if (print_ansi_qualifiers) + { + if (!string_empty (&decl)) + string_prepend (&decl, " "); + string_prepend (&decl, "const"); + } + break; + } + + /* fall through */ + default: + done = 1; + break; + } + } + + done = 0; + non_empty = 0; + while (success && !done) + { + switch (**type) + { + case 'C': + *type += 1; + if (print_ansi_qualifiers) + { + if (non_empty) + string_append (result, " "); + else + non_empty = 1; + string_append (result, "const"); + } + break; + case 'U': + *type += 1; + if (non_empty) + string_append (result, " "); + else + non_empty = 1; + string_append (result, "unsigned"); + break; + case 'V': + *type += 1; + if (print_ansi_qualifiers) + { + if (non_empty) + string_append (result, " "); + else + non_empty = 1; + string_append (result, "volatile"); + } + break; + default: + done = 1; + break; + } + } + + if (success) + switch (**type) + { + case '\0': + case '_': + break; + case 'v': + *type += 1; + if (non_empty) + string_append (result, " "); + string_append (result, "void"); + break; + case 'x': + *type += 1; + if (non_empty) + string_append (result, " "); + string_append (result, "long long"); + break; + case 'l': + *type += 1; + if (non_empty) + string_append (result, " "); + string_append (result, "long"); + break; + case 'i': + *type += 1; + if (non_empty) + string_append (result, " "); + string_append (result, "int"); + break; + case 's': + *type += 1; + if (non_empty) + string_append (result, " "); + string_append (result, "short"); + break; + case 'c': + *type += 1; + if (non_empty) + string_append (result, " "); + string_append (result, "char"); + break; + case 'r': + *type += 1; + if (non_empty) + string_append (result, " "); + string_append (result, "long double"); + break; + case 'd': + *type += 1; + if (non_empty) + string_append (result, " "); + string_append (result, "double"); + break; + case 'f': + *type += 1; + if (non_empty) + string_append (result, " "); + string_append (result, "float"); + break; + case 'G': + *type += 1; + if (!isdigit (**type)) + { + success = 0; + break; + } + /* fall through */ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + n = 0; + do + { + n *= 10; + n += **type - '0'; + *type += 1; + } + while (isdigit (**type)); + if (strlen (*type) < n) + { + success = 0; + break; + } + if (non_empty) + string_append (result, " "); + string_appendn (result, *type, n); + *type += n; + break; + default: + success = 0; + break; + } + + if (success) + { + if (!string_empty (&decl)) + { + string_append (result, " "); + string_appends (result, &decl); + } + string_delete (&decl); + return 1; + } + else + { + string_delete (&decl); + string_delete (result); + return 0; + } +} + +/* `result' will be initialised in do_type; it will be freed on failure */ + +static int +do_arg (type, result, arg_mode) + const char **type; + string *result; + int arg_mode; +{ + const char *start = *type; + + if (!do_type (type, result, arg_mode)) + return 0; + remember_type (start, *type - start); + return 1; +} + +static void +remember_type (start, len) + const char *start; + int len; +{ + char *tem; + + if (ntypes >= typevec_size) + { + if (typevec_size == 0) + { + typevec_size = 3; + typevec = (char **) xmalloc (sizeof (char*)*typevec_size); + } + else + { + typevec_size *= 2; + typevec = (char **) xrealloc ((char *)typevec, sizeof (char*)*typevec_size); + } + } + tem = (char *) xmalloc (len + 1); + memcpy (tem, start, len); + tem[len] = '\0'; + typevec[ntypes++] = tem; +} + +/* `decl' must be already initialised, usually non-empty; + it won't be freed on failure */ + +static int +do_args (type, decl, arg_mode) + const char **type; + string *decl; + int arg_mode; +{ + string arg; + int need_comma = 0; + + if (print_arg_types) + string_append (decl, "("); + + while (**type != '_' && **type != '\0' && **type != 'e' && **type != 'v') + { + if (**type == 'N') + { + int r; + int t; + *type += 1; + if (!get_count (type, &r) || !get_count (type, &t) || t >= ntypes) + return 0; + while (--r >= 0) + { + const char *tem = typevec[t]; + if (need_comma && print_arg_types) + string_append (decl, ", "); + if (!do_arg (&tem, &arg, arg_mode)) + return 0; + if (print_arg_types) + string_appends (decl, &arg); + string_delete (&arg); + need_comma = 1; + } + } + else + { + if (need_comma & print_arg_types) + string_append (decl, ", "); + if (!do_arg (type, &arg, arg_mode)) + return 0; + if (print_arg_types) + string_appends (decl, &arg); + string_delete (&arg); + need_comma = 1; + } + } + + if (**type == 'v') + *type += 1; + else if (**type == 'e') + { + *type += 1; + if (print_arg_types) + { + if (need_comma) + string_append (decl, ","); + string_append (decl, "..."); + } + } + + if (print_arg_types) + string_append (decl, ")"); + return 1; +} + +static void +munge_function_name (name, arg_mode) + string *name; + int arg_mode; +{ + if (!string_empty (name) && name->p - name->b >= 3 + && name->b[0] == 'o' && name->b[1] == 'p' && name->b[2] == '$') + { + int i; + /* see if it's an assignment expression */ + if (name->p - name->b >= 10 /* op$assign_ */ + && memcmp (name->b + 3, "assign_", 7) == 0) + { + for (i = 0; i < sizeof (optable)/sizeof (optable[0]); i++) + { + int len = name->p - name->b - 10; + if (strlen (optable[i].in) == len + && memcmp (optable[i].in, name->b + 10, len) == 0) + { + string_clear (name); + string_append (name, "operator"); + string_append (name, optable[i].out); + string_append (name, "="); + return; + } + } + } + else + { + for (i = 0; i < sizeof (optable)/sizeof (optable[0]); i++) + { + int len = name->p - name->b - 3; + if (strlen (optable[i].in) == len + && memcmp (optable[i].in, name->b + 3, len) == 0) + { + string_clear (name); + string_append (name, "operator"); + string_append (name, optable[i].out); + return; + } + } + } + return; + } + else if (!string_empty (name) && name->p - name->b >= 5 + && memcmp (name->b, "type$", 5) == 0) + { + /* type conversion operator */ + string type; + const char *tem = name->b + 5; + if (do_type (&tem, &type, arg_mode)) + { + string_clear (name); + string_append (name, "operator "); + string_appends (name, &type); + string_delete (&type); + return; + } + } +} + +/* a mini string-handling package */ + +static void +string_need (s, n) + string *s; + int n; +{ + if (s->b == NULL) + { + if (n < 32) + n = 32; + s->p = s->b = (char *) xmalloc (n); + s->e = s->b + n; + } + else if (s->e - s->p < n) + { + int tem = s->p - s->b; + n += tem; + n *= 2; + s->b = (char *) xrealloc (s->b, n); + s->p = s->b + tem; + s->e = s->b + n; + } +} + +static void +string_delete (s) + string *s; +{ + if (s->b != NULL) + { + free (s->b); + s->b = s->e = s->p = NULL; + } +} + +static void +string_init (s) + string *s; +{ + s->b = s->p = s->e = NULL; +} + +static void +string_clear (s) + string *s; +{ + s->p = s->b; +} + +static int +string_empty (s) + string *s; +{ + return s->b == s->p; +} + +static void +string_append (p, s) + string *p; + const char *s; +{ + int n; + if (s == NULL || *s == '\0') + return; + n = strlen (s); + string_need (p, n); + memcpy (p->p, s, n); + p->p += n; +} + +static void +string_appends (p, s) + string *p, *s; +{ + int n; + if (s->b == s->p) + return; + n = s->p - s->b; + string_need (p, n); + memcpy (p->p, s->b, n); + p->p += n; +} + +static void +string_appendn (p, s, n) + string *p; + const char *s; + int n; +{ + if (n == 0) + return; + string_need (p, n); + memcpy (p->p, s, n); + p->p += n; +} + +static void +string_prepend (p, s) + string *p; + const char *s; +{ + if (s == NULL || *s == '\0') + return; + string_prependn (p, s, strlen (s)); +} + +#if 0 +static void +string_prepends (p, s) + string *p, *s; +{ + if (s->b == s->p) + return; + string_prependn (p, s->b, s->p - s->b); +} +#endif + +static void +string_prependn (p, s, n) + string *p; + const char *s; + int n; +{ + char *q; + + if (n == 0) + return; + string_need (p, n); + for (q = p->p - 1; q >= p->b; q--) + q[n] = q[0]; + memcpy (p->b, s, n); + p->p += n; +} diff --git a/gnu/usr.bin/gdb/dbxread.c b/gnu/usr.bin/gdb/dbxread.c new file mode 100644 index 0000000..1e95d96 --- /dev/null +++ b/gnu/usr.bin/gdb/dbxread.c @@ -0,0 +1,5587 @@ +/*- + * This code is derived from software copyrighted by the Free Software + * Foundation. + * + * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. + * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory. + */ + +#ifndef lint +static char sccsid[] = "@(#)dbxread.c 6.3 (Berkeley) 5/8/91"; +#endif /* not lint */ + +/* Read dbx symbol tables and convert to internal format, 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. */ + +/* 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()). + 2. Full read-in of symbols. (psymtab_to_symtab()). This happens + when a symbol in a file for which symbols have not yet been + read in is referenced. + 2a. The "add-file" command. Similar to #2. */ + +#include <stdio.h> +#include "defs.h" +#include "param.h" + +#ifdef READ_DBX_FORMAT + +#ifdef USG +#include <sys/types.h> +#include <fcntl.h> +#define L_SET 0 +#define L_INCR 1 +#endif + +#ifdef COFF_ENCAPSULATE +#include "a.out.encap.h" +#include "stab.gnu.h" +#else +#include <a.out.h> +#include <stab.h> +#endif +#include <ctype.h> + +#ifndef NO_GNU_STABS +/* + * Define specifically gnu symbols here. + */ + +/* The following type indicates the definition of a symbol as being + an indirect reference to another symbol. The other symbol + appears as an undefined reference, immediately following this symbol. + + Indirection is asymmetrical. The other symbol's value will be used + to satisfy requests for the indirect symbol, but not vice versa. + If the other symbol does not have a definition, libraries will + be searched to find a definition. */ +#ifndef N_INDR +#define N_INDR 0xa +#endif + +/* The following symbols refer to set elements. + All the N_SET[ATDB] symbols with the same name form one set. + Space is allocated for the set in the text section, and each set + element's value is stored into one word of the space. + The first word of the space is the length of the set (number of elements). + + The address of the set is made into an N_SETV symbol + whose name is the same as the name of the set. + This symbol acts like a N_DATA global symbol + in that it can satisfy undefined external references. */ + +#ifndef N_SETA +#define N_SETA 0x14 /* Absolute set element symbol */ +#endif /* This is input to LD, in a .o file. */ + +#ifndef N_SETT +#define N_SETT 0x16 /* Text set element symbol */ +#endif /* This is input to LD, in a .o file. */ + +#ifndef N_SETD +#define N_SETD 0x18 /* Data set element symbol */ +#endif /* This is input to LD, in a .o file. */ + +#ifndef N_SETB +#define N_SETB 0x1A /* Bss set element symbol */ +#endif /* This is input to LD, in a .o file. */ + +/* Macros dealing with the set element symbols defined in a.out.h */ +#define SET_ELEMENT_P(x) ((x)>=N_SETA&&(x)<=(N_SETB|N_EXT)) +#define TYPE_OF_SET_ELEMENT(x) ((x)-N_SETA+N_ABS) + +#ifndef N_SETV +#define N_SETV 0x1C /* Pointer to set vector in data area. */ +#endif /* This is output from LD. */ + +#ifndef N_WARNING +#define N_WARNING 0x1E /* Warning message to print if file included */ +#endif /* This is input to ld */ + +#ifndef __GNU_STAB__ + +/* Line number for the data section. This is to be used to describe + the source location of a variable declaration. */ +#ifndef N_DSLINE +#define N_DSLINE (N_SLINE+N_DATA-N_TEXT) +#endif + +/* Line number for the bss section. This is to be used to describe + the source location of a variable declaration. */ +#ifndef N_BSLINE +#define N_BSLINE (N_SLINE+N_BSS-N_TEXT) +#endif + +#endif /* not __GNU_STAB__ */ +#endif /* NO_GNU_STABS */ + +#include <obstack.h> +#include <sys/param.h> +#include <sys/file.h> +#include <sys/stat.h> + +#include "symtab.h" + +#ifndef COFF_FORMAT +#ifndef AOUTHDR +#define AOUTHDR struct exec +#endif +#endif + +static void add_symbol_to_list (); +static void read_dbx_symtab (); +static void process_one_symbol (); +static void free_all_psymbols (); +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 void hash_symsegs (); +static struct pending *copy_pending (); +static void fix_common_block (); + +static void add_undefined_type (); +static void cleanup_undefined_types (); + +extern char *index(); + +extern struct symtab *read_symsegs (); +extern void free_all_symtabs (); +extern void free_all_psymtabs (); +extern void free_inclink_symtabs (); + +/* C++ */ +static struct type **read_args (); + +/* Macro to determine which symbols to ignore when reading the first symbol + of a file. Some machines override this definition. */ +#ifdef N_NSYMS +#ifndef IGNORE_SYMBOL +/* This code is used on Ultrix systems. Ignore it */ +#define IGNORE_SYMBOL(type) (type == N_NSYMS) +#endif +#else +#ifndef IGNORE_SYMBOL +/* Don't ignore any symbols. */ +#define IGNORE_SYMBOL(type) (0) +#endif +#endif /* not N_NSYMS */ + +/* Macro for number of symbol table entries (in usual a.out format). + Some machines override this definition. */ +#ifndef NUMBER_OF_SYMBOLS +#ifdef COFF_HEADER +#define NUMBER_OF_SYMBOLS \ + ((COFF_HEADER(hdr) ? hdr.coffhdr.filehdr.f_nsyms : hdr.a_syms) / \ + sizeof (struct nlist)) +#else +#define NUMBER_OF_SYMBOLS (hdr.a_syms / sizeof (struct nlist)) +#endif +#endif + +/* Macro for file-offset of symbol table (in usual a.out format). */ +#ifndef SYMBOL_TABLE_OFFSET +#define SYMBOL_TABLE_OFFSET N_SYMOFF (hdr) +#endif + +/* Macro for file-offset of string table (in usual a.out format). */ +#ifndef STRING_TABLE_OFFSET +#define STRING_TABLE_OFFSET (N_SYMOFF (hdr) + hdr.a_syms) +#endif + +/* Macro to store the length of the string table data in INTO. */ +#ifndef READ_STRING_TABLE_SIZE +#define READ_STRING_TABLE_SIZE(INTO) \ +{ val = myread (desc, &INTO, sizeof INTO); \ + if (val < 0) perror_with_name (name); } +#endif + +/* Macro to declare variables to hold the file's header data. */ +#ifndef DECLARE_FILE_HEADERS +#define DECLARE_FILE_HEADERS AOUTHDR hdr +#endif + +/* Macro to read the header data from descriptor DESC and validate it. + NAME is the file name, for error messages. */ +#ifndef READ_FILE_HEADERS +#ifdef HEADER_SEEK_FD +#define READ_FILE_HEADERS(DESC, NAME) \ +{ HEADER_SEEK_FD (DESC); \ + 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); } +#else +#define READ_FILE_HEADERS(DESC, NAME) \ +{ 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); } +#endif +#endif + +/* Non-zero if this is an object (.o) file, rather than an executable. + Distinguishing between the two is rarely necessary (and seems like + a hack, but there is no other way to do ADDR_OF_TEXT_SEGMENT + right for SunOS). */ +#if !defined (IS_OBJECT_FILE) +/* This will not work + if someone decides to make ld preserve relocation info. */ +#define IS_OBJECT_FILE (hdr.a_trsize != 0) +#endif + +/* Macro for size of text segment */ +#ifndef SIZE_OF_TEXT_SEGMENT +#define SIZE_OF_TEXT_SEGMENT hdr.a_text +#endif + +/* Get the address in debugged memory of the start + of the text segment. */ +#if !defined (ADDR_OF_TEXT_SEGMENT) +#if defined (N_TXTADDR) +#define ADDR_OF_TEXT_SEGMENT (IS_OBJECT_FILE ? 0 : N_TXTADDR (hdr)) +#else /* no N_TXTADDR */ +#define ADDR_OF_TEXT_SEGMENT 0 +#endif /* no N_TXTADDR */ +#endif /* no ADDR_OF_TEXT_SEGMENT */ + +/* Macro to get entry point from headers. */ +#ifndef ENTRY_POINT +#define ENTRY_POINT hdr.a_entry +#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; + +/* Chain of symtabs made from reading the file's symsegs. + These symtabs do not go into symtab_list themselves, + but the information is copied from them when appropriate + to make the symtabs that will exist permanently. */ + +static struct symtab *symseg_chain; + +/* Symseg symbol table for the file whose data we are now processing. + It is one of those in symseg_chain. Or 0, for a compilation that + has no symseg. */ + +static struct symtab *current_symseg; + +/* 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; + +/* End of the text segment of the executable file, + as found in the symbol _etext. */ + +static CORE_ADDR end_of_text_addr; + +/* 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; + 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 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, 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; + 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 */ + +/* File name symbols were loaded from. */ + +static char *symfile; + +/* Low and high symbol values (inclusive) for the global variable + entries in the symbol file. */ + +static int first_global_sym, last_global_sym; + +/* Structures with which to manage partial symbol allocation. */ + +struct psymbol_allocation_list global_psymbols, static_psymbols; + +/* 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; + + /* Setup a define to deal cleanly with the underscore problem */ + +#ifdef NAMES_HAVE_UNDERSCORE +#define HASH_OFFSET 1 +#else +#define HASH_OFFSET 0 +#endif + +#if 0 +/* I'm not sure why this is here. To debug bugs which cause + an infinite loop of allocations, I suppose. In any event, + dumping core when out of memory isn't usually right. */ +static int +xxmalloc (n) +{ + int v = malloc (n); + if (v == 0) + { + fprintf (stderr, "Virtual memory exhausted.\n"); + abort (); + } + return v; +} +#else /* not 0 */ +#define xxmalloc xmalloc +#endif /* not 0 */ + +/* 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. */ + +static 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. */ + +static 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; +} + +/* 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; + +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; + +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; + +/* At the start of reading dbx symbols, allocate our tables. */ + +static void +init_header_files () +{ + n_allocated_header_files = 10; + header_files = (struct header_file *) xxmalloc (10 * sizeof (struct header_file)); + n_header_files = 0; + + n_allocated_this_object_header_files = 10; + this_object_header_files = (int *) xxmalloc (10 * sizeof (int)); +} + +/* At the end of reading dbx symbols, free our tables. */ + +static void +free_header_files () +{ + register int i; + for (i = 0; i < n_header_files; i++) + free (header_files[i].name); + if (header_files) free (header_files); + if (this_object_header_files) + free (this_object_header_files); +} + +/* 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; + register struct header_file *p = header_files; + header_file_prev_index = -1; + +#if 0 + /* This code was used before I knew about the instance codes. + My first hypothesis is that it is not necessary now + that instance codes are handled. */ + + /* Has this header file a previous definition? + If so, make a new entry anyway so that this use in this source file + gets a separate entry. Later source files get the old entry. + Record here the index of the old entry, so that any type indices + not previously defined can get defined in the old entry as + well as in the new one. */ + + for (i = 0; i < n_header_files; i++) + if (!strcmp (p[i].name, name)) + { + header_file_prev_index = i; + } + +#endif + + /* 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 **) xxmalloc (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; + + if (real_filenum >= n_header_files) + abort (); + + 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]; + } +} + +/* 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 *) xxmalloc (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. */ + +static void +really_free_pendings () +{ + struct pending *next, *next1; + struct pending_block *bnext, *bnext1; + + for (next = free_pendings; next; next = next1) + { + next1 = next->next; + free (next); + } + free_pendings = 0; + + for (bnext = pending_blocks; bnext; bnext = bnext1) + { + bnext1 = bnext->next; + free (bnext); + } + 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); + + 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) + 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, *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; + +#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; + + 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, start_addr) + char *name; + CORE_ADDR start_addr; +{ + register struct symtab *s; + + 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 *) xxmalloc (10 * sizeof (struct context_stack)); + context_stack_size = 10; + context_stack_depth = 0; + + new_object_header_files (); + + for (s = symseg_chain; s; s = s->next) + if (s->ldsymoff == symnum * sizeof (struct nlist)) + break; + current_symseg = s; + if (s != 0) + return; + + type_vector_length = 160; + type_vector = (struct typevector *) + xxmalloc (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); + +#if 0 /* This is now set at the beginning of read_ofile_symtab */ + /* Set default for compiler to pcc; assume that we aren't processing + a gcc compiled file until proved otherwise. */ + + processing_gcc_compilation = 0; +#endif +} + +/* 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) + char *name; +{ + 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 *) + xxmalloc (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 *) xxmalloc (sizeof (struct subfile)); + subfile->next = subfiles; + subfile->name = savestring (name, strlen (name)); + 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; + + if (current_symseg != 0) + { + last_source_file = 0; + current_symseg = 0; + return; + } + + /* 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 *) xxmalloc (sizeof (struct symtab)); + symtab->free_ptr = 0; + + /* Fill in its components. */ + symtab->blockvector = blockvector; + type_vector->length = type_vector_length; + symtab->typevector = type_vector; + symtab->free_code = free_linetable; + if (subfile->next == 0) + symtab->free_ptr = (char *) type_vector; + + symtab->filename = subfile->name; + 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))); + symtab->nlines = 0; + symtab->line_charpos = 0; + + /* 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; +} + +#ifdef N_BINCL + +/* 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 *) xxmalloc (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; +} +#endif /* Have N_BINCL */ + +/* Accumulate the misc functions in bunches of 127. + At the end, copy them all into one newly allocated structure. */ + +#define MISC_BUNCH_SIZE 127 + +struct misc_bunch +{ + struct misc_bunch *next; + struct misc_function contents[MISC_BUNCH_SIZE]; +}; + +/* Bunch currently being filled up. + The next field points to chain of filled bunches. */ + +static struct misc_bunch *misc_bunch; + +/* Number of slots filled in current bunch. */ + +static int misc_bunch_index; + +/* Total number of misc functions recorded so far. */ + +static int misc_count; + +static void +init_misc_functions () +{ + misc_count = 0; + misc_bunch = 0; + misc_bunch_index = MISC_BUNCH_SIZE; +} + +static void +record_misc_function (name, address, type) + char *name; + CORE_ADDR address; + int type; +{ + register struct misc_bunch *new; + register unsigned char mtype; + + if (misc_bunch_index == MISC_BUNCH_SIZE) + { + new = (struct misc_bunch *) xxmalloc (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; + switch (type &~ N_EXT) + { + case N_TEXT: mtype = mf_text; break; + case N_DATA: mtype = mf_data; break; + case N_BSS: mtype = mf_bss; break; + case N_ABS: mtype = mf_abs; break; +#ifdef N_SETV + case N_SETV: mtype = mf_data; break; +#endif + default: mtype = mf_unknown; break; + } + misc_bunch->contents[misc_bunch_index].type = mtype; + misc_bunch_index++; + misc_count++; +} + +static int +compare_misc_functions (fn1, fn2) + struct misc_function *fn1, *fn2; +{ + /* Return a signed result based on unsigned comparisons + so that we sort into unsigned numeric order. */ + if (fn1->address < fn2->address) + return -1; + if (fn1->address > fn2->address) + return 1; + return 0; +} + +static void +discard_misc_bunches () +{ + register struct misc_bunch *next; + + while (misc_bunch) + { + next = misc_bunch->next; + free (misc_bunch); + misc_bunch = next; + } +} + +/* 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. */ +static void +condense_misc_bunches (inclink) + int inclink; +{ + register int i, j; + register struct misc_bunch *bunch; +#ifdef NAMES_HAVE_UNDERSCORE + int offset = 1; +#else + int offset = 0; +#endif + + 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 *) + xxmalloc (misc_count * sizeof (struct misc_function)); + j = 0; + } + + bunch = misc_bunch; + while (bunch) + { + for (i = 0; i < misc_bunch_index; i++) + { + misc_function_vector[j] = bunch->contents[i]; + misc_function_vector[j].name + = obconcat (misc_function_vector[j].name + + (misc_function_vector[j].name[0] == '_' ? offset : 0), + "", ""); + j++; + } + bunch = bunch->next; + misc_bunch_index = MISC_BUNCH_SIZE; + } + + if (inclink) + misc_function_count += misc_count; + else + misc_function_count = j; + + /* Sort the misc functions by address. */ + + qsort (misc_function_vector, misc_function_count, + sizeof (struct misc_function), + compare_misc_functions); + + /* (re)build the hash table (positions changed during the sort) */ + + for (i = 0; i < MISC_FUNC_HASH_SIZE; ++i) + misc_function_hash_tab[i] = -1; + for (i = 0; i < misc_function_count; ++i) + { + j = hash_symbol(misc_function_vector[i].name) & (MISC_FUNC_HASH_SIZE - 1); + misc_function_vector[i].next = misc_function_hash_tab[j]; + misc_function_hash_tab[j] = i; + } +} + +/* Call sort_syms to sort alphabetically + the symbols of each block of each symtab. */ + +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)); +} + +static void sort_symtab_syms (); + +static void +sort_syms () +{ + register struct symtab *s; + + for (s = symtab_list; s; s = s->next) + sort_symtab_syms (s); +} + +static 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; + + /* Note that 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). We do this by a + correct compare in compare_symbols, and by the reversal of the + symbols if we don't sort. This works as long as a register debug + symbol always comes after a parameter debug symbol. */ + + /* This is no longer necessary; lookup_block_symbol now always + prefers some other declaration over a parameter declaration. We + still sort the thing (that is necessary), but we don't reverse it + if we shouldn't sort it. */ + + for (i = 0; i < nbl; i++) + { + b = BLOCKVECTOR_BLOCK (bv, i); + if (BLOCK_SHOULD_SORT (b)) + qsort (&BLOCK_SYM (b, 0), BLOCK_NSYMS (b), + sizeof (struct symbol *), compare_symbols); + } +} + + +extern struct symtab *psymtab_to_symtab (); + +/* The entry point. */ +static CORE_ADDR entry_point; + +static char *symfile_string_table; +static int symfile_string_table_size; + +/* 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; +{ + register int desc; + DECLARE_FILE_HEADERS; + struct nlist *nlist; + + /* The string table. */ + char *stringtab; + + /* The size of the string table (buffer is a bizarre name...). */ + long buffer; + + register int val; + extern void close (); + struct cleanup *old_chain; + struct symtab *symseg; + struct stat statbuf; + + dont_repeat (); + + if (name == 0) + { + if ((symtab_list || partial_symtab_list) + && from_tty + && !query ("Discard symbol table? ", 0)) + error ("Not confirmed."); + if (symfile) + free (symfile); + symfile = 0; + free_all_symtabs (); + free_all_psymtabs (); + return; + } + + name = tilde_expand (name); + make_cleanup (free, name); + + if ((symtab_list || partial_symtab_list) + && !query ("Load new symbol table from \"%s\"? ", name)) + error ("Not confirmed."); + + { + 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); + + READ_FILE_HEADERS (desc, name); + + entry_point = ENTRY_POINT; + + if (NUMBER_OF_SYMBOLS == 0) + { + if (symfile) + free (symfile); + symfile = 0; + free_all_symtabs (); + free_all_psymtabs (); + printf ("%s has no symbol-table; symbols discarded.\n", name); + fflush (stdout); + do_cleanups (old_chain); + return; + } + + printf ("Reading symbol data from %s...", name); + fflush (stdout); + + /* Now read the string table, all at once. */ + val = lseek (desc, STRING_TABLE_OFFSET, 0); + if (val < 0) + perror_with_name (name); + if (stat (name, &statbuf) == -1) + perror_with_name (name); + READ_STRING_TABLE_SIZE (buffer); + if (buffer >= 0 && buffer < statbuf.st_size) + { + /* This should speed things up without consuming much + extra memory (because probably little of the space is going + to be reused anyway, whether in data or stack space). + + A quick test (running GDB on itself and setting 9 breakpoints + in different files) showed that memory usage was almost + identical for the two cases. */ +#if 0 +#ifdef BROKEN_LARGE_ALLOCA + stringtab = (char *) xmalloc (buffer); + make_cleanup (free, stringtab); +#else + stringtab = (char *) alloca (buffer); +#endif +#endif + stringtab = (char *) xmalloc (buffer); + symfile_string_table = stringtab; + symfile_string_table_size = buffer; + } + else + stringtab = NULL; + if (stringtab == NULL) + error ("ridiculous string table size: %d bytes", buffer); + + /* Usually READ_STRING_TABLE_SIZE will have shifted the file pointer. + Occaisionally, it won't. */ + val = lseek (desc, STRING_TABLE_OFFSET, L_SET); + if (val < 0) + perror_with_name (name); + val = myread (desc, stringtab, buffer); + if (val < 0) + perror_with_name (name); + + /* Throw away the old symbol table. */ + + if (symfile) + free (symfile); + symfile = 0; + free_all_symtabs (); + free_all_psymtabs (); + + /* Empty the hash table of global syms looking for values. */ + bzero (global_sym_chain, sizeof global_sym_chain); + + /* Symsegs are no longer supported by GDB. Setting symseg_chain to + 0 is easier than finding all the symseg code and eliminating it. */ + symseg_chain = 0; + + /* Position to read the symbol table. Do not read it all at once. */ + val = lseek (desc, SYMBOL_TABLE_OFFSET, 0); + if (val < 0) + perror_with_name (name); + + /* 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. */ + free_header_files (); + init_header_files (); + + init_misc_functions (); + make_cleanup (discard_misc_bunches, 0); + + free_pendings = 0; + pending_blocks = 0; + file_symbols = 0; + global_symbols = 0; + make_cleanup (really_free_pendings, 0); + + /* Now that the symbol table data of the executable file are all in core, + process them and define symbols accordingly. Closes desc. */ + + read_dbx_symtab (desc, stringtab, buffer, NUMBER_OF_SYMBOLS, 0, + ADDR_OF_TEXT_SEGMENT, SIZE_OF_TEXT_SEGMENT); + + /* Go over the misc functions 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; + + /* Make a default for file to list. */ + + symfile = savestring (name, strlen (name)); + + /* 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 */ + + do_cleanups (old_chain); /* Descriptor closed here */ + + /* Free the symtabs made by read_symsegs, but not their contents, + which have been copied into symtabs on symtab_list. */ + while (symseg_chain) + { + register struct symtab *s = symseg_chain->next; + free (symseg_chain); + symseg_chain = s; + } + + if (!partial_symtab_list) + printf ("\n(no debugging symbols found)..."); + + printf ("done.\n"); + fflush (stdout); +} + +/* Return name of file symbols were loaded from, or 0 if none.. */ + +char * +get_sym_file () +{ + return symfile; +} + +/* 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 of the string table + of the object file we are reading (as copied into core). */ +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) + error ("error or end of file reading symbol table"); + symbuf_end = nbytes / sizeof (struct nlist); + symbuf_idx = 0; + return 1; +} + +/* 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++; + 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. + */ +void +init_psymbol_list (total_symbols) + int total_symbols; +{ + /* 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 (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 add_psymtab_dependency (); +static void end_psymtab(); + +static int +compare_psymbols (s1, s2) + register struct partial_symbol *s1, *s2; +{ + register char + *st1 = SYMBOL_NAME (s1), + *st2 = SYMBOL_NAME (s2); + register int i; + + if (st1[0] - st2[0]) + return (st1[0] - st2[0]); + if (st1[1] - st2[1]) + return (st1[1] - st2[1]); + if (i = strcmp(st1, st2)) + return (i); + /* Next comparison implements policy that used to be in lookup_symbol: + * it would search psymtabs in psymtab_list order (reverse order of + * declaration) & take first occurance of symbol it found. So, we + * collate duplicate names in reverse psymtab order. */ + return (s2->pst - s1->pst); +} + +/* 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. + + I have no idea whether or not this routine should be setup to deal + with inclinks. It seems reasonable to me that they be dealt with + standardly, so I am not going to make a strong effort to deal with + them here. + */ + +static void +read_dbx_symtab (desc, stringtab, stringtab_size, nlistlen, inclink, + text_addr, text_size) + int desc; + register char *stringtab; + register long stringtab_size; + register int nlistlen; + int inclink; + unsigned text_addr; + int text_size; +{ + register struct nlist *bufp; + register char *namestring; + register struct partial_symbol *psym; + register struct psymbol_allocation_list *psymbol_struct; + + int nsl; + int past_first_source_file = 0; + CORE_ADDR last_o_file_start = 0; + char *last_o_file_name = "*bogus*"; + struct cleanup *old_chain; + char *p; + enum namespace ns; + enum address_class class; + +#ifdef PROFILE_TYPES + int i; + int profile_types [256]; + int strcmp_called = 0; + int autovars = 0; + int global_funs = 0; +#endif + + /* 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; + +#ifdef PROFILE_TYPES + for (i = 0; i < 256; i++) + profile_types[i] = 0; +#endif + + 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 *)); + + old_chain = make_cleanup (free_all_psymtabs, 0); + + /* Init bincl list */ + init_bincl_list (20); + make_cleanup (free_bincl_list, 0); + + /* Setup global partial symbol list */ + init_psymbol_list (nlistlen); + + last_source_file = 0; + +#ifdef END_OF_TEXT_DEFAULT + end_of_text_addr = END_OF_TEXT_DEFAULT; +#else + end_of_text_addr = text_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++]; + +#ifdef PROFILE_TYPES + profile_types[bufp->n_type]++; +#endif + + /* + * Special case to speed up readin. + */ + if (bufp->n_type == N_SLINE) continue; + + /* Ok. There is a lot of code duplicated in the rest of this + switch statiement (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 index. + *) 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. */ +#define SET_NAMESTRING()\ + 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 + +#define ADD_PSYMBOL_TO_LIST(NAME, NAMELENGTH, NAMESPACE, CLASS, LIST, VALUE)\ + 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); \ + SYMBOL_VALUE (psym) = (VALUE); \ + } while (0); + + + switch (bufp->n_type) + { + /* + * Standard, non-debugger, symbols + */ + + case N_TEXT | N_EXT: + /* Catch etext */ + + SET_NAMESTRING(); + + if (namestring[6] == '\0' && namestring[5] == 't' + && namestring[4] == 'x' && namestring[3] == 'e' + && namestring[2] == 't' && namestring[1] == 'e' + && namestring[0] == '_') + end_of_text_addr = bufp->n_value; + + /* Figure out beginning and end of global linker symbol + section and put non-debugger specified symbols on + tmp_symchain */ + + last_global_sym = symnum; + if (!first_global_sym) first_global_sym = symnum; + + record_misc_function (namestring, bufp->n_value, + bufp->n_type); /* Always */ + + continue; + +#ifdef N_NBTEXT + case N_NBTEXT | N_EXT: +#endif +#ifdef N_NBDATA + case N_NBDATA | N_EXT: +#endif +#ifdef N_NBBSS + case N_NBBSS | N_EXT: +#endif +#ifdef N_SETV + case N_SETV | N_EXT: +#endif + case N_ABS | N_EXT: + case N_DATA | N_EXT: + case N_BSS | N_EXT: + /* Figure out beginning and end of global linker symbol + section and put non-debugger specified symbols on + tmp_symchain */ + + SET_NAMESTRING(); + + last_global_sym = symnum; + if (!first_global_sym) first_global_sym = symnum; + + /* Not really a function here, but... */ + record_misc_function (namestring, bufp->n_value, + bufp->n_type); /* Always */ + + continue; + +#ifdef N_NBTEXT + case N_NBTEXT: +#endif + + /* 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: + 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) + { + startup_file_start = last_o_file_start; + startup_file_end = bufp->n_value; + } + if (past_first_source_file && pst) + { + 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; + last_o_file_name = namestring; + nsl = strlen(namestring); + if (namestring[nsl-2] == '.' && namestring[nsl-1] == 'o') + namestring[nsl-2] = 0; + } + else if (strcmp(namestring, "gcc_compiled.")) + { + if (*namestring == '_') + ++namestring; + namestring = obconcat(last_o_file_name, ":", namestring); + last_global_sym = symnum; + if (!first_global_sym) + first_global_sym = symnum; + record_misc_function(namestring, bufp->n_value, bufp->n_type); + } + continue; + + case N_ABS: + case N_DATA: + case N_BSS: + SET_NAMESTRING(); + if (*namestring == '_') + ++namestring; + namestring = obconcat(last_o_file_name, ":", namestring); + last_global_sym = symnum; + if (!first_global_sym) + first_global_sym = symnum; + record_misc_function(namestring, bufp->n_value, bufp->n_type); + continue; + + case N_UNDF: + case N_UNDF | N_EXT: +#ifdef N_NBDATA + case N_NBDATA: +#endif +#ifdef N_NBBSS + case N_NBBSS: +#endif + + /* Keep going . . .*/ + + /* + * Special symbol types for GNU + */ +#ifdef N_INDR + case N_INDR: + case N_INDR | N_EXT: +#endif +#ifdef N_SETA + 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: +#endif + continue; + + /* + * Debugger symbols + */ + + case N_SO: + /* End the current partial symtab and start a new one */ + + SET_NAMESTRING(); + + if (pst && past_first_source_file) + { + 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; + + pst = start_psymtab (namestring, bufp->n_value, + symnum * sizeof (struct nlist), + global_psymbols.next, static_psymbols.next); + + continue; + +#ifdef N_BINCL + 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 return */ + + 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; +#endif + + 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 *) index (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); + 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. */ + + /* We are looking for something of the form + <name> ":" ("t" | "T") [<number> "="] "e" + {<constant> ":" <value> ","} ";". */ + + /* Skip over the colon and the 't' or 'T'. */ + p += 2; + /* This type may be given a number. Skip over it. */ + while ((*p >= '0' && *p <= '9') + || *p == '=') + p++; + + if (*p++ == 'e') + { + /* We have found an enumerated type. */ + /* According to comments in read_enum_type + a comma could end it instead of a semicolon. + I don't know where that happens. + Accept either. */ + while (*p && *p != ';' && *p != ',') + { + char *q; + + /* Check for and handle cretinous dbx symbol name + continuation! */ + if (*p == '\\') + p = next_symbol_text (); + + /* Point to the character after the name + of the enum constant. */ + for (q = p; *q && *q != ':'; q++) + ; + /* Note that the value doesn't matter for + enum constants in psymtabs, just in symtabs. */ + ADD_PSYMBOL_TO_LIST (p, q - p, + VAR_NAMESPACE, LOC_CONST, + static_psymbols, 0); + /* Point past the name. */ + p = q; + /* Skip over the value. */ + while (*p && *p != ',') + p++; + /* Advance past the comma. */ + if (*p) + p++; + } + } + + continue; + case 'c': + /* Constant, e.g. from "const" in Pascal. */ + ADD_PSYMBOL_TO_LIST (namestring, p - namestring, + VAR_NAMESPACE, LOC_CONST, + static_psymbols, bufp->n_value); + continue; + default: +#ifdef PROFILE_TYPES + if (isalpha(p[1])) + printf ("Funny...LSYM with a letter that isn't a type\n"); + autovars++; +#endif + /* 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: +#if 0 + /* This special-casing of N_FUN is just wrong; N_FUN + does not mean "function"; it means "text segment". + So N_FUN can go with 'V', etc. as well as 'f' or 'F'. */ + + SET_NAMESTRING(); + + p = (char *) index (namestring, ':'); + + if (!p || p[1] == 'F') continue; + +#ifdef PROFILE_TYPES + if (p[1] != 'f') + printf ("Funny...FUN with a letter that isn't 'F' or 'f'.\n"); + global_funs++; +#endif + + ADD_PSYMBOL_TO_LIST (namestring, p - namestring, + VAR_NAMESPACE, LOC_BLOCK, + static_psymbols, bufp->n_value); + + continue; +#endif /* 0 */ + case N_GSYM: /* Global (extern) variable; can be + data or bss (sigh). */ + case N_STSYM: /* Data seg var -- static */ + case N_LCSYM: /* BSS " */ + + /* 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. */ +#ifdef N_M2C + case N_M2C: /* I suspect that I can ignore this here. */ + case N_SCOPE: /* Same. */ +#endif + + SET_NAMESTRING(); + + p = (char *) index (namestring, ':'); + if (!p) + continue; /* Not a debugging symbol. */ + + process_symbol_for_psymtab: + + /* 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': + ADD_PSYMBOL_TO_LIST (namestring, p - namestring, + VAR_NAMESPACE, LOC_STATIC, + static_psymbols, bufp->n_value); + continue; + case 'G': + ADD_PSYMBOL_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: + fatal ("Internal error: Unexpected debugging symbol type '%c' at symnum %d.\n", + p[1], symnum); + } + +#ifdef N_BINCL + 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: +#endif +#ifdef N_DSLINE + case N_DSLINE: +#endif +#ifdef N_BSLINE + case N_BSLINE: +#endif + case N_SSYM: /* Claim: Structure or union element. + Hopefully, I can ignore this. */ + case N_ENTRY: /* Alternate entry point; can ignore. */ +#ifdef N_MAIN + case N_MAIN: /* Can definitely ignore this. */ +#endif + 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: + /* These symbols aren't interesting; don't worry about them */ + + continue; + + default: + /* If we haven't found it yet, we've got problems */ + + if (IGNORE_SYMBOL (bufp->n_type)) + continue; + + fatal ("Bad symbol type 0x%x encountered in gdb scan", bufp->n_type); + } + } + + /* 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; + } + + /* sort the global & static symtab list so we can binary search them */ + qsort (global_psymbols.list, global_psymbols.next - global_psymbols.list, + sizeof (struct partial_symbol), compare_psymbols); + qsort (static_psymbols.list, static_psymbols.next - static_psymbols.list, + sizeof (struct partial_symbol), compare_psymbols); + free_bincl_list (); + discard_cleanups (old_chain); +#ifdef PROFILE_TYPES + { + int i, j; +#define __define_stab(SYM, NUMBER, NAME) {NUMBER, NAME}, + static struct xyzzy { + unsigned char symnum; + char *name; + } tmp_list[] = { +#include "stab.def" + {0x1, "eREF"}, + {0x2, "ABS"}, + {0x3, "eABS"}, + {0x4, "TEXT"}, + {0x5, "eTEXT"}, + {0x6, "DATA"}, + {0x7, "eDATA"}, + {0x8, "BSS"}, + {0x9, "eBSS"}, + {0x12, "COMM"}, + {0x13, "eCOMM"}, + {0x1f, "FN"}, + {0, "Unknown"}, +}; + for (i = 0; i < 256; i++) + { + for (j = 0; j < (sizeof (tmp_list) / sizeof (struct xyzzy)) - 1; j++) + if (tmp_list[j].symnum == i) + break; + printf ("Symbol \"%s\" (0x%x) occured %d times.\n", + tmp_list[j].name, i, profile_types[i]); + } + printf ("Auto vars (under LSYM): %d\n", autovars); + printf ("Global funs (under FUN): %d\n", global_funs); + } +#endif +} + +/* + * Allocate and partially fill a partial symtab. It will be + * completely filled at the end of the symbol list. + */ +static struct partial_symtab * +start_psymtab (filename, textlow, ldsymoff, global_syms, static_syms) + char *filename; + int 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->filename = + (char *) obstack_alloc (psymbol_obstack, + strlen (filename) + 1); + strcpy (result->filename, filename); + + result->textlow = textlow; + result->ldsymoff = ldsymoff; + + result->readin = 0; + + 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; +} + + +/* 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; + int capping_text; + struct partial_symtab **dependency_list; + int number_dependencies; + struct partial_symbol *capping_global, *capping_static; +{ + int i; + register struct partial_symbol *ps; + + 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->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 *)); + pst->number_of_dependencies = number_dependencies; + + 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->ldsymoff = + subpst->ldsymlen = + subpst->textlow = + subpst->texthigh = 0; + subpst->readin = 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->next = partial_symtab_list; + partial_symtab_list = subpst; + } + + for (ps = global_psymbols.list + pst->globals_offset; + ps < capping_global; ++ps) + ps->pst = pst; + for (ps = static_psymbols.list + pst->statics_offset; + ps < capping_static; ++ps) + ps->pst = pst; + + /* Put the psymtab on the psymtab list */ + pst->next = partial_symtab_list; + partial_symtab_list = pst; +} + + +/* Helper routines for psymtab_to_symtab. */ +static void scan_file_globals (); +static void read_ofile_symtab (); + +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) + { + printf_filtered (" and %s...", pst->dependencies[i]->filename); + 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, 0); + 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. Return + * the value of the symtab you create. Do not free the storage + * allocated to the psymtab; it may have pointers to it. + */ +struct symtab * +psymtab_to_symtab(pst) + struct partial_symtab *pst; +{ + int desc; + DECLARE_FILE_HEADERS; + char *stringtab; + struct partial_symtab **list_patch; + int stsize, val; + struct stat statbuf; + struct cleanup *old_chain; + extern void close (); + int i; + struct symtab *result; + char *name = symfile; /* Some of the macros require the */ + /* variable "name" to be defined in */ + /* the context in which they execute */ + /* (Yech!) */ + + if (!pst) + return 0; + + if (pst->readin) + { + fprintf (stderr, "Psymtab for %s already read in. Shouldn't happen.\n", + pst->filename); + return 0; + } + + if (!name) + error("No symbol file currently specified; use command symbol-file"); + + 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 */ + if (stat (name, &statbuf) < 0) + perror_with_name (name); + desc = open(name, O_RDONLY, 0); /* symbol_file_command + guarrantees that the symbol file name + will be absolute, so there is no + need for openp */ + + old_chain = make_cleanup (close, desc); + + if (desc < 0) + error("Symbol file not readable"); + + READ_FILE_HEADERS (desc, name); + +#if 0 + /* Read in the string table */ + lseek (desc, STRING_TABLE_OFFSET, L_SET); + READ_STRING_TABLE_SIZE (stsize); + 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) + error ("ridiculous string table size: %d bytes", stsize); + + /* Usually READ_STRING_TABLE_SIZE will have shifted the file pointer. + Occaisionally, it won't. */ + val = lseek (desc, STRING_TABLE_OFFSET, L_SET); + if (val < 0) + perror_with_name (name); + val = myread (desc, stringtab, stsize); + if (val < 0) + perror_with_name (name); +#endif /* 0 */ + stringtab = symfile_string_table; + stsize = symfile_string_table_size; + + 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"); + } + + /* Search through list for correct name. */ + for (result = symtab_list; result; result = result->next) + if (!strcmp (result->filename, pst->filename)) + return result; + + return 0; +} + +/* + * 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 (prev) = SYMBOL_VALUE (sym); + else + global_sym_chain[hash] + = (struct symbol *) SYMBOL_VALUE (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 (sym) = misc_function_vector[mf].address; + + if (prev) + sym = (struct symbol *) SYMBOL_VALUE (prev); + else + sym = global_sym_chain[hash]; + } + else + { + prev = sym; + sym = (struct symbol *) SYMBOL_VALUE (sym); + } + } + } +} + +/* + * 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 offset to be added to + * all values of symbols coming in and + * TEXT_SIZE is the size of the text segment read in. + * OFFSET is a flag which indicates that the value of all of the + * symbols should be offset by TEXT_OFFSET (for the purposes of + * incremental linking). + */ + +static void +read_ofile_symtab (desc, stringtab, stringtab_size, sym_offset, + sym_size, text_offset, text_size, offset) + int desc; + register char *stringtab; + int sym_offset; + int sym_size; + int text_offset; + int text_size; + int offset; +{ + register char *namestring; + register struct symbol *sym, *prev; + int hash; + struct cleanup *old_chain; + struct nlist *bufp; + unsigned char type; +#ifdef N_BINCL + subfile_stack = 0; +#endif + + 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 >= sizeof (struct nlist)) + { + lseek (desc, sym_offset - sizeof (struct nlist), L_INCR); + fill_symbuf (); + bufp = &symbuf[symbuf_idx++]; + + 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 ((unsigned char) bufp->n_type != N_SO) + fatal("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++]; + type = bufp->n_type; + + if (offset && + (type == N_TEXT || type == N_DATA || type == N_BSS)) + bufp->n_value += text_offset; + + 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) + process_one_symbol(type, bufp->n_desc, + bufp->n_value, 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 == N_TEXT +#ifdef N_NBTEXT + || type == N_NBTEXT +#endif + ) + /* 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. */ + &stringtab_global; /* For debugger; am I right? */ + } + 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; +} + +/* Put all appropriate global symbols in the symseg data + onto the hash chains so that their addresses will be stored + when seen later in loader global symbols. */ + +static void +hash_symsegs () +{ + /* Look at each symbol in each block in each symseg symtab. */ + struct symtab *s; + for (s = symseg_chain; s; s = s->next) + { + register int n; + for (n = BLOCKVECTOR_NBLOCKS (BLOCKVECTOR (s)) - 1; n >= 0; n--) + { + register struct block *b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), n); + register int i; + for (i = BLOCK_NSYMS (b) - 1; i >= 0; i--) + { + register struct symbol *sym = BLOCK_SYM (b, i); + + /* Put the symbol on a chain if its value is an address + that is figured out by the loader. */ + + if (SYMBOL_CLASS (sym) == LOC_EXTERNAL) + { + register int hash = hashname (SYMBOL_NAME (sym)); + SYMBOL_VALUE (sym) = (int) global_sym_chain[hash]; + global_sym_chain[hash] = sym; + SYMBOL_CLASS (sym) = LOC_STATIC; + } + } + } + } +} + +static void +process_one_symbol (type, desc, value, name) + int type, desc; + CORE_ADDR value; + char *name; +{ + 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 != N_SO) + { + /* Currently this ignores N_ENTRY on Gould machines, N_NSYM on machines + where that code is defined. */ + if (IGNORE_SYMBOL (type)) + return; + + 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. */ + + colon_pos = index (name, ':'); + if (!colon_pos++ + || (*colon_pos != 'f' && *colon_pos != 'F')) + { + define_symbol (value, name, desc); + 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, value); + } + /* 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 = value; + new->name = define_symbol (value, name, desc); + local_symbols = 0; + break; + + case N_LBRAC: + /* This "symbol" just indicates the start of an inner lexical + context within a function. */ + + 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 = value; + 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. */ + 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 native 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. */ +#if !defined (VARIABLES_INSIDE_BLOCK) +#define VARIABLES_INSIDE_BLOCK(desc) 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)) + 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)) + { + /* Muzzle a compiler bug that makes end < start. */ + if (new->start_addr > value) + new->start_addr = value; + /* Make a block for the local symbols within. */ + finish_block (0, &local_symbols, new->old_blocks, + new->start_addr + last_source_start_addr, + value + last_source_start_addr); + } + else + { + within_function = 0; + } + if (VARIABLES_INSIDE_BLOCK(desc)) + /* 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. */ +#ifdef PCC_SOL_BROKEN + /* pcc bug, occasionally puts out SO for SOL. */ + if (context_stack_depth > 0) + { + start_subfile (name); + break; + } +#endif + if (last_source_file) + end_symtab (value); + start_symtab (name, value); + 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); + break; + +#ifdef N_BINCL + case N_BINCL: + push_subfile (); + add_new_header_file (name, value); + start_subfile (name); + break; + + case N_EINCL: + start_subfile (pop_subfile ()); + break; + + case N_EXCL: + add_old_header_file (name, value); + break; +#endif /* have N_BINCL */ + + 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. */ + record_line (desc, value); + 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 pending *link = local_symbols; + 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 (sym) = (int) 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 (value, name, desc); + } +} + +/* This function was added for C++ functionality. I presume that it + condenses the bunches formed by reading in an additional .o file + (incremental linking). */ + +static void +condense_addl_misc_bunches () +{ + register int i, j; + register struct misc_bunch *bunch; +#ifdef NAMES_HAVE_UNDERSCORE + int offset = 1; +#else + int offset = 0; +#endif + + misc_function_vector + = (struct misc_function *) xrealloc (misc_function_vector, + (misc_count + misc_function_count) * sizeof (struct misc_function)); + + j = misc_function_count; + bunch = misc_bunch; + while (bunch) + { + for (i = 0; i < misc_bunch_index; i++) + { + misc_function_vector[j] = bunch->contents[i]; + misc_function_vector[j].name + = concat (misc_function_vector[j].name + + (misc_function_vector[j].name[0] == '_' ? offset : 0), + "", ""); + j++; + } + bunch = bunch->next; + misc_bunch_index = MISC_BUNCH_SIZE; + } + + misc_function_count += misc_count; + + /* Sort the misc functions by address. */ + + qsort (misc_function_vector, misc_function_count, + sizeof (struct misc_function), compare_misc_functions); +} + + +/* Read in another .o file and create a symtab entry for it.*/ + +static void +read_addl_syms (desc, stringtab, nlistlen, text_addr, text_size) + int desc; + register char *stringtab; + register int nlistlen; + unsigned text_addr; + int text_size; +{ + FILE *stream = fdopen (desc, "r"); + register char *namestring; + register struct symbol *sym, *prev; + int hash; + +#ifdef N_BINCL + subfile_stack = 0; +#endif + + last_source_file = 0; + bzero (global_sym_chain, sizeof global_sym_chain); + symtab_input_desc = desc; + stringtab_global = stringtab; + fill_symbuf (); + + for (symnum = 0; symnum < nlistlen; symnum++) + { + struct nlist *bufp; + unsigned char type; + + QUIT; /* allow this to be interruptable */ + if (symbuf_idx == symbuf_end) + fill_symbuf (); + bufp = &symbuf[symbuf_idx++]; + type = bufp->n_type & N_TYPE; + namestring = bufp->n_un.n_strx + stringtab; + + if( (type == N_TEXT) || (type == N_DATA) || (type == N_BSS) ) + { + /* Relocate this file's symbol table information + to the address it has been loaded into. */ + bufp->n_value += text_addr; + } + + type = bufp->n_type; + + if (type & N_STAB) + process_one_symbol (type, bufp->n_desc, + bufp->n_value, namestring); + /* A static text symbol whose name ends in ".o" + can only mean the start of another object file. + So end the symtab of the source file we have been processing. + This is how we avoid counting the libraries as part + or the last source file. + Also this way we find end of first object file (crt0). */ + else if ((type == N_TEXT +#ifdef N_NBTEXT + || type == N_NBTEXT +#endif + ) + && (!strcmp (namestring + strlen (namestring) - 2, ".o")) + || ! strncmp (namestring, "-l", 2)) + { + if (last_source_file) + end_symtab (bufp->n_value); + } + else if (type & N_EXT || type == N_TEXT +#ifdef N_NBTEXT + || type == N_NBTEXT +#endif + ) + { + int used_up = 0; + + /* Record the location of _etext. */ + if (type == (N_TEXT | N_EXT) + && !strcmp (namestring, "_etext")) + end_of_text_addr = bufp->n_value; + +#if 0 + /* 25 Sep 89: The following seems to be stolen from + read_ofile_symtab, and is wrong here (i.e. there was no + first pass for add-file symbols). */ + /* This shouldn't be necessary, as we now do all of this work + in scan_global syms and all misc functions should have been + recorded on the first pass. */ + /* Global symbol: see if we came across a dbx definition + 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. */ + if (type & N_EXT) + { + prev = 0; +#ifdef NAMES_HAVE_UNDERSCORE + hash = hashname (namestring + 1); +#else /* not NAMES_HAVE_UNDERSCORE */ + hash = hashname (namestring); +#endif /* not NAMES_HAVE_UNDERSCORE */ + for (sym = global_sym_chain[hash]; + sym;) + { + if ( +#ifdef NAMES_HAVE_UNDERSCORE + *namestring == '_' + && namestring[1] == SYMBOL_NAME (sym)[0] + && + !strcmp (namestring + 2, SYMBOL_NAME (sym) + 1) +#else /* NAMES_HAVE_UNDERSCORE */ + namestring[0] == SYMBOL_NAME (sym)[0] + && + !strcmp (namestring + 1, SYMBOL_NAME (sym) + 1) +#endif /* NAMES_HAVE_UNDERSCORE */ + ) + { + if (prev) + SYMBOL_VALUE (prev) = SYMBOL_VALUE (sym); + else + global_sym_chain[hash] + = (struct symbol *) SYMBOL_VALUE (sym); + if (SYMBOL_CLASS (sym) == LOC_BLOCK) + fix_common_block (sym, bufp->n_value); + else + SYMBOL_VALUE (sym) = bufp->n_value; + if (prev) + sym = (struct symbol *) SYMBOL_VALUE (prev); + else + sym = global_sym_chain[hash]; + + used_up = 1; + } + else + { + prev = sym; + sym = (struct symbol *) SYMBOL_VALUE (sym); + } + } + } + + /* Defined global or text symbol: record as a misc function + if it didn't give its address to a debugger symbol above. */ + if (type <= (N_TYPE | N_EXT) + && type != N_EXT + && ! used_up) + record_misc_function (namestring, bufp->n_value, + bufp->n_type); +#endif /* 0 */ + } + } + + if (last_source_file) + end_symtab (text_addr + text_size); + + fclose (stream); +} + +/* 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. */ + +void +add_file_command (arg_string) + char* arg_string; +{ + register int desc; + DECLARE_FILE_HEADERS; + struct nlist *nlist; + char *stringtab; + long buffer; + register int val; + extern void close (); + struct cleanup *old_chain; + struct symtab *symseg; + struct stat statbuf; + char *name; + unsigned text_addr; + + 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."); + + desc = open (name, O_RDONLY); + if (desc < 0) + perror_with_name (name); + + old_chain = make_cleanup (close, desc); + + READ_FILE_HEADERS (desc, name); + + if (NUMBER_OF_SYMBOLS == 0) + { + printf ("%s does not have a symbol-table.\n", name); + fflush (stdout); + return; + } + + printf ("Reading symbol data from %s...", name); + fflush (stdout); + + /* Now read the string table, all at once. */ + val = lseek (desc, STRING_TABLE_OFFSET, 0); + if (val < 0) + perror_with_name (name); + if (stat (name, &statbuf) < 0) + perror_with_name (name); + READ_STRING_TABLE_SIZE (buffer); + if (buffer >= 0 && buffer < statbuf.st_size) + { +#ifdef BROKEN_LARGE_ALLOCA + stringtab = (char *) xmalloc (buffer); + make_cleanup (free, stringtab); +#else + stringtab = (char *) alloca (buffer); +#endif + } + else + stringtab = NULL; + if (stringtab == NULL) + error ("ridiculous string table size: %d bytes", buffer); + + /* Usually READ_STRING_TABLE_SIZE will have shifted the file pointer. + Occaisionally, it won't. */ + val = lseek (desc, STRING_TABLE_OFFSET, 0); + if (val < 0) + perror_with_name (name); + val = myread (desc, stringtab, buffer); + if (val < 0) + perror_with_name (name); + + /* Symsegs are no longer supported by GDB. Setting symseg_chain to + 0 is easier than finding all the symseg code and eliminating it. */ + symseg_chain = 0; + + /* Position to read the symbol table. Do not read it all at once. */ + val = lseek (desc, SYMBOL_TABLE_OFFSET, 0); + if (val < 0) + perror_with_name (name); + + init_misc_functions (); + make_cleanup (discard_misc_bunches, 0); + init_header_files (); + make_cleanup (free_header_files, 0); + free_pendings = 0; + pending_blocks = 0; + file_symbols = 0; + global_symbols = 0; + make_cleanup (really_free_pendings, 0); + + read_addl_syms (desc, stringtab, NUMBER_OF_SYMBOLS, text_addr, + SIZE_OF_TEXT_SEGMENT); + + + /* Sort symbols alphabetically within each block. */ + + sort_syms (); + + /* Go over the misc functions and install them in vector. */ + + condense_addl_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); + + /* Free the symtabs made by read_symsegs, but not their contents, + which have been copied into symtabs on symtab_list. */ + while (symseg_chain) + { + register struct symtab *s = symseg_chain->next; + free (symseg_chain); + symseg_chain = s; + } + + printf ("done.\n"); + fflush (stdout); +} + +/* 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); + } +} + + + +static struct symbol * +define_symbol (value, string, desc) + int value; + char *string; + int desc; +{ + register struct symbol *sym + = (struct symbol *) obstack_alloc (symbol_obstack, sizeof (struct symbol)); + char *p = (char *) index (string, ':'); + int deftype; + 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; + + 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. */ + if ((*p >= '0' && *p <= '9') || *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 *value; + + SYMBOL_TYPE (sym) = builtin_type_double; + value = (char *) obstack_alloc (symbol_obstack, sizeof (double)); + bcopy (&d, value, sizeof (double)); + SYMBOL_VALUE_BYTES (sym) = value; + 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 = 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 '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 (sym) = (int) 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) = value; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, &local_symbols); + break; + + case 'p': + SYMBOL_CLASS (sym) = LOC_ARG; + SYMBOL_VALUE (sym) = value; + 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 (value); + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, &local_symbols); + break; + + case 'r': +/* XXX */ +#ifdef sparc +{ + struct symbol *s0; + + /* + * If we see a parm decl immediately followed by a reg decl of + * the same name (and in the same block), we change it to a single + * instance of a reg parm. Sun's cc will generate these. + */ + if (local_symbols && + (s0 = local_symbols->symbol[local_symbols->nsyms - 1]) && + SYMBOL_CLASS(s0) == LOC_ARG && + strcmp(SYMBOL_NAME(s0), SYMBOL_NAME(sym)) == 0) { + SYMBOL_CLASS (s0) = LOC_REGPARM; + SYMBOL_VALUE (s0) = STAB_REG_TO_REGNUM (value); + SYMBOL_NAMESPACE (s0) = VAR_NAMESPACE; + return s0; + } +} +#endif + SYMBOL_CLASS (sym) = LOC_REGISTER; + SYMBOL_VALUE (sym) = STAB_REG_TO_REGNUM (value); + 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 (sym) = value; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, &file_symbols); + break; + + case 't': + SYMBOL_CLASS (sym) = LOC_TYPEDEF; + SYMBOL_VALUE (sym) = value; + 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)); i > 0; i--) + if (TYPE_FIELD_NAME (SYMBOL_TYPE (sym), i - 1) == 0) + TYPE_FIELD_NAME (SYMBOL_TYPE (sym), i - 1) = + TYPE_NAME (TYPE_BASECLASS (SYMBOL_TYPE (sym), i)); + } + + add_symbol_to_list (sym, &file_symbols); + break; + + case 'T': + SYMBOL_CLASS (sym) = LOC_TYPEDEF; + SYMBOL_VALUE (sym) = value; + 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); + break; + + case 'V': + /* Static symbol of local scope */ + SYMBOL_CLASS (sym) = LOC_STATIC; + SYMBOL_VALUE (sym) = value; + 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) = value; + 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) = value; + 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, *ntype; + struct symbol *sym; + + for (type = undef_types; type < undef_types + undef_types_length; type++) + { + struct type *ntype = 0; + /* 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; +} + + + +/* 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; + register int n; + struct type *type1; + int typenums[2]; + int xtypenums[2]; + char *tmpc; + + /* 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: + error ("Bad type cross reference at symnum: %d.", symnum); + } + + to = type_name = (char *) + obstack_alloc (symbol_obstack, + (strlen (prefix) + + ((char *) index (*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 *) index (*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); + if (TYPE_POINTER_TYPE (type1)) + { + type = TYPE_POINTER_TYPE (type1); + if (typenums[0] != -1) + *dbx_lookup_type (typenums) = type; + } + else + { + type = dbx_alloc_type (typenums); + smash_to_pointer_type (type, type1); + } + break; + + case '@': + { + struct type *domain = read_type (pp); + char c; + struct type *memtype; + + if (*(*pp)++ != ',') + error ("invalid member type data format, at symtab pos %d.", + symnum); + + memtype = read_type (pp); + type = dbx_alloc_type (typenums); + smash_to_member_type (type, domain, memtype); + } + break; + + case '#': + { + struct type *domain = read_type (pp); + char c; + 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); + if (TYPE_REFERENCE_TYPE (type1)) + { + type = TYPE_REFERENCE_TYPE (type1); + if (typenums[0] != -1) + *dbx_lookup_type (typenums) = type; + } + else + { + type = dbx_alloc_type (typenums); + smash_to_reference_type (type, type1); + } + break; + + case 'f': + type1 = read_type (pp); + if (TYPE_FUNCTION_TYPE (type1)) + { + type = TYPE_FUNCTION_TYPE (type1); + if (typenums[0] != -1) + *dbx_lookup_type (typenums) = type; + } + else + { + type = dbx_alloc_type (typenums); + smash_to_function_type (type, type1); + } + 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 = read_struct_type (pp, type); + break; + + case 'u': + type = dbx_alloc_type (typenums); + type = read_struct_type (pp, type); + TYPE_CODE (type) = TYPE_CODE_UNION; + break; + + case 'a': + if (*(*pp)++ != 'r') + error ("Invalid symbol data: unrecognized type-code `a%c' %s %d.", + (*pp)[-1], "at symtab position", symnum); + + type = dbx_alloc_type (typenums); + type = read_array_type (pp, type); + break; + + default: + error ("Invalid symbol data: unrecognized type-code `%c' at symtab pos %d.", + (*pp)[-1], symnum); + } + + 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; +} + +/* 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 (pp, type) + char **pp; + register struct type *type; +{ + struct nextfield + { + struct nextfield *next; + int visibility; + struct field field; + }; + + struct next_fnfield + { + struct next_fnfield *next; + int visibility; + 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; + int totalsize; + char *name; + register char *p; + int nfields = 0; + register int n; + + register struct next_fnfieldlist *mainlist = 0; + int nfn_fields = 0; + int read_possible_virtual_info = 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_vec; + 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, ','); + baseclass_vec = (struct type **) + obstack_alloc (symbol_obstack, + (n_baseclasses) * sizeof (struct type **)) - 1; + + for (i = 1; 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: + error ("Invalid symbol data: bad visibility format at symtab pos %d", + symnum); + } + + switch (*(*pp)++) + { + case '0': + via_public = 0; + break; + case '2': + via_public = 1; + break; + default: + error ("Invalid symbol data: bad visibility format at symtab pos %d.", + symnum); + } + + /* 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 (offset != 0) + { + static int error_printed = 0; + + if (!error_printed) + { + fprintf (stderr, +"\nWarning: GDB has limited understanding of multiple inheritance..."); + error_printed = 1; + } + offset = 0; + } + + baseclass_vec[i] = lookup_basetype_type (baseclass, offset, via_virtual, via_public); + + /* Since lookup_basetype_type can copy the type, + it might copy a stub type (complete with stub flag). + If so, we need to add it to the list of undefined types + to clean up later. Even if lookup_basetype_type + didn't copy the type, adding it to the undefined list + will not do any harm. */ + if (TYPE_FLAGS(baseclass_vec[i]) & TYPE_FLAG_STUB) + add_undefined_type (baseclass_vec[i]); + + /* Make this baseclass visible for structure-printing purposes. */ + new = (struct nextfield *) alloca (sizeof (struct nextfield)); + new->next = list; + list = new; + list->field.type = baseclass_vec[i]; + list->field.name = TYPE_NAME (baseclass_vec[i]); + list->field.bitpos = offset; + list->field.bitsize = 0; /* this should be an unpacked field! */ + nfields++; + } + TYPE_N_BASECLASSES (type) = n_baseclasses; + TYPE_BASECLASSES (type) = baseclass_vec; + } + + /* 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 '+' (public visibility), + '0' (protected visibility), and '-' (private visibility). */ + + /* We better set p right now, in case there are no fields at all... */ + p = *pp; + + while (**pp != ';') + { + int visibility; + + /* 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; + 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': + visibility = 0; + *pp += 1; + break; + + case '1': + visibility = 1; + *pp += 1; + break; + + case '2': + visibility = 2; + *pp += 1; + break; + } + } + /* else normal dbx-style format. */ + + list->field.type = read_type (pp); + if (**pp == ':') + { + 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 != ',') + error ("Invalid symbol data: bad structure-type format at symtab pos %d.", + symnum); + (*pp)++; /* Skip the comma. */ + list->field.bitpos = read_number (pp, ','); + list->field.bitsize = read_number (pp, ';'); + +#if 0 + /* 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) + { + /* Have we given the warning yet? */ + static int warning_given = 0; + + /* Only give the warning once, no matter how many class + variables there are. */ + if (!warning_given) + { + warning_given = 1; + fprintf_filtered (stderr, "\n\ +Warning: DBX-style class variable debugging information encountered.\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.\n\ +"); + } + + /* 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++; + } + } + + /* 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. */ + + p = *pp; + + /* chill the list of fields: the last entry (at the head) + is a partially constructed entry which we now scrub. */ + list = list->next; + + /* For each list of method lists... */ + do + { + int i; + struct next_fnfield *sublist = 0; + struct fn_field *fn_fields = 0; + int length = 0; + struct next_fnfieldlist *new_mainlist = + (struct next_fnfieldlist *)alloca (sizeof (struct next_fnfieldlist)); + + /* read in the name. */ + while (*p != ':') p++; + if ((*pp)[0] == 'o' && (*pp)[1] == 'p' && (*pp)[2] == '$') + { + static char opname[] = "operator"; + char *o = opname + strlen(opname); + + /* Skip past '::'. */ + p += 2; + while (*p != '.') + *o++ = *p++; + new_mainlist->fn_fieldlist.name = savestring (opname, o - opname); + /* Skip past '.' */ + *pp = p + 1; + } + else + { + i = 0; + new_mainlist->fn_fieldlist.name = savestring (*pp, p - *pp); + /* Skip past '::'. */ + *pp = p + 2; + } + + 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 != ':') + error ("invalid symtab info for method at symbol number %d.", + symnum); + *pp += 1; + new_sublist->fn_field.args = + TYPE_ARG_TYPES (new_sublist->fn_field.type); + p = *pp; + while (*p != ';') p++; + new_sublist->fn_field.physname = savestring (*pp, p - *pp); + *pp = p + 1; + new_sublist->visibility = *(*pp)++ - '0'; + if (**pp == '\\') *pp = next_symbol_text (); + + switch (*(*pp)++) + { + case '*': + /* virtual member function, followed by index. */ + new_sublist->fn_field.voffset = read_number (pp, ';') + 1; + break; + case '?': + /* static member function. */ + new_sublist->fn_field.voffset = 1; + break; + default: + /* **pp == '.'. */ + /* normal member function. */ + new_sublist->fn_field.voffset = 0; + break; + } + + new_sublist->next = sublist; + sublist = new_sublist; + length++; + } + while (**pp != ';'); + + *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) = + (int *) obstack_alloc (symbol_obstack, + sizeof (int) * (1 + (length >> 5))); + + TYPE_FN_PROTECTED_BITS (new_mainlist->fn_fieldlist) = + (int *) obstack_alloc (symbol_obstack, + sizeof (int) * (1 + (length >> 5))); + + for (i = length; 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++; + } + while (**pp != ';'); + } + + *pp += 1; + + /* 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); + TYPE_FIELD_PRIVATE_BITS (type) = + (int *) obstack_alloc (symbol_obstack, + sizeof (int) * (1 + (nfields >> 5))); + TYPE_FIELD_PROTECTED_BITS (type) = + (int *) obstack_alloc (symbol_obstack, + sizeof (int) * (1 + (nfields >> 5))); + + TYPE_NFN_FIELDS (type) = nfn_fields; + TYPE_NFN_FIELDS_TOTAL (type) = nfn_fields; + + { + int i; + for (i = 1; i <= TYPE_N_BASECLASSES (type); ++i) + TYPE_NFN_FIELDS_TOTAL (type) += + TYPE_NFN_FIELDS_TOTAL (TYPE_BASECLASS (type, i)); + } + + TYPE_FN_FIELDLISTS (type) = + (struct fn_fieldlist *) obstack_alloc (symbol_obstack, + sizeof (struct fn_fieldlist) * nfn_fields); + + /* Copy the saved-up fields into the field vector. */ + + for (n = nfields; list; list = list->next) + { + 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); + } + + 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 != ';') p++; + TYPE_VPTR_BASETYPE (type) = t; + if (type == t) + { + if (TYPE_FIELD_NAME (t, 0) == 0) + TYPE_VPTR_FIELDNO (type) = i = 0; + else for (i = TYPE_NFIELDS (t) - 1; i >= 0; --i) + if (! strncmp (TYPE_FIELD_NAME (t, i), *pp, + strlen (TYPE_FIELD_NAME (t, i)))) + { + TYPE_VPTR_FIELDNO (type) = i; + break; + } + if (i < 0) + error ("virtual function table field not found"); + } + else + TYPE_VPTR_FIELDNO (type) = TYPE_VPTR_FIELDNO (TYPE_BASECLASS (type, 1)); + *pp = p + 1; + } + else + { + TYPE_VPTR_BASETYPE (type) = 0; + TYPE_VPTR_FIELDNO (type) = -1; + } + } + else + { + TYPE_VPTR_BASETYPE (type) = 0; + TYPE_VPTR_FIELDNO (type) = -1; + } + + return type; +} + +/* Read a definition of an array type, + and create and return a suitable type object. + Also creates a range type which represents the bounds of that + array. */ +static struct type * +read_array_type (pp, type) + register char **pp; + register struct type *type; +{ + struct type *index_type, *element_type, *range_type; + int lower, upper; + int adjustable = 0; + + /* Format of an array type: + "ar<index type>;lower;upper;<array_contents_type>". Put code in + to handle this. + + Fortran adjustable arrays use Adigits or Tdigits for lower or upper; + for these, produce a type like float[][]. */ + + index_type = read_type (pp); + if (*(*pp)++ != ';') + error ("Invalid symbol data; improper format of array type decl."); + + 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++) + { + 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; +} + +#define MAX_OF_TYPE(t) ((1 << (sizeof (t) - 1)) - 1) +#define MIN_OF_TYPE(t) (-(1 << (sizeof (t) - 1))) + +static struct type * +read_range_type (pp, typenums) + char **pp; + int typenums[2]; +{ + char *errp = *pp; + int rangenums[2]; + int n2, n3; + 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. */ + n2 = read_number (pp, ';'); + n3 = read_number (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 == (1 << (8 * sizeof (int))) - 1) + return builtin_type_unsigned_int; + if (n3 == (1 << (8 * sizeof (short))) - 1) + return builtin_type_unsigned_short; + if (n3 == (1 << (8 * sizeof (char))) - 1) + 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) + error ("Type defined as subrange of itself."); + + 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 + error ("Ranged type doesn't fit within known sizes."); + + 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. It is terminated with + a ':', FYI. Return the list of types read in. */ +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 != ',') + error ("Invalid argument list: no ',', at symtab pos %d", symnum); + *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; +} + +/* This function is really horrible, but to avoid it, there would need + to be more filling in of forward references. THIS SHOULD BE MOVED OUT + OF COFFREAD.C AND DBXREAD.C TO SOME PLACE WHERE IT CAN BE SHARED */ +int +fill_in_vptr_fieldno (type) + struct type *type; +{ + if (TYPE_VPTR_FIELDNO (type) < 0) + TYPE_VPTR_FIELDNO (type) = + fill_in_vptr_fieldno (TYPE_BASECLASS (type, 1)); + return TYPE_VPTR_FIELDNO (type); +} + +/* Copy a pending list, used to record the contents of a common + block for later fixup. BUG FIX by rde@topexpress.co.uk */ +static struct pending * +copy_pending (beg, begi, end) + struct pending *beg, *end; + int begi; +{ + struct pending *new = 0; + struct pending *next; + + /* rde note: `begi' is an offset in block `end', NOT `beg' */ + for (next = beg; next != 0; next = next->next) + { + register int j; + for (j = next == end ? begi : 0; j < next->nsyms; j++) + add_symbol_to_list (next->symbol[j], &new); + + if (next == end) + break; + } + 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, value) + struct symbol *sym; + int value; +{ + 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 (next->symbol[j]) += value; + } +} + +void +_initialize_dbxread () +{ + symfile = 0; + header_files = (struct header_file *) 0; + this_object_header_files = (int *) 0; + + undef_types_allocated = 20; + undef_types_length = 0; + undef_types = (struct type **) xmalloc (undef_types_allocated * + sizeof (struct type *)); + + add_com ("symbol-file", class_files, symbol_file_command, + "Load symbol table (in dbx format) from executable file FILE."); + + add_com ("add-file", class_files, add_file_command, + "Load the symbols from FILE, assuming its code is at TEXT_START.") ; +} + +#endif /* READ_DBX_FORMAT */ diff --git a/gnu/usr.bin/gdb/defs.h b/gnu/usr.bin/gdb/defs.h new file mode 100644 index 0000000..de744fc --- /dev/null +++ b/gnu/usr.bin/gdb/defs.h @@ -0,0 +1,122 @@ +/*- + * This code is derived from software copyrighted by the Free Software + * Foundation. + * + * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. + * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory. + * + * @(#)defs.h 6.3 (Berkeley) 5/8/91 + */ + +/* Basic definitions 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. */ + +#define CORE_ADDR unsigned int + +#define min(a, b) ((a) < (b) ? (a) : (b)) +#define max(a, b) ((a) > (b) ? (a) : (b)) + +extern char *savestring (); +extern char *concat (); +extern char *xmalloc (), *xrealloc (); +extern int parse_escape (); +extern char *reg_names[]; + +/* Various possibilities for alloca. */ +#ifdef sparc +#include <alloca.h> +#else +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else +extern char *alloca (); +#endif +#endif + +extern int quit_flag; + +extern int immediate_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 +{ + 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; +}; + +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 void reinitialize_more_filter (); +extern void fputs_filtered (); +extern void fprintf_filtered (); +extern void printf_filtered (); +extern void print_spaces_filtered (); +extern char *tilde_expand (); + +/* Structure for saved commands lines + (for breakpoints, defined commands, etc). */ + +struct command_line +{ + struct command_line *next; + char *line; + int type; /* statement type */ +#define CL_END 0 +#define CL_NORMAL 1 +#define CL_WHILE 2 +#define CL_IF 3 +#define CL_EXITLOOP 4 +#define CL_NOP 5 + struct command_line *body; /* body of loop for while, body of if */ + struct command_line *elsebody; /* body of else part of if */ +}; + +extern struct command_line *read_command_lines (); +extern void do_command_lines(); + +/* String containing the current directory (what getwd would return). */ + +char *current_directory; + diff --git a/gnu/usr.bin/gdb/environ.c b/gnu/usr.bin/gdb/environ.c new file mode 100644 index 0000000..0220166 --- /dev/null +++ b/gnu/usr.bin/gdb/environ.c @@ -0,0 +1,185 @@ +/*- + * This code is derived from software copyrighted by the Free Software + * Foundation. + * + * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. + * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory. + */ + +#ifndef lint +static char sccsid[] = "@(#)environ.c 6.3 (Berkeley) 5/8/91"; +#endif /* not lint */ + +/* 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" + +/* 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++); + + if (e->allocated < i) + { + e->allocated = max (i, e->allocated + 10); + e->vector = (char **) xrealloc (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]) + 1; + register char *new = (char *) xmalloc (len); + bcopy (e->vector[i], new, len); + 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 (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; + 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/gnu/usr.bin/gdb/environ.h b/gnu/usr.bin/gdb/environ.h new file mode 100644 index 0000000..13f31f4 --- /dev/null +++ b/gnu/usr.bin/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/gnu/usr.bin/gdb/eval.c b/gnu/usr.bin/gdb/eval.c new file mode 100644 index 0000000..60779e6 --- /dev/null +++ b/gnu/usr.bin/gdb/eval.c @@ -0,0 +1,1065 @@ +/*- + * This code is derived from software copyrighted by the Free Software + * Foundation. + * + * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. + * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory. + */ + +#ifndef lint +static char sccsid[] = "@(#)eval.c 6.3 (Berkeley) 5/8/91"; +#endif /* not lint */ + +/* 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" + + +/* 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 = 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 (); + +/* return true if 'var' has an address in inferior's memory. */ +static int +value_has_lval(var) + register struct symbol *var; +{ + switch (SYMBOL_CLASS(var)) + { + case LOC_STATIC: + case LOC_LABEL: + case LOC_ARG: + case LOC_REF_ARG: + case LOC_LOCAL: + case LOC_BLOCK: + return (1); + } + return (0); +} + +/* 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 (0, 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 (0, 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; + case LOC_REGISTER: + case LOC_REGPARM: + lv = lval_register; + default: + lv = lval_memory; + } + + 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 (0, exp, pos, noside); + if (value_zerop (arg1)) + { + evaluate_subexp (0, exp, pos, EVAL_SKIP); + return evaluate_subexp (0, exp, pos, noside); + } + else + { + arg2 = evaluate_subexp (0, exp, pos, noside); + evaluate_subexp (0, 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; + int tem2; + + 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 (0, 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 (0, 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 (0, 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; + + argvec[1] = arg2; + argvec[0] = + value_struct_elt (arg2, argvec+1, &exp->elts[pc2 + 1].string, + &static_memfuncp, + op == STRUCTOP_STRUCT + ? "structure" : "structure pointer"); + 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 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)); + + /* Try to convert "foo.bar" into "(&foo)->bar" so we won't copy + * the entire contents of a large struct just to extract one + * value from it. */ + if (noside == EVAL_NORMAL && exp->elts[*pos].opcode == OP_VAR_VALUE + && value_has_lval(exp->elts[*pos + 1].symbol)) + arg1 = evaluate_subexp_for_address(exp, pos, noside); + else + arg1 = evaluate_subexp (0, exp, pos, noside); + + if (noside == EVAL_SKIP) + goto nosideret; + if (noside == EVAL_AVOID_SIDE_EFFECTS) + { + register struct type *type = VALUE_TYPE (arg1); + if (TYPE_CODE (type) == TYPE_CODE_PTR) + type = TYPE_TARGET_TYPE (type); + return value_zero (lookup_struct_elt_type (type, + &exp->elts[pc + 1].string), + lval_memory); + } + else + return value_struct_elt (arg1, 0, &exp->elts[pc + 1].string, 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 (0, 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 + return value_struct_elt (arg1, 0, &exp->elts[pc + 1].string, 0, + "structure pointer"); + + case STRUCTOP_MEMBER: + arg1 = evaluate_subexp_for_address (exp, pos, noside); + arg2 = evaluate_subexp (0, 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 (0, exp, pos, noside); + arg2 = evaluate_subexp (0, 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 (0, 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 (0, 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 (0, exp, pos, noside); + arg2 = evaluate_subexp (0, 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 (0, exp, pos, noside); + if (noside == EVAL_SKIP) + { + arg2 = evaluate_subexp (0, exp, pos, noside); + goto nosideret; + } + + oldpos = *pos; + arg2 = evaluate_subexp (0, exp, pos, EVAL_AVOID_SIDE_EFFECTS); + *pos = oldpos; + + if (binop_user_defined_p (op, arg1, arg2)) + { + arg2 = evaluate_subexp (0, exp, pos, noside); + return value_x_binop (arg1, arg2, op, 0); + } + else + { + tem = value_zerop (arg1); + arg2 = evaluate_subexp (0, exp, pos, + (tem ? EVAL_SKIP : noside)); + return value_from_long (builtin_type_int, + (LONGEST) (!tem && !value_zerop (arg2))); + } + + case BINOP_OR: + arg1 = evaluate_subexp (0, exp, pos, noside); + if (noside == EVAL_SKIP) + { + arg2 = evaluate_subexp (0, exp, pos, noside); + goto nosideret; + } + + oldpos = *pos; + arg2 = evaluate_subexp (0, exp, pos, EVAL_AVOID_SIDE_EFFECTS); + *pos = oldpos; + + if (binop_user_defined_p (op, arg1, arg2)) + { + arg2 = evaluate_subexp (0, exp, pos, noside); + return value_x_binop (arg1, arg2, op, 0); + } + else + { + tem = value_zerop (arg1); + arg2 = evaluate_subexp (0, exp, pos, + (!tem ? EVAL_SKIP : noside)); + return value_from_long (builtin_type_int, + (LONGEST) (!tem || !value_zerop (arg2))); + } + + case BINOP_EQUAL: + arg1 = evaluate_subexp (0, 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 (0, 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 (0, 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 (0, 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 (0, 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 (0, 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 (0, exp, pos, noside); + arg2 = evaluate_subexp (0, 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 (0, exp, pos, noside); + return evaluate_subexp (0, exp, pos, noside); + + case UNOP_NEG: + arg1 = evaluate_subexp (0, 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 (0, 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 (0, 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 tem = strlen (name); + (*pos) += 2 + (tem + 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 tem = strlen (name); + struct type *domain = exp->elts[pc+2].type; + (*pos) += 2 + (tem + 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 (0, 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 (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 (0, exp, pos, noside); + + case UNOP_MEMVAL: + (*pos) += 3; + return value_cast (lookup_pointer_type (exp->elts[pc + 1].type), + evaluate_subexp (0, 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 (0, 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 (0, 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); + } + } + + return evaluate_subexp (0, 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 (0, 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 (0, exp, pos, EVAL_AVOID_SIDE_EFFECTS); + return value_from_long (builtin_type_int, + (LONGEST) TYPE_LENGTH (VALUE_TYPE (val))); + } +} diff --git a/gnu/usr.bin/gdb/expprint.c b/gnu/usr.bin/gdb/expprint.c new file mode 100644 index 0000000..8ac95e9 --- /dev/null +++ b/gnu/usr.bin/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 <stdio.h> +#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 int tem; + register int pc; + int 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/gnu/usr.bin/gdb/expread.y b/gnu/usr.bin/gdb/expread.y new file mode 100644 index 0000000..96a12c4 --- /dev/null +++ b/gnu/usr.bin/gdb/expread.y @@ -0,0 +1,1782 @@ +/*- + * This code is derived from software copyrighted by the Free Software + * Foundation. + * + * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. + * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory. + */ + +/* Parse C expressions 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. */ + +/* Parse a C expression from text in a string, + and return the result as a struct expression pointer. + That structure contains arithmetic operations in reverse polish, + with constants represented by operations that are followed by special data. + See expression.h for the details of the format. + What is important here is that it can be built up sequentially + during the process of parsing; the lower levels of the tree always + come first in the result. */ + +%{ +#ifndef lint +static char sccsid[] = "@(#)expread.y 6.3 (Berkeley) 5/8/91"; +#endif /* not lint */ + +#include <stdio.h> +#include "defs.h" +#include "param.h" +#include "symtab.h" +#include "frame.h" +#include "expression.h" + +#include <a.out.h> + +static struct expression *expout; +static int expout_size; +static int expout_ptr; + +static int yylex (); +static void yyerror (); +static void write_exp_elt (); +static void write_exp_elt_opcode (); +static void write_exp_elt_sym (); +static void write_exp_elt_longcst (); +static void write_exp_elt_dblcst (); +static void write_exp_elt_type (); +static void write_exp_elt_intern (); +static void write_exp_string (); +static void start_arglist (); +static int end_arglist (); +static void free_funcalls (); +static char *copy_name (); + +/* If this is nonzero, this block is used as the lexical context + for symbol names. */ + +static struct block *expression_context_block; + +/* The innermost context required by the stack and register variables + we've encountered so far. */ +struct block *innermost_block; + +/* The block in which the most recently discovered symbol was found. */ +struct block *block_found; + +/* Number of arguments seen so far in innermost function call. */ +static int arglist_len; + +/* Data structure for saving values of arglist_len + for function calls whose arguments contain other function calls. */ + +struct funcall + { + struct funcall *next; + int arglist_len; + }; + +struct funcall *funcall_chain; + +/* This kind of datum is used to represent the name + of a symbol token. */ + +struct stoken + { + char *ptr; + int length; + }; + +/* For parsing of complicated types. + An array should be preceded in the list by the size of the array. */ +enum type_pieces + {tp_end = -1, tp_pointer, tp_reference, tp_array, tp_function}; +static enum type_pieces *type_stack; +static int type_stack_depth, type_stack_size; + +static void push_type (); +static enum type_pieces pop_type (); + +/* Allow debugging of parsing. */ +#define YYDEBUG 1 +%} + +/* Although the yacc "value" of an expression is not used, + since the result is stored in the structure being created, + other node types do have values. */ + +%union + { + LONGEST lval; + unsigned LONGEST ulval; + double dval; + struct symbol *sym; + struct type *tval; + struct stoken sval; + int voidval; + struct block *bval; + enum exp_opcode opcode; + struct internalvar *ivar; + + struct type **tvec; + int *ivec; + } + +%type <voidval> exp exp1 start variable +%type <tval> type typebase +%type <tvec> nonempty_typelist +%type <bval> block + +/* Fancy type parsing. */ +%type <voidval> func_mod direct_abs_decl abs_decl +%type <tval> ptype +%type <lval> array_mod + +%token <lval> INT CHAR +%token <ulval> UINT +%token <dval> FLOAT + +/* Both NAME and TYPENAME tokens represent symbols in the input, + and both convey their data as strings. + But a TYPENAME is a string that happens to be defined as a typedef + or builtin type name (such as int or char) + and a NAME is any other symbol. + + Contexts where this distinction is not important can use the + nonterminal "name", which matches either NAME or TYPENAME. */ + +%token <sval> NAME TYPENAME BLOCKNAME STRING +%type <sval> name name_not_typename typename + +%token STRUCT UNION ENUM SIZEOF UNSIGNED COLONCOLON + +/* Special type cases, put in to allow the parser to distinguish different + legal basetypes. */ +%token SIGNED LONG SHORT INT_KEYWORD + +%token <lval> LAST REGNAME + +%token <ivar> VARIABLE + +%token <opcode> ASSIGN_MODIFY + +/* C++ */ +%token THIS + +%left ',' +%left ABOVE_COMMA +%right '=' ASSIGN_MODIFY +%right '?' +%left OR +%left AND +%left '|' +%left '^' +%left '&' +%left EQUAL NOTEQUAL +%left '<' '>' LEQ GEQ +%left LSH RSH +%left '@' +%left '+' '-' +%left '*' '/' '%' +%right UNARY INCREMENT DECREMENT +%right ARROW '.' '[' '(' +%left COLONCOLON + +%% + +start : exp1 + ; + +/* Expressions, including the comma operator. */ +exp1 : exp + | exp1 ',' exp + { write_exp_elt_opcode (BINOP_COMMA); } + ; + +/* Expressions, not including the comma operator. */ +exp : '*' exp %prec UNARY + { write_exp_elt_opcode (UNOP_IND); } + +exp : '&' exp %prec UNARY + { write_exp_elt_opcode (UNOP_ADDR); } + +exp : '-' exp %prec UNARY + { write_exp_elt_opcode (UNOP_NEG); } + ; + +exp : '!' exp %prec UNARY + { write_exp_elt_opcode (UNOP_ZEROP); } + ; + +exp : '~' exp %prec UNARY + { write_exp_elt_opcode (UNOP_LOGNOT); } + ; + +exp : INCREMENT exp %prec UNARY + { write_exp_elt_opcode (UNOP_PREINCREMENT); } + ; + +exp : DECREMENT exp %prec UNARY + { write_exp_elt_opcode (UNOP_PREDECREMENT); } + ; + +exp : exp INCREMENT %prec UNARY + { write_exp_elt_opcode (UNOP_POSTINCREMENT); } + ; + +exp : exp DECREMENT %prec UNARY + { write_exp_elt_opcode (UNOP_POSTDECREMENT); } + ; + +exp : SIZEOF exp %prec UNARY + { write_exp_elt_opcode (UNOP_SIZEOF); } + ; + +exp : exp ARROW name + { write_exp_elt_opcode (STRUCTOP_PTR); + write_exp_string ($3); + write_exp_elt_opcode (STRUCTOP_PTR); } + ; + +exp : exp ARROW '*' exp + { write_exp_elt_opcode (STRUCTOP_MPTR); } + ; + +exp : exp '.' name + { write_exp_elt_opcode (STRUCTOP_STRUCT); + write_exp_string ($3); + write_exp_elt_opcode (STRUCTOP_STRUCT); } + ; + +exp : exp '.' '*' exp + { write_exp_elt_opcode (STRUCTOP_MEMBER); } + ; + +exp : exp '[' exp1 ']' + { write_exp_elt_opcode (BINOP_SUBSCRIPT); } + ; + +exp : exp '(' + /* This is to save the value of arglist_len + being accumulated by an outer function call. */ + { start_arglist (); } + arglist ')' %prec ARROW + { write_exp_elt_opcode (OP_FUNCALL); + write_exp_elt_longcst ((LONGEST) end_arglist ()); + write_exp_elt_opcode (OP_FUNCALL); } + ; + +arglist : + ; + +arglist : exp + { arglist_len = 1; } + ; + +arglist : arglist ',' exp %prec ABOVE_COMMA + { arglist_len++; } + ; + +exp : '{' type '}' exp %prec UNARY + { write_exp_elt_opcode (UNOP_MEMVAL); + write_exp_elt_type ($2); + write_exp_elt_opcode (UNOP_MEMVAL); } + ; + +exp : '(' type ')' exp %prec UNARY + { write_exp_elt_opcode (UNOP_CAST); + write_exp_elt_type ($2); + write_exp_elt_opcode (UNOP_CAST); } + ; + +exp : '(' exp1 ')' + { } + ; + +/* Binary operators in order of decreasing precedence. */ + +exp : exp '@' exp + { write_exp_elt_opcode (BINOP_REPEAT); } + ; + +exp : exp '*' exp + { write_exp_elt_opcode (BINOP_MUL); } + ; + +exp : exp '/' exp + { write_exp_elt_opcode (BINOP_DIV); } + ; + +exp : exp '%' exp + { write_exp_elt_opcode (BINOP_REM); } + ; + +exp : exp '+' exp + { write_exp_elt_opcode (BINOP_ADD); } + ; + +exp : exp '-' exp + { write_exp_elt_opcode (BINOP_SUB); } + ; + +exp : exp LSH exp + { write_exp_elt_opcode (BINOP_LSH); } + ; + +exp : exp RSH exp + { write_exp_elt_opcode (BINOP_RSH); } + ; + +exp : exp EQUAL exp + { write_exp_elt_opcode (BINOP_EQUAL); } + ; + +exp : exp NOTEQUAL exp + { write_exp_elt_opcode (BINOP_NOTEQUAL); } + ; + +exp : exp LEQ exp + { write_exp_elt_opcode (BINOP_LEQ); } + ; + +exp : exp GEQ exp + { write_exp_elt_opcode (BINOP_GEQ); } + ; + +exp : exp '<' exp + { write_exp_elt_opcode (BINOP_LESS); } + ; + +exp : exp '>' exp + { write_exp_elt_opcode (BINOP_GTR); } + ; + +exp : exp '&' exp + { write_exp_elt_opcode (BINOP_LOGAND); } + ; + +exp : exp '^' exp + { write_exp_elt_opcode (BINOP_LOGXOR); } + ; + +exp : exp '|' exp + { write_exp_elt_opcode (BINOP_LOGIOR); } + ; + +exp : exp AND exp + { write_exp_elt_opcode (BINOP_AND); } + ; + +exp : exp OR exp + { write_exp_elt_opcode (BINOP_OR); } + ; + +exp : exp '?' exp ':' exp %prec '?' + { write_exp_elt_opcode (TERNOP_COND); } + ; + +exp : exp '=' exp + { write_exp_elt_opcode (BINOP_ASSIGN); } + ; + +exp : exp ASSIGN_MODIFY exp + { write_exp_elt_opcode (BINOP_ASSIGN_MODIFY); + write_exp_elt_opcode ($2); + write_exp_elt_opcode (BINOP_ASSIGN_MODIFY); } + ; + +exp : INT + { write_exp_elt_opcode (OP_LONG); + if ($1 == (int) $1 || $1 == (unsigned int) $1) + write_exp_elt_type (builtin_type_int); + else + write_exp_elt_type (BUILTIN_TYPE_LONGEST); + write_exp_elt_longcst ((LONGEST) $1); + write_exp_elt_opcode (OP_LONG); } + ; + +exp : UINT + { + write_exp_elt_opcode (OP_LONG); + if ($1 == (unsigned int) $1) + write_exp_elt_type (builtin_type_unsigned_int); + else + write_exp_elt_type (BUILTIN_TYPE_UNSIGNED_LONGEST); + write_exp_elt_longcst ((LONGEST) $1); + write_exp_elt_opcode (OP_LONG); + } + ; + +exp : CHAR + { write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_char); + write_exp_elt_longcst ((LONGEST) $1); + write_exp_elt_opcode (OP_LONG); } + ; + +exp : FLOAT + { write_exp_elt_opcode (OP_DOUBLE); + write_exp_elt_type (builtin_type_double); + write_exp_elt_dblcst ($1); + write_exp_elt_opcode (OP_DOUBLE); } + ; + +exp : variable + ; + +exp : LAST + { write_exp_elt_opcode (OP_LAST); + write_exp_elt_longcst ((LONGEST) $1); + write_exp_elt_opcode (OP_LAST); } + ; + +exp : REGNAME + { write_exp_elt_opcode (OP_REGISTER); + write_exp_elt_longcst ((LONGEST) $1); + write_exp_elt_opcode (OP_REGISTER); } + ; + +exp : VARIABLE + { write_exp_elt_opcode (OP_INTERNALVAR); + write_exp_elt_intern ($1); + write_exp_elt_opcode (OP_INTERNALVAR); } + ; + +exp : SIZEOF '(' type ')' %prec UNARY + { write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_int); + write_exp_elt_longcst ((LONGEST) TYPE_LENGTH ($3)); + write_exp_elt_opcode (OP_LONG); } + ; + +exp : STRING + { write_exp_elt_opcode (OP_STRING); + write_exp_string ($1); + write_exp_elt_opcode (OP_STRING); } + ; + +/* C++. */ +exp : THIS + { write_exp_elt_opcode (OP_THIS); + write_exp_elt_opcode (OP_THIS); } + ; + +/* end of C++. */ + +block : BLOCKNAME + { + struct symtab *tem = lookup_symtab (copy_name ($1)); + struct symbol *sym; + + if (tem) + $$ = BLOCKVECTOR_BLOCK (BLOCKVECTOR (tem), 1); + else + { + sym = lookup_symbol (copy_name ($1), + expression_context_block, + VAR_NAMESPACE, 0); + if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK) + $$ = SYMBOL_BLOCK_VALUE (sym); + else + error ("No file or function \"%s\".", + copy_name ($1)); + } + } + ; + +block : block COLONCOLON name + { struct symbol *tem + = lookup_symbol (copy_name ($3), $1, VAR_NAMESPACE, 0); + if (!tem || SYMBOL_CLASS (tem) != LOC_BLOCK) + error ("No function \"%s\" in specified context.", + copy_name ($3)); + $$ = SYMBOL_BLOCK_VALUE (tem); } + ; + +variable: block COLONCOLON name + { struct symbol *sym; + sym = lookup_symbol (copy_name ($3), $1, VAR_NAMESPACE, 0); + if (sym == 0) + error ("No symbol \"%s\" in specified context.", + copy_name ($3)); + write_exp_elt_opcode (OP_VAR_VALUE); + write_exp_elt_sym (sym); + write_exp_elt_opcode (OP_VAR_VALUE); } + ; + +variable: typebase COLONCOLON name + { + struct type *type = $1; + if (TYPE_CODE (type) != TYPE_CODE_STRUCT + && TYPE_CODE (type) != TYPE_CODE_UNION) + error ("`%s' is not defined as an aggregate type.", + TYPE_NAME (type)); + + write_exp_elt_opcode (OP_SCOPE); + write_exp_elt_type (type); + write_exp_string ($3); + write_exp_elt_opcode (OP_SCOPE); + } + | COLONCOLON name + { + char *name = copy_name ($2); + struct symbol *sym; + int i; + + sym = lookup_symbol (name, 0, VAR_NAMESPACE, 0); + if (sym) + { + write_exp_elt_opcode (OP_VAR_VALUE); + write_exp_elt_sym (sym); + write_exp_elt_opcode (OP_VAR_VALUE); + break; + } + for (i = 0; i < misc_function_count; i++) + if (!strcmp (misc_function_vector[i].name, name)) + break; + + if (i < misc_function_count) + { + enum misc_function_type mft = + (enum misc_function_type) + misc_function_vector[i].type; + + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_int); + write_exp_elt_longcst ((LONGEST) misc_function_vector[i].address); + write_exp_elt_opcode (OP_LONG); + write_exp_elt_opcode (UNOP_MEMVAL); + if (mft == mf_data || mft == mf_bss) + write_exp_elt_type (builtin_type_int); + else if (mft == mf_text) + write_exp_elt_type (lookup_function_type (builtin_type_int)); + else + write_exp_elt_type (builtin_type_char); + write_exp_elt_opcode (UNOP_MEMVAL); + } + else + if (symtab_list == 0 + && partial_symtab_list == 0) + error ("No symbol table is loaded. Use the \"symbol-file\" command."); + else + error ("No symbol \"%s\" in current context.", name); + } + ; + +variable: name_not_typename + { struct symbol *sym; + int is_a_field_of_this; + + sym = lookup_symbol (copy_name ($1), + expression_context_block, + VAR_NAMESPACE, + &is_a_field_of_this); + if (sym) + { + switch (sym->class) + { + case LOC_REGISTER: + case LOC_ARG: + case LOC_LOCAL: + if (innermost_block == 0 || + contained_in (block_found, + innermost_block)) + innermost_block = block_found; + } + write_exp_elt_opcode (OP_VAR_VALUE); + write_exp_elt_sym (sym); + write_exp_elt_opcode (OP_VAR_VALUE); + } + else if (is_a_field_of_this) + { + /* C++: it hangs off of `this'. Must + not inadvertently convert from a method call + to data ref. */ + if (innermost_block == 0 || + contained_in (block_found, innermost_block)) + innermost_block = block_found; + write_exp_elt_opcode (OP_THIS); + write_exp_elt_opcode (OP_THIS); + write_exp_elt_opcode (STRUCTOP_PTR); + write_exp_string ($1); + write_exp_elt_opcode (STRUCTOP_PTR); + } + else + { + register int i; + register char *arg = copy_name ($1); + + for (i = 0; i < misc_function_count; i++) + if (!strcmp (misc_function_vector[i].name, arg)) + break; + + if (i < misc_function_count) + { + enum misc_function_type mft = + (enum misc_function_type) + misc_function_vector[i].type; + + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_int); + write_exp_elt_longcst ((LONGEST) misc_function_vector[i].address); + write_exp_elt_opcode (OP_LONG); + write_exp_elt_opcode (UNOP_MEMVAL); + if (mft == mf_data || mft == mf_bss) + write_exp_elt_type (builtin_type_int); + else if (mft == mf_text) + write_exp_elt_type (lookup_function_type (builtin_type_int)); + else + write_exp_elt_type (builtin_type_char); + write_exp_elt_opcode (UNOP_MEMVAL); + } + else if (symtab_list == 0 + && partial_symtab_list == 0) + error ("No symbol table is loaded. Use the \"symbol-file\" command."); + else + error ("No symbol \"%s\" in current context.", + copy_name ($1)); + } + } + ; + + +ptype : typebase + | typebase abs_decl + { + /* This is where the interesting stuff happens. */ + int done = 0; + int array_size; + struct type *follow_type = $1; + + while (!done) + switch (pop_type ()) + { + case tp_end: + done = 1; + break; + case tp_pointer: + follow_type = lookup_pointer_type (follow_type); + break; + case tp_reference: + follow_type = lookup_reference_type (follow_type); + break; + case tp_array: + array_size = (int) pop_type (); + if (array_size != -1) + follow_type = create_array_type (follow_type, + array_size); + else + follow_type = lookup_pointer_type (follow_type); + break; + case tp_function: + follow_type = lookup_function_type (follow_type); + break; + } + $$ = follow_type; + } + ; + +abs_decl: '*' + { push_type (tp_pointer); $$ = 0; } + | '*' abs_decl + { push_type (tp_pointer); $$ = $2; } + | direct_abs_decl + ; + +direct_abs_decl: '(' abs_decl ')' + { $$ = $2; } + | direct_abs_decl array_mod + { + push_type ((enum type_pieces) $2); + push_type (tp_array); + } + | array_mod + { + push_type ((enum type_pieces) $1); + push_type (tp_array); + $$ = 0; + } + | direct_abs_decl func_mod + { push_type (tp_function); } + | func_mod + { push_type (tp_function); } + ; + +array_mod: '[' ']' + { $$ = -1; } + | '[' INT ']' + { $$ = $2; } + ; + +func_mod: '(' ')' + { $$ = 0; } + ; + +type : ptype + | typebase COLONCOLON '*' + { $$ = lookup_member_type (builtin_type_int, $1); } + | type '(' typebase COLONCOLON '*' ')' + { $$ = lookup_member_type ($1, $3); } + | type '(' typebase COLONCOLON '*' ')' '(' ')' + { $$ = lookup_member_type + (lookup_function_type ($1), $3); } + | type '(' typebase COLONCOLON '*' ')' '(' nonempty_typelist ')' + { $$ = lookup_member_type + (lookup_function_type ($1), $3); + free ($8); } + ; + +typebase + : TYPENAME + { $$ = lookup_typename (copy_name ($1), + expression_context_block, 0); } + | INT_KEYWORD + { $$ = builtin_type_int; } + | LONG + { $$ = builtin_type_long; } + | SHORT + { $$ = builtin_type_short; } + | LONG INT_KEYWORD + { $$ = builtin_type_long; } + | UNSIGNED LONG INT_KEYWORD + { $$ = builtin_type_unsigned_long; } + | SHORT INT_KEYWORD + { $$ = builtin_type_short; } + | UNSIGNED SHORT INT_KEYWORD + { $$ = builtin_type_unsigned_short; } + | STRUCT name + { $$ = lookup_struct (copy_name ($2), + expression_context_block); } + | UNION name + { $$ = lookup_union (copy_name ($2), + expression_context_block); } + | ENUM name + { $$ = lookup_enum (copy_name ($2), + expression_context_block); } + | UNSIGNED typename + { $$ = lookup_unsigned_typename (copy_name ($2)); } + | UNSIGNED + { $$ = builtin_type_unsigned_int; } + | SIGNED typename + { $$ = lookup_typename (copy_name ($2), + expression_context_block, 0); } + | SIGNED + { $$ = builtin_type_int; } + ; + +typename: TYPENAME + | INT_KEYWORD + { + $$.ptr = "int"; + $$.length = 3; + } + | LONG + { + $$.ptr = "long"; + $$.length = 4; + } + | SHORT + { + $$.ptr = "short"; + $$.length = 5; + } + ; + +nonempty_typelist + : type + { $$ = (struct type **)xmalloc (sizeof (struct type *) * 2); + $$[0] = (struct type *)0; + $$[1] = $1; + } + | nonempty_typelist ',' type + { int len = sizeof (struct type *) * ++($<ivec>1[0]); + $$ = (struct type **)xrealloc ($1, len); + $$[$<ivec>$[0]] = $3; + } + ; + +name : NAME + | BLOCKNAME + | TYPENAME + ; + +name_not_typename : NAME + | BLOCKNAME + ; + +%% + +/* Begin counting arguments for a function call, + saving the data about any containing call. */ + +static void +start_arglist () +{ + register struct funcall *new = (struct funcall *) xmalloc (sizeof (struct funcall)); + + new->next = funcall_chain; + new->arglist_len = arglist_len; + arglist_len = 0; + funcall_chain = new; +} + +/* Return the number of arguments in a function call just terminated, + and restore the data for the containing function call. */ + +static int +end_arglist () +{ + register int val = arglist_len; + register struct funcall *call = funcall_chain; + funcall_chain = call->next; + arglist_len = call->arglist_len; + free (call); + return val; +} + +/* Free everything in the funcall chain. + Used when there is an error inside parsing. */ + +static void +free_funcalls () +{ + register struct funcall *call, *next; + + for (call = funcall_chain; call; call = next) + { + next = call->next; + free (call); + } +} + +/* This page contains the functions for adding data to the struct expression + being constructed. */ + +/* Add one element to the end of the expression. */ + +/* To avoid a bug in the Sun 4 compiler, we pass things that can fit into + a register through here */ + +static void +write_exp_elt (expelt) + union exp_element expelt; +{ + if (expout_ptr >= expout_size) + { + expout_size *= 2; + expout = (struct expression *) xrealloc (expout, + sizeof (struct expression) + + expout_size * sizeof (union exp_element)); + } + expout->elts[expout_ptr++] = expelt; +} + +static void +write_exp_elt_opcode (expelt) + enum exp_opcode expelt; +{ + union exp_element tmp; + + tmp.opcode = expelt; + + write_exp_elt (tmp); +} + +static void +write_exp_elt_sym (expelt) + struct symbol *expelt; +{ + union exp_element tmp; + + tmp.symbol = expelt; + + write_exp_elt (tmp); +} + +static void +write_exp_elt_longcst (expelt) + LONGEST expelt; +{ + union exp_element tmp; + + tmp.longconst = expelt; + + write_exp_elt (tmp); +} + +static void +write_exp_elt_dblcst (expelt) + double expelt; +{ + union exp_element tmp; + + tmp.doubleconst = expelt; + + write_exp_elt (tmp); +} + +static void +write_exp_elt_type (expelt) + struct type *expelt; +{ + union exp_element tmp; + + tmp.type = expelt; + + write_exp_elt (tmp); +} + +static void +write_exp_elt_intern (expelt) + struct internalvar *expelt; +{ + union exp_element tmp; + + tmp.internalvar = expelt; + + write_exp_elt (tmp); +} + +/* Add a string constant to the end of the expression. + Follow it by its length in bytes, as a separate exp_element. */ + +static void +write_exp_string (str) + struct stoken str; +{ + register int len = str.length; + register int lenelt + = (len + sizeof (union exp_element)) / sizeof (union exp_element); + + expout_ptr += lenelt; + + if (expout_ptr >= expout_size) + { + expout_size = max (expout_size * 2, expout_ptr + 10); + expout = (struct expression *) + xrealloc (expout, (sizeof (struct expression) + + (expout_size * sizeof (union exp_element)))); + } + bcopy (str.ptr, (char *) &expout->elts[expout_ptr - lenelt], len); + ((char *) &expout->elts[expout_ptr - lenelt])[len] = 0; + write_exp_elt_longcst ((LONGEST) len); +} + +/* During parsing of a C expression, the pointer to the next character + is in this variable. */ + +static char *lexptr; + +/* Tokens that refer to names do so with explicit pointer and length, + so they can share the storage that lexptr is parsing. + + When it is necessary to pass a name to a function that expects + a null-terminated string, the substring is copied out + into a block of storage that namecopy points to. + + namecopy is allocated once, guaranteed big enough, for each parsing. */ + +static char *namecopy; + +/* Current depth in parentheses within the expression. */ + +static int paren_depth; + +/* Nonzero means stop parsing on first comma (if not within parentheses). */ + +static int comma_terminates; + +/* Take care of parsing a number (anything that starts with a digit). + Set yylval and return the token type; update lexptr. + LEN is the number of characters in it. */ + +/*** Needs some error checking for the float case ***/ + +static int +parse_number (olen) + int olen; +{ + register char *p = lexptr; + register LONGEST n = 0; + register int c; + register int base = 10; + register int len = olen; + char *err_copy; + int unsigned_p = 0; + + extern double atof (); + + for (c = 0; c < len; c++) + if (p[c] == '.') + { + /* It's a float since it contains a point. */ + yylval.dval = atof (p); + lexptr += len; + return FLOAT; + } + + if (len >= 3 && (!strncmp (p, "0x", 2) || !strncmp (p, "0X", 2))) + { + p += 2; + base = 16; + len -= 2; + } + else if (*p == '0') + base = 8; + + while (len-- > 0) + { + c = *p++; + if (c >= 'A' && c <= 'Z') c += 'a' - 'A'; + if (c != 'l' && c != 'u') + n *= base; + if (c >= '0' && c <= '9') + n += c - '0'; + else + { + if (base == 16 && c >= 'a' && c <= 'f') + n += c - 'a' + 10; + else if (len == 0 && c == 'l') + ; + else if (len == 0 && c == 'u') + unsigned_p = 1; + else if (base == 10 && len != 0 && (c == 'e' || c == 'E')) + { + /* Scientific notation, where we are unlucky enough not + to have a '.' in the string. */ + yylval.dval = atof (lexptr); + lexptr += olen; + return FLOAT; + } + else + { + err_copy = (char *) alloca (olen + 1); + bcopy (lexptr, err_copy, olen); + err_copy[olen] = 0; + error ("Invalid number \"%s\".", err_copy); + } + } + } + + lexptr = p; + if (unsigned_p) + { + yylval.ulval = n; + return UINT; + } + else + { + yylval.lval = n; + return INT; + } +} + +struct token +{ + char *operator; + int token; + enum exp_opcode opcode; +}; + +static struct token tokentab3[] = + { + {">>=", ASSIGN_MODIFY, BINOP_RSH}, + {"<<=", ASSIGN_MODIFY, BINOP_LSH} + }; + +static struct token tokentab2[] = + { + {"+=", ASSIGN_MODIFY, BINOP_ADD}, + {"-=", ASSIGN_MODIFY, BINOP_SUB}, + {"*=", ASSIGN_MODIFY, BINOP_MUL}, + {"/=", ASSIGN_MODIFY, BINOP_DIV}, + {"%=", ASSIGN_MODIFY, BINOP_REM}, + {"|=", ASSIGN_MODIFY, BINOP_LOGIOR}, + {"&=", ASSIGN_MODIFY, BINOP_LOGAND}, + {"^=", ASSIGN_MODIFY, BINOP_LOGXOR}, + {"++", INCREMENT, BINOP_END}, + {"--", DECREMENT, BINOP_END}, + {"->", ARROW, BINOP_END}, + {"&&", AND, BINOP_END}, + {"||", OR, BINOP_END}, + {"::", COLONCOLON, BINOP_END}, + {"<<", LSH, BINOP_END}, + {">>", RSH, BINOP_END}, + {"==", EQUAL, BINOP_END}, + {"!=", NOTEQUAL, BINOP_END}, + {"<=", LEQ, BINOP_END}, + {">=", GEQ, BINOP_END} + }; + +/* assign machine-independent names to certain registers + * (unless overridden by the REGISTER_NAMES table) + */ +struct std_regs { + char *name; + int regnum; +} std_regs[] = { +#ifdef PC_REGNUM + { "pc", PC_REGNUM }, +#endif +#ifdef FP_REGNUM + { "fp", FP_REGNUM }, +#endif +#ifdef SP_REGNUM + { "sp", SP_REGNUM }, +#endif +#ifdef PS_REGNUM + { "ps", PS_REGNUM }, +#endif +}; + +#define NUM_STD_REGS (sizeof std_regs / sizeof std_regs[0]) + +/* Read one token, getting characters through lexptr. */ + +static int +yylex () +{ + register int c; + register int namelen; + register int i; + register char *tokstart; + + retry: + + tokstart = lexptr; + /* See if it is a special token of length 3. */ + for (i = 0; i < sizeof tokentab3 / sizeof tokentab3[0]; i++) + if (!strncmp (tokstart, tokentab3[i].operator, 3)) + { + lexptr += 3; + yylval.opcode = tokentab3[i].opcode; + return tokentab3[i].token; + } + + /* See if it is a special token of length 2. */ + for (i = 0; i < sizeof tokentab2 / sizeof tokentab2[0]; i++) + if (!strncmp (tokstart, tokentab2[i].operator, 2)) + { + lexptr += 2; + yylval.opcode = tokentab2[i].opcode; + return tokentab2[i].token; + } + + switch (c = *tokstart) + { + case 0: + return 0; + + case ' ': + case '\t': + case '\n': + lexptr++; + goto retry; + + case '\'': + lexptr++; + c = *lexptr++; + if (c == '\\') + c = parse_escape (&lexptr); + yylval.lval = c; + c = *lexptr++; + if (c != '\'') + error ("Invalid character constant."); + return CHAR; + + case '(': + paren_depth++; + lexptr++; + return c; + + case ')': + if (paren_depth == 0) + return 0; + paren_depth--; + lexptr++; + return c; + + case ',': + if (comma_terminates && paren_depth == 0) + return 0; + lexptr++; + return c; + + case '.': + /* Might be a floating point number. */ + if (lexptr[1] >= '0' && lexptr[1] <= '9') + break; /* Falls into number code. */ + + case '+': + case '-': + case '*': + case '/': + case '%': + case '|': + case '&': + case '^': + case '~': + case '!': + case '@': + case '<': + case '>': + case '[': + case ']': + case '?': + case ':': + case '=': + case '{': + case '}': + lexptr++; + return c; + + case '"': + for (namelen = 1; (c = tokstart[namelen]) != '"'; namelen++) + if (c == '\\') + { + c = tokstart[++namelen]; + if (c >= '0' && c <= '9') + { + c = tokstart[++namelen]; + if (c >= '0' && c <= '9') + c = tokstart[++namelen]; + } + } + yylval.sval.ptr = tokstart + 1; + yylval.sval.length = namelen - 1; + lexptr += namelen + 1; + return STRING; + } + + /* Is it a number? */ + /* Note: We have already dealt with the case of the token '.'. + See case '.' above. */ + if ((c >= '0' && c <= '9') || c == '.') + { + /* It's a number. */ + int got_dot = 0, got_e = 0; + register char *p = tokstart; + int hex = c == '0' && (p[1] == 'x' || p[1] == 'X'); + if (hex) + p += 2; + for (;; ++p) + { + if (!hex && !got_e && (*p == 'e' || *p == 'E')) + got_dot = got_e = 1; + else if (!hex && !got_dot && *p == '.') + got_dot = 1; + else if (got_e && (p[-1] == 'e' || p[-1] == 'E') + && (*p == '-' || *p == '+')) + /* This is the sign of the exponent, not the end of the + number. */ + continue; + else if (!got_dot && !got_e && (*p=='l'||*p=='L')){ + ++p; break; + } + else if (!got_dot && !got_e && !hex && (*p=='u'||*p=='U')){ + ++p; break; + } + else if (*p < '0' || *p > '9' + && (!hex || ((*p < 'a' || *p > 'f') + && (*p < 'A' || *p > 'F')))) + break; + } + return parse_number (p - tokstart); + } + + if (!(c == '_' || c == '$' + || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) + /* We must have come across a bad character (e.g. ';'). */ + error ("Invalid character '%c' in expression.", c); + + /* It's a name. See how long it is. */ + namelen = 0; + for (c = tokstart[namelen]; + (c == '_' || c == '$' || (c >= '0' && c <= '9') + || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')); + c = tokstart[++namelen]) + ; + + /* The token "if" terminates the expression and is NOT + removed from the input stream. */ + if (namelen == 2 && tokstart[0] == 'i' && tokstart[1] == 'f') + { + return 0; + } + + lexptr += namelen; + + /* Handle the tokens $digits; also $ (short for $0) and $$ (short for $$1) + and $$digits (equivalent to $<-digits> if you could type that). + Make token type LAST, and put the number (the digits) in yylval. */ + + if (*tokstart == '$') + { + register int negate = 0; + c = 1; + /* Double dollar means negate the number and add -1 as well. + Thus $$ alone means -1. */ + if (namelen >= 2 && tokstart[1] == '$') + { + negate = 1; + c = 2; + } + if (c == namelen) + { + /* Just dollars (one or two) */ + yylval.lval = - negate; + return LAST; + } + /* Is the rest of the token digits? */ + for (; c < namelen; c++) + if (!(tokstart[c] >= '0' && tokstart[c] <= '9')) + break; + if (c == namelen) + { + yylval.lval = atoi (tokstart + 1 + negate); + if (negate) + yylval.lval = - yylval.lval; + return LAST; + } + } + + /* Handle tokens that refer to machine registers: + $ followed by a register name. */ + + if (*tokstart == '$') { + for (c = 0; c < NUM_REGS; c++) + if (namelen - 1 == strlen (reg_names[c]) + && !strncmp (tokstart + 1, reg_names[c], namelen - 1)) + { + yylval.lval = c; + return REGNAME; + } + for (c = 0; c < NUM_STD_REGS; c++) + if (namelen - 1 == strlen (std_regs[c].name) + && !strncmp (tokstart + 1, std_regs[c].name, namelen - 1)) + { + yylval.lval = std_regs[c].regnum; + return REGNAME; + } + } + /* Catch specific keywords. Should be done with a data structure. */ + switch (namelen) + { + case 8: + if (!strncmp (tokstart, "unsigned", 8)) + return UNSIGNED; + break; + case 6: + if (!strncmp (tokstart, "struct", 6)) + return STRUCT; + if (!strncmp (tokstart, "signed", 6)) + return SIGNED; + if (!strncmp (tokstart, "sizeof", 6)) + return SIZEOF; + break; + case 5: + if (!strncmp (tokstart, "union", 5)) + return UNION; + if (!strncmp (tokstart, "short", 5)) + return SHORT; + break; + case 4: + if (!strncmp (tokstart, "enum", 4)) + return ENUM; + if (!strncmp (tokstart, "long", 4)) + return LONG; + if (!strncmp (tokstart, "this", 4) + && lookup_symbol ("$this", expression_context_block, + VAR_NAMESPACE, 0)) + return THIS; + break; + case 3: + if (!strncmp (tokstart, "int", 3)) + return INT_KEYWORD; + break; + default: + break; + } + + yylval.sval.ptr = tokstart; + yylval.sval.length = namelen; + + /* Any other names starting in $ are debugger internal variables. */ + + if (*tokstart == '$') + { + yylval.ivar = (struct internalvar *) lookup_internalvar (copy_name (yylval.sval) + 1); + return VARIABLE; + } + + /* Use token-type BLOCKNAME for symbols that happen to be defined as + functions or symtabs. If this is not so, then ... + Use token-type TYPENAME for symbols that happen to be defined + currently as names of types; NAME for other symbols. + The caller is not constrained to care about the distinction. */ + { + char *tmp = copy_name (yylval.sval); + struct symbol *sym; + + if (lookup_partial_symtab (tmp)) + return BLOCKNAME; + sym = lookup_symbol (tmp, expression_context_block, + VAR_NAMESPACE, 0); + if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK) + return BLOCKNAME; + if (lookup_typename (copy_name (yylval.sval), expression_context_block, 1)) + return TYPENAME; + return NAME; + } +} + +static void +yyerror () +{ + error ("Invalid syntax in expression."); +} + +/* Return a null-terminated temporary copy of the name + of a string token. */ + +static char * +copy_name (token) + struct stoken token; +{ + bcopy (token.ptr, namecopy, token.length); + namecopy[token.length] = 0; + return namecopy; +} + +/* Reverse an expression from suffix form (in which it is constructed) + to prefix form (in which we can conveniently print or execute it). */ + +static void prefixify_subexp (); + +static void +prefixify_expression (expr) + register struct expression *expr; +{ + register int len = sizeof (struct expression) + + expr->nelts * sizeof (union exp_element); + register struct expression *temp; + register int inpos = expr->nelts, outpos = 0; + + temp = (struct expression *) alloca (len); + + /* Copy the original expression into temp. */ + bcopy (expr, temp, len); + + prefixify_subexp (temp, expr, inpos, outpos); +} + +/* Return the number of exp_elements in the subexpression of EXPR + whose last exp_element is at index ENDPOS - 1 in EXPR. */ + +static int +length_of_subexp (expr, endpos) + register struct expression *expr; + register int endpos; +{ + register int oplen = 1; + register int args = 0; + register int i; + + if (endpos < 0) + error ("?error in length_of_subexp"); + + i = (int) expr->elts[endpos - 1].opcode; + + switch (i) + { + /* C++ */ + case OP_SCOPE: + oplen = 4 + ((expr->elts[endpos - 2].longconst + + sizeof (union exp_element)) + / sizeof (union exp_element)); + break; + + case OP_LONG: + case OP_DOUBLE: + oplen = 4; + break; + + case OP_VAR_VALUE: + case OP_LAST: + case OP_REGISTER: + case OP_INTERNALVAR: + oplen = 3; + break; + + case OP_FUNCALL: + oplen = 3; + args = 1 + expr->elts[endpos - 2].longconst; + break; + + case UNOP_CAST: + case UNOP_MEMVAL: + oplen = 3; + args = 1; + break; + + case STRUCTOP_STRUCT: + case STRUCTOP_PTR: + args = 1; + case OP_STRING: + oplen = 3 + ((expr->elts[endpos - 2].longconst + + sizeof (union exp_element)) + / sizeof (union exp_element)); + break; + + case TERNOP_COND: + args = 3; + break; + + case BINOP_ASSIGN_MODIFY: + oplen = 3; + args = 2; + break; + + /* C++ */ + case OP_THIS: + oplen = 2; + break; + + default: + args = 1 + (i < (int) BINOP_END); + } + + while (args > 0) + { + oplen += length_of_subexp (expr, endpos - oplen); + args--; + } + + return oplen; +} + +/* Copy the subexpression ending just before index INEND in INEXPR + into OUTEXPR, starting at index OUTBEG. + In the process, convert it from suffix to prefix form. */ + +static void +prefixify_subexp (inexpr, outexpr, inend, outbeg) + register struct expression *inexpr; + struct expression *outexpr; + register int inend; + int outbeg; +{ + register int oplen = 1; + register int args = 0; + register int i; + int *arglens; + enum exp_opcode opcode; + + /* Compute how long the last operation is (in OPLEN), + and also how many preceding subexpressions serve as + arguments for it (in ARGS). */ + + opcode = inexpr->elts[inend - 1].opcode; + switch (opcode) + { + /* C++ */ + case OP_SCOPE: + oplen = 4 + ((inexpr->elts[inend - 2].longconst + + sizeof (union exp_element)) + / sizeof (union exp_element)); + break; + + case OP_LONG: + case OP_DOUBLE: + oplen = 4; + break; + + case OP_VAR_VALUE: + case OP_LAST: + case OP_REGISTER: + case OP_INTERNALVAR: + oplen = 3; + break; + + case OP_FUNCALL: + oplen = 3; + args = 1 + inexpr->elts[inend - 2].longconst; + break; + + case UNOP_CAST: + case UNOP_MEMVAL: + oplen = 3; + args = 1; + break; + + case STRUCTOP_STRUCT: + case STRUCTOP_PTR: + args = 1; + case OP_STRING: + oplen = 3 + ((inexpr->elts[inend - 2].longconst + + sizeof (union exp_element)) + / sizeof (union exp_element)); + + break; + + case TERNOP_COND: + args = 3; + break; + + case BINOP_ASSIGN_MODIFY: + oplen = 3; + args = 2; + break; + + /* C++ */ + case OP_THIS: + oplen = 2; + break; + + default: + args = 1 + ((int) opcode < (int) BINOP_END); + } + + /* Copy the final operator itself, from the end of the input + to the beginning of the output. */ + inend -= oplen; + bcopy (&inexpr->elts[inend], &outexpr->elts[outbeg], + oplen * sizeof (union exp_element)); + outbeg += oplen; + + /* Find the lengths of the arg subexpressions. */ + arglens = (int *) alloca (args * sizeof (int)); + for (i = args - 1; i >= 0; i--) + { + oplen = length_of_subexp (inexpr, inend); + arglens[i] = oplen; + inend -= oplen; + } + + /* Now copy each subexpression, preserving the order of + the subexpressions, but prefixifying each one. + In this loop, inend starts at the beginning of + the expression this level is working on + and marches forward over the arguments. + outbeg does similarly in the output. */ + for (i = 0; i < args; i++) + { + oplen = arglens[i]; + inend += oplen; + prefixify_subexp (inexpr, outexpr, inend, outbeg); + outbeg += oplen; + } +} + +/* This page contains the two entry points to this file. */ + +/* Read a C expression from the string *STRINGPTR points to, + parse it, and return a pointer to a struct expression that we malloc. + Use block BLOCK as the lexical context for variable names; + if BLOCK is zero, use the block of the selected stack frame. + Meanwhile, advance *STRINGPTR to point after the expression, + at the first nonwhite character that is not part of the expression + (possibly a null character). + + If COMMA is nonzero, stop if a comma is reached. */ + +struct expression * +parse_c_1 (stringptr, block, comma) + char **stringptr; + struct block *block; +{ + struct cleanup *old_chain; + + lexptr = *stringptr; + + paren_depth = 0; + type_stack_depth = 0; + + comma_terminates = comma; + + if (lexptr == 0 || *lexptr == 0) + error_no_arg ("expression to compute"); + + old_chain = make_cleanup (free_funcalls, 0); + funcall_chain = 0; + + expression_context_block = block ? block : get_selected_block (); + + namecopy = (char *) alloca (strlen (lexptr) + 1); + expout_size = 10; + expout_ptr = 0; + expout = (struct expression *) + xmalloc (sizeof (struct expression) + + expout_size * sizeof (union exp_element)); + make_cleanup (free_current_contents, &expout); + if (yyparse ()) + yyerror (); + discard_cleanups (old_chain); + expout->nelts = expout_ptr; + expout = (struct expression *) + xrealloc (expout, + sizeof (struct expression) + + expout_ptr * sizeof (union exp_element)); + prefixify_expression (expout); + *stringptr = lexptr; + return expout; +} + +/* Parse STRING as an expression, and complain if this fails + to use up all of the contents of STRING. */ + +struct expression * +parse_c_expression (string) + char *string; +{ + register struct expression *exp; + exp = parse_c_1 (&string, 0, 0); + if (*string) + error ("Junk after end of expression."); + return exp; +} + +static void +push_type (tp) + enum type_pieces tp; +{ + if (type_stack_depth == type_stack_size) + { + type_stack_size *= 2; + type_stack = (enum type_pieces *) + xrealloc (type_stack, type_stack_size * sizeof (enum type_pieces)); + } + type_stack[type_stack_depth++] = tp; +} + +static enum type_pieces +pop_type () +{ + if (type_stack_depth) + return type_stack[--type_stack_depth]; + return tp_end; +} + +void +_initialize_expread () +{ + type_stack_size = 80; + type_stack_depth = 0; + type_stack = (enum type_pieces *) + xmalloc (type_stack_size * sizeof (enum type_pieces)); +} diff --git a/gnu/usr.bin/gdb/expression.h b/gnu/usr.bin/gdb/expression.h new file mode 100644 index 0000000..5a5e20e --- /dev/null +++ b/gnu/usr.bin/gdb/expression.h @@ -0,0 +1,191 @@ +/* Definitions for expressions stored in reversed prefix form, for GDB. + Copyright (C) 1986, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Definitions for saved C expressions. */ + +/* An expression is represented as a vector of union exp_element's. + Each exp_element is an opcode, except that some opcodes cause + the following exp_element to be treated as a long or double constant + or as a variable. The opcodes are obeyed, using a stack for temporaries. + The value is left on the temporary stack at the end. */ + +/* When it is necessary to include a string, + it can occupy as many exp_elements as it needs. + We find the length of the string using strlen, + divide to find out how many exp_elements are used up, + and skip that many. Strings, like numbers, are indicated + by the preceding opcode. */ + +enum exp_opcode +{ +/* BINOP_... operate on two values computed by following subexpressions, + replacing them by one result value. They take no immediate arguments. */ + BINOP_ADD, /* + */ + BINOP_SUB, /* - */ + BINOP_MUL, /* * */ + BINOP_DIV, /* / */ + BINOP_REM, /* % */ + BINOP_LSH, /* << */ + BINOP_RSH, /* >> */ + BINOP_AND, /* && */ + BINOP_OR, /* || */ + BINOP_LOGAND, /* & */ + BINOP_LOGIOR, /* | */ + BINOP_LOGXOR, /* ^ */ + BINOP_EQUAL, /* == */ + BINOP_NOTEQUAL, /* != */ + BINOP_LESS, /* < */ + BINOP_GTR, /* > */ + BINOP_LEQ, /* <= */ + BINOP_GEQ, /* >= */ + BINOP_REPEAT, /* @ */ + BINOP_ASSIGN, /* = */ + BINOP_COMMA, /* , */ + BINOP_SUBSCRIPT, /* x[y] */ + BINOP_EXP, /* Exponentiation */ + +/* C++. */ + BINOP_MIN, /* <? */ + BINOP_MAX, /* >? */ + BINOP_SCOPE, /* :: */ + + /* STRUCTOP_MEMBER is used for pointer-to-member constructs. + X . * Y translates into X STRUCTOP_MEMBER Y. */ + STRUCTOP_MEMBER, + /* STRUCTOP_MPTR is used for pointer-to-member constructs + when X is a pointer instead of an aggregate. */ + STRUCTOP_MPTR, +/* end of C++. */ + + BINOP_END, + + BINOP_ASSIGN_MODIFY, /* +=, -=, *=, and so on. + The following exp_element is another opcode, + a BINOP_, saying how to modify. + Then comes another BINOP_ASSIGN_MODIFY, + making three exp_elements in total. */ + +/* Operates on three values computed by following subexpressions. */ + TERNOP_COND, /* ?: */ + +/* The OP_... series take immediate following arguments. + After the arguments come another OP_... (the same one) + so that the grouping can be recognized from the end. */ + +/* OP_LONG is followed by a type pointer in the next exp_element + and the long constant value in the following exp_element. + Then comes another OP_LONG. + Thus, the operation occupies four exp_elements. */ + + OP_LONG, +/* OP_DOUBLE is similar but takes a double constant instead of a long one. */ + OP_DOUBLE, +/* OP_VAR_VALUE takes one struct symbol * in the following exp_element, + followed by another OP_VAR_VALUE, making three exp_elements. */ + OP_VAR_VALUE, +/* OP_LAST is followed by an integer in the next exp_element. + The integer is zero for the last value printed, + or it is the absolute number of a history element. + With another OP_LAST at the end, this makes three exp_elements. */ + OP_LAST, +/* OP_REGISTER is followed by an integer in the next exp_element. + This is the number of a register to fetch (as an int). + With another OP_REGISTER at the end, this makes three exp_elements. */ + OP_REGISTER, +/* OP_INTERNALVAR is followed by an internalvar ptr in the next exp_element. + With another OP_INTERNALVAR at the end, this makes three exp_elements. */ + OP_INTERNALVAR, +/* OP_FUNCALL is followed by an integer in the next exp_element. + The integer is the number of args to the function call. + That many plus one values from following subexpressions + are used, the first one being the function. + The integer is followed by a repeat of OP_FUNCALL, + making three exp_elements. */ + OP_FUNCALL, +/* OP_STRING represents a string constant. + Its format is the same as that of a STRUCTOP, but the string + data is just made into a string constant when the operation + is executed. */ + OP_STRING, + +/* UNOP_CAST is followed by a type pointer in the next exp_element. + With another UNOP_CAST at the end, this makes three exp_elements. + It casts the value of the following subexpression. */ + UNOP_CAST, +/* UNOP_MEMVAL is followed by a type pointer in the next exp_element + With another UNOP_MEMVAL at the end, this makes three exp_elements. + It casts the contents of the word addressed by the value of the + following subexpression. */ + UNOP_MEMVAL, +/* UNOP_... operate on one value from a following subexpression + and replace it with a result. They take no immediate arguments. */ + UNOP_NEG, /* Unary - */ + UNOP_ZEROP, /* Unary ! */ + UNOP_LOGNOT, /* Unary ~ */ + UNOP_IND, /* Unary * */ + UNOP_ADDR, /* Unary & */ + UNOP_PREINCREMENT, /* ++ before an expression */ + UNOP_POSTINCREMENT, /* ++ after an expression */ + UNOP_PREDECREMENT, /* -- before an expression */ + UNOP_POSTDECREMENT, /* -- after an expression */ + UNOP_SIZEOF, /* Unary sizeof (followed by expression) */ + +/* STRUCTOP_... operate on a value from a following subexpression + by extracting a structure component specified by a string + that appears in the following exp_elements (as many as needed). + STRUCTOP_STRUCT is used for "." and STRUCTOP_PTR for "->". + They differ only in the error message given in case the value is + not suitable or the structure component specified is not found. + + The length of the string follows in the next exp_element, + (after the string), followed by another STRUCTOP_... code. */ + STRUCTOP_STRUCT, + STRUCTOP_PTR, + +/* C++ */ + /* OP_THIS is just a placeholder for the class instance variable. + It just comes in a tight (OP_THIS, OP_THIS) pair. */ + OP_THIS, + + /* OP_SCOPE surrounds a type name and a field name. The type + name is encoded as one element, but the field name stays as + a string, which, of course, is variable length. */ + OP_SCOPE, + +}; + +union exp_element +{ + enum exp_opcode opcode; + struct symbol *symbol; + LONGEST longconst; + double doubleconst; + char string; + struct type *type; + struct internalvar *internalvar; +}; + +struct expression +{ + int nelts; + union exp_element elts[1]; +}; + +struct expression *parse_c_expression (); +struct expression *parse_c_1 (); diff --git a/gnu/usr.bin/gdb/findvar.c b/gnu/usr.bin/gdb/findvar.c new file mode 100644 index 0000000..0157d10 --- /dev/null +++ b/gnu/usr.bin/gdb/findvar.c @@ -0,0 +1,579 @@ +/* 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 "defs.h" +#include "param.h" +#include "symtab.h" +#include "frame.h" +#include "value.h" + +CORE_ADDR read_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; + +#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 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] ? + saved_regs.regs[regnum] : 0); + } +#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; +} + +/* Copy the bytes of register REGNUM, relative to the current stack frame, + into our memory at MYADDR. + The number of bytes copied is REGISTER_RAW_SIZE (REGNUM). */ + +void +read_relative_register_raw_bytes (regnum, myaddr) + int regnum; + char *myaddr; +{ + register CORE_ADDR addr; + + if (regnum == FP_REGNUM) + { + bcopy (&FRAME_FP(selected_frame), myaddr, sizeof (CORE_ADDR)); + return; + } + + addr = find_saved_register (selected_frame, regnum); + + if (addr) + { + if (regnum == SP_REGNUM) + { + CORE_ADDR buffer = addr; + bcopy (&buffer, myaddr, sizeof (CORE_ADDR)); + } + else + read_memory (addr, myaddr, REGISTER_RAW_SIZE (regnum)); + return; + } + read_register_bytes (REGISTER_BYTE (regnum), + myaddr, REGISTER_RAW_SIZE (regnum)); +} + +/* 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; +{ + register CORE_ADDR addr; + register value val; + char raw_buffer[MAX_REGISTER_RAW_SIZE]; + char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE]; + + if (! (have_inferior_p () || have_core_file_p ())) + error ("Can't get value of register without inferior or core file"); + + addr = find_saved_register (selected_frame, regnum); + if (addr) + { + if (regnum == SP_REGNUM) + return value_from_long (builtin_type_int, (LONGEST) addr); + read_memory (addr, raw_buffer, REGISTER_RAW_SIZE (regnum)); + } + else + read_register_bytes (REGISTER_BYTE (regnum), raw_buffer, + REGISTER_RAW_SIZE (regnum)); + + REGISTER_CONVERT_TO_VIRTUAL (regnum, raw_buffer, virtual_buffer); + val = allocate_value (REGISTER_VIRTUAL_TYPE (regnum)); + bcopy (virtual_buffer, VALUE_CONTENTS (val), REGISTER_VIRTUAL_SIZE (regnum)); + VALUE_LVAL (val) = addr ? lval_memory : lval_register; + VALUE_ADDRESS (val) = addr ? addr : REGISTER_BYTE (regnum); + VALUE_REGNO (val) = regnum; + return val; +} + +/* Low level examining and depositing of registers. + + Note that you must call `fetch_registers' once + before examining or depositing any registers. */ + +char registers[REGISTER_BYTES]; + +/* 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; +{ + bcopy (®isters[regbyte], myaddr, len); +} + +/* 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; +{ + bcopy (myaddr, ®isters[regbyte], len); + if (have_inferior_p ()) + store_inferior_registers (-1); +} + +/* Return the contents of register REGNO, + regarding it as an integer. */ + +CORE_ADDR +read_register (regno) + int regno; +{ + /* This loses when REGISTER_RAW_SIZE (regno) != sizeof (int) */ + return *(int *) ®isters[REGISTER_BYTE (regno)]; +} + +/* Store VALUE in the register number REGNO, regarded as an integer. */ + +void +write_register (regno, val) + int regno, val; +{ + /* This loses when REGISTER_RAW_SIZE (regno) != sizeof (int) */ +#if defined(sun4) + /* This is a no-op on a Sun 4. */ + if (regno == 0) + return; +#endif + + *(int *) ®isters[REGISTER_BYTE (regno)] = val; + + if (have_inferior_p ()) + store_inferior_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; +{ + 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. */ + +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); + register CORE_ADDR addr = 0; + int val = SYMBOL_VALUE (var); + 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: + case LOC_LABEL: + bcopy (&val, VALUE_CONTENTS (v), len); + VALUE_LVAL (v) = not_lval; + return v; + + case LOC_CONST_BYTES: + bcopy (val, VALUE_CONTENTS (v), len); + VALUE_LVAL (v) = not_lval; + return v; + + case LOC_STATIC: + addr = val; + 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 = val + FRAME_ARGS_ADDRESS (fi); + break; + + case LOC_REF_ARG: + fi = get_frame_info (frame); + addr = val + FRAME_ARGS_ADDRESS (fi); + addr = read_memory_integer (addr, sizeof (CORE_ADDR)); + break; + + case LOC_LOCAL: + fi = get_frame_info (frame); + addr = val + FRAME_LOCALS_ADDRESS (fi); + break; + + case LOC_TYPEDEF: + error ("Cannot look up value of a typedef"); + + 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, val, 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; + } + } + + read_memory (addr, VALUE_CONTENTS (v), len); + VALUE_ADDRESS (v) = addr; + 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; + value v = allocate_value (type); + int len = TYPE_LENGTH (type); + char *value_bytes = 0; + int value_bytes_copied = 0; + int num_storage_locs; + + 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; + + 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)) + { + int register_index = local_regnum - regnum; + addr = find_saved_register (frame, local_regnum); + if (addr == 0) + { + read_register_bytes (REGISTER_BYTE (local_regnum), + value_bytes + value_bytes_copied, + REGISTER_RAW_SIZE (local_regnum)); + reg_stor++; + } + else + { + read_memory (addr, value_bytes + value_bytes_copied, + REGISTER_RAW_SIZE (local_regnum)); + mem_stor++; + 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) = find_saved_register (frame, regnum); + } + else if (reg_stor) + { + VALUE_LVAL (v) = lval_register; + VALUE_ADDRESS (v) = REGISTER_BYTE (regnum); + } + else + fatal ("value_from_register: Value not stored anywhere!"); + + /* Any structure stored in more than one register will always be + an inegral 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 (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. */ + + addr = find_saved_register (frame, regnum); + if (addr == 0) + { + /* Value is really in a register. */ + + VALUE_LVAL (v) = lval_register; + VALUE_ADDRESS (v) = REGISTER_BYTE (regnum); + + read_register_bytes (REGISTER_BYTE (regnum), + raw_buffer, REGISTER_RAW_SIZE (regnum)); + } + else + { + /* Value was in a register that has been saved in memory. */ + + read_memory (addr, raw_buffer, REGISTER_RAW_SIZE (regnum)); + VALUE_LVAL (v) = lval_memory; + VALUE_ADDRESS (v) = addr; + } + + /* Convert the raw contents to virtual contents. + (Just copy them if the formats are the same.) */ + + REGISTER_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 (v), len); + v = value_cast (type, v); + } + else + bcopy (virtual_buffer, VALUE_CONTENTS (v), len); + } + else + { + /* Raw and virtual formats are the same for this register. */ + +#ifdef BYTES_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 (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; +{ + register CORE_ADDR addr = 0; + int val = SYMBOL_VALUE (var); + struct frame_info *fi; + struct type *type = SYMBOL_TYPE (var); + struct type *result_type; + + if (frame == 0) frame = selected_frame; + + switch (SYMBOL_CLASS (var)) + { + case LOC_CONST: + case LOC_CONST_BYTES: + error ("Address requested for identifier \"%s\" which is a constant.", + SYMBOL_NAME (var)); + + case LOC_REGISTER: + case LOC_REGPARM: + addr = find_saved_register (frame, val); + if (addr != 0) + { + int len = TYPE_LENGTH (type); +#ifdef BYTES_BIG_ENDIAN + if (len < REGISTER_RAW_SIZE (val)) + /* Big-endian, and we want less than full size. */ + addr += REGISTER_RAW_SIZE (val) - len; +#endif + break; + } + error ("Address requested for identifier \"%s\" which is in a register.", + SYMBOL_NAME (var)); + + case LOC_STATIC: + case LOC_LABEL: + addr = val; + break; + + case LOC_ARG: + fi = get_frame_info (frame); + addr = val + FRAME_ARGS_ADDRESS (fi); + break; + + case LOC_REF_ARG: + fi = get_frame_info (frame); + addr = val + FRAME_ARGS_ADDRESS (fi); + addr = read_memory_integer (addr, sizeof (CORE_ADDR)); + break; + + case LOC_LOCAL: + fi = get_frame_info (frame); + addr = val + FRAME_LOCALS_ADDRESS (fi); + break; + + case LOC_TYPEDEF: + error ("Address requested for identifier \"%s\" which is a typedef.", + SYMBOL_NAME (var)); + + case LOC_BLOCK: + addr = BLOCK_START (SYMBOL_BLOCK_VALUE (var)); + break; + } + + /* 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)); +} + diff --git a/gnu/usr.bin/gdb/frame.h b/gnu/usr.bin/gdb/frame.h new file mode 100644 index 0000000..322ddba --- /dev/null +++ b/gnu/usr.bin/gdb/frame.h @@ -0,0 +1,115 @@ +/* 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. */ + +/* Note that frame.h requires 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 get_frame_saved_regs (); + +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 struct symbol *get_pc_function (); + +/* In stack.c */ +extern FRAME find_relative_frame (); + +/* Generic pointer value indicating "I don't know." */ +#define Frame_unknown (CORE_ADDR)-1 diff --git a/gnu/usr.bin/gdb/gdb.1 b/gnu/usr.bin/gdb/gdb.1 new file mode 100644 index 0000000..57d744b --- /dev/null +++ b/gnu/usr.bin/gdb/gdb.1 @@ -0,0 +1,3 @@ +.\" %W% (Berkeley) %G% +.\" +.\" placeholder, until we can produce the manual page diff --git a/gnu/usr.bin/gdb/getpagesize.h b/gnu/usr.bin/gdb/getpagesize.h new file mode 100644 index 0000000..32adae6 --- /dev/null +++ b/gnu/usr.bin/gdb/getpagesize.h @@ -0,0 +1,25 @@ +#ifdef BSD +#ifndef BSD4_1 +#define HAVE_GETPAGESIZE +#endif +#endif + +#ifndef HAVE_GETPAGESIZE + +#include <sys/param.h> + +#ifdef EXEC_PAGESIZE +#define getpagesize() EXEC_PAGESIZE +#else +#ifdef NBPG +#define getpagesize() NBPG * CLSIZE +#ifndef CLSIZE +#define CLSIZE 1 +#endif /* no CLSIZE */ +#else /* no NBPG */ +#define getpagesize() NBPC +#endif /* no NBPG */ +#endif /* no EXEC_PAGESIZE */ + +#endif /* not HAVE_GETPAGESIZE */ + diff --git a/gnu/usr.bin/gdb/infcmd.c b/gnu/usr.bin/gdb/infcmd.c new file mode 100644 index 0000000..378784f --- /dev/null +++ b/gnu/usr.bin/gdb/infcmd.c @@ -0,0 +1,1204 @@ +/*- + * This code is derived from software copyrighted by the Free Software + * Foundation. + * + * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. + * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory. + */ + +#ifndef lint +static char sccsid[] = "@(#)infcmd.c 6.4 (Berkeley) 5/8/91"; +#endif /* not lint */ + +/* Memory-access and commands for inferior process, for GDB. + Copyright (C) 1986, 1987, 1988, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <stdio.h> +#include "defs.h" +#include "param.h" +#include "symtab.h" +#include "frame.h" +#include "inferior.h" +#include "environ.h" +#include "value.h" + +#include <signal.h> +#include <sys/param.h> + +extern char *sys_siglist[]; + +#define ERROR_NO_INFERIOR \ + if (inferior_pid == 0) error ("The program is not being run."); + +/* String containing arguments to give to the program, + with a space added at the front. Just a space 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. */ + +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; + +/* Number of breakpoint it stopped at, or 0 if none. */ + +int stop_breakpoint; + +/* 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 (); +struct command_line *get_breakpoint_commands (); +void breakpoint_clear_ignore_counts (); + + +int +have_inferior_p () +{ + return inferior_pid != 0; +} + +static void +set_args_command (args) + char *args; +{ + free (inferior_args); + if (!args) args = ""; + inferior_args = concat (" ", args, ""); +} + +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; +{ + extern char **environ; + register int i; + char *exec_file; + char *allargs; + + extern int sys_nerr; + extern char *sys_errlist[]; + extern int errno; + + dont_repeat (); + + if (inferior_pid) + { + extern int inhibit_confirm; + if (!(inhibit_confirm || + query ("The program being debugged has been started already.\n\ +Start it from the beginning? "))) + error ("Program not restarted."); + kill_inferior (); + } + +#if 0 + /* On the other hand, some users want to do + break open + ignore 1 40 + run + So it's not clear what is best. */ + + /* 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 (); +#endif + + exec_file = (char *) get_exec_file (1); + + if (remote_debugging) + { + if (from_tty) + { + printf ("Starting program: %s\n", exec_file); + fflush (stdout); + } + } + else + { + if (args) + set_args_command (args); + + if (from_tty) + { + printf ("Starting program: %s%s\n", + exec_file, inferior_args); + fflush (stdout); + } + + allargs = concat ("exec ", exec_file, inferior_args); + inferior_pid = create_inferior (allargs, environ_vector (inferior_environ)); + } + + clear_proceed_status (); + + start_inferior (); +} + +void +cont_command (proc_count_exp, from_tty) + char *proc_count_exp; + int from_tty; +{ + ERROR_NO_INFERIOR; + + clear_proceed_status (); + + /* If have argument, set proceed count of breakpoint we stopped at. */ + + if (stop_breakpoint > 0 && proc_count_exp) + { + set_ignore_count (stop_breakpoint, + parse_and_eval_address (proc_count_exp) - 1, + from_tty); + if (from_tty) + printf (" "); + } + + if (from_tty) + printf ("Continuing.\n"); + + proceed (-1, -1, 0); +} + +/* Step until outside of current statement. */ +static void step_1 (); + +static void +step_command (count_string) +{ + step_1 (0, 0, count_string); +} + +/* Likewise, but skip over subroutine calls as if single instructions. */ + +static void +next_command (count_string) +{ + step_1 (1, 0, count_string); +} + +/* Likewise, but step only one instruction. */ + +static void +stepi_command (count_string) +{ + step_1 (0, 1, count_string); +} + +static void +nexti_command (count_string) +{ + 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; + + ERROR_NO_INFERIOR; + count = count_string ? parse_and_eval_address (count_string) : 1; + + for (; count > 0; count--) + { + clear_proceed_status (); + + step_frame_address = FRAME_FP (get_current_frame ()); + + 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); + 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 (-1, -1, 1); + if (! stop_step) + break; + } +} + +/* 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 = sal.pc; + + clear_proceed_status (); + + if (from_tty) + printf ("Continuing at 0x%x.\n", addr); + + 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); + + clear_proceed_status (); + + if (from_tty) + printf ("Continuing with signal %d.\n", signum); + + 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; + REGISTER_TYPE *buffer; +{ + /* Now proceed, having reached the desired place. */ + clear_proceed_status (); +#ifdef notdef + if (stack_dummy_testing & 4) + { + POP_FRAME; + return; + } +#endif + proceed (addr, 0, 0); + + if (!stop_stack_dummy) + error ("Cannot continue previously requested operation."); + + /* On return, the stack dummy has been popped already. */ + + read_register_bytes(0, buffer, REGISTER_BYTES); +} + +/* Proceed until we reach the given line as argument or exit the + function. When called with no argument, 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. + + The effect of this command with an argument is identical to setting + a momentary breakpoint at the line specified and executing + "finish". + + 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 (arg, from_tty) + char *arg; + 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 (-1, -1, 1); +} + +void +until_command (arg, from_tty) + char *arg; + int from_tty; +{ + if (!have_inferior_p ()) + error ("The program is not being run."); + + if (arg) + until_break_command (arg, from_tty); + else + until_next_command (arg, 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 (!have_inferior_p ()) + error ("The program is not being run."); + if (arg) + error ("The \"finish\" command does not take any arguments."); + + 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 (-1, -1, 0); + + if (stop_breakpoint == -3 && function != 0) + { + struct type *value_type; + register value val; + CORE_ADDR funcaddr; + extern char registers[]; + + 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, registers, + using_struct_return (function, + funcaddr, + value_type)); + + printf ("Value returned is $%d = ", record_latest_value (val)); + value_print (val, stdout, 0, Val_no_prettyprint); + putchar ('\n'); + } +} + +static void +program_info () +{ + if (inferior_pid == 0) + { + printf ("The program being debugged is not being run.\n"); + return; + } + + printf ("Program being debugged is in process %d, stopped at 0x%x.\n", + inferior_pid, stop_pc); + if (stop_step) + printf ("It stopped after being stepped.\n"); + else if (stop_breakpoint > 0) + printf ("It stopped at breakpoint %d.\n", stop_breakpoint); + else if (stop_signal) + printf ("It stopped with signal %d (%s).\n", + stop_signal, sys_siglist[stop_signal]); + + printf ("\nType \"info stack\" or \"info reg\" 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 *) index (arg, '='); + val = (char *) index (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 (); + } + + unset_in_environ (inferior_environ, var); +} + +/* Read an integer from debugged memory, given address and number of bytes. */ + +long +read_memory_integer (memaddr, len) + CORE_ADDR memaddr; + int len; +{ + char cbuf; + short sbuf; + int ibuf; + long lbuf; + int result_err; + extern int sys_nerr; + extern char *sys_errlist[]; + + if (len == sizeof (char)) + { + result_err = read_memory (memaddr, &cbuf, len); + if (result_err) + error ("Error reading memory address 0x%x: %s (%d).", + memaddr, (result_err < sys_nerr ? + sys_errlist[result_err] : + "uknown error"), result_err); + return cbuf; + } + if (len == sizeof (short)) + { + result_err = read_memory (memaddr, &sbuf, len); + if (result_err) + error ("Error reading memory address 0x%x: %s (%d).", + memaddr, (result_err < sys_nerr ? + sys_errlist[result_err] : + "uknown error"), result_err); + return sbuf; + } + if (len == sizeof (int)) + { + result_err = read_memory (memaddr, &ibuf, len); + if (result_err) + error ("Error reading memory address 0x%x: %s (%d).", + memaddr, (result_err < sys_nerr ? + sys_errlist[result_err] : + "uknown error"), result_err); + return ibuf; + } + if (len == sizeof (lbuf)) + { + result_err = read_memory (memaddr, &lbuf, len); + if (result_err) + error ("Error reading memory address 0x%x: %s (%d).", + memaddr, (result_err < sys_nerr ? + sys_errlist[result_err] : + "uknown error"), result_err); + return lbuf; + } + error ("Cannot handle integers of %d bytes.", len); +} + +CORE_ADDR +read_pc () +{ + return (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 +} + +char *reg_names[] = REGISTER_NAMES; + +#if !defined (DO_REGISTERS_INFO) +static void +print_one_register(i) + int i; +{ + unsigned char raw_buffer[MAX_REGISTER_RAW_SIZE]; + unsigned char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE]; + REGISTER_TYPE val; + + /* Get the data in raw format, then convert also to virtual format. */ + read_relative_register_raw_bytes (i, raw_buffer); + REGISTER_CONVERT_TO_VIRTUAL (i, raw_buffer, virtual_buffer); + + fputs_filtered (reg_names[i], stdout); + print_spaces_filtered (15 - strlen (reg_names[i]), stdout); + + /* If virtual format is floating, print it that way. */ + if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (i)) == TYPE_CODE_FLT + && ! INVALID_FLOAT (virtual_buffer, REGISTER_VIRTUAL_SIZE (i))) + val_print (REGISTER_VIRTUAL_TYPE (i), virtual_buffer, 0, + stdout, 0, 1, 0, Val_pretty_default); + /* 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", virtual_buffer[j]); + } + /* Else print as integer in hex and in decimal. */ + else + { + long val; + + bcopy (virtual_buffer, &val, sizeof (long)); + if (val == 0) + printf_filtered ("0"); + else + printf_filtered ("0x%08x %d", val, val); + } + + /* If register has different raw and virtual formats, + print the raw format in hex now. */ + + if (REGISTER_CONVERTIBLE (i)) + { + register int j; + + printf_filtered (" (raw 0x"); + for (j = 0; j < REGISTER_RAW_SIZE (i); j++) + printf_filtered ("%02x", raw_buffer[j]); + printf_filtered (")"); + } + printf_filtered ("\n"); +} + + +/* 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. */ +static void +do_registers_info (regnum, fpregs) + int regnum; + int fpregs; +{ + register int i; + + if (regnum >= 0) { + print_one_register(regnum); + return; + } +#ifdef notdef + printf_filtered ( +"Register Contents (relative to selected stack frame)\n\n"); +#endif + for (i = 0; i < NUM_REGS; i++) + if (TYPE_CODE(REGISTER_VIRTUAL_TYPE(i)) != TYPE_CODE_FLT || + fpregs) + print_one_register(i); +} +#endif /* no DO_REGISTERS_INFO. */ + +static void +registers_info (addr_exp, fpregs) + char *addr_exp; + int fpregs; +{ + int regnum; + + if (!have_inferior_p () && !have_core_file_p ()) + error ("No inferior or core file"); + + 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; + +#ifdef DO_REGISTERS_INFO + DO_REGISTERS_INFO(regnum); +#else + do_registers_info(regnum, fpregs); +#endif +} + +static void +all_registers_info (addr_exp) + char *addr_exp; +{ + registers_info(addr_exp, 1); +} + +static void +nofp_registers_info (addr_exp) + char *addr_exp; +{ + registers_info(addr_exp, 0); +} + + +#ifdef ATTACH_DETACH +#define PROCESS_ATTACH_ALLOWED 1 +#else +#define PROCESS_ATTACH_ALLOWED 0 +#endif +/* + * 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. + */ +static void +attach_command (args, from_tty) + char *args; + int from_tty; +{ + char *exec_file; + int pid; + int remote = 0; + + dont_repeat(); + + if (!args) + error_no_arg ("process-id or device file to attach"); + + while (*args == ' ' || *args == '\t') args++; + + if (args[0] < '0' || args[0] > '9') + remote = 1; + else +#ifndef ATTACH_DETACH + error ("Can't attach to a process on this machine."); +#else + pid = atoi (args); +#endif + + if (inferior_pid) + { + if (query ("A program is being debugged already. Kill it? ")) + kill_inferior (); + else + error ("Inferior not killed."); + } + + exec_file = (char *) get_exec_file (1); + + if (from_tty) + { + if (remote) + printf ("Attaching remote machine\n"); + else + printf ("Attaching program: %s pid %d\n", + exec_file, pid); + fflush (stdout); + } + + if (remote) + { + remote_open (args, from_tty); + start_remote (); + } +#ifdef ATTACH_DETACH + else + attach_program (pid); +#endif +} + +/* + * 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; +{ + int signal = 0; + +#ifdef ATTACH_DETACH + if (inferior_pid && !remote_debugging) + { + if (from_tty) + { + char *exec_file = (char *)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) + signal = atoi (args); + + detach (signal); + inferior_pid = 0; + } + else +#endif + { + if (!remote_debugging) + error ("Not currently attached to subsidiary or remote process."); + + if (args) + error ("Argument given to \"detach\" when remotely debugging."); + + inferior_pid = 0; + remote_close (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 +} + +extern struct cmd_list_element *setlist, *deletelist; + +void +_initialize_infcmd () +{ + add_com ("tty", class_run, tty_command, + "Set terminal for future runs of program being debugged."); + + add_cmd ("args", class_run, set_args_command, + "Specify 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); + + add_info ("environment", 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."); + + 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); + + 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); + +#ifdef ATTACH_DETACH + add_com ("attach", class_run, attach_command, + "Attach to a process that was started up outside of GDB.\n\ +This 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\ +For a device file, the file must be a connection to a remote debug server.\n\n\ +Before using \"attach\", you must use the \"exec-file\" command\n\ +to specify the program running in the process,\n\ +and the \"symbol-file\" command to load its symbol table."); +#else + add_com ("attach", class_run, attach_command, + "Attach to a process that was started up outside of GDB.\n\ +This commands takes as an argument the name of a device file.\n\ +This file must be a connection to a remote debug server.\n\n\ +Before using \"attach\", you must use the \"exec-file\" command\n\ +to specify the program running in the process,\n\ +and the \"symbol-file\" command to load its symbol table."); +#endif + add_com ("detach", class_run, detach_command, + "Detach the process previously attached.\n\ +The process is no longer traced and continues its execution."); + + 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 ("cont", class_run, cont_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 ("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", nofp_registers_info, + "List of registers and their contents, for selected stack frame.\n\ +Register name as argument means describe only that register.\n\ +(Doesn't display floating point registers; use 'info all-registers'.)\n"); + + add_info ("all-registers", all_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); /* By default, no args. */ + inferior_environ = make_environ (); + init_environ (inferior_environ); +} + diff --git a/gnu/usr.bin/gdb/inferior.h b/gnu/usr.bin/gdb/inferior.h new file mode 100644 index 0000000..04c662e --- /dev/null +++ b/gnu/usr.bin/gdb/inferior.h @@ -0,0 +1,142 @@ +/*- + * This code is derived from software copyrighted by the Free Software + * Foundation. + * + * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. + * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory. + * + * @(#)inferior.h 6.3 (Berkeley) 5/8/91 + */ + +/* 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. */ + +/* + * 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; + int stop_frame_address; + int stop_breakpoint; + 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_after_attach; + FRAME_ADDR selected_frame_address; + int selected_level; + struct command_line *breakpoint_commands; + char register_context[REGISTER_BYTES]; + int restore_stack_info; +}; + +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; + +/* Nonzero if debugging a remote machine via a serial link or ethernet. */ +extern int remote_debugging; + +/* Routines for use in remote debugging. Documented in remote.c. */ +int remote_read_inferior_memory (); +int remote_write_inferior_memory (); + +/* 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; + +/* Number of breakpoint it stopped at, or 0 if none. */ + +extern int stop_breakpoint; + +/* 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; + +/* Save register contents here when about to pop a stack dummy frame. */ + +extern char stop_registers[REGISTER_BYTES]; + +/* Nonzero if pc has been changed by the debugger + since the inferior stopped. */ + +extern int pc_changed; + +long read_memory_integer (); diff --git a/gnu/usr.bin/gdb/inflow.c b/gnu/usr.bin/gdb/inflow.c new file mode 100644 index 0000000..209fcf3 --- /dev/null +++ b/gnu/usr.bin/gdb/inflow.c @@ -0,0 +1,569 @@ +/*- + * This code is derived from software copyrighted by the Free Software + * Foundation. + * + * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. + * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory. + */ + +#ifndef lint +static char sccsid[] = "@(#)inflow.c 6.5 (Berkeley) 5/8/91"; +#endif /* not lint */ + +/* Low level interface to ptrace, for GDB when running under Unix. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <stdio.h> +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" + +#ifdef USG +#include <sys/types.h> +#endif + +/* Some USG-esque systems (some of which are BSD-esque enough so that USG + is not defined) want this header, and it won't do any harm. */ +#include <fcntl.h> + +#include <sys/param.h> +#include <sys/dir.h> +#include <signal.h> + +#ifdef HAVE_TERMIO +#include <termio.h> +#undef TIOCGETP +#define TIOCGETP TCGETA +#undef TIOCSETN +#define TIOCSETN TCSETA +#undef TIOCSETP +#define TIOCSETP TCSETAF +#define TERMINAL struct termio +#else +#include <sys/ioctl.h> +#include <fcntl.h> +#include <sgtty.h> +#define TERMINAL struct sgttyb +#endif + +#ifdef SET_STACK_LIMIT_HUGE +#include <sys/time.h> +#include <sys/resource.h> +extern int original_stack_limit; +#endif /* SET_STACK_LIMIT_HUGE */ + +extern int errno; + +/* 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 int (*sigint_ours) (); +static int (*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 () +{ + if (remote_debugging) + return; + + 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 (remote_debugging) + return; + + 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 = (int (*) ()) signal (SIGINT, SIG_IGN); + sigquit_ours = (int (*) ()) 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 () +{ + if (remote_debugging) + return; + + 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 () +{ + if (remote_debugging) + return; + + 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 */ + + if (!terminal_is_ours) /* && inferior_thisrun_terminal == 0) */ + { + terminal_is_ours = 1; + +#ifdef TIOCGPGRP + osigttou = 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 */ +} + +static void +term_status_command () +{ + register int i; + + if (remote_debugging) + { + printf_filtered ("No terminal status when remote debugging.\n"); + return; + } + + 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 < 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 < sizeof (struct ltchars); i++) + printf_filtered ("0x%x ", ((char *)<c_inferior)[i]); + printf_filtered ("\n"); + ioctl (0, TIOCSLTC, <c_ours); +#endif + +#ifdef TIOCLGET + printf_filtered ("lmode: %x\n", lmode_inferior); +#endif +} + +static void +new_tty (ttyname) + char *ttyname; +{ + register int tty; + register int fd; + +#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) + _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); +} + +/* Start an inferior process and returns its pid. + ALLARGS is a string containing shell command to run the program. + ENV is the environment vector to pass. */ + +#ifndef SHELL_FILE +#define SHELL_FILE "/bin/sh" +#endif + +int +create_inferior (allargs, env) + char *allargs; + char **env; +{ + int pid; + char *shell_command; + extern int sys_nerr; + extern char *sys_errlist[]; + extern int errno; + + /* 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) + strlen (allargs) + 1); + strcpy (shell_command, SHELL_COMMAND_CONCAT); + strcat (shell_command, allargs); +#else + shell_command = allargs; +#endif + + /* exec is said to fail if the executable is open. */ + close_exec_file (); + +#if defined(USG) && !defined(HAVE_VFORK) + pid = fork (); +#else + pid = vfork (); +#endif + + if (pid < 0) + perror_with_name ("vfork"); + + if (pid == 0) + { +#ifdef TIOCGPGRP + /* Run inferior in a separate process group. */ + setpgrp (getpid (), getpid ()); +#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 */ + + + inferior_thisrun_terminal = inferior_io_terminal; + if (inferior_io_terminal != 0) + new_tty (inferior_io_terminal); + +/* It seems that changing the signal handlers for the inferior after + a vfork also changes them for the superior. See comments in + initialize_signals for how we get the right signal handlers + for the inferior. */ +/* Not needed on Sun, at least, and loses there + because it clobbers the superior. */ +/*??? signal (SIGQUIT, SIG_DFL); + signal (SIGINT, SIG_DFL); */ + + call_ptrace (0); + execle (SHELL_FILE, "sh", "-c", shell_command, 0, env); + + fprintf (stderr, "Cannot exec %s: %s.\n", SHELL_FILE, + errno < sys_nerr ? sys_errlist[errno] : "unknown error"); + fflush (stderr); + _exit (0177); + } + +#ifdef TIOCGPGRP + /* Avoid race with TIOCSPGRP: guarantee that inferior's pgrp exists. */ + setpgrp (pid, pid); +#endif /* TIOCGPGRP */ + +#ifdef CREATE_INFERIOR_HOOK + CREATE_INFERIOR_HOOK (pid); +#endif + return pid; +} + +/* Kill the inferior process. Make us have no inferior. */ + +static void +kill_command () +{ + if (remote_debugging) + { + inferior_pid = 0; + return; + } + if (inferior_pid == 0) + error ("The program is not being run."); + if (!query ("Kill the inferior process? ")) + error ("Not confirmed."); + kill_inferior (); +} + +void +inferior_died () +{ + inferior_pid = 0; + attach_flag = 0; + mark_breakpoints_out (); + select_frame ((FRAME) 0, -1); + reopen_exec_file (); + if (have_core_file_p ()) + set_current_frame ( create_new_frame (read_register (FP_REGNUM), + read_pc ())); + else + set_current_frame (0); +} + +#if 0 +/* This function is just for testing, and on some systems (Sony NewsOS + 3.2) <sys/user.h> also includes <sys/time.h> which leads to errors + (since on this system at least sys/time.h is not protected against + multiple inclusion). */ +static void +try_writing_regs_command () +{ + register int i; + register int value; + extern int errno; + + 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_com ("term-status", class_obscure, term_status_command, + "Print info on 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); + tflags_ours = fcntl (0, F_GETFL, 0); + +#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/gnu/usr.bin/gdb/infrun.c b/gnu/usr.bin/gdb/infrun.c new file mode 100644 index 0000000..887a0bb --- /dev/null +++ b/gnu/usr.bin/gdb/infrun.c @@ -0,0 +1,1459 @@ +/*- + * This code is derived from software copyrighted by the Free Software + * Foundation. + * + * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. + * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory. + */ + +#ifndef lint +static char sccsid[] = "@(#)infrun.c 6.4 (Berkeley) 5/8/91"; +#endif /* not lint */ + +/* Start and stop the 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. */ + +/* 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. + randy@wheaties.ai.mit.edu). This is true (albeit slipperly + so) on all machines I'm aware of: + + m68k: Call changes stack pointer. Regular jumps don't. + + sparc: Recursive calls must have frames and therefor, + prologues. + + vax: All calls have frames and hence change the + stack pointer. + + b) We did a return from a recursive call. I don't see that we + have either the ability or the need to distinguish this + from an ordinary jump. The stack frame will be printed + when and if the frame pointer changes; if we are in a + function without a frame pointer, it's the users own + lookout. + + c) We did a jump within a function. We assume that this is + true if we didn't do a recursive call. + + d) We are in no-man's land ("I see no symbols here"). We + don't worry about this; it will make calls look like simple + jumps (and the stack frames will be printed when the frame + pointer moves), which is a reasonably non-violent response. + +#if 0 + We skip this; it causes more problems than it's worth. +#ifdef SUN4_COMPILER_FEATURE + We do a special ifdef for the sun 4, forcing it to single step + into calls which don't have prologues. This means that we can't + nexti over leaf nodes, we can probably next over them (since they + won't have debugging symbols, usually), and we can next out of + functions returning structures (with a "call .stret4" at the end). +#endif +#endif +*/ + + + + + +#include <stdio.h> +#include "defs.h" +#include "param.h" +#include "symtab.h" +#include "frame.h" +#include "inferior.h" +#include "wait.h" + +#include <signal.h> + +/* unistd.h is needed to #define X_OK */ +#ifdef USG +#include <unistd.h> +#else +#include <sys/file.h> +#endif + +#ifdef UMAX_PTRACE +#include <aouthdr.h> +#include <sys/param.h> +#include <sys/ptrace.h> +#endif /* UMAX_PTRACE */ + +/* Required by <sys/user.h>. */ +#include <sys/types.h> +/* Required by <sys/user.h>, at least on system V. */ +#include <sys/dir.h> +/* Needed by IN_SIGTRAMP on some machines (e.g. vax). */ +#include <sys/param.h> +/* Needed by IN_SIGTRAMP on some machines (e.g. vax). */ +#include <sys/user.h> + +extern char *sys_siglist[]; +extern int errno; + +/* 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. */ + +static int breakpoints_inserted; + +/* Function inferior was in as of last step command. */ + +static struct symbol *step_start_function; + +/* This is the sequence of bytes we insert for a breakpoint. */ + +static char break_insn[] = BREAKPOINT; + +/* Nonzero => address for special breakpoint for resuming stepping. */ + +static CORE_ADDR step_resume_break_address; + +/* Original contents of the byte where the special breakpoint is. */ + +static char step_resume_break_shadow[sizeof break_insn]; + +/* 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. + 2 means expecting 2 trace traps and should continue both times. + That occurs when we tell sh to exec the program: we will get + a trap after the exec of sh and a second when the program is exec'd. */ + +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 trace trap due to attaching to a process. */ + +int stop_after_attach; + +/* Nonzero if pc has been changed by the debugger + since the inferior stopped. */ + +int pc_changed; + +/* Nonzero if debugging a remote machine via a serial link or ethernet. */ + +int remote_debugging; + +/* Nonzero if program stopped due to error trying to insert breakpoints. */ + +static int breakpoints_failed; + +/* Nonzero if inferior is in sh before our program got exec'd. */ + +static int running_in_shell; + +/* 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 (); +static 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_after_attach = 0; + + /* Discard any remaining commands left by breakpoint we had stopped at. */ + clear_breakpoint_commands (); +} + +/* Basic routine for continuing the program in various fashions. + + ADDR is the address to resume at, or -1 for resume where stopped. + SIGNAL 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, signal, step) + CORE_ADDR addr; + int signal; + 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); +#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. */ + terminal_inferior (); + + if (signal >= 0) + stop_signal = signal; + /* 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; + + /* Resume inferior. */ + resume (oneproc || 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 (); +} + +/* 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; +} + +/* Start an inferior process for the first time. + Actually it was started by the fork that created it, + but it will have stopped one instruction after execing sh. + Here we must get it up to actual execution of the real program. */ + +void +start_inferior () +{ + /* 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 + trap_expected = START_INFERIOR_TRAPS_EXPECTED; +#else + trap_expected = 2; +#endif + + running_in_shell = 0; /* Set to 1 at first SIGTRAP, 0 at second. */ + trap_expected_after_continue = 0; + breakpoints_inserted = 0; + mark_breakpoints_out (); + + /* Set up the "saved terminal modes" of the inferior + based on what modes we are starting it with. */ + terminal_init_inferior (); + + /* Install inferior's terminal modes. */ + terminal_inferior (); + + if (remote_debugging) + { + trap_expected = 0; + fetch_inferior_registers(); + set_current_frame (create_new_frame (read_register (FP_REGNUM), + read_pc ())); + stop_frame_address = FRAME_FP (get_current_frame()); + inferior_pid = 3; + if (insert_breakpoints()) + fatal("Can't insert breakpoints"); + breakpoints_inserted = 1; + proceed(-1, -1, 0); + } + else + { + wait_for_inferior (); + normal_stop (); + } +} + +/* Start or restart remote-debugging of a machine over a serial link. */ + +void +restart_remote () +{ + clear_proceed_status (); + running_in_shell = 0; + trap_expected = 0; + stop_after_attach = 1; + inferior_pid = 3; + wait_for_inferior (); + normal_stop(); +} + +void +start_remote () +{ + breakpoints_inserted = 0; + mark_breakpoints_out (); + restart_remote(); +} + +#ifdef ATTACH_DETACH + +/* Attach to process PID, then initialize for debugging it + and wait for the trace-trap that results from attaching. */ + +void +attach_program (pid) + int pid; +{ + attach (pid); + inferior_pid = pid; + + mark_breakpoints_out (); + terminal_init_inferior (); + clear_proceed_status (); + stop_after_attach = 1; + /*proceed (-1, 0, -2);*/ + 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. */ + +static void +wait_for_inferior () +{ + register int pid; + WAITTYPE w; + CORE_ADDR pc; + int tem; + int another_trap; + int random_signal; + CORE_ADDR stop_sp, prev_sp; + CORE_ADDR prev_func_start, stop_func_start; + char *prev_func_name, *stop_func_name; + CORE_ADDR prologue_pc; + int stop_step_resume_break; + CORE_ADDR step_resume_break_sp; + int newmisc; + int newfun_pc; + struct symtab_and_line sal; + int prev_pc; + extern CORE_ADDR text_end; + int remove_breakpoints_on_following_step = 0; + + 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); + + while (1) + { + /* Clean up saved state that will become invalid. */ + pc_changed = 0; + flush_cached_frames (); + + if (remote_debugging) + remote_wait (&w); + else + { + pid = wait (&w); + if (pid != inferior_pid) + continue; + } + + /* See if the process still exists; clean up if it doesn't. */ + if (WIFEXITED (w)) + { + terminal_ours_for_output (); + if (WEXITSTATUS (w)) + printf ("\nProgram exited with code 0%o.\n", WEXITSTATUS (w)); + else + printf ("\nProgram exited normally.\n"); + fflush (stdout); + inferior_died (); +#ifdef NO_SINGLE_STEP + one_stepped = 0; +#endif + stop_print_frame = 0; + break; + } + else if (!WIFSTOPPED (w)) + { + kill_inferior (); + stop_print_frame = 0; + stop_signal = WTERMSIG (w); + terminal_ours_for_output (); + printf ("\nProgram terminated with signal %d, %s\n", + stop_signal, + stop_signal < NSIG + ? sys_siglist[stop_signal] + : "(undocumented)"); + 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 */ + + fetch_inferior_registers (); + 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; + stop_breakpoint = 0; + 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_after_attach) + { + if (stop_signal == SIGTRAP && stop_after_trap) + { + stop_print_frame = 0; + break; + } + if (stop_after_attach) + break; + /* Don't even think about breakpoints + if still running the shell that will exec the program + or if just proceeded over a breakpoint. */ + if (stop_signal == SIGTRAP && trap_expected) + stop_breakpoint = 0; + 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 (stop_pc - DECR_PC_AFTER_BREAK + == 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_breakpoint = + breakpoint_stop_status (stop_pc, stop_frame_address); + /* Following in case break condition called a + function. */ + stop_print_frame = 1; + if (stop_breakpoint && DECR_PC_AFTER_BREAK) + { + stop_pc -= DECR_PC_AFTER_BREAK; + write_register (PC_REGNUM, stop_pc); +#ifdef NPC_REGNUM + write_register (NPC_REGNUM, stop_pc + 4); +#endif + pc_changed = 0; + } + } + } + } + + if (stop_signal == SIGTRAP) + random_signal + = !(stop_breakpoint || trap_expected + || stop_step_resume_break +#ifndef CANNOT_EXECUTE_STACK + || (stop_sp INNER_THAN stop_pc + && stop_pc INNER_THAN stop_frame_address) +#else + || stop_pc == text_end - 2 +#endif + || (step_range_end && !step_resume_break_address)); + else + { + random_signal + = !(stop_breakpoint + || stop_step_resume_break +#ifdef sony_news + || (stop_sp INNER_THAN stop_pc + && stop_pc INNER_THAN stop_frame_address) +#endif + + ); + 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 + && !(running_in_shell && stop_signal == SIGSEGV)) + { + /* Signal not for debugging purposes. */ + int printed = 0; + + stopped_by_random_signal = 1; + + if (stop_signal >= NSIG + || signal_print[stop_signal]) + { + printed = 1; + terminal_ours_for_output (); + printf ("\nProgram received signal %d, %s\n", + stop_signal, + stop_signal < NSIG + ? sys_siglist[stop_signal] + : "(undocumented)"); + 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) + terminal_inferior (); + } + + /* Handle cases caused by hitting a breakpoint. */ + + if (!random_signal + && (stop_breakpoint || stop_step_resume_break)) + { + /* Does a breakpoint want us to stop? */ + if (stop_breakpoint && stop_breakpoint != -1 + && stop_breakpoint != -0x1000001) + { + /* 0x1000000 is set in stop_breakpoint as returned by + breakpoint_stop_status to indicate a silent + breakpoint. */ + if ((stop_breakpoint > 0 ? stop_breakpoint : + -stop_breakpoint) + & 0x1000000) + { + stop_print_frame = 0; + if (stop_breakpoint > 0) + stop_breakpoint -= 0x1000000; + else + stop_breakpoint += 0x1000000; + } + 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; + } + /* 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. */ +#ifndef CANNOT_EXECUTE_STACK + if (stop_sp INNER_THAN stop_pc + && stop_pc INNER_THAN stop_frame_address) +#else + if (stop_pc == text_end - 2) +#endif + { + 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))) + { + /* 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; + } + } + + /* 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); + step_resume_break_sp = stop_sp; + 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 = + SAVED_PC_AFTER_CALL (get_current_frame ()); + step_resume_break_duplicate + = breakpoint_here_p (step_resume_break_address); + step_resume_break_sp = stop_sp; + 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_sp = stop_sp; + + 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; + } + } + + /* 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 is 2, it means continue once more + and insert breakpoints at the next trap. + If trap_expected is 1 and the signal was SIGSEGV, it means + the shell is doing some memory allocation--just resume it + with SIGSEGV. + Otherwise insert breakpoints now, and possibly single step. */ + + if (trap_expected > 1) + { + trap_expected--; + running_in_shell = 1; + resume (0, 0); + } + else if (running_in_shell && stop_signal == SIGSEGV) + { + resume (0, SIGSEGV); + } + else if (trap_expected && stop_signal != SIGTRAP) + { + /* We took a signal which we are supposed to pass through to + the inferior and we haven't yet gotten our trap. Simply + continue. */ + resume ((step_range_end && !step_resume_break_address) + || trap_expected, + stop_signal); + } + else + { + /* Here, we are not awaiting another exec to get + the program we really want to debug. + Insert breakpoints now, unless we are trying + to one-proceed past a breakpoint. */ + running_in_shell = 0; + /* 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 && !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; + + resume ((step_range_end && !step_resume_break_address) + || trap_expected, + stop_signal); + } + } +} + +/* Here to return control to GDB when the inferior stops for real. + Print appropriate messages, remove breakpoints, give terminal our modes. + + RUNNING_IN_SHELL nonzero means the shell got a signal before + exec'ing the program we wanted to run. + 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. */ + +static 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 (inferior_pid) + (get_current_frame ())->pc = read_pc (); + + if (breakpoints_failed) + { + 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 (inferior_pid) + remove_step_breakpoint (); + + if (inferior_pid && breakpoints_inserted) + if (remove_breakpoints ()) + { + terminal_ours_for_output (); + printf ("Cannot remove breakpoints because program is no longer writable.\n\ +It must 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_breakpoint); + + /* 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; + + terminal_ours (); + + if (running_in_shell) + { + if (stop_signal == SIGSEGV) + { + char *exec_file = (char *) get_exec_file (1); + + if (access (exec_file, X_OK) != 0) + printf ("The file \"%s\" is not executable.\n", exec_file); + else + /* I don't think we should ever get here. + wait_for_inferior now ignores SIGSEGV's which happen in + the shell (since the Bourne shell (/bin/sh) has some + rather, er, uh, *unorthodox* memory management + involving catching SIGSEGV). */ + printf ("\ +You have just encountered a bug in \"sh\". GDB starts your program\n\ +by running \"sh\" with a command to exec your program.\n\ +This is so that \"sh\" will process wildcards and I/O redirection.\n\ +This time, \"sh\" crashed.\n\ +\n\ +One known bug in \"sh\" bites when the environment takes up a lot of space.\n\ +Try \"info env\" to see the environment; then use \"delete env\" to kill\n\ +some variables whose values are large; then do \"run\" again.\n\ +\n\ +If that works, you might want to put those \"delete env\" commands\n\ +into a \".gdbinit\" file in this directory so they will happen every time.\n"); + } + /* Don't confuse user with his program's symbols on sh's data. */ + stop_print_frame = 0; + } + + if (inferior_pid == 0) + 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) + { + if (stop_breakpoint > 0) + printf ("\nBpt %d, ", stop_breakpoint); + print_sel_frame (stop_step + && step_frame_address == stop_frame_address + && step_start_function == find_pc_function (stop_pc)); + /* Display the auto-display expressions. */ + do_displays (); + } + } + + 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. */ +#ifndef NEW_CALL_FUNCTION + POP_FRAME; +#endif + select_frame (get_current_frame (), 0); + } +} + +static void +insert_step_breakpoint () +{ + if (step_resume_break_address && !step_resume_break_duplicate) + { + read_memory (step_resume_break_address, + step_resume_break_shadow, sizeof break_insn); + write_memory (step_resume_break_address, + break_insn, sizeof break_insn); + } +} + +static void +remove_step_breakpoint () +{ + if (step_resume_break_address && !step_resume_break_duplicate) + write_memory (step_resume_break_address, step_resume_break_shadow, + sizeof break_insn); +} + +/* 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; + + 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++); + for (digits = 0; p[digits] >= '0' && p[digits] <= '9'; digits++); + + /* If it is all digits, it is signal number to operate on. */ + if (digits == wordlen) + { + signum = atoi (p); + if (signum <= 0 || signum >= NSIG) + { + p[wordlen] = '\0'; + error ("Invalid signal %s given as argument to \"handle\".", p); + } + if (signum == SIGTRAP || signum == SIGINT) + { + if (!query ("Signal %d is used by the debugger.\nAre you sure you want to change it? ", signum)) + error ("Not confirmed."); + } + } + else if (signum == 0) + error ("First argument is not a signal number."); + + /* 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 + { + p[wordlen] = 0; + error ("Unrecognized flag word: \"%s\".", p); + } + + /* Find start of next word. */ + p += wordlen; + while (*p == ' ' || *p == '\t') p++; + } + + if (from_tty) + { + /* Show the results. */ + printf ("Number\tStop\tPrint\tPass to program\tDescription\n"); + printf ("%d\t", signum); + printf ("%s\t", signal_stop[signum] ? "Yes" : "No"); + printf ("%s\t", signal_print[signum] ? "Yes" : "No"); + printf ("%s\t\t", signal_program[signum] ? "Yes" : "No"); + printf ("%s\n", sys_siglist[signum]); + } +} + +/* Print current contents of the tables set by the handle command. */ + +static void +signals_info (signum_exp) + char *signum_exp; +{ + register int i; + printf_filtered ("Number\tStop\tPrint\tPass to program\tDescription\n"); + + if (signum_exp) + { + i = parse_and_eval_address (signum_exp); + if (i >= NSIG || i < 0) + error ("Signal number out of bounds."); + printf_filtered ("%d\t", i); + printf_filtered ("%s\t", signal_stop[i] ? "Yes" : "No"); + printf_filtered ("%s\t", signal_print[i] ? "Yes" : "No"); + printf_filtered ("%s\t\t", signal_program[i] ? "Yes" : "No"); + printf_filtered ("%s\n", sys_siglist[i]); + return; + } + + printf_filtered ("\n"); + for (i = 0; i < NSIG; i++) + { + QUIT; + + printf_filtered ("%d\t", i); + printf_filtered ("%s\t", signal_stop[i] ? "Yes" : "No"); + printf_filtered ("%s\t", signal_print[i] ? "Yes" : "No"); + printf_filtered ("%s\t\t", signal_program[i] ? "Yes" : "No"); + printf_filtered ("%s\n", sys_siglist[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). */ + +struct command_line *get_breakpoint_commands (); + +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_breakpoint = stop_breakpoint; + 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_after_attach = stop_after_attach; + inf_status->breakpoint_commands = get_breakpoint_commands (); + inf_status->restore_stack_info = restore_stack_info; + + read_register_bytes(0, inf_status->register_context, 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_breakpoint = inf_status->stop_breakpoint; + 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_after_attach = inf_status->stop_after_attach; + set_breakpoint_commands (inf_status->breakpoint_commands); + + write_register_bytes(0, inf_status->register_context, REGISTER_BYTES); + + /* The inferior can be gone if the user types "print exit(0)" + (and perhaps other times). */ + if (have_inferior_p() && inf_status->restore_stack_info) + { + flush_cached_frames(); + set_current_frame(create_new_frame(read_register (FP_REGNUM), + read_pc())); + + fid = find_relative_frame (get_current_frame (), &level); + + if (fid == 0 || + FRAME_FP (fid) != inf_status->selected_frame_address || + level != 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"); + select_frame (get_current_frame (), 0); + return; + } + + select_frame (fid, inf_status->selected_level); + } + return; +} + + +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/gnu/usr.bin/gdb/kgdb_proto.h b/gnu/usr.bin/gdb/kgdb_proto.h new file mode 100644 index 0000000..8bbd5be --- /dev/null +++ b/gnu/usr.bin/gdb/kgdb_proto.h @@ -0,0 +1,63 @@ +/*- + * Copyright (c) 1991 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Steven McCanne of Lawrence Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)kgdb_proto.h 6.3 (Berkeley) 5/8/91 + * + * + * $Header: /home/cvs/386BSD/src/usr.bin/gdb/kgdb_proto.h,v 1.1.1.1 1993/06/12 14:52:25 rgrimes Exp $ (LBL) + */ + +/* + * Message types. + */ +#define KGDB_MEM_R 0x01 +#define KGDB_MEM_W 0x02 +#define KGDB_REG_R 0x03 +#define KGDB_REG_W 0x04 +#define KGDB_CONT 0x05 +#define KGDB_STEP 0x06 +#define KGDB_KILL 0x07 +#define KGDB_SIGNAL 0x08 +#define KGDB_EXEC 0x09 + +#define KGDB_CMD(x) ((x) & 0x0f) + +/* + * Message flags. + */ +#define KGDB_ACK 0x80 +#define KGDB_DELTA 0x40 +#define KGDB_MORE 0x20 +#define KGDB_SEQ 0x10 diff --git a/gnu/usr.bin/gdb/main.c b/gnu/usr.bin/gdb/main.c new file mode 100644 index 0000000..06e1b9c --- /dev/null +++ b/gnu/usr.bin/gdb/main.c @@ -0,0 +1,2240 @@ +/*- + * This code is derived from software copyrighted by the Free Software + * Foundation. + * + * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. + * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory. + */ + +#ifndef lint +static char sccsid[] = "@(#)main.c 6.6 (Berkeley) 5/13/91"; +#endif /* not lint */ + +/* Top level for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1988, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <stdio.h> +#include "defs.h" +#include "command.h" +#include "param.h" +#include "expression.h" + +#ifdef USG +#include <sys/types.h> +#include <unistd.h> +#endif + +#include <sys/file.h> +#include <setjmp.h> +#include <signal.h> +#include <sys/param.h> +#include <sys/stat.h> +#include <ctype.h> + +#ifdef SET_STACK_LIMIT_HUGE +#include <sys/time.h> +#include <sys/resource.h> + +int original_stack_limit; +#endif + +/* If this definition isn't overridden by the header files, assume + that isatty and fileno exist on this system. */ +#ifndef ISATTY +#define ISATTY(FP) (isatty (fileno (FP))) +#endif + +extern void free (); + +/* Version number of GDB, as a string. */ + +extern char *version; + +/* + * Declare 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 \"set history\". */ + +struct cmd_list_element *sethistlist; + +/* 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]; + +#ifdef KERNELDEBUG +/* Nonzero if we're debugging /dev/mem or a kernel crash dump */ + +int kernel_debugging; +#endif + +/* Nonzero to inhibit confirmation of quitting or restarting + a stopped inferior. */ +int inhibit_confirm; + +/* Nonzero if we can write in text or core file */ + +int writeable_text; + +/* The number of lines on a page, and the number of spaces + in a line. */ +int linesize, pagesize; + +/* Nonzero if we should refrain from using an X window. */ + +int inhibit_windows = 0; + +/* 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 xgdb_verbose; + +void execute_command(); +void free_command_lines (); +char *gdb_readline (); +char *command_line_input (); +static void initialize_main (); +static void initialize_cmd_lists (); +void command_loop (); +static void source_command (); +static void print_gdb_version (); +static void float_handler (); +static void cd_command (); + +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; + + +/* This is how `error' returns to command level. */ + +jmp_buf to_top_level; + +void +return_to_top_level () +{ + quit_flag = 0; + immediate_quit = 0; + clear_breakpoint_commands (); + clear_momentary_breakpoints (); + disable_current_display (); + do_cleanups (0); + longjmp (to_top_level, 1); +} + +/* Call FUNC with arg ARG, 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, arg, errstring) + int (*func) (); + int arg; + 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) (arg); + else + { + 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). + Close the file opened by the command + and restore the previous input stream. */ + +static void +source_cleanup (stream) + FILE *stream; +{ + /* Instream may be 0; set to it when executing user-defined command. */ + if (instream) + fclose (instream); + instream = stream; +} + +/* + * Source $HOME/.gdbinit and $cwd/.gdbinit. + * If X is enabled, also $HOME/.xgdbinit and $cwd/.xgdbinit.source + */ +void +source_init_files() +{ + char *homedir, initfile[256]; + int samedir = 0; + + /* Read init file, if it exists in home directory */ + homedir = getenv ("HOME"); + if (homedir) { + struct stat homebuf, cwdbuf; + + sprintf(initfile, "%s/.gdbinit", homedir); + if (access (initfile, R_OK) == 0) + if (!setjmp (to_top_level)) + source_command (initfile); + if (!inhibit_windows) { + sprintf(initfile, "%s/.xgdbinit", homedir); + if (access (initfile, R_OK) == 0) + if (!setjmp (to_top_level)) + source_command (initfile); + } + /* Determine if current directory is the same as the home + directory, so we don't source the same file twice. */ + + bzero (&homebuf, sizeof (struct stat)); + bzero (&cwdbuf, sizeof (struct stat)); + + stat(homedir, &homebuf); + stat(".", &cwdbuf); + + samedir = bcmp(&homebuf, &cwdbuf, sizeof(struct stat)) == 0; + } + /* Read the input file in the current directory, *if* it isn't + the same file (it should exist, also). */ + if (!samedir) { + if (access (".gdbinit", R_OK) == 0) + if (!setjmp (to_top_level)) + source_command (".gdbinit"); + if (access (".xgdbinit", R_OK) == 0) + if (!setjmp (to_top_level)) + source_command (".xgdbinit"); + } +} + + +int +main (argc, argv, envp) + int argc; + char **argv; + char **envp; +{ + int count; + int inhibit_gdbinit = 0; + int quiet = 1; + int batch = 0; + register int i; + char *cp; + + /* XXX Windows only for xgdb. */ + char *strrchr(); + if (cp = strrchr(argv[0], '/')) + ++cp; + else + cp = argv[0]; + if (*cp != 'x') + inhibit_windows = 1; + +#if defined (ALIGN_STACK_ON_STARTUP) + i = (int) &count & 0x3; + if (i != 0) + alloca (4 - i); +#endif + + quit_flag = 0; + linesize = 100; + line = (char *) xmalloc (linesize); + *line = 0; + 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 */ + + /* Look for flag arguments. */ + + for (i = 1; i < argc; i++) + { + if (!strcmp (argv[i], "-q") || !strcmp (argv[i], "-quiet")) + quiet = 1; + else if (!strcmp (argv[i], "-nx")) + inhibit_gdbinit = 1; + else if (!strcmp (argv[i], "-nw")) + inhibit_windows = 1; + else if (!strcmp (argv[i], "-batch")) + batch = 1, quiet = 1; + else if (!strcmp (argv[i], "-fullname")) + frame_file_full_name = 1; + else if (!strcmp (argv[i], "-xgdb_verbose")) + xgdb_verbose = 1; + /* -help: print a summary of command line switches. */ + else if (!strcmp (argv[i], "-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\ + -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\ + -k Kernel debugging.\n\ + -w Writeable text.\n\ + -v Print GNU message and version number on startup.\n\ + -nc Don't confirm quit or run commands.\n\ +\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); + } +#ifdef KERNELDEBUG + else if (!strcmp (argv[i], "-k")) + kernel_debugging = 1; +#endif + else if (!strcmp (argv[i], "-w")) + writeable_text = 1; + else if (!strcmp (argv[i], "-v")) + quiet = 0; + else if (!strcmp (argv[i], "-nc")) + inhibit_confirm = 1; + else if (argv[i][0] == '-') + /* Other options take arguments, so don't confuse an + argument with an option. */ + i++; + } + + /* 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 */ + initialize_signals (); + + if (!quiet) + print_gdb_version (); + + /* Process the command line arguments. */ + + count = 0; + for (i = 1; i < argc; i++) + { + register char *arg = argv[i]; + /* Args starting with - say what to do with the following arg + as a filename. */ + if (arg[0] == '-') + { + extern void exec_file_command (), symbol_file_command (); + extern void core_file_command (), directory_command (); + extern void tty_command (); + + if (!strcmp (arg, "-q") || !strcmp (arg, "-nx") + || !strcmp (arg, "-quiet") || !strcmp (arg, "-batch") + || !strcmp (arg, "-fullname") || !strcmp (arg, "-nw") + || !strcmp (arg, "-xgdb_verbose") + || !strcmp (arg, "-help") + || !strcmp (arg, "-k") + || !strcmp (arg, "-w") + || !strcmp (arg, "-v") + || !strcmp (arg, "-nc")) + /* Already processed above */ + continue; + + if (++i == argc) + fprintf (stderr, "No argument follows \"%s\".\n", arg); + if (!setjmp (to_top_level)) + { + /* -s foo: get syms from foo. -e foo: execute foo. + -se foo: do both with foo. -c foo: use foo as core dump. */ + if (!strcmp (arg, "-se")) + { + exec_file_command (argv[i], !batch); + symbol_file_command (argv[i], !batch); + } + else if (!strcmp (arg, "-s") || !strcmp (arg, "-symbols")) + symbol_file_command (argv[i], !batch); + else if (!strcmp (arg, "-e") || !strcmp (arg, "-exec")) + exec_file_command (argv[i], !batch); + else if (!strcmp (arg, "-c") || !strcmp (arg, "-core")) + core_file_command (argv[i], !batch); + /* -x foo: execute commands from foo. */ + else if (!strcmp (arg, "-x") || !strcmp (arg, "-command") + || !strcmp (arg, "-commands")) + source_command (argv[i]); + /* -d foo: add directory `foo' to source-file directory + search-list */ + else if (!strcmp (arg, "-d") || !strcmp (arg, "-dir") + || !strcmp (arg, "-directory")) + directory_command (argv[i], 0); + /* -cd FOO: specify current directory as FOO. + GDB remembers the precise string FOO as the dirname. */ + else if (!strcmp (arg, "-cd")) + { + cd_command (argv[i], 0); + init_source_path (); + } + /* -t /def/ttyp1: use /dev/ttyp1 for inferior I/O. */ + else if (!strcmp (arg, "-t") || !strcmp (arg, "-tty")) + tty_command (argv[i], 0); + + else + error ("Unknown command-line switch: \"%s\"\n", arg); + } + } + else + { + /* Args not thus accounted for + are treated as, first, the symbol/executable file + and, second, the core dump file. */ + count++; + if (!setjmp (to_top_level)) + switch (count) + { + case 1: + exec_file_command (arg, !batch); + symbol_file_command (arg, !batch); + break; + + case 2: + core_file_command (arg, !batch); + break; + + case 3: + fprintf (stderr, "Excess command line args ignored. (%s%s)\n", + arg, (i == argc - 1) ? "" : " ..."); + } + } + } + + if (!inhibit_gdbinit) + source_init_files(); + + if (batch) + { +#if 0 + fatal ("Attempt to read commands from stdin in batch mode."); +#endif + /* We have hit the end of the batch file. */ + exit (0); + } + + if (!quiet) + printf ("Type \"help\" for a list of commands.\n"); + + /* The command loop. */ + + while (1) + { + if (!setjmp (to_top_level)) + command_loop (); + if (ISATTY(stdin)) + clearerr (stdin); /* Don't get hung if C-d is typed. */ + else if (feof(instream)) /* Avoid endless loops for redirected stdin */ + break; + } + exit (0); +} + + +static void +do_nothing () +{ +} + +/* Read commands from `instream' and execute them + until end of file. */ +void +command_loop () +{ + struct cleanup *old_chain; + register int toplevel = (instream == stdin); + register int interactive = (toplevel && ISATTY(stdin)); + + while (!feof (instream)) + { + register char *cmd_line; + + quit_flag = 0; + if (interactive) + reinitialize_more_filter (); + old_chain = make_cleanup (do_nothing, 0); + cmd_line = command_line_input (prompt, toplevel); + execute_command (cmd_line, toplevel); + /* Do any commands attached to breakpoint we stopped at. */ + do_breakpoint_commands (); + 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 PROMPT once at the start. + Action is compatible with "readline" (i.e., space for typing is + malloced & should be freed by caller). */ +char * +gdb_readline (prompt) + char *prompt; +{ + int c; + char *result; + int input_index = 0; + int result_size = 80; + + if (prompt) + { + printf (prompt); + fflush (stdout); + } + + result = (char *) xmalloc (result_size); + + while (1) + { + c = fgetc (instream ? instream : stdin); + if (c == EOF) + { + free(result); + return ((char *)0); + } + if (c == '\n') + break; + + result[input_index++] = c; + if (input_index >= result_size) + { + result_size <= 1; + result = (char *)xrealloc(result, result_size); + } + } + result[input_index++] = '\0'; + return result; +} + +/* 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. */ + +/* 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. */ +char * +symbol_completion_function (text, state) + char *text; + int state; +{ + char **make_symbol_completion_list (); + 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 (p + strlen(text) != tmp_command + rl_point) + 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 = make_symbol_completion_list (""); + } + else + { + if (c->prefixlist && !c->allow_unknown) + { + *p = '\0'; + error ("\"%s\" command requires a subcommand.", + tmp_command); + } + else + list = make_symbol_completion_list (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); +} + + +void +print_prompt () +{ + if (prompt) + { + printf ("%s", prompt); + fflush (stdout); + } +} + + +#ifdef HAVE_TERMIO +#include <termio.h> +static struct termio norm_tty; + +static void +suspend_sig() +{ + int tty = fileno(stdin); + struct termio cur_tty; + + ioctl(tty, TCGETA, &cur_tty); + ioctl(tty, TCSETAW, &norm_tty); + + (void) sigsetmask(0); + signal(SIGTSTP, SIG_DFL); + kill(0, SIGTSTP); + + /* + * we've just been resumed -- current tty params become new + * 'normal' params (in case tset/stty was done while we were + * suspended). Merge values that readline might have changed + * into new params, then restore term mode. + */ + ioctl(tty, TCGETA, &norm_tty); + cur_tty.c_lflag = (cur_tty.c_lflag & (ICANON|ECHO|ISIG)) | + (norm_tty.c_lflag &~ (ICANON|ECHO|ISIG)); + cur_tty.c_iflag = (cur_tty.c_iflag & (IXON|ISTRIP|INPCK)) | + (norm_tty.c_iflag &~ (IXON|ISTRIP|INPCK)); + ioctl(tty, TCSETAW, &cur_tty); + + signal(SIGTSTP, suspend_sig); + print_prompt(); + + /* + * Forget about any previous command -- null line now will do + * nothing. + */ + dont_repeat(); +} + +#else + +#include <sys/ioctl.h> +#include <fcntl.h> +#include <sgtty.h> + +static struct sgttyb norm_tty; +static struct tchars norm_tchars; +static struct ltchars norm_ltchars; +static int norm_lflags; + +#ifdef PASS8 +#define RL_TFLAGS (RAW|CRMOD|ECHO|CBREAK|PASS8) +#else +#define RL_TFLAGS (RAW|CRMOD|ECHO|CBREAK) +#endif + +static void +suspend_sig() +{ + int tty = fileno(stdin); + struct sgttyb cur_tty; + struct tchars cur_tchars; + struct ltchars cur_ltchars; + int cur_lflags; + int cur_flags; + + ioctl(tty, TIOCGETP, &cur_tty); + ioctl(tty, TIOCGETC, &cur_tchars); + ioctl(tty, TIOCLGET, &cur_lflags); + ioctl(tty, TIOCGLTC, &cur_ltchars); + + ioctl(tty, TIOCSETP, &norm_tty); + ioctl(tty, TIOCSETC, &norm_tchars); + ioctl(tty, TIOCLSET, &norm_lflags); + ioctl(tty, TIOCSLTC, &norm_ltchars); + + (void) sigsetmask(0); + signal(SIGTSTP, SIG_DFL); + kill(0, SIGTSTP); + + /* + * we've just been resumed -- current tty params become new + * 'normal' params (in case tset/stty was done while we were + * suspended). Merge values that readline might have changed + * into new params, then restore term mode. + */ + ioctl(tty, TIOCGETP, &norm_tty); + cur_flags = cur_tty.sg_flags; + cur_tty = norm_tty; + cur_tty.sg_flags = (cur_tty.sg_flags &~ RL_TFLAGS) + | (cur_flags & RL_TFLAGS); + + ioctl(tty, TIOCLGET, &norm_lflags); +#ifdef LPASS8 + cur_lflags = (cur_lflags &~ LPASS8) | (cur_flags & LPASS8); +#endif + ioctl(tty, TIOCGETC, &norm_tchars); + ioctl(tty, TIOCGLTC, &norm_ltchars); + + ioctl(tty, TIOCSETP, &cur_tty); + ioctl(tty, TIOCSETC, &cur_tchars); + ioctl(tty, TIOCLSET, &cur_lflags); + ioctl(tty, TIOCSLTC, &cur_ltchars); + + signal(SIGTSTP, suspend_sig); + print_prompt(); + + /* + * Forget about any previous command -- null line now will do + * nothing. + */ + dont_repeat(); +} +#endif /* HAVE_TERMIO */ + +/* Initialize signal handlers. */ +initialize_signals () +{ + extern void request_quit (); + int tty = fileno(stdin); + + 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); + + ioctl(tty, TIOCGETP, &norm_tty); + ioctl(tty, TIOCLGET, &norm_lflags); + ioctl(tty, TIOCGETC, &norm_tchars); + ioctl(tty, TIOCGLTC, &norm_ltchars); + signal(SIGTSTP, suspend_sig); +} + +char * +finish_command_input(inputline, repeat, interactive) + register char *inputline; + int repeat; + int interactive; +{ + static char *do_free; + + if (do_free) { + free(do_free); + do_free = NULL; + } + + /* Do history expansion if that is wished. */ + if (interactive && history_expansion_p) { + int expanded; + + expanded = history_expand(inputline, &do_free); + if (expanded) { + /* Print the changes. */ + puts(do_free); + + /* An error acts like no input. */ + if (expanded < 0) { + *do_free = 0; + return (do_free); + } + } + inputline = do_free; + } + /* get rid of any leading whitespace */ + while (isspace(*inputline)) + ++inputline; + /* + * If we just got an empty line, and that is supposed to repeat the + * previous command, return the value in the global buffer. + */ + if (*inputline == 0) { + if (repeat) + return (line); + } else if (interactive) + add_history(inputline); + + /* + * If line is a comment, clear it out. + * Note: 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 '#'. + */ + if (*inputline == '#') + *inputline = 0; + else if (repeat) { + /* Save into global buffer. */ + register int i = strlen(inputline) + 1; + + if (i > linesize) { + line = xrealloc(line, i); + linesize = i; + } + strcpy(line, inputline); + } + return (inputline); +} + +static char * +get_a_cmd_line(prompt, interactive) + char *prompt; + int interactive; +{ + register char *cp; + + /* Control-C quits instantly if typed while reading input. */ + immediate_quit++; + if (interactive && command_editing_p) { + extern void (*rl_event_hook)(); + + rl_event_hook = window_hook; + cp = readline(prompt); + } else { + if (interactive) { + if (window_hook) { + print_prompt(); + (*window_hook)(); + } + } else + prompt = NULL; + cp = gdb_readline(prompt); + } + --immediate_quit; + return (cp); +} + +/* Read one line from the command input stream `instream' + Returns the address of the start of the line. + + *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(prompt, repeat) + char *prompt; + int repeat; +{ + static char *do_free; + register int interactive = (instream == stdin && ISATTY(instream)); + register char *cp; + register int i; + + if (do_free) { + free(do_free); + do_free = NULL; + } + cp = get_a_cmd_line(prompt, interactive); + + /* + * handle continued lines (this loop is not particularly + * efficient because it's rare). + */ + while (cp && cp[i = strlen(cp) - 1] == '\\') { + register char *np = get_a_cmd_line(prompt, interactive); + register int j; + + if (np == NULL) { + cp[i] = 0; + break; + } + j = strlen(np); + cp = xrealloc(cp, i + j + 1); + strcpy(cp + i, np); + free(np); + } + if (cp == NULL) + return (""); + do_free = cp; + return (finish_command_input(cp, repeat, interactive)); +} + + +#define MAX_USER_ARGS 32 + +static struct user_args { + struct { + char *arg; + int len; + } a[10]; +} uargs[MAX_USER_ARGS]; + +static struct user_args *user_arg = uargs; + +static void +arg_cleanup(ap) + struct user_args *ap; +{ + user_arg = ap; +} + +/* Bind arguments $arg0, $arg1, ..., for a user defined command. */ +struct cleanup * +setup_user_args(p) + char *p; +{ + register int i; + struct cleanup *old_chain = make_cleanup(arg_cleanup, user_arg); + + if (++user_arg >= &uargs[MAX_USER_ARGS]) + error("user defined functions nested too deeply\n"); + + bzero(user_arg, sizeof(*user_arg)); + + i = 0; + while (*p) { + while (isspace(*p)) + ++p; + user_arg->a[i].arg = p; + while (*p && ! isspace(*p)) + ++p; + user_arg->a[i].len = p - user_arg->a[i].arg; + ++i; + } + return (old_chain); +} + +static char * +findarg(str) + register char *str; +{ + register char *cp = str; + extern char *index(); + + while (cp = index(cp, '$')) { + if (strncmp(cp, "$arg", 4) == 0 && isdigit(cp[4])) + return (cp); + ++cp; + } + return (char *)0; +} + +/* expand arguments from "line" into "new" */ +static void +expand_args(line, new) + register char *line, *new; +{ + register char *cp = findarg(line); + + while (cp = findarg(line)) { + int i, len; + + bcopy(line, new, cp - line); + new += cp - line; + i = cp[4] - '0'; + if (len = user_arg->a[i].len) { + bcopy(user_arg->a[i].arg, new, len); + new += len; + } + line = cp + 5; + } + strcpy(new, line); +} + +/* expand any arguments in "line" then execute the result */ +static void +expand_and_execute(line, from_tty) + char *line; + int from_tty; +{ + void execute_command(); + char new[1024]; + + if (! findarg(line)) { + execute_command(line, from_tty); + return; + } + expand_args(line, new); + execute_command(new, from_tty); +} + +char * +read_one_command_line(prompt, from_tty) + char *prompt; +{ + register char *p, *p1; + + dont_repeat(); + p = command_line_input(prompt, from_tty); + + /* Remove trailing blanks. */ + p1 = p + strlen(p); + while (--p1 > p && (*p1 == ' ' || *p1 == '\t')) + ; + *++p1 = 0; + return (p); +} + +static char cmd_prompt[] = " > "; + +int +parse_control_structure(rootcmd, from_tty, level) + struct command_line *rootcmd; + int from_tty; +{ + struct command_line *cmd = (struct command_line *)xmalloc(sizeof(*cmd)); + char *prompt; + + ++level; + prompt = from_tty? &cmd_prompt[sizeof(cmd_prompt) - 1 - 2*level] : + (char *)0; + bzero(cmd, sizeof(*cmd)); + rootcmd->body = cmd; + while (1) { + char *p = read_one_command_line(prompt, from_tty); + + p = savestring(p, strlen(p)); + cmd->line = p; + if (!strncmp(p, "while ", 6)) { + cmd->type = CL_WHILE; + if (parse_control_structure(cmd, from_tty, level)) + return (1); + } else if (!strncmp(p, "if ", 3)) { + cmd->type = CL_IF; + if (parse_control_structure(cmd, from_tty, level)) { + struct command_line *tmp; + int stat; + + cmd->elsebody = cmd->body; + stat = parse_control_structure(cmd, from_tty, + level); + tmp = cmd->elsebody; + cmd->elsebody = cmd->body; + cmd->body = tmp; + if (stat) + return (1); + } + } else if (!strcmp(p, "else")) { + cmd->type = CL_END; + return (1); + } else if (!strcmp(p, "end")) { + cmd->type = CL_END; + return (0); + } else if (!strcmp(p, "exitloop")) { + cmd->type = CL_EXITLOOP; + } else { + cmd->type = CL_NORMAL; + } + cmd->next = (struct command_line *)xmalloc(sizeof(*cmd)); + cmd = cmd->next; + bzero(cmd, sizeof(*cmd)); + } + /* NOTREACHED */ +} + +int +execute_control_structure(cmd) + register struct command_line *cmd; +{ + char expn[1024]; + struct expression *cond; + int stat; + + while (cmd) { + QUIT; + switch (cmd->type) { + case CL_END: + return (0); + case CL_NORMAL: + expand_and_execute(cmd->line, 0); + break; + case CL_WHILE: + expand_args(cmd->line + 6, expn); + cond = parse_c_expression(expn); + while (breakpoint_cond_eval(cond) == 0) + if (execute_control_structure(cmd->body)) + break; + free(cond); + break; + case CL_IF: + expand_args(cmd->line + 3, expn); + cond = parse_c_expression(expn); + stat = breakpoint_cond_eval(cond); + free(cond); + if (stat == 0) { + if (execute_control_structure(cmd->body)) + return (1); + } else if (cmd->elsebody) { + if (execute_control_structure(cmd->elsebody)) + return (1); + } + break; + case CL_EXITLOOP: + return (1); + } + cmd = cmd->next; + } + free_all_values(); +} + +execute_command_lines(cmd) + struct command_line *cmd; +{ + struct cleanup *old_chain = make_cleanup(source_cleanup, instream); + + /* + * Set the instream to 0, indicating execution of a user-defined + * function. + */ + ++immediate_quit; + instream = (FILE *) 0; + (void)execute_control_structure(cmd); + --immediate_quit; + do_cleanups(old_chain); +} + +/* do following command lines if expression true */ +if_command(p, from_tty) + char *p; + int from_tty; +{ + struct cleanup *old_chain; + struct command_line *cmd = (struct command_line *)xmalloc(sizeof(*cmd)); + char buf[128]; + + sprintf(buf, "if %s", p); + + bzero(cmd, sizeof(*cmd)); + old_chain = make_cleanup(free_command_lines, cmd); + cmd->type = CL_IF; + cmd->line = savestring(buf, strlen(buf)); + /* XXX cmd->line? */ + if (parse_control_structure(cmd, from_tty, 0)) { + struct command_line *tmp; + + cmd->elsebody = cmd->body; + (void) parse_control_structure(cmd, from_tty, 0); + tmp = cmd->elsebody; + cmd->elsebody = cmd->body; + cmd->body = tmp; + } + (void) execute_command_lines(cmd); + do_cleanups(old_chain); +} + +/* do following command lines while expression true */ +while_command(p, from_tty) + char *p; + int from_tty; +{ + struct cleanup *old_chain; + struct command_line *cmd = (struct command_line *)xmalloc(sizeof(*cmd)); + char buf[128]; + + sprintf(buf, "while %s", p); + + bzero(cmd, sizeof(*cmd)); + old_chain = make_cleanup(free_command_lines, cmd); + cmd->type = CL_WHILE; + cmd->line = savestring(buf, strlen(buf)); + (void)parse_control_structure(cmd, from_tty, 0); + (void)execute_command_lines(cmd); + do_cleanups(old_chain); +} + +/* + * 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(); + if (*p) { + c = lookup_cmd(&p, cmdlist, "", 0, 1); + if (c->function == 0) + error("That is not a command, just a help topic."); + else if (c->class == (int) class_user) { + struct cleanup *old_chain = setup_user_args(p); + + cmdlines = (struct command_line *) c->function; + if (cmdlines) + (void)execute_command_lines(cmdlines); + + do_cleanups(old_chain); + } else + /* Pass null arg rather than an empty one. */ + (*c->function) (*p ? p : 0, from_tty); + } +} + +/* + * 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(from_tty) + int from_tty; +{ + struct cleanup *old_chain; + struct command_line *cmd = (struct command_line *)xmalloc(sizeof(*cmd)); + struct command_line *next; + + bzero(cmd, sizeof(*cmd)); + old_chain = make_cleanup(free_command_lines, cmd); + cmd->type = CL_NOP; + (void)parse_control_structure(cmd, from_tty, 0); + dont_repeat(); + discard_cleanups(old_chain); + next = cmd->body; + free(cmd); + return (next); +} + +/* Free a chain of struct command_line's. */ + +void +free_command_lines(cmds) + struct command_line *cmds; +{ + struct command_line *next; + + while (cmds) { + if (cmds->body) + free(cmds->body); + if (cmds->elsebody) + free(cmds->elsebody); + if (cmds->line) + free(cmds->line); + next = cmds->next; + free(cmds); + cmds = 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. */ + +static void +info_command () +{ + printf ("\"info\" must be followed by the name of an info command.\n"); + help_list (infolist, "info ", -1, stdout); +} + +/* Add an element to the list of commands. */ + +void +add_com (name, class, fun, doc) + char *name; + int 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; + int 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; + char *tem = comname; + + validate_comname (comname); + + c = lookup_cmd (&tem, cmdlist, "", -1, 1); + if (c) + { + if (c->class == (int) class_user || c->class == (int) 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 (from_tty); + + if (c && c->class == (int) class_user) + free_command_lines (c->function); + + add_com (comname, class_user, cmds, + (c && c->class == (int) class_user) + ? c->doc : savestring ("User-defined.", 13)); +} + +static void +document_command (comname, from_tty) + char *comname; + int from_tty; +{ + register struct cmd_list_element *c; + register char *p; + register char *cp; + register char *doc = 0; + register int len; + char *tmp = comname; + + validate_comname (comname); + c = lookup_cmd (&tmp, cmdlist, "", 0, 1); + if (c->class != (int) class_user) + error ("Command \"%s\" is built-in.", comname); + + if (from_tty) + printf ("Type documentation for \"%s\". \ +End with a line saying just \"end\".\n", comname); + + while (p = read_one_command_line(from_tty? "> " : 0, from_tty)) + { + if (strcmp(p, "end") == 0) + break; + len = strlen(p) + 1; + if (! doc) + { + doc = xmalloc(len); + cp = doc; + } + else + { + int i = cp - doc; + doc = xrealloc(doc, i + len); + cp = doc + i; + } + strcpy(cp, p); + cp += len; + cp[-1] = '\n'; + } + if (doc && cp > doc) + cp[-1] = 0; + if (c->doc) + free (c->doc); + c->doc = doc; +} + +static void +print_gdb_version () +{ + printf ("GDB %s, Copyright (C) 1989 Free Software Foundation, Inc.\n\ +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", + version); +} + +static void +version_info () +{ + immediate_quit++; + print_gdb_version (); + immediate_quit--; +} + + +/* Command to specify a prompt string instead of "(gdb) ". */ + +void +set_prompt_command (text) + char *text; +{ + char *p, *q; + register int c; + char *new; + + if (text == 0) + error_no_arg ("string to which to set prompt"); + + new = (char *) xmalloc (strlen (text) + 2); + p = text; q = new; + while (c = *p++) + { + if (c == '\\') + { + /* \ at end of argument is used after spaces + so they won't be lost. */ + if (*p == 0) + break; + c = parse_escape (&p); + if (c == 0) + break; /* C loses */ + else if (c > 0) + *q++ = c; + } + else + *q++ = c; + } + if (*(p - 1) != '\\') + *q++ = ' '; + *q++ = '\0'; + new = (char *) xrealloc (new, q - new); + free (prompt); + prompt = new; +} + +static void +quit_command () +{ + if (have_inferior_p ()) + { + if (inhibit_confirm || query ("The program is running. Quit anyway? ")) + { + /* Prevent any warning message from reopen_exec_file, in case + we have a core file that's inconsistent with the exec file. */ + exec_file_command (0, 0); + kill_inferior (); + } + 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; +} + +static void +pwd_command (arg, from_tty) + char *arg; + int from_tty; +{ + if (arg) error ("The \"pwd\" command does not take an argument: %s", arg); + 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); + + if (from_tty) + pwd_command ((char *) 0, 1); +} + +static void +source_command (arg, from_tty) + char *arg; + int from_tty; +{ + FILE *stream; + struct cleanup *cleanups; + char *file = arg; + char *path; + + if (file == 0) + /* Let source without arguments read .gdbinit. */ + file = ".gdbinit"; + + file = tilde_expand (file); + make_cleanup (free, file); + +#ifdef KERNELDEBUG + if (path = getenv(kernel_debugging? "KGDBPATH" : "GDBPATH")) +#else + if (path = getenv("GDBPATH")) +#endif + { + int fd = openp(path, 1, file, O_RDONLY, 0, 0); + + if (fd == -1) + stream = 0; + else + stream = fdopen(fd, "r"); + } + else + stream = fopen (file, "r"); + + if (stream == 0) + perror_with_name (file); + + cleanups = make_cleanup (source_cleanup, instream); + + instream = stream; + + command_loop (); + + do_cleanups (cleanups); +} + +static void +echo_command (text) + char *text; +{ + 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); + } + fflush(stdout); +} + +static void +dump_me_command () +{ + if (query ("Should GDB dump core? ")) + { + signal (SIGQUIT, SIG_DFL); + kill (getpid (), SIGQUIT); + } +} + +int +parse_binary_operation (caller, arg) + char *caller, *arg; +{ + int length; + + if (!arg || !*arg) + return 1; + + length = strlen (arg); + + while (arg[length - 1] == ' ' || arg[length - 1] == '\t') + length--; + + if (!strncmp (arg, "on", length) + || !strncmp (arg, "1", length) + || !strncmp (arg, "yes", length)) + return 1; + else + if (!strncmp (arg, "off", length) + || !strncmp (arg, "0", length) + || !strncmp (arg, "no", length)) + return 0; + else + error ("\"%s\" not given a binary valued argument.", caller); +} + +/* Functions to manipulate command line editing control variables. */ + +static void +set_editing (arg, from_tty) + char *arg; + int from_tty; +{ + command_editing_p = parse_binary_operation ("set command-editing", arg); +} + +/* Number of commands to print in each call to editing_info. */ +#define Hist_print 10 +static void +editing_info (arg, from_tty) + char *arg; + 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 { + char *line; + char *data; + } *history_get(); + extern int history_base; + + 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 : ""); + + /* 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 (arg) + { + if (arg[0] == '+' && arg[1] == '\0') + /* "info editing +" should print from the stored position. */ + ; + else + /* "info editing <exp>" should print around command number <exp>. */ + num = (parse_and_eval_address (arg) - 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 (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"); + + 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 && arg) + { + arg[0] = '+'; + arg[1] = '\0'; + } +} + +static void +set_history_expansion (arg, from_tty) + char *arg; + int from_tty; +{ + history_expansion_p = parse_binary_operation ("set history expansion", arg); +} + +static void +set_history_write (arg, from_tty) + char *arg; + int from_tty; +{ + write_history_p = parse_binary_operation ("set history write", arg); +} + +static void +set_history (arg, from_tty) + char *arg; + 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 +set_history_size (arg, from_tty) + char *arg; + int from_tty; +{ + if (!*arg) + error_no_arg ("set history size"); + + history_size = atoi (arg); +} + +static void +set_history_filename (arg, from_tty) + char *arg; + int from_tty; +{ + int i; + + if (!arg) + error_no_arg ("history file name"); + + arg = tilde_expand (arg); + make_cleanup (free, arg); + + i = strlen (arg) - 1; + + free (history_filename); + + while (i > 0 && (arg[i] == ' ' || arg[i] == '\t')) + i--; + ++i; + + if (!*arg) + history_filename = (char *) 0; + else + history_filename = savestring (arg, i + 1); + history_filename[i] = '\0'; +} + +int info_verbose; + +static void +set_verbose_command (arg, from_tty) + char *arg; + int from_tty; +{ + info_verbose = parse_binary_operation ("set verbose", arg); +} + +static void +verbose_info (arg, from_tty) + char *arg; + int from_tty; +{ + if (arg) + error ("\"info verbose\" does not take any arguments.\n"); + + printf ("Verbose printing of information is %s.\n", + info_verbose ? "on" : "off"); +} + +static void +float_handler () +{ + error ("Invalid floating value encountered or computed."); +} + + +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; + sethistlist = (struct cmd_list_element *) 0; + unsethistlist = (struct cmd_list_element *) 0; +} + +static void +initialize_main () +{ + char *tmpenv; + /* Command line editing externals. */ + extern int (*rl_completion_entry_function)(); + extern char *rl_completer_word_break_characters; + extern char *rl_readline_name; + + /* Set default verbose mode on. */ + info_verbose = 1; + +#ifdef KERNELDEBUG + if (kernel_debugging) + prompt = savestring ("(kgdb) ", 7); + else +#endif + prompt = savestring ("(gdb) ", 6); + + /* 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, 0, "Obscure features.", &cmdlist); + add_cmd ("alias", class_alias, 0, "Aliases of other commands.", &cmdlist); + add_cmd ("user", class_user, 0, "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, 0, "Support facilities.", &cmdlist); + add_cmd ("status", class_info, 0, "Status inquiries.", &cmdlist); + add_cmd ("files", class_files, 0, "Specifying and examining files.", &cmdlist); + add_cmd ("breakpoints", class_breakpoint, 0, "Making program stop at certain points.", &cmdlist); + add_cmd ("data", class_vars, 0, "Examining data.", &cmdlist); + add_cmd ("stack", class_stack, 0, "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, 0, "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_cmd ("prompt", class_support, set_prompt_command, + "Change gdb's prompt from the default of \"(gdb)\"", + &setlist); + 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."); + + 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."); + 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); + add_com ("while", class_support, while_command, + "execute following commands while condition is true.\n\ +Expression for condition follows \"while\" keyword."); + add_com ("if", class_support, if_command, + "execute following commands if condition is true.\n\ +Expression for condition follows \"if\" keyword."); + add_cmd ("verbose", class_support, set_verbose_command, + "Change the number of informational messages gdb prints.", + &setlist); + add_info ("verbose", verbose_info, + "Status of gdb's verbose printing option.\n"); + + add_com ("dump-me", class_obscure, dump_me_command, + "Get fatal error; make debugger dump its core."); + + add_cmd ("editing", class_support, set_editing, + "Enable or disable 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); + + add_prefix_cmd ("history", class_support, set_history, + "Generic command for setting command history parameters.", + &sethistlist, "set history ", 0, &setlist); + + add_cmd ("expansion", no_class, set_history_expansion, + "Enable or disable history expansion on command input.\n\ +Without an argument, history expansion is enabled.", &sethistlist); + + add_cmd ("write", no_class, set_history_write, + "Enable or disable 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); + + add_cmd ("size", no_class, set_history_size, + "Set the size of the command history, \n\ +ie. the number of previous commands to keep a record of.", &sethistlist); + + add_cmd ("filename", no_class, set_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); + + 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_info ("editing", editing_info, "Status of command editor."); + + add_info ("version", version_info, "Report what version of GDB this is."); +} diff --git a/gnu/usr.bin/gdb/ngdb.i386/Makefile b/gnu/usr.bin/gdb/ngdb.i386/Makefile new file mode 100644 index 0000000..3bf4c6c --- /dev/null +++ b/gnu/usr.bin/gdb/ngdb.i386/Makefile @@ -0,0 +1,27 @@ +# %W% (Berkeley) %G% + +.include "../config/Makefile.$(MACHINE)" + +PROG= ngdb +SRCS= i386bsd-dep.c blockframe.c +GDBOBJS+= i386-pinsn.o \ + breakpoint.o command.o copying.o core.o \ + cplus-dem.o dbxread.o environ.o eval.o expprint.o \ + expread.o findvar.o infcmd.o inflow.o infrun.o \ + main.o obstack.o printcmd.o regex.o remote.o \ + remote-sl.o source.o stack.o symmisc.o symtab.o \ + utils.o valarith.o valops.o valprint.o values.o \ + version.o \ + funmap.o history.o keymaps.o readline.o \ + init.o +CFLAGS+= -g -I$(.CURDIR) -I.. -I$(.CURDIR)/.. -I$(.CURDIR)/../config \ + -I/usr/src/sys.newvm \ + -DNEWVM -DHAVE_VPRINTF -DVI_MODE -DKERNELDEBUG +# CC= /usr/old/bin/cc +# CC= cc -traditional +LDADD+= $(GDBOBJS:S/^/..\//g) -ltermcap +NOMAN= noman + +.PATH: $(.CURDIR)/../config $(.CURDIR)/.. + +.include <bsd.prog.mk> diff --git a/gnu/usr.bin/gdb/obstack.c b/gnu/usr.bin/gdb/obstack.c new file mode 100644 index 0000000..6f4b282 --- /dev/null +++ b/gnu/usr.bin/gdb/obstack.c @@ -0,0 +1,313 @@ +/* obstack.c - subroutines used implicitly by object stack macros + Copyright (C) 1988 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, 675 Mass Ave, Cambridge, MA 02139, USA. + + +In other words, you are welcome to use, share and improve this program. +You are forbidden to forbid anyone else to use, share and improve +what you give them. Help stamp out software-hoarding! */ + + +#include "obstack.h" + +#ifdef __STDC__ +#define POINTER void * +#else +#define POINTER char * +#endif + +/* Determine default alignment. */ +struct fooalign {char x; double d;}; +#define DEFAULT_ALIGNMENT ((char *)&((struct fooalign *) 0)->d - (char *)0) +/* If malloc were really smart, it would round addresses to DEFAULT_ALIGNMENT. + But in fact it might be less smart and round addresses to as much as + DEFAULT_ROUNDING. So we prepare for it to do that. */ +union fooround {long x; double d;}; +#define DEFAULT_ROUNDING (sizeof (union fooround)) + +/* When we copy a long block of data, this is the unit to do it with. + On some machines, copying successive ints does not work; + in such a case, redefine COPYING_UNIT to `long' (if that works) + or `char' as a last resort. */ +#ifndef COPYING_UNIT +#define COPYING_UNIT int +#endif + +/* The non-GNU-C macros copy the obstack into this global variable + to avoid multiple evaluation. */ + +struct obstack *_obstack; + +/* Initialize an obstack H for use. Specify chunk size SIZE (0 means default). + Objects start on multiples of ALIGNMENT (0 means use default). + CHUNKFUN is the function to use to allocate chunks, + and FREEFUN the function to free them. */ + +void +_obstack_begin (h, size, alignment, chunkfun, freefun) + struct obstack *h; + int size; + int alignment; + POINTER (*chunkfun) (); + void (*freefun) (); +{ + register struct _obstack_chunk* chunk; /* points to new chunk */ + + if (alignment == 0) + alignment = DEFAULT_ALIGNMENT; + if (size == 0) + /* Default size is what GNU malloc can fit in a 4096-byte block. + Pick a number small enough that when rounded up to DEFAULT_ROUNDING + it is still smaller than 4096 - 4. */ + { + int extra = 4; + if (extra < DEFAULT_ROUNDING) + extra = DEFAULT_ROUNDING; + size = 4096 - extra; + } + + h->chunkfun = (struct _obstack_chunk * (*)()) chunkfun; + h->freefun = freefun; + h->chunk_size = size; + h->alignment_mask = alignment - 1; + + chunk = h->chunk = (*h->chunkfun) (h->chunk_size); + h->next_free = h->object_base = chunk->contents; + h->chunk_limit = chunk->limit + = (char *) chunk + h->chunk_size; + chunk->prev = 0; +} + +/* Allocate a new current chunk for the obstack *H + on the assumption that LENGTH bytes need to be added + to the current object, or a new object of length LENGTH allocated. + Copies any partial object from the end of the old chunk + to the beginning of the new one. */ + +void +_obstack_newchunk (h, length) + struct obstack *h; + int length; +{ + register struct _obstack_chunk* old_chunk = h->chunk; + register struct _obstack_chunk* new_chunk; + register long new_size; + register int obj_size = h->next_free - h->object_base; + register int i; + + /* Compute size for new chunk. */ + new_size = (obj_size + length) << 1; + if (new_size < h->chunk_size) + new_size = h->chunk_size; + + /* Allocate and initialize the new chunk. */ + new_chunk = h->chunk = (*h->chunkfun) (new_size); + new_chunk->prev = old_chunk; + new_chunk->limit = h->chunk_limit = (char *) new_chunk + new_size; + + /* Move the existing object to the new chunk. + Word at a time is fast and is safe because these + structures are aligned at least that much. */ + for (i = (obj_size + sizeof (COPYING_UNIT) - 1) / sizeof (COPYING_UNIT) - 1; + i >= 0; i--) + ((COPYING_UNIT *)new_chunk->contents)[i] + = ((COPYING_UNIT *)h->object_base)[i]; + + h->object_base = new_chunk->contents; + h->next_free = h->object_base + obj_size; +} + +/* Return nonzero if object OBJ has been allocated from obstack H. + This is here for debugging. + If you use it in a program, you are probably losing. */ + +int +_obstack_allocated_p (h, obj) + struct obstack *h; + POINTER obj; +{ + register struct _obstack_chunk* lp; /* below addr of any objects in this chunk */ + register struct _obstack_chunk* plp; /* point to previous chunk if any */ + + lp = (h)->chunk; + while (lp != 0 && ((POINTER)lp > obj || (POINTER)(lp)->limit < obj)) + { + plp = lp -> prev; + lp = plp; + } + return lp != 0; +} + +/* Free objects in obstack H, including OBJ and everything allocate + more recently than OBJ. If OBJ is zero, free everything in H. */ + +void +#ifdef __STDC__ +#undef obstack_free +obstack_free (struct obstack *h, POINTER obj) +#else +_obstack_free (h, obj) + struct obstack *h; + POINTER obj; +#endif +{ + register struct _obstack_chunk* lp; /* below addr of any objects in this chunk */ + register struct _obstack_chunk* plp; /* point to previous chunk if any */ + + lp = (h)->chunk; + while (lp != 0 && ((POINTER)lp > obj || (POINTER)(lp)->limit < obj)) + { + plp = lp -> prev; + (*h->freefun) (lp); + lp = plp; + } + if (lp) + { + (h)->object_base = (h)->next_free = (char *)(obj); + (h)->chunk_limit = lp->limit; + (h)->chunk = lp; + } + else if (obj != 0) + /* obj is not in any of the chunks! */ + abort (); +} + +/* Let same .o link with output of gcc and other compilers. */ + +#ifdef __STDC__ +void +_obstack_free (h, obj) + struct obstack *h; + POINTER obj; +{ + obstack_free (h, obj); +} +#endif + +#if 0 +/* These are now turned off because the applications do not use it + and it uses bcopy via obstack_grow, which causes trouble on sysV. */ + +/* Now define the functional versions of the obstack macros. + Define them to simply use the corresponding macros to do the job. */ + +#ifdef __STDC__ +/* These function definitions do not work with non-ANSI preprocessors; + they won't pass through the macro names in parentheses. */ + +/* The function names appear in parentheses in order to prevent + the macro-definitions of the names from being expanded there. */ + +POINTER (obstack_base) (obstack) + struct obstack *obstack; +{ + return obstack_base (obstack); +} + +POINTER (obstack_next_free) (obstack) + struct obstack *obstack; +{ + return obstack_next_free (obstack); +} + +int (obstack_object_size) (obstack) + struct obstack *obstack; +{ + return obstack_object_size (obstack); +} + +int (obstack_room) (obstack) + struct obstack *obstack; +{ + return obstack_room (obstack); +} + +void (obstack_grow) (obstack, pointer, length) + struct obstack *obstack; + POINTER pointer; + int length; +{ + obstack_grow (obstack, pointer, length); +} + +void (obstack_grow0) (obstack, pointer, length) + struct obstack *obstack; + POINTER pointer; + int length; +{ + obstack_grow0 (obstack, pointer, length); +} + +void (obstack_1grow) (obstack, character) + struct obstack *obstack; + int character; +{ + obstack_1grow (obstack, character); +} + +void (obstack_blank) (obstack, length) + struct obstack *obstack; + int length; +{ + obstack_blank (obstack, length); +} + +void (obstack_1grow_fast) (obstack, character) + struct obstack *obstack; + int character; +{ + obstack_1grow_fast (obstack, character); +} + +void (obstack_blank_fast) (obstack, length) + struct obstack *obstack; + int length; +{ + obstack_blank_fast (obstack, length); +} + +POINTER (obstack_finish) (obstack) + struct obstack *obstack; +{ + return obstack_finish (obstack); +} + +POINTER (obstack_alloc) (obstack, length) + struct obstack *obstack; + int length; +{ + return obstack_alloc (obstack, length); +} + +POINTER (obstack_copy) (obstack, pointer, length) + struct obstack *obstack; + POINTER pointer; + int length; +{ + return obstack_copy (obstack, pointer, length); +} + +POINTER (obstack_copy0) (obstack, pointer, length) + struct obstack *obstack; + POINTER pointer; + int length; +{ + return obstack_copy0 (obstack, pointer, length); +} + +#endif /* __STDC__ */ + +#endif /* 0 */ diff --git a/gnu/usr.bin/gdb/obstack.h b/gnu/usr.bin/gdb/obstack.h new file mode 100644 index 0000000..27c017e --- /dev/null +++ b/gnu/usr.bin/gdb/obstack.h @@ -0,0 +1,372 @@ +/* obstack.h - object stack macros + Copyright (C) 1988 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, 675 Mass Ave, Cambridge, MA 02139, USA. + + +In other words, you are welcome to use, share and improve this program. +You are forbidden to forbid anyone else to use, share and improve +what you give them. Help stamp out software-hoarding! */ + + +/* Summary: + +All the apparent functions defined here are macros. The idea +is that you would use these pre-tested macros to solve a +very specific set of problems, and they would run fast. +Caution: no side-effects in arguments please!! They may be +evaluated MANY times!! + +These macros operate a stack of objects. Each object starts life +small, and may grow to maturity. (Consider building a word syllable +by syllable.) An object can move while it is growing. Once it has +been "finished" it never changes address again. So the "top of the +stack" is typically an immature growing object, while the rest of the +stack is of mature, fixed size and fixed address objects. + +These routines grab large chunks of memory, using a function you +supply, called `obstack_chunk_alloc'. On occasion, they free chunks, +by calling `obstack_chunk_free'. You must define them and declare +them before using any obstack macros. + +Each independent stack is represented by a `struct obstack'. +Each of the obstack macros expects a pointer to such a structure +as the first argument. + +One motivation for this package is the problem of growing char strings +in symbol tables. Unless you are "facist pig with a read-only mind" +[Gosper's immortal quote from HAKMEM item 154, out of context] you +would not like to put any arbitrary upper limit on the length of your +symbols. + +In practice this often means you will build many short symbols and a +few long symbols. At the time you are reading a symbol you don't know +how long it is. One traditional method is to read a symbol into a +buffer, realloc()ating the buffer every time you try to read a symbol +that is longer than the buffer. This is beaut, but you still will +want to copy the symbol from the buffer to a more permanent +symbol-table entry say about half the time. + +With obstacks, you can work differently. Use one obstack for all symbol +names. As you read a symbol, grow the name in the obstack gradually. +When the name is complete, finalize it. Then, if the symbol exists already, +free the newly read name. + +The way we do this is to take a large chunk, allocating memory from +low addresses. When you want to build a aymbol in the chunk you just +add chars above the current "high water mark" in the chunk. When you +have finished adding chars, because you got to the end of the symbol, +you know how long the chars are, and you can create a new object. +Mostly the chars will not burst over the highest address of the chunk, +because you would typically expect a chunk to be (say) 100 times as +long as an average object. + +In case that isn't clear, when we have enough chars to make up +the object, THEY ARE ALREADY CONTIGUOUS IN THE CHUNK (guaranteed) +so we just point to it where it lies. No moving of chars is +needed and this is the second win: potentially long strings need +never be explicitly shuffled. Once an object is formed, it does not +change its address during its lifetime. + +When the chars burst over a chunk boundary, we allocate a larger +chunk, and then copy the partly formed object from the end of the old +chunk to the beggining of the new larger chunk. We then carry on +accreting characters to the end of the object as we normaly would. + +A special macro is provided to add a single char at a time to a +growing object. This allows the use of register variables, which +break the ordinary 'growth' macro. + +Summary: + We allocate large chunks. + We carve out one object at a time from the current chunk. + Once carved, an object never moves. + We are free to append data of any size to the currently + growing object. + Exactly one object is growing in an obstack at any one time. + You can run one obstack per control block. + You may have as many control blocks as you dare. + Because of the way we do it, you can `unwind' a obstack + back to a previous state. (You may remove objects much + as you would with a stack.) +*/ + + +/* Don't do the contents of this file more than once. */ + +#ifndef __OBSTACKS__ +#define __OBSTACKS__ + +/* We use subtraction of (char *)0 instead of casting to int + because on word-addressable machines a simple cast to int + may ignore the byte-within-word field of the pointer. */ + +#ifndef __PTR_TO_INT +#define __PTR_TO_INT(P) ((P) - (char *)0) +#endif + +#ifndef __INT_TO_PTR +#define __INT_TO_PTR(P) ((P) + (char *)0) +#endif + +struct _obstack_chunk /* Lives at front of each chunk. */ +{ + char *limit; /* 1 past end of this chunk */ + struct _obstack_chunk *prev; /* address of prior chunk or NULL */ + char contents[4]; /* objects begin here */ +}; + +struct obstack /* control current object in current chunk */ +{ + long chunk_size; /* preferred size to allocate chunks in */ + struct _obstack_chunk* chunk; /* address of current struct obstack_chunk */ + char *object_base; /* address of object we are building */ + char *next_free; /* where to add next char to current object */ + char *chunk_limit; /* address of char after current chunk */ + int temp; /* Temporary for some macros. */ + int alignment_mask; /* Mask of alignment for each object. */ + struct _obstack_chunk *(*chunkfun) (); /* User's fcn to allocate a chunk. */ + void (*freefun) (); /* User's function to free a chunk. */ +}; + +#ifdef __STDC__ + +/* Do the function-declarations after the structs + but before defining the macros. */ + +void obstack_init (struct obstack *obstack); + +void * obstack_alloc (struct obstack *obstack, int size); + +void * obstack_copy (struct obstack *obstack, void *address, int size); +void * obstack_copy0 (struct obstack *obstack, void *address, int size); + +void obstack_free (struct obstack *obstack, void *block); + +void obstack_blank (struct obstack *obstack, int size); + +void obstack_grow (struct obstack *obstack, void *data, int size); +void obstack_grow0 (struct obstack *obstack, void *data, int size); + +void obstack_1grow (struct obstack *obstack, int data_char); + +void * obstack_finish (struct obstack *obstack); + +int obstack_object_size (struct obstack *obstack); + +int obstack_room (struct obstack *obstack); +void obstack_1grow_fast (struct obstack *obstack, int data_char); +void obstack_blank_fast (struct obstack *obstack, int size); + +void * obstack_base (struct obstack *obstack); +void * obstack_next_free (struct obstack *obstack); +int obstack_alignment_mask (struct obstack *obstack); +int obstack_chunk_size (struct obstack *obstack); + +#endif /* __STDC__ */ + +/* Non-ANSI C cannot really support alternative functions for these macros, + so we do not declare them. */ + +/* Pointer to beginning of object being allocated or to be allocated next. + Note that this might not be the final address of the object + because a new chunk might be needed to hold the final size. */ + +#define obstack_base(h) ((h)->object_base) + +/* Size for allocating ordinary chunks. */ + +#define obstack_chunk_size(h) ((h)->chunk_size) + +/* Pointer to next byte not yet allocated in current chunk. */ + +#define obstack_next_free(h) ((h)->next_free) + +/* Mask specifying low bits that should be clear in address of an object. */ + +#define obstack_alignment_mask(h) ((h)->alignment_mask) + +#define obstack_init(h) \ + _obstack_begin ((h), 0, 0, obstack_chunk_alloc, obstack_chunk_free) + +#define obstack_begin(h, size) \ + _obstack_begin ((h), (size), 0, obstack_chunk_alloc, obstack_chunk_free) + +#define obstack_1grow_fast(h,achar) (*((h)->next_free)++ = achar) + +#define obstack_blank_fast(h,n) ((h)->next_free += (n)) + +#if defined (__GNUC__) && defined (__STDC__) + +/* For GNU C, if not -traditional, + we can define these macros to compute all args only once + without using a global variable. + Also, we can avoid using the `temp' slot, to make faster code. */ + +#define obstack_object_size(OBSTACK) \ + ({ struct obstack *__o = (OBSTACK); \ + (unsigned) (__o->next_free - __o->object_base); }) + +#define obstack_room(OBSTACK) \ + ({ struct obstack *__o = (OBSTACK); \ + (unsigned) (__o->chunk_limit - __o->next_free); }) + +#define obstack_grow(OBSTACK,where,length) \ +({ struct obstack *__o = (OBSTACK); \ + int __len = (length); \ + ((__o->next_free + __len > __o->chunk_limit) \ + ? _obstack_newchunk (__o, __len) : 0); \ + bcopy (where, __o->next_free, __len); \ + __o->next_free += __len; \ + (void) 0; }) + +#define obstack_grow0(OBSTACK,where,length) \ +({ struct obstack *__o = (OBSTACK); \ + int __len = (length); \ + ((__o->next_free + __len + 1 > __o->chunk_limit) \ + ? _obstack_newchunk (__o, __len + 1) : 0), \ + bcopy (where, __o->next_free, __len), \ + __o->next_free += __len, \ + *(__o->next_free)++ = 0; \ + (void) 0; }) + +#define obstack_1grow(OBSTACK,datum) \ +({ struct obstack *__o = (OBSTACK); \ + ((__o->next_free + 1 > __o->chunk_limit) \ + ? _obstack_newchunk (__o, 1) : 0), \ + *(__o->next_free)++ = (datum); \ + (void) 0; }) + +#define obstack_blank(OBSTACK,length) \ +({ struct obstack *__o = (OBSTACK); \ + int __len = (length); \ + ((__o->next_free + __len > __o->chunk_limit) \ + ? _obstack_newchunk (__o, __len) : 0); \ + __o->next_free += __len; \ + (void) 0; }) + +#define obstack_alloc(OBSTACK,length) \ +({ struct obstack *__h = (OBSTACK); \ + obstack_blank (__h, (length)); \ + obstack_finish (__h); }) + +#define obstack_copy(OBSTACK,where,length) \ +({ struct obstack *__h = (OBSTACK); \ + obstack_grow (__h, (where), (length)); \ + obstack_finish (__h); }) + +#define obstack_copy0(OBSTACK,where,length) \ +({ struct obstack *__h = (OBSTACK); \ + obstack_grow0 (__h, (where), (length)); \ + obstack_finish (__h); }) + +#define obstack_finish(OBSTACK) \ +({ struct obstack *__o = (OBSTACK); \ + void *value = (void *) __o->object_base; \ + __o->next_free \ + = __INT_TO_PTR ((__PTR_TO_INT (__o->next_free)+__o->alignment_mask)\ + & ~ (__o->alignment_mask)); \ + ((__o->next_free - (char *)__o->chunk \ + > __o->chunk_limit - (char *)__o->chunk) \ + ? (__o->next_free = __o->chunk_limit) : 0); \ + __o->object_base = __o->next_free; \ + value; }) + +#define obstack_free(OBSTACK, OBJ) \ +({ struct obstack *__o = (OBSTACK); \ + void *__obj = (OBJ); \ + if (__obj >= (void *)__o->chunk && __obj < (void *)__o->chunk_limit) \ + __o->next_free = __o->object_base = __obj; \ + else (obstack_free) (__o, __obj); }) + +#else /* not __GNUC__ or not __STDC__ */ + +/* The non-GNU macros copy the obstack-pointer into this global variable + to avoid multiple evaluation. */ + +extern struct obstack *_obstack; + +#define obstack_object_size(h) \ + (unsigned) (_obstack = (h), (h)->next_free - (h)->object_base) + +#define obstack_room(h) \ + (unsigned) (_obstack = (h), (h)->chunk_limit - (h)->next_free) + +#define obstack_grow(h,where,length) \ +( (h)->temp = (length), \ + (((h)->next_free + (h)->temp > (h)->chunk_limit) \ + ? _obstack_newchunk ((h), (h)->temp) : 0), \ + bcopy (where, (h)->next_free, (h)->temp), \ + (h)->next_free += (h)->temp) + +#define obstack_grow0(h,where,length) \ +( (h)->temp = (length), \ + (((h)->next_free + (h)->temp + 1 > (h)->chunk_limit) \ + ? _obstack_newchunk ((h), (h)->temp + 1) : 0), \ + bcopy (where, (h)->next_free, (h)->temp), \ + (h)->next_free += (h)->temp, \ + *((h)->next_free)++ = 0) + +#define obstack_1grow(h,datum) \ +( (((h)->next_free + 1 > (h)->chunk_limit) \ + ? _obstack_newchunk ((h), 1) : 0), \ + *((h)->next_free)++ = (datum)) + +#define obstack_blank(h,length) \ +( (h)->temp = (length), \ + (((h)->next_free + (h)->temp > (h)->chunk_limit) \ + ? _obstack_newchunk ((h), (h)->temp) : 0), \ + (h)->next_free += (h)->temp) + +#define obstack_alloc(h,length) \ + (obstack_blank ((h), (length)), obstack_finish ((h))) + +#define obstack_copy(h,where,length) \ + (obstack_grow ((h), (where), (length)), obstack_finish ((h))) + +#define obstack_copy0(h,where,length) \ + (obstack_grow0 ((h), (where), (length)), obstack_finish ((h))) + +#define obstack_finish(h) \ +( (h)->temp = __PTR_TO_INT ((h)->object_base), \ + (h)->next_free \ + = __INT_TO_PTR ((__PTR_TO_INT ((h)->next_free)+(h)->alignment_mask) \ + & ~ ((h)->alignment_mask)), \ + (((h)->next_free - (char *)(h)->chunk \ + > (h)->chunk_limit - (char *)(h)->chunk) \ + ? ((h)->next_free = (h)->chunk_limit) : 0), \ + (h)->object_base = (h)->next_free, \ + __INT_TO_PTR ((h)->temp)) + +#ifdef __STDC__ +#define obstack_free(h,obj) \ +( (h)->temp = (char *)(obj) - (char *) (h)->chunk, \ + (((h)->temp >= 0 && (h)->temp < (h)->chunk_limit - (char *) (h)->chunk)\ + ? (int) ((h)->next_free = (h)->object_base \ + = (h)->temp + (char *) (h)->chunk) \ + : ((obstack_free) ((h), (h)->temp + (char *) (h)->chunk), 0))) +#else +#define obstack_free(h,obj) \ +( (h)->temp = (char *)(obj) - (char *) (h)->chunk, \ + (((h)->temp >= 0 && (h)->temp < (h)->chunk_limit - (char *) (h)->chunk)\ + ? (int) ((h)->next_free = (h)->object_base \ + = (h)->temp + (char *) (h)->chunk) \ + : (int) _obstack_free ((h), (h)->temp + (char *) (h)->chunk))) +#endif + +#endif /* not __GNUC__ or not __STDC__ */ + +#endif /* not __OBSTACKS__ */ + diff --git a/gnu/usr.bin/gdb/printcmd.c b/gnu/usr.bin/gdb/printcmd.c new file mode 100644 index 0000000..6edd7bd --- /dev/null +++ b/gnu/usr.bin/gdb/printcmd.c @@ -0,0 +1,1867 @@ +/*- + * This code is derived from software copyrighted by the Free Software + * Foundation. + * + * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. + * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory. + */ + +#ifndef lint +static char sccsid[] = "@(#)printcmd.c 6.5 (Berkeley) 5/8/91"; +#endif /* not lint */ + +/* Print values for GNU debugger GDB. + Copyright (C) 1986, 1987, 1988, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <stdio.h> +#include "defs.h" +#include "param.h" +#include "frame.h" +#include "symtab.h" +#include "value.h" +#include "expression.h" + +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; + +static void do_one_display (); + +void do_displays (); +void print_address (); +void print_floating (); +void print_scalar_formatted (); +void print_formatted_address (); + + +/* 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') || (*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': + case 'A': + /* 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, 0, 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. */ + unsigned long v1, v2, tmp; + + v1 = unpack_long (builtin_type_long, valaddr); + v2 = unpack_long (builtin_type_long, valaddr + 4); + +#ifdef BYTES_BIG_ENDIAN +#else + /* 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': +#ifdef LONG_LONG + if (!size) + size = (len < sizeof (long long) ? 'w' : 'g'); + switch (size) + { + case 'b': + fprintf_filtered (stream, "0x%02llx", val_long); + break; + case 'h': + fprintf_filtered (stream, "0x%04llx", val_long); + break; + case 0: /* no size specified, like in print */ + 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 + switch (size) + { + case 'b': + fprintf_filtered (stream, "0x%02x", val_long); + break; + case 'h': + fprintf_filtered (stream, "0x%04x", val_long); + break; + case 0: /* no size specified, like in print */ + case 'w': + fprintf_filtered (stream, "0x%08x", val_long); + break; + case 'g': + fprintf_filtered (stream, "0x%o16x", 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 'A': + print_formatted_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); + } +} + +/* 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; + int len = TYPE_LENGTH (type); + + doub = unpack_double (type, valaddr, &inv); + if (inv) + fprintf_filtered (stream, "Invalid float value"); + else if (doub != doub) + { + /* Surely it is an IEEE floating point NaN. */ + + long low, high, *arg = (long *)valaddr; /* ASSUMED 32 BITS */ + int nonneg; + + if (len <= sizeof(float)) + { + /* It's single precision. */ + low = *arg; + nonneg = low >= 0; + low &= 0x7fffff; + high = 0; + } + else + { + /* It's double precision. + Get the high and low words of the fraction. + Distinguish big and little-endian machines. */ +#ifdef WORDS_BIG_ENDIAN + low = arg[1], high = arg[0]; +#else + low = arg[0], high = arg[1]; +#endif + nonneg = high >= 0; + high &= 0xfffff; + } + if (high) + fprintf_filtered (stream, "-NaN(0x%lx%.8lx)" + nonneg, high, low); + else + fprintf_filtered (stream, "-NaN(0x%lx)" + nonneg, low); + } + else + fprintf_filtered (stream, len <= sizeof(float) ? "%.6g" : "%.17g", doub); +} + +/* Specify default address for `x' command. + `info lines' uses this. */ + +void +set_next_address (addr) + CORE_ADDR addr; +{ + next_address = addr; + + /* Make address available to the user as $_. */ + set_internalvar (lookup_internalvar ("_"), + value_from_long (builtin_type_int, (LONGEST) addr)); +} + +/* Optionally print address ADDR symbolically as <SYMBOL+OFFSET> on STREAM. */ + +void +print_address_symbolic (addr, stream) + CORE_ADDR addr; + FILE *stream; +{ + register char *format; + int name_location; + register int i = find_pc_misc_function (addr); + + /* If nothing comes out, don't print anything symbolic. */ + if (i < 0) return; + name_location = misc_function_vector[i].address; + + if (addr - name_location) + format = " <%s+%d>"; + else + format = " <%s>"; + + fprintf_filtered (stream, format, + misc_function_vector[i].name, addr - name_location); +} + +/* Print address ADDR symbolically on STREAM. + First print it as a number. Then perhaps print + <SYMBOL + OFFSET> after the number. */ + +void +print_address (addr, stream) + CORE_ADDR addr; + FILE *stream; +{ + fprintf_filtered (stream, "0x%x", addr); + print_address_symbolic (addr, stream); +} + +/* Like print_address but opnly prints symbolically. */ + +void +print_formatted_address (addr, stream) + CORE_ADDR addr; + FILE *stream; +{ + register int i = 0; + register char *format; + register struct symbol *fs; + char *name; + int name_location; + + i = find_pc_partial_function (addr, &name, &name_location); + + /* If nothing comes out, don't print anything symbolic. */ + + if (i == 0) + fprintf_filtered (stream, "0x%x", addr); + else if (addr - name_location) + fprintf_filtered (stream, "%s+%d", name, addr - name_location); + else + fprintf_filtered (stream, "%s", name); +} + +/* 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 (exp) + char *exp; +{ + struct expression *expr; + register struct cleanup *old_chain = 0; + register char format = 0; + register value val; + struct format_data fmt; + int histindex; + int cleanup = 0; + + if (exp && *exp == '/') + { + exp++; + fmt = decode_format (&exp, last_format, 0); + validate_format (fmt, "print"); + last_format = format = fmt.format; + } + + 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); + + histindex = record_latest_value (val); + if (histindex >= 0) printf_filtered ("$%d = ", histindex); + + print_formatted (val, format, fmt.size); + printf_filtered ("\n"); + + if (cleanup) + do_cleanups (old_chain); +} + +static void +output_command (exp) + char *exp; +{ + 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) + char *exp; +{ + 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) + char *exp; +{ + 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); + 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", val); + break; + + case LOC_REGISTER: + printf ("a variable in register %s", reg_names[val]); + break; + + case LOC_STATIC: + printf ("static at address 0x%x", val); + break; + + case LOC_REGPARM: + printf ("an argument in register %s", reg_names[val]); + break; + + case LOC_ARG: + printf ("an argument at offset %d", val); + break; + + case LOC_LOCAL: + printf ("a local variable at frame offset %d", val); + break; + + case LOC_REF_ARG: + printf ("a reference argument at offset %d", 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; + } + 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. */ + +static void +whatis_command (exp) + char *exp; +{ + 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 = "); + /* 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. */ + type_print (VALUE_TYPE (val), "", stdout, -1); + printf_filtered ("\n"); + + if (exp) + do_cleanups (old_chain); +} + +static void +ptype_command (typename) + char *typename; +{ + register char *p = typename; + register int len; + extern struct block *get_current_block (); + register struct block *b + = (have_inferior_p () || have_core_file_p ()) ? get_current_block () : 0; + register struct type *type; + + if (typename == 0) + error_no_arg ("type name"); + + 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); + if (sym == 0) + error ("No type named %s.", typename); + 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"); + } + printf_filtered (" %s. Type \"help ptype\".\n", typename); + type = SYMBOL_TYPE (sym); + } + } + + type_print (type, "", stdout, 1); + printf_filtered ("\n"); +} + +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; + extern struct block *innermost_block; + + 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 && have_inferior_p ()) + 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; + register struct display *d, *d1; + + 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) + { + 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 (" "); + do_examine (d->format, + (CORE_ADDR) value_as_long (evaluate_expression (d->exp))); + + } + 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 int num; + 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."); + + num = atoi (p); + + 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); +} + +static int +compare_ints (i, j) + int *i, *j; +{ + return *i - *j; +} + +/* 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). */ + +static void print_frame_nameless_args (); + +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 int last_regparm = 0; + register struct symbol *lastsym, *sym, *nextsym; + register value val; + /* Offset of stack argument that is at the highest offset. + -1 if we haven't come to a stack argument yet. */ + CORE_ADDR highest_offset = (CORE_ADDR) -1; + register CORE_ADDR addr = FRAME_ARGS_ADDRESS (fi); + + 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_REF_ARG) + continue; + + /* Print the next arg. */ + if (SYMBOL_CLASS (sym) == LOC_REGPARM) + val = value_from_register (SYMBOL_TYPE (sym), + SYMBOL_VALUE (sym), + FRAME_INFO_ID (fi)); + else + { + int current_offset = SYMBOL_VALUE (sym); + int arg_size = TYPE_LENGTH (SYMBOL_TYPE (sym)); + + if (SYMBOL_CLASS (sym) == LOC_REF_ARG) + val = value_at (SYMBOL_TYPE (sym), + read_memory_integer (addr + current_offset, + sizeof (CORE_ADDR))); + else + val = value_at (SYMBOL_TYPE (sym), addr + current_offset); + + /* Round up address of next arg to multiple of size of int. */ + current_offset + = (((current_offset + sizeof (int) - 1) / sizeof (int)) + * sizeof (int)); + + /* If this is the highest offset seen yet, set highest_offset. */ + if (highest_offset == (CORE_ADDR)-1 + || ((current_offset + + (arg_size - sizeof (int) + 3) / (sizeof (int))) + > highest_offset)) + highest_offset = current_offset; + } + + if (! first) + fprintf_filtered (stream, ", "); + fputs_filtered (SYMBOL_NAME (sym), stream); + fputs_filtered ("=", stream); + +/* Nonzero if a LOC_ARG which is a struct is useless. */ +#if !defined (STRUCT_ARG_SYM_GARBAGE) +#define STRUCT_ARG_SYM_GARBAGE(gcc_p) 0 +#endif + + if (STRUCT_ARG_SYM_GARBAGE (b->gcc_compile_flag) + && TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_STRUCT + && SYMBOL_CLASS (sym) == LOC_ARG) + { + /* Try looking up that name. SunOS4 puts out a usable + symbol as a local variable (in addition to the one + for the arg). */ + struct symbol *sym2 = + lookup_symbol (SYMBOL_NAME (sym), b, VAR_NAMESPACE, 0); + + if (sym2 != NULL) + val = value_of_variable (sym2); + else + { + fputs_filtered ("?", stream); + first = 0; + continue; + } + } + + value_print (val, stream, 0, Val_no_prettyprint); + first = 0; + } + + /* Don't print nameless args in situations where we don't know + enough about the stack to find them. */ + if (num != -1) + { + if (highest_offset != (CORE_ADDR) -1 + && num * sizeof (int) + FRAME_ARGS_SKIP > highest_offset) + print_frame_nameless_args (fi, addr, + highest_offset + sizeof (int), + num * sizeof (int) + FRAME_ARGS_SKIP, + stream); + else + print_frame_nameless_args (fi, addr, FRAME_ARGS_SKIP, + num * sizeof (int) + FRAME_ARGS_SKIP, + stream); + } +} + +static void +print_frame_nameless_args (fi, argsaddr, start, end, stream) + struct frame_info *fi; + CORE_ADDR argsaddr; + int start; + int end; + FILE *stream; +{ + extern void (*default_scalar_print)(); + LONGEST v; + int p = start; + char *s = ""; + + for (p = start; p < end; p += sizeof(int)) { + QUIT; +#if defined(NAMELESS_ARG) + v = NAMELESS_ARG(fi, (p - start) / sizeof(int)); +#else + v = read_memory_integer (argsaddr + p, sizeof (int)); +#endif + fprintf_filtered (stream, s); + s = ", "; + (*default_scalar_print) (stream, builtin_type_int, v); + } +} + +static void +printf_command (arg) + char *arg; +{ + 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 (index ("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); + } + } + } + vprintf (string, arg_bytes); +} + +/* 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 *) index (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); +} + + +extern struct cmd_list_element *enablelist, *disablelist, *deletelist; +extern struct cmd_list_element *cmdlist, *setlist; + +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."); + + 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", + &setlist, "set ", 1, &cmdlist); + + 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); +} diff --git a/gnu/usr.bin/gdb/readline/ChangeLog b/gnu/usr.bin/gdb/readline/ChangeLog new file mode 100644 index 0000000..b72a59d --- /dev/null +++ b/gnu/usr.bin/gdb/readline/ChangeLog @@ -0,0 +1,98 @@ +Thu Feb 8 01:04:00 1990 Jim Kingdon (kingdon at pogo.ai.mit.edu) + + * Makefile (the *other* libreadline.a): Uncomment out ranlib line. + +Thu Feb 1 17:50:22 1990 Jim Kingdon (kingdon at pogo.ai.mit.edu) + + * Makefile (libreadline.a): Uncomment out ranlib line. + +Sun Nov 26 16:29:11 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * readline.c (rl_deprep_terminal): Only restore local_mode_flags + if they had been set. + +Thu Oct 19 17:18:40 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * Move vi_doing_insert from vi_mode.c to readline.c + + * readline.c: Move compare_strings before its use. + Remove declarations. + + * readline.c: Move defining_kbd_macro above rl_dispatch. + (rl_dispatch): Remove "extern int defining_kbd_macro". + +Mon Oct 16 11:56:03 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * readline.c (rl_set_signals): Remove unnecessary "static int + rl_signal_handler()". + +Sat Sep 30 14:51:56 1989 Jim Kingdon (kingdon at hobbes.ai.mit.edu) + + * readline.c (rl_initialize): Change parsing_conditionalized_out + to static. + (rl_dispatch): Change defining_kbd_macro to static. + (rl_newline): Change vi_doing_insert to static. + +Fri Sep 8 09:00:45 1989 Brian Fox (bfox at aurel) + + * readline.c: rl_prep_terminal (). Only turn on 8th bit + as meta-bit iff the terminal is not using parity. + +Sun Sep 3 08:57:40 1989 Brian Fox (bfox at aurel) + + * readline.c: start_insert (). Uses multiple + insertion call in cases where that makes sense. + + rl_insert (). Read type-ahead buffer for additional + keys that are bound to rl_insert, and insert them + all at once. Make insertion of single keys given + with an argument much more efficient. + +Tue Aug 8 18:13:57 1989 Brian Fox (bfox at aurel) + + * readline.c: Changed handling of EOF. readline () returns + (char *)EOF or consed string. The EOF character is read from the + tty, or if the tty doesn't have one, defaults to C-d. + + * readline.c: Added support for event driven programs. + rl_event_hook is the address of a function you want called + while Readline is waiting for input. + + * readline.c: Cleanup time. Functions without type declarations + do not use return with a value. + + * history.c: history_expand () has new variable which is the + characters to ignore immediately following history_expansion_char. + +Sun Jul 16 08:14:00 1989 Brian Fox (bfox at aurel) + + * rl_prep_terminal () + BSD version turns off C-s, C-q, C-y, C-v. + + * readline.c -- rl_prep_terminal () + SYSV version hacks readline_echoing_p. + BSD version turns on passing of the 8th bit for the duration + of reading the line. + +Tue Jul 11 06:25:01 1989 Brian Fox (bfox at aurel) + + * readline.c: new variable rl_tilde_expander. + 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. + + * readline.h - new file chardefs.h + Separates things that only readline.c needs from the standard + header file publishing interesting things about readline. + + * readline.c: + readline_default_bindings () now looks at terminal chararacters + and binds those as well. + +Wed Jun 28 20:20:51 1989 Brian Fox (bfox at aurel) + + * Made readline and history into independent libraries. + + diff --git a/gnu/usr.bin/gdb/readline/Makefile.gnu b/gnu/usr.bin/gdb/readline/Makefile.gnu new file mode 100644 index 0000000..dc11539 --- /dev/null +++ b/gnu/usr.bin/gdb/readline/Makefile.gnu @@ -0,0 +1,114 @@ +## -*- 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) $*.c + +# 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/gnu/lib +INCDIR = /usr/gnu/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 this out if you don't think that anyone will ever desire +# the vi line editing mode and features. +READLINE_DEFINES = -DVI_MODE + +DEBUG_FLAGS = -g +LDFLAGS = $(DEBUG_FLAGS) +CFLAGS = $(DEBUG_FLAGS) $(TYPE) $(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 keymaps.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 + $(CC) -c $(CFLAGS) $(CPPFLAGS) $(READLINE_DEFINES) \ + $(LOCAL_INCLUDES) $*.c + +history.o: history.c history.h + $(CC) -c $(CFLAGS) $(CPPFLAGS) $(READLINE_DEFINES) \ + $(LOCAL_INCLUDES) $*.c + +funmap.o: readline.h + $(CC) -c $(CFLAGS) $(CPPFLAGS) $(READLINE_DEFINES) \ + $(LOCAL_INCLUDES) $*.c + +keymaps.o: emacs_keymap.c vi_keymap.c keymaps.h chardefs.h keymaps.c + $(CC) -c $(CFLAGS) $(CPPFLAGS) $(READLINE_DEFINES) \ + $(LOCAL_INCLUDES) $*.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/gnu/usr.bin/gdb/readline/chardefs.h b/gnu/usr.bin/gdb/readline/chardefs.h new file mode 100644 index 0000000..9749ae4 --- /dev/null +++ b/gnu/usr.bin/gdb/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/gnu/usr.bin/gdb/readline/emacs_keymap.c b/gnu/usr.bin/gdb/readline/emacs_keymap.c new file mode 100644 index 0000000..7030e69 --- /dev/null +++ b/gnu/usr.bin/gdb/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 FILE +#include <stdio.h> +#endif /* FILE */ + +#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, rl_re_read_init_file }, /* 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/gnu/usr.bin/gdb/readline/funmap.c b/gnu/usr.bin/gdb/readline/funmap.c new file mode 100644 index 0000000..357e716 --- /dev/null +++ b/gnu/usr.bin/gdb/readline/funmap.c @@ -0,0 +1,217 @@ +/* funmap.c -- attach names to functions. */ + +/* Copyright (C) 1988,1989 Free Software Foundation, Inc. + + This file is part of GNU Readline, a library for reading lines + of text with interactive input and history editing. + + Readline is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 1, or (at your option) any + later version. + + Readline is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Readline; see the file COPYING. If not, write to the Free + Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define STATIC_MALLOC +#ifndef STATIC_MALLOC +extern char *xmalloc (), *xrealloc (); +#else +static char *xmalloc (), *xrealloc (); +#endif + +#ifndef FILE +#include <stdio.h> +#endif /* FILE */ + +#include "readline.h" + +FUNMAP **funmap = (FUNMAP **)NULL; +static int funmap_size = 0; + +static int just_testing_ar_tmp = 0; +static int just_testing_ar_tmp_2 = 5; +int foo_testing_ar; + +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 char * +xmalloc (bytes) + int bytes; +{ + static memory_error_and_abort (); + char *temp = (char *)malloc (bytes); + + if (!temp) + memory_error_and_abort (); + return (temp); +} + +static char * +xrealloc (pointer, bytes) + char *pointer; + int bytes; +{ + static memory_error_and_abort (); + char *temp = (char *)realloc (pointer, bytes); + + if (!temp) + memory_error_and_abort (); + return (temp); +} + +static +memory_error_and_abort () +{ + fprintf (stderr, "history: Out of virtual memory!\n"); + abort (); +} +#endif /* STATIC_MALLOC */ diff --git a/gnu/usr.bin/gdb/readline/history.c b/gnu/usr.bin/gdb/readline/history.c new file mode 100644 index 0000000..7087718 --- /dev/null +++ b/gnu/usr.bin/gdb/readline/history.c @@ -0,0 +1,1462 @@ +/* History.c -- standalone history library */ + +/* Copyright (C) 1989 Free Software Foundation, Inc. + + This file contains the GNU History Library (the Library), a set of + routines for managing the text of previously typed lines. + + The Library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + The Library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* The goal is to make the implementation transparent, so that you + don't have to know what data types are used, just what functions + you can call. I think I have done that. */ + +/* Remove these declarations when we have a complete libgnu.a. */ +#define STATIC_MALLOC +#ifndef STATIC_MALLOC +extern char *xmalloc (), *xrealloc (); +#else +static char *xmalloc (), *xrealloc (); +#endif + +#include <stdio.h> + +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else +#if defined (sparc) && defined (sun) +#include <alloca.h> +#else +extern char *alloca (); +#endif +#endif + +#include "history.h" + +#ifndef savestring +#define savestring(x) (char *)strcpy (xmalloc (1 + strlen (x)), (x)) +#endif + +#ifndef whitespace +#define whitespace(c) (((c) == ' ') || ((c) == '\t')) +#endif + +#ifndef digit +#define digit(c) ((c) >= '0' && (c) <= '9') +#endif + +#ifndef member +#define member(c, s) ((c) ? index ((s), (c)) : 0) +#endif + +/* **************************************************************** */ +/* */ +/* History functions */ +/* */ +/* **************************************************************** */ + +/* An array of HIST_ENTRY. This is where we store the history. */ +static HIST_ENTRY **the_history = (HIST_ENTRY **)NULL; + +/* Non-zero means that we have enforced a limit on the amount of + history that we save. */ +static int history_stifled = 0; + +/* If HISTORY_STIFLED is non-zero, then this is the maximum number of + entries to remember. */ +static int max_input_history; + +/* The current location of the interactive history pointer. Just makes + life easier for outside callers. */ +static int history_offset = 0; + +/* The number of strings currently stored in the input_history list. */ +static int history_length = 0; + +/* The current number of slots allocated to the input_history. */ +static int history_size = 0; + +/* The number of slots to increase the_history by. */ +#define DEFAULT_HISTORY_GROW_SIZE 50 + +/* The character that represents the start of a history expansion + request. This is usually `!'. */ +char history_expansion_char = '!'; + +/* The character that invokes word substitution if found at the start of + a line. This is usually `^'. */ +char history_subst_char = '^'; + +/* During tokenization, if this character is seen as the first character + of a word, then it, and all subsequent characters upto a newline are + ignored. For a Bourne shell, this should be '#'. Bash special cases + the interactive comment character to not be a comment delimiter. */ +char history_comment_char = '\0'; + +/* The list of characters which inhibit the expansion of text if found + immediately following history_expansion_char. */ +char *history_no_expand_chars = " \t\n\r="; + +/* The logical `base' of the history array. It defaults to 1. */ +int history_base = 1; + +/* Begin a session in which the history functions might be used. This + initializes interactive variables. */ +void +using_history () +{ + history_offset = history_length; +} + +/* Place STRING at the end of the history list. The data field + is set to NULL. */ +void +add_history (string) + char *string; +{ + HIST_ENTRY *temp; + + if (history_stifled && (history_length == max_input_history)) { + register int i; + + /* If the history is stifled, and history_length is zero, + and it equals max_input_history, we don't save items. */ + if (!history_length) + return; + + /* If there is something in the slot, then remove it. */ + if (the_history[0]) { + free (the_history[0]->line); + free (the_history[0]); + } + + for (i = 0; i < history_length; i++) + the_history[i] = the_history[i + 1]; + + history_base++; + + } else { + + if (!history_size) { + the_history = + (HIST_ENTRY **)xmalloc ((history_size = DEFAULT_HISTORY_GROW_SIZE) + * sizeof (HIST_ENTRY *)); + history_length = 1; + + } else { + if (history_length == (history_size - 1)) { + the_history = + (HIST_ENTRY **)xrealloc (the_history, + ((history_size += DEFAULT_HISTORY_GROW_SIZE) + * sizeof (HIST_ENTRY *))); + } + history_length++; + } + } + + temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY)); + temp->line = savestring (string); + temp->data = (char *)NULL; + + the_history[history_length] = (HIST_ENTRY *)NULL; + the_history[history_length - 1] = temp; +} + +/* Make the history entry at WHICH have LINE and DATA. This returns + the old entry so you can dispose of the data. In the case of an + invalid WHICH, a NULL pointer is returned. */ +HIST_ENTRY * +replace_history_entry (which, line, data) + int which; + char *line; + char *data; +{ + HIST_ENTRY *temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY)); + HIST_ENTRY *old_value; + + if (which >= history_length) + return ((HIST_ENTRY *)NULL); + + old_value = the_history[which]; + + temp->line = savestring (line); + temp->data = data; + the_history[which] = temp; + + return (old_value); +} + +/* Returns the magic number which says what history element we are + looking at now. In this implementation, it returns history_offset. */ +int +where_history () +{ + return (history_offset); +} + +/* Search the history for STRING, starting at history_offset. + If DIRECTION < 0, then the search is through previous entries, + else through subsequent. If the string is found, then + current_history () is the history entry, and the value of this function + is the offset in the line of that history entry that the string was + found in. Otherwise, nothing is changed, and a -1 is returned. */ +int +history_search (string, direction) + char *string; + int direction; +{ + register int i = history_offset; + register int reverse = (direction < 0); + register char *line; + register int index; + int string_len = strlen (string); + + /* Take care of trivial cases first. */ + + if (!history_length || (i == history_length) && !reverse) + return (-1); + + if (reverse && (i == history_length)) + i--; + + while (1) + { + /* Search each line in the history list for STRING. */ + + /* At limit for direction? */ + if ((reverse && i < 0) || + (!reverse && i == history_length)) + return (-1); + + line = the_history[i]->line; + index = strlen (line); + + /* If STRING is longer than line, no match. */ + if (string_len > index) + goto next_line; + + /* Do the actual search. */ + if (reverse) + { + index -= string_len; + + while (index >= 0) + { + if (strncmp (string, line + index, string_len) == 0) + { + history_offset = i; + return (index); + } + index--; + } + } + else + { + register int limit = (string_len - index) + 1; + index = 0; + + while (index < limit) + { + if (strncmp (string, line + index, string_len) == 0) + { + history_offset = i; + return (index); + } + index++; + } + } + next_line: + if (reverse) + i--; + else + i++; + } +} + +/* Remove history element WHICH from the history. The removed + element is returned to you so you can free the line, data, + and containing structure. */ +HIST_ENTRY * +remove_history (which) + int which; +{ + HIST_ENTRY *return_value; + + if (which >= history_length || !history_length) + return_value = (HIST_ENTRY *)NULL; + else + { + register int i; + return_value = the_history[which]; + + for (i = which; i < history_length; i++) + the_history[i] = the_history[i + 1]; + + history_length--; + } + return (return_value); +} + +/* Stifle the history list, remembering only MAX number of lines. */ +void +stifle_history (max) + int max; +{ + if (history_length > max) + { + register int i, j; + + /* This loses because we cannot free the data. */ + for (i = 0; i < (history_length - max); i++) + { + free (the_history[i]->line); + free (the_history[i]); + } + history_base = i; + for (j = 0, i = history_length - max; j < max; i++, j++) + the_history[j] = the_history[i]; + the_history[j] = (HIST_ENTRY *)NULL; + history_length = j; + } + history_stifled = 1; + max_input_history = max; +} + +/* Stop stifling the history. This returns the previous amount the history + was stifled by. The value is positive if the history was stifled, negative + if it wasn't. */ +int +unstifle_history () +{ + int result = max_input_history; + if (history_stifled) + { + result = - result; + history_stifled = 0; + } + return (result); +} + +/* Return the string that should be used in the place of this + filename. This only matters when you don't specify the + filename to read_history (), or write_history (). */ +static char * +history_filename (filename) + char *filename; +{ + char *return_val = filename ? savestring (filename) : (char *)NULL; + + if (!return_val) + { + char *home = (char *)getenv ("HOME"); + if (!home) home = "."; + return_val = (char *)xmalloc (2 + strlen (home) + strlen (".history")); + strcpy (return_val, home); + strcat (return_val, "/"); + strcat (return_val, ".history"); + } + return (return_val); +} + +/* What to use until the line gets too big. */ +#define TYPICAL_LINE_SIZE 2048 + +/* Add the contents of FILENAME to the history list, a line at a time. + If FILENAME is NULL, then read from ~/.history. Returns 0 if + successful, or errno if not. */ +int +read_history (filename) + char *filename; +{ + char *input = history_filename (filename); + FILE *file = fopen (input, "r"); + char *line = (char *)xmalloc (TYPICAL_LINE_SIZE); + int line_size = TYPICAL_LINE_SIZE; + int done = 0; + + if (!file) + { + extern int errno; + free (line); + return (errno); + } + + while (!done) + { + int c; + int i; + + i = 0; + while (!(done = ((c = getc (file)) == EOF))) + { + if (c == '\n') + break; + + line [i++] = c; + if (i == line_size) + line = (char *)xrealloc (line, line_size += TYPICAL_LINE_SIZE); + } + line[i] = '\0'; + if (line[0]) + add_history (line); + } + free (line); + fclose (file); + return (0); +} + +/* Overwrite FILENAME with the current history. If FILENAME is NULL, + then write the history list to ~/.history. Values returned + are as in read_history ().*/ +int +write_history (filename) + char *filename; +{ + extern int errno; + char *output = history_filename (filename); + FILE *file = fopen (output, "w"); + register int i; + + if (!file) return (errno); + if (!history_length) return (0); + + for (i = 0; i < history_length; i++) + fprintf (file, "%s\n", the_history[i]->line); + + fclose (file); + return (0); +} + +/* Return the history entry at the current position, as determined by + history_offset. If there is no entry there, return a NULL pointer. */ +HIST_ENTRY * +current_history () +{ + if ((history_offset == history_length) || !the_history) + return ((HIST_ENTRY *)NULL); + else + return (the_history[history_offset]); +} + +/* Back up history_offset to the previous history entry, and return + a pointer to that entry. If there is no previous entry then return + a NULL pointer. */ +HIST_ENTRY * +previous_history () +{ + if (!history_offset) + return ((HIST_ENTRY *)NULL); + else + return (the_history[--history_offset]); +} + +/* Move history_offset forward to the next history entry, and return + a pointer to that entry. If there is no next entry then return a + NULL pointer. */ +HIST_ENTRY * +next_history () +{ + if (history_offset == history_length) + return ((HIST_ENTRY *)NULL); + else + return (the_history[++history_offset]); +} + +/* Return the current history array. The caller has to be carefull, since this + is the actual array of data, and could be bashed or made corrupt easily. + The array is terminated with a NULL pointer. */ +HIST_ENTRY ** +history_list () +{ + return (the_history); +} + +/* Return the history entry which is logically at OFFSET in the history array. + OFFSET is relative to history_base. */ +HIST_ENTRY * +history_get (offset) + int offset; +{ + int index = offset - history_base; + + if (index >= history_length || + index < 0 || + !the_history) + return ((HIST_ENTRY *)NULL); + return (the_history[index]); +} + +/* Search for STRING in the history list. DIR is < 0 for searching + backwards. POS is an absolute index into the history list at + which point to begin searching. */ +int +history_search_pos (string, dir, pos) + char *string; + int dir, pos; +{ + int ret, old = where_history (); + history_set_pos (pos); + if (history_search (string, dir) == -1) + { + history_set_pos (old); + return (-1); + } + ret = where_history (); + history_set_pos (old); + return ret; +} + +/* Make the current history item be the one at POS, an absolute index. + Returns zero if POS is out of range, else non-zero. */ +int +history_set_pos (pos) + int pos; +{ + if (pos > history_length || pos < 0 || !the_history) + return (0); + history_offset = pos; + return (1); +} + + +/* **************************************************************** */ +/* */ +/* 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[2]; + 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); + } + 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] == '*') + { + *caller_index = i + 1; + return (history_arg_extract (1, '$', from)); + } + + /* `$' 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. */ +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 == '$') + 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 char * +xmalloc (bytes) + int bytes; +{ + static memory_error_and_abort (); + char *temp = (char *)malloc (bytes); + + if (!temp) + memory_error_and_abort (); + return (temp); +} + +static char * +xrealloc (pointer, bytes) + char *pointer; + int bytes; +{ + static memory_error_and_abort (); + char *temp = (char *)realloc (pointer, bytes); + + if (!temp) + memory_error_and_abort (); + return (temp); +} + +static +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/gnu/usr.bin/gdb/readline/history.h b/gnu/usr.bin/gdb/readline/history.h new file mode 100644 index 0000000..0bac209 --- /dev/null +++ b/gnu/usr.bin/gdb/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/gnu/usr.bin/gdb/readline/keymaps.c b/gnu/usr.bin/gdb/readline/keymaps.c new file mode 100644 index 0000000..e0c5e39 --- /dev/null +++ b/gnu/usr.bin/gdb/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 char * +xmalloc (bytes) + int bytes; +{ + static memory_error_and_abort (); + char *temp = (char *)malloc (bytes); + + if (!temp) + memory_error_and_abort (); + return (temp); +} + +static char * +xrealloc (pointer, bytes) + char *pointer; + int bytes; +{ + static memory_error_and_abort (); + char *temp = (char *)realloc (pointer, bytes); + + if (!temp) + memory_error_and_abort (); + return (temp); +} + +static +memory_error_and_abort () +{ + fprintf (stderr, "readline: Out of virtual memory!\n"); + abort (); +} +#endif /* STATIC_MALLOC */ diff --git a/gnu/usr.bin/gdb/readline/keymaps.h b/gnu/usr.bin/gdb/readline/keymaps.h new file mode 100644 index 0000000..3c577b3 --- /dev/null +++ b/gnu/usr.bin/gdb/readline/keymaps.h @@ -0,0 +1,53 @@ +/* keymaps.h -- Manipulation of readline keymaps. */ + +#ifndef _KEYMAPS_H_ +#define _KEYMAPS_H_ + +#include <readline/chardefs.h> + +#ifndef __FUNCTION_DEF +typedef int Function (); +#define __FUNCTION_DEF +#endif + +/* A keymap contains one entry for each key in the ASCII set. + Each entry consists of a type and a pointer. + POINTER is the address of a function to run, or the + address of a keymap to indirect through. + TYPE says which kind of thing POINTER is. */ +typedef struct _keymap_entry { + char type; + Function *function; +} KEYMAP_ENTRY; + +/* I wanted to make the above structure contain a union of: + union { Function *function; struct _keymap_entry *keymap; } value; + but this made it impossible for me to create a static array. + Maybe I need C lessons. */ + +typedef KEYMAP_ENTRY KEYMAP_ENTRY_ARRAY[128]; +typedef KEYMAP_ENTRY *Keymap; + +/* The values that TYPE can have in a keymap entry. */ +#define ISFUNC 0 +#define ISKMAP 1 +#define ISMACR 2 + +extern KEYMAP_ENTRY_ARRAY emacs_standard_keymap, emacs_meta_keymap, emacs_ctlx_keymap; +extern KEYMAP_ENTRY_ARRAY vi_insertion_keymap, vi_movement_keymap; + +/* Return a new, empty keymap. + Free it with free() when you are done. */ +Keymap rl_make_bare_keymap (); + +/* Return a new keymap which is a copy of MAP. */ +Keymap rl_copy_keymap (); + +/* Return a new keymap with the printing characters bound to rl_insert, + the lowercase Meta characters bound to run their equivalents, and + the Meta digits bound to produce numeric arguments. */ +Keymap rl_make_keymap (); + +#endif /* _KEYMAPS_H_ */ + + diff --git a/gnu/usr.bin/gdb/readline/readline.c b/gnu/usr.bin/gdb/readline/readline.c new file mode 100644 index 0000000..a29efe1 --- /dev/null +++ b/gnu/usr.bin/gdb/readline/readline.c @@ -0,0 +1,5557 @@ +/*- + * This code is derived from software copyrighted by the Free Software + * Foundation. + * + * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. + * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory. + */ + +#ifndef lint +static char sccsid[] = "@(#)readline.c 6.4 (Berkeley) 5/8/91"; +#endif /* not lint */ + +/* readline.c -- a general facility for reading lines of input + with emacs style editing and completion. */ + +/* Copyright (C) 1987,1989 Free Software Foundation, Inc. + + This file contains the Readline Library (the Library), a set of + routines for providing Emacs style line input to programs that ask + for it. + + The Library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + The Library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Remove these declarations when we have a complete libgnu.a. */ +#define STATIC_MALLOC +#ifndef STATIC_MALLOC +extern char *xmalloc (), *xrealloc (); +#else +static char *xmalloc (), *xrealloc (); +#endif + +#include <stdio.h> +#include <sys/types.h> +#include <fcntl.h> +#include <sys/file.h> +#include <signal.h> + +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else +#if defined (sparc) && defined (sun) +#include <alloca.h> +#endif +#endif + +#define NEW_TTY_DRIVER +#if defined (SYSV) || defined (hpux) +#undef NEW_TTY_DRIVER +#include <termio.h> +#else +#include <sgtty.h> +#endif + +#include <errno.h> +extern int errno; + +#include <setjmp.h> + +/* These next are for filename completion. Perhaps this belongs + in a different place. */ +#include <sys/stat.h> + +#include <pwd.h> +#ifdef SYSV +struct passwd *getpwuid (), *getpwent (); +#endif + +#define HACK_TERMCAP_MOTION + +#ifndef SYSV +#include <sys/dir.h> +#else /* SYSV */ +#ifdef hpux +#include <ndir.h> +#else +#include <dirent.h> +#define direct dirent +#define d_namlen d_reclen +#endif /* hpux */ +#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 start_insert (); +static end_insert (); + +/* This typedef is equivalant to the one for Function; it allows us + to say SigHandler *foo = signal (SIGKILL, SIG_IGN); */ +typedef void SigHandler (); + +#ifdef SIGWINCH +static void rl_handle_sigwinch (); +static SigHandler *old_sigwinch = (SigHandler *)NULL; +#endif + +/* If on, then readline handles signals in a way that doesn't screw. */ +/* #define HANDLE_SIGNALS */ + +#if defined (SYSV) +#ifdef HANDLE_SIGNALS +#undef HANDLE_SIGNALS +#endif +#endif + +/* Stupid comparison routine for qsort () ing strings. */ +static int +compare_strings (s1, s2) + char **s1, **s2; +{ + return (strcmp (*s1, *s2)); +} + + +/* **************************************************************** */ +/* */ +/* 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; + +/* 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 + + +/* **************************************************************** */ +/* */ +/* 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 SIGWINCH + old_sigwinch = (SigHandler *)signal (SIGWINCH, rl_handle_sigwinch); +#endif + +#ifdef HANDLE_SIGNALS + rl_set_signals (); +#endif + + value = readline_internal (); + rl_deprep_terminal (); + +#ifdef SIGWINCH + signal (SIGWINCH, old_sigwinch); +#endif + +#ifdef HANDLE_SIGNALS + rl_clear_signals (); +#endif + + return (value); +} + +/* Read a line of input from the global rl_instream, doing output on + the global rl_outstream. + If rl_prompt is non-null, then that is our prompt. */ +char * +readline_internal () +{ + int lastc, c, eof_found; + + in_stream = rl_instream; out_stream = rl_outstream; + lastc = eof_found = 0; + + if (rl_startup_hook) + (*rl_startup_hook) (); + + if (!readline_echoing_p) + { + if (rl_prompt) { + fprintf (out_stream, "%s", rl_prompt); + fflush(out_stream); + } + } + else + { + rl_on_new_line (); + rl_redisplay (); +#ifdef VI_MODE + if (rl_editing_mode == vi_mode) + rl_vi_insertion_mode (); +#endif /* VI_MODE */ + } + + while (!rl_done) + { + int lk = last_command_was_kill; + int code = setjmp (readline_top_level); + + if (code) + rl_redisplay (); + + if (!rl_pending_input) + { + /* Then initialize the argument and number of keys read. */ + rl_init_argument (); + rl_key_sequence_length = 0; + } + + c = rl_read_key (); + + /* EOF typed to a non-blank line is a <NL>. */ + if (c == EOF && rl_end) + c = NEWLINE; + + /* The character eof_char typed to blank line, and not as the + previous character is interpreted as EOF. */ + if (((c == eof_char && lastc != c) || c == EOF) && !rl_end) + { + eof_found = 1; + break; + } + + lastc = c; + rl_dispatch (c, keymap); + + /* If there was no change in last_command_was_kill, then no kill + has taken place. Note that if input is pending we are reading + a prefix command, so nothing has changed yet. */ + if (!rl_pending_input) + { + if (lk == last_command_was_kill) + last_command_was_kill = 0; + } + +#ifdef VI_MODE + /* In vi mode, when you exit insert mode, the cursor moves back + over the previous character. We explicitly check for that here. */ + if (rl_editing_mode == vi_mode && keymap == vi_movement_keymap) + rl_vi_check (); +#endif + + if (!rl_done) + rl_redisplay (); + } + + /* Restore the original of this history line, iff the line that we + are editing was originally in the history, AND the line has changed. */ + { + HIST_ENTRY *entry = current_history (); + + if (entry && rl_undo_list) + { + char *temp = savestring (the_line); + rl_revert_line (); + entry = replace_history_entry (where_history (), the_line, + (HIST_ENTRY *)NULL); + free_history_entry (entry); + + strcpy (the_line, temp); + free (temp); + } + } + + /* At any rate, it is highly likely that this line has an undo list. Get + rid of it now. */ + if (rl_undo_list) + free_undo_list (); + + if (eof_found) + return (char *)NULL; + else + return (savestring (the_line)); +} + + +/* Variables for 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; + +/* Non-zero means to save keys that we dispatch on in a kbd macro. */ +static int defining_kbd_macro = 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; + + +/* **************************************************************** */ +/* */ +/* Signal Handling */ +/* */ +/* **************************************************************** */ + +#ifdef SIGWINCH +static void +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 void +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 SIGWINCH + signal (SIGWINCH, old_sigwinch); +#endif + +#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); +#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 +} +#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. + Result is KEY if there was a key, or -2 if there wasn't. */ +int +rl_get_char () +{ + int key; + + if (push_index == pop_index) + return (-2); + + key = ibuffer[pop_index++]; + + if (pop_index >= ibuffer_len) + pop_index = 0; + + return (key); +} + +/* 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); +} + + + +static void +rl_getc (stream) + FILE *stream; +{ + int result; + int nchar; + int tty = fileno(stream); + char buf[512]; /* XXX - must be at least as large as ibuffer */ + + while (1) + { + if (ioctl(tty, FIONREAD, &nchar) == -1) + nchar = sizeof(buf); + else if (nchar <= 0) + nchar = 1; + result = ibuffer_space(); + if (nchar > result) + nchar = result; + result = read(tty, buf, nchar); + if (result > 0) + { + register char *cp = buf; + + while (--result >= 0) + rl_stuff_char(*cp++); + return; + } + if (errno != EINTR) + { + rl_stuff_char(EOF); + return; + } + } +} + +/* 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); + + while ((c = rl_get_char()) == -2) + { + if (rl_event_hook) + { + (*rl_event_hook) (); + if ((c = rl_get_char()) != -2) + return (c); + } + rl_getc(in_stream); + } + } +#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 */ + return (c); +} + +/* 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) + { + static add_macro_char (); + + 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 */ +/* */ +/* **************************************************************** */ + +/* 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; +{ + static push_executing_macro (); + + 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]) + { + static pop_executing_macro (); + + 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 +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 +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 +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)); +} + + +/* Non-zero means do not parse any lines other than comments and + parser directives. */ +static unsigned char parsing_conditionalized_out = 0; + +/* **************************************************************** */ +/* */ +/* 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 TIOCGETP + 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 */ +#endif /* TIOCGETP */ +} + + +/* **************************************************************** */ +/* */ +/* 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. */ +int horizontal_scroll_mode = 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 (); + +/* 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 (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 || !*term_IC)) + { + output_some_chars (nfd, (ne - nfd)); + last_c_pos += (ne - nfd); + } + else + { + if (*ols) + { + start_insert (lendiff); + output_some_chars (nfd, lendiff); + last_c_pos += lendiff; + end_insert (); + } + 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; + static void output_character_function (); + + /* 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); + term_ip = tgetstr ("ip", &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." */ +#ifdef notdef + /* XXX Circumvent broken code. */ + terminal_can_insert = (term_IC || term_im || term_ic || term_ip); +#endif + + 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); + } +} + +/* Prepare to insert by inserting COUNT blank spaces. */ +static +start_insert (count) + int count; +{ + if (term_im && *term_im) + tputs (term_im, 1, output_character_function); + + if (term_IC && *term_IC && + (count > 1 || !term_ic || !*term_ic)) + { + char *tgoto (), *buffer; + buffer = tgoto (term_IC, 0, count); + tputs (buffer, 1, output_character_function); + } + else + { + if (term_ic && *term_ic) + while (count--) + tputs (term_ic, 1, output_character_function); + } +} + +/* We are finished doing our insertion. Send ending string. */ +static +end_insert () +{ + 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 */ +/* */ +/* **************************************************************** */ + +#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); + + /* 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 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 | EVENP)) == (ODDP | EVENP)) + { +#ifdef PASS8 + the_ttybuff.sg_flags |= PASS8; +#endif + +#if defined (TIOCLGET) && defined (LPASS8) + { + int flags; + ioctl (tty, TIOCLGET, &flags); + local_mode_flags = flags; + 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); +} + +/* Restore the terminal to its original state. */ +static +rl_deprep_terminal () +{ + int tty = fileno (rl_instream); + +#if defined (TIOCLGET) && defined (LPASS8) + if ((the_ttybuff.sg_flags & (ODDP | EVENP)) == (ODDP | EVENP)) + ioctl (tty, TIOCLSET, &local_mode_flags); +#endif + +#ifdef TIOCSLTC + ioctl (tty, TIOCSLTC, &original_ltchars); +#endif + +#ifdef TIOCSETC + ioctl (tty, TIOCSETC, &original_tchars); +#endif + + the_ttybuff.sg_flags = original_tty_flags; + ioctl (tty, TIOCSETN, &the_ttybuff); + readline_echoing_p = 1; +} + +#else /* !defined (NEW_TTY_DRIVER) */ +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|ISTRIP|INPCK); + +#ifndef HANDLE_SIGNALS + tio.c_lflag &= ~ISIG; +#endif + + tio.c_cc[VEOF] = 1; /* really: MIN */ + tio.c_cc[VEOL] = 0; /* really: TIME */ + ioctl (tty, TCSETAW,&tio); +} + +static +rl_deprep_terminal () +{ + int tty = fileno (rl_instream); + ioctl (tty, TCSETAW, &otio); +} +#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. */ +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; + + move_vert(curr_line); + move_cursor_relative (0, the_line); /* XXX is this right */ + 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; + static void output_character_function (); + + 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 descreaser; + + string = (char *)alloca (1024 + 1); + + for (i = 0; i < 1024; i++) + string[i] = c; + + while (count) + { + descreaser = (count > 1024 ? 1024 : count); + string[descreaser] = '\0'; + rl_insert_text (string); + count -= descreaser; + } + 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 slen, key = 0, t; + + i = 0; + string = (char *)alloca (ibuffer_len + 1); + string[i++] = c; + + while ((key = rl_get_char()) != -2 && + (keymap[key].type == ISFUNC && + keymap[key].function == rl_insert)) + string[i++] = key; + + if (key != -2) + 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 (in_stream); + rl_insert (count, c); +} + +/* Insert a tab character. */ +rl_tab_insert (count) + int count; +{ + rl_insert (count, '\t'); +} + +#ifdef VI_MODE +/* Non-zero means enter insertion mode. */ +static vi_doing_insert = 0; +#endif + +/* 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 + { + 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--; + 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; +{ + if (count < 0) + { + rl_rubout (-count); + return; + } + + if (rl_point == rl_end) + { + ding (); + return; + } + +#ifdef VI_MODE + if ((count > 1) || ((count == 1) && (rl_editing_mode == vi_mode))) +#else + if (count > 1) +#endif + { + int orig_point = rl_point; + while (count && (rl_point < rl_end)) + { + rl_point++; + 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); + if (running_in_emacs) + printf ("%s", the_line); +} + +/* 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 (in_stream); + 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: + 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); + } +} + +/* 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 (in_stream); + + /* 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; +#ifdef SHELL + { + extern int follow_symbolic_links; + char *make_absolute (); + + if (follow_symbolic_links && (strcmp (dirname, ".") != 0)) + { + temp_dirname = make_absolute (dirname, get_working_directory ("")); + + if (temp_dirname) + { + free (dirname); + dirname = temp_dirname; + } + } + } +#endif /* SHELL */ + } + directory = opendir (dirname); + filename_len = strlen (filename); + + rl_filename_completion_desired = 1; + } + + /* At this point we should entertain the possibility of hacking wildcarded + filenames, like /usr/man*\/te<TAB>. If the directory name contains + globbing characters, then build an array of directories to glob on, and + glob on the first one. */ + + /* Now that we have some state, we can read the directory. */ + + while (directory && (entry = readdir (directory))) + { + /* Special case for no filename. + All entries except "." and ".." match. */ + if (!filename_len) + { + if ((strcmp (entry->d_name, ".") != 0) && + (strcmp (entry->d_name, "..") != 0)) + break; + } + else + { + /* Otherwise, if these match upto the length of filename, then + it is a match. */ +#ifdef TMB_SYSV + if ((strlen (entry->d_name) >= filename_len) && + (strncmp (filename, entry->d_name, filename_len) == 0)) +#else + if ((entry->d_namlen >= filename_len) && + (strncmp (filename, entry->d_name, filename_len) == 0)) +#endif /* TMB_SYSV */ + { + break; + } + } + } + + if (!entry) + { + if (directory) + { + closedir (directory); + directory = (DIR *)NULL; + } + return (char *)NULL; + } + else + { + char *temp; + + if (dirname && (strcmp (dirname, ".") != 0)) + { +#ifdef TMB_SYSV + temp = (char *)xmalloc (1 + strlen (users_dirname) + + strlen (entry->d_name)); +#else + temp = (char *)xmalloc (1 + strlen (users_dirname) + + entry->d_namlen); +#endif /* TMB_SYSV */ + strcpy (temp, users_dirname); + strcat (temp, entry->d_name); + } + else + { + temp = (savestring (entry->d_name)); + } + return (temp); + } +} + + +/* **************************************************************** */ +/* */ +/* 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; + int start; + + /* 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; + + /* Handle mapping of the ESC Key in vi mode */ + start = 0; +#ifdef VI_MODE + if ((rl_editing_mode == vi_mode) && (keys[0] == ESC)) + { + start++; + map = vi_movement_keymap; + if(keys[1] == ESC) + { + extern KEYMAP_ENTRY_ARRAY vi_escape_keymap; + + start++; + map = vi_escape_keymap; + } + } +#endif + + /* Bind keys, making new keymaps as necessary. */ + for (i = start; 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; + } + + array[l] = '\0'; + *len = l; + 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; + static int stricmp (); + + 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; +{ + 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 = getc(file)) != EOF) + { + /* If comment, flush to EOL. */ + if (c == '#') + { + while ((c = 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 = 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; + static int stricmp (); + + /* 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; + static int stricmp (); + + /* 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 (), stricmp (); + 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; +{ + static int strnicmp (), stricmp (); + + 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; + } +} + +/* 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; + static int stricmp (); + + 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); +} + + +#ifdef STATIC_MALLOC + +/* **************************************************************** */ +/* */ +/* xmalloc and xrealloc () */ +/* */ +/* **************************************************************** */ + +static char * +xmalloc (bytes) + int bytes; +{ + static memory_error_and_abort (); + char *temp = (char *)malloc (bytes); + + if (!temp) + memory_error_and_abort (); + return (temp); +} + +static char * +xrealloc (pointer, bytes) + char *pointer; + int bytes; +{ + static memory_error_and_abort (); + char *temp = (char *)realloc (pointer, bytes); + + if (!temp) + memory_error_and_abort (); + return (temp); +} + +static +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/gnu/usr.bin/gdb/readline/readline.h b/gnu/usr.bin/gdb/readline/readline.h new file mode 100644 index 0000000..7d7fbe7 --- /dev/null +++ b/gnu/usr.bin/gdb/readline/readline.h @@ -0,0 +1,161 @@ +/* Readline.h -- the names of functions callable from within readline. */ + +#ifndef _READLINE_H_ +#define _READLINE_H_ + +#include <readline/keymaps.h> + +#ifndef __FUNCTION_DEF +typedef int Function (); +#define __FUNCTION_DEF +#endif + +/* The functions for manipulating the text of the line within readline. +Most of these functions are bound to keys by default. */ +extern int +rl_beg_of_line (), rl_backward (), rl_delete (), rl_end_of_line (), +rl_forward (), ding (), rl_backward (), rl_newline (), rl_kill_line (), +rl_clear_screen (), rl_get_next_history (), rl_get_previous_history (), +rl_quoted_insert (), rl_reverse_search_history (), rl_transpose_chars +(), rl_unix_line_discard (), rl_quoted_insert (), rl_unix_word_rubout +(), rl_yank (), rl_rubout (), rl_backward_word (), rl_kill_word (), +rl_forward_word (), rl_tab_insert (), rl_yank_pop (), rl_yank_nth_arg (), +rl_backward_kill_word (), rl_backward_kill_line (), rl_transpose_words +(), rl_complete (), rl_possible_completions (), rl_do_lowercase_version +(), rl_digit_argument (), rl_universal_argument (), rl_abort (), +rl_undo_command (), rl_revert_line (), rl_beginning_of_history (), +rl_end_of_history (), rl_forward_search_history (), rl_insert (), +rl_upcase_word (), rl_downcase_word (), rl_capitalize_word (), +rl_restart_output (), rl_re_read_init_file (); + +/* These are *both* defined even when VI_MODE is not. */ +extern int rl_vi_editing_mode (), rl_emacs_editing_mode (); + +#ifdef VI_MODE +/* Things for vi mode. */ +extern int rl_vi_movement_mode (), rl_vi_insertion_mode (), rl_vi_arg_digit (), +rl_vi_prev_word (), rl_vi_next_word (), rl_vi_char_search (), +rl_vi_eof_maybe (), rl_vi_append_mode (), rl_vi_put (), +rl_vi_append_eol (), rl_vi_insert_beg (), rl_vi_delete (), rl_vi_comment (), +rl_vi_first_print (), rl_vi_fword (), rl_vi_fWord (), rl_vi_bword (), +rl_vi_bWord (), rl_vi_eword (), rl_vi_eWord (), rl_vi_end_word (), +rl_vi_change_case (), rl_vi_match (), rl_vi_bracktype (), rl_vi_change_char (), +rl_vi_yank_arg (), rl_vi_search (), rl_vi_search_again (), +rl_vi_dosearch (), rl_vi_subst (), rl_vi_overstrike (), +rl_vi_overstrike_delete (), rl_vi_replace(), rl_vi_column (), +rl_vi_delete_to (), rl_vi_change_to (), rl_vi_yank_to (), rl_vi_complete (); +#endif /* VI_MODE */ + +/* Keyboard macro commands. */ +extern int +rl_start_kbd_macro (), rl_end_kbd_macro (), rl_call_last_kbd_macro (); + +/* Maintaining the state of undo. We remember individual deletes and inserts + on a chain of things to do. */ + +/* The actions that undo knows how to undo. Notice that UNDO_DELETE means + to insert some text, and UNDO_INSERT means to delete some text. I.e., + the code tells undo what to undo, not how to undo it. */ +enum undo_code { UNDO_DELETE, UNDO_INSERT, UNDO_BEGIN, UNDO_END }; + +/* What an element of THE_UNDO_LIST looks like. */ +typedef struct undo_list { + struct undo_list *next; + int start, end; /* Where the change took place. */ + char *text; /* The text to insert, if undoing a delete. */ + enum undo_code what; /* Delete, Insert, Begin, End. */ +} UNDO_LIST; + +/* The current undo list for RL_LINE_BUFFER. */ +extern UNDO_LIST *rl_undo_list; + +/* The data structure for mapping textual names to code addresses. */ +typedef struct { + char *name; + Function *function; +} FUNMAP; + +extern FUNMAP **funmap; + +/* **************************************************************** */ +/* */ +/* Well Published Variables */ +/* */ +/* **************************************************************** */ + +/* The name of the calling program. You should initialize this to + whatever was in argv[0]. It is used when parsing conditionals. */ +extern char *rl_readline_name; + +/* The line buffer that is in use. */ +extern char *rl_line_buffer; + +/* The location of point, and end. */ +extern int rl_point, rl_end; + +/* The name of the terminal to use. */ +extern char *rl_terminal_name; + +/* The input and output streams. */ +extern FILE *rl_instream, *rl_outstream; + +/* The basic list of characters that signal a break between words for the + completer routine. The contents of this variable is what breaks words + in the shell, i.e. "n\"\\'`@$>". */ +extern char *rl_basic_word_break_characters; + +/* The list of characters that signal a break between words for + rl_complete_internal. The default list is the contents of + rl_basic_word_break_characters. */ +extern char *rl_completer_word_break_characters; + +/* List of characters that are word break characters, but should be left + in TEXT when it is passed to the completion function. The shell uses + this to help determine what kind of completing to do. */ +extern char *rl_special_prefixes; + +/* Pointer to the generator function for completion_matches (). + NULL means to use filename_entry_function (), the default filename + completer. */ +extern Function *rl_completion_entry_function; + +/* Pointer to alternative function to create matches. + Function is called with TEXT, START, and END. + START and END are indices in RL_LINE_BUFFER saying what the boundaries + of TEXT are. + If this function exists and returns NULL then call the value of + rl_completion_entry_function to try to match, otherwise use the + array of strings returned. */ +extern Function *rl_attempted_completion_function; + +/* If non-null, this contains the address of a function to call if the + standard meaning for expanding a tilde fails. The function is called + with the text (sans tilde, as in "foo"), and returns a malloc()'ed string + which is the expansion, or a NULL pointer if there is no expansion. */ +extern Function *rl_tilde_expander; + +/* If non-zero, then this is the address of a function to call just + before readline_internal () prints the first prompt. */ +extern Function *rl_startup_hook; + +/* **************************************************************** */ +/* */ +/* 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/gnu/usr.bin/gdb/readline/vi_keymap.c b/gnu/usr.bin/gdb/readline/vi_keymap.c new file mode 100644 index 0000000..71c7ec8 --- /dev/null +++ b/gnu/usr.bin/gdb/readline/vi_keymap.c @@ -0,0 +1,484 @@ +/*- + * This code is derived from software copyrighted by the Free Software + * Foundation. + * + * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. + * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory. + * + * @(#)vi_keymap.c 6.4 (Berkeley) 5/8/91 + */ + +/* vi_keymap.c -- the keymap for vi_mode in readline (). */ + +/* Copyright (C) 1988,1989 Free Software Foundation, Inc. + + This file is part of GNU Readline, a library for reading lines + of text with interactive input and history editing. + + Readline is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 1, or (at your option) any + later version. + + Readline is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Readline; see the file COPYING. If not, write to the Free + Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef FILE +#include <stdio.h> +#endif /* FILE */ + +#include "readline.h" + +extern KEYMAP_ENTRY_ARRAY vi_escape_keymap; + +/* The keymap arrays for handling vi mode. */ +KEYMAP_ENTRY_ARRAY vi_movement_keymap = { + + /* The regular control keys come first. */ + { ISFUNC, (Function *)0x0 }, /* Control-@ */ + { ISFUNC, (Function *)0x0 }, /* Control-a */ + { ISFUNC, (Function *)0x0 }, /* Control-b */ + { ISFUNC, (Function *)0x0 }, /* Control-c */ + { ISFUNC, rl_vi_eof_maybe }, /* Control-d */ + { ISFUNC, rl_emacs_editing_mode }, /* Control-e */ + { ISFUNC, (Function *)0x0 }, /* Control-f */ + { ISFUNC, rl_abort }, /* Control-g */ + { ISFUNC, rl_backward }, /* Control-h */ + { ISFUNC, (Function *)0x0 }, /* Control-i */ + { ISFUNC, rl_newline }, /* Control-j */ + { ISFUNC, rl_kill_line }, /* Control-k */ + { ISFUNC, rl_clear_screen }, /* Control-l */ + { ISFUNC, rl_newline }, /* Control-m */ + { ISFUNC, rl_get_next_history }, /* Control-n */ + { ISFUNC, (Function *)0x0 }, /* Control-o */ + { ISFUNC, rl_get_previous_history }, /* Control-p */ + { ISFUNC, rl_quoted_insert }, /* Control-q */ + { ISFUNC, rl_reverse_search_history }, /* Control-r */ + { ISFUNC, rl_forward_search_history }, /* Control-s */ + { ISFUNC, rl_transpose_chars }, /* Control-t */ + { ISFUNC, rl_unix_line_discard }, /* Control-u */ + { ISFUNC, rl_quoted_insert }, /* Control-v */ + { ISFUNC, rl_unix_word_rubout }, /* Control-w */ + { ISFUNC, (Function *)0x0 }, /* Control-x */ + { ISFUNC, rl_yank }, /* Control-y */ + { ISFUNC, (Function *)0x0 }, /* Control-z */ + + { ISKMAP, (Function *)vi_escape_keymap }, /* Control-[ */ + { ISFUNC, (Function *)0x0 }, /* Control-\ */ + { ISFUNC, (Function *)0x0 }, /* Control-] */ + { ISFUNC, (Function *)0x0 }, /* Control-^ */ + { ISFUNC, rl_undo_command }, /* Control-_ */ + + /* The start of printing characters. */ + { ISFUNC, rl_forward }, /* SPACE */ + { ISFUNC, (Function *)0x0 }, /* ! */ + { ISFUNC, (Function *)0x0 }, /* " */ + { ISFUNC, rl_vi_comment }, /* # */ + { ISFUNC, rl_end_of_line }, /* $ */ + { ISFUNC, rl_vi_match }, /* % */ + { ISFUNC, (Function *)0x0 }, /* & */ + { ISFUNC, (Function *)0x0 }, /* ' */ + { ISFUNC, (Function *)0x0 }, /* ( */ + { ISFUNC, (Function *)0x0 }, /* ) */ + { ISFUNC, rl_vi_complete }, /* * */ + { ISFUNC, rl_get_previous_history}, /* + */ + { ISFUNC, rl_vi_char_search }, /* , */ + { ISFUNC, rl_get_next_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/gnu/usr.bin/gdb/readline/vi_mode.c b/gnu/usr.bin/gdb/readline/vi_mode.c new file mode 100644 index 0000000..3a13cc6 --- /dev/null +++ b/gnu/usr.bin/gdb/readline/vi_mode.c @@ -0,0 +1,875 @@ +/*- + * This code is derived from software copyrighted by the Free Software + * Foundation. + * + * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. + * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory. + * + * @(#)vi_mode.c 6.4 (Berkeley) 5/8/91 + */ + +/* vi_mode.c -- A vi emulation mode for Bash. + Mostly 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; + +/* *** 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); +} + +/* 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; + char *p; + + switch (key) + { + case '?': + dir = 1; + break; + + case '/': + dir = -1; + break; + + default: + ding (); + return; + } + + vi_histpos = where_history (); + maybe_save_line (); + + /* 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); + + while (c = rl_read_key (in_stream)) + { + switch (c) + { + case CTRL('W'): + case CTRL('U'): + case CTRL('H'): + case RUBOUT: + 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])) + { + rl_vi_end_word (1, 'E'); + rl_point++; + } + rl_complete_internal ('*'); + 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; + 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); + 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)) + { + if(rl_point != rl_end) + rl_point++; + } + + 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 () +{ + int c, save; + + rl_mark = rl_point; + c = rl_read_key (in_stream); + + if (!member (c, vi_motion)) + { + if (digit (c)) + { + save = rl_numeric_arg; + rl_digit_loop1 (); + rl_numeric_arg *= save; + } + 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--; + while((rl_point > 0) && whitespace (the_line[rl_point])) + rl_point--; + 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); + 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; +{ + if (uppercase_p (key)) + rl_stuff_char ('$'); + + if (rl_vi_domove ()) + { + ding (); + return; + } + + rl_kill_text (rl_point, rl_mark); +} + +rl_vi_change_to (count, key) + int count, key; +{ + if (uppercase_p (key)) + rl_stuff_char ('$'); + + if (rl_vi_domove ()) + { + ding (); + return; + } + + 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 save = rl_point; + + if (uppercase_p (key)) + rl_stuff_char ('$'); + + if (rl_vi_domove ()) + { + 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); + if (rl_point > 0) + rl_backward (1); + } + else + rl_delete (count); +} + +/* 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_read_key(); + + 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_read_key(); + + switch (c) + { + case '\033': + case CTRL('C'): + return; + + default: + rl_begin_undo_group (); + rl_delete (1); + 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); + + 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); + 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[CTRL('H')].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; +} diff --git a/gnu/usr.bin/gdb/regex.c b/gnu/usr.bin/gdb/regex.c new file mode 100644 index 0000000..45c3478 --- /dev/null +++ b/gnu/usr.bin/gdb/regex.c @@ -0,0 +1,1738 @@ +/* Extended regular expression matching and search library. + Copyright (C) 1985, 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. + + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! */ + + +/* To test, compile with -Dtest. + This Dtestable feature turns this into a self-contained program + which reads a pattern, describes how it compiles, + then reads a string and searches for it. */ + +#ifdef emacs + +/* The `emacs' switch turns on certain special matching commands + that make sense only in emacs. */ + +#include "config.h" +#include "lisp.h" +#include "buffer.h" +#include "syntax.h" + +#else /* not emacs */ + +#ifdef USG +#ifndef BSTRING +#define bcopy(s,d,n) memcpy((d),(s),(n)) +#define bcmp(s1,s2,n) memcmp((s1),(s2),(n)) +#define bzero(s,n) memset((s),0,(n)) +#endif +#endif + +/* Make alloca work the best possible way. */ +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else +#ifdef sparc +#include <alloca.h> +#endif +#endif + +/* + * Define the syntax stuff, so we can do the \<...\> things. + */ + +#ifndef Sword /* must be non-zero in some of the tests below... */ +#define Sword 1 +#endif + +#define SYNTAX(c) re_syntax_table[c] + +#ifdef SYNTAX_TABLE + +char *re_syntax_table; + +#else + +static char re_syntax_table[256]; + +static void +init_syntax_once () +{ + register int c; + static int done = 0; + + if (done) + return; + + bzero (re_syntax_table, sizeof re_syntax_table); + + for (c = 'a'; c <= 'z'; c++) + re_syntax_table[c] = Sword; + + for (c = 'A'; c <= 'Z'; c++) + re_syntax_table[c] = Sword; + + for (c = '0'; c <= '9'; c++) + re_syntax_table[c] = Sword; + + done = 1; +} + +#endif /* SYNTAX_TABLE */ +#endif /* not emacs */ + +#include "regex.h" + +/* Number of failure points to allocate space for initially, + when matching. If this number is exceeded, more space is allocated, + so it is not a hard limit. */ + +#ifndef NFAILURES +#define NFAILURES 80 +#endif /* NFAILURES */ + +/* width of a byte in bits */ + +#define BYTEWIDTH 8 + +#ifndef SIGN_EXTEND_CHAR +#define SIGN_EXTEND_CHAR(x) (x) +#endif + +static int obscure_syntax = 0; + +/* Specify the precise syntax of regexp for compilation. + This provides for compatibility for various utilities + which historically have different, incompatible syntaxes. + + The argument SYNTAX is a bit-mask containing the two bits + RE_NO_BK_PARENS and RE_NO_BK_VBAR. */ + +int +re_set_syntax (syntax) +{ + int ret; + + ret = obscure_syntax; + obscure_syntax = syntax; + return ret; +} + +/* re_compile_pattern takes a regular-expression string + and converts it into a buffer full of byte commands for matching. + + PATTERN is the address of the pattern string + SIZE is the length of it. + BUFP is a struct re_pattern_buffer * which points to the info + on where to store the byte commands. + This structure contains a char * which points to the + actual space, which should have been obtained with malloc. + re_compile_pattern may use realloc to grow the buffer space. + + The number of bytes of commands can be found out by looking in + the struct re_pattern_buffer that bufp pointed to, + after re_compile_pattern returns. +*/ + +#define PATPUSH(ch) (*b++ = (char) (ch)) + +#define PATFETCH(c) \ + {if (p == pend) goto end_of_pattern; \ + c = * (unsigned char *) p++; \ + if (translate) c = translate[c]; } + +#define PATFETCH_RAW(c) \ + {if (p == pend) goto end_of_pattern; \ + c = * (unsigned char *) p++; } + +#define PATUNFETCH p-- + +#define EXTEND_BUFFER \ + { char *old_buffer = bufp->buffer; \ + if (bufp->allocated == (1<<16)) goto too_big; \ + bufp->allocated *= 2; \ + if (bufp->allocated > (1<<16)) bufp->allocated = (1<<16); \ + if (!(bufp->buffer = (char *) realloc (bufp->buffer, bufp->allocated))) \ + goto memory_exhausted; \ + c = bufp->buffer - old_buffer; \ + b += c; \ + if (fixup_jump) \ + fixup_jump += c; \ + if (laststart) \ + laststart += c; \ + begalt += c; \ + if (pending_exact) \ + pending_exact += c; \ + } + +static int store_jump (), insert_jump (); + +char * +re_compile_pattern (pattern, size, bufp) + char *pattern; + int size; + struct re_pattern_buffer *bufp; +{ + register char *b = bufp->buffer; + register char *p = pattern; + char *pend = pattern + size; + register unsigned c, c1; + char *p1; + unsigned char *translate = (unsigned char *) bufp->translate; + + /* address of the count-byte of the most recently inserted "exactn" command. + This makes it possible to tell whether a new exact-match character + can be added to that command or requires a new "exactn" command. */ + + char *pending_exact = 0; + + /* address of the place where a forward-jump should go + to the end of the containing expression. + Each alternative of an "or", except the last, ends with a forward-jump + of this sort. */ + + char *fixup_jump = 0; + + /* address of start of the most recently finished expression. + This tells postfix * where to find the start of its operand. */ + + char *laststart = 0; + + /* In processing a repeat, 1 means zero matches is allowed */ + + char zero_times_ok; + + /* In processing a repeat, 1 means many matches is allowed */ + + char many_times_ok; + + /* address of beginning of regexp, or inside of last \( */ + + char *begalt = b; + + /* Stack of information saved by \( and restored by \). + Four stack elements are pushed by each \(: + First, the value of b. + Second, the value of fixup_jump. + Third, the value of regnum. + Fourth, the value of begalt. */ + + int stackb[40]; + int *stackp = stackb; + int *stacke = stackb + 40; + int *stackt; + + /* Counts \('s as they are encountered. Remembered for the matching \), + where it becomes the "register number" to put in the stop_memory command */ + + int regnum = 1; + + bufp->fastmap_accurate = 0; + +#ifndef emacs +#ifndef SYNTAX_TABLE + /* + * Initialize the syntax table. + */ + init_syntax_once(); +#endif +#endif + + if (bufp->allocated == 0) + { + bufp->allocated = 28; + if (bufp->buffer) + /* EXTEND_BUFFER loses when bufp->allocated is 0 */ + bufp->buffer = (char *) realloc (bufp->buffer, 28); + else + /* Caller did not allocate a buffer. Do it for him */ + bufp->buffer = (char *) malloc (28); + if (!bufp->buffer) goto memory_exhausted; + begalt = b = bufp->buffer; + } + + while (p != pend) + { + if (b - bufp->buffer > bufp->allocated - 10) + /* Note that EXTEND_BUFFER clobbers c */ + EXTEND_BUFFER; + + PATFETCH (c); + + switch (c) + { + case '$': + if (obscure_syntax & RE_TIGHT_VBAR) + { + if (! (obscure_syntax & RE_CONTEXT_INDEP_OPS) && p != pend) + goto normal_char; + /* Make operand of last vbar end before this `$'. */ + if (fixup_jump) + store_jump (fixup_jump, jump, b); + fixup_jump = 0; + PATPUSH (endline); + break; + } + + /* $ means succeed if at end of line, but only in special contexts. + If randomly in the middle of a pattern, it is a normal character. */ + if (p == pend || *p == '\n' + || (obscure_syntax & RE_CONTEXT_INDEP_OPS) + || (obscure_syntax & RE_NO_BK_PARENS + ? *p == ')' + : *p == '\\' && p[1] == ')') + || (obscure_syntax & RE_NO_BK_VBAR + ? *p == '|' + : *p == '\\' && p[1] == '|')) + { + PATPUSH (endline); + break; + } + goto normal_char; + + case '^': + /* ^ means succeed if at beg of line, but only if no preceding pattern. */ + + if (laststart && p[-2] != '\n' + && ! (obscure_syntax & RE_CONTEXT_INDEP_OPS)) + goto normal_char; + if (obscure_syntax & RE_TIGHT_VBAR) + { + if (p != pattern + 1 + && ! (obscure_syntax & RE_CONTEXT_INDEP_OPS)) + goto normal_char; + PATPUSH (begline); + begalt = b; + } + else + PATPUSH (begline); + break; + + case '+': + case '?': + if (obscure_syntax & RE_BK_PLUS_QM) + goto normal_char; + handle_plus: + case '*': + /* If there is no previous pattern, char not special. */ + if (!laststart && ! (obscure_syntax & RE_CONTEXT_INDEP_OPS)) + goto normal_char; + /* If there is a sequence of repetition chars, + collapse it down to equivalent to just one. */ + zero_times_ok = 0; + many_times_ok = 0; + while (1) + { + zero_times_ok |= c != '+'; + many_times_ok |= c != '?'; + if (p == pend) + break; + PATFETCH (c); + if (c == '*') + ; + else if (!(obscure_syntax & RE_BK_PLUS_QM) + && (c == '+' || c == '?')) + ; + else if ((obscure_syntax & RE_BK_PLUS_QM) + && c == '\\') + { + int c1; + PATFETCH (c1); + if (!(c1 == '+' || c1 == '?')) + { + PATUNFETCH; + PATUNFETCH; + break; + } + c = c1; + } + else + { + PATUNFETCH; + break; + } + } + + /* Star, etc. applied to an empty pattern is equivalent + to an empty pattern. */ + if (!laststart) + break; + + /* Now we know whether 0 matches is allowed, + and whether 2 or more matches is allowed. */ + if (many_times_ok) + { + /* If more than one repetition is allowed, + put in a backward jump at the end. */ + store_jump (b, maybe_finalize_jump, laststart - 3); + b += 3; + } + insert_jump (on_failure_jump, laststart, b + 3, b); + pending_exact = 0; + b += 3; + if (!zero_times_ok) + { + /* At least one repetition required: insert before the loop + a skip over the initial on-failure-jump instruction */ + insert_jump (dummy_failure_jump, laststart, laststart + 6, b); + b += 3; + } + break; + + case '.': + laststart = b; + PATPUSH (anychar); + break; + + case '[': + while (b - bufp->buffer + > bufp->allocated - 3 - (1 << BYTEWIDTH) / BYTEWIDTH) + /* Note that EXTEND_BUFFER clobbers c */ + EXTEND_BUFFER; + + laststart = b; + if (*p == '^') + PATPUSH (charset_not), p++; + else + PATPUSH (charset); + p1 = p; + + PATPUSH ((1 << BYTEWIDTH) / BYTEWIDTH); + /* Clear the whole map */ + bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH); + /* Read in characters and ranges, setting map bits */ + while (1) + { + PATFETCH (c); + if (c == ']' && p != p1 + 1) break; + if (*p == '-' && p[1] != ']') + { + PATFETCH (c1); + PATFETCH (c1); + while (c <= c1) + b[c / BYTEWIDTH] |= 1 << (c % BYTEWIDTH), c++; + } + else + { + b[c / BYTEWIDTH] |= 1 << (c % BYTEWIDTH); + } + } + /* Discard any bitmap bytes that are all 0 at the end of the map. + Decrement the map-length byte too. */ + while ((int) b[-1] > 0 && b[b[-1] - 1] == 0) + b[-1]--; + b += b[-1]; + break; + + case '(': + if (! (obscure_syntax & RE_NO_BK_PARENS)) + goto normal_char; + else + goto handle_open; + + case ')': + if (! (obscure_syntax & RE_NO_BK_PARENS)) + goto normal_char; + else + goto handle_close; + + case '\n': + if (! (obscure_syntax & RE_NEWLINE_OR)) + goto normal_char; + else + goto handle_bar; + + case '|': + if (! (obscure_syntax & RE_NO_BK_VBAR)) + goto normal_char; + else + goto handle_bar; + + case '\\': + if (p == pend) goto invalid_pattern; + PATFETCH_RAW (c); + switch (c) + { + case '(': + if (obscure_syntax & RE_NO_BK_PARENS) + goto normal_backsl; + handle_open: + if (stackp == stacke) goto nesting_too_deep; + if (regnum < RE_NREGS) + { + PATPUSH (start_memory); + PATPUSH (regnum); + } + *stackp++ = b - bufp->buffer; + *stackp++ = fixup_jump ? fixup_jump - bufp->buffer + 1 : 0; + *stackp++ = regnum++; + *stackp++ = begalt - bufp->buffer; + fixup_jump = 0; + laststart = 0; + begalt = b; + break; + + case ')': + if (obscure_syntax & RE_NO_BK_PARENS) + goto normal_backsl; + handle_close: + if (stackp == stackb) goto unmatched_close; + begalt = *--stackp + bufp->buffer; + if (fixup_jump) + store_jump (fixup_jump, jump, b); + if (stackp[-1] < RE_NREGS) + { + PATPUSH (stop_memory); + PATPUSH (stackp[-1]); + } + stackp -= 2; + fixup_jump = 0; + if (*stackp) + fixup_jump = *stackp + bufp->buffer - 1; + laststart = *--stackp + bufp->buffer; + break; + + case '|': + if (obscure_syntax & RE_NO_BK_VBAR) + goto normal_backsl; + handle_bar: + insert_jump (on_failure_jump, begalt, b + 6, b); + pending_exact = 0; + b += 3; + if (fixup_jump) + store_jump (fixup_jump, jump, b); + fixup_jump = b; + b += 3; + laststart = 0; + begalt = b; + break; + +#ifdef emacs + case '=': + PATPUSH (at_dot); + break; + + case 's': + laststart = b; + PATPUSH (syntaxspec); + PATFETCH (c); + PATPUSH (syntax_spec_code[c]); + break; + + case 'S': + laststart = b; + PATPUSH (notsyntaxspec); + PATFETCH (c); + PATPUSH (syntax_spec_code[c]); + break; +#endif /* emacs */ + + case 'w': + laststart = b; + PATPUSH (wordchar); + break; + + case 'W': + laststart = b; + PATPUSH (notwordchar); + break; + + case '<': + PATPUSH (wordbeg); + break; + + case '>': + PATPUSH (wordend); + break; + + case 'b': + PATPUSH (wordbound); + break; + + case 'B': + PATPUSH (notwordbound); + break; + + case '`': + PATPUSH (begbuf); + break; + + case '\'': + PATPUSH (endbuf); + break; + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + c1 = c - '0'; + if (c1 >= regnum) + goto normal_char; + for (stackt = stackp - 2; stackt > stackb; stackt -= 4) + if (*stackt == c1) + goto normal_char; + laststart = b; + PATPUSH (duplicate); + PATPUSH (c1); + break; + + case '+': + case '?': + if (obscure_syntax & RE_BK_PLUS_QM) + goto handle_plus; + + default: + normal_backsl: + /* You might think it would be useful for \ to mean + not to translate; but if we don't translate it + it will never match anything. */ + if (translate) c = translate[c]; + goto normal_char; + } + break; + + default: + normal_char: + if (!pending_exact || pending_exact + *pending_exact + 1 != b + || *pending_exact == 0177 || *p == '*' || *p == '^' + || ((obscure_syntax & RE_BK_PLUS_QM) + ? *p == '\\' && (p[1] == '+' || p[1] == '?') + : (*p == '+' || *p == '?'))) + { + laststart = b; + PATPUSH (exactn); + pending_exact = b; + PATPUSH (0); + } + PATPUSH (c); + (*pending_exact)++; + } + } + + if (fixup_jump) + store_jump (fixup_jump, jump, b); + + if (stackp != stackb) goto unmatched_open; + + bufp->used = b - bufp->buffer; + return 0; + + invalid_pattern: + return "Invalid regular expression"; + + unmatched_open: + return "Unmatched \\("; + + unmatched_close: + return "Unmatched \\)"; + + end_of_pattern: + return "Premature end of regular expression"; + + nesting_too_deep: + return "Nesting too deep"; + + too_big: + return "Regular expression too big"; + + memory_exhausted: + return "Memory exhausted"; +} + +/* Store where `from' points a jump operation to jump to where `to' points. + `opcode' is the opcode to store. */ + +static int +store_jump (from, opcode, to) + char *from, *to; + char opcode; +{ + from[0] = opcode; + from[1] = (to - (from + 3)) & 0377; + from[2] = (to - (from + 3)) >> 8; +} + +/* Open up space at char FROM, and insert there a jump to TO. + CURRENT_END gives te end of the storage no in use, + so we know how much data to copy up. + OP is the opcode of the jump to insert. + + If you call this function, you must zero out pending_exact. */ + +static int +insert_jump (op, from, to, current_end) + char op; + char *from, *to, *current_end; +{ + register char *pto = current_end + 3; + register char *pfrom = current_end; + while (pfrom != from) + *--pto = *--pfrom; + store_jump (from, op, to); +} + +/* Given a pattern, compute a fastmap from it. + The fastmap records which of the (1 << BYTEWIDTH) possible characters + can start a string that matches the pattern. + This fastmap is used by re_search to skip quickly over totally implausible text. + + The caller must supply the address of a (1 << BYTEWIDTH)-byte data area + as bufp->fastmap. + The other components of bufp describe the pattern to be used. */ + +void +re_compile_fastmap (bufp) + struct re_pattern_buffer *bufp; +{ + unsigned char *pattern = (unsigned char *) bufp->buffer; + int size = bufp->used; + register char *fastmap = bufp->fastmap; + register unsigned char *p = pattern; + register unsigned char *pend = pattern + size; + register int j, k; + unsigned char *translate = (unsigned char *) bufp->translate; + + unsigned char *stackb[NFAILURES]; + unsigned char **stackp = stackb; + + bzero (fastmap, (1 << BYTEWIDTH)); + bufp->fastmap_accurate = 1; + bufp->can_be_null = 0; + + while (p) + { + if (p == pend) + { + bufp->can_be_null = 1; + break; + } +#ifdef SWITCH_ENUM_BUG + switch ((int) ((enum regexpcode) *p++)) +#else + switch ((enum regexpcode) *p++) +#endif + { + case exactn: + if (translate) + fastmap[translate[p[1]]] = 1; + else + fastmap[p[1]] = 1; + break; + + case begline: + case before_dot: + case at_dot: + case after_dot: + case begbuf: + case endbuf: + case wordbound: + case notwordbound: + case wordbeg: + case wordend: + continue; + + case endline: + if (translate) + fastmap[translate['\n']] = 1; + else + fastmap['\n'] = 1; + if (bufp->can_be_null != 1) + bufp->can_be_null = 2; + break; + + case finalize_jump: + case maybe_finalize_jump: + case jump: + case dummy_failure_jump: + bufp->can_be_null = 1; + j = *p++ & 0377; + j += SIGN_EXTEND_CHAR (*(char *)p) << 8; + p += j + 1; /* The 1 compensates for missing ++ above */ + if (j > 0) + continue; + /* Jump backward reached implies we just went through + the body of a loop and matched nothing. + Opcode jumped to should be an on_failure_jump. + Just treat it like an ordinary jump. + For a * loop, it has pushed its failure point already; + if so, discard that as redundant. */ + if ((enum regexpcode) *p != on_failure_jump) + continue; + p++; + j = *p++ & 0377; + j += SIGN_EXTEND_CHAR (*(char *)p) << 8; + p += j + 1; /* The 1 compensates for missing ++ above */ + if (stackp != stackb && *stackp == p) + stackp--; + continue; + + case on_failure_jump: + j = *p++ & 0377; + j += SIGN_EXTEND_CHAR (*(char *)p) << 8; + p++; + *++stackp = p + j; + continue; + + case start_memory: + case stop_memory: + p++; + continue; + + case duplicate: + bufp->can_be_null = 1; + fastmap['\n'] = 1; + case anychar: + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (j != '\n') + fastmap[j] = 1; + if (bufp->can_be_null) + return; + /* Don't return; check the alternative paths + so we can set can_be_null if appropriate. */ + break; + + case wordchar: + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) == Sword) + fastmap[j] = 1; + break; + + case notwordchar: + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) != Sword) + fastmap[j] = 1; + break; + +#ifdef emacs + case syntaxspec: + k = *p++; + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) == (enum syntaxcode) k) + fastmap[j] = 1; + break; + + case notsyntaxspec: + k = *p++; + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) != (enum syntaxcode) k) + fastmap[j] = 1; + break; +#endif /* emacs */ + + case charset: + for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) + if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))) + { + if (translate) + fastmap[translate[j]] = 1; + else + fastmap[j] = 1; + } + break; + + case charset_not: + /* Chars beyond end of map must be allowed */ + for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++) + if (translate) + fastmap[translate[j]] = 1; + else + fastmap[j] = 1; + + for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) + if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))) + { + if (translate) + fastmap[translate[j]] = 1; + else + fastmap[j] = 1; + } + break; + } + + /* Get here means we have successfully found the possible starting characters + of one path of the pattern. We need not follow this path any farther. + Instead, look at the next alternative remembered in the stack. */ + if (stackp != stackb) + p = *stackp--; + else + break; + } +} + +/* Like re_search_2, below, but only one string is specified. */ + +int +re_search (pbufp, string, size, startpos, range, regs) + struct re_pattern_buffer *pbufp; + char *string; + int size, startpos, range; + struct re_registers *regs; +{ + return re_search_2 (pbufp, 0, 0, string, size, startpos, range, regs, size); +} + +/* Like re_match_2 but tries first a match starting at index STARTPOS, + then at STARTPOS + 1, and so on. + RANGE is the number of places to try before giving up. + If RANGE is negative, the starting positions tried are + STARTPOS, STARTPOS - 1, etc. + It is up to the caller to make sure that range is not so large + as to take the starting position outside of the input strings. + +The value returned is the position at which the match was found, + or -1 if no match was found, + or -2 if error (such as failure stack overflow). */ + +int +re_search_2 (pbufp, string1, size1, string2, size2, startpos, range, regs, mstop) + struct re_pattern_buffer *pbufp; + char *string1, *string2; + int size1, size2; + int startpos; + register int range; + struct re_registers *regs; + int mstop; +{ + register char *fastmap = pbufp->fastmap; + register unsigned char *translate = (unsigned char *) pbufp->translate; + int total = size1 + size2; + int val; + + /* Update the fastmap now if not correct already */ + if (fastmap && !pbufp->fastmap_accurate) + re_compile_fastmap (pbufp); + + /* Don't waste time in a long search for a pattern + that says it is anchored. */ + if (pbufp->used > 0 && (enum regexpcode) pbufp->buffer[0] == begbuf + && range > 0) + { + if (startpos > 0) + return -1; + else + range = 1; + } + + while (1) + { + /* If a fastmap is supplied, skip quickly over characters + that cannot possibly be the start of a match. + Note, however, that if the pattern can possibly match + the null string, we must test it at each starting point + so that we take the first null string we get. */ + + if (fastmap && startpos < total && pbufp->can_be_null != 1) + { + if (range > 0) + { + register int lim = 0; + register unsigned char *p; + int irange = range; + if (startpos < size1 && startpos + range >= size1) + lim = range - (size1 - startpos); + + p = ((unsigned char *) + &(startpos >= size1 ? string2 - size1 : string1)[startpos]); + + if (translate) + { + while (range > lim && !fastmap[translate[*p++]]) + range--; + } + else + { + while (range > lim && !fastmap[*p++]) + range--; + } + startpos += irange - range; + } + else + { + register unsigned char c; + if (startpos >= size1) + c = string2[startpos - size1]; + else + c = string1[startpos]; + c &= 0xff; + if (translate ? !fastmap[translate[c]] : !fastmap[c]) + goto advance; + } + } + + if (range >= 0 && startpos == total + && fastmap && pbufp->can_be_null == 0) + return -1; + + val = re_match_2 (pbufp, string1, size1, string2, size2, startpos, regs, mstop); + if (0 <= val) + { + if (val == -2) + return -2; + return startpos; + } + +#ifdef C_ALLOCA + alloca (0); +#endif /* C_ALLOCA */ + + advance: + if (!range) break; + if (range > 0) range--, startpos++; else range++, startpos--; + } + return -1; +} + +#ifndef emacs /* emacs never uses this */ +int +re_match (pbufp, string, size, pos, regs) + struct re_pattern_buffer *pbufp; + char *string; + int size, pos; + struct re_registers *regs; +{ + return re_match_2 (pbufp, 0, 0, string, size, pos, regs, size); +} +#endif /* emacs */ + +/* Maximum size of failure stack. Beyond this, overflow is an error. */ + +int re_max_failures = 2000; + +static int bcmp_translate(); +/* Match the pattern described by PBUFP + against data which is the virtual concatenation of STRING1 and STRING2. + SIZE1 and SIZE2 are the sizes of the two data strings. + Start the match at position POS. + Do not consider matching past the position MSTOP. + + If pbufp->fastmap is nonzero, then it had better be up to date. + + The reason that the data to match are specified as two components + which are to be regarded as concatenated + is so this function can be used directly on the contents of an Emacs buffer. + + -1 is returned if there is no match. -2 is returned if there is + an error (such as match stack overflow). Otherwise the value is the length + of the substring which was matched. */ + +int +re_match_2 (pbufp, string1, size1, string2, size2, pos, regs, mstop) + struct re_pattern_buffer *pbufp; + unsigned char *string1, *string2; + int size1, size2; + int pos; + struct re_registers *regs; + int mstop; +{ + register unsigned char *p = (unsigned char *) pbufp->buffer; + register unsigned char *pend = p + pbufp->used; + /* End of first string */ + unsigned char *end1; + /* End of second string */ + unsigned char *end2; + /* Pointer just past last char to consider matching */ + unsigned char *end_match_1, *end_match_2; + register unsigned char *d, *dend; + register int mcnt; + unsigned char *translate = (unsigned char *) pbufp->translate; + + /* Failure point stack. Each place that can handle a failure further down the line + pushes a failure point on this stack. It consists of two char *'s. + The first one pushed is where to resume scanning the pattern; + the second pushed is where to resume scanning the strings. + If the latter is zero, the failure point is a "dummy". + If a failure happens and the innermost failure point is dormant, + it discards that failure point and tries the next one. */ + + unsigned char *initial_stack[2 * NFAILURES]; + unsigned char **stackb = initial_stack; + unsigned char **stackp = stackb, **stacke = &stackb[2 * NFAILURES]; + + /* Information on the "contents" of registers. + These are pointers into the input strings; they record + just what was matched (on this attempt) by some part of the pattern. + The start_memory command stores the start of a register's contents + and the stop_memory command stores the end. + + At that point, regstart[regnum] points to the first character in the register, + regend[regnum] points to the first character beyond the end of the register, + regstart_seg1[regnum] is true iff regstart[regnum] points into string1, + and regend_seg1[regnum] is true iff regend[regnum] points into string1. */ + + unsigned char *regstart[RE_NREGS]; + unsigned char *regend[RE_NREGS]; + unsigned char regstart_seg1[RE_NREGS], regend_seg1[RE_NREGS]; + + /* Set up pointers to ends of strings. + Don't allow the second string to be empty unless both are empty. */ + if (!size2) + { + string2 = string1; + size2 = size1; + string1 = 0; + size1 = 0; + } + end1 = string1 + size1; + end2 = string2 + size2; + + /* Compute where to stop matching, within the two strings */ + if (mstop <= size1) + { + end_match_1 = string1 + mstop; + end_match_2 = string2; + } + else + { + end_match_1 = end1; + end_match_2 = string2 + mstop - size1; + } + + /* Initialize \) text positions to -1 + to mark ones that no \( or \) has been seen for. */ + + for (mcnt = 0; mcnt < sizeof (regend) / sizeof (*regend); mcnt++) + regend[mcnt] = (unsigned char *) -1; + + /* `p' scans through the pattern as `d' scans through the data. + `dend' is the end of the input string that `d' points within. + `d' is advanced into the following input string whenever necessary, + but this happens before fetching; + therefore, at the beginning of the loop, + `d' can be pointing at the end of a string, + but it cannot equal string2. */ + + if (pos <= size1) + d = string1 + pos, dend = end_match_1; + else + d = string2 + pos - size1, dend = end_match_2; + +/* Write PREFETCH; just before fetching a character with *d. */ +#define PREFETCH \ + while (d == dend) \ + { if (dend == end_match_2) goto fail; /* end of string2 => failure */ \ + d = string2; /* end of string1 => advance to string2. */ \ + dend = end_match_2; } + + /* This loop loops over pattern commands. + It exits by returning from the function if match is complete, + or it drops through if match fails at this starting point in the input data. */ + + while (1) + { + if (p == pend) + /* End of pattern means we have succeeded! */ + { + /* If caller wants register contents data back, convert it to indices */ + if (regs) + { + regs->start[0] = pos; + if (dend == end_match_1) + regs->end[0] = d - string1; + else + regs->end[0] = d - string2 + size1; + for (mcnt = 1; mcnt < RE_NREGS; mcnt++) + { + if (regend[mcnt] == (unsigned char *) -1) + { + regs->start[mcnt] = -1; + regs->end[mcnt] = -1; + continue; + } + if (regstart_seg1[mcnt]) + regs->start[mcnt] = regstart[mcnt] - string1; + else + regs->start[mcnt] = regstart[mcnt] - string2 + size1; + if (regend_seg1[mcnt]) + regs->end[mcnt] = regend[mcnt] - string1; + else + regs->end[mcnt] = regend[mcnt] - string2 + size1; + } + } + if (dend == end_match_1) + return (d - string1 - pos); + else + return d - string2 + size1 - pos; + } + + /* Otherwise match next pattern command */ +#ifdef SWITCH_ENUM_BUG + switch ((int) ((enum regexpcode) *p++)) +#else + switch ((enum regexpcode) *p++) +#endif + { + + /* \( is represented by a start_memory, \) by a stop_memory. + Both of those commands contain a "register number" argument. + The text matched within the \( and \) is recorded under that number. + Then, \<digit> turns into a `duplicate' command which + is followed by the numeric value of <digit> as the register number. */ + + case start_memory: + regstart[*p] = d; + regstart_seg1[*p++] = (dend == end_match_1); + break; + + case stop_memory: + regend[*p] = d; + regend_seg1[*p++] = (dend == end_match_1); + break; + + case duplicate: + { + int regno = *p++; /* Get which register to match against */ + register unsigned char *d2, *dend2; + + d2 = regstart[regno]; + dend2 = ((regstart_seg1[regno] == regend_seg1[regno]) + ? regend[regno] : end_match_1); + while (1) + { + /* Advance to next segment in register contents, if necessary */ + while (d2 == dend2) + { + if (dend2 == end_match_2) break; + if (dend2 == regend[regno]) break; + d2 = string2, dend2 = regend[regno]; /* end of string1 => advance to string2. */ + } + /* At end of register contents => success */ + if (d2 == dend2) break; + + /* Advance to next segment in data being matched, if necessary */ + PREFETCH; + + /* mcnt gets # consecutive chars to compare */ + mcnt = dend - d; + if (mcnt > dend2 - d2) + mcnt = dend2 - d2; + /* Compare that many; failure if mismatch, else skip them. */ + if (translate ? bcmp_translate (d, d2, mcnt, translate) : bcmp (d, d2, mcnt)) + goto fail; + d += mcnt, d2 += mcnt; + } + } + break; + + case anychar: + /* fetch a data character */ + PREFETCH; + /* Match anything but a newline. */ + if ((translate ? translate[*d++] : *d++) == '\n') + goto fail; + break; + + case charset: + case charset_not: + { + /* Nonzero for charset_not */ + int not = 0; + register int c; + if (*(p - 1) == (unsigned char) charset_not) + not = 1; + + /* fetch a data character */ + PREFETCH; + + if (translate) + c = translate [*d]; + else + c = *d; + + if (c < *p * BYTEWIDTH + && p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) + not = !not; + + p += 1 + *p; + + if (!not) goto fail; + d++; + break; + } + + case begline: + if (d == string1 || d[-1] == '\n') + break; + goto fail; + + case endline: + if (d == end2 + || (d == end1 ? (size2 == 0 || *string2 == '\n') : *d == '\n')) + break; + goto fail; + + /* "or" constructs ("|") are handled by starting each alternative + with an on_failure_jump that points to the start of the next alternative. + Each alternative except the last ends with a jump to the joining point. + (Actually, each jump except for the last one really jumps + to the following jump, because tensioning the jumps is a hassle.) */ + + /* The start of a stupid repeat has an on_failure_jump that points + past the end of the repeat text. + This makes a failure point so that, on failure to match a repetition, + matching restarts past as many repetitions have been found + with no way to fail and look for another one. */ + + /* A smart repeat is similar but loops back to the on_failure_jump + so that each repetition makes another failure point. */ + + case on_failure_jump: + if (stackp == stacke) + { + unsigned char **stackx; + if (stacke - stackb > re_max_failures * 2) + return -2; + stackx = (unsigned char **) alloca (2 * (stacke - stackb) + * sizeof (char *)); + bcopy (stackb, stackx, (stacke - stackb) * sizeof (char *)); + stackp = stackx + (stackp - stackb); + stacke = stackx + 2 * (stacke - stackb); + stackb = stackx; + } + mcnt = *p++ & 0377; + mcnt += SIGN_EXTEND_CHAR (*(char *)p) << 8; + p++; + *stackp++ = mcnt + p; + *stackp++ = d; + break; + + /* The end of a smart repeat has an maybe_finalize_jump back. + Change it either to a finalize_jump or an ordinary jump. */ + + case maybe_finalize_jump: + mcnt = *p++ & 0377; + mcnt += SIGN_EXTEND_CHAR (*(char *)p) << 8; + p++; + { + register unsigned char *p2 = p; + /* Compare what follows with the begining of the repeat. + If we can establish that there is nothing that they would + both match, we can change to finalize_jump */ + while (p2 != pend + && (*p2 == (unsigned char) stop_memory + || *p2 == (unsigned char) start_memory)) + p2++; + if (p2 == pend) + p[-3] = (unsigned char) finalize_jump; + else if (*p2 == (unsigned char) exactn + || *p2 == (unsigned char) endline) + { + register int c = *p2 == (unsigned char) endline ? '\n' : p2[2]; + register unsigned char *p1 = p + mcnt; + /* p1[0] ... p1[2] are an on_failure_jump. + Examine what follows that */ + if (p1[3] == (unsigned char) exactn && p1[5] != c) + p[-3] = (unsigned char) finalize_jump; + else if (p1[3] == (unsigned char) charset + || p1[3] == (unsigned char) charset_not) + { + int not = p1[3] == (unsigned char) charset_not; + if (c < p1[4] * BYTEWIDTH + && p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) + not = !not; + /* not is 1 if c would match */ + /* That means it is not safe to finalize */ + if (!not) + p[-3] = (unsigned char) finalize_jump; + } + } + } + p -= 2; + if (p[-1] != (unsigned char) finalize_jump) + { + p[-1] = (unsigned char) jump; + goto nofinalize; + } + + /* The end of a stupid repeat has a finalize-jump + back to the start, where another failure point will be made + which will point after all the repetitions found so far. */ + + case finalize_jump: + stackp -= 2; + + case jump: + nofinalize: + mcnt = *p++ & 0377; + mcnt += SIGN_EXTEND_CHAR (*(char *)p) << 8; + p += mcnt + 1; /* The 1 compensates for missing ++ above */ + break; + + case dummy_failure_jump: + if (stackp == stacke) + { + unsigned char **stackx + = (unsigned char **) alloca (2 * (stacke - stackb) + * sizeof (char *)); + bcopy (stackb, stackx, (stacke - stackb) * sizeof (char *)); + stackp = stackx + (stackp - stackb); + stacke = stackx + 2 * (stacke - stackb); + stackb = stackx; + } + *stackp++ = 0; + *stackp++ = 0; + goto nofinalize; + + case wordbound: + if (d == string1 /* Points to first char */ + || d == end2 /* Points to end */ + || (d == end1 && size2 == 0)) /* Points to end */ + break; + if ((SYNTAX (d[-1]) == Sword) + != (SYNTAX (d == end1 ? *string2 : *d) == Sword)) + break; + goto fail; + + case notwordbound: + if (d == string1 /* Points to first char */ + || d == end2 /* Points to end */ + || (d == end1 && size2 == 0)) /* Points to end */ + goto fail; + if ((SYNTAX (d[-1]) == Sword) + != (SYNTAX (d == end1 ? *string2 : *d) == Sword)) + goto fail; + break; + + case wordbeg: + if (d == end2 /* Points to end */ + || (d == end1 && size2 == 0) /* Points to end */ + || SYNTAX (* (d == end1 ? string2 : d)) != Sword) /* Next char not a letter */ + goto fail; + if (d == string1 /* Points to first char */ + || SYNTAX (d[-1]) != Sword) /* prev char not letter */ + break; + goto fail; + + case wordend: + if (d == string1 /* Points to first char */ + || SYNTAX (d[-1]) != Sword) /* prev char not letter */ + goto fail; + if (d == end2 /* Points to end */ + || (d == end1 && size2 == 0) /* Points to end */ + || SYNTAX (d == end1 ? *string2 : *d) != Sword) /* Next char not a letter */ + break; + goto fail; + +#ifdef emacs + case before_dot: + if (((d - string2 <= (unsigned) size2) + ? d - bf_p2 : d - bf_p1) + <= point) + goto fail; + break; + + case at_dot: + if (((d - string2 <= (unsigned) size2) + ? d - bf_p2 : d - bf_p1) + == point) + goto fail; + break; + + case after_dot: + if (((d - string2 <= (unsigned) size2) + ? d - bf_p2 : d - bf_p1) + >= point) + goto fail; + break; + + case wordchar: + mcnt = (int) Sword; + goto matchsyntax; + + case syntaxspec: + mcnt = *p++; + matchsyntax: + PREFETCH; + if (SYNTAX (*d++) != (enum syntaxcode) mcnt) goto fail; + break; + + case notwordchar: + mcnt = (int) Sword; + goto matchnotsyntax; + + case notsyntaxspec: + mcnt = *p++; + matchnotsyntax: + PREFETCH; + if (SYNTAX (*d++) == (enum syntaxcode) mcnt) goto fail; + break; +#else + case wordchar: + PREFETCH; + if (SYNTAX (*d++) == 0) goto fail; + break; + + case notwordchar: + PREFETCH; + if (SYNTAX (*d++) != 0) goto fail; + break; +#endif /* not emacs */ + + case begbuf: + if (d == string1) /* Note, d cannot equal string2 */ + break; /* unless string1 == string2. */ + goto fail; + + case endbuf: + if (d == end2 || (d == end1 && size2 == 0)) + break; + goto fail; + + case exactn: + /* Match the next few pattern characters exactly. + mcnt is how many characters to match. */ + mcnt = *p++; + if (translate) + { + do + { + PREFETCH; + if (translate[*d++] != *p++) goto fail; + } + while (--mcnt); + } + else + { + do + { + PREFETCH; + if (*d++ != *p++) goto fail; + } + while (--mcnt); + } + break; + } + continue; /* Successfully matched one pattern command; keep matching */ + + /* Jump here if any matching operation fails. */ + fail: + if (stackp != stackb) + /* A restart point is known. Restart there and pop it. */ + { + if (!stackp[-2]) + { /* If innermost failure point is dormant, flush it and keep looking */ + stackp -= 2; + goto fail; + } + d = *--stackp; + p = *--stackp; + if (d >= string1 && d <= end1) + dend = end_match_1; + } + else break; /* Matching at this starting point really fails! */ + } + return -1; /* Failure to match */ +} + +static int +bcmp_translate (s1, s2, len, translate) + unsigned char *s1, *s2; + register int len; + unsigned char *translate; +{ + register unsigned char *p1 = s1, *p2 = s2; + while (len) + { + if (translate [*p1++] != translate [*p2++]) return 1; + len--; + } + return 0; +} + +/* Entry points compatible with bsd4.2 regex library */ + +#ifndef emacs + +static struct re_pattern_buffer re_comp_buf; + +char * +re_comp (s) + char *s; +{ + if (!s) + { + if (!re_comp_buf.buffer) + return "No previous regular expression"; + return 0; + } + + if (!re_comp_buf.buffer) + { + if (!(re_comp_buf.buffer = (char *) malloc (200))) + return "Memory exhausted"; + re_comp_buf.allocated = 200; + if (!(re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH))) + return "Memory exhausted"; + } + return re_compile_pattern (s, strlen (s), &re_comp_buf); +} + +int +re_exec (s) + char *s; +{ + int len = strlen (s); + return 0 <= re_search (&re_comp_buf, s, len, 0, len, 0); +} + +#endif /* emacs */ + +#ifdef test + +#include <stdio.h> + +/* Indexed by a character, gives the upper case equivalent of the character */ + +static char upcase[0400] = + { 000, 001, 002, 003, 004, 005, 006, 007, + 010, 011, 012, 013, 014, 015, 016, 017, + 020, 021, 022, 023, 024, 025, 026, 027, + 030, 031, 032, 033, 034, 035, 036, 037, + 040, 041, 042, 043, 044, 045, 046, 047, + 050, 051, 052, 053, 054, 055, 056, 057, + 060, 061, 062, 063, 064, 065, 066, 067, + 070, 071, 072, 073, 074, 075, 076, 077, + 0100, 0101, 0102, 0103, 0104, 0105, 0106, 0107, + 0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117, + 0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127, + 0130, 0131, 0132, 0133, 0134, 0135, 0136, 0137, + 0140, 0101, 0102, 0103, 0104, 0105, 0106, 0107, + 0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117, + 0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127, + 0130, 0131, 0132, 0173, 0174, 0175, 0176, 0177, + 0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207, + 0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217, + 0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227, + 0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237, + 0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247, + 0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257, + 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267, + 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277, + 0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307, + 0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317, + 0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327, + 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337, + 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347, + 0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357, + 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367, + 0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377 + }; + +main (argc, argv) + int argc; + char **argv; +{ + char pat[80]; + struct re_pattern_buffer buf; + int i; + char c; + char fastmap[(1 << BYTEWIDTH)]; + + /* Allow a command argument to specify the style of syntax. */ + if (argc > 1) + obscure_syntax = atoi (argv[1]); + + buf.allocated = 40; + buf.buffer = (char *) malloc (buf.allocated); + buf.fastmap = fastmap; + buf.translate = upcase; + + while (1) + { + gets (pat); + + if (*pat) + { + re_compile_pattern (pat, strlen(pat), &buf); + + for (i = 0; i < buf.used; i++) + printchar (buf.buffer[i]); + + putchar ('\n'); + + printf ("%d allocated, %d used.\n", buf.allocated, buf.used); + + re_compile_fastmap (&buf); + printf ("Allowed by fastmap: "); + for (i = 0; i < (1 << BYTEWIDTH); i++) + if (fastmap[i]) printchar (i); + putchar ('\n'); + } + + gets (pat); /* Now read the string to match against */ + + i = re_match (&buf, pat, strlen (pat), 0, 0); + printf ("Match value %d.\n", i); + } +} + +#ifdef NOTDEF +print_buf (bufp) + struct re_pattern_buffer *bufp; +{ + int i; + + printf ("buf is :\n----------------\n"); + for (i = 0; i < bufp->used; i++) + printchar (bufp->buffer[i]); + + printf ("\n%d allocated, %d used.\n", bufp->allocated, bufp->used); + + printf ("Allowed by fastmap: "); + for (i = 0; i < (1 << BYTEWIDTH); i++) + if (bufp->fastmap[i]) + printchar (i); + printf ("\nAllowed by translate: "); + if (bufp->translate) + for (i = 0; i < (1 << BYTEWIDTH); i++) + if (bufp->translate[i]) + printchar (i); + printf ("\nfastmap is%s accurate\n", bufp->fastmap_accurate ? "" : "n't"); + printf ("can %s be null\n----------", bufp->can_be_null ? "" : "not"); +} +#endif + +printchar (c) + char c; +{ + if (c < 041 || c >= 0177) + { + putchar ('\\'); + putchar (((c >> 6) & 3) + '0'); + putchar (((c >> 3) & 7) + '0'); + putchar ((c & 7) + '0'); + } + else + putchar (c); +} + +error (string) + char *string; +{ + puts (string); + exit (1); +} + +#endif /* test */ diff --git a/gnu/usr.bin/gdb/regex.h b/gnu/usr.bin/gdb/regex.h new file mode 100644 index 0000000..d0d8a82 --- /dev/null +++ b/gnu/usr.bin/gdb/regex.h @@ -0,0 +1,185 @@ +/* Definitions for data structures callers pass the regex library. + Copyright (C) 1985, 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. + + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! */ + + +/* Define number of parens for which we record the beginnings and ends. + This affects how much space the `struct re_registers' type takes up. */ +#ifndef RE_NREGS +#define RE_NREGS 10 +#endif + +/* These bits are used in the obscure_syntax variable to choose among + alternative regexp syntaxes. */ + +/* 1 means plain parentheses serve as grouping, and backslash + parentheses are needed for literal searching. + 0 means backslash-parentheses are grouping, and plain parentheses + are for literal searching. */ +#define RE_NO_BK_PARENS 1 + +/* 1 means plain | serves as the "or"-operator, and \| is a literal. + 0 means \| serves as the "or"-operator, and | is a literal. */ +#define RE_NO_BK_VBAR 2 + +/* 0 means plain + or ? serves as an operator, and \+, \? are literals. + 1 means \+, \? are operators and plain +, ? are literals. */ +#define RE_BK_PLUS_QM 4 + +/* 1 means | binds tighter than ^ or $. + 0 means the contrary. */ +#define RE_TIGHT_VBAR 8 + +/* 1 means treat \n as an _OR operator + 0 means treat it as a normal character */ +#define RE_NEWLINE_OR 16 + +/* 0 means that a special characters (such as *, ^, and $) always have + their special meaning regardless of the surrounding context. + 1 means that special characters may act as normal characters in some + contexts. Specifically, this applies to: + ^ - only special at the beginning, or after ( or | + $ - only special at the end, or before ) or | + *, +, ? - only special when not after the beginning, (, or | */ +#define RE_CONTEXT_INDEP_OPS 32 + +/* Now define combinations of bits for the standard possibilities. */ +#define RE_SYNTAX_AWK (RE_NO_BK_PARENS | RE_NO_BK_VBAR | RE_CONTEXT_INDEP_OPS) +#define RE_SYNTAX_EGREP (RE_SYNTAX_AWK | RE_NEWLINE_OR) +#define RE_SYNTAX_GREP (RE_BK_PLUS_QM | RE_NEWLINE_OR) +#define RE_SYNTAX_EMACS 0 + +/* This data structure is used to represent a compiled pattern. */ + +struct re_pattern_buffer + { + char *buffer; /* Space holding the compiled pattern commands. */ + int allocated; /* Size of space that buffer points to */ + int used; /* Length of portion of buffer actually occupied */ + char *fastmap; /* Pointer to fastmap, if any, or zero if none. */ + /* re_search uses the fastmap, if there is one, + to skip quickly over totally implausible characters */ + char *translate; /* Translate table to apply to all characters before comparing. + Or zero for no translation. + The translation is applied to a pattern when it is compiled + and to data when it is matched. */ + char fastmap_accurate; + /* Set to zero when a new pattern is stored, + set to one when the fastmap is updated from it. */ + char can_be_null; /* Set to one by compiling fastmap + if this pattern might match the null string. + It does not necessarily match the null string + in that case, but if this is zero, it cannot. + 2 as value means can match null string + but at end of range or before a character + listed in the fastmap. */ + }; + +/* Structure to store "register" contents data in. + + Pass the address of such a structure as an argument to re_match, etc., + if you want this information back. + + start[i] and end[i] record the string matched by \( ... \) grouping i, + for i from 1 to RE_NREGS - 1. + start[0] and end[0] record the entire string matched. */ + +struct re_registers + { + int start[RE_NREGS]; + int end[RE_NREGS]; + }; + +/* These are the command codes that appear in compiled regular expressions, one per byte. + Some command codes are followed by argument bytes. + A command code can specify any interpretation whatever for its arguments. + Zero-bytes may appear in the compiled regular expression. */ + +enum regexpcode + { + unused, + exactn, /* followed by one byte giving n, and then by n literal bytes */ + begline, /* fails unless at beginning of line */ + endline, /* fails unless at end of line */ + jump, /* followed by two bytes giving relative address to jump to */ + on_failure_jump, /* followed by two bytes giving relative address of place + to resume at in case of failure. */ + finalize_jump, /* Throw away latest failure point and then jump to address. */ + maybe_finalize_jump, /* Like jump but finalize if safe to do so. + This is used to jump back to the beginning + of a repeat. If the command that follows + this jump is clearly incompatible with the + one at the beginning of the repeat, such that + we can be sure that there is no use backtracking + out of repetitions already completed, + then we finalize. */ + dummy_failure_jump, /* jump, and push a dummy failure point. + This failure point will be thrown away + if an attempt is made to use it for a failure. + A + construct makes this before the first repeat. */ + anychar, /* matches any one character */ + charset, /* matches any one char belonging to specified set. + First following byte is # bitmap bytes. + Then come bytes for a bit-map saying which chars are in. + Bits in each byte are ordered low-bit-first. + A character is in the set if its bit is 1. + A character too large to have a bit in the map + is automatically not in the set */ + charset_not, /* similar but match any character that is NOT one of those specified */ + start_memory, /* starts remembering the text that is matched + and stores it in a memory register. + followed by one byte containing the register number. + Register numbers must be in the range 0 through NREGS. */ + stop_memory, /* stops remembering the text that is matched + and stores it in a memory register. + followed by one byte containing the register number. + Register numbers must be in the range 0 through NREGS. */ + duplicate, /* match a duplicate of something remembered. + Followed by one byte containing the index of the memory register. */ + before_dot, /* Succeeds if before dot */ + at_dot, /* Succeeds if at dot */ + after_dot, /* Succeeds if after dot */ + begbuf, /* Succeeds if at beginning of buffer */ + endbuf, /* Succeeds if at end of buffer */ + wordchar, /* Matches any word-constituent character */ + notwordchar, /* Matches any char that is not a word-constituent */ + wordbeg, /* Succeeds if at word beginning */ + wordend, /* Succeeds if at word end */ + wordbound, /* Succeeds if at a word boundary */ + notwordbound, /* Succeeds if not at a word boundary */ + syntaxspec, /* Matches any character whose syntax is specified. + followed by a byte which contains a syntax code, Sword or such like */ + notsyntaxspec /* Matches any character whose syntax differs from the specified. */ + }; + +extern char *re_compile_pattern (); +/* Is this really advertised? */ +extern void re_compile_fastmap (); +extern int re_search (), re_search_2 (); +extern int re_match (), re_match_2 (); + +/* 4.2 bsd compatibility (yuck) */ +extern char *re_comp (); +extern int re_exec (); + +#ifdef SYNTAX_TABLE +extern char *re_syntax_table; +#endif diff --git a/gnu/usr.bin/gdb/remote-sl.c b/gnu/usr.bin/gdb/remote-sl.c new file mode 100644 index 0000000..4c72197 --- /dev/null +++ b/gnu/usr.bin/gdb/remote-sl.c @@ -0,0 +1,10 @@ +/* + * The binary remote protocol is still under development at LBL; + * the current version can't be released. + * Sorry, folks... + */ +int +sl_open() +{ + return -1; +} diff --git a/gnu/usr.bin/gdb/remote.c b/gnu/usr.bin/gdb/remote.c new file mode 100644 index 0000000..59658a8 --- /dev/null +++ b/gnu/usr.bin/gdb/remote.c @@ -0,0 +1,626 @@ +/*- + * Copyright (c) 1991 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Van Jacobson and Steven McCanne of Lawrence Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Header: /home/cvs/386BSD/src/usr.bin/gdb/remote.c,v 1.1.1.1 1993/06/12 14:52:22 rgrimes Exp $; + */ + +#ifndef lint +static char sccsid[] = "@(#)remote.c 6.5 (Berkeley) 5/8/91"; +#endif /* not lint */ + +#include "param.h" + +#include <stdio.h> +#include <varargs.h> + +#include <signal.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/file.h> + +#include "defs.h" +#include "frame.h" +#include "inferior.h" +#include "wait.h" + +#include "kgdb_proto.h" + +static FILE *kiodebug; +static int icache = 1; +extern int kernel_debugging; + +static int remote_cache_valid; +static int remote_instub; + +static void remote_signal(); +static void remote_debug(); +static void print_msg(); + +static int remote_mtu; +static int (*send_msg)(); +static int (*recv_msg)(); +static void (*closelink)(); + +static u_char *inbuffer; +static u_char *outbuffer; + +/* + * Statistics. + */ +static int remote_ierrs; +static int remote_oerrs; +static int remote_seqerrs; +static int remote_spurious; + +#define PUTCMD(cmd) m_xchg(cmd, (u_char *)0, 0, (u_char *)0, (int *)0) + +/* + * Send an outbound message to the remote machine and read the reply. + * Either or both message buffers may be NULL. + */ +static int +m_xchg(type, out, outlen, in, inlen) + int type; + u_char *out; + int outlen; + u_char *in; + int *inlen; +{ + register int err, (*send)() = send_msg, (*recv)() = recv_msg; + int ack; + static int seqbit = 0; + + if (!remote_instub) { + remote_instub = 1; + PUTCMD(KGDB_EXEC); + } + + seqbit ^= KGDB_SEQ; + while (1) { + err = (*send)(type | seqbit, out, outlen); + if (err) { + ++remote_oerrs; + if (kiodebug) + remote_debug("send error %d\n", err); + } + if (kiodebug) + print_msg(type | seqbit, out, outlen, 'O'); + + recv: + err = (*recv)(&ack, in, inlen); + if (err) { + ++remote_ierrs; + if (kiodebug) + remote_debug("recv error %d\n", err); + remote_cache_valid = 0; + } else if (kiodebug) + print_msg(ack, in, inlen ? *inlen : 0, 'I'); + + if (err) + continue; + + if ((ack & KGDB_ACK) == 0 || KGDB_CMD(ack) != KGDB_CMD(type)) { + ++remote_spurious; + continue; + } + if ((ack & KGDB_SEQ) ^ seqbit) { + ++remote_seqerrs; + goto recv; + } + return ack; + } +} + +/* + * Wait for the specified message type. Discard anything else. + * (this is used by 'remote-signal' to help us resync with other side.) + */ +static void +m_recv(type, in, inlen) + int type; + u_char *in; + int *inlen; +{ + int reply, err; + + while (1) { + err = (*recv_msg)(&reply, in, inlen); + if (err) { + ++remote_ierrs; + if (kiodebug) + remote_debug("recv error %d\n", err); + } else if (kiodebug) + print_msg(reply, in, inlen ? *inlen : 0, 'I'); + + if (KGDB_CMD(reply) == type) + return; + ++remote_spurious; + } +} + +/* + * Send a message. Do not wait for *any* response from the other side. + * Some other thread of control will pick up the ack that will be generated. + */ +static void +m_send(type, buf, len) + int type; + u_char *buf; + int len; +{ + int err; + + if (!remote_instub) { + remote_instub = 1; + PUTCMD(KGDB_EXEC); + } + + err = (*send_msg)(type, buf, len); + if (err) { + ++remote_ierrs; + if (kiodebug) + remote_debug("[send error %d] ", err); + } + if (kiodebug) + print_msg(type, buf, len, 'O'); +} + +/* + * 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; +{ + int bufsize; + + remote_debugging = 0; + if (sl_open(name, &send_msg, &recv_msg, &closelink, &remote_mtu, + &bufsize)) + return; + if (from_tty) + printf("Remote debugging using %s\n", name); + remote_debugging = 1; + + remote_cache_valid = 0; + + inbuffer = (u_char *)malloc(bufsize); + outbuffer = (u_char *)malloc(bufsize); + + remote_signal(); + + remote_ierrs = 0; + remote_oerrs = 0; + remote_spurious = 0; +} + +/* + * Close the open connection to the remote debugger. Use this when you want + * to detach and do something else with your gdb. + */ +void +remote_close(from_tty) + int from_tty; +{ + if (!remote_debugging) + error("remote debugging not enabled"); + + remote_debugging = 0; + /* + * Take remote machine out of debug mode. + */ + (void)PUTCMD(KGDB_KILL); + (*closelink)(); + if (from_tty) + printf("Ending remote debugging\n"); + + free((char *)inbuffer); + free((char *)outbuffer); +} + +/* + * Tell the remote machine to resume. + */ +int +remote_resume(step, signal) + int step, signal; +{ + if (!step) { + (void)PUTCMD(KGDB_CONT); + remote_instub = 0; + } else { +#ifdef NO_SINGLE_STEP + single_step(0); +#else + (void)PUTCMD(KGDB_STEP); +#endif + } +} + +/* + * Wait until the remote machine stops, then return, storing status in STATUS + * just as `wait' would. + */ +int +remote_wait(status) + WAITTYPE *status; +{ + int len; + + WSETEXIT((*status), 0); + /* + * When the machine stops, it will send us a KGDB_SIGNAL message, + * so we wait for one of these. + */ + m_recv(KGDB_SIGNAL, inbuffer, &len); + WSETSTOP((*status), inbuffer[0]); +} + +/* + * Register context as of last remote_fetch_registers(). + */ +static char reg_cache[REGISTER_BYTES]; + +/* + * Read the remote registers into the block REGS. + */ +void +remote_fetch_registers(regs) + char *regs; +{ + int regno, len, rlen, ack; + u_char *cp, *ep; + + regno = -1; + do { + outbuffer[0] = regno + 1; + ack = m_xchg(remote_cache_valid ? + KGDB_REG_R|KGDB_DELTA : KGDB_REG_R, + outbuffer, 1, inbuffer, &len); + cp = inbuffer; + ep = cp + len; + while (cp < ep) { + regno = *cp++; + rlen = REGISTER_RAW_SIZE(regno); + bcopy((char *)cp, + ®_cache[REGISTER_BYTE(regno)], rlen); + cp += rlen; + } + } while (ack & KGDB_MORE); + + remote_cache_valid = 1; + bcopy(reg_cache, regs, REGISTER_BYTES); +} + +/* + * Store the remote registers from the contents of the block REGS. + */ +void +remote_store_registers(regs) + char *regs; +{ + u_char *cp, *ep; + int regno, off, rlen; + + cp = outbuffer; + ep = cp + remote_mtu; + + for (regno = 0; regno < NUM_REGS; ++regno) { + off = REGISTER_BYTE(regno); + rlen = REGISTER_RAW_SIZE(regno); + if (!remote_cache_valid || + bcmp(®s[off], ®_cache[off], rlen) != 0) { + if (cp + rlen + 1 >= ep) { + (void)m_xchg(KGDB_REG_W, + outbuffer, cp - outbuffer, + (u_char *)0, (int *)0); + cp = outbuffer; + } + *cp++ = regno; + bcopy(®s[off], cp, rlen); + cp += rlen; + } + } + if (cp != outbuffer) + (void)m_xchg(KGDB_REG_W, outbuffer, cp - outbuffer, + (u_char *)0, (int *)0); + bcopy(regs, reg_cache, REGISTER_BYTES); +} + +/* + * Store a chunk of memory into the remote host. + * 'remote_addr' is the address in the remote memory space. + * 'cp' is the address of the buffer in our space, and 'len' is + * the number of bytes. Returns an errno status. + */ +int +remote_write_inferior_memory(remote_addr, cp, len) + CORE_ADDR remote_addr; + u_char *cp; + int len; +{ + int cnt; + + while (len > 0) { + cnt = min(len, remote_mtu - 4); + bcopy((char *)&remote_addr, outbuffer, 4); + bcopy(cp, outbuffer + 4, cnt); + (void)m_xchg(KGDB_MEM_W, outbuffer, cnt + 4, inbuffer, &len); + + if (inbuffer[0]) + return inbuffer[0]; + + remote_addr += cnt; + cp += cnt; + len -= cnt; + } + return 0; +} + +/* + * Read memory data directly from the remote machine. + * 'remote_addr' is the address in the remote memory space. + * 'cp' is the address of the buffer in our space, and 'len' is + * the number of bytes. Returns an errno status. + */ +static int +remote_read_memory(remote_addr, cp, len) + CORE_ADDR remote_addr; + u_char *cp; + int len; +{ + int cnt, inlen; + + while (len > 0) { + cnt = min(len, remote_mtu - 1); + outbuffer[0] = cnt; + bcopy((char *)&remote_addr, (char *)&outbuffer[1], 4); + + (void)m_xchg(KGDB_MEM_R, outbuffer, 5, inbuffer, &inlen); + + if (inbuffer[0] != 0) + return inbuffer[0]; + + if (cnt != inlen - 1) + /* XXX */ + error("remote_read_memory() request botched"); + + bcopy((char *)&inbuffer[1], (char *)cp, cnt); + + remote_addr += cnt; + cp += cnt; + len -= cnt; + } + return 0; +} + +int +remote_read_inferior_memory(remote_addr, cp, len) + CORE_ADDR remote_addr; + char *cp; + int len; +{ + int stat = 0; + + if (icache) { + extern CORE_ADDR text_start, text_end; + CORE_ADDR xferend = remote_addr + len; + + if (remote_addr < text_end && text_start < xferend) { + /* + * at least part of this xfer is in the text + * space -- xfer the overlap from the exec file. + */ + if (remote_addr >= text_start && xferend < text_end) + return (xfer_core_file(remote_addr, cp, len)); + if (remote_addr >= text_start) { + int i = text_end - remote_addr; + + if (stat = xfer_core_file(remote_addr, cp, i)) + return (stat); + remote_addr += i; + cp += i; + len -= i; + } else if (xferend <= text_end) { + int i = xferend - text_start; + + len = text_start - remote_addr; + if (stat = xfer_core_file(text_start, + cp + len, i)) + return (stat); + } + } + } + return remote_read_memory(remote_addr, cp, len); +} + +/* + * Signal the remote machine. The remote end might be idle or it might + * already be in debug mode -- we need to handle both case. Thus, we use + * the framing character as the wakeup byte, and send a SIGNAL packet. + * If the remote host is idle, the framing character will wake it up. + * If it is in the kgdb stub, then we will get a SIGNAL reply. + */ +static void +remote_signal() +{ + if (!remote_debugging) + printf("Remote debugging not enabled.\n"); + else { + remote_instub = 0; + m_send(KGDB_SIGNAL, (u_char *)0, 0); + } +} + +static void +remote_signal_command() +{ + extern int stop_after_attach; + + if (!remote_debugging) + error("Not debugging remote."); + remote_cache_valid = 0; + remote_signal(); + restart_remote(); +} + +/* + * Print a message for debugging. + */ +static void +print_msg(type, buf, len, dir) + int type; + u_char *buf; + int len; + int dir; +{ + int i; + char *s; + + switch (KGDB_CMD(type)) { + case KGDB_MEM_R: s = "memr"; break; + case KGDB_MEM_W: s = "memw"; break; + case KGDB_REG_R: s = "regr"; break; + case KGDB_REG_W: s = "regw"; break; + case KGDB_CONT: s = "cont"; break; + case KGDB_STEP: s = "step"; break; + case KGDB_KILL: s = "kill"; break; + case KGDB_SIGNAL: s = "sig "; break; + case KGDB_EXEC: s = "exec"; break; + default: s = "unk "; break; + } + remote_debug("%c %c%c%c%c %s (%02x): ", dir, + (type & KGDB_ACK) ? 'A' : '.', + (type & KGDB_DELTA) ? 'D' : '.', + (type & KGDB_MORE) ? 'M' : '.', + (type & KGDB_SEQ) ? '-' : '+', + s, type); + if (buf) + for (i = 0; i < len; ++i) + remote_debug("%02x", buf[i]); + remote_debug("\n"); +} + +static void +set_remote_text_refs_command(arg, from_tty) + char *arg; + int from_tty; +{ + icache = !parse_binary_operation("set remote-text-refs", arg); +} + +static void +remote_debug_command(arg, from_tty) + char *arg; + int from_tty; +{ + char *name; + + if (kiodebug != 0 && kiodebug != stderr) + (void)fclose(kiodebug); + + if (arg == 0) { + kiodebug = 0; + printf("Remote debugging off.\n"); + return; + } + if (arg[0] == '-') { + kiodebug = stderr; + name = "stderr"; + } else { + kiodebug = fopen(arg, "w"); + if (kiodebug == 0) { + printf("Cannot open '%s'.\n", arg); + return; + } + name = arg; + } + printf("Remote debugging output routed to %s.\n", name); +} + +/* ARGSUSED */ +static void +remote_info(arg, from_tty) + char *arg; + int from_tty; +{ + printf("Using %s for text references.\n", + icache? "local executable" : "remote"); + printf("Protocol debugging is %s.\n", kiodebug? "on" : "off"); + printf("%d spurious input messages.\n", remote_spurious); + printf("%d input errors; %d output errors; %d sequence errors.\n", + remote_ierrs, remote_oerrs, remote_seqerrs); +} + +/* VARARGS */ +static void +remote_debug(va_alist) + va_dcl +{ + register char *cp; + va_list ap; + + va_start(ap); + cp = va_arg(ap, char *); + (void)vfprintf(kiodebug, cp, ap); + va_end(ap); + fflush(kiodebug); +} + +extern struct cmd_list_element *setlist; + +void +_initialize_remote() +{ + add_com("remote-signal", class_run, remote_signal_command, + "If remote debugging, send interrupt signal to remote."); + add_cmd("remote-text-refs", class_support, + set_remote_text_refs_command, +"Enable/disable use of local executable for text segment references.\n\ +If on, all memory read/writes go to remote.\n\ +If off, text segment reads use the local executable.", + &setlist); + + add_com("remote-debug", class_run, remote_debug_command, +"With a file name argument, enables output of remote protocol debugging\n\ +messages to said file. If file is `-', stderr is used.\n\ +With no argument, remote debugging is disabled."); + + add_info("remote", remote_info, + "Show current settings of remote debugging options."); +} + diff --git a/gnu/usr.bin/gdb/source.c b/gnu/usr.bin/gdb/source.c new file mode 100644 index 0000000..d9ae20f --- /dev/null +++ b/gnu/usr.bin/gdb/source.c @@ -0,0 +1,1166 @@ +/*- + * This code is derived from software copyrighted by the Free Software + * Foundation. + * + * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. + * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory. + */ + +#ifndef lint +static char sccsid[] = "@(#)source.c 6.3 (Berkeley) 5/8/91"; +#endif /* not lint */ + +/* List lines of source files for GDB, the GNU debugger. + Copyright (C) 1986, 1987, 1988, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <stdio.h> +#include "defs.h" +#include "symtab.h" +#include "param.h" + +#ifdef USG +#include <sys/types.h> +#include <fcntl.h> +#endif + +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/file.h> + +/* Path of directories to search for source files. + Same format as the PATH environment variable's value. */ + +static 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; + + +struct symtab *psymtab_to_symtab (); + +/* Set the source file default for the "list" command, specifying a + symtab. Sigh. Behaivior 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 psytab_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, *cs_pst; + + 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)) + { + sals = decode_line_spec ("main", 1); + sal = sals.sals[0]; + free (sals.sals); + current_source_symtab = sal.symtab; + current_source_line = max (sal.line - 9, 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); +} + +void +init_source_path () +{ + register struct symtab *s; + + source_path = savestring (current_directory, strlen (current_directory)); + + /* Forget what we learned about line positions in source files; + must check again now since files may be found in + a different directory now. */ + for (s = symtab_list; s; s = s->next) + if (s->line_charpos != 0) + { + free (s->line_charpos); + s->line_charpos = 0; + } +} + +void +directory_command (dirname, from_tty) + char *dirname; + int from_tty; +{ + char *old = source_path; + + dont_repeat (); + + if (dirname == 0) + { + if (query ("Reinitialize source path to %s? ", current_directory)) + { + init_source_path (); + free (old); + } + } + else + { + dirname = tilde_expand (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 != '/') + name = concat (current_directory, "/", name); + else + name = savestring (name, p - name); + make_cleanup (free, name); + + 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 = source_path; + while (1) + { + if (!strncmp (p, name, len) + && (p[len] == '\0' || p[len] == ':')) + { + if (from_tty) + printf ("\"%s\" is already in the source path.\n", name); + break; + } + p = index (p, ':'); + if (p != 0) + ++p; + else + break; + } + if (p == 0) + { + source_path = concat (old, ":", name); + free (old); + old = source_path; + } + } + } while (*dirname != '\0'); + if (from_tty) + directories_info (); + } +} + +/* 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 "/" + + 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; + + 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; + } + + filename = (char *) alloca (strlen (path) + strlen (string) + 2); + fd = -1; + for (p = path; p; p = p1 ? p1 + 1 : 0) + { + p1 = (char *) index (p, ':'); + if (p1) + len = p1 - p; + else + len = strlen (p); + + strncpy (filename, p, len); + filename[len] = 0; + strcat (filename, "/"); + 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 + { + *filename_opened = concat (current_directory, "/", filename); + } + + return fd; +} + +/* 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)); + extern int exec_mtime; + + if (fstat (desc, &st) < 0) + perror_with_name (s->filename); + if (get_exec_file (0) != 0 && exec_mtime < st.st_mtime) + printf ("Source file is more recent than executable.\n"); + + data = (char *) alloca (st.st_size); + 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, line, fullname) + struct symtab *s; + int line; + char **fullname; +{ + register int desc, linenums_changed = 0; + + desc = openp (source_path, 0, s->filename, O_RDONLY, 0, &s->fullname); + 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, line, 0); + 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; + + desc = openp (source_path, 0, s->filename, O_RDONLY, 0, &s->fullname); + if (desc < 0) + { + extern int errno; + if (noerror && line + 1 == stopline) + { + /* can't find the file - tell user where we are anyway */ + current_source_symtab = s; + current_source_line = line; + first_line_listed = line; + last_line_listed = line; + printf_filtered ("%d\t(%s)\n", current_source_line++, s->filename); + } + else + { + if (! noerror) + perror_with_name (s->filename); + print_sys_errmsg (s->filename, 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); + } + + current_source_symtab = s; + current_source_line = line; + first_line_listed = line; + + 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 +file_command(arg, from_tty) + char *arg; + int from_tty; +{ + struct symtabs_and_lines sals; + struct symtab_and_line sal; + struct symbol *sym; + char *arg1; + 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 (arg == 0 || arg[0] == 0) { + if (current_source_symtab == 0) + select_source_symtab(0); + else + printf("%s\n", current_source_symtab->filename); + return; + } + arg1 = arg; + 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); + + /* if line was specified by address, + 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 (sal.symtab == 0) + { + if (! linenum_beg) + error ("No line number known for %s.", arg); + else + error ("No default source file yet. Do \"help list\"."); + } + else + { + current_source_symtab = sal.symtab; + current_source_line = sal.line; + first_line_listed = sal.line; + } +} + +#define PUSH_STACK_SIZE 32 +static struct { + struct symtab *symtab; + int line; +} push_stack[PUSH_STACK_SIZE]; + +static unsigned int push_stack_ptr; + +static void +push_to_file_command (arg, from_tty) + char *arg; + int from_tty; +{ + struct symtab *cursym = current_source_symtab; + int curline = current_source_line; + register unsigned int i; + + file_command(arg, from_tty); + + /* if we got back, command was successful */ + i = push_stack_ptr; + push_stack[i].symtab = cursym; + push_stack[i].line = curline; + push_stack_ptr = (i + 1) & (PUSH_STACK_SIZE - 1); +} + +static void +pop_file_command (arg, from_tty) + char *arg; + int from_tty; +{ + register unsigned int i = push_stack_ptr; + + /* if there's something on the stack, pop it & clear the slot. */ + i = (i + (PUSH_STACK_SIZE - 1)) & (PUSH_STACK_SIZE - 1); + if (push_stack[i].symtab) { + current_source_symtab = push_stack[i].symtab; + first_line_listed = current_source_line = push_stack[i].line; + push_stack[i].symtab = NULL; + push_stack_ptr = i; + } +} + + +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 + 10, 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 - 10, 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 - 9, 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 - 5, 1), sal.line + 5, 0); + else + print_source_lines (sal.symtab, sal.line, + dummy_end ? sal.line + 10 : 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; + int 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; +{ + 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 = openp (source_path, 0, current_source_symtab->filename, + O_RDONLY, 0, ¤t_source_symtab->fullname); + 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 - 5, 1); + return; + } + line++; + } + + printf ("Expression not found\n"); + fclose (stream); +} + +static void +reverse_search_command (regex, from_tty) + char *regex; +{ + 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 = openp (source_path, 0, current_source_symtab->filename, + O_RDONLY, 0, ¤t_source_symtab->fullname); + 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 - 5, 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 end of search path for source files.\n\ +With no argument, reset the search path to just the working directory\n\ +and forget cached info on line positions in source files."); + + add_info ("directories", directories_info, + "Current search path for finding source files."); + + 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 ("file", class_files, file_command, + "Select current file, function and line for display or list.\n\ +Specification can have the form:\n\ + LINENUM, to select that line in current file,\n\ + FILE:LINENUM, to select that line in that file,\n\ + FUNCTION, to select beginning of that function,\n\ + FILE:FUNCTION, to distinguish among like-named static functions.\n\ + *ADDRESS, to select the line containing that address."); + add_com ("push-to-file", class_files, push_to_file_command, + "Like \"file\" command but remembers current file & line on a stack.\n\ +Can later return to current file with \"pop-file\" command.\n\ +Up to 32 file positions can be pushed on stack."); + add_com ("pop-file", class_files, pop_file_command, + "Pops back to file position saved by most recent \"push-to-file\".\n\ +If everything has been popped from stack, command does nothing."); +} + diff --git a/gnu/usr.bin/gdb/stab.def b/gnu/usr.bin/gdb/stab.def new file mode 100644 index 0000000..b81cda4 --- /dev/null +++ b/gnu/usr.bin/gdb/stab.def @@ -0,0 +1,115 @@ +/* Table of DBX symbol codes for the GNU system. + Copyright (C) 1988 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. */ + +/* Global variable. Only the name is significant. + To find the address, look in the corresponding external symbol. */ +__define_stab (N_GSYM, 0x20, "GSYM") + +/* Function name for BSD Fortran. Only the name is significant. + To find the address, look in the corresponding external symbol. */ +__define_stab (N_FNAME, 0x22, "FNAME") + +/* Function name or text-segment variable for C. Value is its address. + Desc is supposedly starting line number, but GCC doesn't set it + and DBX seems not to miss it. */ +__define_stab (N_FUN, 0x24, "FUN") + +/* Data-segment variable with internal linkage. Value is its address. */ +__define_stab (N_STSYM, 0x26, "STSYM") + +/* BSS-segment variable with internal linkage. Value is its address. */ +__define_stab (N_LCSYM, 0x28, "LCSYM") + +/* Name of main routine. Only the name is significant. + This is not used in C. */ +__define_stab (N_MAIN, 0x2a, "MAIN") + +/* Register variable. Value is number of register. */ +__define_stab (N_RSYM, 0x40, "RSYM") + +/* Structure or union element. Value is offset in the structure. */ +__define_stab (N_SSYM, 0x60, "SSYM") + +/* Parameter variable. Value is offset from argument pointer. + (On most machines the argument pointer is the same as the frame pointer. */ +__define_stab (N_PSYM, 0xa0, "PSYM") + +/* Automatic variable in the stack. Value is offset from frame pointer. + Also used for type descriptions. */ +__define_stab (N_LSYM, 0x80, "LSYM") + +/* Alternate entry point. Value is its address. */ +__define_stab (N_ENTRY, 0xa4, "ENTRY") + +/* Name of main source file. + Value is starting text address of the compilation. */ +__define_stab (N_SO, 0x64, "SO") + +/* Name of sub-source file. + Value is starting text address of the compilation. */ +__define_stab (N_SOL, 0x84, "SOL") + +/* Line number in text segment. Desc is the line number; + value is corresponding address. */ +__define_stab (N_SLINE, 0x44, "SLINE") +/* Similar, for data segment. */ +__define_stab (N_DSLINE, 0x46, "DSLINE") +/* Similar, for bss segment. */ +__define_stab (N_BSLINE, 0x48, "BSLINE") + +/* Beginning of an include file. Only Sun uses this. + In an object file, only the name is significant. + The Sun linker puts data into some of the other fields. */ +__define_stab (N_BINCL, 0x82, "BINCL") +/* End of an include file. No name. + These two act as brackets around the file's output. + In an object file, there is no significant data in this entry. + The Sun linker puts data into some of the fields. */ +__define_stab (N_EINCL, 0xa2, "EINCL") +/* Place holder for deleted include file. + This appears only in output from the Sun linker. */ +__define_stab (N_EXCL, 0xc2, "EXCL") + +/* Beginning of lexical block. + The desc is the nesting level in lexical blocks. + The value is the address of the start of the text for the block. + The variables declared inside the block *precede* the N_LBRAC symbol. */ +__define_stab (N_LBRAC, 0xc0, "LBRAC") +/* End of a lexical block. Desc matches the N_LBRAC's desc. + The value is the address of the end of the text for the block. */ +__define_stab (N_RBRAC, 0xe0, "RBRAC") + +/* Begin named common block. Only the name is significant. */ +__define_stab (N_BCOMM, 0xe2, "BCOMM") +/* Begin named common block. Only the name is significant + (and it should match the N_BCOMM). */ +__define_stab (N_ECOMM, 0xe4, "ECOMM") +/* End common (local name): value is address. + I'm not sure how this is used. */ +__define_stab (N_ECOML, 0xe8, "ECOML") +/* Second symbol entry containing a length-value for the preceding entry. + The value is the length. */ +__define_stab (N_LENG, 0xfe, "LENG") + +/* Global symbol in Pascal. + Supposedly the value is its line number; I'm skeptical. */ +__define_stab (N_PC, 0x30, "PC") + +/* Modula-2 compilation unit. Can someone say what info it contains? */ +__define_stab (N_M2C, 0x42, "M2C") +/* Modula-2 scope information. Can someone say what info it contains? */ +__define_stab (N_SCOPE, 0xc4, "SCOPE") diff --git a/gnu/usr.bin/gdb/stack.c b/gnu/usr.bin/gdb/stack.c new file mode 100644 index 0000000..91218aa --- /dev/null +++ b/gnu/usr.bin/gdb/stack.c @@ -0,0 +1,960 @@ +/*- + * This code is derived from software copyrighted by the Free Software + * Foundation. + * + * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. + * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory. + */ + +#ifndef lint +static char sccsid[] = "@(#)stack.c 6.3 (Berkeley) 5/8/91"; +#endif /* not lint */ + +/* 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. */ + +/* modified by rjc Thu Nov 1 16:46:57 1990, fixed return_command so that + it can return values, it still has problems when running on pmax, + cannot write register 65 */ + +#include <stdio.h> + +#include "defs.h" +#include "param.h" +#include "symtab.h" +#include "frame.h" +#include "value.h" + + +/* 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; + +static void select_calling_frame (); + +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); +} + +/* Flag which will indicate when the frame has been changed + by and "up" or "down" command. */ +static int frame_changed; + +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; + 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); + printf_filtered ("0x%x in ", fi->pc); + + fputs_demangled(fname, stdout, -1); + fputs_filtered(" (...)\n", stdout); + + return; + } + + 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 (frame_changed || source >= 0 || !sal.symtab) + { + if (level >= 0) + printf_filtered ("#%-2d ", level); + else if (frame_changed) + printf ("#%-2d ", 0); + if (fi->pc != sal.pc || !sal.symtab) + printf_filtered ("0x%x in ", fi->pc); + fputs_demangled(funname ? funname : "??", stdout, -1); + printf_filtered(" ("); + if (args) + { + if (func) + numargs = -1; + else + FRAME_NUM_ARGS (numargs, fi); + + print_frame_args (func, fi, numargs, stdout); + } + printf_filtered (")"); + if (sal.symtab) + printf_filtered (" (%s line %d)", sal.symtab->filename, sal.line); + printf_filtered ("\n"); + } + + if ((frame_changed || 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 (mid_statement) + printf_filtered ("0x%x\t", fi->pc); + print_source_lines (sal.symtab, sal.line, sal.line + 1, 1); + } + current_source_line = max (sal.line - 5, 1); + } + frame_changed = 0; + 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; + struct frame_info *fci; + + 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 Frame_unknown + instead of guessing (this happens on the VAX, 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 (!(have_inferior_p () || have_core_file_p ())) + error ("No inferior or core file."); + + frame = parse_frame_specification (addr_exp); + if (!frame) + error ("Invalid frame specified."); + + fi = get_frame_info (frame); + get_frame_saved_regs (fi, &fsr); + 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 ("Stack level %d, frame at 0x%x:\n pc = 0x%x", + selected_frame_level, FRAME_FP(frame), fi->pc); + else + printf ("Stack frame at 0x%x:\n pc = 0x%x", + FRAME_FP(frame), fi->pc); + + if (funname) + printf (" in %s", funname); + if (sal.symtab) + printf (" (%s line %d)", sal.symtab->filename, sal.line); + printf ("; saved pc 0x%x\n", FRAME_SAVED_PC (frame)); + if (calling_frame) + printf (" called by frame at 0x%x", FRAME_FP (calling_frame)); + if (fi->next_frame && calling_frame) + printf (","); + if (fi->next_frame) + printf (" caller of frame at 0x%x", fi->next_frame); + if (fi->next_frame || calling_frame) + printf ("\n"); + + { + /* Address of the argument list for this frame, or Frame_unknown. */ + CORE_ADDR arg_list = FRAME_ARGS_ADDRESS_CORRECT (fi); + /* Number of args for this frame, or -1 if unknown. */ + int numargs; + + if (arg_list != Frame_unknown) + { + printf (" Arglist at 0x%x,", arg_list); + + FRAME_NUM_ARGS (numargs, fi); + if (numargs < 0) + printf (" args: "); + else if (numargs == 0) + printf (" no args."); + else if (numargs == 1) + printf (" 1 arg: "); + else + printf (" %d args: ", numargs); + print_frame_args (func, fi, numargs, stdout); + printf ("\n"); + } + } + + /* The sp is special; what's returned isn't the save address, but + actually the value of the previous frame's sp. */ + printf (" 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 % 4 != 0) + printf (", "); + else + { + if (count == 0) + printf (" Saved registers:"); + printf ("\n "); + } + printf ("%s at 0x%x", reg_names[i], fsr.regs[i]); + count++; + } + if (count) + printf ("\n"); +} + +#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) + char *count_exp; +{ + 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--) + current = get_prev_frame (current); + + /* Will stop when CURRENT reaches the top of the stack. TRAILING + will be COUNT below it. */ + while (current) + { + trailing = get_prev_frame (trailing); + current = get_prev_frame (current); + trailing_level++; + } + + count = -1; + } + } + else + count = -1; + + 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) + 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; + fputs_filtered (SYMBOL_NAME (sym), stream); + fputs_filtered (" = ", stream); + print_variable_value (sym, frame, stream); + fprintf_filtered (stream, "\n"); + 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; +} + +static void +locals_info () +{ + if (!have_inferior_p () && !have_core_file_p ()) + error ("No inferior or core file."); + + print_frame_local_vars (selected_frame, 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; + 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_REF_ARG + || SYMBOL_CLASS (sym) == LOC_REGPARM) + { + values_printed = 1; + fputs_filtered (SYMBOL_NAME (sym), stream); + fputs_filtered (" = ", stream); + print_variable_value (sym, 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 (!have_inferior_p () && !have_core_file_p ()) + error ("No inferior or core file."); + 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 (!have_inferior_p () && !have_core_file_p ()) + 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 (!have_inferior_p () && ! have_core_file_p ()) + error ("No inferior or core file."); + + 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; + + frame_changed = level; + 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_command (count_exp) + char *count_exp; +{ + register FRAME frame; + int count = 1, count1; + if (count_exp) + count = parse_and_eval_address (count_exp); + count1 = count; + + if (!have_inferior_p () && !have_core_file_p ()) + error ("No inferior or core file."); + + 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); + + print_stack_frame (selected_frame, selected_frame_level, 1); + frame_changed++; +} + +/* Select the frame down one or COUNT stack levels + from the previously selected frame, and print it briefly. */ + +static void +down_command (count_exp) + char *count_exp; +{ + 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); + + print_stack_frame (selected_frame, selected_frame_level, 1); + frame_changed--; +} + +static void +return_command (retval_exp, from_tty) + char *retval_exp; + int from_tty; +{ + value return_value; + struct symbol *thisfun = get_frame_function (selected_frame); + FRAME_ADDR selected_frame_addr = FRAME_FP (selected_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. Note that this will not work if the selected frame + shares it's fp with another frame. */ + + while (selected_frame_addr != FRAME_FP (get_current_frame())) + POP_FRAME; + + /* get the return value while still in this frame */ + if (retval_exp) + return_value = parse_and_eval (retval_exp); + + /* Then pop that frame. */ + POP_FRAME; + + /* Store the return value if there was one */ + + if (retval_exp) + set_return_value (return_value); + + /* If interactive, print the frame that is now current. */ + + if (from_tty) + frame_command ("0", 1); +} + +extern struct cmd_list_element *setlist; + +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 ("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 ("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."); + +#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/gnu/usr.bin/gdb/symmisc.c b/gnu/usr.bin/gdb/symmisc.c new file mode 100644 index 0000000..bb4eb50 --- /dev/null +++ b/gnu/usr.bin/gdb/symmisc.c @@ -0,0 +1,584 @@ +/* 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 "symtab.h" + +#include <stdio.h> +#include <obstack.h> + +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 (); + clear_breakpoints (); + 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; +} + +/* 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 type *type; + 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); + + if (s->line_charpos) + free (s->line_charpos); + free (s->filename); + free (s); +} + +/* Convert a raw symbol-segment to a struct symtab, + and relocate its internal pointers so that it is valid. */ + +/* This is how to relocate one pointer, given a name for it. + Works independent of the type of object pointed to. */ +#define RELOCATE(slot) (slot ? (* (char **) &slot += relocation) : 0) + +/* This is the inverse of RELOCATE. We use it when storing + a core address into a slot that has yet to be relocated. */ +#define UNRELOCATE(slot) (slot ? (* (char **) &slot -= relocation) : 0) + +/* During the process of relocation, this holds the amount to relocate by + (the address of the file's symtab data, in core in the debugger). */ +static int relocation; + +#define CORE_RELOCATE(slot) \ + ((slot) += (((slot) < data_start) ? text_relocation \ + : ((slot) < bss_start) ? data_relocation : bss_relocation)) + +#define TEXT_RELOCATE(slot) ((slot) += text_relocation) + +/* Relocation amounts for addresses in the program's core image. */ +static int text_relocation, data_relocation, bss_relocation; + +/* Boundaries that divide program core addresses into text, data and bss; + used to determine which relocation amount to use. */ +static int data_start, bss_start; + +static void relocate_typevector (); +static void relocate_blockvector (); +static void relocate_type (); +static void relocate_block (); +static void relocate_symbol (); +static void relocate_source (); + +/* Relocate a file's symseg so that all the pointers are valid C pointers. + Value is a `struct symtab'; but it is not suitable for direct + insertion into the `symtab_list' because it describes several files. */ + +static struct symtab * +relocate_symtab (root) + struct symbol_root *root; +{ + struct symtab *sp = (struct symtab *) xmalloc (sizeof (struct symtab)); + bzero (sp, sizeof (struct symtab)); + + relocation = (int) root; + text_relocation = root->textrel; + data_relocation = root->datarel; + bss_relocation = root->bssrel; + data_start = root->databeg; + bss_start = root->bssbeg; + + sp->filename = root->filename; + sp->ldsymoff = root->ldsymoff; + sp->language = root->language; + sp->compilation = root->compilation; + sp->version = root->version; + sp->blockvector = root->blockvector; + sp->typevector = root->typevector; + + RELOCATE (TYPEVECTOR (sp)); + RELOCATE (BLOCKVECTOR (sp)); + RELOCATE (sp->version); + RELOCATE (sp->compilation); + RELOCATE (sp->filename); + + relocate_typevector (TYPEVECTOR (sp)); + relocate_blockvector (BLOCKVECTOR (sp)); + + return sp; +} + +static void +relocate_blockvector (blp) + register struct blockvector *blp; +{ + register int nblocks = BLOCKVECTOR_NBLOCKS (blp); + register int i; + for (i = 0; i < nblocks; i++) + RELOCATE (BLOCKVECTOR_BLOCK (blp, i)); + for (i = 0; i < nblocks; i++) + relocate_block (BLOCKVECTOR_BLOCK (blp, i)); +} + +static void +relocate_block (bp) + register struct block *bp; +{ + register int nsyms = BLOCK_NSYMS (bp); + register int i; + + TEXT_RELOCATE (BLOCK_START (bp)); + TEXT_RELOCATE (BLOCK_END (bp)); + + /* These two should not be recursively processed. + The superblock need not be because all blocks are + processed from relocate_blockvector. + The function need not be because it will be processed + under the block which is its scope. */ + RELOCATE (BLOCK_SUPERBLOCK (bp)); + RELOCATE (BLOCK_FUNCTION (bp)); + + for (i = 0; i < nsyms; i++) + RELOCATE (BLOCK_SYM (bp, i)); + + for (i = 0; i < nsyms; i++) + relocate_symbol (BLOCK_SYM (bp, i)); +} + +static void +relocate_symbol (sp) + register struct symbol *sp; +{ + RELOCATE (SYMBOL_NAME (sp)); + if (SYMBOL_CLASS (sp) == LOC_BLOCK) + { + RELOCATE (SYMBOL_BLOCK_VALUE (sp)); + /* We can assume the block that belongs to this symbol + is not relocated yet, since it comes after + the block that contains this symbol. */ + BLOCK_FUNCTION (SYMBOL_BLOCK_VALUE (sp)) = sp; + UNRELOCATE (BLOCK_FUNCTION (SYMBOL_BLOCK_VALUE (sp))); + } + else if (SYMBOL_CLASS (sp) == LOC_STATIC) + CORE_RELOCATE (SYMBOL_VALUE (sp)); + else if (SYMBOL_CLASS (sp) == LOC_LABEL) + TEXT_RELOCATE (SYMBOL_VALUE (sp)); + RELOCATE (SYMBOL_TYPE (sp)); +} + +static void +relocate_typevector (tv) + struct typevector *tv; +{ + register int ntypes = TYPEVECTOR_NTYPES (tv); + register int i; + + for (i = 0; i < ntypes; i++) + RELOCATE (TYPEVECTOR_TYPE (tv, i)); + for (i = 0; i < ntypes; i++) + relocate_type (TYPEVECTOR_TYPE (tv, i)); +} + +/* We cannot come up with an a priori spanning tree + for the network of types, since types can be used + for many symbols and also as components of other types. + Therefore, we need to be able to mark types that we + already have relocated (or are already in the middle of relocating) + as in a garbage collector. */ + +static void +relocate_type (tp) + register struct type *tp; +{ + register int nfields = TYPE_NFIELDS (tp); + register int i; + + RELOCATE (TYPE_NAME (tp)); + RELOCATE (TYPE_TARGET_TYPE (tp)); + RELOCATE (TYPE_FIELDS (tp)); + RELOCATE (TYPE_POINTER_TYPE (tp)); + + for (i = 0; i < nfields; i++) + { + RELOCATE (TYPE_FIELD_TYPE (tp, i)); + RELOCATE (TYPE_FIELD_NAME (tp, i)); + } +} + +static void +relocate_sourcevector (svp) + register struct sourcevector *svp; +{ + register int nfiles = svp->length; + register int i; + for (i = 0; i < nfiles; i++) + RELOCATE (svp->source[i]); + for (i = 0; i < nfiles; i++) + relocate_source (svp->source[i]); +} + +static void +relocate_source (sp) + register struct source *sp; +{ + register int nitems = sp->contents.nitems; + register int i; + + RELOCATE (sp->name); + for (i = 0; i < nitems; i++) + TEXT_RELOCATE (sp->contents.item[i].pc); +} + +/* Read symsegs from file named NAME open on DESC, + make symtabs from them, and return a chain of them. + These symtabs are not suitable for direct use in `symtab_list' + because each one describes a single object file, perhaps many source files. + `symbol_file_command' takes each of these, makes many real symtabs + from it, and then frees it. + + We assume DESC is prepositioned at the end of the string table, + just before the symsegs if there are any. */ + +struct symtab * +read_symsegs (desc, name) + int desc; + char *name; +{ + struct symbol_root root; + register char *data; + register struct symtab *sp, *sp1, *chain = 0; + register int len; + + while (1) + { + len = myread (desc, &root, sizeof root); + if (len == 0 || root.format == 0) + break; + /* format 1 was ok for the original gdb, but since the size of the + type structure changed when C++ support was added, it can no + longer be used. Accept only format 2. */ + if (root.format != 2 || + root.length < sizeof root) + error ("\nInvalid symbol segment format code"); + data = (char *) xmalloc (root.length); + bcopy (&root, data, sizeof root); + len = myread (desc, data + sizeof root, + root.length - sizeof root); + sp = relocate_symtab (data); + RELOCATE (((struct symbol_root *)data)->sourcevector); + relocate_sourcevector (((struct symbol_root *)data)->sourcevector); + sp->next = chain; + chain = sp; + sp->linetable = (struct linetable *) ((struct symbol_root *)data)->sourcevector; + } + + return chain; +} + +static int block_depth (); +void print_spaces (); +static void print_symbol (); + +void +print_symtabs (filename) + char *filename; +{ + FILE *outfile; + register struct symtab *s; + register int i, j; + int len, line, 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 (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 %d (0x%x),", + SYMBOL_VALUE (symbol), SYMBOL_VALUE (symbol)); + break; + + case LOC_CONST_BYTES: + fprintf (outfile, "const %d hex bytes:", + TYPE_LENGTH (SYMBOL_TYPE (symbol))); + { + int i; + for (i = 0; i < TYPE_LENGTH (SYMBOL_TYPE (symbol)); i++) + fprintf (outfile, " %2x", SYMBOL_VALUE_BYTES (symbol) [i]); + fprintf (outfile, ","); + } + break; + + case LOC_STATIC: + fprintf (outfile, "static at 0x%x,", SYMBOL_VALUE (symbol)); + break; + + case LOC_REGISTER: + fprintf (outfile, "register %d,", SYMBOL_VALUE (symbol)); + break; + + case LOC_ARG: + fprintf (outfile, "arg at 0x%x,", SYMBOL_VALUE (symbol)); + break; + + case LOC_REF_ARG: + fprintf (outfile, "reference arg at 0x%x,", SYMBOL_VALUE (symbol)); + break; + + case LOC_REGPARM: + fprintf (outfile, "parameter register %d,", SYMBOL_VALUE (symbol)); + break; + + case LOC_LOCAL: + fprintf (outfile, "local at 0x%x,", SYMBOL_VALUE (symbol)); + break; + + case LOC_TYPEDEF: + break; + + case LOC_LABEL: + fprintf (outfile, "label at 0x%x", SYMBOL_VALUE (symbol)); + break; + + case LOC_BLOCK: + fprintf (outfile, "block (object 0x%x) starting at 0x%x,", + SYMBOL_VALUE (symbol), + BLOCK_START (SYMBOL_BLOCK_VALUE (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/gnu/usr.bin/gdb/symseg.h b/gnu/usr.bin/gdb/symseg.h new file mode 100644 index 0000000..6a61a17 --- /dev/null +++ b/gnu/usr.bin/gdb/symseg.h @@ -0,0 +1,523 @@ +/*- + * This code is derived from software copyrighted by the Free Software + * Foundation. + * + * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. + * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory. + * + * @(#)symseg.h 6.3 (Berkeley) 5/8/91 + */ + +/* GDB symbol table format definitions. + Copyright (C) 1986, 1989 Free Software Foundation, Inc. + Hacked by Michael Tiemann (tiemann@mcc.com) + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Format of GDB symbol table data. + There is one symbol segment for each source file or + independant compilation. These segments are simply concatenated + to form the GDB symbol table. A zero word where the beginning + of a segment is expected indicates there are no more segments. + +Format of a symbol segment: + + The symbol segment begins with a word containing 1 + if it is in the format described here. Other formats may + be designed, with other code numbers. + + The segment contains many objects which point at each other. + The pointers are offsets in bytes from the beginning of the segment. + Thus, each segment can be loaded into core and its pointers relocated + to make valid in-core pointers. + + All the data objects in the segment can be found indirectly from + one of them, the root object, of type `struct symbol_root'. + It appears at the beginning of the segment. + + The total size of the segment, in bytes, appears as the `length' + field of this object. This size includes the size of the + root object. + + All the object data types are defined here to contain pointer types + appropriate for in-core use on a relocated symbol segment. + Casts to and from type int are required for working with + unrelocated symbol segments such as are found in the file. + + The ldsymaddr word is filled in by the loader to contain + the offset (in bytes) within the ld symbol table + of the first nonglobal symbol from this compilation. + This makes it possible to match those symbols + (which contain line number information) reliably with + the segment they go with. + + Core addresses within the program that appear in the symbol segment + are not relocated by the loader. They are inserted by the assembler + and apply to addresses as output by the assembler, so GDB must + relocate them when it loads the symbol segment. It gets the information + on how to relocate from the textrel, datarel, bssrel, databeg and bssbeg + words of the root object. + + The words textrel, datarel and bssrel + are filled in by ld with the amounts to relocate within-the-file + text, data and bss addresses by; databeg and bssbeg can be + used to tell which kind of relocation an address needs. */ + +enum language {language_c}; + +struct symbol_root +{ + int format; /* Data format version */ + int length; /* # bytes in this symbol segment */ + int ldsymoff; /* Offset in ld symtab of this file's syms */ + int textrel; /* Relocation for text addresses */ + int datarel; /* Relocation for data addresses */ + int bssrel; /* Relocation for bss addresses */ + char *filename; /* Name of main source file compiled */ + char *filedir; /* Name of directory it was reached from */ + struct blockvector *blockvector; /* Vector of all symbol-naming blocks */ + struct typevector *typevector; /* Vector of all data types */ + enum language language; /* Code identifying the language used */ + char *version; /* Version info. Not fully specified */ + char *compilation; /* Compilation info. Not fully specified */ + int databeg; /* Address within the file of data start */ + int bssbeg; /* Address within the file of bss start */ + struct sourcevector *sourcevector; /* Vector of line-number info */ +}; + +/* 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 */ + + /* 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 +/* Indicates that this type is a public baseclass of another class, + i.e. that all its public methods are available in the derived + class. */ +#define TYPE_FLAG_VIA_PUBLIC 1024 +/* Indicates that this type is a virtual baseclass of another class, + i.e. that if this class is inherited more than once by another + class, only one set of member variables will be included. */ +#define TYPE_FLAG_VIA_VIRTUAL 2048 + +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. + Type names specified as input are defined by symbols. */ + char *name; + /* Length in bytes of storage for a value of this type */ + int 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. */ + 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++ */ + int *private_field_bits; + int *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; + /* If this is a virtual function, the offset into the vtbl-1, + else 0. */ + int voffset; + } *fn_fields; + + int *private_fn_field_bits; + int *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; + + /* If this type has a base class, put it here. + If this type is a pointer type, the chain of member pointer + types goes here. + Unused otherwise. + + Contrary to all maxims of C style and common sense, the baseclasses + are indexed from 1 to N_BASECLASSES rather than 0 to N_BASECLASSES-1 + (i.e. BASECLASSES points to one *before* the first element of + the array). */ + struct type **baseclasses; +}; + +/* 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. */ + int 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 the symbol in core. */ + +enum address_class +{ + LOC_UNDEF, /* Not used; catches errors */ + LOC_CONST, /* Value is constant int */ + LOC_STATIC, /* Value is at fixed address */ + LOC_REGISTER, /* Value is in register */ + LOC_ARG, /* Value is at spec'd position in arglist */ + LOC_REF_ARG, /* Value address is at spec'd position in */ + /* arglist. */ + LOC_REGPARM, /* Value is at spec'd position in register window */ + LOC_LOCAL, /* Value is at spec'd pos 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 in the code */ + LOC_BLOCK, /* Value is address of a `struct block'. + Function names have this class. */ + LOC_EXTERNAL, /* Value is at address not in this compilation. + This is used for .comm symbols + and for extern symbols within functions. + Inside GDB, this is changed to LOC_STATIC once the + real address is obtained from a loader symbol. */ + LOC_CONST_BYTES /* Value is a constant byte-sequence. */ +}; + +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; + /* constant value, or address if static, or register number, + or offset in arguments, or offset in stack frame. */ + union + { + long value; + struct block *block; /* for LOC_BLOCK */ + char *bytes; /* for LOC_CONST_BYTES */ + } + value; +}; + +struct partial_symbol +{ + /* Symbol name */ + char *name; + /* Name space code. */ + enum namespace namespace; + /* Address class (for info_symbols) */ + enum address_class class; + /* Associated partial symbol table */ + struct partial_symtab *pst; + /* 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 (pst) + in a partial symbol table, but BLOCK_START (SYMBOL_BLOCK_VALUE (st)) + in a symbol table. */ + union + { + long value; + } + value; +}; + +/* + * Vectors of all partial symbols read in from file; actually declared + * and used in dbxread.c. + */ +extern struct psymbol_allocation_list { + struct partial_symbol *list, *next; + int size; +} global_psymbols, static_psymbols; + + +/* 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; +}; diff --git a/gnu/usr.bin/gdb/symtab.c b/gnu/usr.bin/gdb/symtab.c new file mode 100644 index 0000000..a6feff4 --- /dev/null +++ b/gnu/usr.bin/gdb/symtab.c @@ -0,0 +1,2473 @@ +/*- + * This code is derived from software copyrighted by the Free Software + * Foundation. + * + * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. + * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory. + * + * $Header: /home/cvs/386BSD/src/usr.bin/gdb/symtab.c,v 1.1.1.1 1993/06/12 14:52:20 rgrimes Exp $; + */ + +#ifndef lint +static char sccsid[] = "@(#)symtab.c 6.3 (Berkeley) 5/8/91"; +#endif /* not lint */ + +/* Symbol table lookup for the GNU debugger, GDB. + Copyright (C) 1986, 1987, 1988, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <stdio.h> +#include "defs.h" +#include "symtab.h" +#include "param.h" + +#include <obstack.h> +#include <assert.h> + +char *index (); +extern char *cplus_demangle (); +extern struct value * value_of_this (); + +/* 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; + +/* 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; + +/* 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; + +/* Functions */ +static int find_line_common (); +int lookup_misc_func (); +struct partial_symtab *lookup_partial_symtab (); +struct symtab *psymtab_to_symtab (); +static struct partial_symbol *lookup_partial_symbol (); + +/* 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 = index (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."); + s = psymtab_to_symtab (ps); + return s; + } + + 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."); + s = psymtab_to_symtab (ps); + return s; + } + } + } + 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; + register char *copy; + + for (s = partial_symtab_list; s; s = s->next) + if (!strcmp (name, s->filename)) + return s; + + 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); + if (sym == 0 || SYMBOL_CLASS (sym) != LOC_TYPEDEF) + { + 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; + + if (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); +} + +/* 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); + + 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); + + 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); + 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; +{ + struct type *t; + int i; + char *errmsg; + + if (TYPE_CODE (type) != TYPE_CODE_STRUCT + && TYPE_CODE (type) != TYPE_CODE_UNION) + { + terminal_ours (); + fflush (stdout); + fprintf (stderr, "Type "); + type_print (type, "", stderr, -1); + fprintf (stderr, " is not a structure or union type.\n"); + return_to_top_level (); + } + + for (i = TYPE_NFIELDS (type) - 1; i >= 0; i--) + if (!strcmp (TYPE_FIELD_NAME (type, i), name)) + return TYPE_FIELD_TYPE (type, i); + + terminal_ours (); + fflush (stdout); + fprintf (stderr, "Type "); + type_print (type, "", stderr, -1); + fprintf (stderr, " has no component named %s\n", name); + return_to_top_level (); +} + +/* 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; +} + +/* 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; +} + +/* 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 pointers to TO_TYPE. + If TO_TYPE is not permanent and has no pointer-type yet, + record TYPE as its pointer-type. */ + +void +smash_to_pointer_type (type, to_type) + struct type *type, *to_type; +{ + int type_permanent = (TYPE_FLAGS (type) & TYPE_FLAG_PERM); + + bzero (type, sizeof (struct type)); + TYPE_TARGET_TYPE (type) = to_type; + /* We assume the machine has only one representation for pointers! */ + TYPE_LENGTH (type) = sizeof (char *); + TYPE_CODE (type) = TYPE_CODE_PTR; + + TYPE_MAIN_VARIANT (type) = type; + + if (type_permanent) + TYPE_FLAGS (type) |= TYPE_FLAG_PERM; + + if (TYPE_POINTER_TYPE (to_type) == 0 + && (!(TYPE_FLAGS (to_type) & TYPE_FLAG_PERM) + || type_permanent)) + { + TYPE_POINTER_TYPE (to_type) = 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); +} + +/* Smash TYPE to be a type of reference to TO_TYPE. + If TO_TYPE is not permanent and has no pointer-type yet, + record TYPE as its pointer-type. */ + +void +smash_to_reference_type (type, to_type) + struct type *type, *to_type; +{ + int type_permanent = (TYPE_FLAGS (type) & TYPE_FLAG_PERM); + + bzero (type, sizeof (struct type)); + TYPE_TARGET_TYPE (type) = to_type; + /* We assume the machine has only one representation for pointers! */ + TYPE_LENGTH (type) = sizeof (char *); + TYPE_CODE (type) = TYPE_CODE_REF; + + TYPE_MAIN_VARIANT (type) = type; + + if (type_permanent) + TYPE_FLAGS (type) |= TYPE_FLAG_PERM; + + if (TYPE_REFERENCE_TYPE (to_type) == 0 + && (!(TYPE_FLAGS (to_type) & TYPE_FLAG_PERM) + || type_permanent)) + { + TYPE_REFERENCE_TYPE (to_type) = type; + } +} + +/* Smash TYPE to be a type of functions returning TO_TYPE. + If TO_TYPE is not permanent and has no function-type yet, + record TYPE as its function-type. */ + +void +smash_to_function_type (type, to_type) + struct type *type, *to_type; +{ + int type_permanent = (TYPE_FLAGS (type) & TYPE_FLAG_PERM); + + bzero (type, sizeof (struct type)); + TYPE_TARGET_TYPE (type) = to_type; + TYPE_LENGTH (type) = 1; + TYPE_CODE (type) = TYPE_CODE_FUNC; + TYPE_NFIELDS (type) = 0; + + if (type_permanent) + TYPE_FLAGS (type) |= TYPE_FLAG_PERM; + + if (TYPE_FUNCTION_TYPE (to_type) == 0 + && (!(TYPE_FLAGS (to_type) & TYPE_FLAG_PERM) + || type_permanent)) + { + TYPE_FUNCTION_TYPE (to_type) = type; + } +} + +/* 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; + int 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 (p) + && SYMBOL_VALUE (p) > best_pc) + { + best_pc = SYMBOL_VALUE (p); + best = p; + } + if (best_pc == psymtab->textlow - 1) + return 0; + return best; +} + + +static struct symbol *lookup_block_symbol (); + +/* 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. + 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) + char *name; + register struct block *block; + enum namespace namespace; + int *is_a_field_of_this; +{ + register int i, n; + register struct symbol *sym; + register struct symtab *s; + register struct partial_symtab *ps; + register struct partial_symbol *psym; + struct blockvector *bv; + + /* Search specified block and its superiors. */ + + while (block != 0) + { + sym = lookup_block_symbol (block, name, namespace); + if (sym) + { + block_found = block; + 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; + 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; + 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 index = lookup_misc_func (name); + + if (index == -1) + { /* Look for a mangled C++ name for NAME. */ + int name_len = strlen (name); + for (index = misc_function_count; --index >= 0; ) + /* Assume orginal name is prefix of mangled name. */ + if (!strncmp (misc_function_vector[index].name, name, name_len)) + { + char *demangled = + cplus_demangle(misc_function_vector[index].name, -1); + if (demangled != NULL) + { + int cond = strcmp (demangled, name); + free (demangled); + if (!cond) + break; + } + } + /* Loop terminates on no match with index == -1. */ + } + + if (index != -1) + { + ps = find_pc_psymtab (misc_function_vector[index].address); + if (ps && !ps->readin) + { + s = psymtab_to_symtab (ps); + bv = BLOCKVECTOR (s); + block = BLOCKVECTOR_BLOCK (bv, 0); + sym = lookup_block_symbol (block, name, namespace); + /* sym == 0 if symbol was found in the psymtab 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:"); + */ + + return sym; + } + } + } + + if (psym = lookup_partial_symbol (name, 1, namespace)) + { + ps = psym->pst; + 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"); + 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; + return sym; + } + } + + if (psym = lookup_partial_symbol(name, 0, namespace)) + { + ps = psym->pst; + 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"); + return sym; + } + + 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 (name, global, namespace) + register char *name; + register int global; + register enum namespace namespace; +{ + register struct partial_symbol *start, *psym; + register struct partial_symbol *top, *bottom, *center; + register struct partial_symtab *pst; + register int length; + + if (global) + { + start = global_psymbols.list; + length = global_psymbols.next - start; + } + else + { + start = static_psymbols.list; + length = static_psymbols.next - start; + } + + if (!length) + return (struct partial_symbol *) 0; + + /* Binary search. This search is guarranteed 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) == 0) + { + if (!top->pst->readin && SYMBOL_NAMESPACE (top) == namespace) + return top; + top ++; + } + + return (struct partial_symbol *) 0; +} + +/* Look for a symbol in block BLOCK. */ + +static 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_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 value; + 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) + { + value.symtab = 0; + value.line = 0; + value.pc = pc; + value.end = 0; + return value; + } + + 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) + { + value.symtab = alt_symtab; + value.line = alt_line - 1; + value.pc = BLOCK_END (BLOCKVECTOR_BLOCK (bv, 0)); + value.end = alt_pc; + } + else + { + value.symtab = best_symtab; + value.line = best_line; + value.pc = best_pc; + value.end = (best_end ? best_end + : (alt_pc ? alt_pc + : BLOCK_END (BLOCKVECTOR_BLOCK (bv, 0)))); + } + return value; +} + +/* 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 index; + int dummy; + + if (symtab == 0) + return 0; + l = LINETABLE (symtab); + index = find_line_common(l, line, &dummy); + return index ? l->item[index].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 index; + int exact_match; /* did we get an exact linenumber match */ + register CORE_ADDR prev_pc; + CORE_ADDR last_pc; + + if (symtab == 0) + return 0; + + l = LINETABLE (symtab); + index = find_line_common (l, thisline, &exact_match); + if (index) + { + *startptr = l->item[index].pc; + /* If we have not seen an entry for the specified line, + assume that means the specified line has zero bytes. */ + if (!exact_match || index == l->nitems-1) + *endptr = *startptr; + else + /* Perhaps the following entry is for the following line. + It's worth a try. */ + if (l->item[index+1].line == thisline + 1) + *endptr = l->item[index+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; + + int nextline = -1; + + 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; +} + +/* 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. + 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 value; + register char *p, *p1; + register struct symtab *s; + register struct symbol *sym; + register CORE_ADDR pc; + register int i; + char *copy; + struct symbol *sym_class; + char *class_name, *method_name, *phys_name; + int method_counter; + int i1; + struct symbol **sym_arr; + struct type *t, *field; + 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 *) + malloc (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); + + 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; + 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); + if (sym_arr[i1]) i1++; + } + else while (t) + { + class_name = TYPE_NAME (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) + { + /* We just want the class name. In the context + of C++, stripping off "struct " is always + sensible. */ + if (strncmp("struct ", class_name, 7) == 0) + class_name += 7; + if (strncmp("union ", class_name, 6) == 0) + class_name += 6; + + sym_class = lookup_symbol (class_name, 0, STRUCT_NAMESPACE, 0); + for (method_counter = TYPE_NFN_FIELDS (SYMBOL_TYPE (sym_class)) - 1; + method_counter >= 0; + --method_counter) + { + int field_counter; + struct fn_field *f = + TYPE_FN_FIELDLIST1 (SYMBOL_TYPE (sym_class), method_counter); + + method_name = TYPE_FN_FIELDLIST_NAME (SYMBOL_TYPE (sym_class), method_counter); + if (!strcmp (copy, method_name)) + /* Find all the fields with that name. */ + for (field_counter = TYPE_FN_FIELDLIST_LENGTH (SYMBOL_TYPE (sym_class), method_counter) - 1; + field_counter >= 0; + --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, 0); + if (sym_arr[i1]) i1++; + } + } + } + if (TYPE_N_BASECLASSES (t)) + t = TYPE_BASECLASS(t, 1); + else + break; + } + + 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 *)malloc (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 (argptr, sym_arr, physnames, + i1, funfirstline); + } + else + error ("that class does not have any method named %s",copy); + } + else + 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 symbol table is loaded. Use the \"symbol-file\" command."); + 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 guarrantee 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 symbol table is loaded. Use the \"symbol-file\" command."); + 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)++; + value.line = atoi (*argptr); + switch (sign) + { + case plus: + if (p == *argptr) + value.line = 5; + if (s == 0) + value.line = default_line + value.line; + break; + case minus: + if (p == *argptr) + value.line = 15; + if (s == 0) + value.line = default_line - value.line; + else + value.line = 1; + break; + } + + while (*p == ' ' || *p == '\t') p++; + *argptr = p; + if (s == 0) + s = default_symtab; + value.symtab = s; + value.pc = 0; + values.sals = (struct symtab_and_line *)malloc (sizeof (struct symtab_and_line)); + values.sals[0] = value; + values.nelts = 1; + return values; + } + + /* 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++; + 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 function. + If file specified, use that file's per-file block to start with. */ + + if (s == 0) + /* use current file as default if none is specified. */ + s = default_symtab; + + sym = lookup_symbol (copy, s ? BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), 1) : 0, + VAR_NAMESPACE, 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); + value = find_pc_line (pc, 0); +#ifdef PROLOGUE_FIRSTLINE_OVERLAP + /* Convex: no need to suppress code on first line, if any */ + value.pc = pc; +#else + value.pc = (value.end && value.pc != pc) ? value.end : pc; +#endif + values.sals = (struct symtab_and_line *)malloc (sizeof (struct symtab_and_line)); + values.sals[0] = value; + values.nelts = 1; + return values; + } + + if (sym) + error ("%s is not a function.", copy); + + if (symtab_list == 0 && partial_symtab_list == 0) + error ("No symbol table is loaded. Use the \"symbol-file\" command."); + + if ((i = lookup_misc_func (copy)) >= 0) + { + value.symtab = 0; + value.line = 0; + value.pc = misc_function_vector[i].address + FUNCTION_START_OFFSET; + if (funfirstline) + SKIP_PROLOGUE (value.pc); + values.sals = (struct symtab_and_line *)malloc (sizeof (struct symtab_and_line)); + values.sals[0] = value; + values.nelts = 1; + return values; + } + + error ("Function %s not defined.", copy); +} + +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 (argptr, sym_arr, physnames, nelts, funfirstline) + char **argptr; + struct symbol *sym_arr[]; + char *physnames[]; + 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 *) malloc (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; +} + +/* hash a symbol ("hashpjw" from Aho, Sethi & Ullman, p.436) */ + +int +hash_symbol(str) + register char *str; +{ + register unsigned int h = 0, g; + register unsigned char c; + + while (c = *(unsigned char *)str++) { + h = (h << 4) + c; + if (g = h & 0xf0000000) { + h = h ^ (g >> 24); + h = h ^ g; + } + } + return ((int)h); +} + +/* Return the index of misc function named NAME. */ + +int +lookup_misc_func (name) + register char *name; +{ + register int i = hash_symbol(name) & (MISC_FUNC_HASH_SIZE - 1); + + if (misc_function_vector == 0) + error("No symbol file"); + + i = misc_function_hash_tab[i]; + while (i >= 0) + { + if (strcmp(misc_function_vector[i].name, name) == 0) + break; + i = misc_function_vector[i].next; + } + return (i); +} + +/* + * Slave routine for sources_info. Force line breaks at ,'s. + */ +static void +output_source_filename (name, next) +char *name; +int next; +{ + static int column = 0; + + if (column != 0 && column + strlen (name) >= 70) + { + printf_filtered ("\n"); + column = 0; + } + else if (column != 0) + { + printf_filtered (" "); + column++; + } + printf_filtered ("%s", name); + column += strlen (name); + if (next) + { + printf_filtered (","); + column++; + } + + if (!next) column = 0; +} + +static void +sources_info () +{ + register struct symtab *s; + register struct partial_symtab *ps; + register int column = 0; + + if (symtab_list == 0 && partial_symtab_list == 0) + { + printf ("No symbol table is loaded.\n"); + return; + } + + printf_filtered ("Source files for which symbols have been read in:\n\n"); + + for (s = symtab_list; s; s = s->next) + output_source_filename (s->filename, s->next); + printf_filtered ("\n\n"); + + printf_filtered ("Source files for which symbols will be read in on demand:\n\n"); + + for (ps = partial_symtab_list; ps; ps = ps->next) + if (!ps->readin) + output_source_filename (ps->filename, ps->next); + 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. */ + +static void sort_block_syms (); + +static void +list_symbols (regexp, class) + char *regexp; + int class; +{ + 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, *bound; + char *val; + static char *classnames[] + = {"variable", "function", "type", "method"}; + int print_count = 0; + int found_in_file = 0; + + if (regexp) + if (val = (char *) re_comp (regexp)) + error ("Invalid regexp: %s", val); + + /* 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 (psym = global_psymbols.list, bound = global_psymbols.next; ; + psym = static_psymbols.list, bound = static_psymbols.next) + { + for (; psym < bound; ++psym) + { + if (psym->pst->readin) + continue; + + 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))) + psymtab_to_symtab(psym->pst); + } + if (psym == static_psymbols.next) + break; + } + + /* Printout here so as to get after the "Reading in symbols" + messages which will be generated above. */ + printf_filtered (regexp + ? "All %ss matching regular expression \"%s\":\n" + : "All defined %ss:\n", + classnames[class], + regexp); + + /* Here, *if* the class is correct (function only, right now), we + should search through the misc function vector for symbols that + match and call find_pc_psymtab on them. If find_pc_psymtab returns + 0, don't worry about it (already read in or no debugging info). */ + + if (class == 1) + { + for (i = 0; i < misc_function_count; i++) + if (regexp == 0 || re_exec (misc_function_vector[i].name)) + { + ps = find_pc_psymtab (misc_function_vector[i].address); + if (ps && !ps->readin) + psymtab_to_symtab (ps); + } + } + + 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 (!found_in_file) + { + printf_filtered ("\nFile %s:\n", s->filename); + print_count += 2; + } + 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)))) + printf_filtered (" %s", 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 (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); +} + +static void +functions_info (regexp) + char *regexp; +{ + list_symbols (regexp, 1); +} + +static void +types_info (regexp) + char *regexp; +{ + list_symbols (regexp, 2); +} + +#if 0 +/* Tiemann says: "info methods was never implemented." */ +static void +methods_info (regexp) + char *regexp; +{ + list_symbols (regexp, 3); +} +#endif /* 0 */ + +/* Call sort_block_syms to sort alphabetically the symbols of one block. */ + +static int +compare_symbols (s1, s2) + struct symbol **s1, **s2; +{ + /* Names that are less should come first. */ + register int namediff = strcmp (SYMBOL_NAME (*s1), SYMBOL_NAME (*s2)); + if (namediff != 0) return namediff; + /* For symbols of the same name, registers should come first. */ + return ((SYMBOL_CLASS (*s2) == LOC_REGISTER) + - (SYMBOL_CLASS (*s1) == LOC_REGISTER)); +} + +static void +sort_block_syms (b) + register struct block *b; +{ + qsort (&BLOCK_SYM (b, 0), BLOCK_NSYMS (b), + sizeof (struct symbol *), compare_symbols); +} + +/* 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; + TYPE_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 a->startaddr >= b->startaddr && a->endaddr <= b->endaddr; +} + + +/* 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 blockvector *bv; + struct blockvector *prev_bv = 0; + register struct block *b, *surrounding_static_block; + extern struct block *get_selected_block (); + register int i, j; + register struct symbol *sym; + 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 = 0; 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) + { + struct block *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) + { + struct block *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."); + add_info ("types", types_info, + "All types names, or those matching REGEXP."); +#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."); + + obstack_init (symbol_obstack); + obstack_init (psymbol_obstack); + + 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 +} + diff --git a/gnu/usr.bin/gdb/symtab.h b/gnu/usr.bin/gdb/symtab.h new file mode 100644 index 0000000..fefed60 --- /dev/null +++ b/gnu/usr.bin/gdb/symtab.h @@ -0,0 +1,384 @@ +/*- + * This code is derived from software copyrighted by the Free Software + * Foundation. + * + * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. + * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory. + * + * @(#)symtab.h 6.3 (Berkeley) 5/8/91 + */ + +/* 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. */ + +#include <obstack.h> + +/* An obstack to hold objects that should be freed + when we load a new symbol table. + This includes the symbols made by dbxread + and the types that are not permanent. */ + +extern struct obstack *symbol_obstack; +extern struct obstack *psymbol_obstack; + +/* Some definitions and declarations to go with use of obstacks. */ +#define obstack_chunk_alloc xmalloc +#define obstack_chunk_free free +extern char *xmalloc (); +extern void free (); + +/* 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 appears + never to be used. */ + +enum misc_function_type {mf_unknown = 0, mf_text, mf_data, mf_bss, mf_abs}; + +struct misc_function +{ + char *name; + CORE_ADDR address; + int next; /* index of next in this hash bucket */ + unsigned char type; /* Really enum misc_function_type. */ +}; + +/* Address and length of the vector recording all misc function names/addresses. */ + +struct misc_function *misc_function_vector; +int misc_function_count; +#define MISC_FUNC_HASH_SIZE (2048) +int misc_function_hash_tab[MISC_FUNC_HASH_SIZE]; + +#include "symseg.h" + +/* 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; + /* 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. */ + 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; + /* String of compilation information. May be zero. */ + char *compilation; + /* Offset within loader symbol table + of first local symbol for this file. */ + int ldsymoff; + /* 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. + */ +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; + /* 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. */ + int textlow, texthigh; + /* Non-zero if the symtab corresponding to this psymtab has been + readin */ + unsigned char readin; + /* Array of pointers to all of the partial_symtab s which this one + depends one. Since this array can only be set to previous or + the current (?) psymtab, this dependency tree is guarranteed 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; +}; + +/* 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_BYTES(symbol) (symbol)->value.bytes +#define SYMBOL_BLOCK_VALUE(symbol) (symbol)->value.block +#define SYMBOL_TYPE(symbol) (symbol)->type + +/* Some macros for bitfields. */ +#define B_SET(a,x) (a[x>>5] |= (1 << (x&31))) +#define B_CLR(a,x) (a[x>>5] &= ~(1 << (x&31))) +#define B_TST(a,x) (a[x>>5] & (1 << (x&31))) + +#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_BASECLASSES(thistype) (thistype)->baseclasses +#define TYPE_ARG_TYPES(thistype) (thistype)->arg_types +#define TYPE_BASECLASS(thistype,index) (thistype)->baseclasses[index] +#define TYPE_N_BASECLASSES(thistype) (thistype)->n_baseclasses +#define TYPE_VIA_PUBLIC(thistype) ((thistype)->flags & TYPE_FLAG_VIA_PUBLIC) +#define TYPE_VIA_VIRTUAL(thistype) ((thistype)->flags & TYPE_FLAG_VIA_VIRTUAL) + +#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 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 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_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) (thistype)[n].args +#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 > 0) +#define TYPE_FN_FIELD_VOFFSET(thistype, n) ((thistype)[n].voffset-1) + +#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) + +/* Functions that work on the objects described above */ + +extern struct symtab *lookup_symtab (); +extern struct symbol *lookup_symbol (); +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 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 (); + +/* C++ stuff. */ +extern struct type *lookup_reference_type (); +extern struct type *lookup_member_type (); +extern struct type *lookup_class (); +/* end of C++ stuff. */ + +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; + +#ifdef LONG_LONG +extern struct type *builtin_type_long_long; +extern struct type *builtin_type_unsigned_long_long; + +#ifndef BUILTIN_TYPE_LONGEST +#define BUILTIN_TYPE_LONGEST builtin_type_long_long +#endif + +#ifndef BUILTIN_TYPE_UNSIGNED_LONGEST +#define BUILTIN_TYPE_UNSIGNED_LONGEST builtin_type_unsigned_long_long +#endif + +#else /* LONG_LONG */ + +#ifndef BUILTIN_TYPE_LONGEST +#define BUILTIN_TYPE_LONGEST builtin_type_long +#endif + +#ifndef BUILTIN_TYPE_UNSIGNED_LONGEST +#define BUILTIN_TYPE_UNSIGNED_LONGEST builtin_type_unsigned_long +#endif + +#endif + +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 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 (); diff --git a/gnu/usr.bin/gdb/utils.c b/gnu/usr.bin/gdb/utils.c new file mode 100644 index 0000000..b03f2be --- /dev/null +++ b/gnu/usr.bin/gdb/utils.c @@ -0,0 +1,1096 @@ +/*- + * This code is derived from software copyrighted by the Free Software + * Foundation. + * + * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. + * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory. + * + * $Header: /home/cvs/386BSD/src/usr.bin/gdb/utils.c,v 1.1.1.1 1993/06/12 14:52:20 rgrimes Exp $; + */ + +#ifndef lint +static char sccsid[] = "@(#)utils.c 6.4 (Berkeley) 5/8/91"; +#endif /* not lint */ + +/* General utility routines 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. */ + +#include "param.h" + +#include <stdio.h> +#include <ctype.h> +#include <signal.h> +#include <sys/ioctl.h> +#include <sys/param.h> +#include <pwd.h> +#include "defs.h" +#ifdef HAVE_TERMIO +#include <termio.h> +#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 + +extern FILE *instream; + +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; + +/* 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); +} + +/* Generally useful subroutines used throughout the program. */ + +/* Like malloc but get error if no storage available. */ + +char * +xmalloc (size) + long size; +{ + register char *val = (char *) malloc (size); + if (!val) + fatal ("virtual memory exhausted.", 0); + return val; +} + +/* Like realloc but get error if no storage available. */ + +char * +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[]; + extern int errno; + 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); + + 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); +} + +void +quit () +{ +#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 () +{ + extern int remote_debugging; + + quit_flag = 1; + +#ifdef USG + /* Restore the signal handler. */ + signal (SIGINT, request_quit); +#endif + + if (immediate_quit) + quit(); +} + +/* Print an error message and return to command level. + STRING is the error message, used as a fprintf string, + and ARG is passed as an argument to it. */ + +void +error (string, arg1, arg2, arg3) + char *string; + int arg1, arg2, arg3; +{ + terminal_ours (); /* Should be ok even if no inf. */ + fflush (stdout); + fprintf (stderr, string, arg1, arg2, arg3); + fprintf (stderr, "\n"); + return_to_top_level (); +} + +/* Print an error message and exit reporting failure. + This is for a error that we cannot continue from. + STRING and ARG are passed to fprintf. */ + +void +fatal (string, arg) + char *string; + int arg; +{ + fprintf (stderr, "gdb: "); + fprintf (stderr, string, arg); + fprintf (stderr, "\n"); + exit (1); +} + +/* Print an error message and exit, dumping core. + STRING is a printf-style control string, and ARG is a corresponding + argument. */ +void +fatal_dump_core (string, arg) + char *string; + int arg; +{ + /* "internal error" is always correct, since GDB should never dump + core, no matter what the input. */ + fprintf (stderr, "gdb internal error: "); + fprintf (stderr, string, arg); + fprintf (stderr, "\n"); + signal (SIGQUIT, SIG_DFL); + kill (getpid (), SIGQUIT); + /* We should never get here, but just in case... */ + exit (1); +} + +/* 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 * +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. */ + +int +query (ctlstr, arg1, arg2) + char *ctlstr; +{ + register int answer; + + /* Automatically answer "yes" if input is not from a terminal. */ + if (!input_from_terminal_p ()) + return 1; + + while (1) + { + printf (ctlstr, arg1, arg2); + printf ("(y or n) "); + fflush (stdout); + answer = fgetc (stdin); + clearerr (stdin); /* in case of C-d */ + if (answer != '\n') + while (fgetc (stdin) != '\n') clearerr (stdin); + 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 + 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 || 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); + } +} + +static int lines_per_page, lines_printed, chars_per_line, chars_printed; + +/* Set values of page and line size. */ +static void +set_screensize_command (arg, from_tty) + char *arg; + int from_tty; +{ + char *p = arg; + char *p1; + int tolinesize = lines_per_page; + int tocharsize = chars_per_line; + + if (p == 0) + error_no_arg ("set screensize"); + + while (*p >= '0' && *p <= '9') + p++; + + if (*p && *p != ' ' && *p != '\t') + error ("Non-integral argument given to \"set screensize\"."); + + tolinesize = atoi (arg); + + while (*p == ' ' || *p == '\t') + p++; + + if (*p) + { + p1 = p; + while (*p1 >= '0' && *p1 <= '9') + p1++; + + if (*p1) + error ("Non-integral second argument given to \"set screensize\"."); + + tocharsize = atoi (p); + } + + lines_per_page = tolinesize; + chars_per_line = tocharsize; +} + +static void +instream_cleanup(stream) + FILE *stream; +{ + instream = stream; +} + +static void +prompt_for_continue () +{ + if (ISATTY(stdin) && ISATTY(stdout)) + { + struct cleanup *old_chain = make_cleanup(instream_cleanup, instream); + char *cp, *gdb_readline(); + + instream = stdin; + immediate_quit++; + if (cp = gdb_readline ("---Type <return> to continue---")) + free(cp); + chars_printed = lines_printed = 0; + immediate_quit--; + do_cleanups(old_chain); + } +} + +/* Reinitialize filter; ie. tell it to reset to original values. */ + +void +reinitialize_more_filter () +{ + lines_printed = 0; + chars_printed = 0; +} + +static void +screensize_info (arg, from_tty) + char *arg; + int from_tty; +{ + if (arg) + error ("\"info screensize\" does not take any arguments."); + + if (!lines_per_page) + printf ("Output more filtering is disabled.\n"); + else + { + printf ("Output more filtering is enabled with\n"); + printf ("%d lines per page and %d characters per line.\n", + lines_per_page, chars_per_line); + } +} + +/* Like fputs but pause after every screenful. + 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 || !ISATTY(stdout) || lines_per_page == 0) + { + 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') + { + 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 + { + putc (*lineptr, stream); + chars_printed++; + lineptr++; + } + + if (chars_printed >= chars_per_line) + { + chars_printed = 0; + lines_printed++; + /* Possible new page. */ + if (lines_printed >= lines_per_page - 1) + prompt_for_continue (); + } + } + + if (*lineptr == '\n') + { + lines_printed++; + putc ('\n', stream); + lineptr++; + chars_printed = 0; + } + } +} + +/* fputs_demangled is a variant of fputs_filtered that + demangles g++ names.*/ + +void +fputs_demangled (linebuffer, stream, arg_mode) + char *linebuffer; + FILE *stream; +{ +#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]; + char *p; + + if (linebuffer == NULL) + return; + + p = linebuffer; + + while ( *p != (char) 0 ) { + int i = 0; + + /* collect non-interesting characters into buf */ + while ( *p != (char) 0 && !SYMBOL_CHAR(*p) ) { + 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) ) { + 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 ARG1, ARG2, and ARG3 on stdout using format FORMAT. If this + information is going to put the amount written since the last call + to INIIALIZE_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. + + 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. */ + +void +fprintf_filtered (stream, format, arg1, arg2, arg3, arg4, arg5, arg6) + FILE *stream; + char *format; + int arg1, arg2, arg3, arg4, arg5, arg6; +{ + static char *linebuffer = (char *) 0; + static int line_size; + int format_length = strlen (format); + int numchars; + + /* 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. */ + (void) sprintf (linebuffer, format, arg1, arg2, arg3, arg4, arg5, arg6); + + fputs_filtered (linebuffer, stream); +} + +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); +} + +/* Print N spaces. */ +void +print_spaces_filtered (n, stream) + int n; + FILE *stream; +{ + register char *s = (char *) alloca (n + 1); + register char *t = s; + + while (n--) + *t++ = ' '; + *t = '\0'; + + fputs_filtered (s, stream); +} + + +#ifdef USG +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); +} + +#ifndef USG +char *sys_siglist[32] = { + "SIG0", + "SIGHUP", + "SIGINT", + "SIGQUIT", + "SIGILL", + "SIGTRAP", + "SIGIOT", + "SIGEMT", + "SIGFPE", + "SIGKILL", + "SIGBUS", + "SIGSEGV", + "SIGSYS", + "SIGPIPE", + "SIGALRM", + "SIGTERM", + "SIGUSR1", + "SIGUSR2", + "SIGCLD", + "SIGPWR", + "SIGWIND", + "SIGPHONE", + "SIGPOLL", +}; +#endif + +/* 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 /* USG */ + +#ifdef USG +/* There is too much variation in Sys V signal numbers and names, so + we must initialize them at runtime. */ +static char undoc[] = "(undocumented)"; + +char *sys_siglist[NSIG]; +#endif /* USG */ + +extern struct cmd_list_element *setlist; + +void +_initialize_utils () +{ + int i; + add_cmd ("screensize", class_support, set_screensize_command, + "Change gdb's notion of the size of the output screen.\n\ +The first argument is the number of lines on a page.\n\ +The second argument (optional) is the number of characters on a line.", + &setlist); + add_info ("screensize", screensize_info, + "Show gdb's current notion of the size of the output screen."); + + /* 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. */ + { + int 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 = 0; + + val = tgetnum ("co"); + if (val >= 0) + chars_per_line = val; + } + } + } + +#ifdef USG + /* Initialize signal names. */ + for (i = 0; i < NSIG; i++) + sys_siglist[i] = undoc; + +#ifdef SIGHUP + sys_siglist[SIGHUP ] = "SIGHUP"; +#endif +#ifdef SIGINT + sys_siglist[SIGINT ] = "SIGINT"; +#endif +#ifdef SIGQUIT + sys_siglist[SIGQUIT ] = "SIGQUIT"; +#endif +#ifdef SIGILL + sys_siglist[SIGILL ] = "SIGILL"; +#endif +#ifdef SIGTRAP + sys_siglist[SIGTRAP ] = "SIGTRAP"; +#endif +#ifdef SIGIOT + sys_siglist[SIGIOT ] = "SIGIOT"; +#endif +#ifdef SIGEMT + sys_siglist[SIGEMT ] = "SIGEMT"; +#endif +#ifdef SIGFPE + sys_siglist[SIGFPE ] = "SIGFPE"; +#endif +#ifdef SIGKILL + sys_siglist[SIGKILL ] = "SIGKILL"; +#endif +#ifdef SIGBUS + sys_siglist[SIGBUS ] = "SIGBUS"; +#endif +#ifdef SIGSEGV + sys_siglist[SIGSEGV ] = "SIGSEGV"; +#endif +#ifdef SIGSYS + sys_siglist[SIGSYS ] = "SIGSYS"; +#endif +#ifdef SIGPIPE + sys_siglist[SIGPIPE ] = "SIGPIPE"; +#endif +#ifdef SIGALRM + sys_siglist[SIGALRM ] = "SIGALRM"; +#endif +#ifdef SIGTERM + sys_siglist[SIGTERM ] = "SIGTERM"; +#endif +#ifdef SIGUSR1 + sys_siglist[SIGUSR1 ] = "SIGUSR1"; +#endif +#ifdef SIGUSR2 + sys_siglist[SIGUSR2 ] = "SIGUSR2"; +#endif +#ifdef SIGCLD + sys_siglist[SIGCLD ] = "SIGCLD"; +#endif +#ifdef SIGCHLD + sys_siglist[SIGCHLD ] = "SIGCHLD"; +#endif +#ifdef SIGPWR + sys_siglist[SIGPWR ] = "SIGPWR"; +#endif +#ifdef SIGTSTP + sys_siglist[SIGTSTP ] = "SIGTSTP"; +#endif +#ifdef SIGTTIN + sys_siglist[SIGTTIN ] = "SIGTTIN"; +#endif +#ifdef SIGTTOU + sys_siglist[SIGTTOU ] = "SIGTTOU"; +#endif +#ifdef SIGSTOP + sys_siglist[SIGSTOP ] = "SIGSTOP"; +#endif +#ifdef SIGXCPU + sys_siglist[SIGXCPU ] = "SIGXCPU"; +#endif +#ifdef SIGXFSZ + sys_siglist[SIGXFSZ ] = "SIGXFSZ"; +#endif +#ifdef SIGVTALRM + sys_siglist[SIGVTALRM ] = "SIGVTALRM"; +#endif +#ifdef SIGPROF + sys_siglist[SIGPROF ] = "SIGPROF"; +#endif +#ifdef SIGWINCH + sys_siglist[SIGWINCH ] = "SIGWINCH"; +#endif +#ifdef SIGCONT + sys_siglist[SIGCONT ] = "SIGCONT"; +#endif +#ifdef SIGURG + sys_siglist[SIGURG ] = "SIGURG"; +#endif +#ifdef SIGIO + sys_siglist[SIGIO ] = "SIGIO"; +#endif +#ifdef SIGWIND + sys_siglist[SIGWIND ] = "SIGWIND"; +#endif +#ifdef SIGPHONE + sys_siglist[SIGPHONE ] = "SIGPHONE"; +#endif +#ifdef SIGPOLL + sys_siglist[SIGPOLL ] = "SIGPOLL"; +#endif +#endif /* USG */ +} diff --git a/gnu/usr.bin/gdb/valarith.c b/gnu/usr.bin/gdb/valarith.c new file mode 100644 index 0000000..8e76899 --- /dev/null +++ b/gnu/usr.bin/gdb/valarith.c @@ -0,0 +1,690 @@ +/*- + * This code is derived from software copyrighted by the Free Software + * Foundation. + * + * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. + * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory. + */ + +#ifndef lint +static char sccsid[] = "@(#)valarith.c 6.3 (Berkeley) 5/8/91"; +#endif /* not lint */ + +/* 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 "symtab.h" +#include "value.h" +#include "expression.h" + + +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 + && + TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_INT) + { + 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; + } + + if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_PTR + && + VALUE_TYPE (arg1) == VALUE_TYPE (arg2)) + { + 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; + } + + 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) */ + +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"); + + if (TYPE_CODE (elt_type) == TYPE_CODE_FLT) + { + if (elt_size == sizeof (float)) + v = value_from_double (elt_type, (double) *(float *) + (VALUE_CONTENTS (array) + elt_offs)); + else + v = value_from_double (elt_type, *(double *) + (VALUE_CONTENTS (array) + elt_offs)); + } + else + { + int offs; + union {int i; char c;} test; + test.i = 1; + if (test.c == 1) + offs = 0; + else + offs = sizeof (LONGEST) - elt_size; + v = value_from_long (elt_type, *(LONGEST *) + (VALUE_CONTENTS (array) + elt_offs - offs)); + } + + 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; + int 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 ("friend functions not implemented yet"); + + 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+9; + switch (op) + { + case BINOP_ADD: strcpy(ptr,"+"); break; + case BINOP_SUB: strcpy(ptr,"-"); break; + case BINOP_MUL: strcpy(ptr,"*"); break; + case BINOP_DIV: strcpy(ptr,"/"); break; + case BINOP_REM: strcpy(ptr,"%"); break; + case BINOP_LSH: strcpy(ptr,"<<"); break; + case BINOP_RSH: strcpy(ptr,">>"); break; + case BINOP_LOGAND: strcpy(ptr,"&"); break; + case BINOP_LOGIOR: strcpy(ptr,"|"); break; + case BINOP_LOGXOR: strcpy(ptr,"^"); break; + case BINOP_AND: strcpy(ptr,"&&"); break; + case BINOP_OR: strcpy(ptr,"||"); break; + case BINOP_MIN: strcpy(ptr,"<?"); break; + case BINOP_MAX: strcpy(ptr,">?"); break; + case BINOP_ASSIGN: strcpy(ptr,"="); break; + case BINOP_ASSIGN_MODIFY: + switch (otherop) + { + case BINOP_ADD: strcpy(ptr,"+="); break; + case BINOP_SUB: strcpy(ptr,"-="); break; + case BINOP_MUL: strcpy(ptr,"*="); break; + case BINOP_DIV: strcpy(ptr,"/="); break; + case BINOP_REM: strcpy(ptr,"%="); break; + case BINOP_LOGAND: strcpy(ptr,"&="); break; + case BINOP_LOGIOR: strcpy(ptr,"|="); break; + case BINOP_LOGXOR: strcpy(ptr,"^="); break; + default: + error ("Invalid binary operation specified."); + } + break; + case BINOP_SUBSCRIPT: strcpy(ptr,"[]"); break; + case BINOP_EQUAL: strcpy(ptr,"=="); break; + case BINOP_NOTEQUAL: strcpy(ptr,"!="); break; + case BINOP_LESS: strcpy(ptr,"<"); break; + case BINOP_GTR: strcpy(ptr,">"); break; + case BINOP_GEQ: strcpy(ptr,">="); break; + case BINOP_LEQ: strcpy(ptr,"<="); break; + default: + error ("Invalid binary operation specified."); + } + argvec[0] = value_struct_elt (arg1, argvec+1, tstr, &static_memfuncp, "structure"); + if (argvec[0]) + { + if (static_memfuncp) + { + argvec[1] = argvec[0]; + argvec++; + } + return call_function (argvec[0], 2 - static_memfuncp, argvec + 1); + } + error ("member function %s not found", tstr); +} + +/* 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; + int 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 ("friend functions not implemented yet"); + + 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+9; + 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 call_function (argvec[0], 1 - static_memfuncp, argvec + 1); + } + error ("member function %s not found", tstr); +} + +/* 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); + *(double *) VALUE_CONTENTS (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 (arg2)) >= 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); + *(unsigned LONGEST *) VALUE_CONTENTS (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); + *(LONGEST *) VALUE_CONTENTS (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."); +} + +/* 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) + 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)) + return (char *) value_as_long (arg1) < (char *) value_as_long (arg2); + else + error ("Invalid type combination in ordering comparison."); +} + +/* 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."); +} + +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/gnu/usr.bin/gdb/valops.c b/gnu/usr.bin/gdb/valops.c new file mode 100644 index 0000000..ab5652c --- /dev/null +++ b/gnu/usr.bin/gdb/valops.c @@ -0,0 +1,1418 @@ +/*- + * This code is derived from software copyrighted by the Free Software + * Foundation. + * + * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. + * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory. + */ + +#ifndef lint +static char sccsid[] = "@(#)valops.c 6.4 (Berkeley) 5/8/91"; +#endif /* not lint */ + +/* Perform non-arithmetic operations on values, for GDB. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "stdio.h" +#include "defs.h" +#include "param.h" +#include "symtab.h" +#include "value.h" +#include "frame.h" +#include "inferior.h" + +/* 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. */ + +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))) + { + VALUE_TYPE (arg2) = type; + return arg2; + } + else if (VALUE_LVAL (arg2) == lval_memory) + { + return value_at (type, VALUE_ADDRESS (arg2) + VALUE_OFFSET (arg2)); + } + else + error ("Invalid cast."); +} + +/* 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 the value with a specified type located at specified address. */ + +value +value_at (type, addr) + struct type *type; + CORE_ADDR addr; +{ + register value val = allocate_value (type); + int temp; + + temp = read_memory (addr, VALUE_CONTENTS (val), TYPE_LENGTH (type)); + if (temp) + { + if (have_inferior_p () && !remote_debugging) + print_sys_errmsg ("ptrace", temp); + /* Actually, address between addr and addr + len was out of bounds. */ + error ("Cannot read memory: address 0x%x out of bounds.", addr); + } + + VALUE_LVAL (val) = lval_memory; + VALUE_ADDRESS (val) = addr; + + return val; +} + +/* 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; + + extern CORE_ADDR find_saved_register (); + + 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)); + REGISTER_CONVERT_TO_RAW (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 val; + read_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), + &val, sizeof val); + modify_field (&val, (int) value_as_long (fromval), + VALUE_BITPOS (toval), VALUE_BITSIZE (toval)); + write_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), + &val, sizeof val); + } + 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 val; + + read_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), + &val, sizeof val); + modify_field (&val, (int) value_as_long (fromval), + VALUE_BITPOS (toval), VALUE_BITSIZE (toval)); + write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), + &val, sizeof val); + } + 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; + CORE_ADDR addr; + + /* 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++) + { + addr = find_saved_register (frame, regno); + if (addr == 0) + read_register_bytes (REGISTER_BYTE (regno), + buffer + amount_copied, + reg_size); + else + read_memory (addr, buffer + amount_copied, reg_size); + } + + /* 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++) + { + addr = find_saved_register (frame, regno); + if (addr == 0) + write_register_bytes (REGISTER_BYTE (regno), + buffer + amount_copied, + reg_size); + else + write_memory (addr, buffer + amount_copied, reg_size); + } + } + 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 (val) - (char *) val); + bcopy (VALUE_CONTENTS (fromval), VALUE_CONTENTS (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 (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; +{ + return read_var_value (var, (FRAME) 0); +} + +/* 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; +} + +/* 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, arg1_coerced; + + /* Taking the address of an array is really a no-op + once the array is coerced to a pointer to its first element. */ + arg1_coerced = arg1; + COERCE_ARRAY (arg1_coerced); + if (arg1 != arg1_coerced) + return arg1_coerced; + + 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; +{ + /* Must do this before COERCE_ARRAY, otherwise an infinite loop + will result */ + if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_REF) + return value_at (TYPE_TARGET_TYPE (VALUE_TYPE (arg1)), + (CORE_ADDR) value_as_long (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 (TYPE_TARGET_TYPE (VALUE_TYPE (arg1)), + (CORE_ADDR) value_as_long (arg1)); + else if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_REF) + return value_at (TYPE_TARGET_TYPE (VALUE_TYPE (arg1)), + (CORE_ADDR) value_as_long (arg1)); + error ("Attempt to take contents of a non-pointer value."); +} + +/* 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, &buffer, len); +#else /* stack grows upward */ + write_memory (sp, &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)); +} + +#ifdef NEW_CALL_FUNCTION + +int +arg_stacklen(nargs, args) + int nargs; + value *args; +{ + int len = 0; + + while (--nargs >= 0) + len += TYPE_LENGTH(VALUE_TYPE(value_arg_coerce(args[nargs]))); + + return len; +} + +CORE_ADDR +function_address(function, type) + value function; + struct type **type; +{ + register CORE_ADDR funaddr; + register struct type *ftype = VALUE_TYPE(function); + register enum type_code code = TYPE_CODE(ftype); + + /* + * 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); + *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) + *type = TYPE_TARGET_TYPE(TYPE_TARGET_TYPE(ftype)); + else + *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); + + *type = builtin_type_int; + } else + error("Invalid data type for function to be called."); + + return funaddr; +} + +/* 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(function, nargs, args) + value function; + int nargs; + value *args; +{ + register CORE_ADDR sp, pc; + struct type *value_type; + struct inferior_status inf_status; + struct cleanup *old_chain; + register CORE_ADDR funaddr; + int struct_return_bytes; + char retbuf[REGISTER_BYTES]; + + if (!have_inferior_p()) + error("Cannot invoke functions if the inferior is not running."); + + save_inferior_status(&inf_status, 1); + old_chain = make_cleanup(restore_inferior_status, &inf_status); + + sp = read_register(SP_REGNUM); + funaddr = function_address(function, &value_type); + /* + * Are we returning a value using a structure return or a + * normal value return? + */ + if (using_struct_return(function, funaddr, value_type)) + struct_return_bytes = TYPE_LENGTH(value_type); + else + struct_return_bytes = 0; + /* + * Create a call sequence customized for this function and + * the number of arguments for it. + */ + pc = setup_dummy(sp, funaddr, nargs, args, + struct_return_bytes, value_arg_push); + + /* + * Execute the stack dummy stub. The register state will be + * returned in retbuf. It is restored below. + */ + run_stack_dummy(pc, retbuf); + + /* + * This will restore the register context that existed before + * we called the dummy function. + */ + do_cleanups(old_chain); + + return value_being_returned(value_type, retbuf, struct_return_bytes); +} +#else + +/* 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 (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; + + if (!have_inferior_p ()) + error ("Cannot invoke functions if the inferior is not running."); + + 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 + + { + register CORE_ADDR funaddr; + register struct type *ftype = VALUE_TYPE (function); + register enum type_code code = TYPE_CODE (ftype); + + /* 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."); + + /* Are we returning a value using a structure return or a normal + value return? */ + + struct_return = using_struct_return (function, funaddr, value_type); + + /* 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, value_type); + } + +#ifndef CANNOT_EXECUTE_STACK + write_memory (start_sp, dummy1, sizeof dummy); + +#else + /* Convex Unix prohibits executing in the stack segment. */ + /* Hope there is empty room at the top of the text segment. */ + { + extern CORE_ADDR text_end; + 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, dummy1, sizeof dummy); + } +#endif /* CANNOT_EXECUTE_STACK */ +#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 + } + + for (i = nargs - 1; i >= 0; i--) + sp = value_arg_push (sp, args[i]); + +#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 this + convention in a slightly twisted way also. */ + + if (struct_return) + STORE_STRUCT_RETURN (struct_addr, sp); + + /* Write the stack pointer. This is here because the statement above + might fool with it */ + 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); + } +} +#endif + +/* 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; +#ifdef KERNELDEBUG + extern int kernel_debugging; + + if (kernel_debugging) + error("Can't stuff string constants into kernel (yet)."); +#endif + + /* 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); + 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 i; + for (i = 0; i < misc_function_count; i++) + if (!strcmp (misc_function_vector[i].name, "malloc")) + break; + if (i < misc_function_count) + val = value_from_long (builtin_type_long, + (LONGEST) misc_function_vector[i].address); + else + error ("String constants require the program to have a function \"malloc\"."); + } + + blocklen = value_from_long (builtin_type_int, (LONGEST) (len + 1)); + val = 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; +} + +static int +type_field_index(t, name) + register struct type *t; + register char *name; +{ + register int i; + + for (i = TYPE_NFIELDS(t); --i >= 0;) + { + register char *t_field_name = TYPE_FIELD_NAME (t, i); + + if (t_field_name && !strcmp (t_field_name, name)) + break; + } + return (i); +} + +/* Given ARG1, 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 ARG1'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. + + ERR is an error message to be printed in case the field is not found. */ + +value +value_struct_elt (arg1, args, name, static_memfuncp, err) + register value arg1, *args; + char *name; + int *static_memfuncp; + char *err; +{ + register struct type *t; + register int i; + int found = 0; + + struct type *baseclass; + + COERCE_ARRAY (arg1); + + t = VALUE_TYPE (arg1); + + /* Check for the usual case: we have pointer, target type is a struct + * and `name' is a legal field of the struct. In this case, we can + * just snarf the value of the field & not waste time while value_ind + * sucks over the entire struct. */ + if (! args) + { + if (TYPE_CODE(t) == TYPE_CODE_PTR + && (TYPE_CODE((baseclass = TYPE_TARGET_TYPE(t))) == TYPE_CODE_STRUCT + || TYPE_CODE(baseclass) == TYPE_CODE_UNION) + && (i = type_field_index(baseclass, name)) >= 0) + { + register int offset; + register struct type *f = TYPE_FIELD_TYPE(baseclass, i); + + offset = TYPE_FIELD_BITPOS(baseclass, i) >> 3; + if (TYPE_FIELD_BITSIZE(baseclass, i) == 0) + return value_at(f, (CORE_ADDR)(value_as_long(arg1) + offset)); + } + } + + /* Follow pointers until we get to a non-pointer. */ + + while (TYPE_CODE (t) == TYPE_CODE_PTR || TYPE_CODE (t) == TYPE_CODE_REF) + { + arg1 = value_ind (arg1); + COERCE_ARRAY (arg1); + t = VALUE_TYPE (arg1); + } + + 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); + + baseclass = t; + + /* 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. */ + while (t) + { + i = type_field_index(t, name); + if (i >= 0) + return TYPE_FIELD_STATIC (t, i) + ? value_static_field (t, name, i) : value_field (arg1, i); + + if (TYPE_N_BASECLASSES (t) == 0) + break; + + t = TYPE_BASECLASS (t, 1); + VALUE_TYPE (arg1) = t; /* side effect! */ + } + + /* C++: If it was not found as a data field, then try to + return it as a pointer to a method. */ + t = baseclass; + VALUE_TYPE (arg1) = t; /* side effect! */ + + if (destructor_name_p (name, t)) + error ("use `info method' command to print out value of destructor"); + + while (t) + { + for (i = TYPE_NFN_FIELDS (t) - 1; i >= 0; --i) + { + if (! strcmp (TYPE_FN_FIELDLIST_NAME (t, i), name)) + { + error ("use `info method' command to print value of method \"%s\"", name); + } + } + + if (TYPE_N_BASECLASSES (t) == 0) + break; + + t = TYPE_BASECLASS (t, 1); + } + + error ("There is no field named %s.", name); + return 0; + } + + if (destructor_name_p (name, t)) + { + if (!args[1]) + { + /* destructors are a special case. */ + return (value)value_fn_field (arg1, 0, + TYPE_FN_FIELDLIST_LENGTH (t, 0)); + } + else + { + error ("destructor should not have any argument"); + } + } + + /* This following loop is for methods with arguments. */ + while (t) + { + /* Look up as method first, because that is where we + expect to find it first. */ + for (i = TYPE_NFN_FIELDS (t) - 1; i >= 0; i--) + { + struct fn_field *f = TYPE_FN_FIELDLIST1 (t, i); + + if (!strcmp (TYPE_FN_FIELDLIST_NAME (t, i), name)) + { + int j; + struct fn_field *f = TYPE_FN_FIELDLIST1 (t, i); + + found = 1; + for (j = TYPE_FN_FIELDLIST_LENGTH (t, i) - 1; j >= 0; --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, t); + if (TYPE_FN_FIELD_STATIC_P (f, j) && static_memfuncp) + *static_memfuncp = 1; + return (value)value_fn_field (arg1, i, j); + } + } + } + + if (TYPE_N_BASECLASSES (t) == 0) + break; + + t = TYPE_BASECLASS (t, 1); + VALUE_TYPE (arg1) = t; /* side effect! */ + } + + if (found) + { + error ("Structure method %s not defined for arglist.", name); + return 0; + } + else + { + /* See if user tried to invoke data as function */ + t = baseclass; + while (t) + { + i = type_field_index(t, name); + if (i >= 0) + return TYPE_FIELD_STATIC (t, i) + ? value_static_field (t, name, i) : value_field (arg1, i); + + if (TYPE_N_BASECLASSES (t) == 0) + break; + + t = TYPE_BASECLASS (t, 1); + VALUE_TYPE (arg1) = t; /* side effect! */ + } + error ("Structure has no component named %s.", name); + } +} + +/* 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. */ + char *dname = TYPE_NAME (type); + + if (name[0] == '~') + { + if (! TYPE_HAS_DESTRUCTOR (type)) + error ("type `%s' does not have destructor defined", + TYPE_NAME (type)); + /* Skip past the "struct " at the front. */ + while (*dname++ != ' ') ; + if (strcmp (dname, name+1)) + error ("destructor specification error"); + else + 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; + register int i; + int found = 0; + + struct type *baseclass; + + 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"); + + baseclass = t; + + while (t) + { + for (i = TYPE_NFIELDS (t) - 1; i >= 0; i--) + { + char *t_field_name = TYPE_FIELD_NAME (t, i); + if (t_field_name && !strcmp (t_field_name, name)) + goto success; + } + if (TYPE_N_BASECLASSES (t) == 0) + break; + + t = TYPE_BASECLASS (t, 1); + VALUE_TYPE (arg1) = t; /* side effect! */ + } + + /* 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)) + goto success; + + while (t) + { + for (i = TYPE_NFN_FIELDS (t) - 1; i >= 0; --i) + { + if (!strcmp (TYPE_FN_FIELDLIST_NAME (t, i), name)) + return 1; + } + + if (TYPE_N_BASECLASSES (t) == 0) + break; + + t = TYPE_BASECLASS (t, 1); + } + return 0; + + success: + t = VALUE_TYPE (arg1); + while (TYPE_CODE (t) == TYPE_CODE_PTR || TYPE_CODE (t) == TYPE_CODE_REF) + { + arg1 = value_ind (arg1); + COERCE_ARRAY (arg1); + t = VALUE_TYPE (arg1); + } +} + +/* 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; + int found = 0; + 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 >= 0; i--) + { + char *t_field_name = TYPE_FIELD_NAME (t, i); + if (t_field_name && !strcmp (t_field_name, name)) + { + 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, 1); + } + + /* 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); + 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, 1); + } + 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? */ + +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 + || 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; + char *funname = 0; + struct block *b; + int i; + + if (selected_frame == 0) + if (complain) + error ("no frame selected"); + else return 0; + + func = get_frame_function (selected_frame); + if (func) + funname = SYMBOL_NAME (func); + else + 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; + + sym = BLOCK_SYM (b, 0); + if (strncmp ("$this", SYMBOL_NAME (sym), 5)) + if (complain) + error ("current stack frame not in method"); + else return 0; + + return read_var_value (sym, selected_frame); +} diff --git a/gnu/usr.bin/gdb/valprint.c b/gnu/usr.bin/gdb/valprint.c new file mode 100644 index 0000000..781eb29 --- /dev/null +++ b/gnu/usr.bin/gdb/valprint.c @@ -0,0 +1,1430 @@ +/*- + * This code is derived from software copyrighted by the Free Software + * Foundation. + * + * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. + * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory. + */ + +#ifndef lint +static char sccsid[] = "@(#)valprint.c 6.5 (Berkeley) 5/8/91"; +#endif /* not lint */ + +/* Print values for GNU debugger gdb. + Copyright (C) 1986, 1988, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <stdio.h> +#include "defs.h" +#include "param.h" +#include "symtab.h" +#include "value.h" + +/* GNU software is only expected to run on systems with 32-bit integers. */ +#define UINT_MAX 0xffffffff + +/* 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 (); + + +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; + + 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 repititions 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) + { + fputs_filtered ("\", ", stream); + in_quotes = 0; + } + fputs_filtered ("'", stream); + printchar (string[i], stream, '\''); + fprintf_filtered (stream, "' <repeats %u times>", reps); + i = rep1 - 1; + things_printed += REPEAT_COUNT_THRESHOLD; + need_comma = 1; + } + else + { + if (!in_quotes) + { + fputs_filtered ("\"", stream); + in_quotes = 1; + } + printchar (string[i], stream, '"'); + ++things_printed; + } + } + + /* Terminate the quotes if necessary. */ + if (in_quotes) + fputs_filtered ("\"", stream); + + if (force_ellipses || i < length) + fputs_filtered ("...", stream); +} + +/* 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; + + /* A "repeated" value really contains several values in a row. + They are made by the @ operator. + Print such values as if they were arrays. */ + + 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 repititions we have detected so far. */ + unsigned int reps; + + if (i != 0) + fprintf_filtered (stream, ", "); + + rep1 = i + 1; + reps = 1; + while (rep1 < n + && !bcmp (VALUE_CONTENTS (val) + typelen * i, + VALUE_CONTENTS (val) + typelen * rep1, typelen)) + { + ++reps; + ++rep1; + } + + if (reps > REPEAT_COUNT_THRESHOLD) + { + val_print (VALUE_TYPE (val), + VALUE_CONTENTS (val) + typelen * i, + VALUE_ADDRESS (val) + typelen * i, + stream, format, 1, 0, pretty); + fprintf (stream, " <repeats %u times>", reps); + i = rep1 - 1; + things_printed += REPEAT_COUNT_THRESHOLD; + } + else + { + val_print (VALUE_TYPE (val), + VALUE_CONTENTS (val) + typelen * i, + VALUE_ADDRESS (val) + typelen * i, + stream, format, 1, 0, pretty); + things_printed++; + } + } + if (i < n) + fprintf_filtered (stream, "..."); + } + fprintf_filtered (stream, "}"); + return n * typelen; + } + else + { + /* If it is a pointer, indicate what it points to. + + Print type also if it is a reference. + + C++: if it is a member pointer, we will take care + of that when we print it. */ + if (TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_PTR + || TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_REF) + { + fprintf_filtered (stream, "("); + type_print (VALUE_TYPE (val), "", stream, -1); + fprintf_filtered (stream, ") "); + + /* If this is a function pointer, try to print what + function it is pointing to by name. */ + if (TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (val))) + == TYPE_CODE_FUNC) + { + print_address (((int *) VALUE_CONTENTS (val))[0], stream); + /* Return value is irrelevant except for string pointers. */ + return 0; + } + } + return val_print (VALUE_TYPE (val), VALUE_CONTENTS (val), + VALUE_ADDRESS (val), stream, format, 1, 0, pretty); + } +} + +static int prettyprint; /* Controls prettyprinting of structures. */ +int unionprint; /* Controls printing of nested unions. */ +static void scalar_print_hack(); +void (*default_scalar_print)() = scalar_print_hack; + +/* 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). + + 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; + int len, n_baseclasses; + struct type *elttype; + int eltlen; + LONGEST val; + unsigned char c; + + if (pretty == Val_pretty_default) + { + pretty = prettyprint ? Val_prettyprint : Val_no_prettyprint; + } + + QUIT; + + if (TYPE_FLAGS (type) & TYPE_FLAG_STUB) + { + fprintf_filtered (stream, "<Type not defined in this context>"); + 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; + fprintf_filtered (stream, "{"); + /* For an array of chars, print with string syntax. */ + if (eltlen == 1 && TYPE_CODE (elttype) == TYPE_CODE_INT + && format == 0) + 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 repititions we have detected so far. */ + unsigned int reps; + + if (i > 0) + fprintf_filtered (stream, ", "); + + rep1 = i + 1; + reps = 1; + while (rep1 < len + && !bcmp (valaddr + i * eltlen, + valaddr + rep1 * eltlen, eltlen)) + { + ++reps; + ++rep1; + } + + if (reps > REPEAT_COUNT_THRESHOLD) + { + val_print (elttype, valaddr + i * eltlen, + 0, stream, format, deref_ref, + recurse + 1, pretty); + fprintf_filtered (stream, " <repeats %u times>", reps); + i = rep1 - 1; + things_printed += REPEAT_COUNT_THRESHOLD; + } + else + { + val_print (elttype, valaddr + i * eltlen, + 0, stream, format, deref_ref, + recurse + 1, pretty); + things_printed++; + } + } + if (i < len) + fprintf_filtered (stream, "..."); + } + fprintf_filtered (stream, "}"); + break; + } + /* Array of unspecified length: treat like pointer to first elt. */ + valaddr = (char *) &address; + + case TYPE_CODE_PTR: + if (format) + { + 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 type *target = TYPE_TARGET_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] == '$') + 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)); + struct type *target = TYPE_TARGET_TYPE (TYPE_TARGET_TYPE (type)); + char *kind = ""; + + /* 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 = 0; i < len; i++) + { + int bitpos = TYPE_FIELD_BITPOS (domain, i); + QUIT; + if (val == bitpos) + break; + if (val < bitpos && i > 0) + { + int ptrsize = (TYPE_LENGTH (builtin_type_char) * TYPE_LENGTH (target)); + /* 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 + { + fprintf_filtered (stream, "0x%x", * (int *) valaddr); + /* For a pointer to char or unsigned char, + also print the string pointed to, unless pointer is null. */ + + /* For an array of chars, print with string syntax. */ + elttype = TYPE_TARGET_TYPE (type); + i = 0; /* Number of characters printed. */ + if (TYPE_LENGTH (elttype) == 1 + && TYPE_CODE (elttype) == TYPE_CODE_INT + && format == 0 + && unpack_long (type, valaddr) != 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) + { + fprintf_filtered (stream, " "); + + /* Get first character. */ + if (read_memory ( (CORE_ADDR) unpack_long (type, valaddr), + &c, 1)) + { + /* First address out of bounds. */ + fprintf_filtered (stream, "<Address 0x%x out of bounds>", + (* (int *) valaddr)); + break; + } + else + { + /* A real string. */ + int out_of_bounds = 0; + 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 only fetches print_max characters, even + though print_string might want to print more + (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. */ + while (i < print_max) + { + QUIT; + if (read_memory ((CORE_ADDR) unpack_long (type, valaddr) + + i, &c, 1)) + { + out_of_bounds = 1; + force_ellipses = 0; + break; + } + else if (c == '\0') + { + force_ellipses = 0; + break; + } + else + string[i++] = c; + } + + if (i != 0) + print_string (stream, string, i, force_ellipses); + if (out_of_bounds) + fprintf_filtered (stream, + " <Address 0x%x out of bounds>", + (*(int *) valaddr) + i); + } + + fflush (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: + fprintf_filtered (stream, "(0x%x &) = ", * (int *) valaddr); + /* 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), * (int *) valaddr); + val_print (VALUE_TYPE (val), VALUE_CONTENTS (val), + VALUE_ADDRESS (val), stream, format, + deref_ref, recurse + 1, pretty); + } + else + fprintf_filtered (stream, "???"); + } + break; + + case TYPE_CODE_UNION: + if (recurse && !unionprint) + { + fprintf_filtered (stream, "{...}"); + break; + } + /* Fall through. */ + case TYPE_CODE_STRUCT: + fprintf_filtered (stream, "{"); + len = TYPE_NFIELDS (type); + n_baseclasses = TYPE_N_BASECLASSES (type); + for (i = 1; i <= n_baseclasses; i++) + { + fprintf_filtered (stream, "\n"); + if (pretty) + print_spaces_filtered (2 + 2 * recurse, stream); + fputs_filtered ("<", stream); + fputs_filtered (TYPE_NAME (TYPE_BASECLASS (type, i)), stream); + fputs_filtered ("> = ", stream); + val_print (TYPE_FIELD_TYPE (type, 0), + valaddr + TYPE_FIELD_BITPOS (type, i-1) / 8, + 0, stream, 0, 0, recurse + 1, pretty); + } + if (i > 1) { + fprintf_filtered (stream, "\n"); + print_spaces_filtered (2 + 2 * recurse, stream); + fputs_filtered ("members of ", stream); + fputs_filtered (TYPE_NAME (type), stream); + fputs_filtered (": ", stream); + } + if (!len && i == 1) + fprintf_filtered (stream, "<No data fields>"); + else + { + for (i -= 1; i < len; i++) + { + if (i > n_baseclasses) fprintf_filtered (stream, ", "); + if (pretty) + { + fprintf_filtered (stream, "\n"); + print_spaces_filtered (2 + 2 * recurse, stream); + } + fputs_filtered (TYPE_FIELD_NAME (type, i), stream); + fputs_filtered (" = ", stream); + /* check if static field */ + if (TYPE_FIELD_STATIC (type, i)) + { + value v; + + v = value_static_field (type, TYPE_FIELD_NAME (type, i), i); + val_print (TYPE_FIELD_TYPE (type, i), + VALUE_CONTENTS (v), 0, stream, format, + deref_ref, recurse + 1, pretty); + } + else if (TYPE_FIELD_PACKED (type, i)) + { + char *valp = (char *) & val; + union {int i; char c;} test; + test.i = 1; + if (test.c != 1) + valp += sizeof val - TYPE_LENGTH (TYPE_FIELD_TYPE (type, i)); + val = unpack_field_as_long (type, valaddr, i); + val_print (TYPE_FIELD_TYPE (type, i), valp, 0, + stream, format, deref_ref, recurse + 1, pretty); + } + else + { + val_print (TYPE_FIELD_TYPE (type, i), + valaddr + TYPE_FIELD_BITPOS (type, i) / 8, + 0, stream, format, deref_ref, + recurse + 1, pretty); + } + } + if (pretty) + { + fprintf_filtered (stream, "\n"); + print_spaces_filtered (2 * recurse, stream); + } + } + fprintf_filtered (stream, "}"); + 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, "} "); + fprintf_filtered (stream, "0x%x", address); + break; + + case TYPE_CODE_INT: + if (format) + print_scalar_formatted (valaddr, type, format, 0, stream); + else + { + (*default_scalar_print)(stream, type, unpack_long(type, valaddr)); +#ifdef notdef + if (TYPE_LENGTH (type) == 1) + { + fprintf_filtered (stream, " '"); + printchar ((unsigned char) unpack_long (type, valaddr), + stream, '\''); + fprintf_filtered (stream, "'"); + } +#endif + } + 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; + + 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. + 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_filtered (varstring, stream); + 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_filtered (prefix, stream); + fputs_filtered (varstring, stream); + 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 == 1) + { + basetype = TYPE_BASECLASS (type, 1); + if (TYPE_NAME (basetype) && (name = TYPE_NAME (basetype))) + { + while (*name != ' ') name++; + fprintf_filtered (stream, ": %s%s ", + TYPE_VIA_PUBLIC (basetype) ? "public" : "private", + TYPE_VIA_VIRTUAL (basetype) ? " virtual" : ""); + fputs_filtered (name + 1, stream); + fputs_filtered (" ", stream); + } + n_baseclasses = TYPE_N_BASECLASSES (basetype); + type = basetype; + } + + if (type) + { + if (n_baseclasses != 0) + fprintf_filtered (stream, ": "); + for (i = 1; i <= n_baseclasses; i++) + { + basetype = TYPE_BASECLASS (type, i); + if (TYPE_NAME (basetype) && (name = TYPE_NAME (basetype))) + { + while (*name != ' ') name++; + fprintf_filtered (stream, "%s%s ", + TYPE_VIA_PUBLIC (basetype) ? "public" : "private", + TYPE_VIA_VIRTUAL (basetype) ? " virtual" : ""); + fputs_filtered (name + 1, stream); + } + if (i < n_baseclasses) + fprintf_filtered (stream, ", "); + } + fprintf_filtered (stream, " "); + } +} + +/* 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, "("); + } +} + +/* 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; + } +} + +/* 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 (TYPE_NAME (type) && (name = TYPE_NAME (type))) + { + while (*name != ' ') name++; + fputs_filtered (name + 1, stream); + fputs_filtered (" ", stream); + } + if (show < 0) + fprintf_filtered (stream, "{...}"); + else + { + int i; + + type_print_derivation_info (stream, type); + + fprintf_filtered (stream, "{"); + len = TYPE_NFIELDS (type); + if (len) + fprintf_filtered (stream, "\n"); + else + { + if (TYPE_FLAGS (type) & TYPE_FLAG_STUB) + fprintf_filtered (stream, "<incomplete type>\n"); + else + fprintf_filtered (stream, "<no data fields>\n"); + } + + /* If there is a base class for this type, + do not print the field that it occupies. */ + for (i = TYPE_N_BASECLASSES (type); i < len; i++) + { + QUIT; + /* Don't print out virtual function table. */ + if (! strncmp (TYPE_FIELD_NAME (type, i), + "_vptr$", 6)) + 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_FN_FIELD_PHYSNAME (f, j)[0] == '_' + && TYPE_FN_FIELD_PHYSNAME (f, j)[1] == '$') + 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"); + } + if (len2) fprintf_filtered (stream, "\n"); + } + + print_spaces_filtered (level, stream); + fprintf_filtered (stream, "}"); + } + break; + + case TYPE_CODE_ENUM: + fprintf_filtered (stream, "enum "); + if (TYPE_NAME (type)) + { + name = TYPE_NAME (type); + while (*name != ' ') name++; + fputs_filtered (name + 1, 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_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; + + default: + error ("Invalid type code in symbol table."); + } +} + +static void +scalar_print_decimal(stream, type, val) + FILE *stream; + struct type *type; + LONGEST val; +{ + fprintf_filtered(stream, TYPE_UNSIGNED(type)? "%lu":"%ld", val); +} + +static void +scalar_print_hex(stream, type, val) + FILE *stream; + struct type *type; + LONGEST val; +{ + switch (TYPE_LENGTH(type)) { + case 1: + fprintf_filtered (stream, "0x%02lx", val); + break; + case 2: + fprintf_filtered (stream, "0x%04lx", val); + break; + case 4: + fprintf_filtered (stream, "0x%08lx", val); + break; + default: + fprintf_filtered (stream, "0x%lx", val); + break; + } +} + +static void +scalar_print_octal(stream, type, val) + FILE *stream; + struct type *type; + LONGEST val; +{ + switch (TYPE_LENGTH(type)) { + case 1: + fprintf_filtered (stream, "0%03lo", val); + break; + case 2: + fprintf_filtered (stream, "0%06lo", val); + break; + case 4: + fprintf_filtered (stream, "0%012lo", val); + break; + default: + fprintf_filtered (stream, "0%lo", val); + break; + } +} + +static void +scalar_print_hack(stream, type, val) + FILE *stream; + struct type *type; + LONGEST val; +{ + if (TYPE_UNSIGNED(type)) + scalar_print_hex(stream, type, val); + else + scalar_print_decimal(stream, type, val); +} + +static void +set_maximum_command (arg) + char *arg; +{ + if (!arg) error_no_arg ("value for maximum elements to print"); + print_max = parse_and_eval_address (arg); + if (print_max == 0) + print_max = UINT_MAX; +} + +static void +set_base_command(arg) + char *arg; +{ + int base; + + if (!arg) + base = 0; + else + base = parse_and_eval_address (arg); + switch (base) { + default: + default_scalar_print = scalar_print_hack; + break; + case 8: + default_scalar_print = scalar_print_octal; + break; + case 10: + default_scalar_print = scalar_print_decimal; + break; + case 16: + default_scalar_print = scalar_print_hex; + break; + } +} + +static void +set_prettyprint_command (arg, from_tty) + char *arg; + int from_tty; +{ + prettyprint = parse_binary_operation ("set prettyprint", arg); +} + +static void +set_unionprint_command (arg, from_tty) + char *arg; + int from_tty; +{ + unionprint = parse_binary_operation ("set unionprint", arg); +} + +format_info (arg, from_tty) + char *arg; + int from_tty; +{ + if (arg) + error ("\"info format\" does not take any arguments."); + printf ("Prettyprinting of structures is %s.\n", + prettyprint ? "on" : "off"); + printf ("Printing of unions interior to structures is %s.\n", + unionprint ? "on" : "off"); + if (print_max == UINT_MAX) + printf_filtered + ("There is no maximum number of array elements printed.\n"); + else + printf_filtered + ("The maximum number of array elements printed is %d.\n", print_max); +} + +extern struct cmd_list_element *setlist; + +void +_initialize_valprint () +{ + add_cmd ("base", class_support, set_base_command, + "Change default integer print radix to 8, 10 or 16\n\ +No args returns to the ad-hoc default of `16' for unsigned values\n\ +and `10' otherwise.", + &setlist); + add_cmd ("array-max", class_vars, set_maximum_command, + "Set NUMBER as limit on string chars or array elements to print.\n\ +\"set array-max 0\" causes there to be no limit.", + &setlist); + + add_cmd ("prettyprint", class_support, set_prettyprint_command, + "Turn prettyprinting of structures on and off.", + &setlist); + add_alias_cmd ("pp", "prettyprint", class_support, 1, &setlist); + + add_cmd ("unionprint", class_support, set_unionprint_command, + "Turn printing of unions interior to structures on and off.", + &setlist); + + add_info ("format", format_info, + "Show current settings of data formatting options."); + + /* Give people the defaults which they are used to. */ + prettyprint = 0; + unionprint = 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"; +} + diff --git a/gnu/usr.bin/gdb/value.h b/gnu/usr.bin/gdb/value.h new file mode 100644 index 0000000..07dd8e8 --- /dev/null +++ b/gnu/usr.bin/gdb/value.h @@ -0,0 +1,212 @@ +/* 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. */ + +/* + * 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; + /* Actual contents of the value. For use of this value; setting + it uses the stuff above. */ + long contents[1]; + }; + +typedef struct value *value; + +#define VALUE_TYPE(val) (val)->type +#define VALUE_CONTENTS(val) ((char *) (val)->contents) +#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 + +/* If ARG is an array, convert it to a pointer. + If ARG is an enum, convert it to an integer. + + References are dereferenced. */ + +#define COERCE_ARRAY(arg) \ +{ if (TYPE_CODE ( VALUE_TYPE (arg)) == TYPE_CODE_REF) \ + arg = value_ind (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_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; +}; + +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_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_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 value_cast (); +value value_zero (); +value value_repeat (); +value value_subscript (); + +value call_function (); +value value_being_returned (); +int using_struct_return (); + +value evaluate_expression (); +value evaluate_type (); +value parse_and_eval (); +value parse_to_comma_and_eval (); + +value access_value_history (); +value value_of_internalvar (); +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 (); +int binop_user_defined_p (); +int unop_user_defined_p (); + +void read_register_bytes (); +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 + }; + diff --git a/gnu/usr.bin/gdb/values.c b/gnu/usr.bin/gdb/values.c new file mode 100644 index 0000000..93a2911 --- /dev/null +++ b/gnu/usr.bin/gdb/values.c @@ -0,0 +1,1059 @@ +/*- + * This code is derived from software copyrighted by the Free Software + * Foundation. + * + * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. + * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory. + */ + +#ifndef lint +static char sccsid[] = "@(#)values.c 6.3 (Berkeley) 5/8/91"; +#endif /* not lint */ + +/* Low level packing and unpacking of values for GDB. + Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <stdio.h> +#include "defs.h" +#include "param.h" +#include "symtab.h" +#include "value.h" + +/* The value-history records all the values printed + by print commands during this session. Each chunk + records 60 consecutive values. The first chunk on + the chain records the most recent values. + The total number of values is in value_history_count. */ + +#define VALUE_HISTORY_CHUNK 60 + +struct value_history_chunk +{ + struct value_history_chunk *next; + value values[VALUE_HISTORY_CHUNK]; +}; + +/* Chain of chunks now in use. */ + +static struct value_history_chunk *value_history_chain; + +static int value_history_count; /* Abs number of last entry stored */ + + +/* List of all value objects currently allocated + (except for those released by calls to release_value) + This is so they can be freed after each command. */ + +static value all_values; + +/* Allocate a value that has the correct length for type TYPE. */ + +value +allocate_value (type) + struct type *type; +{ + register value val; + + /* If the type we want had no definition in the file it first + * appeared in, it will be marked a `stub'. The real definition + * probably appeared later so try to find it. */ + if (TYPE_FLAGS(type) & TYPE_FLAG_STUB) + { + register char *cp; + register struct symbol *sym; + extern char *index(); + + if (cp = index(TYPE_NAME(type), ' ')) + ++cp; + else + cp = TYPE_NAME(type); + + sym = lookup_symbol(cp, 0, STRUCT_NAMESPACE, 0); + + if (sym && TYPE_CODE(SYMBOL_TYPE(sym)) == TYPE_CODE(type)) + bcopy (SYMBOL_TYPE (sym), type, sizeof (*type)); + } + val = (value) xmalloc (sizeof (struct value) + TYPE_LENGTH (type)); + VALUE_NEXT (val) = all_values; + all_values = val; + VALUE_TYPE (val) = type; + VALUE_LVAL (val) = not_lval; + VALUE_ADDRESS (val) = 0; + VALUE_FRAME (val) = 0; + VALUE_OFFSET (val) = 0; + VALUE_BITPOS (val) = 0; + VALUE_BITSIZE (val) = 0; + VALUE_REPEATED (val) = 0; + VALUE_REPETITIONS (val) = 0; + VALUE_REGNO (val) = -1; + return val; +} + +/* Allocate a value that has the correct length + for COUNT repetitions type TYPE. */ + +value +allocate_repeat_value (type, count) + struct type *type; + int count; +{ + register value val; + + val = (value) xmalloc (sizeof (struct value) + TYPE_LENGTH (type) * count); + VALUE_NEXT (val) = all_values; + all_values = val; + VALUE_TYPE (val) = type; + VALUE_LVAL (val) = not_lval; + VALUE_ADDRESS (val) = 0; + VALUE_FRAME (val) = 0; + VALUE_OFFSET (val) = 0; + VALUE_BITPOS (val) = 0; + VALUE_BITSIZE (val) = 0; + VALUE_REPEATED (val) = 1; + VALUE_REPETITIONS (val) = count; + VALUE_REGNO (val) = -1; + return val; +} + +/* Free all the values that have been allocated (except for those released). + Called after each command, successful or not. */ + +void +free_all_values () +{ + register value val, next; + + for (val = all_values; val; val = next) + { + next = VALUE_NEXT (val); + free (val); + } + + all_values = 0; +} + +/* Remove VAL from the chain all_values + so it will not be freed automatically. */ + +void +release_value (val) + register value val; +{ + register value v; + + if (all_values == val) + { + all_values = val->next; + return; + } + + for (v = all_values; v; v = v->next) + { + if (v->next == val) + { + v->next = val->next; + break; + } + } +} + +/* Return a copy of the value ARG. + It contains the same contents, for same memory address, + but it's a different block of storage. */ + +static value +value_copy (arg) + value arg; +{ + register value val; + register struct type *type = VALUE_TYPE (arg); + if (VALUE_REPEATED (arg)) + val = allocate_repeat_value (type, VALUE_REPETITIONS (arg)); + else + val = allocate_value (type); + VALUE_LVAL (val) = VALUE_LVAL (arg); + VALUE_ADDRESS (val) = VALUE_ADDRESS (arg); + VALUE_OFFSET (val) = VALUE_OFFSET (arg); + VALUE_BITPOS (val) = VALUE_BITPOS (arg); + VALUE_BITSIZE (val) = VALUE_BITSIZE (arg); + VALUE_REGNO (val) = VALUE_REGNO (arg); + bcopy (VALUE_CONTENTS (arg), VALUE_CONTENTS (val), + TYPE_LENGTH (VALUE_TYPE (arg)) + * (VALUE_REPEATED (arg) ? VALUE_REPETITIONS (arg) : 1)); + return val; +} + +/* Access to the value history. */ + +/* Record a new value in the value history. + Returns the absolute history index of the entry. */ + +int +record_latest_value (val) + value val; +{ + int i; + double foo; + + /* Check error now if about to store an invalid float. We return -1 + to the caller, but allow them to continue, e.g. to print it as "Nan". */ + if (TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_FLT) { + foo = unpack_double (VALUE_TYPE (val), VALUE_CONTENTS (val), &i); + if (i) return -1; /* Indicate value not saved in history */ + } + + /* Here we treat value_history_count as origin-zero + and applying to the value being stored now. */ + + i = value_history_count % VALUE_HISTORY_CHUNK; + if (i == 0) + { + register struct value_history_chunk *new + = (struct value_history_chunk *) + xmalloc (sizeof (struct value_history_chunk)); + bzero (new->values, sizeof new->values); + new->next = value_history_chain; + value_history_chain = new; + } + + value_history_chain->values[i] = val; + release_value (val); + + /* Now we regard value_history_count as origin-one + and applying to the value just stored. */ + + return ++value_history_count; +} + +/* Return a copy of the value in the history with sequence number NUM. */ + +value +access_value_history (num) + int num; +{ + register struct value_history_chunk *chunk; + register int i; + register int absnum = num; + + if (absnum <= 0) + absnum += value_history_count; + + if (absnum <= 0) + { + if (num == 0) + error ("The history is empty."); + else if (num == 1) + error ("There is only one value in the history."); + else + error ("History does not go back to $$%d.", -num); + } + if (absnum > value_history_count) + error ("History has not yet reached $%d.", absnum); + + absnum--; + + /* Now absnum is always absolute and origin zero. */ + + chunk = value_history_chain; + for (i = (value_history_count - 1) / VALUE_HISTORY_CHUNK - absnum / VALUE_HISTORY_CHUNK; + i > 0; i--) + chunk = chunk->next; + + return value_copy (chunk->values[absnum % VALUE_HISTORY_CHUNK]); +} + +/* Clear the value history entirely. + Must be done when new symbol tables are loaded, + because the type pointers become invalid. */ + +void +clear_value_history () +{ + register struct value_history_chunk *next; + register int i; + register value val; + + while (value_history_chain) + { + for (i = 0; i < VALUE_HISTORY_CHUNK; i++) + if (val = value_history_chain->values[i]) + free (val); + next = value_history_chain->next; + free (value_history_chain); + value_history_chain = next; + } + value_history_count = 0; +} + +static void +value_history_info (num_exp, from_tty) + char *num_exp; + int from_tty; +{ + register int i; + register value val; + static int num = 1; + + if (num_exp) + { + if (num_exp[0] == '+' && num_exp[1] == '\0') + /* "info history +" should print from the stored position. */ + ; + else + /* "info history <exp>" should print around value number <exp>. */ + num = parse_and_eval_address (num_exp) - 5; + } + else + { + /* "info history" means print the last 10 values. */ + num = value_history_count - 9; + } + + if (num <= 0) + num = 1; + + for (i = num; i < num + 10 && i <= value_history_count; i++) + { + val = access_value_history (i); + printf_filtered ("$%d = ", i); + value_print (val, stdout, 0, Val_pretty_default); + printf_filtered ("\n"); + } + + /* The next "info history +" should start after what we just printed. */ + num += 10; + + /* Hitting just return after this command should do the same thing as + "info history +". If num_exp is null, this is unnecessary, since + "info history +" is not useful after "info history". */ + if (from_tty && num_exp) + { + num_exp[0] = '+'; + num_exp[1] = '\0'; + } +} + +/* Internal variables. These are variables within the debugger + that hold values assigned by debugger commands. + The user refers to them with a '$' prefix + that does not appear in the variable names stored internally. */ + +static struct internalvar *internalvars; + +/* Look up an internal variable with name NAME. NAME should not + normally include a dollar sign. + + If the specified internal variable does not exist, + one is created, with a void value. */ + +struct internalvar * +lookup_internalvar (name) + char *name; +{ + register struct internalvar *var; + + for (var = internalvars; var; var = var->next) + if (!strcmp (var->name, name)) + return var; + + var = (struct internalvar *) xmalloc (sizeof (struct internalvar)); + var->name = concat (name, "", ""); + var->value = allocate_value (builtin_type_void); + release_value (var->value); + var->next = internalvars; + internalvars = var; + return var; +} + +value +value_of_internalvar (var) + struct internalvar *var; +{ + register value val; + +#ifdef IS_TRAPPED_INTERNALVAR + if (IS_TRAPPED_INTERNALVAR (var->name)) + return VALUE_OF_TRAPPED_INTERNALVAR (var); +#endif + + val = value_copy (var->value); + VALUE_LVAL (val) = lval_internalvar; + VALUE_INTERNALVAR (val) = var; + return val; +} + +void +set_internalvar_component (var, offset, bitpos, bitsize, newval) + struct internalvar *var; + int offset, bitpos, bitsize; + value newval; +{ + register char *addr = VALUE_CONTENTS (var->value) + offset; + +#ifdef IS_TRAPPED_INTERNALVAR + if (IS_TRAPPED_INTERNALVAR (var->name)) + SET_TRAPPED_INTERNALVAR (var, newval, bitpos, bitsize, offset); +#endif + + if (bitsize) + modify_field (addr, (int) value_as_long (newval), + bitpos, bitsize); + else + bcopy (VALUE_CONTENTS (newval), addr, + TYPE_LENGTH (VALUE_TYPE (newval))); +} + +void +set_internalvar (var, val) + struct internalvar *var; + value val; +{ +#ifdef IS_TRAPPED_INTERNALVAR + if (IS_TRAPPED_INTERNALVAR (var->name)) + SET_TRAPPED_INTERNALVAR (var, val, 0, 0, 0); +#endif + + free (var->value); + var->value = value_copy (val); + release_value (var->value); +} + +char * +internalvar_name (var) + struct internalvar *var; +{ + return var->name; +} + +/* Free all internalvars. Done when new symtabs are loaded, + because that makes the values invalid. */ + +void +clear_internalvars () +{ + register struct internalvar *var; + + while (internalvars) + { + var = internalvars; + internalvars = var->next; + free (var->name); + free (var->value); + free (var); + } +} + +static void +convenience_info () +{ + register struct internalvar *var; + int varseen = 0; + + for (var = internalvars; var; var = var->next) + { +#ifdef IS_TRAPPED_INTERNALVAR + if (IS_TRAPPED_INTERNALVAR (var->name)) + continue; +#endif + if (!varseen) + { + printf ("Debugger convenience variables:\n\n"); + varseen = 1; + } + printf ("$%s: ", var->name); + value_print (var->value, stdout, 0, Val_pretty_default); + printf ("\n"); + } + if (!varseen) + printf ("No debugger convenience variables now defined.\n\ +Convenience variables have names starting with \"$\";\n\ +use \"set\" as in \"set $foo = 5\" to define them.\n"); +} + +/* Extract a value as a C number (either long or double). + Knows how to convert fixed values to double, or + floating values to long. + Does not deallocate the value. */ + +LONGEST +value_as_long (val) + register value val; +{ + return unpack_long (VALUE_TYPE (val), VALUE_CONTENTS (val)); +} + +double +value_as_double (val) + register value val; +{ + double foo; + int inv; + + foo = unpack_double (VALUE_TYPE (val), VALUE_CONTENTS (val), &inv); + if (inv) + error ("Invalid floating value found in program."); + return foo; +} + +/* Unpack raw data (copied from debugee) at VALADDR + as a long, or as a double, assuming the raw data is described + by type TYPE. Knows how to convert different sizes of values + and can convert between fixed and floating point. + + C++: It is assumed that the front-end has taken care of + all matters concerning pointers to members. A pointer + to member which reaches here is considered to be equivalent + to an INT (or some size). After all, it is only an offset. */ + +LONGEST +unpack_long (type, valaddr) + struct type *type; + char *valaddr; +{ + register enum type_code code = TYPE_CODE (type); + register int len = TYPE_LENGTH (type); + register int nosign = TYPE_UNSIGNED (type); + + if (code == TYPE_CODE_ENUM) + code = TYPE_CODE_INT; + if (code == TYPE_CODE_FLT) + { + if (len == sizeof (float)) + return * (float *) valaddr; + + if (len == sizeof (double)) + return * (double *) valaddr; + } + else if (code == TYPE_CODE_INT && nosign) + { + if (len == sizeof (char)) + return * (unsigned char *) valaddr; + + if (len == sizeof (short)) + return * (unsigned short *) valaddr; + + if (len == sizeof (int)) + return * (unsigned int *) valaddr; + + if (len == sizeof (long)) + return * (unsigned long *) valaddr; +#ifdef LONG_LONG + if (len == sizeof (long long)) + return * (unsigned long long *) valaddr; +#endif + } + else if (code == TYPE_CODE_INT) + { + if (len == sizeof (char)) + return * (char *) valaddr; + + if (len == sizeof (short)) + return * (short *) valaddr; + + if (len == sizeof (int)) + return * (int *) valaddr; + + if (len == sizeof (long)) + return * (long *) valaddr; + +#ifdef LONG_LONG + if (len == sizeof (long long)) + return * (long long *) valaddr; +#endif + } + else if (code == TYPE_CODE_PTR + || code == TYPE_CODE_REF) + { + if (len == sizeof (char *)) + return (CORE_ADDR) * (char **) valaddr; + } + else if (code == TYPE_CODE_MEMBER) + error ("not implemented: member types in unpack_long"); + + error ("Value not integer or pointer."); +} + +/* Return a double value from the specified type and address. + INVP points to an int which is set to 0 for valid value, + 1 for invalid value (bad float format). In either case, + the returned double is OK to use. */ + +double +unpack_double (type, valaddr, invp) + struct type *type; + char *valaddr; + int *invp; +{ + register enum type_code code = TYPE_CODE (type); + register int len = TYPE_LENGTH (type); + register int nosign = TYPE_UNSIGNED (type); + + *invp = 0; /* Assume valid. */ + if (code == TYPE_CODE_FLT) + { + if (INVALID_FLOAT (valaddr, len)) + { + *invp = 1; + return 1.234567891011121314; + } + + if (len == sizeof (float)) + return * (float *) valaddr; + + if (len == sizeof (double)) + { + /* Some machines require doubleword alignment for doubles. + This code works on them, and on other machines. */ + double temp; + bcopy ((char *) valaddr, (char *) &temp, sizeof (double)); + return temp; + } + } + else if (code == TYPE_CODE_INT && nosign) + { + if (len == sizeof (char)) + return * (unsigned char *) valaddr; + + if (len == sizeof (short)) + return * (unsigned short *) valaddr; + + if (len == sizeof (int)) + return * (unsigned int *) valaddr; + + if (len == sizeof (long)) + return * (unsigned long *) valaddr; + +#ifdef LONG_LONG + if (len == sizeof (long long)) + return * (unsigned long long *) valaddr; +#endif + } + else if (code == TYPE_CODE_INT) + { + if (len == sizeof (char)) + return * (char *) valaddr; + + if (len == sizeof (short)) + return * (short *) valaddr; + + if (len == sizeof (int)) + return * (int *) valaddr; + + if (len == sizeof (long)) + return * (long *) valaddr; + +#ifdef LONG_LONG + if (len == sizeof (long long)) + return * (long long *) valaddr; +#endif + } + + error ("Value not floating number."); + /* NOTREACHED */ + return (double) 0; /* To silence compiler warning. */ +} + +/* Given a value ARG1 of a struct or union type, + extract and return the value of one of its fields. + FIELDNO says which field. + + For C++, must also be able to return values from static fields */ + +value +value_field (arg1, fieldno) + register value arg1; + register int fieldno; +{ + register value v; + register struct type *type = TYPE_FIELD_TYPE (VALUE_TYPE (arg1), fieldno); + register int offset; + + /* Handle packed fields */ + + offset = TYPE_FIELD_BITPOS (VALUE_TYPE (arg1), fieldno) / 8; + if (TYPE_FIELD_BITSIZE (VALUE_TYPE (arg1), fieldno)) + { + v = value_from_long (type, + unpack_field_as_long (VALUE_TYPE (arg1), + VALUE_CONTENTS (arg1), + fieldno)); + VALUE_BITPOS (v) = TYPE_FIELD_BITPOS (VALUE_TYPE (arg1), fieldno) % 8; + VALUE_BITSIZE (v) = TYPE_FIELD_BITSIZE (VALUE_TYPE (arg1), fieldno); + } + else + { + v = allocate_value (type); + bcopy (VALUE_CONTENTS (arg1) + offset, + VALUE_CONTENTS (v), + TYPE_LENGTH (type)); + } + VALUE_LVAL (v) = VALUE_LVAL (arg1); + if (VALUE_LVAL (arg1) == lval_internalvar) + VALUE_LVAL (v) = lval_internalvar_component; + VALUE_ADDRESS (v) = VALUE_ADDRESS (arg1); + VALUE_OFFSET (v) = offset + VALUE_OFFSET (arg1); + return v; +} + +value +value_fn_field (arg1, fieldno, subfieldno) + register value arg1; + register int fieldno; +{ + register value v; + struct fn_field *f = TYPE_FN_FIELDLIST1 (VALUE_TYPE (arg1), fieldno); + register struct type *type = TYPE_FN_FIELD_TYPE (f, subfieldno); + struct symbol *sym; + + sym = lookup_symbol (TYPE_FN_FIELD_PHYSNAME (f, subfieldno), + 0, VAR_NAMESPACE, 0); + if (! sym) error ("Internal error: could not find physical method named %s", + TYPE_FN_FIELD_PHYSNAME (f, subfieldno)); + + v = allocate_value (type); + VALUE_ADDRESS (v) = BLOCK_START (SYMBOL_BLOCK_VALUE (sym)); + VALUE_TYPE (v) = type; + return v; +} + +/* Return a virtual function as a value. + ARG1 is the object which provides the virtual function + table pointer. + F is the list of member functions which contains the desired virtual + function. + J is an index into F which provides the desired virtual function. + TYPE is the basetype which first provides the virtual function table. */ +value +value_virtual_fn_field (arg1, f, j, type) + value arg1; + struct fn_field *f; + int j; + struct type *type; +{ + /* First, get the virtual function table pointer. That comes + with a strange type, so cast it to type `pointer to long' (which + should serve just fine as a function type). Then, index into + the table, and convert final value to appropriate function type. */ + value vfn, vtbl; + value vi = value_from_long (builtin_type_int, + (LONGEST) TYPE_FN_FIELD_VOFFSET (f, j)); + VALUE_TYPE (arg1) = TYPE_VPTR_BASETYPE (type); + + /* This type may have been defined before its virtual function table + was. If so, fill in the virtual function table entry for the + type now. */ + if (TYPE_VPTR_FIELDNO (type) < 0) + TYPE_VPTR_FIELDNO (type) + = fill_in_vptr_fieldno (type); + + /* The virtual function table is now an array of structures + which have the form { int16 offset, delta; void *pfn; }. */ + vtbl = value_ind (value_field (arg1, TYPE_VPTR_FIELDNO (type))); + + /* Index into the virtual function table. This is hard-coded because + looking up a field is not cheap, and it may be important to save + time, e.g. if the user has set a conditional breakpoint calling + a virtual function. */ + vfn = value_field (value_subscript (vtbl, vi), 2); + + /* Reinstantiate the function pointer with the correct type. */ + VALUE_TYPE (vfn) = lookup_pointer_type (TYPE_FN_FIELD_TYPE (f, j)); + return vfn; +} + +/* The value of a static class member does not depend + on its instance, only on its type. If FIELDNO >= 0, + then fieldno is a valid field number and is used directly. + Otherwise, FIELDNAME is the name of the field we are + searching for. If it is not a static field name, an + error is signaled. TYPE is the type in which we look for the + static field member. */ +value +value_static_field (type, fieldname, fieldno) + register struct type *type; + char *fieldname; + register int fieldno; +{ + register value v; + struct symbol *sym; + + if (fieldno < 0) + { + register struct type *t = type; + /* Look for static field. */ + while (t) + { + int i; + for (i = TYPE_NFIELDS (t) - 1; i >= 0; i--) + if (! strcmp (TYPE_FIELD_NAME (t, i), fieldname)) + { + if (TYPE_FIELD_STATIC (t, i)) + { + fieldno = i; + goto found; + } + else + error ("field `%s' is not static"); + } + t = TYPE_BASECLASSES (t) ? TYPE_BASECLASS (t, 1) : 0; + } + + t = type; + + if (destructor_name_p (fieldname, t)) + error ("use `info method' command to print out value of destructor"); + + while (t) + { + int i, j; + + for (i = TYPE_NFN_FIELDS (t) - 1; i >= 0; i--) + { + if (! strcmp (TYPE_FN_FIELDLIST_NAME (t, i), fieldname)) + { + error ("use `info method' command to print value of method \"%s\"", fieldname); + } + } + t = TYPE_BASECLASSES (t) ? TYPE_BASECLASS (t, 1) : 0; + } + error("there is no field named %s", fieldname); + } + + found: + + sym = lookup_symbol (TYPE_FIELD_STATIC_PHYSNAME (type, fieldno), + 0, VAR_NAMESPACE, 0); + if (! sym) error ("Internal error: could not find physical static variable named %s", TYPE_FIELD_BITSIZE (type, fieldno)); + + type = TYPE_FIELD_TYPE (type, fieldno); + v = value_at (type, (CORE_ADDR)SYMBOL_BLOCK_VALUE (sym)); + return v; +} + +long +unpack_field_as_long (type, valaddr, fieldno) + struct type *type; + char *valaddr; + int fieldno; +{ + long val; + int bitpos = TYPE_FIELD_BITPOS (type, fieldno); + int bitsize = TYPE_FIELD_BITSIZE (type, fieldno); + + bcopy (valaddr + bitpos / 8, &val, sizeof val); + + /* Extracting bits depends on endianness of the machine. */ +#ifdef BITS_BIG_ENDIAN + val = val >> (sizeof val * 8 - bitpos % 8 - bitsize); +#else + val = val >> (bitpos % 8); +#endif + + val &= (1 << bitsize) - 1; + return val; +} + +void +modify_field (addr, fieldval, bitpos, bitsize) + char *addr; + int fieldval; + int bitpos, bitsize; +{ + long oword; + + /* Reject values too big to fit in the field in question. + Otherwise adjoining fields may be corrupted. */ + if (fieldval & ~((1<<bitsize)-1)) + error ("Value %d does not fit in %d bits.", fieldval, bitsize); + + bcopy (addr, &oword, sizeof oword); + + /* Shifting for bit field depends on endianness of the machine. */ +#ifdef BITS_BIG_ENDIAN + bitpos = sizeof (oword) * 8 - bitpos - bitsize; +#endif + + oword &= ~(((1 << bitsize) - 1) << bitpos); + oword |= fieldval << bitpos; + bcopy (&oword, addr, sizeof oword); +} + +/* Convert C numbers into newly allocated values */ + +value +value_from_long (type, num) + struct type *type; + register LONGEST num; +{ + register value val = allocate_value (type); + register enum type_code code = TYPE_CODE (type); + register int len = TYPE_LENGTH (type); + + if (code == TYPE_CODE_INT || code == TYPE_CODE_ENUM) + { + if (len == sizeof (char)) + * (char *) VALUE_CONTENTS (val) = num; + else if (len == sizeof (short)) + * (short *) VALUE_CONTENTS (val) = num; + else if (len == sizeof (int)) + * (int *) VALUE_CONTENTS (val) = num; + else if (len == sizeof (long)) + * (long *) VALUE_CONTENTS (val) = num; +#ifdef LONG_LONG + else if (len == sizeof (long long)) + * (long long *) VALUE_CONTENTS (val) = num; +#endif + else + error ("Integer type encountered with unexpected data length."); + } + else + error ("Unexpected type encountered for integer constant."); + + return val; +} + +value +value_from_double (type, num) + struct type *type; + double num; +{ + register value val = allocate_value (type); + register enum type_code code = TYPE_CODE (type); + register int len = TYPE_LENGTH (type); + + if (code == TYPE_CODE_FLT) + { + if (len == sizeof (float)) + * (float *) VALUE_CONTENTS (val) = num; + else if (len == sizeof (double)) + * (double *) VALUE_CONTENTS (val) = num; + else + error ("Floating type encountered with unexpected data length."); + } + else + error ("Unexpected type encountered for floating constant."); + + return val; +} + +/* Deal with the value that is "about to be returned". */ + +/* Return the value that a function returning now + would be returning to its caller, assuming its type is VALTYPE. + RETBUF is where we look for what ought to be the contents + of the registers (in raw form). This is because it is often + desirable to restore old values to those registers + after saving the contents of interest, and then call + this function using the saved values. + struct_return is non-zero when the function in question is + using the structure return conventions on the machine in question; + 0 when it is using the value returning conventions (this often + means returning pointer to where structure is vs. returning value). */ + +value +value_being_returned (valtype, retbuf, struct_return) + register struct type *valtype; + char retbuf[REGISTER_BYTES]; + int struct_return; +{ + register value val; + + if (struct_return) + return value_at (valtype, EXTRACT_STRUCT_VALUE_ADDRESS (retbuf)); + + val = allocate_value (valtype); + EXTRACT_RETURN_VALUE (valtype, retbuf, VALUE_CONTENTS (val)); + + return val; +} + +/* Return true if the function specified is using the structure returning + convention on this machine to return arguments, or 0 if it is using + the value returning convention. FUNCTION is the value representing + the function, FUNCADDR is the address of the function, and VALUE_TYPE + is the type returned by the function */ + +struct block *block_for_pc (); + +int +using_struct_return (function, funcaddr, value_type) + value function; + CORE_ADDR funcaddr; + struct type *value_type; +{ + register enum type_code code = TYPE_CODE (value_type); + + if (code == TYPE_CODE_STRUCT || + code == TYPE_CODE_UNION || + code == TYPE_CODE_ARRAY) + { + struct block *b = block_for_pc (funcaddr); + + if (!(BLOCK_GCC_COMPILED (b) && TYPE_LENGTH (value_type) < 8)) + return 1; + } + + return 0; +} + +/* Store VAL so it will be returned if a function returns now. + Does not verify that VAL's type matches what the current + function wants to return. */ + +void +set_return_value (val) + value val; +{ + register enum type_code code = TYPE_CODE (VALUE_TYPE (val)); + char regbuf[REGISTER_BYTES]; + double dbuf; + LONGEST lbuf; + + if (code == TYPE_CODE_STRUCT + || code == TYPE_CODE_UNION) + error ("Specifying a struct or union return value is not supported."); + + if (code == TYPE_CODE_FLT) + { + dbuf = value_as_double (val); + + STORE_RETURN_VALUE (VALUE_TYPE (val), &dbuf); + } + else + { + lbuf = value_as_long (val); + STORE_RETURN_VALUE (VALUE_TYPE (val), &lbuf); + } +} + +void +_initialize_values () +{ + add_info ("convenience", convenience_info, + "Debugger convenience (\"$foo\") variables.\n\ +These variables are created when you assign them values;\n\ +thus, \"print $foo=1\" gives \"$foo\" the value 1. Values may be any type.\n\n\ +A few convenience variables are given values automatically GDB:\n\ +\"$_\"holds the last address examined with \"x\" or \"info lines\",\n\ +\"$__\" holds the contents of the last address examined with \"x\"."); + + add_info ("values", value_history_info, + "Elements of value history (around item number IDX, or last ten)."); + add_info_alias ("history", value_history_info, 0); +} diff --git a/gnu/usr.bin/gdb/version.c b/gnu/usr.bin/gdb/version.c new file mode 100644 index 0000000..2f3dd85 --- /dev/null +++ b/gnu/usr.bin/gdb/version.c @@ -0,0 +1,20 @@ +/* Define the current version number of GDB. + Copyright (C) 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. */ + +char *version = "3.5"; diff --git a/gnu/usr.bin/gdb/wait.h b/gnu/usr.bin/gdb/wait.h new file mode 100644 index 0000000..c431cb6 --- /dev/null +++ b/gnu/usr.bin/gdb/wait.h @@ -0,0 +1,81 @@ +/*- + * Copyright (c) 1991 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Van Jacobson and Steven McCanne of Lawrence Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)wait.h 6.3 (Berkeley) 5/8/91 + */ + +/* Define how to access the structure that the wait system call stores. + On many systems, there is a structure defined for this. + But on vanilla-ish USG systems there is not. */ + +#ifndef HAVE_WAIT_STRUCT + +#define WAITTYPE int +#define WIFSTOPPED(w) (((w)&0377) == 0177) +#define WIFSIGNALED(w) (((w)&0377) != 0177 && ((w)&~0377) == 0) +#define WIFEXITED(w) (((w)&0377) == 0) +#define WEXITSTATUS(w) ((w) >> 8) +#define WSTOPSIG(w) ((w) >> 8) +#define WCOREDUMP(w) (((w)&0200) != 0) +#define WTERMSIG(w) ((w) & 0177) +#define WSETEXIT(w, status) ((w) = (status)) +#define WSETSTOP(w,sig) ((w) = (0177 | ((sig) << 8))) + +#else + +#include <sys/wait.h> + +#define WAITTYPE union wait +#ifndef WEXITSTATUS +#define WEXITSTATUS(w) (w).w_retcode +#endif +#ifndef WSTOPSIG +#define WSTOPSIG(w) (w).w_stopsig +#endif +#ifndef WCOREDUMP +#define WCOREDUMP(w) (w).w_coredump +#endif +#ifndef WTERMSIG +#define WTERMSIG(w) (w).w_termsig +#endif +#ifndef WSETEXIT +#define WSETEXIT(w, status) ((w).w_status = (status)) +#endif +#ifndef WSETSTOP +#define WSETSTOP(w,sig) \ + ((w).w_stopsig = (sig), (w).w_coredump = 0, (w).w_termsig = 0177) +#endif + +#endif diff --git a/gnu/usr.bin/gdb/xgdb/Makefile b/gnu/usr.bin/gdb/xgdb/Makefile new file mode 100644 index 0000000..72c5359 --- /dev/null +++ b/gnu/usr.bin/gdb/xgdb/Makefile @@ -0,0 +1,33 @@ +# %W% (Berkeley) %G% + +.include "../config/Makefile.$(MACHINE)" + +PROG= xgdb +SRCS= xgdb.c xgdbinit.c +GDBOBJS+= $(CONFIGSRCS:R:S/$/.o/g) \ + blockframe.o breakpoint.o command.o copying.o core.o \ + cplus-dem.o dbxread.o environ.o eval.o expprint.o \ + expread.o findvar.o infcmd.o inflow.o infrun.o \ + main.o obstack.o printcmd.o regex.o remote.o \ + remote-sl.o source.o stack.o symmisc.o symtab.o \ + utils.o valarith.o valops.o valprint.o values.o \ + version.o \ + funmap.o history.o keymaps.o readline.o +CFLAGS+= -I.. -I$(.CURDIR)/.. -I$(.CURDIR)/../config \ + -DHAVE_VPRINTF -DVI_MODE -DKERNELDEBUG +LDFLAGS+= -L/usr/lib/X11 +LDADD+= $(GDBOBJS:S/^/..\//g) -lXaw -lXmu -lXt -lXext -lX11 -ltermcap +NOMAN= noman + +.include "../../Makefile.inc" +.include <bsd.prog.mk> + +# +# Generate the constructor +# +xgdbinit.c: ../init.c xgdb.c + -(sed -e '/^}$$/d' ../init.c; \ + egrep -h '^_initialize_[^ ]* *\(\)' $(.CURDIR)/xgdb.c; \ + echo ';}') > xgdbinit.c + +CLEANFILES+= xgdbinit.c diff --git a/gnu/usr.bin/gdb/xgdb/xgdb.c b/gnu/usr.bin/gdb/xgdb/xgdb.c new file mode 100644 index 0000000..a2bd4f6 --- /dev/null +++ b/gnu/usr.bin/gdb/xgdb/xgdb.c @@ -0,0 +1,700 @@ +/*- + * This code is derived from software copyrighted by the Free Software + * Foundation. + * + * Modified 1991 by Donn Seeley at UUNET Technologies, Inc. + * Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory. + * + * static char rcsid[] = "$Header: /home/cvs/386BSD/src/usr.bin/gdb/xgdb/xgdb.c,v 1.1.1.1 1993/06/12 14:52:36 rgrimes Exp $"; + */ + +#ifndef lint +static char sccsid[] = "@(#)xgdb.c 6.3 (Berkeley) 5/8/91"; +#endif /* not lint */ + +/* + * Interface from GDB to X windows. Copyright (C) 1987 Free Software + * Foundation, Inc. + * + * GDB is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY. No author or distributor accepts responsibility to anyone for + * the consequences of using it or for whether it serves any particular + * purpose or works at all, unless he says so in writing. Refer to the GDB + * General Public License for full details. + * + * Everyone is granted permission to copy, modify and redistribute GDB, but only + * under the conditions described in the GDB General Public License. A copy + * of this license is supposed to have been given to you along with GDB so + * you can know your rights and responsibilities. It should be in a file + * named COPYING. Among other things, the copyright notice and this notice + * must be preserved on all copies. + * + * In other words, go ahead and share GDB, but don't try to stop anyone else + * from sharing it farther. Help stamp out software hoarding! + */ + +/* + * Original version was contributed by Derek Beatty, 30 June 87. + * This version is essentially a re-write of the original by Van + * Jacobson (van@helios.ee.lbl.gov), Nov, 90. + */ + +#include "defs.h" +#include "param.h" +#include "symtab.h" +#include "frame.h" + +extern int stop_breakpoint; + +#include <X11/IntrinsicP.h> +#include <X11/StringDefs.h> +#include <X11/Xaw/AsciiSink.h> +#include <X11/Xaw/AsciiText.h> +#include <X11/Xaw/Box.h> +#include <X11/Xaw/Command.h> +#include <X11/Xaw/Label.h> +#include <X11/Xaw/Paned.h> +#include <X11/Xaw/Text.h> + +#include <stdio.h> +#include <ctype.h> +#include <sys/file.h> +#include <sys/errno.h> + +extern int errno; +extern char *getenv(); +extern char *malloc(); +extern void bcopy(); +extern int select(); + +extern int get_filename_and_charpos(); +extern int source_line_charpos(); +extern int source_charpos_line(); +extern void execute_command(); +extern void error_no_arg(); +extern void add_com(); + +/* The X display where the window appears. */ + +static char *displayname; +static Display *display; + +static XtAppContext app_context; + +/* Windows manipulated by this package. */ + +static Widget main_widget; +static Widget containing_widget; +static Widget source_name_widget; +static Widget source_text_widget; +static Widget button_box_widget; + +/* Source text display. */ + +static struct frame_info *last_fi; +static CORE_ADDR last_pc; +static struct symtab *last_cur_symtab; +static int last_cur_line; + +static int source_window_line; +static char *source_window_file; +static struct symtab *source_window_symtab; + +static char version_label[64]; +extern char *version; + +/* Forward declarations */ + +static Widget create_text_widget(); + +static int +safe_strcmp(a, b) + register char *a, *b; +{ + register int i; + + if (a == b) + return (0); + if (!a && b) + return (1); + if (a && !b) + return (-1); + return (strcmp(a, b)); +} + + +/* Display an appropriate piece of source code in the source window. */ + +void +xgdb_display_source() +{ + char *filename = NULL; + struct symtab_and_line get_selected_frame_sal(); + struct symtab_and_line sal; + struct frame_info *fi; + + /* Do nothing if called before we are initialized */ + + if (!containing_widget) + return; + + /* + * Figure out what to display (the appropriate hooks to tell + * us don't exist so we guess): If there's a current frame + * and it or its pc changed from the last time we were here, + * display appropriate source line. Otherwise if the current + * source symtab or line is different, display that line. + * Otherwise nothing changed so leave the display alone. + */ + fi = get_frame_info(selected_frame); + if (fi && (fi != last_fi || fi->pc != last_pc)) { + last_fi = fi; + last_pc = fi->pc; + sal = find_pc_line(fi->pc, fi->next_frame); + if (sal.symtab == NULL) { /* XXX */ + sal.symtab = current_source_symtab; + sal.line = current_source_line; + } + current_source_symtab = sal.symtab; + current_source_line = sal.line; + } else if (current_source_symtab != last_cur_symtab || + current_source_line != last_cur_line) { + sal.symtab = last_cur_symtab = current_source_symtab; + sal.line = last_cur_line = current_source_line; + } else + return; + /* + * Do a path search and get the exact filename of this source file. + * Also scan it and find its source lines if not already done. + */ + if (sal.symtab && filename == NULL) { + if (get_filename_and_charpos(sal.symtab, sal.line, &filename)) + /* line numbers may have changed - force highlight */ + source_window_line = -1; + } + + /* + * If the source window is wrong, destroy it and make a new one. + */ + if (safe_strcmp(filename, source_window_file)) { + Arg args[1]; + Widget src = XawTextGetSource(source_text_widget); + + if (filename) { + XtSetArg(args[0], XtNstring, filename); + XtSetValues(src, args, XtNumber(args)); + args[0].name = XtNlabel; + XtSetValues(source_name_widget, args, XtNumber(args)); + } else { + XtSetArg(args[0], XtNstring, "/dev/null"); + XtSetValues(src, args, XtNumber(args)); + XtSetArg(args[0], XtNlabel, ""); + XtSetValues(source_name_widget, args, XtNumber(args)); + } + if (source_window_file) + free(source_window_file); + source_window_file = filename; + source_window_line = sal.line + 1; /* force highlight */ + } + if (sal.symtab && source_window_line != sal.line) { + /* + * Update display and cursor positions as necessary. + * Cursor should be placed on line sal.line. + */ + XawTextPosition l, r; + + source_window_symtab = sal.symtab; + source_window_line = sal.line; + l = source_line_charpos(source_window_symtab, sal.line); + r = source_line_charpos(source_window_symtab, sal.line + 1); + if (r < l) + r = l + 1; + XawTextSetSelection(source_text_widget, l, r); + XawTextScrollToLine(source_text_widget, l, 10, 3); + XawTextSetInsertionPoint(source_text_widget, l); + } +} + + +/* + * Handlers for buttons. + */ + +static int +current_lineno() +{ + XawTextPosition start, finish; + + XawTextGetSelectionPos(source_text_widget, &start, &finish); + if (start >= finish) + start = XawTextGetInsertionPoint(source_text_widget); + + return (source_charpos_line(source_window_symtab, start)); +} + +static char * +append_selection(cp) + char *cp; +{ + int len; + XawTextPosition l, r; + + XawTextGetSelectionPos(source_text_widget, &l, &r); + if ((len = r - l) > 0) { + Widget src = XawTextGetSource(source_text_widget); + + while (len > 0) { + XawTextBlock tb; + + XawTextSourceRead(src, l, &tb, len); + bcopy(tb.ptr, cp, tb.length); + cp += tb.length; + len -= tb.length; + } + if (cp[-1] == 0) + --cp; + } + return (cp); +} + +static char * +append_selection_word(cp) + register char *cp; +{ + register int len; + XawTextPosition l, r; + XawTextBlock tb; + register char c; + register Widget src = XawTextGetSource(source_text_widget); + + XawTextGetSelectionPos(source_text_widget, &l, &r); + if ((len = r - l) <= 0) { + l = XawTextGetInsertionPoint(source_text_widget); + len = 128; /* XXX */ + + /* might have clicked in middle of word -- back up to start */ + for ( ; l > 0; --l) { + XawTextSourceRead(src, l - 1, &tb, 1); + c = tb.ptr[0]; + if (! isalnum(c) && c != '_' && c != '$') + break; + } + } + while (len > 0) { + char *sp; + int i; + + XawTextSourceRead(src, l, &tb, len); + for (sp = tb.ptr, i = tb.length; --i >= 0; ) { + c = *sp++; + if (!isalnum(c) && c != '_' && c != '$') + return (cp); + *cp++ = c; + } + len -= tb.length; + } + return (cp); +} + +static char * +append_selection_expr(cp) + char *cp; +{ + int len; + XawTextPosition l, r; + Widget src = XawTextGetSource(source_text_widget); + XawTextBlock tb; + char *sp; + char c; + + XawTextGetSelectionPos(source_text_widget, &l, &r); + if (r > l) + return (append_selection(cp)); + + l = XawTextGetInsertionPoint(source_text_widget); + + /* might have clicked in middle of word -- back up to start */ + for ( ; l > 0; --l) { + XawTextSourceRead(src, l - 1, &tb, 1); + c = tb.ptr[0]; + if (! isalnum(c) && c != '_' && c != '$') + break; + } + + len = 128; /* XXX */ + while (len > 0) { + int i; + char pstack[64]; + int pcnt = 0; + + XawTextSourceRead(src, l, &tb, len); + for (sp = tb.ptr, i = tb.length; --i >= 0; ) { + switch (c = *sp++) { + case '\n': + case ';': + return (cp); + case '=': + if (cp[-1] != '=') + return (cp - 1); + if (len == 128) + return (cp); + break; + case ',': + if (pcnt <= 0) + return (cp); + break; + case '(': + pstack[pcnt] = ')'; + if (++pcnt >= sizeof(pstack)) + return (cp); + break; + case '[': + pstack[pcnt] = ']'; + if (++pcnt >= sizeof(pstack)) + return (cp); + break; + case ')': + case ']': + if (--pcnt < 0 || pstack[pcnt] != c) + return (cp); + break; + } + *cp++ = c; + } + len -= tb.length; + } + return (cp); +} + +static int input_avail; /* XXX kluge: do_command sets this when command + * data from button is avaialble to force top level + * to break out of its loop. */ +/* + * Handle a button by running the command COMMAND. + */ +static void +do_command(w, command, call_data) + Widget w; + register char *command; + caddr_t call_data; +{ + char cmd_line[256]; + char buf[256]; + register char *out = cmd_line; + char *cp; + register char c; + extern char *finish_command_input(); + + while (c = *command++) { + if (c == '%') { + switch (*command++) { + case 's': /* current selection */ + out = append_selection(out); + break; + case 'S': /* 1st selected "word" at curor */ + out = append_selection_word(out); + break; + case 'e': /* echo cmd before executing */ + break; + case 'E': /* 1st selected expression at curor */ + out = append_selection_expr(out); + break; + + case 'l': /* current line number */ + (void) sprintf(buf, "%d", current_lineno()); + for (cp = buf; c = *cp++; *out++ = c) + ; + break; + case 'L': /* line we're stopped at */ + (void) sprintf(buf, "%d", source_window_line); + for (cp = buf; c = *cp++; *out++ = c) + ; + break; + case 'f': /* current file name */ + for (cp = source_window_symtab->filename; + c = *cp++; *out++ = c) + ; + break; + case 'b': /* break # we're stopped at */ + if (stop_breakpoint <= 0) + /* if no breakpoint, don't do cmd */ + return; + + (void) sprintf(buf, "%d", stop_breakpoint); + for (cp = buf; c = *cp++; *out++ = c) + ; + break; + } + } else + *out++ = c; + } + *out = 0; + reinitialize_more_filter(); + /* have to exit via readline or tty modes stay messed up */ + for (cp = cmd_line; c = *cp++; ) + rl_stuff_char(c); + rl_stuff_char('\n'); + input_avail = 1; +} + +/* + * Define and display all the buttons. + */ +static void +addbutton(parent, name, function, closure) + Widget parent; + char *name; + void (*function) (); + caddr_t closure; +{ + static XtCallbackRec Callback[] = { + {NULL, (caddr_t) NULL}, + {NULL, (caddr_t) NULL}, + }; + static Arg commandArgs[] = { + {XtNlabel, (XtArgVal) NULL}, + {XtNcallback, (XtArgVal) Callback}, + }; + Widget w; + char wname[128]; + register char *cp; + + strcpy(wname, name); + while ((cp = index(wname, '*')) || (cp = index(wname, '.'))) + *cp -= 0x10; + + if (w = XtNameToWidget(parent, wname)) + XtDestroyWidget(w); + + Callback[0].callback = (XtCallbackProc) function; + Callback[0].closure = (caddr_t) closure; + commandArgs[0].value = (XtArgVal) name; + XtCreateManagedWidget(wname, commandWidgetClass, parent, + commandArgs, XtNumber(commandArgs)); +} + +/* + * Create the button windows and store them in `buttons'. + */ +static void +create_buttons(parent) + Widget parent; +{ + addbutton(parent, "quit", do_command, "quit"); +} + +static void +button_command(arg) + char *arg; +{ + char *label; + unsigned int len; + + if (! arg) + error_no_arg("button label and command"); + + for (len = strlen(arg); len > 0 && isspace(arg[len - 1]); --len) + ; + if (len == 0) + error_no_arg("button label and command"); + arg[len] = 0; + + /* make a copy of button label & command for toolkit to use */ + label = malloc(len + 1); + strcpy(label, arg); + + /* find the end of the label */ + if (*label == '"') { + if ((arg = index(++label, '"')) == 0) { + printf("button label missing closing quote\n"); + return; + } + *arg++ = 0; + } else if (arg = index(label, ' ')) + *arg++ = 0; + else + arg = label; + + while (*arg && isspace(*arg)) + ++arg; + + addbutton(button_box_widget, label, do_command, arg); +} + +static void +button_delete_command(arg) + char *arg; +{ + unsigned int len; + Widget w; + register char *cp; + + if (! arg) + error_no_arg("button name"); + + for (len = strlen(arg); len > 0 && isspace(arg[len - 1]); --len) + ; + if (len == 0) + error_no_arg("button name"); + arg[len] = 0; + + /* find the end of the label */ + if (*arg == '"') { + if ((cp = index(++arg, '"')) == 0) { + printf("button label missing closing quote\n"); + return; + } + *cp++ = 0; + } + while ((cp = index(arg, '*')) || (cp = index(arg, '.'))) + *cp -= 0x10; + + if (w = XtNameToWidget(button_box_widget, arg)) + XtDestroyWidget(w); +} + +/* + * Create a "label window" that just displays the string LABEL. + */ +static Widget +create_label(name, label) + char *name, *label; +{ + Arg args[1]; + Widget w; + + XtSetArg(args[0], XtNlabel, label); + w = XtCreateManagedWidget(name, labelWidgetClass, containing_widget, + args, XtNumber(args)); + return (w); +} + +/* + * Create a subwindow of PARENT that displays and scrolls the contents of + * file FILENAME. + */ +static Widget +create_text_widget(parent, filename) + Widget parent; + char *filename; +{ + static Arg arg[] = { + {XtNstring, NULL}, + {XtNtype, XawAsciiFile}, + {XtNcursor, None}, + }; + Widget text_widget; + + arg[0].value = (XtArgVal)filename; + text_widget = XtCreateManagedWidget("src", asciiTextWidgetClass, + parent, arg, XtNumber(arg)); + return (text_widget); +} + +/* + * Entry point to create the widgets representing our display. + */ +void +xgdb_create_window() +{ + /* initialize toolkit, setup defaults */ +#ifdef notyet + main_widget = XtAppInitialize(&app_context, "Xgdb", NULL, 0, + argcptr, argv, NULL, NULL, 0); +#else + char *dummy_argv[] = { "xgdb", 0 }; + int dummy_argc = 1; + main_widget = XtAppInitialize(&app_context, "Xgdb", NULL, 0, + &dummy_argc, dummy_argv, NULL, NULL, 0); +#endif + display = XtDisplay(main_widget); + containing_widget = XtCreateManagedWidget("frame", panedWidgetClass, + main_widget, NULL, 0); + + sprintf(version_label, "XGDB %s", version); + button_box_widget = XtCreateManagedWidget("buttons", boxWidgetClass, + containing_widget, NULL, 0); + create_buttons(button_box_widget); + source_name_widget = create_label("srcLabel", "No source file yet."); + source_text_widget = create_text_widget(containing_widget, "/dev/null"); + + XtRealizeWidget(main_widget); + XFlush(display); +} + +/* + * If we use an X window, the readline input loop is told to call + * this function before reading a character from stdin. + */ +/*ARGSUSED*/ +static void +xgdb_window_hook() +{ + register int inmask = 1 << fileno(stdin); + register int xmask = 1 << ConnectionNumber(display); + register int nfds, pend; + int input_rfds; + XEvent ev; + + /* + * Display our current idea of the `interesting' source file then + * loop, dispatching window events until data is available on + * stdin. Then return so the input data can be processed. + */ + input_avail = 0; + xgdb_display_source(); + + input_rfds = 0; + while (input_avail == 0 && (input_rfds & inmask) == 0) { + pend = XPending(display); + if (!pend) { + input_rfds = inmask | xmask; + nfds = select(32, &input_rfds, 0, 0, + (struct timeval *)0); + if (nfds == -1 && errno == EINTR) + continue; + } + if (pend || (input_rfds & xmask)) { + XNextEvent(display, &ev); + XtDispatchEvent(&ev); + } + } +} + +void +_initialize_xgdb() +{ + extern void (*window_hook) (); + extern int inhibit_windows; + extern struct cmd_list_element *deletelist; + + if (inhibit_windows) + return; + + if (! displayname) { + displayname = getenv("DISPLAY"); + if (! displayname) { + fprintf(stderr, "xgdb: no display name\n"); + inhibit_windows = 1; + return; + } + } + xgdb_create_window(); + window_hook = xgdb_window_hook; + add_com("button", class_support, button_command, +"Add command button to xgdb window. First argument is button\n\ +label, second is command associated with button. Command can\n\ +include printf-like escapes:\n\ + %s for current selection,\n\ + %S for first 'word' of current selection,\n\ + %e for current selection or expression at insertion pt,\n\ + %E for current selection or expression at insertion pt,\n\ + %l for current line number,\n\ + %L for line program stopped at,\n\ + %f for current file name,\n\ + %b for current breakpoint number."); + add_cmd("button", class_support, button_delete_command, +"Delete a button from the xgdb window.\n\ +Argument is name of button to be deleted.", + &deletelist); +} |